1 /*****************************************************************************
2 
3   MAME/MESS NES APU CORE
4 
5   Based on the Nofrendo/Nosefart NES N2A03 sound emulation core written by
6   Matthew Conte (matt@conte.com) and redesigned for use in MAME/MESS by
7   Who Wants to Know? (wwtk@mail.com)
8 
9   This core is written with the advise and consent of Matthew Conte and is
10   released under the GNU Public License.  This core is freely avaiable for
11   use in any freeware project, subject to the following terms:
12 
13   Any modifications to this code must be duly noted in the source and
14   approved by Matthew Conte and myself prior to public submission.
15 
16   timing notes:
17   master = 21477270
18   2A03 clock = master/12
19   sequencer = master/89490 or CPU/7457
20 
21  *****************************************************************************
22 
23    NES_APU.C
24 
25    Actual NES APU interface.
26 
27    LAST MODIFIED 02/29/2004
28 
29    - Based on Matthew Conte's Nofrendo/Nosefart core and redesigned to
30      use MAME system calls and to enable multiple APUs.  Sound at this
31      point should be just about 100% accurate, though I cannot tell for
32      certain as yet.
33 
34      A queue interface is also available for additional speed.  However,
35      the implementation is not yet 100% (DPCM sounds are inaccurate),
36      so it is disabled by default.
37 
38  *****************************************************************************
39 
40    BUGFIXES:
41 
42    - Various bugs concerning the DPCM channel fixed. (Oliver Achten)
43    - Fixed $4015 read behaviour. (Oliver Achten)
44 
45  *****************************************************************************/
46 
47 /*
48 	Ported from MAME 0.120
49 	01/02/14
50 */
51 
52 #include "burnint.h"
53 #include "m6502_intf.h"
54 #include "nes_apu.h"
55 #include "nes_defs.h"
56 
57 #define CHIP_NUM	2
58 
59 #define LEFT	0
60 #define RIGHT	1
61 
62 /* GLOBAL CONSTANTS */
63 #define  SYNCS_MAX1     0x20
64 #define  SYNCS_MAX2     0x80
65 
66 /* GLOBAL VARIABLES */
67 struct nesapu_info
68 {
69 	apu_t   APU;			       /* Actual APUs */
70 	float   apu_incsize;           /* Adjustment increment */
71 	UINT32 samps_per_sync;        /* Number of samples per vsync */
72 	UINT32 buffer_size;           /* Actual buffer size in bytes */
73 	UINT32 real_rate;             /* Actual playback rate */
74 	UINT8   noise_lut[NOISE_LONG]; /* Noise sample lookup table */
75 	UINT32 vbl_times[0x20];       /* VBL durations in samples */
76 	UINT32 sync_times1[SYNCS_MAX1]; /* Samples per sync table */
77 	UINT32 sync_times2[SYNCS_MAX2]; /* Samples per sync table */
78 
79 	// FBA-specific variables
80 	INT16 *stream;
81 	INT32 samples_per_frame;
82 	UINT32 (*pSyncCallback)(INT32 samples_per_frame);
83 	INT32 current_position;
84 	INT32 fill_buffer_hack;
85 	double gain[2];
86 	INT32 output_dir[2];
87 	INT32 bAdd;
88 };
89 
90 static nesapu_info nesapu_chips[CHIP_NUM];
91 
92 /* INTERNAL FUNCTIONS */
93 
94 /* INITIALIZE WAVE TIMES RELATIVE TO SAMPLE RATE */
create_vbltimes(UINT32 * table,const UINT8 * vbl,UINT32 rate)95 static void create_vbltimes(UINT32* table,const UINT8 *vbl,UINT32 rate)
96 {
97   INT32 i;
98 
99   for (i=0;i<0x20;i++)
100     table[i]=vbl[i]*rate;
101 }
102 
103 /* INITIALIZE SAMPLE TIMES IN TERMS OF VSYNCS */
create_syncs(struct nesapu_info * info,UINT64 sps)104 static void create_syncs(struct nesapu_info *info, UINT64 sps)
105 {
106   INT32 i;
107   UINT64 val=sps;
108 
109   for (i=0;i<SYNCS_MAX1;i++)
110   {
111     info->sync_times1[i]=val;
112     val+=sps;
113   }
114 
115   val=0;
116   for (i=0;i<SYNCS_MAX2;i++)
117   {
118     info->sync_times2[i]=val;
119     info->sync_times2[i]>>=2;
120     val+=sps;
121   }
122 }
123 
124 /* INITIALIZE NOISE LOOKUP TABLE */
create_noise(UINT8 * buf,const INT32 bits,INT32 size)125 static void create_noise(UINT8 *buf, const INT32 bits, INT32 size)
126 {
127    static INT32 m = 0x0011;
128    INT32 xor_val, i;
129 
130    for (i = 0; i < size; i++)
131    {
132       xor_val = m & 1;
133       m >>= 1;
134       xor_val ^= (m & 1);
135       m |= xor_val << (bits - 1);
136 
137       buf[i] = m;
138    }
139 }
140 
141 /* TODO: sound channels should *ALL* have DC volume decay */
142 
143 /* OUTPUT SQUARE WAVE SAMPLE (VALUES FROM -16 to +15) */
apu_square(struct nesapu_info * info,square_t * chan)144 static int8 apu_square(struct nesapu_info *info, square_t *chan)
145 {
146    INT32 env_delay;
147    INT32 sweep_delay;
148    int8 output;
149 
150    /* reg0: 0-3=volume, 4=envelope, 5=hold, 6-7=duty cycle
151    ** reg1: 0-2=sweep shifts, 3=sweep inc/dec, 4-6=sweep length, 7=sweep on
152    ** reg2: 8 bits of freq
153    ** reg3: 0-2=high freq, 7-4=vbl length counter
154    */
155 
156    if (false == chan->enabled)
157       return 0;
158 
159    /* enveloping */
160    env_delay = info->sync_times1[chan->regs[0] & 0x0F];
161 
162    /* decay is at a rate of (env_regs + 1) / 240 secs */
163    chan->env_phase -= 4;
164    while (chan->env_phase < 0)
165    {
166       chan->env_phase += env_delay;
167       if (chan->regs[0] & 0x20)
168          chan->env_vol = (chan->env_vol + 1) & 15;
169       else if (chan->env_vol < 15)
170          chan->env_vol++;
171    }
172 
173    /* vbl length counter */
174    if (chan->vbl_length > 0 && 0 == (chan->regs [0] & 0x20))
175       chan->vbl_length--;
176 
177    if (0 == chan->vbl_length)
178       return 0;
179 
180    /* freqsweeps */
181    if ((chan->regs[1] & 0x80) && (chan->regs[1] & 7))
182    {
183       sweep_delay = info->sync_times1[(chan->regs[1] >> 4) & 7];
184       chan->sweep_phase -= 2;
185       while (chan->sweep_phase < 0)
186       {
187          chan->sweep_phase += sweep_delay;
188          if (chan->regs[1] & 8)
189             chan->freq -= chan->freq >> (chan->regs[1] & 7);
190          else
191             chan->freq += chan->freq >> (chan->regs[1] & 7);
192       }
193    }
194 
195    if ((0 == (chan->regs[1] & 8) && (chan->freq >> 16) > freq_limit[chan->regs[1] & 7])
196        || (chan->freq >> 16) < 4)
197       return 0;
198 
199    chan->phaseacc -= (float) info->apu_incsize; /* # of cycles per sample */
200 
201    while (chan->phaseacc < 0)
202    {
203       chan->phaseacc += (chan->freq >> 16);
204       chan->adder = (chan->adder + 1) & 0x0F;
205    }
206 
207    if (chan->regs[0] & 0x10) /* fixed volume */
208       output = chan->regs[0] & 0x0F;
209    else
210       output = 0x0F - chan->env_vol;
211 
212    if (chan->adder < (duty_lut[chan->regs[0] >> 6]))
213       output = -output;
214 
215    return (int8) output;
216 }
217 
218 /* OUTPUT TRIANGLE WAVE SAMPLE (VALUES FROM -16 to +15) */
apu_triangle(struct nesapu_info * info,triangle_t * chan)219 static int8 apu_triangle(struct nesapu_info *info, triangle_t *chan)
220 {
221    INT32 freq;
222    int8 output;
223    /* reg0: 7=holdnote, 6-0=linear length counter
224    ** reg2: low 8 bits of frequency
225    ** reg3: 7-3=length counter, 2-0=high 3 bits of frequency
226    */
227 
228    if (false == chan->enabled)
229       return 0;
230 
231    if (false == chan->counter_started && 0 == (chan->regs[0] & 0x80))
232    {
233       if (chan->write_latency)
234          chan->write_latency--;
235       if (0 == chan->write_latency)
236          chan->counter_started = TRUE;
237    }
238 
239    if (chan->counter_started)
240    {
241       if (chan->linear_length > 0)
242          chan->linear_length--;
243       if (chan->vbl_length && 0 == (chan->regs[0] & 0x80))
244             chan->vbl_length--;
245 
246       if (0 == chan->vbl_length)
247          return 0;
248    }
249 
250    if (0 == chan->linear_length)
251       return 0;
252 
253    freq = (((chan->regs[3] & 7) << 8) + chan->regs[2]) + 1;
254 
255    if (freq < 4) /* inaudible */
256       return 0;
257 
258    chan->phaseacc -= (float) info->apu_incsize; /* # of cycles per sample */
259    while (chan->phaseacc < 0)
260    {
261       chan->phaseacc += freq;
262       chan->adder = (chan->adder + 1) & 0x1F;
263 
264       output = (chan->adder & 7) << 1;
265       if (chan->adder & 8)
266          output = 0x10 - output;
267       if (chan->adder & 0x10)
268          output = -output;
269 
270       chan->output_vol = output;
271    }
272 
273    return (int8) chan->output_vol;
274 }
275 
276 /* OUTPUT NOISE WAVE SAMPLE (VALUES FROM -16 to +15) */
apu_noise(struct nesapu_info * info,noise_t * chan)277 static int8 apu_noise(struct nesapu_info *info, noise_t *chan)
278 {
279    INT32 freq, env_delay;
280    UINT8 outvol;
281    UINT8 output;
282 
283    /* reg0: 0-3=volume, 4=envelope, 5=hold
284    ** reg2: 7=small(93 byte) sample,3-0=freq lookup
285    ** reg3: 7-4=vbl length counter
286    */
287 
288    if (false == chan->enabled)
289       return 0;
290 
291    /* enveloping */
292    env_delay = info->sync_times1[chan->regs[0] & 0x0F];
293 
294    /* decay is at a rate of (env_regs + 1) / 240 secs */
295    chan->env_phase -= 4;
296    while (chan->env_phase < 0)
297    {
298       chan->env_phase += env_delay;
299       if (chan->regs[0] & 0x20)
300          chan->env_vol = (chan->env_vol + 1) & 15;
301       else if (chan->env_vol < 15)
302          chan->env_vol++;
303    }
304 
305    /* length counter */
306    if (0 == (chan->regs[0] & 0x20))
307    {
308       if (chan->vbl_length > 0)
309          chan->vbl_length--;
310    }
311 
312    if (0 == chan->vbl_length)
313       return 0;
314 
315    freq = noise_freq[chan->regs[2] & 0x0F];
316    chan->phaseacc -= (float) info->apu_incsize; /* # of cycles per sample */
317    while (chan->phaseacc < 0)
318    {
319       chan->phaseacc += freq;
320 
321       chan->cur_pos++;
322       if (NOISE_SHORT == chan->cur_pos && (chan->regs[2] & 0x80))
323          chan->cur_pos = 0;
324       else if (NOISE_LONG == chan->cur_pos)
325          chan->cur_pos = 0;
326    }
327 
328    if (chan->regs[0] & 0x10) /* fixed volume */
329       outvol = chan->regs[0] & 0x0F;
330    else
331       outvol = 0x0F - chan->env_vol;
332 
333    output = info->noise_lut[chan->cur_pos];
334    if (output > outvol)
335       output = outvol;
336 
337    if (info->noise_lut[chan->cur_pos] & 0x80) /* make it negative */
338       output = -output;
339 
340    return (int8) output;
341 }
342 
343 /* RESET DPCM PARAMETERS */
apu_dpcmreset(dpcm_t * chan)344 static inline void apu_dpcmreset(dpcm_t *chan)
345 {
346    chan->address = 0xC000 + (uint16) (chan->regs[2] << 6);
347    chan->length = (uint16) (chan->regs[3] << 4) + 1;
348    chan->bits_left = chan->length << 3;
349    chan->irq_occurred = false;
350    chan->enabled = TRUE; /* Fixed * Proper DPCM channel ENABLE/DISABLE flag behaviour*/
351    chan->vol = 0; /* Fixed * DPCM DAC resets itself when restarted */
352 }
353 
354 /* OUTPUT DPCM WAVE SAMPLE (VALUES FROM -64 to +63) */
355 /* TODO: centerline naughtiness */
apu_dpcm(struct nesapu_info * info,dpcm_t * chan)356 static int8 apu_dpcm(struct nesapu_info *info, dpcm_t *chan)
357 {
358    INT32 freq, bit_pos;
359 
360    /* reg0: 7=irq gen, 6=looping, 3-0=pointer to clock table
361    ** reg1: output dc level, 7 bits unsigned
362    ** reg2: 8 bits of 64-byte aligned address offset : $C000 + (value * 64)
363    ** reg3: length, (value * 16) + 1
364    */
365 
366    if (chan->enabled)
367    {
368       freq = dpcm_clocks[chan->regs[0] & 0x0F];
369       chan->phaseacc -= (float) info->apu_incsize; /* # of cycles per sample */
370 
371       while (chan->phaseacc < 0)
372       {
373          chan->phaseacc += freq;
374 
375          if (0 == chan->length)
376          {
377             chan->enabled = false; /* Fixed * Proper DPCM channel ENABLE/DISABLE flag behaviour*/
378             chan->vol=0; /* Fixed * DPCM DAC resets itself when restarted */
379             if (chan->regs[0] & 0x40)
380                apu_dpcmreset(chan);
381             else
382             {
383                if (chan->regs[0] & 0x80) /* IRQ Generator */
384                {
385                   chan->irq_occurred = TRUE;
386                  n2a03_irq();
387                }
388                break;
389             }
390          }
391 
392 
393          chan->bits_left--;
394          bit_pos = 7 - (chan->bits_left & 7);
395          if (7 == bit_pos)
396          {
397             chan->cur_byte = M6502ReadByte(chan->address); //memory_read_byte(info->APU.dpcm.memory, chan->address);
398             chan->address++;
399             chan->length--;
400          }
401 
402          if (chan->cur_byte & (1 << bit_pos))
403 //            chan->regs[1]++;
404             chan->vol+=2; /* FIXED * DPCM channel only uses the upper 6 bits of the DAC */
405          else
406 //            chan->regs[1]--;
407             chan->vol-=2;
408       }
409    }
410 
411    if (chan->vol > 63)
412       chan->vol = 63;
413    else if (chan->vol < -64)
414       chan->vol = -64;
415 
416    return (int8) (chan->vol);
417 }
418 
419 /* WRITE REGISTER VALUE */
apu_regwrite(struct nesapu_info * info,INT32 address,UINT8 value)420 static inline void apu_regwrite(struct nesapu_info *info,INT32 address, UINT8 value)
421 {
422    INT32 chan = (address & 4) ? 1 : 0;
423 
424    switch (address)
425    {
426    /* squares */
427    case APU_WRA0:
428    case APU_WRB0:
429       info->APU.squ[chan].regs[0] = value;
430       break;
431 
432    case APU_WRA1:
433    case APU_WRB1:
434       info->APU.squ[chan].regs[1] = value;
435       break;
436 
437    case APU_WRA2:
438    case APU_WRB2:
439       info->APU.squ[chan].regs[2] = value;
440       if (info->APU.squ[chan].enabled)
441          info->APU.squ[chan].freq = ((((info->APU.squ[chan].regs[3] & 7) << 8) + value) + 1) << 16;
442       break;
443 
444    case APU_WRA3:
445    case APU_WRB3:
446       info->APU.squ[chan].regs[3] = value;
447 
448       if (info->APU.squ[chan].enabled)
449       {
450          info->APU.squ[chan].vbl_length = info->vbl_times[value >> 3];
451          info->APU.squ[chan].env_vol = 0;
452          info->APU.squ[chan].freq = ((((value & 7) << 8) + info->APU.squ[chan].regs[2]) + 1) << 16;
453       }
454 
455       break;
456 
457    /* triangle */
458    case APU_WRC0:
459       info->APU.tri.regs[0] = value;
460 
461       if (info->APU.tri.enabled)
462       {                                          /* ??? */
463          if (false == info->APU.tri.counter_started)
464             info->APU.tri.linear_length = info->sync_times2[value & 0x7F];
465       }
466 
467       break;
468 
469    case 0x4009:
470       /* unused */
471       info->APU.tri.regs[1] = value;
472       break;
473 
474    case APU_WRC2:
475       info->APU.tri.regs[2] = value;
476       break;
477 
478    case APU_WRC3:
479       info->APU.tri.regs[3] = value;
480 
481       /* this is somewhat of a hack.  there is some latency on the Real
482       ** Thing between when trireg0 is written to and when the linear
483       ** length counter actually begins its countdown.  we want to prevent
484       ** the case where the program writes to the freq regs first, then
485       ** to reg 0, and the counter accidentally starts running because of
486       ** the sound queue's timestamp processing.
487       **
488       ** set to a few NES sample -- should be sufficient
489       **
490       **     3 * (1789772.727 / 44100) = ~122 cycles, just around one scanline
491       **
492       ** should be plenty of time for the 6502 code to do a couple of table
493       ** dereferences and load up the other triregs
494       */
495 
496 	/* used to be 3, but now we run the clock faster, so base it on samples/sync */
497       info->APU.tri.write_latency = (info->samps_per_sync + 239) / 240;
498 
499       if (info->APU.tri.enabled)
500       {
501          info->APU.tri.counter_started = false;
502          info->APU.tri.vbl_length = info->vbl_times[value >> 3];
503          info->APU.tri.linear_length = info->sync_times2[info->APU.tri.regs[0] & 0x7F];
504       }
505 
506       break;
507 
508    /* noise */
509    case APU_WRD0:
510       info->APU.noi.regs[0] = value;
511       break;
512 
513    case 0x400D:
514       /* unused */
515       info->APU.noi.regs[1] = value;
516       break;
517 
518    case APU_WRD2:
519       info->APU.noi.regs[2] = value;
520       break;
521 
522    case APU_WRD3:
523       info->APU.noi.regs[3] = value;
524 
525       if (info->APU.noi.enabled)
526       {
527          info->APU.noi.vbl_length = info->vbl_times[value >> 3];
528          info->APU.noi.env_vol = 0; /* reset envelope */
529       }
530       break;
531 
532    /* DMC */
533    case APU_WRE0:
534       info->APU.dpcm.regs[0] = value;
535       if (0 == (value & 0x80))
536          info->APU.dpcm.irq_occurred = false;
537       break;
538 
539    case APU_WRE1: /* 7-bit DAC */
540       //info->APU.dpcm.regs[1] = value - 0x40;
541       info->APU.dpcm.regs[1] = value & 0x7F;
542       info->APU.dpcm.vol = (info->APU.dpcm.regs[1]-64);
543       break;
544 
545    case APU_WRE2:
546       info->APU.dpcm.regs[2] = value;
547       //apu_dpcmreset(info->APU.dpcm);
548       break;
549 
550    case APU_WRE3:
551       info->APU.dpcm.regs[3] = value;
552       break;
553 
554    case APU_IRQCTRL:
555    	break;
556 
557    case APU_SMASK:
558       if (value & 0x01)
559          info->APU.squ[0].enabled = TRUE;
560       else
561       {
562          info->APU.squ[0].enabled = false;
563          info->APU.squ[0].vbl_length = 0;
564       }
565 
566       if (value & 0x02)
567          info->APU.squ[1].enabled = TRUE;
568       else
569       {
570          info->APU.squ[1].enabled = false;
571          info->APU.squ[1].vbl_length = 0;
572       }
573 
574       if (value & 0x04)
575          info->APU.tri.enabled = TRUE;
576       else
577       {
578          info->APU.tri.enabled = false;
579          info->APU.tri.vbl_length = 0;
580          info->APU.tri.linear_length = 0;
581          info->APU.tri.counter_started = false;
582          info->APU.tri.write_latency = 0;
583       }
584 
585       if (value & 0x08)
586          info->APU.noi.enabled = TRUE;
587       else
588       {
589          info->APU.noi.enabled = false;
590          info->APU.noi.vbl_length = 0;
591       }
592 
593       if (value & 0x10)
594       {
595          /* only reset dpcm values if DMA is finished */
596          if (false == info->APU.dpcm.enabled)
597          {
598             info->APU.dpcm.enabled = TRUE;
599             apu_dpcmreset(&info->APU.dpcm);
600          }
601       }
602       else
603          info->APU.dpcm.enabled = false;
604 
605       info->APU.dpcm.irq_occurred = false;
606 
607       break;
608    default:
609 #ifdef MAME_DEBUG
610 logerror("invalid apu write: $%02X at $%04X\n", value, address);
611 #endif
612       break;
613    }
614 }
615 
616 /* UPDATE SOUND BUFFER USING CURRENT DATA */
apu_update(struct nesapu_info * info)617 static inline void apu_update(struct nesapu_info *info)
618 {
619    INT32 accum;
620 
621 //------------------------------------------------------------------------------------------------------
622 	if (info->pSyncCallback == NULL) return;
623 	INT32 position;
624 
625 	if (info->fill_buffer_hack) {
626 		position = info->samples_per_frame;
627 		info->fill_buffer_hack = 0;
628 	} else {
629 		position = info->pSyncCallback(info->samples_per_frame);
630 	}
631 
632 	if (position > info->samples_per_frame) position = info->samples_per_frame;
633 	if (position == info->current_position) return;
634 
635 	INT16 *buffer16 = info->stream + info->current_position;
636 
637 	INT32 samples = position - info->current_position;
638 
639 	info->current_position = position;
640 
641 	if (samples <= 0) return;
642 //------------------------------------------------------------------------------------------------------
643 
644    while (samples--)
645    {
646       accum = apu_square(info, &info->APU.squ[0]);
647       accum += apu_square(info, &info->APU.squ[1]);
648       accum += apu_triangle(info, &info->APU.tri);
649       accum += apu_noise(info, &info->APU.noi);
650       accum += apu_dpcm(info, &info->APU.dpcm);
651 
652       /* 8-bit clamps */
653       if (accum > 127)
654          accum = 127;
655       else if (accum < -128)
656          accum = -128;
657 
658       *(buffer16++)=accum<<8;
659    }
660 }
661 
662 /* READ VALUES FROM REGISTERS */
nesapuRead(INT32 chip,INT32 address)663 UINT8 nesapuRead(INT32 chip, INT32 address)
664 {
665 #if defined FBA_DEBUG
666 	if (!DebugSnd_NESAPUSndInitted) bprintf(PRINT_ERROR, _T("nesapuRead called without init\n"));
667 #endif
668 
669 	struct nesapu_info *info = &nesapu_chips[chip];
670 	if (address == 0x0f) /*FIXED* Address $4015 has different behaviour*/
671 	{
672 		INT32 readval = 0;
673 		if (info->APU.squ[0].vbl_length > 0)
674 			readval |= 0x01;
675 
676 		if (info->APU.squ[1].vbl_length > 0)
677 			readval |= 0x02;
678 
679 		if (info->APU.tri.vbl_length > 0)
680 			readval |= 0x04;
681 
682 		if (info->APU.noi.vbl_length > 0)
683 			readval |= 0x08;
684 
685 		if (info->APU.dpcm.enabled == TRUE)
686 			readval |= 0x10;
687 
688 		if (info->APU.dpcm.irq_occurred == TRUE)
689 			readval |= 0x80;
690 
691 		return readval;
692 	} else {
693 		return info->APU.regs[address];
694 	}
695 }
696 
697 /* WRITE VALUE TO TEMP REGISTRY AND QUEUE EVENT */
nesapuWrite(INT32 chip,INT32 address,UINT8 value)698 void nesapuWrite(INT32 chip, INT32 address, UINT8 value)
699 {
700 #if defined FBA_DEBUG
701 	if (!DebugSnd_NESAPUSndInitted) bprintf(PRINT_ERROR, _T("nesapuWrite called without init\n"));
702 #endif
703 
704 	struct nesapu_info *info = &nesapu_chips[chip]; //sndti_token(SOUND_NES, chip);
705 
706 	if (address > 0x17) return;
707 
708 	info->APU.regs[address]=value;
709 	apu_update(info);
710 	apu_regwrite(info,address,value);
711 }
712 
713 /* EXTERNAL INTERFACE FUNCTIONS */
714 
715 /* UPDATE APU SYSTEM */
nesapuUpdate(INT32 chip,INT16 * buf,INT32 samples)716 void nesapuUpdate(INT32 chip, INT16 *buf, INT32 samples)
717 {
718 #if defined FBA_DEBUG
719 	if (!DebugSnd_NESAPUSndInitted) bprintf(PRINT_ERROR, _T("nesapuUpdate called without init\n"));
720 #endif
721 
722 	struct nesapu_info *info = &nesapu_chips[chip];
723 
724 	if (pBurnSoundOut == NULL) {
725 		info->current_position = 0;
726 		return;
727 	}
728 
729 	info->fill_buffer_hack = 1;
730 	apu_update(info);
731 
732 	INT32 nAdd = info->bAdd;
733 	INT16 *stream = info->stream;
734 
735 	UINT32 step = (info->samples_per_frame << 12) / nBurnSoundLen;
736 	INT32 pos = 0;
737 
738 	for (INT32 i = 0; i < samples; i++) {
739 		if ((pos>>12) >= info->samples_per_frame) pos = (info->samples_per_frame-1) << 12;
740 
741 		INT16 output = stream[pos>>12];
742 
743 		/* write sound data to the buffer */
744 		INT32 nLeftSample = 0, nRightSample = 0;
745 
746 		if ((info->output_dir[BURN_SND_NESAPU_ROUTE_1] & BURN_SND_ROUTE_LEFT) == BURN_SND_ROUTE_LEFT) {
747 			nLeftSample += (INT32)((output / 6) * info->gain[BURN_SND_NESAPU_ROUTE_1]);
748 		}
749 		if ((info->output_dir[BURN_SND_NESAPU_ROUTE_1] & BURN_SND_ROUTE_RIGHT) == BURN_SND_ROUTE_RIGHT) {
750 			nRightSample += (INT32)((output / 6) * info->gain[BURN_SND_NESAPU_ROUTE_1]);
751 		}
752 		if ((info->output_dir[BURN_SND_NESAPU_ROUTE_2] & BURN_SND_ROUTE_LEFT) == BURN_SND_ROUTE_LEFT) {
753 			nLeftSample += (INT32)((output / 6) * info->gain[BURN_SND_NESAPU_ROUTE_2]);
754 		}
755 		if ((info->output_dir[BURN_SND_NESAPU_ROUTE_2] & BURN_SND_ROUTE_RIGHT) == BURN_SND_ROUTE_RIGHT) {
756 			nRightSample += (INT32)((output / 6) * info->gain[BURN_SND_NESAPU_ROUTE_2]);
757 		}
758 
759 		nLeftSample = BURN_SND_CLIP(nLeftSample);
760 		nRightSample = BURN_SND_CLIP(nRightSample);
761 
762 		if (nAdd) {
763 			buf[LEFT] += nLeftSample;
764 			buf[RIGHT] += nRightSample;
765 		} else {
766 			buf[LEFT] = nLeftSample;
767 			buf[RIGHT] = nRightSample;
768 		}
769 
770 		buf += 2;
771 		pos += step;
772 	}
773 
774 	info->current_position = 0;
775 	memset (info->stream, 0, info->samples_per_frame * sizeof(INT16));
776 }
777 
nesapuReset()778 void nesapuReset()
779 {
780 #if defined FBA_DEBUG
781 	if (!DebugSnd_NESAPUSndInitted) bprintf(PRINT_ERROR, _T("nesapuReset called without init\n"));
782 #endif
783 
784 	for (INT32 i = 0; i < CHIP_NUM; i++) {
785 		struct nesapu_info *info = &nesapu_chips[i];
786 
787 		info->current_position = 0;
788 		info->fill_buffer_hack = 0;
789 
790 		for (INT32 j = 0; j < 2; j++)
791 		{
792 			for (INT32 k = 0; k < 4; k++) {
793 				info->APU.squ[j].regs[k] = 0;
794 			}
795 			info->APU.squ[j].vbl_length = 0;
796 			info->APU.squ[j].freq = 0;
797 			info->APU.squ[j].phaseacc = 0;
798 			info->APU.squ[j].output_vol = 0;
799 			info->APU.squ[j].env_phase = 0;
800 			info->APU.squ[j].sweep_phase = 0;
801 			info->APU.squ[j].adder = 0;
802 			info->APU.squ[j].env_vol = 0;
803 			info->APU.squ[j].enabled = 0;
804 		}
805 
806 		for (INT32 k = 0; k < 4; k++) {
807 			info->APU.tri.regs[k] = 0;
808 		}
809 		info->APU.tri.linear_length = 0;
810 		info->APU.tri.vbl_length = 0;
811 		info->APU.tri.write_latency = 0;
812 		info->APU.tri.phaseacc = 0;
813 		info->APU.tri.output_vol = 0;
814 		info->APU.tri.adder = 0;
815 		info->APU.tri.counter_started = 0;
816 		info->APU.tri.enabled = 0;
817 		for (INT32 k = 0; k < 4; k++) {
818 			info->APU.noi.regs[k] = 0;
819 		}
820 		info->APU.noi.cur_pos = 0;
821 		info->APU.noi.vbl_length = 0;
822 		info->APU.noi.phaseacc = 0;
823 		info->APU.noi.output_vol = 0;
824 		info->APU.noi.env_phase = 0;
825 		info->APU.noi.env_vol = 0;
826 		info->APU.noi.enabled = 0;
827 		for (INT32 k = 0; k < 4; k++) {
828 			info->APU.dpcm.regs[k] = 0;
829 		}
830 		info->APU.dpcm.address = 0;
831 		info->APU.dpcm.length = 0;
832 		info->APU.dpcm.bits_left = 0;
833 		info->APU.dpcm.phaseacc = 0;
834 		info->APU.dpcm.output_vol = 0;
835 		info->APU.dpcm.cur_byte = 0;
836 		info->APU.dpcm.enabled = 0;
837 		info->APU.dpcm.irq_occurred = 0;
838 		info->APU.dpcm.vol = 0;
839 		for (INT32 k = 0; k < 17; k++) {
840 			info->APU.regs[k] = 0;
841 		}
842 		info->APU.buf_pos = 0;
843 	}
844 }
845 
846 /* INITIALIZE APU SYSTEM */
nesapuInit(INT32 chip,INT32 clock,UINT32 (* pSyncCallback)(INT32 samples_per_frame),INT32 bAdd)847 void nesapuInit(INT32 chip, INT32 clock, UINT32 (*pSyncCallback)(INT32 samples_per_frame), INT32 bAdd)
848 {
849 	DebugSnd_NESAPUSndInitted = 1;
850 
851 	struct nesapu_info *info = &nesapu_chips[chip];
852 	INT32 rate = clock / 4;
853 
854 	memset(info, 0, sizeof(nesapu_info));
855 
856 	/* Initialize global variables */
857 	info->samps_per_sync = (rate * 100) / nBurnFPS;
858 	info->buffer_size = info->samps_per_sync;
859 	info->real_rate = (info->samps_per_sync * nBurnFPS) / 100;
860 	info->apu_incsize = (float) (clock / (float) info->real_rate);
861 
862 	/* Use initializer calls */
863 	create_noise(info->noise_lut, 13, NOISE_LONG);
864 	create_vbltimes(info->vbl_times,vbl_length,info->samps_per_sync);
865 	create_syncs(info, info->samps_per_sync);
866 
867 	/* Adjust buffer size if 16 bits */
868 	info->buffer_size+=info->samps_per_sync;
869 
870 	info->samples_per_frame = (clock * 100) / 4 / nBurnFPS;
871 
872 	info->pSyncCallback = pSyncCallback;
873 
874 	info->bAdd = bAdd;
875 
876 	info->stream = NULL;
877 	info->stream = (INT16*)BurnMalloc(info->samples_per_frame * sizeof(INT16));
878 	info->gain[BURN_SND_NESAPU_ROUTE_1] = 1.00;
879 	info->gain[BURN_SND_NESAPU_ROUTE_2] = 1.00;
880 	info->output_dir[BURN_SND_NESAPU_ROUTE_1] = BURN_SND_ROUTE_BOTH;
881 	info->output_dir[BURN_SND_NESAPU_ROUTE_2] = BURN_SND_ROUTE_BOTH;
882 }
883 
nesapuSetRoute(INT32 nChip,INT32 nIndex,double nVolume,INT32 nRouteDir)884 void nesapuSetRoute(INT32 nChip, INT32 nIndex, double nVolume, INT32 nRouteDir)
885 {
886 #if defined FBA_DEBUG
887 	if (!DebugSnd_NESAPUSndInitted) bprintf(PRINT_ERROR, _T("nesapuSetRoute called without init\n"));
888 #endif
889 
890 	struct nesapu_info *info = &nesapu_chips[nChip];
891 
892 	info->gain[nIndex] = nVolume;
893 	info->output_dir[nIndex] = nRouteDir;
894 }
895 
nesapuExit()896 void nesapuExit()
897 {
898 #if defined FBA_DEBUG
899 	if (!DebugSnd_NESAPUSndInitted) bprintf(PRINT_ERROR, _T("nesapuExit called without init\n"));
900 #endif
901 
902 	if (!DebugSnd_NESAPUSndInitted) return;
903 
904 	struct nesapu_info *info;
905 	for (INT32 i = 0; i < CHIP_NUM; i++)
906 	{
907 		info = &nesapu_chips[i];
908 		if (info->stream)
909 			BurnFree(info->stream);
910 	}
911 
912 	DebugSnd_NESAPUSndInitted = 0;
913 }
914 
nesapuScan(INT32 nAction,INT32 *)915 void nesapuScan(INT32 nAction, INT32 *)
916 {
917 #if defined FBA_DEBUG
918 	if (!DebugSnd_NESAPUSndInitted) bprintf(PRINT_ERROR, _T("nesapuScan called without init\n"));
919 #endif
920 
921 	if (nAction & ACB_DRIVER_DATA)
922 	{
923 		for (INT32 i = 0; i < CHIP_NUM; i++)
924 		{
925 			struct nesapu_info *info = &nesapu_chips[i];
926 
927 			SCAN_VAR(info->APU.squ);
928 			SCAN_VAR(info->APU.tri);
929 			SCAN_VAR(info->APU.noi);
930 			SCAN_VAR(info->APU.dpcm);
931 			SCAN_VAR(info->APU.regs);
932 			SCAN_VAR(info->APU.buf_pos);
933 		}
934 	}
935 }
936