1 /* Festalon - NSF Player
2 * Copyright (C) 2004 Xodnizel
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19 #include <stdlib.h>
20 #include <string.h>
21
22 #include "../types.h"
23 #include "x6502.h"
24
25 #include "sound.h"
26 #include "nsf.h"
27 #include "../filter.h"
28
29 #define SQ_SHIFT 26
30 #define TRINPCM_SHIFT 18
31
32 static const int RectDuties[4]={1,2,4,6};
33
34 static const uint8 lengthtable[0x20]=
35 {
36 0x5*2,0x7f*2,0xA*2,0x1*2,0x14*2,0x2*2,0x28*2,0x3*2,0x50*2,0x4*2,0x1E*2,0x5*2,0x7*2,0x6*2,0x0E*2,0x7*2,
37 0x6*2,0x08*2,0xC*2,0x9*2,0x18*2,0xa*2,0x30*2,0xb*2,0x60*2,0xc*2,0x24*2,0xd*2,0x8*2,0xe*2,0x10*2,0xf*2
38 };
39
40 static const uint32 NoiseFreqTable[0x10]=
41 {
42 2,4,8,0x10,0x20,0x30,0x40,0x50,0x65,0x7f,0xbe,0xfe,0x17d,0x1fc,0x3f9,0x7f2
43 };
44
45 static const uint32 NTSCDMCTable[0x10]=
46 {
47 428,380,340,320,286,254,226,214,
48 190,160,142,128,106, 84 ,72,54
49 };
50
51 static const uint32 PALDMCTable[0x10]=
52 {
53 397, 353, 315, 297, 265, 235, 209, 198,
54 176, 148, 131, 118, 98, 78, 66, 50,
55 };
56
57 static void DoPCM(NESAPU *apu);
58 static void DoSQ1(NESAPU *apu);
59 static void DoSQ2(NESAPU *apu);
60 static void DoTriangle(NESAPU *apu);
61 static void DoNoise(NESAPU *apu);
62
LoadDMCPeriod(NESAPU * apu,uint8 V)63 static void LoadDMCPeriod(NESAPU *apu, uint8 V)
64 {
65 if(apu->X->PAL)
66 apu->DMCPeriod=PALDMCTable[V];
67 else
68 apu->DMCPeriod=NTSCDMCTable[V];
69 }
70
PrepDPCM(NESAPU * apu)71 static void PrepDPCM(NESAPU *apu)
72 {
73 apu->DMCAddress=0x4000+(apu->DMCAddressLatch<<6);
74 apu->DMCSize=(apu->DMCSizeLatch<<4)+1;
75 }
76
77 /* Instantaneous? Maybe the new freq value is being calculated all of the time... */
78
CheckFreq(uint32 cf,uint8 sr)79 static int FASTAPASS(2) CheckFreq(uint32 cf, uint8 sr)
80 {
81 uint32 mod;
82 if(!(sr&0x8))
83 {
84 mod=cf>>(sr&7);
85 if((mod+cf)&0x800)
86 return(0);
87 }
88 return(1);
89 }
90
SQReload(NESAPU * apu,int x,uint8 V)91 static void SQReload(NESAPU *apu, int x, uint8 V)
92 {
93 if(apu->EnabledChannels&(1<<x))
94 {
95 if(x)
96 DoSQ2(apu);
97 else
98 DoSQ1(apu);
99 apu->lengthcount[x]=lengthtable[(V>>3)&0x1f];
100 }
101
102 apu->sweepon[x]=apu->PSG[(x<<2)|1]&0x80;
103 apu->curfreq[x]=apu->PSG[(x<<2)|0x2]|((V&7)<<8);
104 apu->SweepCount[x]=((apu->PSG[(x<<2)|0x1]>>4)&7)+1;
105
106 apu->RectDutyCount[x]=7;
107 apu->EnvUnits[x].reloaddec=1;
108 }
109
DECLFW(Write_PSG)110 static DECLFW(Write_PSG)
111 {
112 NESAPU *apu=private;
113
114 A&=0x1F;
115
116 switch(A)
117 {
118 case 0x0:DoSQ1(apu);
119 apu->EnvUnits[0].Mode=(V&0x30)>>4;
120 apu->EnvUnits[0].Speed=(V&0xF);
121 break;
122 case 0x1:
123 apu->sweepon[0]=V&0x80;
124 break;
125 case 0x2:
126 DoSQ1(apu);
127 apu->curfreq[0]&=0xFF00;
128 apu->curfreq[0]|=V;
129 break;
130 case 0x3:
131 SQReload(apu,0,V);
132 break;
133 case 0x4:
134 DoSQ2(apu);
135 apu->EnvUnits[1].Mode=(V&0x30)>>4;
136 apu->EnvUnits[1].Speed=(V&0xF);
137 break;
138 case 0x5:
139 apu->sweepon[1]=V&0x80;
140 break;
141 case 0x6:DoSQ2(apu);
142 apu->curfreq[1]&=0xFF00;
143 apu->curfreq[1]|=V;
144 break;
145 case 0x7:
146 SQReload(apu,1,V);
147 break;
148 case 0xa:DoTriangle(apu);
149 break;
150 case 0xb:
151 DoTriangle(apu);
152 if(apu->EnabledChannels&0x4)
153 apu->lengthcount[2]=lengthtable[(V>>3)&0x1f];
154 apu->TriMode=1; // Load mode
155 break;
156 case 0xC:DoNoise(apu);
157 apu->EnvUnits[2].Mode=(V&0x30)>>4;
158 apu->EnvUnits[2].Speed=(V&0xF);
159 break;
160 case 0xE:DoNoise(apu);
161 break;
162 case 0xF:
163 DoNoise(apu);
164 if(apu->EnabledChannels&0x8)
165 apu->lengthcount[3]=lengthtable[(V>>3)&0x1f];
166 apu->EnvUnits[2].reloaddec=1;
167 break;
168 case 0x10:DoPCM(apu);
169 LoadDMCPeriod(apu,V&0xF);
170
171 if(apu->SIRQStat&0x80)
172 {
173 if(!(V&0x80))
174 {
175 X6502_IRQEnd(apu->X,FCEU_IQDPCM);
176 apu->SIRQStat&=~0x80;
177 }
178 else X6502_IRQBegin(apu->X,FCEU_IQDPCM);
179 }
180 break;
181 }
182 apu->PSG[A]=V;
183 }
184
DECLFW(Write_DMCRegs)185 static DECLFW(Write_DMCRegs)
186 {
187 NESAPU *apu=private;
188 A&=0xF;
189
190 switch(A)
191 {
192 case 0x00:DoPCM(apu);
193 LoadDMCPeriod(apu,V&0xF);
194
195 if(apu->SIRQStat&0x80)
196 {
197 if(!(V&0x80))
198 {
199 X6502_IRQEnd(apu->X,FCEU_IQDPCM);
200 apu->SIRQStat&=~0x80;
201 }
202 else X6502_IRQBegin(apu->X,FCEU_IQDPCM);
203 }
204 apu->DMCFormat=V;
205 break;
206 case 0x01:DoPCM(apu);
207 apu->RawDALatch=V&0x7F;
208 break;
209 case 0x02:apu->DMCAddressLatch=V;break;
210 case 0x03:apu->DMCSizeLatch=V;break;
211 }
212
213
214 }
215
DECLFW(StatusWrite)216 static DECLFW(StatusWrite)
217 {
218 NESAPU *apu=private;
219 int x;
220
221 DoSQ1(apu);
222 DoSQ2(apu);
223 DoTriangle(apu);
224 DoNoise(apu);
225 DoPCM(apu);
226 for(x=0;x<4;x++)
227 if(!(V&(1<<x))) apu->lengthcount[x]=0; /* Force length counters to 0. */
228
229 if(V&0x10)
230 {
231 if(!apu->DMCSize)
232 PrepDPCM(apu);
233 }
234 else
235 {
236 apu->DMCSize=0;
237 }
238 apu->SIRQStat&=~0x80;
239 X6502_IRQEnd(apu->X,FCEU_IQDPCM);
240 apu->EnabledChannels=V&0x1F;
241 }
242
DECLFR(StatusRead)243 static DECLFR(StatusRead)
244 {
245 NESAPU *apu=private;
246 int x;
247 uint8 ret;
248
249 ret=apu->SIRQStat;
250
251 for(x=0;x<4;x++) ret|=apu->lengthcount[x]?(1<<x):0;
252 if(apu->DMCSize) ret|=0x10;
253
254 apu->SIRQStat&=~0x40;
255 X6502_IRQEnd(apu->X,FCEU_IQFCOUNT);
256
257 return ret;
258 }
259
FrameSoundStuff(NESAPU * apu,int V)260 static void FASTAPASS(2) FrameSoundStuff(NESAPU *apu, int V)
261 {
262 int P;
263
264 DoSQ1(apu);
265 DoSQ2(apu);
266 DoNoise(apu);
267 DoTriangle(apu);
268
269 if(!(V&1)) /* Envelope decay, linear counter, length counter, freq sweep */
270 {
271 if(!(apu->PSG[8]&0x80))
272 if(apu->lengthcount[2]>0)
273 apu->lengthcount[2]--;
274
275 if(!(apu->PSG[0xC]&0x20)) /* Make sure loop flag is not set. */
276 if(apu->lengthcount[3]>0)
277 apu->lengthcount[3]--;
278
279 for(P=0;P<2;P++)
280 {
281 if(!(apu->PSG[P<<2]&0x20)) /* Make sure loop flag is not set. */
282 if(apu->lengthcount[P]>0)
283 apu->lengthcount[P]--;
284
285 /* Frequency Sweep Code Here */
286 /* xxxx 0000 */
287 /* xxxx = hz. 120/(x+1)*/
288 if(apu->sweepon[P])
289 {
290 int32 mod=0;
291
292 if(apu->SweepCount[P]>0) apu->SweepCount[P]--;
293 if(apu->SweepCount[P]<=0)
294 {
295 apu->SweepCount[P]=((apu->PSG[(P<<2)+0x1]>>4)&7)+1; //+1;
296 if(apu->PSG[(P<<2)+0x1]&0x8)
297 {
298 mod-=(P^1)+((apu->curfreq[P])>>(apu->PSG[(P<<2)+0x1]&7));
299 if(apu->curfreq[P] && (apu->PSG[(P<<2)+0x1]&7)/* && sweepon[P]&0x80*/)
300 {
301 apu->curfreq[P]+=mod;
302 }
303 }
304 else
305 {
306 mod=apu->curfreq[P]>>(apu->PSG[(P<<2)+0x1]&7);
307 if((mod+apu->curfreq[P])&0x800)
308 {
309 apu->sweepon[P]=0;
310 apu->curfreq[P]=0;
311 }
312 else
313 {
314 if(apu->curfreq[P] && (apu->PSG[(P<<2)+0x1]&7)/* && sweepon[P]&0x80*/)
315 {
316 apu->curfreq[P]+=mod;
317 }
318 }
319 }
320 }
321 }
322 else /* Sweeping is disabled: */
323 {
324 //curfreq[P]&=0xFF00;
325 //curfreq[P]|=apu->PSG[(P<<2)|0x2]; //|((apu->PSG[(P<<2)|3]&7)<<8);
326 }
327 }
328 }
329
330 /* Now do envelope decay + linear counter. */
331
332 if(apu->TriMode) // In load mode?
333 apu->TriCount=apu->PSG[0x8]&0x7F;
334 else if(apu->TriCount)
335 apu->TriCount--;
336
337 if(!(apu->PSG[0x8]&0x80))
338 apu->TriMode=0;
339
340 for(P=0;P<3;P++)
341 {
342 if(apu->EnvUnits[P].reloaddec)
343 {
344 apu->EnvUnits[P].decvolume=0xF;
345 apu->EnvUnits[P].DecCountTo1=apu->EnvUnits[P].Speed+1;
346 apu->EnvUnits[P].reloaddec=0;
347 continue;
348 }
349
350 if(apu->EnvUnits[P].DecCountTo1>0) apu->EnvUnits[P].DecCountTo1--;
351 if(apu->EnvUnits[P].DecCountTo1==0)
352 {
353 apu->EnvUnits[P].DecCountTo1=apu->EnvUnits[P].Speed+1;
354 if(apu->EnvUnits[P].decvolume || (apu->EnvUnits[P].Mode&0x2))
355 {
356 apu->EnvUnits[P].decvolume--;
357 apu->EnvUnits[P].decvolume&=0xF;
358 }
359 }
360 }
361 }
362
FrameSoundUpdate(NESAPU * apu)363 void FrameSoundUpdate(NESAPU *apu)
364 {
365 // Linear counter: Bit 0-6 of $4008
366 // Length counter: Bit 4-7 of $4003, $4007, $400b, $400f
367
368 if(!apu->fcnt && !(apu->IRQFrameMode&0x3))
369 {
370 apu->SIRQStat|=0x40;
371 X6502_IRQBegin(apu->X,FCEU_IQFCOUNT);
372 }
373
374 if(apu->fcnt==3)
375 {
376 if(apu->IRQFrameMode&0x2)
377 apu->fhcnt+=apu->fhinc;
378 }
379 FrameSoundStuff(apu, apu->fcnt);
380 apu->fcnt=(apu->fcnt+1)&3;
381 }
382
383
tester(NESAPU * apu)384 static INLINE void tester(NESAPU *apu)
385 {
386 if(apu->DMCBitCount==0)
387 {
388 if(!apu->DMCHaveDMA)
389 apu->DMCHaveSample=0;
390 else
391 {
392 apu->DMCHaveSample=1;
393 apu->DMCShift=apu->DMCDMABuf;
394 apu->DMCHaveDMA=0;
395 }
396 }
397 }
398
DMCDMA(NESAPU * apu)399 static INLINE void DMCDMA(NESAPU *apu)
400 {
401 if(apu->DMCSize && !apu->DMCHaveDMA)
402 {
403 X6502_DMR(apu->X,0x8000+apu->DMCAddress);
404 X6502_DMR(apu->X,0x8000+apu->DMCAddress);
405 X6502_DMR(apu->X,0x8000+apu->DMCAddress);
406 apu->DMCDMABuf=X6502_DMR(apu->X,0x8000+apu->DMCAddress);
407 apu->DMCHaveDMA=1;
408 apu->DMCAddress=(apu->DMCAddress+1)&0x7fff;
409 apu->DMCSize--;
410 if(!apu->DMCSize)
411 {
412 if(apu->DMCFormat&0x40)
413 PrepDPCM(apu);
414 else
415 {
416 apu->SIRQStat|=0x80;
417 if(apu->DMCFormat&0x80)
418 X6502_IRQBegin(apu->X,FCEU_IQDPCM);
419 }
420 }
421 }
422 }
423
FCEU_SoundCPUHook(void * private,int cycles)424 void FASTAPASS(2) FCEU_SoundCPUHook(void *private, int cycles)
425 {
426 NESAPU *apu=((FESTALON_NSF *)private)->apu;
427
428 apu->fhcnt-=cycles*48;
429 while(apu->fhcnt<=0)
430 {
431 int32 rest = apu->fhcnt / 48;
432 //printf("%8d:%8d\n",apu->X->timestamp,apu->X->timestamp+rest);
433 apu->X->timestamp+=rest; // Yet another ugly hack.
434 if(apu->X->timestamp < apu->lastpoo) puts("eep");
435 FrameSoundUpdate(apu);
436 apu->X->timestamp-=rest;
437 apu->fhcnt+=apu->fhinc;
438 }
439
440
441 DMCDMA(apu);
442 apu->DMCacc-=cycles;
443
444 while(apu->DMCacc<=0)
445 {
446 DMCDMA(apu);
447 if(apu->DMCHaveSample)
448 {
449 uint8 bah=apu->RawDALatch;
450 int t=((apu->DMCShift&1)<<2)-2;
451 int32 rest = apu->DMCacc;
452 /* Unbelievably ugly hack */
453 apu->X->timestamp+=rest;
454 //printf("%8d:%8d\n",apu->X->timestamp,apu->ChannelBC[4]);
455 DoPCM(apu);
456 apu->X->timestamp-=rest;
457 apu->RawDALatch+=t;
458 if(apu->RawDALatch&0x80)
459 apu->RawDALatch=bah;
460 }
461
462 apu->DMCacc+=apu->DMCPeriod;
463 apu->DMCBitCount=(apu->DMCBitCount+1)&7;
464 apu->DMCShift>>=1;
465 tester(apu);
466 }
467 }
468
DoPCM(NESAPU * apu)469 void DoPCM(NESAPU *apu)
470 {
471 if(!(apu->disabled&0x10))
472 {
473 int32 count;
474 int32 *D;
475 int32 out;
476
477 count = apu->X->timestamp - apu->ChannelBC[4];
478 D = &apu->WaveHi[apu->ChannelBC[4]];
479 out = apu->RawDALatch << TRINPCM_SHIFT;
480
481 while(count > 0)
482 {
483 *D += out;
484 D++;
485 count--;
486 }
487 //for(V=apu->ChannelBC[4];V<apu->X->timestamp;V++)
488 // apu->WaveHi[V]+=apu->RawDALatch<<TRINPCM_SHIFT;
489 }
490 apu->ChannelBC[4]=apu->X->timestamp;
491 }
492
493 /* This has the correct phase. Don't mess with it. */
DoSQ(NESAPU * apu,int x)494 static INLINE void DoSQ(NESAPU *apu, int x)
495 {
496 int32 V;
497 int32 amp;
498 int32 rthresh;
499 int32 *D;
500 int32 currdc;
501 int32 cf;
502 int32 rc;
503
504 if(apu->disabled&(1<<x))
505 goto endit;
506
507 if(apu->curfreq[x]<8 || apu->curfreq[x]>0x7ff)
508 goto endit;
509 if(!CheckFreq(apu->curfreq[x],apu->PSG[(x<<2)|0x1]))
510 goto endit;
511 if(!apu->lengthcount[x])
512 goto endit;
513
514 if(apu->EnvUnits[x].Mode&0x1)
515 amp=apu->EnvUnits[x].Speed;
516 else
517 amp=apu->EnvUnits[x].decvolume;
518 // printf("%d\n",amp);
519 amp<<=SQ_SHIFT;
520
521 rthresh=RectDuties[(apu->PSG[(x<<2)]&0xC0)>>6];
522
523 D=&apu->WaveHi[apu->ChannelBC[x]];
524 V=apu->X->timestamp-apu->ChannelBC[x];
525
526 currdc=apu->RectDutyCount[x];
527 cf=(apu->curfreq[x]+1)*2;
528 rc=apu->wlcount[x];
529
530 while(V>0)
531 {
532 if(currdc<rthresh)
533 *D+=amp;
534 rc--;
535 if(!rc)
536 {
537 int32 tmp;
538 rc=cf;
539 currdc=(currdc+1)&7;
540
541 tmp = rc - 1;
542 if((V-1) < rc) tmp = V - 1;
543
544 if(tmp > 0)
545 {
546 rc -= tmp;
547 if(currdc<rthresh)
548 {
549 do { *D += amp; V--; D++; tmp--; } while(tmp);
550 }
551 else
552 { V -= tmp; D+= tmp; }
553 }
554 }
555 V--;
556 D++;
557 }
558
559 apu->RectDutyCount[x]=currdc;
560 apu->wlcount[x]=rc;
561
562 endit:
563 apu->ChannelBC[x]=apu->X->timestamp;
564 }
565
DoSQ1(NESAPU * apu)566 static void DoSQ1(NESAPU *apu)
567 {
568 DoSQ(apu, 0);
569 }
570
DoSQ2(NESAPU * apu)571 static void DoSQ2(NESAPU *apu)
572 {
573 DoSQ(apu, 1);
574 }
575
DoTriangle(NESAPU * apu)576 static void DoTriangle(NESAPU *apu)
577 {
578 int32 V;
579 int32 tcout;
580
581 tcout=(apu->tristep&0xF);
582 if(!(apu->tristep&0x10)) tcout^=0xF;
583 tcout=tcout*3; //(tcout<<1);
584 tcout <<= TRINPCM_SHIFT;
585
586 if(apu->disabled&4)
587 {
588 apu->ChannelBC[2]=apu->X->timestamp;
589 return;
590 }
591
592 if(!apu->lengthcount[2] || !apu->TriCount)
593 { /* Counter is halted, but we still need to output. */
594 for(V=apu->ChannelBC[2];V<apu->X->timestamp;V++)
595 apu->WaveHi[V]+=tcout;
596 }
597 else
598 {
599 int32 wl = (apu->PSG[0xa]|((apu->PSG[0xb]&7)<<8))+1;
600 for(V=apu->ChannelBC[2];V<apu->X->timestamp;V++)
601 {
602 apu->WaveHi[V]+=tcout;
603 apu->wlcount[2]--;
604 if(!apu->wlcount[2])
605 {
606 apu->wlcount[2]=wl;
607 apu->tristep++;
608 tcout=(apu->tristep&0xF);
609 if(!(apu->tristep&0x10)) tcout^=0xF;
610 tcout=tcout*3;
611 tcout<<=TRINPCM_SHIFT;
612 }
613 }
614 }
615 apu->ChannelBC[2]=apu->X->timestamp;
616 }
617
DoNoise(NESAPU * apu)618 static void DoNoise(NESAPU *apu)
619 {
620 int32 V;
621 int32 outo;
622 uint32 amptab[2];
623 int32 wl;
624
625 if(apu->EnvUnits[2].Mode&0x1)
626 amptab[0]=apu->EnvUnits[2].Speed;
627 else
628 amptab[0]=apu->EnvUnits[2].decvolume;
629
630 amptab[0]<<=TRINPCM_SHIFT;
631 amptab[1]=0;
632
633 amptab[0]<<=1;
634
635 if(apu->disabled&8)
636 {
637 apu->ChannelBC[3]=apu->X->timestamp;
638 return;
639 }
640
641 outo=amptab[apu->nreg&1]; //(nreg>>0xe)&1];
642
643 if(!apu->lengthcount[3])
644 {
645 outo=amptab[0]=0;
646 }
647
648 wl = NoiseFreqTable[apu->PSG[0xE]&0xF]<<1;
649 if(apu->PSG[0xE]&0x80) // "short" noise
650 {
651 for(V=apu->ChannelBC[3];V<apu->X->timestamp;V++)
652 {
653 apu->WaveHi[V]+=outo;
654 apu->wlcount[3]--;
655 if(!apu->wlcount[3])
656 {
657 uint8 feedback;
658 apu->wlcount[3] = wl;
659 feedback=((apu->nreg>>8)&1)^((apu->nreg>>14)&1);
660 apu->nreg=(apu->nreg<<1)+feedback;
661 apu->nreg&=0x7fff;
662 outo=amptab[(apu->nreg>>0xe)&1];
663 }
664 }
665 }
666 else
667 for(V=apu->ChannelBC[3];V<apu->X->timestamp;V++)
668 {
669 apu->WaveHi[V]+=outo;
670 apu->wlcount[3]--;
671 if(!apu->wlcount[3])
672 {
673 uint8 feedback;
674 apu->wlcount[3]=wl;
675 feedback=((apu->nreg>>13)&1)^((apu->nreg>>14)&1);
676 apu->nreg=(apu->nreg<<1)+feedback;
677 apu->nreg&=0x7fff;
678 outo=amptab[(apu->nreg>>0xe)&1];
679 }
680 }
681 apu->ChannelBC[3]=apu->X->timestamp;
682 }
683
DECLFW(Write_IRQFM)684 static DECLFW(Write_IRQFM)
685 {
686 NESAPU *apu=private;
687
688 V=(V&0xC0)>>6;
689 apu->fcnt=0;
690 if(V&0x2)
691 FrameSoundUpdate(apu);
692 apu->fcnt=1;
693 apu->fhcnt=apu->fhinc;
694 X6502_IRQEnd(apu->X,FCEU_IQFCOUNT);
695 apu->SIRQStat&=~0x40;
696 apu->IRQFrameMode=V;
697 }
698
FCEUSND_FlushEmulate(NESAPU * apu)699 int FCEUSND_FlushEmulate(NESAPU *apu)
700 {
701 int x;
702 int32 end,left;
703
704 if(!apu->X->timestamp) return(0);
705
706 DoSQ1(apu);
707 DoSQ2(apu);
708 DoTriangle(apu);
709 DoNoise(apu);
710 DoPCM(apu);
711
712 {
713 for(x=0;x<apu->expcount;x++)
714 if(apu->exp[x]->HiFill) apu->exp[x]->HiFill(apu->exp[x]->private);
715
716 if(apu->ff->input_format == FFI_INT16)
717 {
718 int16 *tmpo=&((int16 *)apu->WaveHi)[apu->lastpoo];
719 uint32 *intmpo = &apu->WaveHi[apu->lastpoo];
720
721 if(apu->expcount)
722 for(x=apu->X->timestamp- apu->lastpoo;x;x--)
723 {
724 uint32 b=*intmpo;
725
726 *(int16 *)tmpo=(*intmpo & 0x3FFFF) + apu->wlookup2[(b>>TRINPCM_SHIFT)&255]+apu->wlookup1[b>>SQ_SHIFT] - 32768;
727 tmpo++;
728 intmpo++;
729 }
730 else
731 for(x=apu->X->timestamp- apu->lastpoo;x;x--)
732 {
733 uint32 b=*intmpo;
734 *(int16 *)tmpo=apu->wlookup2[(b>>TRINPCM_SHIFT)&255]+apu->wlookup1[b>>SQ_SHIFT] - 32768;
735 tmpo++;
736 intmpo++;
737 }
738 }
739 else
740 {
741 int32 *tmpo=&apu->WaveHi[apu->lastpoo];
742 if(apu->expcount)
743 for(x=apu->X->timestamp- apu->lastpoo;x;x--)
744 {
745 uint32 b=*tmpo;
746
747 *(float *)tmpo=(*tmpo & 0x3FFFF) + apu->wlookup2[(b>>TRINPCM_SHIFT)&255]+apu->wlookup1[b>>SQ_SHIFT];
748 tmpo++;
749 }
750 else
751 for(x=apu->X->timestamp- apu->lastpoo;x;x--)
752 {
753 uint32 b=*tmpo;
754 *(float *)tmpo=apu->wlookup2[(b>>TRINPCM_SHIFT)&255]+apu->wlookup1[b>>SQ_SHIFT];
755 tmpo++;
756 }
757 }
758 #ifdef MOO
759 {
760 int x;
761 static int osc=0;
762
763 if(apu->ff->input_format == FFI_INT16)
764 for(x=apu->lastpoo;x<apu->X->timestamp;x++) { ((int16 *)apu->WaveHi)[x] = (osc&64)*64; osc++; }
765 else
766 for(x=apu->lastpoo;x<apu->X->timestamp;x++) { *(float *)&apu->WaveHi[x] = (osc&64)*64; osc++; }
767 }
768 #endif
769 end=FESTAFILT_Do(apu->ff, (float *)apu->WaveHi,apu->WaveFinal,apu->WaveFinalLen, apu->X->timestamp,&left, 0);
770 if(apu->ff->input_format == FFI_INT16)
771 {
772 memmove(apu->WaveHi,(int16 *)apu->WaveHi+apu->X->timestamp-left,left*sizeof(uint16));
773 memset((int16 *)apu->WaveHi+left,0,sizeof(apu->WaveHi)-left*sizeof(uint16));
774 }
775 else
776 {
777 memmove(apu->WaveHi,apu->WaveHi+apu->X->timestamp-left,left*sizeof(uint32));
778 memset(apu->WaveHi+left,0,sizeof(apu->WaveHi)-left*sizeof(uint32));
779 }
780
781 for(x=0;x<apu->expcount;x++)
782 if(apu->exp[x]->HiFill) apu->exp[x]->HiSync(apu->exp[x]->private,left);
783 for(x=0;x<5;x++)
784 apu->ChannelBC[x]=left;
785 }
786
787 apu->X->timestampbase+=apu->X->timestamp;
788 apu->X->timestamp=left;
789 apu->X->timestampbase-=apu->X->timestamp;
790 apu->lastpoo=apu->X->timestamp;
791 apu->inbuf=end;
792
793 return(end);
794 }
795
796 /* FIXME: Find out what sound registers get reset on reset. I know $4001/$4005 don't,
797 due to that whole MegaMan 2 Game Genie thing.
798 */
799
FCEUSND_Reset(NESAPU * apu)800 void FCEUSND_Reset(NESAPU *apu)
801 {
802 int x;
803
804 apu->IRQFrameMode=0x0;
805 apu->fhcnt=apu->fhinc;
806 apu->fcnt=0;
807
808 apu->nreg=1;
809 for(x=0;x<2;x++)
810 {
811 apu->wlcount[x]=2048;
812 apu->sweepon[x]=0;
813 apu->curfreq[x]=0;
814 }
815 apu->wlcount[2]=1; //2048;
816 apu->wlcount[3]=2048;
817 apu->DMCHaveDMA=apu->DMCHaveSample=0;
818 apu->SIRQStat=0x00;
819
820 apu->RawDALatch=0x00;
821 apu->TriCount=0;
822 apu->TriMode=0;
823 apu->tristep=0;
824 apu->EnabledChannels=0;
825 for(x=0;x<4;x++)
826 apu->lengthcount[x]=0;
827
828 apu->DMCAddressLatch=0;
829 apu->DMCSizeLatch=0;
830 apu->DMCFormat=0;
831 apu->DMCAddress=0;
832 apu->DMCSize=0;
833 apu->DMCShift=0;
834 }
835
FCEUSND_Power(NESAPU * apu)836 void FCEUSND_Power(NESAPU *apu)
837 {
838 int x;
839
840 SetWriteHandler(apu->X,0x4000,0x400F,Write_PSG,apu);
841 SetWriteHandler(apu->X,0x4010,0x4013,Write_DMCRegs,apu);
842 SetWriteHandler(apu->X,0x4017,0x4017,Write_IRQFM,apu);
843
844 SetWriteHandler(apu->X,0x4015,0x4015,StatusWrite,apu);
845 SetReadHandler(apu->X,0x4015,0x4015,StatusRead,apu);
846
847 memset(apu->PSG,0x00,sizeof(apu->PSG));
848 FCEUSND_Reset(apu);
849
850 memset(apu->WaveHi,0,sizeof(apu->WaveHi));
851 memset(&apu->EnvUnits,0,sizeof(apu->EnvUnits));
852
853 for(x=0;x<5;x++)
854 apu->ChannelBC[x]=0;
855 apu->lastpoo=0;
856 LoadDMCPeriod(apu, apu->DMCFormat&0xF);
857 }
858
859
FCEUSND_Kill(NESAPU * apu)860 void FCEUSND_Kill(NESAPU *apu)
861 {
862 int x;
863
864 for(x=0;x<apu->expcount;x++)
865 {
866 if(apu->exp[x]->Kill) apu->exp[x]->Kill(apu->exp[x]->private);
867 free(apu->exp[x]);
868 }
869 if(apu->ff)
870 FESTAFILT_Kill(apu->ff);
871 if(apu->WaveFinal)
872 free(apu->WaveFinal);
873 free(apu->realmem);
874 }
875
876
FCEUSND_Init(X6502 * X)877 NESAPU *FCEUSND_Init(X6502 *X)
878 {
879 NESAPU *apu;
880 long x;
881 void *realmem;
882
883 if(!(apu=realmem=malloc(16 + sizeof(NESAPU))))
884 return(0);
885
886 apu = (NESAPU *)(unsigned long)(((unsigned long)apu+0xFLL)&~0xFLL);
887 memset(apu,0,sizeof(NESAPU));
888 apu->realmem = realmem;
889
890 apu->X=X;
891
892 apu->fhinc=X->PAL?16626:14915; // *2 CPU clock rate
893 apu->fhinc*=24;
894
895 apu->wlookup1[0]=0;
896 for(x=1;x<32;x++)
897 {
898 apu->wlookup1[x]=(double)16*16*16*4*95.52/((double)8128/(double)x+100);
899 }
900
901 apu->wlookup2[0]=0;
902 for(x=1;x<203;x++)
903 {
904 apu->wlookup2[x]=(double)16*16*16*4*163.67/((double)24329/(double)x+100);
905 }
906
907 LoadDMCPeriod(apu, apu->DMCFormat&0xF);
908
909 return(apu);
910 }
911
FCEUSND_Disable(NESAPU * apu,int d)912 void FCEUSND_Disable(NESAPU *apu, int d)
913 {
914 int x;
915
916 apu->disabled=d&0x1F;
917
918 d >>= 5;
919
920 for(x=0;x<apu->expcount;x++)
921 {
922 if(apu->exp[x]->Disable) apu->exp[x]->Disable(apu->exp[x]->private, d);
923 d >>= apu->exp[x]->Channels;
924 }
925 }
926
FCEUSND_AddExp(NESAPU * apu,EXPSOUND * exp)927 void FCEUSND_AddExp(NESAPU *apu, EXPSOUND *exp)
928 {
929 if(apu->expcount < 16)
930 apu->exp[apu->expcount++]=exp;
931 }
932
FESTANSF_SetVolume(FESTALON_NSF * fe,uint32 volume)933 void FESTANSF_SetVolume(FESTALON_NSF *fe, uint32 volume)
934 {
935 fe->apu->ff->SoundVolume=volume;
936 }
937
938
FESTANSF_SetLowpass(FESTALON_NSF * nfe,int on,uint32 corner,uint32 order)939 int FESTANSF_SetLowpass(FESTALON_NSF *nfe, int on, uint32 corner, uint32 order)
940 {
941 return(FESTAFILT_SetLowpass(nfe->apu->ff, on, corner, order));
942 }
943
FESTANSF_SetSound(FESTALON_NSF * nfe,uint32 rate,int quality)944 int FESTANSF_SetSound(FESTALON_NSF *nfe, uint32 rate, int quality)
945 {
946 if(nfe->apu->ff)
947 {
948 FESTAFILT_Kill(nfe->apu->ff);
949 nfe->apu->ff = 0;
950 }
951 if(!(nfe->apu->ff = FESTAFILT_Init(rate,nfe->X->PAL?PAL_CPU:NTSC_CPU, nfe->X->PAL, quality)))
952 return(0);
953
954 nfe->apu->WaveFinalLen = rate / (nfe->X->PAL?50:60) * 2; // * 2 for extra room
955 if(nfe->apu->WaveFinal) free(nfe->apu->WaveFinal);
956 if(!(nfe->apu->WaveFinal = malloc(sizeof(float) * nfe->apu->WaveFinalLen)))
957 return(0);
958
959 return(1);
960 }
961