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