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 /********************************************************/
46 int32 WaveFinal[2048];
47 int16 WaveFinalMono[2048];
49 EXPSOUND GameExpSound={0,0,0};
58 static int32 count[5];
59 static int64 sqacc[2]={0,0};
71 static const uint8 Slengthtable[0x20]=
73 0x5,0x7f,0xA,0x1,0x14,0x2,0x28,0x3,0x50,0x4,0x1E,0x5,0x7,0x6,0x0E,0x7,
74 0x6,0x08,0xC,0x9,0x18,0xa,0x30,0xb,0x60,0xc,0x24,0xd,0x8,0xe,0x10,0xf
77 static uint32 lengthtable[0x20];
79 static const uint32 SNoiseFreqTable[0x10]=
81 2,4,8,0x10,0x20,0x30,0x40,0x50,0x65,0x7f,0xbe,0xfe,0x17d,0x1fc,0x3f9,0x7f2
83 static uint32 NoiseFreqTable[0x10];
88 static const uint8 NTSCPCMTable[0x10]=
90 0xd6,0xbe,0xaa,0xa0,0x8f,0x7f,0x71,0x6b,
91 0x5f,0x50,0x47,0x40,0x35,0x2a,0x24,0x1b
94 static const uint8 PALPCMTable[0x10]= // These values are just guessed.
96 0xc6,0xb0,0x9d,0x94,0x84,0x75,0x68,0x63,
97 0x58,0x4a,0x41,0x3b,0x31,0x27,0x21,0x19
103 // $4011 - Actual data outputted
104 // $4012 - Address register: $c000 + V*64
105 // $4013 - Size register: Size in bytes = (V+1)*64
108 static int64 PCMacc=0;
112 uint32 PCMAddressIndex=0;
113 int32 PCMSizeIndex=0;
117 static void Dummyfunc(void) {};
119 static void (*DoNoise)(void)=Dummyfunc;
120 static void (*DoTriangle)(void)=Dummyfunc;
121 static void (*DoPCM)(void)=Dummyfunc;
122 static void (*DoSQ1)(void)=Dummyfunc;
123 static void (*DoSQ2)(void)=Dummyfunc;
125 static void CalcDPCMIRQ(void)
132 freq=(PALPCMTable[PSG[0x10]&0xF]<<4);
134 freq=(NTSCPCMTable[PSG[0x10]&0xF]<<4);
136 cycles=(((PSG[0x13]<<4)+1));
138 honk=((PSG[0x13]<<4)+1)*freq;
141 //else honk/=(double)113.66666666;
143 //PCMIRQCount=honk*3; //180;
144 //if(PAL) PCMIRQCount*=.93;
148 static void PrepDPCM()
150 PCMAddressIndex=0x4000+(PSG[0x12]<<6);
151 PCMSizeIndex=(PSG[0x13]<<4)+1;
153 //PCMBuffer=ARead[0x8000+PCMAddressIndex](0x8000+PCMAddressIndex);
155 PCMfreq=PALPCMTable[PSG[0x10]&0xF];
157 PCMfreq=NTSCPCMTable[PSG[0x10]&0xF];
158 PCMacc=(int64)PCMfreq<<50;
161 uint8 sweepon[2]={0,0};
162 int32 curfreq[2]={0,0};
168 uint8 DecCountTo1[3];
176 /* Instantaneous? Maybe the new freq value is being calculated all of the time... */
177 static int FASTAPASS(2) CheckFreq(uint32 cf, uint8 sr)
189 static DECLFW(Write0x11)
195 static uint8 DutyCount[2]={0,0};
197 static DECLFW(Write_PSG)
199 //if((A>=0x4004 && A<=0x4007) || A==0x4015)
200 //printf("$%04x:$%02x, %d\n",A,V,SOUNDTS);
221 lengthcount[0]=lengthtable[(V>>3)&0x1f];
224 sweepon[0]=PSG[1]&0x80;
225 curfreq[0]=PSG[0x2]|((V&7)<<8);
227 DecCountTo1[0]=(PSG[0]&0xF)+1;
228 SweepCount[0]=((PSG[0x1]>>4)&7)+1;
230 sqacc[0]=((int64)curfreq[0]+1)<<50;
250 lengthcount[1]=lengthtable[(V>>3)&0x1f];
253 sweepon[1]=PSG[0x5]&0x80;
254 curfreq[1]=PSG[0x6]|((V&7)<<8);
256 DecCountTo1[1]=(PSG[0x4]&0xF)+1;
257 SweepCount[1]=((PSG[0x5]>>4)&7)+1;
259 sqacc[1]=((int64)curfreq[1]+1)<<50;
272 case 0xa:DoTriangle();
279 lengthcount[2]=lengthtable[(V>>3)&0x1f];
282 tricoop=PSG[0x8]&0x7f;
283 trimode=PSG[0x8]&0x80;
289 case 0xE:DoNoise();break;
295 lengthcount[3]=lengthtable[(V>>3)&0x1f];
298 DecCountTo1[2]=(PSG[0xC]&0xF)+1;
302 X6502_IRQEnd(FCEU_IQDPCM);
321 if(!(PSG[0x15]&0x10))
331 X6502_IRQEnd(FCEU_IQDPCM);
343 ret=(PSG[0x15]&(sqnon|0x10))|SIRQStat;
345 X6502_IRQEnd(/*FCEU_IQDPCM|*/FCEU_IQFCOUNT);
349 DECLFR(Read_PSGDummy)
353 ret=(PSG[0x15]&sqnon)|SIRQStat;
355 X6502_IRQEnd(/*FCEU_IQDPCM|*/FCEU_IQFCOUNT);
359 static void FASTAPASS(1) FrameSoundStuff(int V)
369 case 1: /* Envelope decay, linear counter, length counter, freq sweep */
370 if(PSG[0x15]&4 && sqnon&4)
376 if(lengthcount[2]<=0)
386 if(PSG[0x15]&(P+1) && sqnon&(P+1))
388 if(!(PSG[P<<2]&0x20))
393 if(lengthcount[P]<=0)
400 /* Frequency Sweep Code Here */
402 /* xxxx = hz. 120/(x+1)*/
407 if(SweepCount[P]>0) SweepCount[P]--;
410 SweepCount[P]=((PSG[(P<<2)+0x1]>>4)&7)+1; //+1;
412 if(PSG[(P<<2)+0x1]&0x8)
414 mod-=(P^1)+((curfreq[P])>>(PSG[(P<<2)+0x1]&7));
416 if(curfreq[P] && (PSG[(P<<2)+0x1]&7)/* && sweepon[P]&0x80*/)
423 mod=curfreq[P]>>(PSG[(P<<2)+0x1]&7);
424 if((mod+curfreq[P])&0x800)
431 if(curfreq[P] && (PSG[(P<<2)+0x1]&7)/* && sweepon[P]&0x80*/)
442 if(PSG[0x15]&0x8 && sqnon&8)
449 if(lengthcount[3]<=0)
457 case 0: /* Envelope decay + linear counter */
463 if(tricoop==1) DoTriangle();
470 if(DecCountTo1[P]>0) DecCountTo1[P]--;
471 if(DecCountTo1[P]<=0)
473 DecCountTo1[P]=(PSG[P<<2]&0xF)+1;
474 if(decvolume[P] || PSG[P<<2]&0x20)
477 /* Step from 0 to full volume seems to take twice as long
478 as the other steps. I don't know if this is the correct
479 way to double its length, though(or if it even matters).
481 if((PSG[P<<2]&0x20) && (decvolume[P]==0))
486 if(!(PSG[P<<2]&0x10))
487 realvolume[P]=decvolume[P];
490 if(DecCountTo1[2]>0) DecCountTo1[2]--;
491 if(DecCountTo1[2]<=0)
493 DecCountTo1[2]=(PSG[0xC]&0xF)+1;
494 if(decvolume[2] || PSG[0xC]&0x20)
497 /* Step from 0 to full volume seems to take twice as long
498 as the other steps. I don't know if this is the correct
499 way to double its length, though(or if it even matters).
501 if((PSG[0xC]&0x20) && (decvolume[2]==0))
507 realvolume[2]=decvolume[2];
514 void FrameSoundUpdate(void)
516 // Linear counter: Bit 0-6 of $4008
517 // Length counter: Bit 4-7 of $4003, $4007, $400b, $400f
523 if(!(PSG[0x17]&0xC0))
526 X6502_IRQBegin(FCEU_IQFCOUNT);
529 //if(SIRQStat&0x40) X6502_IRQBegin(FCEU_IQFCOUNT);
530 FrameSoundStuff(fcnt);
534 static uint32 ChannelBC[5];
536 static uint32 RectAmp[2][8];
538 static void FASTAPASS(1) CalcRectAmp(int P)
540 static int tal[4]={1,2,4,6};
543 uint32 *b=RectAmp[P];
548 //V=(PSG[P<<2]&15)<<4;
550 // V=decvolume[P]<<4;
551 m=tal[(PSG[P<<2]&0xC0)>>6];
558 static void RDoPCM(void)
563 uint32 out=PSG[0x11]<<3;
566 end=(SOUNDTS<<16)/soundtsinc;
567 if(end<=start) return;
575 for(V=start;V<end;V++)
577 PCMacc-=nesincsizeLL;
591 Wave[V>>4]+=PSG[0x11]<<3;
597 PCMBuffer=ARead[0x8000+PCMAddressIndex](0x8000+PCMAddressIndex);
598 PCMAddressIndex=(PCMAddressIndex+1)&0x7fff;
603 int t=(((PCMBuffer>>PCMBitIndex)&1)<<2)-2;
613 PCMBitIndex=(PCMBitIndex+1)&7;
615 Wave[V>>4]+=out; //(PSG[0x11]-64)<<3;
622 for(V=start;V<=(start|15);V++)
625 for(V=(start>>4)+1;V<(end>>4);V++)
628 for(V=end&(~15);V<end;V++)
632 for(V=start;V<end;V++)
638 static void RDoSQ1(void)
646 end=(SOUNDTS<<16)/soundtsinc;
647 if(end<=start) return;
650 if(curfreq[0]<8 || curfreq[0]>0x7ff)
652 if(!CheckFreq(curfreq[0],PSG[0x1]))
655 if(PSG[0x15]&1 && sqnon&1)
657 uint32 out=RectAmp[0][DutyCount[0]];
661 for(V=start;V<end;V++)
664 sqacc[0]-=nesincsizeLL;
670 if(sqacc[0]<=0) goto rea;
673 out=RectAmp[0][DutyCount[0]];
681 static void RDoSQ2(void)
689 end=(SOUNDTS<<16)/soundtsinc;
690 if(end<=start) return;
693 if(curfreq[1]<8 || curfreq[1]>0x7ff)
695 if(!CheckFreq(curfreq[1],PSG[0x5]))
698 if(PSG[0x15]&2 && sqnon&2)
700 uint32 out=RectAmp[1][DutyCount[1]];
705 for(V=start;V<end;V++)
708 sqacc[1]-=nesincsizeLL;
714 if(sqacc[1]<=0) goto rea;
717 out=RectAmp[1][DutyCount[1]];
726 static void RDoTriangle(void)
728 static uint32 tcout=0;
730 int32 start,end; //,freq;
731 int64 freq=(((PSG[0xa]|((PSG[0xb]&7)<<8))+1));
734 end=(SOUNDTS<<16)/soundtsinc;
735 if(end<=start) return;
738 if(! (PSG[0x15]&0x4 && sqnon&4 && tricoop) )
739 { // Counter is halted, but we still need to output.
740 for(V=start;V<end;V++)
743 else if(freq<=4) // 55.9Khz - Might be barely audible on a real NES, but
744 // it's too costly to generate audio at this high of a frequency
745 // (55.9Khz * 32 for the stepping).
746 // The same could probably be said for ~27.8Khz, so we'll
747 // take care of that too. We'll just output the average
748 // value(15/2 - scaled properly for our output format, of course).
749 // We'll also take care of ~18Khz and ~14Khz too, since they should be barely audible.
750 // (Some proof or anything to confirm/disprove this would be nice.).
752 for(V=start;V<end;V++)
753 Wave[V>>4]+=((0xF<<4)+(0xF<<2))>>1;
757 static int64 triacc=0;
761 for(V=start;V<end;V++)
763 triacc-=nesincsizeLL;
769 if(triacc<=0) goto rea;
772 if(tc&0x10) tcout^=0xF;
773 tcout=(tcout<<4)+(tcout<<2);
780 static void RDoNoise(void)
786 end=(SOUNDTS<<16)/soundtsinc;
787 if(end<=start) return;
790 if(PSG[0x15]&0x8 && sqnon&8)
796 amplitude=realvolume[2];
798 // amplitude=(PSG[0xC]&0xF);
800 // amplitude=decvolume[2]&0xF;
802 inc=NoiseFreqTable[PSG[0xE]&0xF];
803 amptab[0]=((amplitude<<2)+amplitude+amplitude)<<1;
809 if(PSG[0xE]&0x80) // "short" noise
810 for(V=start;V<end;V++)
817 feedback=((nreg>>8)&1)^((nreg>>14)&1);
818 nreg=(nreg<<1)+feedback;
826 for(V=start;V<end;V++)
833 feedback=((nreg>>13)&1)^((nreg>>14)&1);
834 nreg=(nreg<<1)+feedback;
855 X6502_IRQEnd(FCEU_IQFCOUNT);
857 //IRQFrameMode=V; // IRQFrameMode is PSG[0x17] upper bits
860 void SetNESSoundMap(void)
862 SetWriteHandler(0x4000,0x4013,Write_PSG);
863 SetWriteHandler(0x4011,0x4011,Write0x11);
864 SetWriteHandler(0x4015,0x4015,Write_PSG);
865 SetWriteHandler(0x4017,0x4017,Write_IRQFM);
866 SetReadHandler(0x4015,0x4015,Read_PSG);
869 static int32 WaveNSF[2048];
871 int32 highp; // 0 through 65536, 0 = no high pass, 65536 = max high pass
873 int32 lowp; // 0 through 65536, 65536 = max low pass(total attenuation)
874 // 65536 = no low pass
875 static void FilterSound(uint32 *in, int32 *out, int16 *outMono, int count)
877 static int64 acc=0, acc2=0;
880 //int16* outorig=out;
882 for(;count;count--,in++)//,out++)//,index++)
886 diff=((int64)*in<<24)-acc;
888 acc+=(diff*highp)>>16;
889 acc2+=((diff-acc2)*lowp)>>16;
892 // don't change the sound here
893 // *out=(acc2*(int64)FSettings.SoundVolume)>>(24+16);
894 // volume, 4 times louder by default??
895 // *out = acc2 >> 24;
896 // just a bit louder. Hope it's okay
899 if(*out<-32767) *out=-32767;
900 if(*out>32767) *out=32767;
904 tmp=(int16 *)(out-1);
905 // don't do this the first time
906 if (prev == -99999) continue;
907 // the middle one should be interpolated
908 tmp[1]=(int16)((*out + prev) >> 1);
911 //outMono[index] = (int16)*out;
912 *outMono = (int16)(acc2 >> 24);
913 //if(*outMono<-16384) *outMono=-16384;
914 //if(*outMono>16384) *outMono=16384;
917 // out=((int64)(acc2>>24)*(int64)FSettings.SoundVolume)>>16; //acc2>>24;
926 static int32 inbuf=0;
927 int FlushEmulateSound(void)
932 if(!timestamp) return(0);
934 if(!FSettings.SndRate || (soundvol == 0))
940 end=(SOUNDTS<<16)/soundtsinc;
947 if(GameExpSound.Fill)
948 GameExpSound.Fill(end&0xF);
950 // FilterSound(Wave,WaveFinal,end>>4);
951 FilterSound(Wave,WaveFinal,WaveFinalMono,end>>4);
952 // printf("count %d, num ints %d\n", end, (end >> 4));
953 if(FCEUGameInfo.type==GIT_NSF)
955 int x;//,s=0,si=end/1024;
958 //WaveNSF[x]=WaveFinal[s>>4];
959 WaveNSF[x]=WaveFinalMono[x];
965 Wave[0]=Wave[(end>>4)];
970 ChannelBC[x]=end&0xF;
971 soundtsoffs=(soundtsinc*(end&0xF))>>16;
977 int GetSoundBuffer(int32 **W)
983 void PowerSound(void)
991 BWrite[0x4000+x](0x4000+x,0);
999 void ResetSound(void)
1003 if(x!=1 && x!=5 && x!=0x14) BWrite[0x4000+x](0x4000+x,0);
1010 void SetSoundVariables(void)
1014 fhinc=PAL?16626:14915; // *2 CPU clock rate
1017 lengthtable[x]=Slengthtable[x]<<1;
1019 if(FSettings.SndRate)
1022 DoTriangle=RDoTriangle;
1029 DoNoise=DoTriangle=DoPCM=DoSQ1=DoSQ2=Dummyfunc;
1032 if(!FSettings.SndRate) return;
1033 if(GameExpSound.RChange)
1034 GameExpSound.RChange();
1036 nesincsizeLL=(int64)((int64)562949953421312*(double)(PAL?PAL_CPU:NTSC_CPU)/(FSettings.SndRate OVERSAMPLE));
1037 nesincsize=(int64)(((int64)1<<17)*(double)(PAL?PAL_CPU:NTSC_CPU)/(FSettings.SndRate * 16));
1038 PSG_base=(uint32)(PAL?(long double)PAL_CPU/16:(long double)NTSC_CPU/16);
1043 z=SNoiseFreqTable[x]<<1;
1044 z=(PAL?PAL_CPU:NTSC_CPU)/z;
1045 z=(long double)((uint32)((FSettings.SndRate OVERSAMPLE)<<12))/z;
1046 NoiseFreqTable[x]=z;
1048 soundtsinc=(uint32)((uint64)(PAL?(long double)PAL_CPU*65536:(long double)NTSC_CPU*65536)/(FSettings.SndRate OVERSAMPLE));
1049 memset(Wave,0,2048*4);
1052 highp=(250<<16)/FSettings.SndRate; // Arbitrary
1053 lowp=((int64)25000<<16)/FSettings.SndRate; // Arbitrary
1055 if(highp>(1<<16)) highp=1<<16;
1056 if(lowp>(1<<16)) lowp=1<<16;
1059 void FixOldSaveStateSFreq(void)
1064 curfreq[x]=PSG[0x2+(x<<2)]|((PSG[0x3+(x<<2)]&7)<<8);
1068 void FCEUI_Sound(int Rate)
1070 FSettings.SndRate=Rate;
1071 SetSoundVariables();
1074 void FCEUI_SetSoundVolume(uint32 volume)
1076 FSettings.SoundVolume=volume;