1 // Nes_Snd_Emu 0.1.8. http://www.slack.net/~ant/
5 /* Copyright (C) 2003-2006 Shay Green. This module is free software; you
6 can redistribute it and/or modify it under the terms of the GNU Lesser
7 General Public License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version. This
9 module is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12 details. You should have received a copy of the GNU Lesser General Public
13 License along with this module; if not, write to the Free Software Foundation,
14 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
16 #include "blargg_source.h"
20 void Osc_clock_length( struct Nes_Osc
* this, int halt_mask
)
22 if ( this->length_counter
&& !(this->regs
[0] & halt_mask
) )
23 this->length_counter
--;
28 void Square_clock_envelope( struct Nes_Square
* this )
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
;
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;
44 int Square_volume( struct Nes_Square
* this )
46 struct Nes_Osc
* osc
= &this->osc
;
47 return osc
->length_counter
== 0 ? 0 : (osc
->regs
[0] & 0x10) ? (osc
->regs
[0] & 15) : this->envelope
;
50 void Square_clock_sweep( struct Nes_Square
* this, int negative_adjust
)
52 struct Nes_Osc
* osc
= &this->osc
;
53 int sweep
= osc
->regs
[1];
55 if ( --this->sweep_delay
< 0 )
57 osc
->reg_written
[1] = true;
59 int period
= Osc_period( osc
);
60 int shift
= sweep
& shift_mask
;
61 if ( shift
&& (sweep
& 0x80) && period
>= 8 )
63 int offset
= period
>> shift
;
65 if ( sweep
& negate_flag
)
66 offset
= negative_adjust
- offset
;
68 if ( period
+ offset
< 0x800 )
72 osc
->regs
[2] = period
& 0xFF;
73 osc
->regs
[3] = (osc
->regs
[3] & ~7) | ((period
>> 8) & 7);
78 if ( osc
->reg_written
[1] ) {
79 osc
->reg_written
[1] = false;
80 this->sweep_delay
= (sweep
>> 4) & 7;
85 static 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
)
88 nes_time_t remain
= end_time
- time
;
91 int count
= (remain
+ timer_period
- 1) / timer_period
;
92 this->phase
= (this->phase
+ count
) & (square_phase_range
- 1);
93 time
+= count
* timer_period
;
98 void Square_run( struct Nes_Square
* this, nes_time_t time
, nes_time_t end_time
)
100 struct Nes_Osc
* osc
= &this->osc
;
101 const int period
= Osc_period( osc
);
102 const int timer_period
= (period
+ 1) * 2;
106 osc
->delay
= Square_maintain_phase( this, time
+ osc
->delay
, end_time
, timer_period
) - end_time
;
110 int offset
= period
>> (osc
->regs
[1] & shift_mask
);
111 if ( osc
->regs
[1] & negate_flag
)
114 const int volume
= Square_volume( this );
115 if ( volume
== 0 || period
< 8 || (period
+ offset
) >= 0x800 )
117 if ( osc
->last_amp
) {
118 Blip_set_modified( osc
->output
);
119 Synth_offset( this->synth
, time
, -osc
->last_amp
, osc
->output
);
124 time
= Square_maintain_phase( this, time
, end_time
, timer_period
);
128 // handle duty select
129 int duty_select
= (osc
->regs
[0] >> 6) & 3;
130 int duty
= 1 << duty_select
; // 1, 2, 4, 2
132 if ( duty_select
== 3 ) {
133 duty
= 2; // negated 25%
136 if ( this->phase
< duty
)
139 Blip_set_modified( osc
->output
);
141 int delta
= Osc_update_amp( osc
, amp
);
143 Synth_offset( this->synth
, time
, delta
, osc
->output
);
147 if ( time
< end_time
)
149 struct Blip_Buffer
* const output
= osc
->output
;
150 Synth
* synth
= this->synth
;
151 int delta
= amp
* 2 - volume
;
152 int phase
= this->phase
;
155 phase
= (phase
+ 1) & (square_phase_range
- 1);
156 if ( phase
== 0 || phase
== duty
) {
158 Synth_offset_inline( synth
, time
, delta
, output
);
160 time
+= timer_period
;
162 while ( time
< end_time
);
164 osc
->last_amp
= (delta
+ volume
) >> 1;
169 osc
->delay
= time
- end_time
;
174 void Triangle_clock_linear_counter( struct Nes_Triangle
* this )
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
--;
182 if ( !(osc
->regs
[0] & 0x80) )
183 osc
->reg_written
[3] = false;
186 static inline int Triangle_calc_amp( struct Nes_Triangle
* this )
188 int amp
= Triangle_phase_range
- this->phase
;
190 amp
= this->phase
- (Triangle_phase_range
+ 1);
195 static 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
)
198 nes_time_t remain
= end_time
- time
;
201 int count
= (remain
+ timer_period
- 1) / timer_period
;
202 this->phase
= ((unsigned) this->phase
+ 1 - count
) & (Triangle_phase_range
* 2 - 1);
204 time
+= count
* timer_period
;
209 void Triangle_run( struct Nes_Triangle
* this, nes_time_t time
, nes_time_t end_time
)
211 struct Nes_Osc
* osc
= &this->osc
;
212 const int timer_period
= Osc_period( osc
) + 1;
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
;
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.
225 int delta
= Osc_update_amp( osc
, Triangle_calc_amp( this ) );
228 Blip_set_modified( osc
->output
);
229 Synth_offset( &this->synth
, time
, delta
, osc
->output
);
233 if ( osc
->length_counter
== 0 || this->linear_counter
== 0 || timer_period
< 3 )
237 else if ( time
< end_time
)
239 struct Blip_Buffer
* const output
= osc
->output
;
241 int phase
= this->phase
;
243 if ( phase
> Triangle_phase_range
) {
244 phase
-= Triangle_phase_range
;
247 Blip_set_modified( osc
->output
);
250 if ( --phase
== 0 ) {
251 phase
= Triangle_phase_range
;
256 Synth_offset_inline( &this->synth
, time
, volume
, output
);
259 time
+= timer_period
;
261 while ( time
< end_time
);
264 phase
+= Triangle_phase_range
;
266 osc
->last_amp
= Triangle_calc_amp( this );
268 osc
->delay
= time
- end_time
;
273 void Dmc_reset( struct Nes_Dmc
* this )
278 this->bits_remain
= 1;
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;
286 Osc_reset( &this->osc
);
287 this->period
= 0x1AC;
290 void Dmc_recalc_irq( struct Nes_Dmc
* this )
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
);
303 int Dmc_count_reads( struct Nes_Dmc
* this, nes_time_t time
, nes_time_t
* last_read
)
305 struct Nes_Osc
* osc
= &this->osc
;
309 if ( osc
->length_counter
== 0 )
310 return 0; // not reading
312 nes_time_t first_read
= Dmc_next_read_time( this );
313 nes_time_t avail
= time
- first_read
;
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
;
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
) );
332 static 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},
336 {398, 354, 316, 298, 276, 236, 210, 198, // PAL
337 176, 148, 132, 118, 98, 78, 66, 50}
340 static inline void Dmc_reload_sample( struct Nes_Dmc
* this )
342 this->address
= 0x4000 + this->osc
.regs
[2] * 0x40;
343 this->osc
.length_counter
= this->osc
.regs
[3] * 0x10 + 1;
346 static int const dmc_table
[128] =
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,
352 1232,1248,1263,1278,1293,1308,1323,1338,1353,1368,1382,1397,1411,1425,1440,1454,
353 1468,1482,1496,1510,1523,1537,1551,1564,1578,1591,1604,1618,1631,1644,1657,1670,
354 1683,1695,1708,1721,1733,1746,1758,1771,1783,1795,1807,1819,1831,1843,1855,1867,
355 1879,1890,1902,1914,1925,1937,1948,1959,1971,1982,1993,2004,2015,2026,2037,2048,
358 static inline int update_amp_nonlinear( struct Nes_Dmc
* this, int in
)
360 if ( !this->nonlinear
)
362 int delta
= in
- this->osc
.last_amp
;
363 this->osc
.last_amp
= in
;
367 void Dmc_write_register( struct Nes_Dmc
* this, int addr
, int data
)
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 );
376 else if ( addr
== 1 )
378 this->dac
= data
& 0x7F;
382 void Dmc_start( struct Nes_Dmc
* this )
384 Dmc_reload_sample( this );
385 Dmc_fill_buffer( this );
386 Dmc_recalc_irq( this );
389 void Dmc_fill_buffer( struct Nes_Dmc
* this )
391 if ( !this->buf_full
&& this->osc
.length_counter
)
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 )
399 if ( this->osc
.regs
[0] & loop_flag
) {
400 Dmc_reload_sample( this );
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
);
412 void Dmc_run( struct Nes_Dmc
* this, nes_time_t time
, nes_time_t end_time
)
414 struct Nes_Osc
* osc
= &this->osc
;
415 int delta
= update_amp_nonlinear( this, this->dac
);
418 this->silence
= true;
422 Blip_set_modified( osc
->output
);
423 Synth_offset( &this->synth
, time
, delta
, osc
->output
);
427 if ( time
< end_time
)
429 int bits_remain
= this->bits_remain
;
430 if ( this->silence
&& !this->buf_full
)
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
;
438 struct Blip_Buffer
* const output
= osc
->output
;
439 const int period
= this->period
;
440 int bits
= this->bits
;
443 Blip_set_modified( output
);
447 if ( !this->silence
)
449 int step
= (bits
& 1) * 4 - 2;
451 if ( (unsigned) (dac
+ step
) <= 0x7F ) {
453 Synth_offset_inline( &this->synth
, time
, update_amp_nonlinear( this, dac
), output
);
459 if ( --bits_remain
== 0 )
462 if ( !this->buf_full
) {
463 this->silence
= true;
467 this->silence
= false;
469 this->buf_full
= false;
471 this->silence
= true;
472 Dmc_fill_buffer( this );
476 while ( time
< end_time
);
479 //osc->last_amp = dac;
482 this->bits_remain
= bits_remain
;
484 osc
->delay
= time
- end_time
;
489 static short const noise_period_table
[16] = {
490 0x004, 0x008, 0x010, 0x020, 0x040, 0x060, 0x080, 0x0A0,
491 0x0CA, 0x0FE, 0x17C, 0x1FC, 0x2FA, 0x3F8, 0x7F2, 0xFE4
494 void Noise_clock_envelope( struct Nes_Noise
* this )
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
;
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;
510 int Noise_volume( struct Nes_Noise
* this )
512 struct Nes_Osc
* osc
= &this->osc
;
513 return osc
->length_counter
== 0 ? 0 : (osc
->regs
[0] & 0x10) ? (osc
->regs
[0] & 15) : this->envelope
;
516 void Noise_run( struct Nes_Noise
* this, nes_time_t time
, nes_time_t end_time
)
518 struct Nes_Osc
* osc
= &this->osc
;
519 int period
= noise_period_table
[osc
->regs
[2] & 15];
525 osc
->delay
= time
+ (end_time
- time
+ period
- 1) / period
* period
- end_time
;
529 const int volume
= Noise_volume( this );
530 int amp
= (this->noise
& 1) ? volume
: 0;
532 int delta
= Osc_update_amp( osc
, amp
);
535 Blip_set_modified( osc
->output
);
536 Synth_offset( &this->synth
, time
, delta
, osc
->output
);
541 if ( time
< end_time
)
543 const int mode_flag
= 0x80;
547 // round to next multiple of period
548 time
+= (end_time
- time
+ period
- 1) / period
* period
;
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);
559 struct Blip_Buffer
* const output
= osc
->output
;
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
);
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
);
571 int feedback
= (noise
<< tap
) ^ (noise
<< 14);
574 if ( (noise
+ 1) & 2 ) {
575 // bits 0 and 1 of noise differ
577 Synth_offset_resampled( &this->synth
, rtime
, delta
, output
);
581 noise
= (feedback
& 0x4000) | (noise
>> 1);
583 while ( time
< end_time
);
585 osc
->last_amp
= (delta
+ volume
) >> 1;
590 osc
->delay
= time
- end_time
;