1 /* FCE Ultra - NES/Famicom Emulator
3 * Copyright notice for this file:
4 * Copyright (C) 2002 Ben Parnell
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 /********************************************************/
24 /******* Sound emulation code and waveform synthesis */
25 /******* routines. A few ideas were inspired */
26 /******* by code from Marat Fayzullin's EMUlib */
28 /********************************************************/
43 uint32 Wave[2048+512];
44 int32 WaveHi[40000]; // unused
45 int16 WaveFinalMono[2048+512];
47 EXPSOUND GameExpSound={0,0,0,0,0,0};
52 static uint8 IRQFrameMode=0; /* $4017 / xx000000 */
54 static uint8 RawDALatch=0; /* $4011 0xxxxxxx */
56 uint8 EnabledChannels=0; /* Byte written to $4015 */
61 static int32 count[5];
62 static int32 sqacc[2]={0,0};
70 static int32 lengthcount[4];
74 static const uint8 Slengthtable[0x20]=
76 0x5,0x7f,0xA,0x1,0x14,0x2,0x28,0x3,0x50,0x4,0x1E,0x5,0x7,0x6,0x0E,0x7,
77 0x6,0x08,0xC,0x9,0x18,0xa,0x30,0xb,0x60,0xc,0x24,0xd,0x8,0xe,0x10,0xf
80 static uint32 lengthtable[0x20];
82 static const uint32 SNoiseFreqTable[0x10]=
84 2,4,8,0x10,0x20,0x30,0x40,0x50,0x65,0x7f,0xbe,0xfe,0x17d,0x1fc,0x3f9,0x7f2
86 static uint32 NoiseFreqTable[0x10];
93 static const uint8 NTSCPCMTable[0x10]=
95 0xd6,0xbe,0xaa,0xa0,0x8f,0x7f,0x71,0x6b,
96 0x5f,0x50,0x47,0x40,0x35,0x2a,0x24,0x1b
99 static const uint8 PALPCMTable[0x10]= // These values are just guessed.
101 0xc6,0xb0,0x9d,0x94,0x84,0x75,0x68,0x63,
102 0x58,0x4a,0x41,0x3b,0x31,0x27,0x21,0x19
105 static const uint32 NTSCDMCTable[0x10]=
107 428,380,340,320,286,254,226,214,
108 190,160,142,128,106, 84 ,72,54
111 /* Previous values for PAL DMC was value - 1,
112 * I am not certain if this is if FCEU handled
113 * PAL differently or not, the NTSC values are right,
114 * so I am assuming that the current value is handled
115 * the same way NTSC is handled. */
117 static const uint32 PALDMCTable[0x10]=
119 398, 354, 316, 298, 276, 236, 210, 198,
120 176, 148, 132, 118, 98, 78, 66, 50
124 // $4011 - Actual data outputted
125 // $4012 - Address register: $c000 + V*64
126 // $4013 - Size register: Size in bytes = (V+1)*64
132 uint8 DMCAddressLatch=0,DMCSizeLatch=0; /* writes to 4012 and 4013 */
133 uint8 DMCFormat=0; /* Write to $4010 */
135 static uint32 DMCAddress=0;
136 static int32 DMCSize=0;
137 static uint8 DMCShift=0;
138 static uint8 SIRQStat=0;
140 static char DMCHaveDMA=0;
141 static uint8 DMCDMABuf=0;
142 char DMCHaveSample=0;
146 static void Dummyfunc(int end) {};
148 static void (*DoNoise)(int end)=Dummyfunc;
149 static void (*DoTriangle)(int end)=Dummyfunc;
150 static void (*DoPCM)(int end)=Dummyfunc;
151 static void (*DoSQ1)(int end)=Dummyfunc;
152 static void (*DoSQ2)(int end)=Dummyfunc;
154 uint8 sweepon[2]={0,0};
155 int32 curfreq[2]={0,0};
158 uint8 DecCountTo1[3];
166 /* Instantaneous? Maybe the new freq value is being calculated all of the time... */
167 static int FASTAPASS(2) CheckFreq(uint32 cf, uint8 sr)
179 static uint8 DutyCount[2]={0,0};
181 static void LoadDMCPeriod(uint8 V)
184 DMCPeriod=PALDMCTable[V];
186 DMCPeriod=NTSCDMCTable[V];
189 static void PrepDPCM()
191 DMCAddress=0x4000+(DMCAddressLatch<<6);
192 DMCSize=(DMCSizeLatch<<4)+1;
195 static void SQReload(int x, uint8 V)
197 if(EnabledChannels&(1<<x))
203 lengthcount[x]=lengthtable[(V>>3)&0x1f];
207 sweepon[x]=PSG[(x<<2)|1]&0x80;
208 curfreq[x]=PSG[(x<<2)|0x2]|((V&7)<<8);
210 SweepCount[x]=((PSG[(x<<2)|0x1]>>4)&7)+1;
212 sqacc[x]=((int32)curfreq[0]+1)<<18;
214 //RectDutyCount[x]=7;
215 //EnvUnits[x].reloaddec=1;
219 static DECLFW(Write_PSG)
221 //if((A>=0x4004 && A<=0x4007) || A==0x4015)
222 //printf("$%04x:$%02x, %d\n",A,V,SOUNDTS);
270 case 0xa:DoTriangle(0);
273 if(EnabledChannels&0x4)
277 lengthcount[2]=lengthtable[(V>>3)&0x1f];
280 tricoop=PSG[0x8]&0x7f;
281 trimode=PSG[0x8]&0x80;
287 case 0xE:DoNoise(0);break;
289 if(EnabledChannels&8)
293 lengthcount[3]=lengthtable[(V>>3)&0x1f];
296 DecCountTo1[2]=(PSG[0xC]&0xF)+1;
302 static DECLFW(Write_DMCRegs)
309 LoadDMCPeriod(V&0xF);
315 X6502_IRQEnd(FCEU_IQDPCM);
318 else X6502_IRQBegin(FCEU_IQDPCM);
325 case 0x02:DMCAddressLatch=V;break;
326 case 0x03:DMCSizeLatch=V;break;
330 static DECLFW(StatusWrite)
333 int32 end=(SOUNDTS<<16)/soundtsinc;
334 int t=V^EnabledChannels;
348 if(!(V&(1<<x))) lengthcount[x]=0; /* Force length counters to 0. */
360 X6502_IRQEnd(FCEU_IQDPCM);
361 EnabledChannels=V&0x1F;
371 //for(x=0;x<4;x++) ret|=lengthcount[x]?(1<<x):0;
372 ret|=EnabledChannels&sqnon;
373 if(DMCSize) ret|=0x10;
375 #ifdef FCEUDEF_DEBUGGER
380 X6502_IRQEnd(FCEU_IQFCOUNT);
385 static void FASTAPASS(1) FrameSoundStuff(int V)
388 uint32 end = (SOUNDTS<<16)/soundtsinc;
396 case 1: /* Envelope decay, linear counter, length counter, freq sweep */
397 if(EnabledChannels&4 && sqnon&4)
403 if(lengthcount[2]<=0)
413 if(EnabledChannels&(P+1) && sqnon&(P+1))
415 if(!(PSG[P<<2]&0x20))
420 if(lengthcount[P]<=0)
427 /* Frequency Sweep Code Here */
429 /* xxxx = hz. 120/(x+1)*/
434 if(SweepCount[P]>0) SweepCount[P]--;
437 SweepCount[P]=((PSG[(P<<2)+0x1]>>4)&7)+1; //+1;
439 if(PSG[(P<<2)+0x1]&0x8)
441 mod-=(P^1)+((curfreq[P])>>(PSG[(P<<2)+0x1]&7));
443 if(curfreq[P] && (PSG[(P<<2)+0x1]&7)/* && sweepon[P]&0x80*/)
450 mod=curfreq[P]>>(PSG[(P<<2)+0x1]&7);
451 if((mod+curfreq[P])&0x800)
458 if(curfreq[P] && (PSG[(P<<2)+0x1]&7)/* && sweepon[P]&0x80*/)
469 if(EnabledChannels&0x8 && sqnon&8)
476 if(lengthcount[3]<=0)
484 case 0: /* Envelope decay + linear counter */
490 if(tricoop==1) DoTriangle(0);
497 if(DecCountTo1[P]>0) DecCountTo1[P]--;
498 if(DecCountTo1[P]<=0)
500 DecCountTo1[P]=(PSG[P<<2]&0xF)+1;
501 if(decvolume[P] || PSG[P<<2]&0x20)
504 /* Step from 0 to full volume seems to take twice as long
505 as the other steps. I don't know if this is the correct
506 way to double its length, though(or if it even matters).
508 if((PSG[P<<2]&0x20) && (decvolume[P]==0))
513 if(!(PSG[P<<2]&0x10))
514 realvolume[P]=decvolume[P];
517 if(DecCountTo1[2]>0) DecCountTo1[2]--;
518 if(DecCountTo1[2]<=0)
520 DecCountTo1[2]=(PSG[0xC]&0xF)+1;
521 if(decvolume[2] || PSG[0xC]&0x20)
524 /* Step from 0 to full volume seems to take twice as long
525 as the other steps. I don't know if this is the correct
526 way to double its length, though(or if it even matters).
528 if((PSG[0xC]&0x20) && (decvolume[2]==0))
534 realvolume[2]=decvolume[2];
541 void FrameSoundUpdate(void)
543 // Linear counter: Bit 0-6 of $4008
544 // Length counter: Bit 4-7 of $4003, $4007, $400b, $400f
546 if(!fcnt && !(IRQFrameMode&0x3))
549 X6502_IRQBegin(FCEU_IQFCOUNT);
557 FrameSoundStuff(fcnt);
561 static INLINE void tester(void)
576 static uint32 ChannelBC[5];
578 static uint32 RectAmp[2][8];
580 static void FASTAPASS(1) CalcRectAmp(int P)
582 static int tal[4]={1,2,4,6};
585 uint32 *b=RectAmp[P];
590 //V=(PSG[P<<2]&15)<<4;
592 // V=decvolume[P]<<4;
593 m=tal[(PSG[P<<2]&0xC0)>>6];
600 static INLINE void DMCDMA(void)
602 if(DMCSize && !DMCHaveDMA)
605 X6502_DMR(0x8000+DMCAddress);
606 X6502_DMR(0x8000+DMCAddress);
607 X6502_DMR(0x8000+DMCAddress);
608 DMCDMABuf=X6502_DMR(0x8000+DMCAddress);
611 DMCDMABuf=X.DB=ARead[0x8000+DMCAddress](0x8000+DMCAddress);
614 DMCAddress=(DMCAddress+1)&0x7fff;
624 X6502_IRQBegin(FCEU_IQDPCM);
630 void FCEU_SoundCPUHook(int cycles48)
646 uint8 bah=RawDALatch;
647 int t=((DMCShift&1)<<2)-2;
649 /* Unbelievably ugly hack */
650 if(FSettings.SndRate)
662 DMCBitCount=(DMCBitCount+1)&7;
668 static void RDoPCM(int32 end)
674 if(end==0) end=(SOUNDTS<<16)/soundtsinc;
675 if(end<=start) return;
678 for(V=start;V<end;V++)
679 //WaveHi[V]+=(((RawDALatch<<16)/256) * FSettings.PCMVolume)&(~0xFFFF); // TODO get rid of floating calculations to binary. set log volume scaling.
680 Wave[V>>4]+=RawDALatch<<3;
683 static void RDoSQ1(int32 end)
690 if(end==0) end=(SOUNDTS<<16)/soundtsinc;
691 if(end<=start) return;
694 if(!(EnabledChannels&1 && sqnon&1))
697 if(curfreq[0]<8 || curfreq[0]>0x7ff)
699 if(!CheckFreq(curfreq[0],PSG[0x1]))
705 uint32 out=RectAmp[0][DutyCount[0]];
709 for(V=start;V<end;V++)
712 sqacc[0]-=nesincsize;
718 if(sqacc[0]<=0) goto rea;
721 out=RectAmp[0][DutyCount[0]];
728 static void RDoSQ2(int32 end)
735 if(end==0) end=(SOUNDTS<<16)/soundtsinc;
736 if(end<=start) return;
739 if(!(EnabledChannels&2 && sqnon&2))
742 if(curfreq[1]<8 || curfreq[1]>0x7ff)
744 if(!CheckFreq(curfreq[1],PSG[0x5]))
750 uint32 out=RectAmp[1][DutyCount[1]];
755 for(V=start;V<end;V++)
758 sqacc[1]-=nesincsize;
764 if(sqacc[1]<=0) goto rea;
767 out=RectAmp[1][DutyCount[1]];
775 static void RDoTriangle(int32 end)
777 static uint32 tcout=0;
779 int32 start; //,freq;
780 int32 freq=(((PSG[0xa]|((PSG[0xb]&7)<<8))+1));
783 if(end==0) end=(SOUNDTS<<16)/soundtsinc;
784 if(end<=start) return;
787 if(! (EnabledChannels&0x4 && sqnon&4 && tricoop) )
788 { // Counter is halted, but we still need to output.
789 for(V=start;V<end;V++)
792 else if(freq<=4) // 55.9Khz - Might be barely audible on a real NES, but
793 // it's too costly to generate audio at this high of a frequency
794 // (55.9Khz * 32 for the stepping).
795 // The same could probably be said for ~27.8Khz, so we'll
796 // take care of that too. We'll just output the average
797 // value(15/2 - scaled properly for our output format, of course).
798 // We'll also take care of ~18Khz and ~14Khz too, since they should be barely audible.
799 // (Some proof or anything to confirm/disprove this would be nice.).
801 for(V=start;V<end;V++)
802 Wave[V>>4]+=((0xF<<4)+(0xF<<2))>>1;
806 static int32 triacc=0;
810 for(V=start;V<end;V++)
818 if(triacc<=0) goto rea;
821 if(tc&0x10) tcout^=0xF;
822 tcout=(tcout<<4)+(tcout<<2);
829 static void RDoNoise(int32 end)
835 if(end==0) end=(SOUNDTS<<16)/soundtsinc;
836 if(end<=start) return;
839 if(EnabledChannels&0x8 && sqnon&8)
845 amplitude=realvolume[2];
847 // amplitude=(PSG[0xC]&0xF);
849 // amplitude=decvolume[2]&0xF;
851 inc=NoiseFreqTable[PSG[0xE]&0xF];
852 amptab[0]=((amplitude<<2)+amplitude+amplitude)<<1;
858 if(PSG[0xE]&0x80) // "short" noise
859 for(V=start;V<end;V++)
866 feedback=((nreg>>8)&1)^((nreg>>14)&1);
867 nreg=(nreg<<1)+feedback;
875 for(V=start;V<end;V++)
882 feedback=((nreg>>13)&1)^((nreg>>14)&1);
883 nreg=(nreg<<1)+feedback;
902 X6502_IRQEnd(FCEU_IQFCOUNT);
907 void SetNESSoundMap(void)
909 SetWriteHandler(0x4000,0x400F,Write_PSG);
910 SetWriteHandler(0x4010,0x4013,Write_DMCRegs);
911 SetWriteHandler(0x4017,0x4017,Write_IRQFM);
913 SetWriteHandler(0x4015,0x4015,StatusWrite);
914 SetReadHandler(0x4015,0x4015,StatusRead);
917 int32 highp; // 0 through 65536, 0 = no high pass, 65536 = max high pass
919 int32 lowp; // 0 through 65536, 65536 = max low pass(total attenuation)
920 // 65536 = no low pass
921 static int32 flt_acc=0, flt_acc2=0;
923 static void FilterSound(uint32 *in, int16 *outMono, int count)
925 // static int min=0, max=0;
927 if (soundvol < 5) sh += 5 - soundvol;
929 for(;count;count--,in++,outMono++)
933 diff = *in - flt_acc;
935 flt_acc += (diff*highp)>>16;
936 flt_acc2+= (int32) (((int64)((diff-flt_acc2)*lowp))>>16);
939 *outMono = flt_acc2*7 >> sh; // * 7 >> 2 = * 1.75
940 // if (acc2 < min) { printf("min: %i %04x\n", acc2, acc2); min = acc2; }
941 // if (acc2 > max) { printf("max: %i %04x\n", acc2, acc2); max = acc2; }
947 static int32 inbuf=0;
948 int FlushEmulateSound(void)
953 if(!timestamp) return(0);
955 if(!FSettings.SndRate || (soundvol == 0))
961 end=(SOUNDTS<<16)/soundtsinc;
968 if(GameExpSound.Fill)
969 GameExpSound.Fill(end&0xF);
971 FilterSound(Wave,WaveFinalMono,end>>4);
974 Wave[0]=Wave[(end>>4)];
979 ChannelBC[x]=end&0xF;
980 soundtsoffs=(soundtsinc*(end&0xF))>>16;
986 int GetSoundBuffer(int16 **W)
992 void FCEUSND_Power(void)
997 memset(PSG,0x00,sizeof(PSG));
1000 memset(Wave,0,sizeof(Wave));
1001 memset(WaveHi,0,sizeof(WaveHi));
1002 //memset(&EnvUnits,0,sizeof(EnvUnits));
1007 LoadDMCPeriod(DMCFormat&0xF);
1010 void FCEUSND_Reset(void)
1014 if(x!=1 && x!=5 && x!=0x14) BWrite[0x4000+x](0x4000+x,0);
1021 DMCHaveDMA=DMCHaveSample=0;
1042 void SetSoundVariables(void)
1046 fhinc=PAL?16626:14915; // *2 CPU clock rate
1049 lengthtable[x]=Slengthtable[x]<<1;
1051 if(FSettings.SndRate)
1054 DoTriangle=RDoTriangle;
1061 DoNoise=DoTriangle=DoPCM=DoSQ1=DoSQ2=Dummyfunc;
1064 if(!FSettings.SndRate) return;
1065 if(GameExpSound.RChange)
1066 GameExpSound.RChange();
1068 // nesincsizeLL=(int64)((int64)562949953421312*(double)(PAL?PAL_CPU:NTSC_CPU)/(FSettings.SndRate OVERSAMPLE));
1069 nesincsize=(int32)(((int64)1<<17)*(double)(PAL?PAL_CPU:NTSC_CPU)/(FSettings.SndRate * 16)); // 308845 - 1832727
1070 PSG_base=(uint32)(PAL?(long double)PAL_CPU/16:(long double)NTSC_CPU/16);
1075 z=SNoiseFreqTable[x]<<1;
1076 z=(PAL?PAL_CPU:NTSC_CPU)/z;
1077 z=(long double)((uint32)((FSettings.SndRate OVERSAMPLE)<<12))/z;
1078 NoiseFreqTable[x]=z;
1080 soundtsinc=(uint32)((uint64)(PAL?(long double)PAL_CPU*65536:(long double)NTSC_CPU*65536)/(FSettings.SndRate OVERSAMPLE));
1081 memset(Wave,0,sizeof(Wave));
1084 highp=(250<<16)/FSettings.SndRate; // Arbitrary
1085 lowp=(25000<<16)/FSettings.SndRate; // Arbitrary
1087 if(highp>(1<<16)) highp=1<<16;
1088 if(lowp>(1<<16)) lowp=1<<16;
1093 void FixOldSaveStateSFreq(void)
1098 curfreq[x]=PSG[0x2+(x<<2)]|((PSG[0x3+(x<<2)]&7)<<8);
1102 void FCEUI_Sound(int Rate)
1104 FSettings.SndRate=Rate;
1105 SetSoundVariables();
1108 void FCEUI_SetSoundVolume(uint32 volume)
1110 FSettings.SoundVolume=volume;
1113 SFORMAT FCEUSND_STATEINFO[]={
1114 { &fhcnt, 4|FCEUSTATE_RLSB,"FHCN"},
1115 { &fcnt, 1, "FCNT"},
1116 { PSG, 0x10, "PSG"},
1117 { &EnabledChannels, 1, "ENCH"},
1118 { &IRQFrameMode, 1, "IQFM"},
1120 { decvolume, 3, "DECV"},
1121 { &sqnon, 1, "SQNO"},
1122 { &nreg, 2|RLSB, "NREG"},
1123 { &trimode, 1, "TRIM"},
1124 { &tricoop, 1, "TRIC"},
1125 { DecCountTo1, 3,"DCT1"},
1127 { sweepon, 2, "SWEE"},
1128 { &curfreq[0], 4|FCEUSTATE_RLSB,"CRF1"},
1129 { &curfreq[1], 4|FCEUSTATE_RLSB,"CRF2"},
1130 { SweepCount, 2,"SWCT"},
1132 { &SIRQStat, 1, "SIRQ"},
1134 { &DMCacc, 4|FCEUSTATE_RLSB, "5ACC"},
1135 { &DMCBitCount, 1, "5BIT"},
1136 { &DMCAddress, 4|FCEUSTATE_RLSB, "5ADD"},
1137 { &DMCSize, 4|FCEUSTATE_RLSB, "5SIZ"},
1138 { &DMCShift, 1, "5SHF"},
1140 { &DMCHaveDMA, 1, "5HVDM"},
1141 { &DMCHaveSample, 1, "5HVSP"},
1143 { &DMCSizeLatch, 1, "5SZL"},
1144 { &DMCAddressLatch, 1, "5ADL"},
1145 { &DMCFormat, 1, "5FMT"},
1146 { &RawDALatch, 1, "RWDA"},
1150 void FCEUSND_SaveState(void)
1155 void FCEUSND_LoadState(int version)
1157 LoadDMCPeriod(DMCFormat&0xF);