From 6365f26d7de0e456f786b58b42e5d5ce35c20ed9 Mon Sep 17 00:00:00 2001 From: zeromus Date: Sat, 16 May 2009 22:22:06 +0000 Subject: [PATCH] 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. --- desmume/src/NDSSystem.h | 2 + desmume/src/SPU.cpp | 438 +++++++++---------------------- desmume/src/SPU.h | 12 +- desmume/src/matrix.h | 10 +- desmume/src/windows/main.cpp | 12 + desmume/src/windows/resource.h | 1 + desmume/src/windows/resources.rc | 18 +- 7 files changed, 167 insertions(+), 326 deletions(-) diff --git a/desmume/src/NDSSystem.h b/desmume/src/NDSSystem.h index 9c9330e5f..28126efff 100644 --- a/desmume/src/NDSSystem.h +++ b/desmume/src/NDSSystem.h @@ -355,6 +355,7 @@ extern struct TCommonSettings { , BootFromFirmware(false) , DebugConsole(false) , wifiBridgeAdapterNum(0) + , spuInterpolationMode(SPUInterpolation_Linear) { strcpy(ARM9BIOS, "biosnds9.bin"); strcpy(ARM7BIOS, "biosnds7.bin"); @@ -374,6 +375,7 @@ extern struct TCommonSettings { bool DebugConsole; int wifiBridgeAdapterNum; + SPUInterpolationMode spuInterpolationMode; } CommonSettings; extern char ROMserial[20]; diff --git a/desmume/src/SPU.cpp b/desmume/src/SPU.cpp index 83a8a3f39..cb74bd4be 100644 --- a/desmume/src/SPU.cpp +++ b/desmume/src/SPU.cpp @@ -41,7 +41,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA //#undef FORCEINLINE //#define FORCEINLINE -#undef SPU_INTERPOLATE SPU_struct *SPU_core = 0; SPU_struct *SPU_user = 0; @@ -52,19 +51,24 @@ extern SoundInterface_struct *SNDCoreList[]; #define CHANSTAT_STOPPED 0 #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) { //return val / 127; //more accurate 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 }; -const u16 adpcmtbl[89] = +static const u16 adpcmtbl[89] = { 0x0007, 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x0010, 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 }; -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 }, @@ -89,10 +93,10 @@ const s16 wavedutytbl[8][8] = { { -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF } }; -s32 precalcdifftbl[89][16]; -u8 precalcindextbl[89][8]; +static s32 precalcdifftbl[89][16]; +static u8 precalcindextbl[89][8]; -FILE *spufp=NULL; +static FILE *spufp=NULL; ////////////////////////////////////////////////////////////////////////////// @@ -129,12 +133,12 @@ public: void lock() { lockCount++; } + int lockCount; u32 addr; - u32 raw_len; s8* raw_copy; //for memcmp + u32 raw_len; s16* decoded; //s16 decoded samples ADPCMCacheItem *next, *prev; //double linked list - int lockCount; }; //notes on the cache: @@ -577,6 +581,7 @@ void SPU_struct::WriteWord(u32 addr, u16 val) case 0xA: thischan.loopstart = val; thischan.totlength = thischan.length + thischan.loopstart; + thischan.double_totlength_shifted = (double)(thischan.totlength << format_shift[thischan.format]); break; } @@ -627,6 +632,7 @@ void SPU_struct::WriteLong(u32 addr, u32 val) case 0xC: thischan.length = val & 0x3FFFFF; thischan.totlength = thischan.length + thischan.loopstart; + thischan.double_totlength_shifted = (double)(thischan.totlength << format_shift[thischan.format]); break; } } @@ -644,66 +650,69 @@ void SPU_WriteLong(u32 addr, u32 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 static FORCEINLINE s32 Interpolate(s32 a, s32 b, double _ratio) { -#ifdef SPU_INTERPOLATE - u32 loc = sputrunc(chan->sampcnt); - s32 a = (s32)(chan->buf8[loc] << 8); - if(loc < (chan->totlength << 2) - 1) { - s32 b = (s32)(chan->buf8[loc + 1] << 8); - a = Interpolate(a, b, chan->sampcnt); + float ratio = (float)_ratio; + if(INTERPOLATE_MODE == SPUInterpolation_Cosine) + { + //why did we change it away from the lookup table? somebody should research that + ratio = ratio - (int)ratio; + 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 static FORCEINLINE void Fetch16BitData(const channel_struct * const chan, s32 *data) +template 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(a, b, chan->sampcnt); + } + *data = a; + } + else + *data = (s32)chan->buf8[loc] << 8; +} + +template static FORCEINLINE void Fetch16BitData(const channel_struct * const chan, s32 *data) { const s16* const buf16 = ADPCM_CACHED ? chan->cacheItem->decoded : chan->buf16; -#ifdef SPU_INTERPOLATE const int shift = ADPCM_CACHED ? 3 : 1; - int loc = sputrunc(chan->sampcnt); - s32 a = (s32)buf16[loc], b; - if(loc < (int)(chan->totlength << shift) - 1) + if(INTERPOLATE_MODE != SPUInterpolation_None) { - b = (s32)buf16[loc + 1]; - a = Interpolate(a, b, chan->sampcnt); + u32 loc = sputrunc(chan->sampcnt); + s32 a = (s32)buf16[loc], b; + if(loc < (chan->totlength << shift) - 1) + { + s32 b = (s32)buf16[loc + 1]; + a = Interpolate(a, b, chan->sampcnt); + } + *data = a; } - *data = a; -#else - *data = (s32)buf16[sputrunc(chan->sampcnt)]; -#endif + else + *data = (s32)buf16[sputrunc(chan->sampcnt)]; } - - -////////////////////////////////////////////////////////////////////////////// - -template static FORCEINLINE void FetchADPCMData(channel_struct * const chan, s32 * const data) +template static FORCEINLINE void FetchADPCMData(channel_struct * const chan, s32 * const data) { if(ADPCM_CACHED) { - return Fetch16BitData(chan, data); + return Fetch16BitData(chan, data); } // No sense decoding, just return the last sample @@ -725,15 +734,12 @@ template static FORCEINLINE void FetchADPCMData(channel_struc chan->lastsampcnt = sputrunc(chan->sampcnt); } -#ifdef SPU_INTERPOLATE - *data = Interpolate((s32)chan->pcm16b_last,(s32)chan->pcm16b,chan->sampcnt); -#else - *data = (s32)chan->pcm16b; -#endif + if(INTERPOLATE_MODE != SPUInterpolation_None) + *data = Interpolate((s32)chan->pcm16b_last,(s32)chan->pcm16b,chan->sampcnt); + else + *data = (s32)chan->pcm16b; } -////////////////////////////////////////////////////////////////////////////// - static FORCEINLINE void FetchPSGData(channel_struct *chan, s32 *data) { 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; } -////////////////////////////////////////////////////////////////////////////// - static FORCEINLINE void MixR(SPU_struct* SPU, channel_struct *chan, s32 data) { data = (spudivide(data * chan->vol)) >> chan->datashift; SPU->sndbuf[(SPU->bufpos<<1)+1] += data; } -////////////////////////////////////////////////////////////////////////////// - static FORCEINLINE void MixLR(SPU_struct* SPU, channel_struct *chan, s32 data) { data = (spudivide(data * chan->vol)) >> chan->datashift; @@ -806,14 +808,12 @@ template static FORCEINLINE void TestForLoop(SPU_struct *SPU, channe 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? if (chan->repeat == 1) { 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 { @@ -826,13 +826,11 @@ template static FORCEINLINE void TestForLoop(SPU_struct *SPU, channe } } -////////////////////////////////////////////////////////////////////////////// - static FORCEINLINE void TestForLoop2(SPU_struct *SPU, channel_struct *chan) { 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? 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->index = chan->buf8[2] & 0x7F; chan->lastsampcnt = 7; + //TODO: ADPCM RESCAN? + //this might would help in case streaming adpcm sounds arent working well } else { @@ -852,273 +852,87 @@ static FORCEINLINE void TestForLoop2(SPU_struct *SPU, channel_struct *chan) } } -////////////////////////////////////////////////////////////////////////////// - -static void SPU_ChanUpdate8LR(SPU_struct* SPU, channel_struct *chan) +template FORCEINLINE static void SPU_Mix(SPU_struct* SPU, channel_struct *chan, s32 data) { - for (; SPU->bufpos < SPU->buflength; SPU->bufpos++) + switch(CHANNELS) { - s32 data; - - // fetch data from source address - 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); + case 0: MixL(SPU, chan, data); break; + case 1: MixLR(SPU, chan, data); break; + case 2: MixR(SPU, chan, data); break; } } -////////////////////////////////////////////////////////////////////////////// - -static void SPU_ChanUpdate8NoMix(SPU_struct *SPU, channel_struct *chan) +template + FORCEINLINE static void _____SPU_ChanUpdate(SPU_struct* const SPU, channel_struct* const chan) { for (; SPU->bufpos < SPU->buflength; SPU->bufpos++) { - // check to see if we're passed the length and need to loop, etc. - 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(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(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(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 FORCEINLINE static void SPU_ChanUpdateADPCM_generic(SPU_struct* SPU, channel_struct *chan) -{ - for (; SPU->bufpos < SPU->buflength; SPU->bufpos++) - { - s32 data; - - FetchADPCMData(chan, &data); - - switch(CHANNELS) + if(CHANNELS != -1) { - case 0: MixL(SPU, chan, data); break; - case 1: MixLR(SPU, chan, data); break; - case 2: MixR(SPU, chan, data); break; + s32 data; + switch(FORMAT) + { + case 0: Fetch8BitData(chan, &data); break; + case 1: Fetch16BitData(chan, &data); break; + case 2: FetchADPCMData(chan, &data); break; + case 3: FetchPSGData(chan, &data); break; + } + SPU_Mix(SPU, chan, data); } - // check to see if we're passed the length and need to loop, etc. - TestForLoop2(SPU, chan); + switch(FORMAT) { + case 0: case 1: TestForLoop(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 + FORCEINLINE static void ____SPU_ChanUpdate(SPU_struct* const SPU, channel_struct* const chan) { - if(chan->cacheItem) SPU_ChanUpdateADPCM_generic<1,true>(SPU,chan); - else SPU_ChanUpdateADPCM_generic<1,false>(SPU,chan); + if(FORMAT == 2 && chan->cacheItem) + _____SPU_ChanUpdate(SPU,chan); + else _____SPU_ChanUpdate(SPU,chan); } -static void SPU_ChanUpdateADPCML(SPU_struct* SPU, channel_struct *chan) +template + 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); - else SPU_ChanUpdateADPCM_generic<0,false>(SPU,chan); + if(!actuallyMix) + ____SPU_ChanUpdate(SPU,chan); + else if (chan->pan == 0) + ____SPU_ChanUpdate(SPU,chan); + else if (chan->pan == 127) + ____SPU_ChanUpdate(SPU,chan); + else + ____SPU_ChanUpdate(SPU,chan); } -static void SPU_ChanUpdateADPCMR(SPU_struct* SPU, channel_struct *chan) +template + 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); - 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++) + switch(chan->format) { - 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); } } - -static void SPU_ChanUpdatePSGLR(SPU_struct* SPU, channel_struct *chan) +FORCEINLINE static void _SPU_ChanUpdate(const bool actuallyMix, SPU_struct* const SPU, channel_struct* const chan) { - for (; SPU->bufpos < SPU->buflength; SPU->bufpos++) + switch(CommonSettings.spuInterpolationMode) { - s32 data; - - // fetch data from source address - FetchPSGData(chan, &data); - - MixLR(SPU, chan, data); - - chan->sampcnt += chan->sampinc; + case SPUInterpolation_None: __SPU_ChanUpdate(actuallyMix, SPU, chan); break; + case SPUInterpolation_Linear: __SPU_ChanUpdate(actuallyMix, SPU, chan); break; + case SPUInterpolation_Cosine: __SPU_ChanUpdate(actuallyMix, SPU, chan); break; + default: assert(false); } } -////////////////////////////////////////////////////////////////////////////// - -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 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; // Mix audio - if(!actuallyMix) - 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); + _SPU_ChanUpdate(actuallyMix, SPU, chan); } // convert from 32-bit->16-bit @@ -1488,6 +1295,7 @@ bool spu_loadstate(std::istream* is, int size) read16le(&chan.loopstart,is); read32le(&chan.length,is); chan.totlength = chan.length + chan.loopstart; + chan.double_totlength_shifted = (double)(chan.totlength << format_shift[chan.format]); if(version == 0) { u64 temp; diff --git a/desmume/src/SPU.h b/desmume/src/SPU.h index 70685f580..d0f00659d 100644 --- a/desmume/src/SPU.h +++ b/desmume/src/SPU.h @@ -27,7 +27,14 @@ #define SNDCORE_DUMMY 0 #define SNDCORE_FILEWRITE 1 -typedef struct +enum SPUInterpolationMode +{ + SPUInterpolation_None = 0, + SPUInterpolation_Linear = 1, + SPUInterpolation_Cosine = 2 +}; + +struct SoundInterface_struct { int id; const char *Name; @@ -38,7 +45,7 @@ typedef struct void (*MuteAudio)(); void (*UnMuteAudio)(); void (*SetVolume)(int volume); -} SoundInterface_struct; +}; extern SoundInterface_struct SNDDummy; extern SoundInterface_struct SNDFile; @@ -64,6 +71,7 @@ struct channel_struct u16 loopstart; u32 length; u32 totlength; + double double_totlength_shifted; union { s8 *buf8; s16 *buf16; diff --git a/desmume/src/matrix.h b/desmume/src/matrix.h index d28a87a47..10407d350 100644 --- a/desmume/src/matrix.h +++ b/desmume/src/matrix.h @@ -98,7 +98,7 @@ void Vector4Copy(float *dst, const float *src); } //extern "C" -//this function is an unreliable, inaccurate floor. +//these functions are an unreliable, inaccurate floor. //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 FORCEINLINE u32 u32floor(float f) @@ -109,6 +109,14 @@ FORCEINLINE u32 u32floor(float f) return (u32)f; #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. //be sure that the results are the same thing as floorf! diff --git a/desmume/src/windows/main.cpp b/desmume/src/windows/main.cpp index 82b16f5af..df95df9db 100644 --- a/desmume/src/windows/main.cpp +++ b/desmume/src/windows/main.cpp @@ -1833,6 +1833,7 @@ int WINAPI WinMain (HINSTANCE hThisInstance, LOG("Init sound core\n"); sndcoretype = GetPrivateProfileInt("Sound","SoundCore", SNDCORE_DIRECTX, IniName); sndbuffersize = GetPrivateProfileInt("Sound","SoundBufferSize", 735 * 4, IniName); + CommonSettings.spuInterpolationMode = (SPUInterpolationMode)GetPrivateProfileInt("Sound","SPUInterpolation", 1, IniName); EnterCriticalSection(&win_sync); 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); } + //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 sprintf(tempstr, "%d", sndbuffersize); SetDlgItemText(hDlg, IDC_SOUNDBUFFERET, tempstr); @@ -3969,6 +3977,10 @@ LRESULT CALLBACK SoundSettingsDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARA WritePrivateProfileString("Sound", "Volume", tempstr, IniName); 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; } case IDCANCEL: diff --git a/desmume/src/windows/resource.h b/desmume/src/windows/resource.h index ffd6c0695..2bff61e94 100644 --- a/desmume/src/windows/resource.h +++ b/desmume/src/windows/resource.h @@ -239,6 +239,7 @@ #define IDC_EDIT11 1004 #define IDC_GI_GAMECODE 1004 #define IDC_ROTATE90 1004 +#define IDC_SPU_INTERPOLATION_CB 1004 #define IDC_ARM7BIOS 1005 #define IDC_EDIT07 1005 #define IDC_ROTATE180 1005 diff --git a/desmume/src/windows/resources.rc b/desmume/src/windows/resources.rc index 64687d4f9..095cb6c27 100644 --- a/desmume/src/windows/resources.rc +++ b/desmume/src/windows/resources.rc @@ -3377,7 +3377,7 @@ FONT 8, "MS Sans Serif", 0, 0, 1 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 CAPTION "Sound Settings" 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 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 - GROUPBOX "Other Settings", -1, 3, 31, 168, 43 - LTEXT "Buffer Size", -1, 10, 42, 60, 10, SS_LEFT - EDITTEXT IDC_SOUNDBUFFERET, 136, 41, 28, 13 - LTEXT "Volume", -1, 10, 57, 30, 10, SS_LEFT - CONTROL "", IDC_SLVOLUME, TRACKBAR_CLASS, 0, 40, 57, 128, 10 - DEFPUSHBUTTON "&OK", IDOK, 82, 78, 40, 14, BS_DEFPUSHBUTTON - PUSHBUTTON "&Cancel", IDCANCEL, 127, 78, 40, 14, BS_PUSHBUTTON + GROUPBOX "Other Settings", -1, 3, 31, 168, 61 + LTEXT "Buffer Size", -1, 10, 62, 60, 10, SS_LEFT + EDITTEXT IDC_SOUNDBUFFERET, 55, 61, 42, 13 + LTEXT "Volume", -1, 10, 77, 30, 10, SS_LEFT + CONTROL "", IDC_SLVOLUME, TRACKBAR_CLASS, 0, 40, 77, 128, 10 + DEFPUSHBUTTON "&OK", IDOK, 82, 97, 40, 14, BS_DEFPUSHBUTTON + 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 }