Split 64bit counters into 2x32bit

This appears to generate slightly saner code
This commit is contained in:
Aikku93 2022-06-13 14:28:44 +10:00
parent 41edf7be5e
commit 589084ec74
3 changed files with 72 additions and 46 deletions

View File

@ -126,6 +126,14 @@ static FORCEINLINE T MinMax(T val, T min, T max)
return val;
}
// T must be unsigned type
template<typename T>
static FORCEINLINE T AddAndReturnCarry(T *a, T b) {
T c = (*a >= (-b));
*a += b;
return c;
}
//--------------external spu interface---------------
int SPU_ChangeSoundCore(int coreid, int newBufferSizeBytes)
@ -380,7 +388,8 @@ static FORCEINLINE void adjust_channel_timer(channel_struct *chan)
// ARM7_CLOCK / (DESMUME_SAMPLE_RATE*2) / (2^16 - Timer)
// = ARM7_CLOCK / (DESMUME_SAMPLE_RATE*2 * (2^16 - Timer))
// ... and then round up for good measure
chan->sampinc = ((u32)ARM7_CLOCK*(1ull<<32)-1) / (DESMUME_SAMPLE_RATE*2ull * (0x10000 - chan->timer)) + 1;
u64 sampinc = ((u32)ARM7_CLOCK*(1ull << 32) - 1) / (DESMUME_SAMPLE_RATE * 2ull * (0x10000 - chan->timer)) + 1;
chan->sampincInt = (u32)(sampinc >> 32), chan->sampincFrac = (u32)sampinc;
}
void SPU_struct::KeyProbe(int chan_num)
@ -431,23 +440,23 @@ void SPU_struct::KeyOn(int channel)
case 0: // 8-bit
// thischan.loopstart = thischan.loopstart << 2;
// thischan.length = (thischan.length << 2) + thischan.loopstart;
thischan.sampcnt = -3 * (1ll<<32);
thischan.sampcntFrac = 0, thischan.sampcntInt = -3;
break;
case 1: // 16-bit
// thischan.loopstart = thischan.loopstart << 1;
// thischan.length = (thischan.length << 1) + thischan.loopstart;
thischan.sampcnt = -3 * (1ll<<32);
thischan.sampcntFrac = 0, thischan.sampcntInt = -3;
break;
case 2: // ADPCM
thischan.pcm16b[0] = (s16)read16(thischan.addr);
thischan.index = read08(thischan.addr + 2) & 0x7F;
thischan.sampcnt = -3 * (1ll<<32);
thischan.sampcntFrac = 0, thischan.sampcntInt = -3;
thischan.loop_index = K_ADPCM_LOOPING_RECOVERY_INDEX;
// thischan.loopstart = thischan.loopstart << 3;
// thischan.length = (thischan.length << 3) + thischan.loopstart;
break;
case 3: // PSG
thischan.sampcnt = -1 * (1ll<<32);
thischan.sampcntFrac = 0, thischan.sampcntInt = -1;
thischan.x = 0x7FFF;
break;
default: break;
@ -756,7 +765,7 @@ void SPU_struct::ProbeCapture(int which)
u32 len = cap.len;
if(len==0) len=1;
cap.runtime.maxdad = cap.dad + len*4;
cap.runtime.sampcnt = 0;
cap.runtime.sampcntFrac = cap.runtime.sampcntInt = 0;
cap.runtime.fifo.reset();
}
@ -1163,7 +1172,7 @@ static FORCEINLINE void MixLR(SPU_struct* SPU, channel_struct *chan, s32 data)
template<int FORMAT> static FORCEINLINE void TestForLoop(SPU_struct *SPU, channel_struct *chan)
{
// Do nothing if we haven't reached the end
if((chan->sampcnt >> 32) < chan->totlength_shifted) return;
if(chan->sampcntInt < chan->totlength_shifted) return;
// Kill the channel if we don't repeat
if(chan->repeat != 1)
@ -1196,8 +1205,8 @@ template<int FORMAT> static FORCEINLINE void TestForLoop(SPU_struct *SPU, channe
}
// Wrap sampcnt
s64 step = chan->totlength_shifted - (chan->loopstart << format_shift[FORMAT]);
while ((chan->sampcnt >> 32) >= chan->totlength_shifted) chan->sampcnt -= step * (1ll << 32);
u32 step = chan->totlength_shifted - (chan->loopstart << format_shift[FORMAT]);
while (chan->sampcntInt >= chan->totlength_shifted) chan->sampcntInt -= step;
}
template<int CHANNELS> FORCEINLINE static void SPU_Mix(SPU_struct* SPU, channel_struct *chan, s32 data)
@ -1220,14 +1229,11 @@ template<int FORMAT, SPUInterpolationMode INTERPOLATE_MODE, int CHANNELS>
{
// Advance sampcnt one sample at a time. This is
// needed to keep pcm16b[] filled for interpolation.
// We need to do some janky things here to keep the
// fractional bits in place when we loop :/
s64 newsampcnt = chan->sampcnt + chan->sampinc;
u32 nSamplesToSkip = (u32)((newsampcnt >> 32) - (chan->sampcnt >> 32));
u32 nSamplesToSkip = chan->sampincInt + AddAndReturnCarry(&chan->sampcntFrac, chan->sampincFrac);
while(nSamplesToSkip--)
{
s16 data = 0;
s32 pos = chan->sampcnt >> 32;
s32 pos = chan->sampcntInt;
switch(FORMAT)
{
case 0: data = Fetch8BitData (chan, pos); break;
@ -1239,14 +1245,13 @@ template<int FORMAT, SPUInterpolationMode INTERPOLATE_MODE, int CHANNELS>
chan->pcm16bOffs++;
chan->pcm16b[SPUCHAN_PCM16B_AT(chan->pcm16bOffs)] = data;
chan->sampcnt += 1ll << 32;
chan->sampcntInt++;
if (FORMAT != 3) TestForLoop<FORMAT>(SPU, chan);
}
chan->sampcnt = ((chan->sampcnt >> 32) << 32) | (u32)newsampcnt;
if(CHANNELS != -1)
{
s32 data = Interpolate<INTERPOLATE_MODE>(chan->pcm16b, chan->pcm16bOffs, (u32)chan->sampcnt);
s32 data = Interpolate<INTERPOLATE_MODE>(chan->pcm16b, chan->pcm16bOffs, chan->sampcntFrac);
SPU_Mix<CHANNELS>(SPU, chan, data);
}
}
@ -1438,13 +1443,13 @@ static void SPU_MixAudio_Advanced(bool actuallyMix, SPU_struct *SPU, int length)
for (int capchan = 0; capchan < 2; capchan++)
{
SPU_struct::REGS::CAP& cap = SPU->regs.cap[capchan];
channel_struct& srcChan = SPU->channels[1 + 2 * capchan];
if (SPU->regs.cap[capchan].runtime.running)
{
SPU_struct::REGS::CAP& cap = SPU->regs.cap[capchan];
u32 last = cap.runtime.sampcnt >> 32;
cap.runtime.sampcnt += SPU->channels[1+2*capchan].sampinc;
u32 curr = cap.runtime.sampcnt >> 32;
for (u32 j = last; j < curr; j++)
u32 nSamplesToProcess = srcChan.sampincInt + AddAndReturnCarry(&cap.runtime.sampcntFrac, srcChan.sampincFrac);
cap.runtime.sampcntInt += nSamplesToProcess;
while(nSamplesToProcess--)
{
//so, this is a little strange. why go through a fifo?
//it seems that some games will set up a reverb effect by capturing
@ -1495,7 +1500,7 @@ static void SPU_MixAudio_Advanced(bool actuallyMix, SPU_struct *SPU, int length)
if (cap.runtime.curdad >= cap.runtime.maxdad)
{
cap.runtime.curdad = cap.dad;
cap.runtime.sampcnt -= cap.len*multiplier * (1ull<<32);
cap.runtime.sampcntInt -= cap.len*multiplier;
}
} //sampinc loop
} //if capchan running
@ -1555,14 +1560,14 @@ static void SPU_MixAudio(bool actuallyMix, SPU_struct *SPU, int length)
for (int capchan = 0; capchan < 2; capchan++)
{
SPU_struct::REGS::CAP& cap = SPU->regs.cap[capchan];
channel_struct& srcChan = SPU->channels[1 + 2 * capchan];
if (cap.runtime.running)
{
for (int samp = 0; samp < length; samp++)
{
u32 last = cap.runtime.sampcnt >> 32;
cap.runtime.sampcnt += SPU->channels[1+2*capchan].sampinc;
u32 curr = cap.runtime.sampcnt >> 32;
for (u32 j = last; j < curr; j++)
u32 nSamplesToProcess = srcChan.sampincInt + AddAndReturnCarry(&cap.runtime.sampcntFrac, srcChan.sampincFrac);
cap.runtime.sampcntInt += nSamplesToProcess;
while (nSamplesToProcess--)
{
if (cap.bits8)
{
@ -1578,7 +1583,7 @@ static void SPU_MixAudio(bool actuallyMix, SPU_struct *SPU, int length)
if (cap.runtime.curdad >= cap.runtime.maxdad)
{
cap.runtime.curdad = cap.dad;
cap.runtime.sampcnt -= cap.len*(cap.bits8?4:2) * (1ull<<32);
cap.runtime.sampcntInt -= cap.len*(cap.bits8?4:2);
}
}
}
@ -1929,8 +1934,10 @@ void spu_savestate(EMUFILE &os)
os.write_16LE(chan.timer);
os.write_16LE(chan.loopstart);
os.write_32LE(chan.length);
os.write_64LE(chan.sampcnt);
os.write_64LE(chan.sampinc);
os.write_32LE(chan.sampcntFrac);
os.write_32LE(chan.sampcntInt);
os.write_32LE(chan.sampincFrac);
os.write_32LE(chan.sampincInt);
for (int i = 0; i < SPUINTERPOLATION_TAPS; i++) os.write_16LE(chan.pcm16b[i]);
os.write_32LE(chan.index);
os.write_16LE(chan.x);
@ -1959,7 +1966,8 @@ void spu_savestate(EMUFILE &os)
os.write_u8(spu->regs.cap[i].runtime.running);
os.write_32LE(spu->regs.cap[i].runtime.curdad);
os.write_32LE(spu->regs.cap[i].runtime.maxdad);
os.write_64LE(spu->regs.cap[i].runtime.sampcnt);
os.write_32LE(spu->regs.cap[i].runtime.sampcntFrac);
os.write_32LE(spu->regs.cap[i].runtime.sampcntInt);
}
for (int i = 0; i < 2; i++)
@ -2001,14 +2009,21 @@ bool spu_loadstate(EMUFILE &is, int size)
chan.totlength = chan.length + chan.loopstart;
chan.totlength_shifted = chan.totlength << format_shift[chan.format];
if(version >= 7) {
is.read_64LE(chan.sampcnt);
is.read_64LE(chan.sampinc);
is.read_32LE(chan.sampcntFrac);
is.read_32LE(chan.sampcntInt);
is.read_32LE(chan.sampincFrac);
is.read_32LE(chan.sampincInt);
}
else if (version >= 2)
{
double temp;
is.read_doubleLE(temp); chan.sampcnt = (s64)(temp * (1ll<<32));
is.read_doubleLE(temp); chan.sampinc = (s64)(temp * (1ll<<32));
s64 temp2;
is.read_doubleLE(temp); temp2 = (s64)(temp * (1ll << 32));
chan.sampcntFrac = (u32)temp2;
chan.sampcntInt = (s32)(temp2 >> 32);
is.read_doubleLE(temp); temp2 = (u64)(temp * (1ull << 32)); // Intentionally unsigned
chan.sampincFrac = (u32)temp2;
chan.sampincInt = (u32)(temp2 >> 32);
}
else
{
@ -2016,8 +2031,10 @@ bool spu_loadstate(EMUFILE &is, int size)
// What even is supposed to be happening here?
// sampcnt and sampinc were double type before
// I even made any changes, so this is broken.
is.read_32LE(*(u32 *)&chan.sampcnt);
is.read_32LE(*(u32 *)&chan.sampinc);
chan.sampcntFrac = 0;
is.read_32LE(chan.sampcntInt);
chan.sampincFrac = 0;
is.read_32LE(chan.sampincInt);
}
if (version >= 7) {
for (int i = 0; i < SPUINTERPOLATION_TAPS; i++) is.read_16LE(chan.pcm16b[i]);
@ -2070,12 +2087,16 @@ bool spu_loadstate(EMUFILE &is, int size)
is.read_32LE(spu->regs.cap[i].runtime.curdad);
is.read_32LE(spu->regs.cap[i].runtime.maxdad);
if (version >= 7) {
is.read_64LE(spu->regs.cap[i].runtime.sampcnt);
is.read_32LE(spu->regs.cap[i].runtime.sampcntFrac);
is.read_32LE(spu->regs.cap[i].runtime.sampcntInt);
}
else
{
double temp;
is.read_doubleLE(temp); spu->regs.cap[i].runtime.sampcnt = temp * (1ull << 32);
u64 temp2;
is.read_doubleLE(temp); temp2 = (u64)(temp * (1ull << 32));
spu->regs.cap[i].runtime.sampcntFrac = (u32)temp2;
spu->regs.cap[i].runtime.sampcntInt = (u32)(temp2 >> 32);
}
}
}

View File

@ -91,8 +91,10 @@ struct channel_struct
length(0),
totlength(0),
totlength_shifted(0),
sampcnt(0),
sampinc(0),
sampcntFrac(0),
sampcntInt(0),
sampincFrac(0),
sampincInt(0),
loop_pcm16b(0),
index(0),
loop_index(0),
@ -114,9 +116,11 @@ struct channel_struct
u16 loopstart;
u32 length;
u32 totlength;
s64 totlength_shifted;
s64 sampcnt; // .32fxp
s64 sampinc; // .32fxp
s32 totlength_shifted;
u32 sampcntFrac;
s32 sampcntInt;
u32 sampincFrac;
u32 sampincInt;
s16 pcm16b[SPUINTERPOLATION_TAPS];
// ADPCM specific
s16 loop_pcm16b;
@ -193,7 +197,8 @@ public:
u8 running;
u32 curdad;
u32 maxdad;
s64 sampcnt;
u32 sampcntFrac;
u32 sampcntInt;
SPUFifo fifo;
} runtime;
} cap[2];

View File

@ -195,7 +195,7 @@ void SoundView_Refresh(bool forceRedraw)
sprintf(buf, "$%04X (%.1f Hz)", thischan.timer, (ARM7_CLOCK/2) / (double)(0x10000 - thischan.timer));
SetDlgItemText(hDlg, IDC_SOUND0TMR+chanId, buf);
sprintf(buf, "samp #%d / #%d", (s32)(thischan.sampcnt >> 32), thischan.totlength << format_shift[thischan.format]);
sprintf(buf, "samp #%d / #%d", thischan.sampcntInt, thischan.totlength_shifted);
SetDlgItemText(hDlg, IDC_SOUND0POSLEN+chanId, buf);
}
else {