summaryrefslogtreecommitdiff
path: root/lib/rbcodec/codecs/libgme/nes_oscs.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rbcodec/codecs/libgme/nes_oscs.c')
-rw-r--r--lib/rbcodec/codecs/libgme/nes_oscs.c592
1 files changed, 592 insertions, 0 deletions
diff --git a/lib/rbcodec/codecs/libgme/nes_oscs.c b/lib/rbcodec/codecs/libgme/nes_oscs.c
new file mode 100644
index 0000000000..ac6e5759da
--- /dev/null
+++ b/lib/rbcodec/codecs/libgme/nes_oscs.c
@@ -0,0 +1,592 @@
1// Nes_Snd_Emu 0.1.8. http://www.slack.net/~ant/
2
3#include "nes_apu.h"
4
5/* Copyright (C) 2003-2006 Shay Green. This module is free software; you
6can redistribute it and/or modify it under the terms of the GNU Lesser
7General Public License as published by the Free Software Foundation; either
8version 2.1 of the License, or (at your option) any later version. This
9module is distributed in the hope that it will be useful, but WITHOUT ANY
10WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12details. You should have received a copy of the GNU Lesser General Public
13License along with this module; if not, write to the Free Software Foundation,
14Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
15
16#include "blargg_source.h"
17
18// Nes_Osc
19
20void Osc_clock_length( struct Nes_Osc* this, int halt_mask )
21{
22 if ( this->length_counter && !(this->regs [0] & halt_mask) )
23 this->length_counter--;
24}
25
26// Nes_Square
27
28void Square_clock_envelope( struct Nes_Square* this )
29{
30 struct Nes_Osc* osc = &this->osc;
31 int period = osc->regs [0] & 15;
32 if ( osc->reg_written [3] ) {
33 osc->reg_written [3] = false;
34 this->env_delay = period;
35 this->envelope = 15;
36 }
37 else if ( --this->env_delay < 0 ) {
38 this->env_delay = period;
39 if ( this->envelope | (osc->regs [0] & 0x20) )
40 this->envelope = (this->envelope - 1) & 15;
41 }
42}
43
44int Square_volume( struct Nes_Square* this )
45{
46 struct Nes_Osc* osc = &this->osc;
47 return osc->length_counter == 0 ? 0 : (osc->regs [0] & 0x10) ? (osc->regs [0] & 15) : this->envelope;
48}
49
50void Square_clock_sweep( struct Nes_Square* this, int negative_adjust )
51{
52 struct Nes_Osc* osc = &this->osc;
53 int sweep = osc->regs [1];
54
55 if ( --this->sweep_delay < 0 )
56 {
57 osc->reg_written [1] = true;
58
59 int period = Osc_period( osc );
60 int shift = sweep & shift_mask;
61 if ( shift && (sweep & 0x80) && period >= 8 )
62 {
63 int offset = period >> shift;
64
65 if ( sweep & negate_flag )
66 offset = negative_adjust - offset;
67
68 if ( period + offset < 0x800 )
69 {
70 period += offset;
71 // rewrite period
72 osc->regs [2] = period & 0xFF;
73 osc->regs [3] = (osc->regs [3] & ~7) | ((period >> 8) & 7);
74 }
75 }
76 }
77
78 if ( osc->reg_written [1] ) {
79 osc->reg_written [1] = false;
80 this->sweep_delay = (sweep >> 4) & 7;
81 }
82}
83
84// TODO: clean up
85static inline nes_time_t Square_maintain_phase( struct Nes_Square* this, nes_time_t time, nes_time_t end_time,
86 nes_time_t timer_period )
87{
88 nes_time_t remain = end_time - time;
89 if ( remain > 0 )
90 {
91 int count = (remain + timer_period - 1) / timer_period;
92 this->phase = (this->phase + count) & (square_phase_range - 1);
93 time += count * timer_period;
94 }
95 return time;
96}
97
98void Square_run( struct Nes_Square* this, nes_time_t time, nes_time_t end_time )
99{
100 struct Nes_Osc* osc = &this->osc;
101 const int period = Osc_period( osc );
102 const int timer_period = (period + 1) * 2;
103
104 if ( !osc->output )
105 {
106 osc->delay = Square_maintain_phase( this, time + osc->delay, end_time, timer_period ) - end_time;
107 return;
108 }
109
110 int offset = period >> (osc->regs [1] & shift_mask);
111 if ( osc->regs [1] & negate_flag )
112 offset = 0;
113
114 const int volume = Square_volume( this );
115 if ( volume == 0 || period < 8 || (period + offset) >= 0x800 )
116 {
117 if ( osc->last_amp ) {
118 Blip_set_modified( osc->output );
119 Synth_offset( this->synth, time, -osc->last_amp, osc->output );
120 osc->last_amp = 0;
121 }
122
123 time += osc->delay;
124 time = Square_maintain_phase( this, time, end_time, timer_period );
125 }
126 else
127 {
128 // handle duty select
129 int duty_select = (osc->regs [0] >> 6) & 3;
130 int duty = 1 << duty_select; // 1, 2, 4, 2
131 int amp = 0;
132 if ( duty_select == 3 ) {
133 duty = 2; // negated 25%
134 amp = volume;
135 }
136 if ( this->phase < duty )
137 amp ^= volume;
138
139 Blip_set_modified( osc->output );
140 {
141 int delta = Osc_update_amp( osc, amp );
142 if ( delta )
143 Synth_offset( this->synth, time, delta, osc->output );
144 }
145
146 time += osc->delay;
147 if ( time < end_time )
148 {
149 struct Blip_Buffer* const output = osc->output;
150 Synth* synth = this->synth;
151 int delta = amp * 2 - volume;
152 int phase = this->phase;
153
154 do {
155 phase = (phase + 1) & (square_phase_range - 1);
156 if ( phase == 0 || phase == duty ) {
157 delta = -delta;
158 Synth_offset_inline( synth, time, delta, output );
159 }
160 time += timer_period;
161 }
162 while ( time < end_time );
163
164 osc->last_amp = (delta + volume) >> 1;
165 this->phase = phase;
166 }
167 }
168
169 osc->delay = time - end_time;
170}
171
172// Nes_Triangle
173
174void Triangle_clock_linear_counter( struct Nes_Triangle* this )
175{
176 struct Nes_Osc* osc = &this->osc;
177 if ( osc->reg_written [3] )
178 this->linear_counter = osc->regs [0] & 0x7F;
179 else if ( this->linear_counter )
180 this->linear_counter--;
181
182 if ( !(osc->regs [0] & 0x80) )
183 osc->reg_written [3] = false;
184}
185
186static inline int Triangle_calc_amp( struct Nes_Triangle* this )
187{
188 int amp = Triangle_phase_range - this->phase;
189 if ( amp < 0 )
190 amp = this->phase - (Triangle_phase_range + 1);
191 return amp;
192}
193
194// TODO: clean up
195static inline nes_time_t Triangle_maintain_phase( struct Nes_Triangle* this, nes_time_t time, nes_time_t end_time,
196 nes_time_t timer_period )
197{
198 nes_time_t remain = end_time - time;
199 if ( remain > 0 )
200 {
201 int count = (remain + timer_period - 1) / timer_period;
202 this->phase = ((unsigned) this->phase + 1 - count) & (Triangle_phase_range * 2 - 1);
203 this->phase++;
204 time += count * timer_period;
205 }
206 return time;
207}
208
209void Triangle_run( struct Nes_Triangle* this, nes_time_t time, nes_time_t end_time )
210{
211 struct Nes_Osc* osc = &this->osc;
212 const int timer_period = Osc_period( osc ) + 1;
213 if ( !osc->output )
214 {
215 time += osc->delay;
216 osc->delay = 0;
217 if ( osc->length_counter && this->linear_counter && timer_period >= 3 )
218 osc->delay = Triangle_maintain_phase( this, time, end_time, timer_period ) - end_time;
219 return;
220 }
221
222 // to do: track phase when period < 3
223 // to do: Output 7.5 on dac when period < 2? More accurate, but results in more clicks.
224
225 int delta = Osc_update_amp( osc, Triangle_calc_amp( this ) );
226 if ( delta )
227 {
228 Blip_set_modified( osc->output );
229 Synth_offset( &this->synth, time, delta, osc->output );
230 }
231
232 time += osc->delay;
233 if ( osc->length_counter == 0 || this->linear_counter == 0 || timer_period < 3 )
234 {
235 time = end_time;
236 }
237 else if ( time < end_time )
238 {
239 struct Blip_Buffer* const output = osc->output;
240
241 int phase = this->phase;
242 int volume = 1;
243 if ( phase > Triangle_phase_range ) {
244 phase -= Triangle_phase_range;
245 volume = -volume;
246 }
247 Blip_set_modified( osc->output );
248
249 do {
250 if ( --phase == 0 ) {
251 phase = Triangle_phase_range;
252 volume = -volume;
253 }
254 else
255 {
256 Synth_offset_inline( &this->synth, time, volume, output );
257 }
258
259 time += timer_period;
260 }
261 while ( time < end_time );
262
263 if ( volume < 0 )
264 phase += Triangle_phase_range;
265 this->phase = phase;
266 osc->last_amp = Triangle_calc_amp( this );
267 }
268 osc->delay = time - end_time;
269}
270
271// Nes_Dmc
272
273void Dmc_reset( struct Nes_Dmc* this )
274{
275 this->address = 0;
276 this->dac = 0;
277 this->buf = 0;
278 this->bits_remain = 1;
279 this->bits = 0;
280 this->buf_full = false;
281 this->silence = true;
282 this->next_irq = apu_no_irq;
283 this->irq_flag = false;
284 this->irq_enabled = false;
285
286 Osc_reset( &this->osc );
287 this->period = 0x1AC;
288}
289
290void Dmc_recalc_irq( struct Nes_Dmc* this )
291{
292 struct Nes_Osc* osc = &this->osc;
293 nes_time_t irq = apu_no_irq;
294 if ( this->irq_enabled && osc->length_counter )
295 irq = this->apu->last_dmc_time + osc->delay +
296 ((osc->length_counter - 1) * 8 + this->bits_remain - 1) * (nes_time_t) (this->period) + 1;
297 if ( irq != this->next_irq ) {
298 this->next_irq = irq;
299 Apu_irq_changed( this->apu );
300 }
301}
302
303int Dmc_count_reads( struct Nes_Dmc* this, nes_time_t time, nes_time_t* last_read )
304{
305 struct Nes_Osc* osc = &this->osc;
306 if ( last_read )
307 *last_read = time;
308
309 if ( osc->length_counter == 0 )
310 return 0; // not reading
311
312 nes_time_t first_read = Dmc_next_read_time( this );
313 nes_time_t avail = time - first_read;
314 if ( avail <= 0 )
315 return 0;
316
317 int count = (avail - 1) / (this->period * 8) + 1;
318 if ( !(osc->regs [0] & loop_flag) && count > osc->length_counter )
319 count = osc->length_counter;
320
321 if ( last_read )
322 {
323 *last_read = first_read + (count - 1) * (this->period * 8) + 1;
324 check( *last_read <= time );
325 check( count == count_reads( *last_read, NULL ) );
326 check( count - 1 == count_reads( *last_read - 1, NULL ) );
327 }
328
329 return count;
330}
331
332static short const dmc_period_table [2] [16] = {
333 {428, 380, 340, 320, 286, 254, 226, 214, // NTSC
334 190, 160, 142, 128, 106, 84, 72, 54},
335
336 {398, 354, 316, 298, 276, 236, 210, 198, // PAL
337 176, 148, 132, 118, 98, 78, 66, 50}
338};
339
340static inline void Dmc_reload_sample( struct Nes_Dmc* this )
341{
342 this->address = 0x4000 + this->osc.regs [2] * 0x40;
343 this->osc.length_counter = this->osc.regs [3] * 0x10 + 1;
344}
345
346static int const dmc_table [128] =
347{
348 0, 24, 48, 71, 94, 118, 141, 163, 186, 209, 231, 253, 275, 297, 319, 340,
349 361, 383, 404, 425, 445, 466, 486, 507, 527, 547, 567, 587, 606, 626, 645, 664,
350 683, 702, 721, 740, 758, 777, 795, 813, 832, 850, 867, 885, 903, 920, 938, 955,
351 972, 989,1006,1023,1040,1056,1073,1089,1105,1122,1138,1154,1170,1185,1201,1217,
3521232,1248,1263,1278,1293,1308,1323,1338,1353,1368,1382,1397,1411,1425,1440,1454,
3531468,1482,1496,1510,1523,1537,1551,1564,1578,1591,1604,1618,1631,1644,1657,1670,
3541683,1695,1708,1721,1733,1746,1758,1771,1783,1795,1807,1819,1831,1843,1855,1867,
3551879,1890,1902,1914,1925,1937,1948,1959,1971,1982,1993,2004,2015,2026,2037,2048,
356};
357
358static inline int update_amp_nonlinear( struct Nes_Dmc* this, int in )
359{
360 if ( !this->nonlinear )
361 in = dmc_table [in];
362 int delta = in - this->osc.last_amp;
363 this->osc.last_amp = in;
364 return delta;
365}
366
367void Dmc_write_register( struct Nes_Dmc* this, int addr, int data )
368{
369 if ( addr == 0 )
370 {
371 this->period = dmc_period_table [this->pal_mode] [data & 15];
372 this->irq_enabled = (data & 0xC0) == 0x80; // enabled only if loop disabled
373 this->irq_flag &= this->irq_enabled;
374 Dmc_recalc_irq( this );
375 }
376 else if ( addr == 1 )
377 {
378 this->dac = data & 0x7F;
379 }
380}
381
382void Dmc_start( struct Nes_Dmc* this )
383{
384 Dmc_reload_sample( this );
385 Dmc_fill_buffer( this );
386 Dmc_recalc_irq( this );
387}
388
389void Dmc_fill_buffer( struct Nes_Dmc* this )
390{
391 if ( !this->buf_full && this->osc.length_counter )
392 {
393 require( this->prg_reader ); // prg_reader must be set
394 this->buf = this->prg_reader( this->prg_reader_data, 0x8000u + this->address );
395 this->address = (this->address + 1) & 0x7FFF;
396 this->buf_full = true;
397 if ( --this->osc.length_counter == 0 )
398 {
399 if ( this->osc.regs [0] & loop_flag ) {
400 Dmc_reload_sample( this );
401 }
402 else {
403 this->apu->osc_enables &= ~0x10;
404 this->irq_flag = this->irq_enabled;
405 this->next_irq = apu_no_irq;
406 Apu_irq_changed( this->apu );
407 }
408 }
409 }
410}
411
412void Dmc_run( struct Nes_Dmc* this, nes_time_t time, nes_time_t end_time )
413{
414 struct Nes_Osc* osc = &this->osc;
415 int delta = update_amp_nonlinear( this, this->dac );
416 if ( !osc->output )
417 {
418 this->silence = true;
419 }
420 else if ( delta )
421 {
422 Blip_set_modified( osc->output );
423 Synth_offset( &this->synth, time, delta, osc->output );
424 }
425
426 time += osc->delay;
427 if ( time < end_time )
428 {
429 int bits_remain = this->bits_remain;
430 if ( this->silence && !this->buf_full )
431 {
432 int count = (end_time - time + this->period - 1) / this->period;
433 bits_remain = (bits_remain - 1 + 8 - (count % 8)) % 8 + 1;
434 time += count * this->period;
435 }
436 else
437 {
438 struct Blip_Buffer* const output = osc->output;
439 const int period = this->period;
440 int bits = this->bits;
441 int dac = this->dac;
442 if ( output )
443 Blip_set_modified( output );
444
445 do
446 {
447 if ( !this->silence )
448 {
449 int step = (bits & 1) * 4 - 2;
450 bits >>= 1;
451 if ( (unsigned) (dac + step) <= 0x7F ) {
452 dac += step;
453 Synth_offset_inline( &this->synth, time, update_amp_nonlinear( this, dac ), output );
454 }
455 }
456
457 time += period;
458
459 if ( --bits_remain == 0 )
460 {
461 bits_remain = 8;
462 if ( !this->buf_full ) {
463 this->silence = true;
464 }
465 else
466 {
467 this->silence = false;
468 bits = this->buf;
469 this->buf_full = false;
470 if ( !output )
471 this->silence = true;
472 Dmc_fill_buffer( this );
473 }
474 }
475 }
476 while ( time < end_time );
477
478 this->dac = dac;
479 //osc->last_amp = dac;
480 this->bits = bits;
481 }
482 this->bits_remain = bits_remain;
483 }
484 osc->delay = time - end_time;
485}
486
487// Nes_Noise
488
489static short const noise_period_table [16] = {
490 0x004, 0x008, 0x010, 0x020, 0x040, 0x060, 0x080, 0x0A0,
491 0x0CA, 0x0FE, 0x17C, 0x1FC, 0x2FA, 0x3F8, 0x7F2, 0xFE4
492};
493
494void Noise_clock_envelope( struct Nes_Noise* this )
495{
496 struct Nes_Osc* osc = &this->osc;
497 int period = osc->regs [0] & 15;
498 if ( osc->reg_written [3] ) {
499 osc->reg_written [3] = false;
500 this->env_delay = period;
501 this->envelope = 15;
502 }
503 else if ( --this->env_delay < 0 ) {
504 this->env_delay = period;
505 if ( this->envelope | (osc->regs [0] & 0x20) )
506 this->envelope = (this->envelope - 1) & 15;
507 }
508}
509
510int Noise_volume( struct Nes_Noise* this )
511{
512 struct Nes_Osc* osc = &this->osc;
513 return osc->length_counter == 0 ? 0 : (osc->regs [0] & 0x10) ? (osc->regs [0] & 15) : this->envelope;
514}
515
516void Noise_run( struct Nes_Noise* this, nes_time_t time, nes_time_t end_time )
517{
518 struct Nes_Osc* osc = &this->osc;
519 int period = noise_period_table [osc->regs [2] & 15];
520
521 if ( !osc->output )
522 {
523 // TODO: clean up
524 time += osc->delay;
525 osc->delay = time + (end_time - time + period - 1) / period * period - end_time;
526 return;
527 }
528
529 const int volume = Noise_volume( this );
530 int amp = (this->noise & 1) ? volume : 0;
531 {
532 int delta = Osc_update_amp( osc, amp );
533 if ( delta )
534 {
535 Blip_set_modified( osc->output );
536 Synth_offset( &this->synth, time, delta, osc->output );
537 }
538 }
539
540 time += osc->delay;
541 if ( time < end_time )
542 {
543 const int mode_flag = 0x80;
544
545 if ( !volume )
546 {
547 // round to next multiple of period
548 time += (end_time - time + period - 1) / period * period;
549
550 // approximate noise cycling while muted, by shuffling up noise register
551 // to do: precise muted noise cycling?
552 if ( !(osc->regs [2] & mode_flag) ) {
553 int feedback = (this->noise << 13) ^ (this->noise << 14);
554 this->noise = (feedback & 0x4000) | (this->noise >> 1);
555 }
556 }
557 else
558 {
559 struct Blip_Buffer* const output = osc->output;
560
561 // using resampled time avoids conversion in synth.offset()
562 blip_resampled_time_t rperiod = Blip_resampled_duration( output, period );
563 blip_resampled_time_t rtime = Blip_resampled_time( output, time );
564
565 int noise = this->noise;
566 int delta = amp * 2 - volume;
567 const int tap = (osc->regs [2] & mode_flag ? 8 : 13);
568 Blip_set_modified( output );
569
570 do {
571 int feedback = (noise << tap) ^ (noise << 14);
572 time += period;
573
574 if ( (noise + 1) & 2 ) {
575 // bits 0 and 1 of noise differ
576 delta = -delta;
577 Synth_offset_resampled( &this->synth, rtime, delta, output );
578 }
579
580 rtime += rperiod;
581 noise = (feedback & 0x4000) | (noise >> 1);
582 }
583 while ( time < end_time );
584
585 osc->last_amp = (delta + volume) >> 1;
586 this->noise = noise;
587 }
588 }
589
590 osc->delay = time - end_time;
591}
592