summaryrefslogtreecommitdiff
path: root/apps/codecs/libgme/nes_oscs.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/codecs/libgme/nes_oscs.c')
-rw-r--r--apps/codecs/libgme/nes_oscs.c583
1 files changed, 583 insertions, 0 deletions
diff --git a/apps/codecs/libgme/nes_oscs.c b/apps/codecs/libgme/nes_oscs.c
new file mode 100644
index 0000000000..f04d5fa9ad
--- /dev/null
+++ b/apps/codecs/libgme/nes_oscs.c
@@ -0,0 +1,583 @@
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
85inline 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 += (blargg_long) 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 Blip_set_modified( osc->output );
111
112 int offset = period >> (osc->regs [1] & shift_mask);
113 if ( osc->regs [1] & negate_flag )
114 offset = 0;
115
116 const int volume = Square_volume( this );
117 if ( volume == 0 || period < 8 || (period + offset) >= 0x800 )
118 {
119 if ( osc->last_amp ) {
120 Synth_offset( this->synth, time, -osc->last_amp, osc->output );
121 osc->last_amp = 0;
122 }
123
124 time += osc->delay;
125 time = Square_maintain_phase( this, time, end_time, timer_period );
126 }
127 else
128 {
129 // handle duty select
130 int duty_select = (osc->regs [0] >> 6) & 3;
131 int duty = 1 << duty_select; // 1, 2, 4, 2
132 int amp = 0;
133 if ( duty_select == 3 ) {
134 duty = 2; // negated 25%
135 amp = volume;
136 }
137 if ( this->phase < duty )
138 amp ^= volume;
139
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
186inline 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
195inline 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 += (blargg_long) 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 Blip_set_modified( osc->output );
223
224 // to do: track phase when period < 3
225 // to do: Output 7.5 on dac when period < 2? More accurate, but results in more clicks.
226
227 int delta = Osc_update_amp( osc, Triangle_calc_amp( this ) );
228 if ( delta )
229 Synth_offset( &this->synth, time, delta, osc->output );
230
231 time += osc->delay;
232 if ( osc->length_counter == 0 || this->linear_counter == 0 || timer_period < 3 )
233 {
234 time = end_time;
235 }
236 else if ( time < end_time )
237 {
238 struct Blip_Buffer* const output = osc->output;
239
240 int phase = this->phase;
241 int volume = 1;
242 if ( phase > Triangle_phase_range ) {
243 phase -= Triangle_phase_range;
244 volume = -volume;
245 }
246
247 do {
248 if ( --phase == 0 ) {
249 phase = Triangle_phase_range;
250 volume = -volume;
251 }
252 else {
253 Synth_offset_inline( &this->synth, time, volume, output );
254 }
255
256 time += timer_period;
257 }
258 while ( time < end_time );
259
260 if ( volume < 0 )
261 phase += Triangle_phase_range;
262 this->phase = phase;
263 osc->last_amp = Triangle_calc_amp( this );
264 }
265 osc->delay = time - end_time;
266}
267
268// Nes_Dmc
269
270void Dmc_reset( struct Nes_Dmc* this )
271{
272 this->address = 0;
273 this->dac = 0;
274 this->buf = 0;
275 this->bits_remain = 1;
276 this->bits = 0;
277 this->buf_full = false;
278 this->silence = true;
279 this->next_irq = apu_no_irq;
280 this->irq_flag = false;
281 this->irq_enabled = false;
282
283 Osc_reset( &this->osc );
284 this->period = 0x1AC;
285}
286
287void Dmc_recalc_irq( struct Nes_Dmc* this )
288{
289 struct Nes_Osc* osc = &this->osc;
290 nes_time_t irq = apu_no_irq;
291 if ( this->irq_enabled && osc->length_counter )
292 irq = this->apu->last_dmc_time + osc->delay +
293 ((osc->length_counter - 1) * 8 + this->bits_remain - 1) * (nes_time_t) (this->period) + 1;
294 if ( irq != this->next_irq ) {
295 this->next_irq = irq;
296 Apu_irq_changed( this->apu );
297 }
298}
299
300int Dmc_count_reads( struct Nes_Dmc* this, nes_time_t time, nes_time_t* last_read )
301{
302 struct Nes_Osc* osc = &this->osc;
303 if ( last_read )
304 *last_read = time;
305
306 if ( osc->length_counter == 0 )
307 return 0; // not reading
308
309 nes_time_t first_read = Dmc_next_read_time( this );
310 nes_time_t avail = time - first_read;
311 if ( avail <= 0 )
312 return 0;
313
314 int count = (avail - 1) / (this->period * 8) + 1;
315 if ( !(osc->regs [0] & loop_flag) && count > osc->length_counter )
316 count = osc->length_counter;
317
318 if ( last_read )
319 {
320 *last_read = first_read + (count - 1) * (this->period * 8) + 1;
321 check( *last_read <= time );
322 check( count == count_reads( *last_read, NULL ) );
323 check( count - 1 == count_reads( *last_read - 1, NULL ) );
324 }
325
326 return count;
327}
328
329static short const dmc_period_table [2] [16] ICONST_ATTR = {
330 {428, 380, 340, 320, 286, 254, 226, 214, // NTSC
331 190, 160, 142, 128, 106, 84, 72, 54},
332
333 {398, 354, 316, 298, 276, 236, 210, 198, // PAL
334 176, 148, 132, 118, 98, 78, 66, 50}
335};
336
337inline void Dmc_reload_sample( struct Nes_Dmc* this )
338{
339 this->address = 0x4000 + this->osc.regs [2] * 0x40;
340 this->osc.length_counter = this->osc.regs [3] * 0x10 + 1;
341}
342
343static byte const dac_table [128] ICONST_ATTR =
344{
345 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 9,10,11,12,13,14,
346 15,15,16,17,18,19,20,20,21,22,23,24,24,25,26,27,
347 27,28,29,30,31,31,32,33,33,34,35,36,36,37,38,38,
348 39,40,41,41,42,43,43,44,45,45,46,47,47,48,48,49,
349 50,50,51,52,52,53,53,54,55,55,56,56,57,58,58,59,
350 59,60,60,61,61,62,63,63,64,64,65,65,66,66,67,67,
351 68,68,69,70,70,71,71,72,72,73,73,74,74,75,75,75,
352 76,76,77,77,78,78,79,79,80,80,81,81,82,82,82,83,
353};
354
355void Dmc_write_register( struct Nes_Dmc* this, int addr, int data )
356{
357 if ( addr == 0 )
358 {
359 this->period = dmc_period_table [this->pal_mode] [data & 15];
360 this->irq_enabled = (data & 0xC0) == 0x80; // enabled only if loop disabled
361 this->irq_flag &= this->irq_enabled;
362 Dmc_recalc_irq( this );
363 }
364 else if ( addr == 1 )
365 {
366 int old_dac = this->dac;
367 this->dac = data & 0x7F;
368
369 // adjust last_amp so that "pop" amplitude will be properly non-linear
370 // with respect to change in dac
371 int faked_nonlinear = this->dac - (dac_table [this->dac] - dac_table [old_dac]);
372 if ( !this->nonlinear )
373 this->osc.last_amp = faked_nonlinear;
374 }
375}
376
377void Dmc_start( struct Nes_Dmc* this )
378{
379 Dmc_reload_sample( this );
380 Dmc_fill_buffer( this );
381 Dmc_recalc_irq( this );
382}
383
384void Dmc_fill_buffer( struct Nes_Dmc* this )
385{
386 if ( !this->buf_full && this->osc.length_counter )
387 {
388 require( this->prg_reader ); // prg_reader must be set
389 this->buf = this->prg_reader( this->prg_reader_data, 0x8000u + this->address );
390 this->address = (this->address + 1) & 0x7FFF;
391 this->buf_full = true;
392 if ( --this->osc.length_counter == 0 )
393 {
394 if ( this->osc.regs [0] & loop_flag ) {
395 Dmc_reload_sample( this );
396 }
397 else {
398 this->apu->osc_enables &= ~0x10;
399 this->irq_flag = this->irq_enabled;
400 this->next_irq = apu_no_irq;
401 Apu_irq_changed( this->apu );
402 }
403 }
404 }
405}
406
407void Dmc_run( struct Nes_Dmc* this, nes_time_t time, nes_time_t end_time )
408{
409 struct Nes_Osc* osc = &this->osc;
410 int delta = Osc_update_amp( osc, this->dac );
411 if ( !osc->output )
412 {
413 this->silence = true;
414 }
415 else
416 {
417 Blip_set_modified( osc->output );
418 if ( delta )
419 Synth_offset( &this->synth, time, delta, osc->output );
420 }
421
422 time += osc->delay;
423 if ( time < end_time )
424 {
425 int bits_remain = this->bits_remain;
426 if ( this->silence && !this->buf_full )
427 {
428 int count = (end_time - time + this->period - 1) / this->period;
429 bits_remain = (bits_remain - 1 + 8 - (count % 8)) % 8 + 1;
430 time += count * this->period;
431 }
432 else
433 {
434 struct Blip_Buffer* const output = osc->output;
435 const int period = this->period;
436 int bits = this->bits;
437 int dac = this->dac;
438
439 do
440 {
441 if ( !this->silence )
442 {
443 int step = (bits & 1) * 4 - 2;
444 bits >>= 1;
445 if ( (unsigned) (dac + step) <= 0x7F ) {
446 dac += step;
447 Synth_offset_inline( &this->synth, time, step, output );
448 }
449 }
450
451 time += period;
452
453 if ( --bits_remain == 0 )
454 {
455 bits_remain = 8;
456 if ( !this->buf_full ) {
457 this->silence = true;
458 }
459 else {
460 this->silence = false;
461 bits = this->buf;
462 this->buf_full = false;
463 if ( !output )
464 this->silence = true;
465 Dmc_fill_buffer( this );
466 }
467 }
468 }
469 while ( time < end_time );
470
471 this->dac = dac;
472 osc->last_amp = dac;
473 this->bits = bits;
474 }
475 this->bits_remain = bits_remain;
476 }
477 osc->delay = time - end_time;
478}
479
480// Nes_Noise
481
482static short const noise_period_table [16] ICONST_ATTR = {
483 0x004, 0x008, 0x010, 0x020, 0x040, 0x060, 0x080, 0x0A0,
484 0x0CA, 0x0FE, 0x17C, 0x1FC, 0x2FA, 0x3F8, 0x7F2, 0xFE4
485};
486
487void Noise_clock_envelope( struct Nes_Noise* this )
488{
489 struct Nes_Osc* osc = &this->osc;
490 int period = osc->regs [0] & 15;
491 if ( osc->reg_written [3] ) {
492 osc->reg_written [3] = false;
493 this->env_delay = period;
494 this->envelope = 15;
495 }
496 else if ( --this->env_delay < 0 ) {
497 this->env_delay = period;
498 if ( this->envelope | (osc->regs [0] & 0x20) )
499 this->envelope = (this->envelope - 1) & 15;
500 }
501}
502
503int Noise_volume( struct Nes_Noise* this )
504{
505 struct Nes_Osc* osc = &this->osc;
506 return osc->length_counter == 0 ? 0 : (osc->regs [0] & 0x10) ? (osc->regs [0] & 15) : this->envelope;
507}
508
509void Noise_run( struct Nes_Noise* this, nes_time_t time, nes_time_t end_time )
510{
511 struct Nes_Osc* osc = &this->osc;
512 int period = noise_period_table [osc->regs [2] & 15];
513
514 if ( !osc->output )
515 {
516 // TODO: clean up
517 time += osc->delay;
518 osc->delay = time + (end_time - time + period - 1) / period * period - end_time;
519 return;
520 }
521
522 Blip_set_modified( osc->output );
523
524 const int volume = Noise_volume( this );
525 int amp = (this->noise & 1) ? volume : 0;
526 {
527 int delta = Osc_update_amp( osc, amp );
528 if ( delta )
529 Synth_offset( &this->synth, time, delta, osc->output );
530 }
531
532 time += osc->delay;
533 if ( time < end_time )
534 {
535 const int mode_flag = 0x80;
536
537 if ( !volume )
538 {
539 // round to next multiple of period
540 time += (end_time - time + period - 1) / period * period;
541
542 // approximate noise cycling while muted, by shuffling up noise register
543 // to do: precise muted noise cycling?
544 if ( !(osc->regs [2] & mode_flag) ) {
545 int feedback = (this->noise << 13) ^ (this->noise << 14);
546 this->noise = (feedback & 0x4000) | (this->noise >> 1);
547 }
548 }
549 else
550 {
551 struct Blip_Buffer* const output = osc->output;
552
553 // using resampled time avoids conversion in synth.offset()
554 blip_resampled_time_t rperiod = Blip_resampled_duration( output, period );
555 blip_resampled_time_t rtime = Blip_resampled_time( output, time );
556
557 int noise = this->noise;
558 int delta = amp * 2 - volume;
559 const int tap = (osc->regs [2] & mode_flag ? 8 : 13);
560
561 do {
562 int feedback = (noise << tap) ^ (noise << 14);
563 time += period;
564
565 if ( (noise + 1) & 2 ) {
566 // bits 0 and 1 of noise differ
567 delta = -delta;
568 Synth_offset_resampled( &this->synth, rtime, delta, output );
569 }
570
571 rtime += rperiod;
572 noise = (feedback & 0x4000) | (noise >> 1);
573 }
574 while ( time < end_time );
575
576 osc->last_amp = (delta + volume) >> 1;
577 this->noise = noise;
578 }
579 }
580
581 osc->delay = time - end_time;
582}
583