// Length counter: Bit 4-7 of $4003, $4007, $400b, $400f
if(!fcnt&&!(IRQFrameMode&0x3))
{
SIRQStat|=0x40;
X6502_IRQBegin(FCEU_IQFCOUNT);
}
if(fcnt==3)
{
if(IRQFrameMode&0x2)
fhcnt+=fhinc;
}
FrameSoundStuff(fcnt);
fcnt=(fcnt+1)&3;
}
staticINLINEvoidtester(void)
{
if(DMCBitCount==0)
{
if(!DMCHaveDMA)
DMCHaveSample=0;
else
{
DMCHaveSample=1;
DMCShift=DMCDMABuf;
DMCHaveDMA=0;
}
}
}
staticINLINEvoidDMCDMA(void)
{
if(DMCSize&&!DMCHaveDMA)
{
X6502_DMR(0x8000+DMCAddress);
X6502_DMR(0x8000+DMCAddress);
X6502_DMR(0x8000+DMCAddress);
DMCDMABuf=X6502_DMR(0x8000+DMCAddress);
DMCHaveDMA=1;
DMCAddress=(DMCAddress+1)&0x7fff;
DMCSize--;
if(!DMCSize)
{
if(DMCFormat&0x40)
PrepDPCM();
else
{
SIRQStat|=0x80;
if(DMCFormat&0x80)
X6502_IRQBegin(FCEU_IQDPCM);
}
}
}
}
voidFCEU_SoundCPUHook(intcycles)
{
fhcnt-=cycles*48;
if(fhcnt<=0)
{
FrameSoundUpdate();
fhcnt+=fhinc;
}
DMCDMA();
DMCacc-=cycles;
while(DMCacc<=0)
{
if(DMCHaveSample)
{
uint8bah=RawDALatch;
intt=((DMCShift&1)<<2)-2;
/* Unbelievably ugly hack */
if(FSettings.SndRate)
{
soundtsoffs+=DMCacc;
DoPCM();
soundtsoffs-=DMCacc;
}
RawDALatch+=t;
if(RawDALatch&0x80)
RawDALatch=bah;
}
DMCacc+=DMCPeriod;
DMCBitCount=(DMCBitCount+1)&7;
DMCShift>>=1;
tester();
}
}
voidRDoPCM(void)
{
uint32V;//mbg merge 7/17/06 made uint32
for(V=ChannelBC[4];V<SOUNDTS;V++)
WaveHi[V]+=(((RawDALatch<<16)/256)*FSettings.PCMVolume)&(~0xFFFF);// TODO get rid of floating calculations to binary. set log volume scaling.
ChannelBC[4]=SOUNDTS;
}
/* This has the correct phase. Don't mess with it. */
staticINLINEvoidRDoSQ(intx)//Int x decides if this is Square Wave 1 or 2
{
int32V;
int32amp,ampx;
int32rthresh;
int32*D;
int32currdc;
int32cf;
int32rc;
if(curfreq[x]<8||curfreq[x]>0x7ff)
gotoendit;
if(!CheckFreq(curfreq[x],PSG[(x<<2)|0x1]))
gotoendit;
if(!lengthcount[x])
gotoendit;
if(EnvUnits[x].Mode&0x1)
amp=EnvUnits[x].Speed;
else
amp=EnvUnits[x].decvolume;//Set the volume of the Square Wave
//Modify Square wave volume based on channel volume modifiers
//adelikat: Note: the formulat x = x * y /100 does not yield exact results, but is "close enough" and avoids the need for using double vales or implicit cohersion which are slower (we need speed here)
ampx=x?FSettings.Square1Volume:FSettings.Square2Volume;// TODO OPTIMIZE ME!
if(ampx!=256)amp=(amp*ampx)/256;// CaH4e3: fixed - setting up maximum volume for square2 caused complete mute square2 channel
amp<<=24;
rthresh=RectDuties[(PSG[(x<<2)]&0xC0)>>6];
D=&WaveHi[ChannelBC[x]];
V=SOUNDTS-ChannelBC[x];
currdc=RectDutyCount[x];
cf=(curfreq[x]+1)*2;
rc=wlcount[x];
while(V>0)
{
if(currdc<rthresh)
*D+=amp;
rc--;
if(!rc)
{
rc=cf;
currdc=(currdc+1)&7;
}
V--;
D++;
}
RectDutyCount[x]=currdc;
wlcount[x]=rc;
endit:
ChannelBC[x]=SOUNDTS;
}
staticvoidRDoSQ1(void)
{
RDoSQ(0);
}
staticvoidRDoSQ2(void)
{
RDoSQ(1);
}
staticvoidRDoSQLQ(void)
{
int32start,end;
int32V;
int32amp[2],ampx;
int32rthresh[2];
int32freq[2];
intx;
int32inie[2];
int32ttable[2][8];
int32totalout;
start=ChannelBC[0];
end=(SOUNDTS<<16)/soundtsinc;
if(end<=start)return;
ChannelBC[0]=end;
for(x=0;x<2;x++)
{
inty;
inie[x]=nesincsize;
if(curfreq[x]<8||curfreq[x]>0x7ff)
inie[x]=0;
if(!CheckFreq(curfreq[x],PSG[(x<<2)|0x1]))
inie[x]=0;
if(!lengthcount[x])
inie[x]=0;
if(EnvUnits[x].Mode&0x1)
amp[x]=EnvUnits[x].Speed;
else
amp[x]=EnvUnits[x].decvolume;
//Modify Square wave volume based on channel volume modifiers
//adelikat: Note: the formulat x = x * y /100 does not yield exact results, but is "close enough" and avoids the need for using double vales or implicit cohersion which are slower (we need speed here)
ampx=x?FSettings.Square1Volume:FSettings.Square2Volume;// TODO OPTIMIZE ME!
if(ampx!=256)amp[x]=(amp[x]*ampx)/256;// CaH4e3: fixed - setting up maximum volume for square2 caused complete mute square2 channel
if(!inie[x])amp[x]=0;/* Correct? Buzzing in MM2, others otherwise... */
{/* Counter is halted, but we still need to output. */
int32*start=&WaveHi[ChannelBC[2]];
int32count=SOUNDTS-ChannelBC[2];
while(count--)
{
//Modify volume based on channel volume modifiers
*start+=(tcout/256*FSettings.TriangleVolume)&(~0xFFFF);// TODO OPTIMIZE ME NOW DAMMIT!
start++;
}
//for(V=ChannelBC[2];V<SOUNDTS;V++)
// WaveHi[V]+=tcout;
}
else
for(V=ChannelBC[2];V<SOUNDTS;V++)
{
//Modify volume based on channel volume modifiers
WaveHi[V]+=(tcout/256*FSettings.TriangleVolume)&(~0xFFFF);// TODO OPTIMIZE ME!
wlcount[2]--;
if(!wlcount[2])
{
wlcount[2]=(PSG[0xa]|((PSG[0xb]&7)<<8))+1;
tristep++;
tcout=(tristep&0xF);
if(!(tristep&0x10))tcout^=0xF;
tcout=(tcout*3)<<16;
}
}
ChannelBC[2]=SOUNDTS;
}
staticvoidRDoTriangleNoisePCMLQ(void)
{
staticuint32tcout=0;
staticint32triacc=0;
staticint32noiseacc=0;
int32V;
int32start,end;
int32freq[2];
int32inie[2];
uint32amptab[2];
uint32noiseout;
intnshift;
int32totalout;
start=ChannelBC[2];
end=(SOUNDTS<<16)/soundtsinc;
if(end<=start)return;
ChannelBC[2]=end;
inie[0]=inie[1]=nesincsize;
freq[0]=(((PSG[0xa]|((PSG[0xb]&7)<<8))+1));
if(!lengthcount[2]||!TriCount||freq[0]<=4)
inie[0]=0;
freq[0]<<=17;
if(EnvUnits[2].Mode&0x1)
amptab[0]=EnvUnits[2].Speed;
else
amptab[0]=EnvUnits[2].decvolume;
//Modify Square wave volume based on channel volume modifiers
//adelikat: Note: the formulat x = x * y /100 does not yield exact results, but is "close enough" and avoids the need for using double vales or implicit cohersion which are slower (we need speed here)
if(FSettings.TriangleVolume!=256)amptab[0]=(amptab[0]*FSettings.TriangleVolume)/256;// TODO OPTIMIZE ME!
amptab[1]=0;
amptab[0]<<=1;
if(!lengthcount[3])
amptab[0]=inie[1]=0;/* Quick hack speedup, set inie[1] to 0 */
noiseout=amptab[(nreg>>0xe)&1];
if(PSG[0xE]&0x80)
nshift=8;
else
nshift=13;
totalout=wlookup2[tcout+noiseout+RawDALatch];
if(inie[0]&&inie[1])
{
for(V=start;V<end;V++)
{
Wave[V>>4]+=totalout;
triacc-=inie[0];
noiseacc-=inie[1];
if(triacc<=0)
{
rea:
triacc+=freq[0];//t;
tristep=(tristep+1)&0x1F;
if(triacc<=0)gotorea;
tcout=(tristep&0xF);
if(!(tristep&0x10))tcout^=0xF;
tcout=tcout*3;
totalout=wlookup2[tcout+noiseout+RawDALatch];
}
if(noiseacc<=0)
{
rea2:
noiseacc+=NoiseFreqTable[PSG[0xE]&0xF]<<(16+2);
nreg=(nreg<<1)+(((nreg>>nshift)^(nreg>>14))&1);
nreg&=0x7fff;
noiseout=amptab[(nreg>>0xe)];
if(noiseacc<=0)gotorea2;
totalout=wlookup2[tcout+noiseout+RawDALatch];
}/* noiseacc<=0 */
}/* for(V=... */
}
elseif(inie[0])
{
for(V=start;V<end;V++)
{
Wave[V>>4]+=totalout;
triacc-=inie[0];
if(triacc<=0)
{
area:
triacc+=freq[0];//t;
tristep=(tristep+1)&0x1F;
if(triacc<=0)gotoarea;
tcout=(tristep&0xF);
if(!(tristep&0x10))tcout^=0xF;
tcout=tcout*3;
totalout=wlookup2[tcout+noiseout+RawDALatch];
}
}
}
elseif(inie[1])
{
for(V=start;V<end;V++)
{
Wave[V>>4]+=totalout;
noiseacc-=inie[1];
if(noiseacc<=0)
{
area2:
noiseacc+=NoiseFreqTable[PSG[0xE]&0xF]<<(16+2);
nreg=(nreg<<1)+(((nreg>>nshift)^(nreg>>14))&1);
nreg&=0x7fff;
noiseout=amptab[(nreg>>0xe)];
if(noiseacc<=0)gotoarea2;
totalout=wlookup2[tcout+noiseout+RawDALatch];
}/* noiseacc<=0 */
}
}
else
{
for(V=start;V<end;V++)
Wave[V>>4]+=totalout;
}
}
staticvoidRDoNoise(void)
{
uint32V;//mbg merge 7/17/06 made uint32
int32outo;
uint32amptab[2];
if(EnvUnits[2].Mode&0x1)
amptab[0]=EnvUnits[2].Speed;
else
amptab[0]=EnvUnits[2].decvolume;
//Modfiy Noise channel volume based on channel volume setting
//adelikat: Note: the formulat x = x * y /100 does not yield exact results, but is "close enough" and avoids the need for using double vales or implicit cohersion which are slower (we need speed here)
if(FSettings.NoiseVolume!=256)amptab[0]=(amptab[0]*FSettings.NoiseVolume)/256;// TODO OPTIMIZE ME!
FCEU_WriteWaveData(WaveFinal,end);/* This function will just return
ifsoundrecordingisoff.*/
return(end);
}
intGetSoundBuffer(int32**W)
{
*W=WaveFinal;
return(inbuf);
}
/* FIXME: Find out what sound registers get reset on reset. I know $4001/$4005 don't,
duetothatwholeMegaMan2GameGeniething.
*/
voidFCEUSND_Reset(void)
{
intx;
IRQFrameMode=0x0;
fhcnt=fhinc;
fcnt=0;
nreg=1;
for(x=0;x<2;x++)
{
wlcount[x]=2048;
if(nesincsize)// lq mode
sqacc[x]=((uint32)2048<<17)/nesincsize;
else
sqacc[x]=1;
sweepon[x]=0;
curfreq[x]=0;
}
wlcount[2]=1;//2048;
wlcount[3]=2048;
DMCHaveDMA=DMCHaveSample=0;
SIRQStat=0x00;
RawDALatch=0x00;
TriCount=0;
TriMode=0;
tristep=0;
EnabledChannels=0;
for(x=0;x<4;x++)
lengthcount[x]=0;
DMCAddressLatch=0;
DMCSizeLatch=0;
DMCFormat=0;
DMCAddress=0;
DMCSize=0;
DMCShift=0;
// MAJOR BUG WAS HERE: DMCacc and DMCBitCount never got reset...
// so, do some ridiculous hackery if a movie's about to play to keep it in sync...
if(movieSyncHackOn)
{
if(resetDMCacc)
{
// no value in movie save state
#ifdef WIN32
// use editbox fields
DMCacc=movieConvertOffset1;
DMCBitCount=movieConvertOffset2;
#else
// no editbox fields, so leave the values alone
// and print out a warning that says what they are
FCEU_PrintError("Warning: These variables were not found in the save state and will keep their current value: DMCacc=%d, DMCBitCount=%d\n",DMCacc,DMCBitCount);
#endif
}
else
{
// keep values loaded from movie save state or reset earlier
}
}
else
{
// reset these variables like should have done in the first place