spu: interpolation is now an emulator option, defaulting to linear, and it is bound to the win32 gui. choosing interpolation:none can net you a small framerate boost.

This commit is contained in:
zeromus 2009-05-16 22:22:06 +00:00
parent 1a6079ce4d
commit 6365f26d7d
7 changed files with 167 additions and 326 deletions

View File

@ -355,6 +355,7 @@ extern struct TCommonSettings {
, BootFromFirmware(false) , BootFromFirmware(false)
, DebugConsole(false) , DebugConsole(false)
, wifiBridgeAdapterNum(0) , wifiBridgeAdapterNum(0)
, spuInterpolationMode(SPUInterpolation_Linear)
{ {
strcpy(ARM9BIOS, "biosnds9.bin"); strcpy(ARM9BIOS, "biosnds9.bin");
strcpy(ARM7BIOS, "biosnds7.bin"); strcpy(ARM7BIOS, "biosnds7.bin");
@ -374,6 +375,7 @@ extern struct TCommonSettings {
bool DebugConsole; bool DebugConsole;
int wifiBridgeAdapterNum; int wifiBridgeAdapterNum;
SPUInterpolationMode spuInterpolationMode;
} CommonSettings; } CommonSettings;
extern char ROMserial[20]; extern char ROMserial[20];

View File

@ -41,7 +41,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//#undef FORCEINLINE //#undef FORCEINLINE
//#define FORCEINLINE //#define FORCEINLINE
#undef SPU_INTERPOLATE
SPU_struct *SPU_core = 0; SPU_struct *SPU_core = 0;
SPU_struct *SPU_user = 0; SPU_struct *SPU_user = 0;
@ -52,19 +51,24 @@ extern SoundInterface_struct *SNDCoreList[];
#define CHANSTAT_STOPPED 0 #define CHANSTAT_STOPPED 0
#define CHANSTAT_PLAY 1 #define CHANSTAT_PLAY 1
//static FORCEINLINE u32 sputrunc(float f) { return u32floor(f); }
static FORCEINLINE int sputrunc(double d) { return (int)d; }
static FORCEINLINE u32 sputrunc(float f) { return u32floor(f); }
static FORCEINLINE u32 sputrunc(double d) { return u32floor(d); }
static FORCEINLINE s32 spudivide(s32 val) { static FORCEINLINE s32 spudivide(s32 val) {
//return val / 127; //more accurate //return val / 127; //more accurate
return val >> 7; //faster return val >> 7; //faster
} }
const s8 indextbl[8] = //const int shift = (FORMAT == 0 ? 2 : 1);
static const int format_shift[] = { 2, 1, 3, 0 };
static const s8 indextbl[8] =
{ {
-1, -1, -1, -1, 2, 4, 6, 8 -1, -1, -1, -1, 2, 4, 6, 8
}; };
const u16 adpcmtbl[89] = static const u16 adpcmtbl[89] =
{ {
0x0007, 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x0010, 0x0007, 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x0010,
0x0011, 0x0013, 0x0015, 0x0017, 0x0019, 0x001C, 0x001F, 0x0022, 0x0025, 0x0011, 0x0013, 0x0015, 0x0017, 0x0019, 0x001C, 0x001F, 0x0022, 0x0025,
@ -78,7 +82,7 @@ const u16 adpcmtbl[89] =
0x41B2, 0x4844, 0x4F7E, 0x5771, 0x602F, 0x69CE, 0x7462, 0x7FFF 0x41B2, 0x4844, 0x4F7E, 0x5771, 0x602F, 0x69CE, 0x7462, 0x7FFF
}; };
const s16 wavedutytbl[8][8] = { static const s16 wavedutytbl[8][8] = {
{ -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, 0x7FFF }, { -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, 0x7FFF },
{ -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, 0x7FFF, 0x7FFF }, { -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, 0x7FFF, 0x7FFF },
{ -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF }, { -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF },
@ -89,10 +93,10 @@ const s16 wavedutytbl[8][8] = {
{ -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF } { -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF }
}; };
s32 precalcdifftbl[89][16]; static s32 precalcdifftbl[89][16];
u8 precalcindextbl[89][8]; static u8 precalcindextbl[89][8];
FILE *spufp=NULL; static FILE *spufp=NULL;
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@ -129,12 +133,12 @@ public:
void lock() { void lock() {
lockCount++; lockCount++;
} }
int lockCount;
u32 addr; u32 addr;
u32 raw_len;
s8* raw_copy; //for memcmp s8* raw_copy; //for memcmp
u32 raw_len;
s16* decoded; //s16 decoded samples s16* decoded; //s16 decoded samples
ADPCMCacheItem *next, *prev; //double linked list ADPCMCacheItem *next, *prev; //double linked list
int lockCount;
}; };
//notes on the cache: //notes on the cache:
@ -577,6 +581,7 @@ void SPU_struct::WriteWord(u32 addr, u16 val)
case 0xA: case 0xA:
thischan.loopstart = val; thischan.loopstart = val;
thischan.totlength = thischan.length + thischan.loopstart; thischan.totlength = thischan.length + thischan.loopstart;
thischan.double_totlength_shifted = (double)(thischan.totlength << format_shift[thischan.format]);
break; break;
} }
@ -627,6 +632,7 @@ void SPU_struct::WriteLong(u32 addr, u32 val)
case 0xC: case 0xC:
thischan.length = val & 0x3FFFFF; thischan.length = val & 0x3FFFFF;
thischan.totlength = thischan.length + thischan.loopstart; thischan.totlength = thischan.length + thischan.loopstart;
thischan.double_totlength_shifted = (double)(thischan.totlength << format_shift[thischan.format]);
break; break;
} }
} }
@ -644,66 +650,69 @@ void SPU_WriteLong(u32 addr, u32 val)
T1WriteLong(MMU.ARM7_REG, addr, val); T1WriteLong(MMU.ARM7_REG, addr, val);
} }
#ifdef SPU_INTERPOLATE
static FORCEINLINE s32 Interpolate(s32 a, s32 b, float ratio)
{
//ratio = ratio - (int)ratio;
//double ratio2 = ((1.0f - cos(ratio * 3.14f)) / 2.0f);
////double ratio2 = (1.0f - cos_lut[((int)(ratio*256.0))&0xFF]) / 2.0f;
//return (((1-ratio2)*a) + (ratio2*b));
//linear interpolation
ratio = ratio - sputrunc(ratio);
return (1-ratio)*a + ratio*b;
}
#endif
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
static FORCEINLINE void Fetch8BitData(channel_struct *chan, s32 *data) template<SPUInterpolationMode INTERPOLATE_MODE> static FORCEINLINE s32 Interpolate(s32 a, s32 b, double _ratio)
{ {
#ifdef SPU_INTERPOLATE float ratio = (float)_ratio;
u32 loc = sputrunc(chan->sampcnt); if(INTERPOLATE_MODE == SPUInterpolation_Cosine)
s32 a = (s32)(chan->buf8[loc] << 8); {
if(loc < (chan->totlength << 2) - 1) { //why did we change it away from the lookup table? somebody should research that
s32 b = (s32)(chan->buf8[loc + 1] << 8); ratio = ratio - (int)ratio;
a = Interpolate(a, b, chan->sampcnt); double ratio2 = ((1.0 - cos(ratio * 3.14)) * 0.5);
//double ratio2 = (1.0f - cos_lut[((int)(ratio*256.0))&0xFF]) / 2.0f;
return (((1-ratio2)*a) + (ratio2*b));
}
else
{
//linear interpolation
ratio = ratio - sputrunc(ratio);
return s32floor((1-ratio)*a + ratio*b);
} }
*data = a;
#else
*data = (s32)chan->buf8[sputrunc(chan->sampcnt)] << 8;
#endif
} }
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
template<bool ADPCM_CACHED> static FORCEINLINE void Fetch16BitData(const channel_struct * const chan, s32 *data) template<SPUInterpolationMode INTERPOLATE_MODE> static FORCEINLINE void Fetch8BitData(channel_struct *chan, s32 *data)
{
u32 loc = sputrunc(chan->sampcnt);
if(INTERPOLATE_MODE != SPUInterpolation_None)
{
s32 a = (s32)(chan->buf8[loc] << 8);
if(loc < (chan->totlength << 2) - 1) {
s32 b = (s32)(chan->buf8[loc + 1] << 8);
a = Interpolate<INTERPOLATE_MODE>(a, b, chan->sampcnt);
}
*data = a;
}
else
*data = (s32)chan->buf8[loc] << 8;
}
template<SPUInterpolationMode INTERPOLATE_MODE, bool ADPCM_CACHED> static FORCEINLINE void Fetch16BitData(const channel_struct * const chan, s32 *data)
{ {
const s16* const buf16 = ADPCM_CACHED ? chan->cacheItem->decoded : chan->buf16; const s16* const buf16 = ADPCM_CACHED ? chan->cacheItem->decoded : chan->buf16;
#ifdef SPU_INTERPOLATE
const int shift = ADPCM_CACHED ? 3 : 1; const int shift = ADPCM_CACHED ? 3 : 1;
int loc = sputrunc(chan->sampcnt); if(INTERPOLATE_MODE != SPUInterpolation_None)
s32 a = (s32)buf16[loc], b;
if(loc < (int)(chan->totlength << shift) - 1)
{ {
b = (s32)buf16[loc + 1]; u32 loc = sputrunc(chan->sampcnt);
a = Interpolate(a, b, chan->sampcnt); s32 a = (s32)buf16[loc], b;
if(loc < (chan->totlength << shift) - 1)
{
s32 b = (s32)buf16[loc + 1];
a = Interpolate<INTERPOLATE_MODE>(a, b, chan->sampcnt);
}
*data = a;
} }
*data = a; else
#else *data = (s32)buf16[sputrunc(chan->sampcnt)];
*data = (s32)buf16[sputrunc(chan->sampcnt)];
#endif
} }
template<SPUInterpolationMode INTERPOLATE_MODE, bool ADPCM_CACHED> static FORCEINLINE void FetchADPCMData(channel_struct * const chan, s32 * const data)
//////////////////////////////////////////////////////////////////////////////
template<bool ADPCM_CACHED> static FORCEINLINE void FetchADPCMData(channel_struct * const chan, s32 * const data)
{ {
if(ADPCM_CACHED) if(ADPCM_CACHED)
{ {
return Fetch16BitData<true>(chan, data); return Fetch16BitData<INTERPOLATE_MODE,true>(chan, data);
} }
// No sense decoding, just return the last sample // No sense decoding, just return the last sample
@ -725,15 +734,12 @@ template<bool ADPCM_CACHED> static FORCEINLINE void FetchADPCMData(channel_struc
chan->lastsampcnt = sputrunc(chan->sampcnt); chan->lastsampcnt = sputrunc(chan->sampcnt);
} }
#ifdef SPU_INTERPOLATE if(INTERPOLATE_MODE != SPUInterpolation_None)
*data = Interpolate((s32)chan->pcm16b_last,(s32)chan->pcm16b,chan->sampcnt); *data = Interpolate<INTERPOLATE_MODE>((s32)chan->pcm16b_last,(s32)chan->pcm16b,chan->sampcnt);
#else else
*data = (s32)chan->pcm16b; *data = (s32)chan->pcm16b;
#endif
} }
//////////////////////////////////////////////////////////////////////////////
static FORCEINLINE void FetchPSGData(channel_struct *chan, s32 *data) static FORCEINLINE void FetchPSGData(channel_struct *chan, s32 *data)
{ {
if(chan->num < 8) if(chan->num < 8)
@ -781,16 +787,12 @@ static FORCEINLINE void MixL(SPU_struct* SPU, channel_struct *chan, s32 data)
SPU->sndbuf[SPU->bufpos<<1] += data; SPU->sndbuf[SPU->bufpos<<1] += data;
} }
//////////////////////////////////////////////////////////////////////////////
static FORCEINLINE void MixR(SPU_struct* SPU, channel_struct *chan, s32 data) static FORCEINLINE void MixR(SPU_struct* SPU, channel_struct *chan, s32 data)
{ {
data = (spudivide(data * chan->vol)) >> chan->datashift; data = (spudivide(data * chan->vol)) >> chan->datashift;
SPU->sndbuf[(SPU->bufpos<<1)+1] += data; SPU->sndbuf[(SPU->bufpos<<1)+1] += data;
} }
//////////////////////////////////////////////////////////////////////////////
static FORCEINLINE void MixLR(SPU_struct* SPU, channel_struct *chan, s32 data) static FORCEINLINE void MixLR(SPU_struct* SPU, channel_struct *chan, s32 data)
{ {
data = (spudivide(data * chan->vol)) >> chan->datashift; data = (spudivide(data * chan->vol)) >> chan->datashift;
@ -806,14 +808,12 @@ template<int FORMAT> static FORCEINLINE void TestForLoop(SPU_struct *SPU, channe
chan->sampcnt += chan->sampinc; chan->sampcnt += chan->sampinc;
if (chan->sampcnt > (double)((chan->length + chan->loopstart) << shift)) if (chan->sampcnt > chan->double_totlength_shifted)
{ {
// Do we loop? Or are we done? // Do we loop? Or are we done?
if (chan->repeat == 1) if (chan->repeat == 1)
{ {
chan->sampcnt = (double)(chan->loopstart << shift); // Is this correct? chan->sampcnt = (double)(chan->loopstart << shift); // Is this correct?
//TODO: ADPCM RESCAN?
//this might would help in case streaming adpcm sounds arent working well
} }
else else
{ {
@ -826,13 +826,11 @@ template<int FORMAT> static FORCEINLINE void TestForLoop(SPU_struct *SPU, channe
} }
} }
//////////////////////////////////////////////////////////////////////////////
static FORCEINLINE void TestForLoop2(SPU_struct *SPU, channel_struct *chan) static FORCEINLINE void TestForLoop2(SPU_struct *SPU, channel_struct *chan)
{ {
chan->sampcnt += chan->sampinc; chan->sampcnt += chan->sampinc;
if (chan->sampcnt > (double)((chan->length + chan->loopstart) << 3)) if (chan->sampcnt > chan->double_totlength_shifted)
{ {
// Do we loop? Or are we done? // Do we loop? Or are we done?
if (chan->repeat == 1) if (chan->repeat == 1)
@ -841,6 +839,8 @@ static FORCEINLINE void TestForLoop2(SPU_struct *SPU, channel_struct *chan)
chan->pcm16b = (s16)((chan->buf8[1] << 8) | chan->buf8[0]); chan->pcm16b = (s16)((chan->buf8[1] << 8) | chan->buf8[0]);
chan->index = chan->buf8[2] & 0x7F; chan->index = chan->buf8[2] & 0x7F;
chan->lastsampcnt = 7; chan->lastsampcnt = 7;
//TODO: ADPCM RESCAN?
//this might would help in case streaming adpcm sounds arent working well
} }
else else
{ {
@ -852,273 +852,87 @@ static FORCEINLINE void TestForLoop2(SPU_struct *SPU, channel_struct *chan)
} }
} }
////////////////////////////////////////////////////////////////////////////// template<int CHANNELS> FORCEINLINE static void SPU_Mix(SPU_struct* SPU, channel_struct *chan, s32 data)
static void SPU_ChanUpdate8LR(SPU_struct* SPU, channel_struct *chan)
{ {
for (; SPU->bufpos < SPU->buflength; SPU->bufpos++) switch(CHANNELS)
{ {
s32 data; case 0: MixL(SPU, chan, data); break;
case 1: MixLR(SPU, chan, data); break;
// fetch data from source address case 2: MixR(SPU, chan, data); break;
Fetch8BitData(chan, &data);
MixLR(SPU, chan, data);
// check to see if we're passed the length and need to loop, etc.
TestForLoop<0>(SPU, chan);
} }
} }
////////////////////////////////////////////////////////////////////////////// template<int FORMAT, SPUInterpolationMode INTERPOLATE_MODE, int CHANNELS, bool CACHED>
FORCEINLINE static void _____SPU_ChanUpdate(SPU_struct* const SPU, channel_struct* const chan)
static void SPU_ChanUpdate8NoMix(SPU_struct *SPU, channel_struct *chan)
{ {
for (; SPU->bufpos < SPU->buflength; SPU->bufpos++) for (; SPU->bufpos < SPU->buflength; SPU->bufpos++)
{ {
// check to see if we're passed the length and need to loop, etc. if(CHANNELS != -1)
TestForLoop<0>(SPU, chan);
}
}
static void SPU_ChanUpdate8L(SPU_struct *SPU, channel_struct *chan)
{
for (; SPU->bufpos < SPU->buflength; SPU->bufpos++)
{
s32 data;
// fetch data from source address
Fetch8BitData(chan, &data);
MixL(SPU, chan, data);
// check to see if we're passed the length and need to loop, etc.
TestForLoop<0>(SPU, chan);
}
}
//////////////////////////////////////////////////////////////////////////////
static void SPU_ChanUpdate8R(SPU_struct* SPU, channel_struct *chan)
{
for (; SPU->bufpos < SPU->buflength; SPU->bufpos++)
{
s32 data;
// fetch data from source address
Fetch8BitData(chan, &data);
MixR(SPU, chan, data);
// check to see if we're passed the length and need to loop, etc.
TestForLoop<0>(SPU, chan);
}
}
//////////////////////////////////////////////////////////////////////////////
static void SPU_ChanUpdate16NoMix(SPU_struct *SPU, channel_struct *chan)
{
for (; SPU->bufpos < SPU->buflength; SPU->bufpos++)
{
// check to see if we're passed the length and need to loop, etc.
TestForLoop<1>(SPU, chan);
}
}
static void SPU_ChanUpdate16LR(SPU_struct* SPU, channel_struct *chan)
{
for (; SPU->bufpos < SPU->buflength; SPU->bufpos++)
{
s32 data;
// fetch data from source address
Fetch16BitData<false>(chan, &data);
MixLR(SPU, chan, data);
// check to see if we're passed the length and need to loop, etc.
TestForLoop<1>(SPU, chan);
}
}
//////////////////////////////////////////////////////////////////////////////
static void SPU_ChanUpdate16L(SPU_struct* SPU, channel_struct *chan)
{
for (; SPU->bufpos < SPU->buflength; SPU->bufpos++)
{
s32 data;
// fetch data from source address
Fetch16BitData<false>(chan, &data);
MixL(SPU, chan, data);
// check to see if we're passed the length and need to loop, etc.
TestForLoop<1>(SPU, chan);
}
}
//////////////////////////////////////////////////////////////////////////////
static void SPU_ChanUpdate16R(SPU_struct* SPU, channel_struct *chan)
{
for (; SPU->bufpos < SPU->buflength; SPU->bufpos++)
{
s32 data;
// fetch data from source address
Fetch16BitData<false>(chan, &data);
MixR(SPU, chan, data);
// check to see if we're passed the length and need to loop, etc.
TestForLoop<1>(SPU, chan);
}
}
//////////////////////////////////////////////////////////////////////////////
static void SPU_ChanUpdateADPCMNoMix(SPU_struct *SPU, channel_struct *chan)
{
for (; SPU->bufpos < SPU->buflength; SPU->bufpos++)
{
// check to see if we're passed the length and need to loop, etc.
TestForLoop2(SPU, chan);
}
}
template<int CHANNELS, bool CACHED> FORCEINLINE static void SPU_ChanUpdateADPCM_generic(SPU_struct* SPU, channel_struct *chan)
{
for (; SPU->bufpos < SPU->buflength; SPU->bufpos++)
{
s32 data;
FetchADPCMData<CACHED>(chan, &data);
switch(CHANNELS)
{ {
case 0: MixL(SPU, chan, data); break; s32 data;
case 1: MixLR(SPU, chan, data); break; switch(FORMAT)
case 2: MixR(SPU, chan, data); break; {
case 0: Fetch8BitData<INTERPOLATE_MODE>(chan, &data); break;
case 1: Fetch16BitData<INTERPOLATE_MODE,false>(chan, &data); break;
case 2: FetchADPCMData<INTERPOLATE_MODE,CACHED>(chan, &data); break;
case 3: FetchPSGData(chan, &data); break;
}
SPU_Mix<CHANNELS>(SPU, chan, data);
} }
// check to see if we're passed the length and need to loop, etc. switch(FORMAT) {
TestForLoop2(SPU, chan); case 0: case 1: TestForLoop<FORMAT>(SPU, chan); break;
case 2: TestForLoop2(SPU, chan); break;
case 3: chan->sampcnt += chan->sampinc; break;
}
} }
} }
static void SPU_ChanUpdateADPCMLR(SPU_struct* SPU, channel_struct *chan) template<int FORMAT, SPUInterpolationMode INTERPOLATE_MODE, int CHANNELS>
FORCEINLINE static void ____SPU_ChanUpdate(SPU_struct* const SPU, channel_struct* const chan)
{ {
if(chan->cacheItem) SPU_ChanUpdateADPCM_generic<1,true>(SPU,chan); if(FORMAT == 2 && chan->cacheItem)
else SPU_ChanUpdateADPCM_generic<1,false>(SPU,chan); _____SPU_ChanUpdate<FORMAT,INTERPOLATE_MODE,CHANNELS,true>(SPU,chan);
else _____SPU_ChanUpdate<FORMAT,INTERPOLATE_MODE,CHANNELS,false>(SPU,chan);
} }
static void SPU_ChanUpdateADPCML(SPU_struct* SPU, channel_struct *chan) template<int FORMAT, SPUInterpolationMode INTERPOLATE_MODE>
FORCEINLINE static void ___SPU_ChanUpdate(const bool actuallyMix, SPU_struct* const SPU, channel_struct* const chan)
{ {
if(chan->cacheItem) SPU_ChanUpdateADPCM_generic<0,true>(SPU,chan); if(!actuallyMix)
else SPU_ChanUpdateADPCM_generic<0,false>(SPU,chan); ____SPU_ChanUpdate<FORMAT,INTERPOLATE_MODE,-1>(SPU,chan);
else if (chan->pan == 0)
____SPU_ChanUpdate<FORMAT,INTERPOLATE_MODE,0>(SPU,chan);
else if (chan->pan == 127)
____SPU_ChanUpdate<FORMAT,INTERPOLATE_MODE,2>(SPU,chan);
else
____SPU_ChanUpdate<FORMAT,INTERPOLATE_MODE,1>(SPU,chan);
} }
static void SPU_ChanUpdateADPCMR(SPU_struct* SPU, channel_struct *chan) template<SPUInterpolationMode INTERPOLATE_MODE>
FORCEINLINE static void __SPU_ChanUpdate(const bool actuallyMix, SPU_struct* const SPU, channel_struct* const chan)
{ {
if(chan->cacheItem) SPU_ChanUpdateADPCM_generic<2,true>(SPU,chan); switch(chan->format)
else SPU_ChanUpdateADPCM_generic<2,false>(SPU,chan);
}
//////////////////////////////////////////////////////////////////////////////
static void SPU_ChanUpdatePSGNoMix(SPU_struct* SPU, channel_struct *chan)
{
for (; SPU->bufpos < SPU->buflength; SPU->bufpos++)
{ {
chan->sampcnt += chan->sampinc; case 0: ___SPU_ChanUpdate<0,INTERPOLATE_MODE>(actuallyMix, SPU, chan); break;
case 1: ___SPU_ChanUpdate<1,INTERPOLATE_MODE>(actuallyMix, SPU, chan); break;
case 2: ___SPU_ChanUpdate<2,INTERPOLATE_MODE>(actuallyMix, SPU, chan); break;
case 3: ___SPU_ChanUpdate<3,INTERPOLATE_MODE>(actuallyMix, SPU, chan); break;
default: assert(false);
} }
} }
FORCEINLINE static void _SPU_ChanUpdate(const bool actuallyMix, SPU_struct* const SPU, channel_struct* const chan)
static void SPU_ChanUpdatePSGLR(SPU_struct* SPU, channel_struct *chan)
{ {
for (; SPU->bufpos < SPU->buflength; SPU->bufpos++) switch(CommonSettings.spuInterpolationMode)
{ {
s32 data; case SPUInterpolation_None: __SPU_ChanUpdate<SPUInterpolation_None>(actuallyMix, SPU, chan); break;
case SPUInterpolation_Linear: __SPU_ChanUpdate<SPUInterpolation_Linear>(actuallyMix, SPU, chan); break;
// fetch data from source address case SPUInterpolation_Cosine: __SPU_ChanUpdate<SPUInterpolation_Cosine>(actuallyMix, SPU, chan); break;
FetchPSGData(chan, &data); default: assert(false);
MixLR(SPU, chan, data);
chan->sampcnt += chan->sampinc;
} }
} }
//////////////////////////////////////////////////////////////////////////////
static void SPU_ChanUpdatePSGL(SPU_struct* SPU, channel_struct *chan)
{
for (; SPU->bufpos < SPU->buflength; SPU->bufpos++)
{
s32 data;
// fetch data from source address
FetchPSGData(chan, &data);
MixL(SPU, chan, data);
chan->sampcnt += chan->sampinc;
}
}
//////////////////////////////////////////////////////////////////////////////
static void SPU_ChanUpdatePSGR(SPU_struct* SPU, channel_struct *chan)
{
for (; SPU->bufpos < SPU->buflength; SPU->bufpos++)
{
s32 data;
// fetch data from source address
FetchPSGData(chan, &data);
MixR(SPU, chan, data);
chan->sampcnt += chan->sampinc;
}
}
//////////////////////////////////////////////////////////////////////////////
void (*SPU_ChanUpdate[4][4])(SPU_struct* SPU, channel_struct *chan) = {
{ // 8-bit PCM
SPU_ChanUpdate8L,
SPU_ChanUpdate8LR,
SPU_ChanUpdate8R,
SPU_ChanUpdate8NoMix
},
{ // 16-bit PCM
SPU_ChanUpdate16L,
SPU_ChanUpdate16LR,
SPU_ChanUpdate16R,
SPU_ChanUpdate16NoMix,
},
{ // IMA-ADPCM
SPU_ChanUpdateADPCML,
SPU_ChanUpdateADPCMLR,
SPU_ChanUpdateADPCMR,
SPU_ChanUpdateADPCMNoMix
},
{ // PSG/White Noise
SPU_ChanUpdatePSGL,
SPU_ChanUpdatePSGLR,
SPU_ChanUpdatePSGR,
SPU_ChanUpdatePSGNoMix
}
};
//////////////////////////////////////////////////////////////////////////////
template<bool actuallyMix> template<bool actuallyMix>
static void SPU_MixAudio(SPU_struct *SPU, int length) static void SPU_MixAudio(SPU_struct *SPU, int length)
{ {
@ -1152,14 +966,7 @@ static void SPU_MixAudio(SPU_struct *SPU, int length)
SPU->buflength = length; SPU->buflength = length;
// Mix audio // Mix audio
if(!actuallyMix) _SPU_ChanUpdate(actuallyMix, SPU, chan);
SPU_ChanUpdate[chan->format][3](SPU,chan);
else if (chan->pan == 0)
SPU_ChanUpdate[chan->format][0](SPU,chan);
else if (chan->pan == 127)
SPU_ChanUpdate[chan->format][2](SPU,chan);
else
SPU_ChanUpdate[chan->format][1](SPU,chan);
} }
// convert from 32-bit->16-bit // convert from 32-bit->16-bit
@ -1488,6 +1295,7 @@ bool spu_loadstate(std::istream* is, int size)
read16le(&chan.loopstart,is); read16le(&chan.loopstart,is);
read32le(&chan.length,is); read32le(&chan.length,is);
chan.totlength = chan.length + chan.loopstart; chan.totlength = chan.length + chan.loopstart;
chan.double_totlength_shifted = (double)(chan.totlength << format_shift[chan.format]);
if(version == 0) if(version == 0)
{ {
u64 temp; u64 temp;

View File

@ -27,7 +27,14 @@
#define SNDCORE_DUMMY 0 #define SNDCORE_DUMMY 0
#define SNDCORE_FILEWRITE 1 #define SNDCORE_FILEWRITE 1
typedef struct enum SPUInterpolationMode
{
SPUInterpolation_None = 0,
SPUInterpolation_Linear = 1,
SPUInterpolation_Cosine = 2
};
struct SoundInterface_struct
{ {
int id; int id;
const char *Name; const char *Name;
@ -38,7 +45,7 @@ typedef struct
void (*MuteAudio)(); void (*MuteAudio)();
void (*UnMuteAudio)(); void (*UnMuteAudio)();
void (*SetVolume)(int volume); void (*SetVolume)(int volume);
} SoundInterface_struct; };
extern SoundInterface_struct SNDDummy; extern SoundInterface_struct SNDDummy;
extern SoundInterface_struct SNDFile; extern SoundInterface_struct SNDFile;
@ -64,6 +71,7 @@ struct channel_struct
u16 loopstart; u16 loopstart;
u32 length; u32 length;
u32 totlength; u32 totlength;
double double_totlength_shifted;
union { union {
s8 *buf8; s8 *buf8;
s16 *buf16; s16 *buf16;

View File

@ -98,7 +98,7 @@ void Vector4Copy(float *dst, const float *src);
} //extern "C" } //extern "C"
//this function is an unreliable, inaccurate floor. //these functions are an unreliable, inaccurate floor.
//it should only be used for positive numbers //it should only be used for positive numbers
//this isnt as fast as it could be if we used a visual c++ intrinsic, but those appear not to be universally available //this isnt as fast as it could be if we used a visual c++ intrinsic, but those appear not to be universally available
FORCEINLINE u32 u32floor(float f) FORCEINLINE u32 u32floor(float f)
@ -109,6 +109,14 @@ FORCEINLINE u32 u32floor(float f)
return (u32)f; return (u32)f;
#endif #endif
} }
FORCEINLINE u32 u32floor(double d)
{
#ifndef NOSSE2
__asm cvttsd2si eax, d;
#else
return (u32)d;
#endif
}
//same as above but works for negative values too. //same as above but works for negative values too.
//be sure that the results are the same thing as floorf! //be sure that the results are the same thing as floorf!

View File

@ -1833,6 +1833,7 @@ int WINAPI WinMain (HINSTANCE hThisInstance,
LOG("Init sound core\n"); LOG("Init sound core\n");
sndcoretype = GetPrivateProfileInt("Sound","SoundCore", SNDCORE_DIRECTX, IniName); sndcoretype = GetPrivateProfileInt("Sound","SoundCore", SNDCORE_DIRECTX, IniName);
sndbuffersize = GetPrivateProfileInt("Sound","SoundBufferSize", 735 * 4, IniName); sndbuffersize = GetPrivateProfileInt("Sound","SoundBufferSize", 735 * 4, IniName);
CommonSettings.spuInterpolationMode = (SPUInterpolationMode)GetPrivateProfileInt("Sound","SPUInterpolation", 1, IniName);
EnterCriticalSection(&win_sync); EnterCriticalSection(&win_sync);
int spu_ret = SPU_ChangeSoundCore(sndcoretype, sndbuffersize); int spu_ret = SPU_ChangeSoundCore(sndcoretype, sndbuffersize);
@ -3914,6 +3915,13 @@ LRESULT CALLBACK SoundSettingsDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARA
SendDlgItemMessage(hDlg, IDC_SOUNDCORECB, CB_SETCURSEL, i, 0); SendDlgItemMessage(hDlg, IDC_SOUNDCORECB, CB_SETCURSEL, i, 0);
} }
//setup interpolation combobox
SendDlgItemMessage(hDlg, IDC_SPU_INTERPOLATION_CB, CB_RESETCONTENT, 0, 0);
SendDlgItemMessage(hDlg, IDC_SPU_INTERPOLATION_CB, CB_ADDSTRING, 0, (LPARAM)"None (fastest, sounds bad)");
SendDlgItemMessage(hDlg, IDC_SPU_INTERPOLATION_CB, CB_ADDSTRING, 0, (LPARAM)"Linear (typical, sounds good)");
SendDlgItemMessage(hDlg, IDC_SPU_INTERPOLATION_CB, CB_ADDSTRING, 0, (LPARAM)"Cosine (slowest, sounds best)");
SendDlgItemMessage(hDlg, IDC_SPU_INTERPOLATION_CB, CB_SETCURSEL, (int)CommonSettings.spuInterpolationMode, 0);
// Setup Sound Buffer Size Edit Text // Setup Sound Buffer Size Edit Text
sprintf(tempstr, "%d", sndbuffersize); sprintf(tempstr, "%d", sndbuffersize);
SetDlgItemText(hDlg, IDC_SOUNDBUFFERET, tempstr); SetDlgItemText(hDlg, IDC_SOUNDBUFFERET, tempstr);
@ -3969,6 +3977,10 @@ LRESULT CALLBACK SoundSettingsDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARA
WritePrivateProfileString("Sound", "Volume", tempstr, IniName); WritePrivateProfileString("Sound", "Volume", tempstr, IniName);
SPU_SetVolume(sndvolume); SPU_SetVolume(sndvolume);
//write interpolation type
CommonSettings.spuInterpolationMode = (SPUInterpolationMode)SendDlgItemMessage(hDlg, IDC_SPU_INTERPOLATION_CB, CB_GETCURSEL, 0, 0);
WritePrivateProfileInt("Sound","SPUInterpolation",(int)CommonSettings.spuInterpolationMode, IniName);
return TRUE; return TRUE;
} }
case IDCANCEL: case IDCANCEL:

View File

@ -239,6 +239,7 @@
#define IDC_EDIT11 1004 #define IDC_EDIT11 1004
#define IDC_GI_GAMECODE 1004 #define IDC_GI_GAMECODE 1004
#define IDC_ROTATE90 1004 #define IDC_ROTATE90 1004
#define IDC_SPU_INTERPOLATION_CB 1004
#define IDC_ARM7BIOS 1005 #define IDC_ARM7BIOS 1005
#define IDC_EDIT07 1005 #define IDC_EDIT07 1005
#define IDC_ROTATE180 1005 #define IDC_ROTATE180 1005

View File

@ -3377,7 +3377,7 @@ FONT 8, "MS Sans Serif", 0, 0, 1
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
IDD_SOUNDSETTINGS DIALOGEX 0, 0, 174, 96 IDD_SOUNDSETTINGS DIALOGEX 0, 0, 174, 127
STYLE DS_CENTER | DS_MODALFRAME | DS_SETFONT | WS_VISIBLE | WS_BORDER | WS_CAPTION | WS_DLGFRAME | WS_POPUP | WS_SYSMENU STYLE DS_CENTER | DS_MODALFRAME | DS_SETFONT | WS_VISIBLE | WS_BORDER | WS_CAPTION | WS_DLGFRAME | WS_POPUP | WS_SYSMENU
CAPTION "Sound Settings" CAPTION "Sound Settings"
FONT 8, "MS Sans Serif", 0, 0, 1 FONT 8, "MS Sans Serif", 0, 0, 1
@ -3385,13 +3385,15 @@ FONT 8, "MS Sans Serif", 0, 0, 1
GROUPBOX "Sound Core Settings", -1, 3, 2, 168, 28 GROUPBOX "Sound Core Settings", -1, 3, 2, 168, 28
LTEXT "Sound Core", -1, 10, 14, 40, 10, SS_LEFT LTEXT "Sound Core", -1, 10, 14, 40, 10, SS_LEFT
COMBOBOX IDC_SOUNDCORECB, 54, 13, 110, 33, WS_TABSTOP | WS_VSCROLL | WS_TABSTOP | CBS_DROPDOWNLIST COMBOBOX IDC_SOUNDCORECB, 54, 13, 110, 33, WS_TABSTOP | WS_VSCROLL | WS_TABSTOP | CBS_DROPDOWNLIST
GROUPBOX "Other Settings", -1, 3, 31, 168, 43 GROUPBOX "Other Settings", -1, 3, 31, 168, 61
LTEXT "Buffer Size", -1, 10, 42, 60, 10, SS_LEFT LTEXT "Buffer Size", -1, 10, 62, 60, 10, SS_LEFT
EDITTEXT IDC_SOUNDBUFFERET, 136, 41, 28, 13 EDITTEXT IDC_SOUNDBUFFERET, 55, 61, 42, 13
LTEXT "Volume", -1, 10, 57, 30, 10, SS_LEFT LTEXT "Volume", -1, 10, 77, 30, 10, SS_LEFT
CONTROL "", IDC_SLVOLUME, TRACKBAR_CLASS, 0, 40, 57, 128, 10 CONTROL "", IDC_SLVOLUME, TRACKBAR_CLASS, 0, 40, 77, 128, 10
DEFPUSHBUTTON "&OK", IDOK, 82, 78, 40, 14, BS_DEFPUSHBUTTON DEFPUSHBUTTON "&OK", IDOK, 82, 97, 40, 14, BS_DEFPUSHBUTTON
PUSHBUTTON "&Cancel", IDCANCEL, 127, 78, 40, 14, BS_PUSHBUTTON PUSHBUTTON "&Cancel", IDCANCEL, 127, 97, 40, 14, BS_PUSHBUTTON
LTEXT "Interpolation", -1, 9, 46, 40, 8, SS_LEFT
COMBOBOX IDC_SPU_INTERPOLATION_CB, 55, 42, 110, 33, WS_TABSTOP | WS_VSCROLL | WS_TABSTOP | CBS_DROPDOWNLIST
} }