1 // Gb_Snd_Emu 0.1.5. http://www.slack.net/~ant/
2 
3 #include "Gb_Apu.h"
4 
5 #include <string.h>
6 
7 /* Copyright (C) 2003-2006 Shay Green. This module is free software; you
8 can redistribute it and/or modify it under the terms of the GNU Lesser
9 General Public License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version. This
11 module is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
14 details. You should have received a copy of the GNU Lesser General Public
15 License along with this module; if not, write to the Free Software Foundation,
16 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
17 
18 #include "blargg_source.h"
19 
20 unsigned const vol_reg    = 0xFF24;
21 unsigned const status_reg = 0xFF26;
22 
Gb_Apu()23 Gb_Apu::Gb_Apu()
24 {
25 	square1.synth = &square_synth;
26 	square2.synth = &square_synth;
27 	wave.synth  = &other_synth;
28 	noise.synth = &other_synth;
29 
30 	oscs [0] = &square1;
31 	oscs [1] = &square2;
32 	oscs [2] = &wave;
33 	oscs [3] = &noise;
34 
35 	for ( int i = 0; i < osc_count; i++ )
36 	{
37 		Gb_Osc& osc = *oscs [i];
38 		osc.regs = &regs [i * 5];
39 		osc.output = 0;
40 		osc.outputs [0] = 0;
41 		osc.outputs [1] = 0;
42 		osc.outputs [2] = 0;
43 		osc.outputs [3] = 0;
44 	}
45 
46 	set_tempo( 1.0 );
47 	volume( 1.0 );
48 	reset();
49 }
50 
treble_eq(const blip_eq_t & eq)51 void Gb_Apu::treble_eq( const blip_eq_t& eq )
52 {
53 	square_synth.treble_eq( eq );
54 	other_synth.treble_eq( eq );
55 }
56 
osc_output(int index,Blip_Buffer * center,Blip_Buffer * left,Blip_Buffer * right)57 void Gb_Apu::osc_output( int index, Blip_Buffer* center, Blip_Buffer* left, Blip_Buffer* right )
58 {
59 	require( (unsigned) index < osc_count );
60 	require( (center && left && right) || (!center && !left && !right) );
61 	Gb_Osc& osc = *oscs [index];
62 	osc.outputs [1] = right;
63 	osc.outputs [2] = left;
64 	osc.outputs [3] = center;
65 	osc.output = osc.outputs [osc.output_select];
66 }
67 
output(Blip_Buffer * center,Blip_Buffer * left,Blip_Buffer * right)68 void Gb_Apu::output( Blip_Buffer* center, Blip_Buffer* left, Blip_Buffer* right )
69 {
70 	for ( int i = 0; i < osc_count; i++ )
71 		osc_output( i, center, left, right );
72 }
73 
update_volume()74 void Gb_Apu::update_volume()
75 {
76 	// TODO: doesn't handle differing left/right global volume (support would
77 	// require modification to all oscillator code)
78 	int data = regs [vol_reg - start_addr];
79 	double vol = (max( data & 7, data >> 4 & 7 ) + 1) * volume_unit;
80 	square_synth.volume( vol );
81 	other_synth.volume( vol );
82 }
83 
84 static unsigned char const powerup_regs [0x20] = {
85 	0x80,0x3F,0x00,0xFF,0xBF, // square 1
86 	0xFF,0x3F,0x00,0xFF,0xBF, // square 2
87 	0x7F,0xFF,0x9F,0xFF,0xBF, // wave
88 	0xFF,0xFF,0x00,0x00,0xBF, // noise
89 	0x00, // left/right enables
90 	0x77, // master volume
91 	0x80, // power
92 	0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
93 };
94 
set_tempo(double t)95 void Gb_Apu::set_tempo( double t )
96 {
97 	frame_period = 4194304 / 256; // 256 Hz
98 	if ( t != 1.0 )
99 		frame_period = blip_time_t (frame_period / t);
100 }
101 
reset()102 void Gb_Apu::reset()
103 {
104 	next_frame_time = 0;
105 	last_time       = 0;
106 	frame_count     = 0;
107 
108 	square1.reset();
109 	square2.reset();
110 	wave.reset();
111 	noise.reset();
112 	noise.bits = 1;
113 	wave.wave_pos = 0;
114 
115 	// avoid click at beginning
116 	regs [vol_reg - start_addr] = 0x77;
117 	update_volume();
118 
119 	regs [status_reg - start_addr] = 0x01; // force power
120 	write_register( 0, status_reg, 0x00 );
121 
122 	static unsigned char const initial_wave [] = {
123 		0x84,0x40,0x43,0xAA,0x2D,0x78,0x92,0x3C, // wave table
124 		0x60,0x59,0x59,0xB0,0x34,0xB8,0x2E,0xDA
125 	};
126 	memcpy( wave.wave, initial_wave, sizeof initial_wave );
127 }
128 
run_until(blip_time_t end_time)129 void Gb_Apu::run_until( blip_time_t end_time )
130 {
131 	require( end_time >= last_time ); // end_time must not be before previous time
132 	if ( end_time == last_time )
133 		return;
134 
135 	while ( true )
136 	{
137 		blip_time_t time = next_frame_time;
138 		if ( time > end_time )
139 			time = end_time;
140 
141 		// run oscillators
142 		for ( int i = 0; i < osc_count; ++i )
143 		{
144 			Gb_Osc& osc = *oscs [i];
145 			if ( osc.output )
146 			{
147 				osc.output->set_modified(); // TODO: misses optimization opportunities?
148 				int playing = false;
149 				if ( osc.enabled && osc.volume &&
150 						(!(osc.regs [4] & osc.len_enabled_mask) || osc.length) )
151 					playing = -1;
152 				switch ( i )
153 				{
154 				case 0: square1.run( last_time, time, playing ); break;
155 				case 1: square2.run( last_time, time, playing ); break;
156 				case 2: wave   .run( last_time, time, playing ); break;
157 				case 3: noise  .run( last_time, time, playing ); break;
158 				}
159 			}
160 		}
161 		last_time = time;
162 
163 		if ( time == end_time )
164 			break;
165 
166 		next_frame_time += frame_period;
167 
168 		// 256 Hz actions
169 		square1.clock_length();
170 		square2.clock_length();
171 		wave.clock_length();
172 		noise.clock_length();
173 
174 		frame_count = (frame_count + 1) & 3;
175 		if ( frame_count == 0 )
176 		{
177 			// 64 Hz actions
178 			square1.clock_envelope();
179 			square2.clock_envelope();
180 			noise.clock_envelope();
181 		}
182 
183 		if ( frame_count & 1 )
184 			square1.clock_sweep(); // 128 Hz action
185 	}
186 }
187 
end_frame(blip_time_t end_time)188 void Gb_Apu::end_frame( blip_time_t end_time )
189 {
190 	if ( end_time > last_time )
191 		run_until( end_time );
192 
193 	assert( next_frame_time >= end_time );
194 	next_frame_time -= end_time;
195 
196 	assert( last_time >= end_time );
197 	last_time -= end_time;
198 }
199 
write_register(blip_time_t time,unsigned addr,int data)200 void Gb_Apu::write_register( blip_time_t time, unsigned addr, int data )
201 {
202 	require( (unsigned) data < 0x100 );
203 
204 	int reg = addr - start_addr;
205 	if ( (unsigned) reg >= register_count )
206 		return;
207 
208 	run_until( time );
209 
210 	int old_reg = regs [reg];
211 	regs [reg] = data;
212 
213 	if ( addr < vol_reg )
214 	{
215 		write_osc( reg / 5, reg, data );
216 	}
217 	else if ( addr == vol_reg && data != old_reg ) // global volume
218 	{
219 		// return all oscs to 0
220 		for ( int i = 0; i < osc_count; i++ )
221 		{
222 			Gb_Osc& osc = *oscs [i];
223 			int amp = osc.last_amp;
224 			osc.last_amp = 0;
225 			if ( amp && osc.enabled && osc.output )
226 				other_synth.offset( time, -amp, osc.output );
227 		}
228 
229 		if ( wave.outputs [3] )
230 			other_synth.offset( time, 30, wave.outputs [3] );
231 
232 		update_volume();
233 
234 		if ( wave.outputs [3] )
235 			other_synth.offset( time, -30, wave.outputs [3] );
236 
237 		// oscs will update with new amplitude when next run
238 	}
239 	else if ( addr == 0xFF25 || addr == status_reg )
240 	{
241 		int mask = (regs [status_reg - start_addr] & 0x80) ? ~0 : 0;
242 		int flags = regs [0xFF25 - start_addr] & mask;
243 
244 		// left/right assignments
245 		for ( int i = 0; i < osc_count; i++ )
246 		{
247 			Gb_Osc& osc = *oscs [i];
248 			osc.enabled &= mask;
249 			int bits = flags >> i;
250 			Blip_Buffer* old_output = osc.output;
251 			osc.output_select = (bits >> 3 & 2) | (bits & 1);
252 			osc.output = osc.outputs [osc.output_select];
253 			if ( osc.output != old_output )
254 			{
255 				int amp = osc.last_amp;
256 				osc.last_amp = 0;
257 				if ( amp && old_output )
258 					other_synth.offset( time, -amp, old_output );
259 			}
260 		}
261 
262 		if ( addr == status_reg && data != old_reg )
263 		{
264 			if ( !(data & 0x80) )
265 			{
266 				for ( unsigned i = 0; i < sizeof powerup_regs; i++ )
267 				{
268 					if ( i != status_reg - start_addr )
269 						write_register( time, i + start_addr, powerup_regs [i] );
270 				}
271 			}
272 			else
273 			{
274 				//debug_printf( "APU powered on\n" );
275 			}
276 		}
277 	}
278 	else if ( addr >= 0xFF30 )
279 	{
280 		int index = (addr & 0x0F) * 2;
281 		wave.wave [index] = data >> 4;
282 		wave.wave [index + 1] = data & 0x0F;
283 	}
284 }
285 
read_register(blip_time_t time,unsigned addr)286 int Gb_Apu::read_register( blip_time_t time, unsigned addr )
287 {
288 	run_until( time );
289 
290 	int index = addr - start_addr;
291 	require( (unsigned) index < register_count );
292 	int data = regs [index];
293 
294 	if ( addr == status_reg )
295 	{
296 		data = (data & 0x80) | 0x70;
297 		for ( int i = 0; i < osc_count; i++ )
298 		{
299 			const Gb_Osc& osc = *oscs [i];
300 			if ( osc.enabled && (osc.length || !(osc.regs [4] & osc.len_enabled_mask)) )
301 				data |= 1 << i;
302 		}
303 	}
304 
305 	return data;
306 }
307