summaryrefslogtreecommitdiff
path: root/lib/rbcodec/codecs/libgme/gb_apu.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rbcodec/codecs/libgme/gb_apu.c')
-rw-r--r--lib/rbcodec/codecs/libgme/gb_apu.c410
1 files changed, 410 insertions, 0 deletions
diff --git a/lib/rbcodec/codecs/libgme/gb_apu.c b/lib/rbcodec/codecs/libgme/gb_apu.c
new file mode 100644
index 0000000000..e8bf3afcf5
--- /dev/null
+++ b/lib/rbcodec/codecs/libgme/gb_apu.c
@@ -0,0 +1,410 @@
1// Gb_Snd_Emu 0.1.4. http://www.slack.net/~ant/
2
3#include "gb_apu.h"
4
5//#include "gb_apu_logger.h"
6
7/* Copyright (C) 2003-2008 Shay Green. This module is free software; you
8can redistribute it and/or modify it under the terms of the GNU Lesser
9General Public License as published by the Free Software Foundation; either
10version 2.1 of the License, or (at your option) any later version. This
11module is distributed in the hope that it will be useful, but WITHOUT ANY
12WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
14details. You should have received a copy of the GNU Lesser General Public
15License along with this module; if not, write to the Free Software Foundation,
16Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
17
18#include "blargg_source.h"
19
20int const vol_reg = 0xFF24;
21int const stereo_reg = 0xFF25;
22int const status_reg = 0xFF26;
23int const wave_ram = 0xFF30;
24
25int const power_mask = 0x80;
26
27static inline int calc_output( struct Gb_Apu* this, int osc )
28{
29 int bits = this->regs [stereo_reg - io_addr] >> osc;
30 return (bits >> 3 & 2) | (bits & 1);
31}
32
33void Apu_set_output( struct Gb_Apu* this, int i, struct Blip_Buffer* center, struct Blip_Buffer* left, struct Blip_Buffer* right )
34{
35 // Must be silent (all NULL), mono (left and right NULL), or stereo (none NULL)
36 require( !center || (center && !left && !right) || (center && left && right) );
37 require( (unsigned) i < osc_count ); // fails if you pass invalid osc index
38
39 if ( !center || !left || !right )
40 {
41 left = center;
42 right = center;
43 }
44
45 struct Gb_Osc* o = this->oscs [i];
46 o->outputs [1] = right;
47 o->outputs [2] = left;
48 o->outputs [3] = center;
49 o->output = o->outputs [calc_output( this, i )];
50}
51
52static void synth_volume( struct Gb_Apu* this, int iv )
53{
54 int v = (this->volume_ * 6) / 10 / osc_count / 15 /*steps*/ / 8 /*master vol range*/ * iv;
55 Synth_volume( &this->synth, v );
56}
57
58static void apply_volume( struct Gb_Apu* this )
59{
60 // TODO: Doesn't handle differing left and right volumes (panning).
61 // Not worth the complexity.
62 int data = this->regs [vol_reg - io_addr];
63 int left = data >> 4 & 7;
64 int right = data & 7;
65 //if ( data & 0x88 ) dprintf( "Vin: %02X\n", data & 0x88 );
66 //if ( left != right ) dprintf( "l: %d r: %d\n", left, right );
67 synth_volume( this, max( left, right ) + 1 );
68}
69
70void Apu_volume( struct Gb_Apu* this, int v )
71{
72 if ( this->volume_ != v )
73 {
74 this->volume_ = v;
75 apply_volume( this );
76 }
77}
78
79static void reset_regs( struct Gb_Apu* this )
80{
81 int i;
82 for ( i = 0; i < 0x20; i++ )
83 this->regs [i] = 0;
84
85 Sweep_reset ( &this->square1 );
86 Square_reset( &this->square2 );
87 Wave_reset ( &this->wave );
88 Noise_reset ( &this->noise );
89
90 apply_volume( this );
91}
92
93static void reset_lengths( struct Gb_Apu* this )
94{
95 this->square1.osc.length_ctr = 64;
96 this->square2.osc.length_ctr = 64;
97 this->wave .osc.length_ctr = 256;
98 this->noise .osc.length_ctr = 64;
99}
100
101void Apu_reduce_clicks( struct Gb_Apu* this, bool reduce )
102{
103 this->reduce_clicks_ = reduce;
104
105 // Click reduction makes DAC off generate same output as volume 0
106 int dac_off_amp = 0;
107 if ( reduce && this->wave.osc.mode != mode_agb ) // AGB already eliminates clicks
108 dac_off_amp = -dac_bias;
109
110 int i;
111 for ( i = 0; i < osc_count; i++ )
112 this->oscs [i]->dac_off_amp = dac_off_amp;
113
114 // AGB always eliminates clicks on wave channel using same method
115 if ( this->wave.osc.mode == mode_agb )
116 this->wave.osc.dac_off_amp = -dac_bias;
117}
118
119void Apu_reset( struct Gb_Apu* this, enum gb_mode_t mode, bool agb_wave )
120{
121 // Hardware mode
122 if ( agb_wave )
123 mode = mode_agb; // using AGB wave features implies AGB hardware
124 this->wave.agb_mask = agb_wave ? 0xFF : 0;
125 int i;
126 for ( i = 0; i < osc_count; i++ )
127 this->oscs [i]->mode = mode;
128 Apu_reduce_clicks( this, this->reduce_clicks_ );
129
130 // Reset state
131 this->frame_time = 0;
132 this->last_time = 0;
133 this->frame_phase = 0;
134
135 reset_regs( this );
136 reset_lengths( this );
137
138 // Load initial wave RAM
139 static byte const initial_wave [2] [16] = {
140 {0x84,0x40,0x43,0xAA,0x2D,0x78,0x92,0x3C,0x60,0x59,0x59,0xB0,0x34,0xB8,0x2E,0xDA},
141 {0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF},
142 };
143 int b;
144 for ( b = 2; --b >= 0; )
145 {
146 // Init both banks (does nothing if not in AGB mode)
147 // TODO: verify that this works
148 Apu_write_register( this, 0, 0xFF1A, b * 0x40 );
149 unsigned i;
150 for ( i = 0; i < sizeof initial_wave [0]; i++ )
151 Apu_write_register( this, 0, i + wave_ram, initial_wave [(mode != mode_dmg)] [i] );
152 }
153}
154
155void Apu_set_tempo( struct Gb_Apu* this, int t )
156{
157 this->frame_period = 4194304 / 512; // 512 Hz
158 if ( t != (int)FP_ONE_TEMPO )
159 this->frame_period = t ? (blip_time_t) ((this->frame_period * FP_ONE_TEMPO) / t) : (blip_time_t) (0);
160}
161
162void Apu_init( struct Gb_Apu* this )
163{
164 this->wave.wave_ram = &this->regs [wave_ram - io_addr];
165
166 Synth_init( &this->synth );
167
168 this->oscs [0] = &this->square1.osc;
169 this->oscs [1] = &this->square2.osc;
170 this->oscs [2] = &this->wave.osc;
171 this->oscs [3] = &this->noise.osc;
172
173 int i;
174 for ( i = osc_count; --i >= 0; )
175 {
176 struct Gb_Osc* o = this->oscs [i];
177 o->regs = &this->regs [i * 5];
178 o->output = NULL;
179 o->outputs [0] = NULL;
180 o->outputs [1] = NULL;
181 o->outputs [2] = NULL;
182 o->outputs [3] = NULL;
183 o->synth = &this->synth;
184 }
185
186 this->reduce_clicks_ = false;
187 Apu_set_tempo( this, (int)FP_ONE_TEMPO );
188 this->volume_ = (int)FP_ONE_VOLUME;
189 Apu_reset( this, mode_cgb, false );
190}
191
192static void run_until_( struct Gb_Apu* this, blip_time_t end_time )
193{
194 if ( !this->frame_period )
195 this->frame_time += end_time - this->last_time;
196
197 while ( true )
198 {
199 // run oscillators
200 blip_time_t time = end_time;
201 if ( time > this->frame_time )
202 time = this->frame_time;
203
204 Square_run( &this->square1, this->last_time, time );
205 Square_run( &this->square2, this->last_time, time );
206 Wave_run ( &this->wave, this->last_time, time );
207 Noise_run ( &this->noise, this->last_time, time );
208 this->last_time = time;
209
210 if ( time == end_time )
211 break;
212
213 // run frame sequencer
214 assert( this->frame_period );
215 this->frame_time += this->frame_period * clk_mul;
216 switch ( this->frame_phase++ )
217 {
218 case 2:
219 case 6:
220 // 128 Hz
221 clock_sweep( &this->square1 );
222 case 0:
223 case 4:
224 // 256 Hz
225 Osc_clock_length( &this->square1.osc );
226 Osc_clock_length( &this->square2.osc);
227 Osc_clock_length( &this->wave.osc);
228 Osc_clock_length( &this->noise.osc);
229 break;
230
231 case 7:
232 // 64 Hz
233 this->frame_phase = 0;
234 Square_clock_envelope( &this->square1 );
235 Square_clock_envelope( &this->square2 );
236 Noise_clock_envelope( &this->noise );
237 }
238 }
239}
240
241static inline void run_until( struct Gb_Apu* this, blip_time_t time )
242{
243 require( time >= this->last_time ); // end_time must not be before previous time
244 if ( time > this->last_time )
245 run_until_( this, time );
246}
247
248void Apu_end_frame( struct Gb_Apu* this, blip_time_t end_time )
249{
250 #ifdef LOG_FRAME
251 LOG_FRAME( end_time );
252 #endif
253
254 if ( end_time > this->last_time )
255 run_until( this, end_time );
256
257 this->frame_time -= end_time;
258 assert( this->frame_time >= 0 );
259
260 this->last_time -= end_time;
261 assert( this->last_time >= 0 );
262}
263
264static void silence_osc( struct Gb_Apu* this, struct Gb_Osc* o )
265{
266 int delta = -o->last_amp;
267 if ( this->reduce_clicks_ )
268 delta += o->dac_off_amp;
269
270 if ( delta )
271 {
272 o->last_amp = o->dac_off_amp;
273 if ( o->output )
274 {
275 Blip_set_modified( o->output );
276 Synth_offset( &this->synth, this->last_time, delta, o->output );
277 }
278 }
279}
280
281static void apply_stereo( struct Gb_Apu* this )
282{
283 int i;
284 for ( i = osc_count; --i >= 0; )
285 {
286 struct Gb_Osc* o = this->oscs [i];
287 struct Blip_Buffer* out = o->outputs [calc_output( this, i )];
288 if ( o->output != out )
289 {
290 silence_osc( this, o );
291 o->output = out;
292 }
293 }
294}
295
296void Apu_write_register( struct Gb_Apu* this, blip_time_t time, int addr, int data )
297{
298 require( (unsigned) data < 0x100 );
299
300 int reg = addr - io_addr;
301 if ( (unsigned) reg >= io_size )
302 {
303 require( false );
304 return;
305 }
306
307 #ifdef LOG_WRITE
308 LOG_WRITE( time, addr, data );
309 #endif
310
311 if ( addr < status_reg && !(this->regs [status_reg - io_addr] & power_mask) )
312 {
313 // Power is off
314
315 // length counters can only be written in DMG mode
316 if ( this->wave.osc.mode != mode_dmg || (reg != 1 && reg != 5+1 && reg != 10+1 && reg != 15+1) )
317 return;
318
319 if ( reg < 10 )
320 data &= 0x3F; // clear square duty
321 }
322
323 run_until( this, time );
324
325 if ( addr >= wave_ram )
326 {
327 Wave_write( &this->wave, addr, data );
328 }
329 else
330 {
331 int old_data = this->regs [reg];
332 this->regs [reg] = data;
333
334 if ( addr < vol_reg )
335 {
336 // Oscillator
337 write_osc( this, reg, old_data, data );
338 }
339 else if ( addr == vol_reg && data != old_data )
340 {
341 // Master volume
342 int i;
343 for ( i = osc_count; --i >= 0; )
344 silence_osc( this, this->oscs [i] );
345
346 apply_volume( this );
347 }
348 else if ( addr == stereo_reg )
349 {
350 // Stereo panning
351 apply_stereo( this );
352 }
353 else if ( addr == status_reg && (data ^ old_data) & power_mask )
354 {
355 // Power control
356 this->frame_phase = 0;
357 int i;
358 for ( i = osc_count; --i >= 0; )
359 silence_osc( this, this->oscs [i] );
360
361 reset_regs( this );
362 if ( this->wave.osc.mode != mode_dmg )
363 reset_lengths( this );
364
365 this->regs [status_reg - io_addr] = data;
366 }
367 }
368}
369
370int Apu_read_register( struct Gb_Apu* this, blip_time_t time, int addr )
371{
372 if ( addr >= status_reg )
373 run_until( this, time );
374
375 int reg = addr - io_addr;
376 if ( (unsigned) reg >= io_size )
377 {
378 require( false );
379 return 0;
380 }
381
382 if ( addr >= wave_ram )
383 return Wave_read( &this->wave, addr );
384
385 // Value read back has some bits always set
386 static byte const masks [] = {
387 0x80,0x3F,0x00,0xFF,0xBF,
388 0xFF,0x3F,0x00,0xFF,0xBF,
389 0x7F,0xFF,0x9F,0xFF,0xBF,
390 0xFF,0xFF,0x00,0x00,0xBF,
391 0x00,0x00,0x70,
392 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
393 };
394 int mask = masks [reg];
395 if ( this->wave.agb_mask && (reg == 10 || reg == 12) )
396 mask = 0x1F; // extra implemented bits in wave regs on AGB
397 int data = this->regs [reg] | mask;
398
399 // Status register
400 if ( addr == status_reg )
401 {
402 data &= 0xF0;
403 data |= (int) this->square1.osc.enabled << 0;
404 data |= (int) this->square2.osc.enabled << 1;
405 data |= (int) this->wave .osc.enabled << 2;
406 data |= (int) this->noise .osc.enabled << 3;
407 }
408
409 return data;
410}