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 = ®s [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