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 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
+= (blargg_long
) 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 Blip_set_modified( osc
->output
);
112 int offset
= period
>> (osc
->regs
[1] & shift_mask
);
113 if ( osc
->regs
[1] & negate_flag
)
116 const int volume
= Square_volume( this );
117 if ( volume
== 0 || period
< 8 || (period
+ offset
) >= 0x800 )
119 if ( osc
->last_amp
) {
120 Synth_offset( this->synth
, time
, -osc
->last_amp
, osc
->output
);
125 time
= Square_maintain_phase( this, time
, end_time
, timer_period
);
129 // handle duty select
130 int duty_select
= (osc
->regs
[0] >> 6) & 3;
131 int duty
= 1 << duty_select
; // 1, 2, 4, 2
133 if ( duty_select
== 3 ) {
134 duty
= 2; // negated 25%
137 if ( this->phase
< duty
)
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 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 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
+= (blargg_long
) 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 Blip_set_modified( osc
->output
);
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.
227 int delta
= Osc_update_amp( osc
, Triangle_calc_amp( this ) );
229 Synth_offset( &this->synth
, time
, delta
, osc
->output
);
232 if ( osc
->length_counter
== 0 || this->linear_counter
== 0 || timer_period
< 3 )
236 else if ( time
< end_time
)
238 struct Blip_Buffer
* const output
= osc
->output
;
240 int phase
= this->phase
;
242 if ( phase
> Triangle_phase_range
) {
243 phase
-= Triangle_phase_range
;
248 if ( --phase
== 0 ) {
249 phase
= Triangle_phase_range
;
253 Synth_offset_inline( &this->synth
, time
, volume
, output
);
256 time
+= timer_period
;
258 while ( time
< end_time
);
261 phase
+= Triangle_phase_range
;
263 osc
->last_amp
= Triangle_calc_amp( this );
265 osc
->delay
= time
- end_time
;
270 void Dmc_reset( struct Nes_Dmc
* this )
275 this->bits_remain
= 1;
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;
283 Osc_reset( &this->osc
);
284 this->period
= 0x1AC;
287 void Dmc_recalc_irq( struct Nes_Dmc
* this )
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
);
300 int Dmc_count_reads( struct Nes_Dmc
* this, nes_time_t time
, nes_time_t
* last_read
)
302 struct Nes_Osc
* osc
= &this->osc
;
306 if ( osc
->length_counter
== 0 )
307 return 0; // not reading
309 nes_time_t first_read
= Dmc_next_read_time( this );
310 nes_time_t avail
= time
- first_read
;
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
;
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
) );
329 static 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},
333 {398, 354, 316, 298, 276, 236, 210, 198, // PAL
334 176, 148, 132, 118, 98, 78, 66, 50}
337 inline void Dmc_reload_sample( struct Nes_Dmc
* this )
339 this->address
= 0x4000 + this->osc
.regs
[2] * 0x40;
340 this->osc
.length_counter
= this->osc
.regs
[3] * 0x10 + 1;
343 static byte
const dac_table
[128] ICONST_ATTR
=
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,
355 void Dmc_write_register( struct Nes_Dmc
* this, int addr
, int data
)
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 );
364 else if ( addr
== 1 )
366 int old_dac
= this->dac
;
367 this->dac
= data
& 0x7F;
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
;
377 void Dmc_start( struct Nes_Dmc
* this )
379 Dmc_reload_sample( this );
380 Dmc_fill_buffer( this );
381 Dmc_recalc_irq( this );
384 void Dmc_fill_buffer( struct Nes_Dmc
* this )
386 if ( !this->buf_full
&& this->osc
.length_counter
)
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 )
394 if ( this->osc
.regs
[0] & loop_flag
) {
395 Dmc_reload_sample( this );
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
);
407 void Dmc_run( struct Nes_Dmc
* this, nes_time_t time
, nes_time_t end_time
)
409 struct Nes_Osc
* osc
= &this->osc
;
410 int delta
= Osc_update_amp( osc
, this->dac
);
413 this->silence
= true;
417 Blip_set_modified( osc
->output
);
419 Synth_offset( &this->synth
, time
, delta
, osc
->output
);
423 if ( time
< end_time
)
425 int bits_remain
= this->bits_remain
;
426 if ( this->silence
&& !this->buf_full
)
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
;
434 struct Blip_Buffer
* const output
= osc
->output
;
435 const int period
= this->period
;
436 int bits
= this->bits
;
441 if ( !this->silence
)
443 int step
= (bits
& 1) * 4 - 2;
445 if ( (unsigned) (dac
+ step
) <= 0x7F ) {
447 Synth_offset_inline( &this->synth
, time
, step
, output
);
453 if ( --bits_remain
== 0 )
456 if ( !this->buf_full
) {
457 this->silence
= true;
460 this->silence
= false;
462 this->buf_full
= false;
464 this->silence
= true;
465 Dmc_fill_buffer( this );
469 while ( time
< end_time
);
475 this->bits_remain
= bits_remain
;
477 osc
->delay
= time
- end_time
;
482 static 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
487 void Noise_clock_envelope( struct Nes_Noise
* this )
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
;
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;
503 int Noise_volume( struct Nes_Noise
* this )
505 struct Nes_Osc
* osc
= &this->osc
;
506 return osc
->length_counter
== 0 ? 0 : (osc
->regs
[0] & 0x10) ? (osc
->regs
[0] & 15) : this->envelope
;
509 void Noise_run( struct Nes_Noise
* this, nes_time_t time
, nes_time_t end_time
)
511 struct Nes_Osc
* osc
= &this->osc
;
512 int period
= noise_period_table
[osc
->regs
[2] & 15];
518 osc
->delay
= time
+ (end_time
- time
+ period
- 1) / period
* period
- end_time
;
522 Blip_set_modified( osc
->output
);
524 const int volume
= Noise_volume( this );
525 int amp
= (this->noise
& 1) ? volume
: 0;
527 int delta
= Osc_update_amp( osc
, amp
);
529 Synth_offset( &this->synth
, time
, delta
, osc
->output
);
533 if ( time
< end_time
)
535 const int mode_flag
= 0x80;
539 // round to next multiple of period
540 time
+= (end_time
- time
+ period
- 1) / period
* period
;
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);
551 struct Blip_Buffer
* const output
= osc
->output
;
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
);
557 int noise
= this->noise
;
558 int delta
= amp
* 2 - volume
;
559 const int tap
= (osc
->regs
[2] & mode_flag
? 8 : 13);
562 int feedback
= (noise
<< tap
) ^ (noise
<< 14);
565 if ( (noise
+ 1) & 2 ) {
566 // bits 0 and 1 of noise differ
568 Synth_offset_resampled( &this->synth
, rtime
, delta
, output
);
572 noise
= (feedback
& 0x4000) | (noise
>> 1);
574 while ( time
< end_time
);
576 osc
->last_amp
= (delta
+ volume
) >> 1;
581 osc
->delay
= time
- end_time
;