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