From: <man...@us...> - 2013-03-25 15:03:48
|
Revision: 1668 http://sourceforge.net/p/modplug/code/1668 Author: manxorist Date: 2013-03-25 15:03:37 +0000 (Mon, 25 Mar 2013) Log Message: ----------- [Ref] Start splitting DSP and EQ stuff from soundlib. Move soundlib/snd_dsp.cpp and soundlib/snd_eq.cpp to their own directory sounddsp/. Modified Paths: -------------- trunk/OpenMPT/mptrack/mptrack_08.vcproj trunk/OpenMPT/mptrack/mptrack_10.vcxproj trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters Added Paths: ----------- trunk/OpenMPT/sounddsp/ trunk/OpenMPT/sounddsp/DSP.cpp trunk/OpenMPT/sounddsp/EQ.cpp Removed Paths: ------------- trunk/OpenMPT/soundlib/Snd_dsp.cpp trunk/OpenMPT/soundlib/Snd_eq.cpp Modified: trunk/OpenMPT/mptrack/mptrack_08.vcproj =================================================================== --- trunk/OpenMPT/mptrack/mptrack_08.vcproj 2013-03-25 14:43:07 UTC (rev 1667) +++ trunk/OpenMPT/mptrack/mptrack_08.vcproj 2013-03-25 15:03:37 UTC (rev 1668) @@ -493,11 +493,11 @@ > </File> <File - RelativePath="..\soundlib\snd_dsp.cpp" + RelativePath="..\sounddsp\DSP.cpp" > </File> <File - RelativePath="..\soundlib\snd_eq.cpp" + RelativePath="..\sounddsp\EQ.cpp" > </File> <File Modified: trunk/OpenMPT/mptrack/mptrack_10.vcxproj =================================================================== --- trunk/OpenMPT/mptrack/mptrack_10.vcxproj 2013-03-25 14:43:07 UTC (rev 1667) +++ trunk/OpenMPT/mptrack/mptrack_10.vcxproj 2013-03-25 15:03:37 UTC (rev 1668) @@ -247,6 +247,8 @@ <ClCompile Include="..\common\AudioCriticalSection.cpp" /> <ClCompile Include="..\common\misc_util.cpp" /> <ClCompile Include="..\common\Reporting.cpp" /> + <ClCompile Include="..\sounddsp\DSP.cpp" /> + <ClCompile Include="..\sounddsp\EQ.cpp" /> <ClCompile Include="..\soundlib\ITCompression.cpp" /> <ClCompile Include="..\soundlib\ITTools.cpp" /> <ClCompile Include="..\soundlib\MIDIEvents.cpp" /> @@ -326,8 +328,6 @@ <ClCompile Include="ScaleEnvPointsDlg.cpp" /> <ClCompile Include="SelectPluginDialog.cpp" /> <ClCompile Include="..\common\serialization_utils.cpp" /> - <ClCompile Include="..\soundlib\snd_dsp.cpp" /> - <ClCompile Include="..\soundlib\snd_eq.cpp" /> <ClCompile Include="..\soundlib\snd_flt.cpp" /> <ClCompile Include="..\soundlib\Snd_fx.cpp" /> <ClCompile Include="..\Soundlib\Snd_rvb.cpp" /> Modified: trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters =================================================================== --- trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters 2013-03-25 14:43:07 UTC (rev 1667) +++ trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters 2013-03-25 15:03:37 UTC (rev 1668) @@ -259,12 +259,6 @@ <ClCompile Include="..\soundlib\snd_flt.cpp"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="..\soundlib\snd_eq.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="..\soundlib\snd_dsp.cpp"> - <Filter>Source Files</Filter> - </ClCompile> <ClCompile Include="..\common\serialization_utils.cpp"> <Filter>Source Files</Filter> </ClCompile> @@ -427,6 +421,12 @@ <ClCompile Include="..\soundlib\ITCompression.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="..\sounddsp\DSP.cpp"> + <Filter>Source Files\sounddsp</Filter> + </ClCompile> + <ClCompile Include="..\sounddsp\EQ.cpp"> + <Filter>Source Files\sounddsp</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="AbstractVstEditor.h"> @@ -871,6 +871,12 @@ <UniqueIdentifier>{5a7bae01-9526-4d85-9c00-0a280e22ad0b}</UniqueIdentifier> <Extensions>ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe</Extensions> </Filter> + <Filter Include="Source Files\sounddsp"> + <UniqueIdentifier>{ad75f592-baa3-4f6a-b4fe-496e1fad42e1}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files\sounddsp"> + <UniqueIdentifier>{2174b62f-1cac-4ad9-9db3-e3447eaa1bd0}</UniqueIdentifier> + </Filter> </ItemGroup> <ItemGroup> <ResourceCompile Include="mptrack.rc"> Index: trunk/OpenMPT/sounddsp =================================================================== --- trunk/OpenMPT/sounddsp 2013-03-25 14:43:07 UTC (rev 1667) +++ trunk/OpenMPT/sounddsp 2013-03-25 15:03:37 UTC (rev 1668) Property changes on: trunk/OpenMPT/sounddsp ___________________________________________________________________ Added: tsvn:logminsize ## -0,0 +1 ## +10 \ No newline at end of property Copied: trunk/OpenMPT/sounddsp/DSP.cpp (from rev 1664, trunk/OpenMPT/soundlib/Snd_dsp.cpp) =================================================================== --- trunk/OpenMPT/sounddsp/DSP.cpp (rev 0) +++ trunk/OpenMPT/sounddsp/DSP.cpp 2013-03-25 15:03:37 UTC (rev 1668) @@ -0,0 +1,521 @@ +/* + * DSP.cpp + * ----------- + * Purpose: Mixing code for various DSPs (EQ, Mega-Bass, ...) + * Notes : Ugh... This should really be removed at some point. + * Authors: Olivier Lapicque + * OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + + +#include "stdafx.h" +#include "../soundlib/sndfile.h" +#include <math.h> + + +// Bass Expansion +#define DEFAULT_XBASS_RANGE 14 // (x+2)*20 Hz (320Hz) +#define DEFAULT_XBASS_DEPTH 6 // 1+(3>>(x-4)) (+6dB) + +// Buffer Sizes +#define XBASSBUFFERSIZE 64 // 2 ms at 50KHz +#define SURROUNDBUFFERSIZE 2048 // 50ms @ 48kHz + + +// DSP Effects: PUBLIC members +UINT CSoundFile::m_nXBassDepth = DEFAULT_XBASS_DEPTH; +UINT CSoundFile::m_nXBassRange = DEFAULT_XBASS_RANGE; +UINT CSoundFile::gnReverbType = 0; +UINT CSoundFile::m_nReverbDepth = 8; // 50% +UINT CSoundFile::m_nProLogicDepth = 12; +UINT CSoundFile::m_nProLogicDelay = 20; + +//////////////////////////////////////////////////////////////////// +// DSP Effects internal state + +// Noise Reduction: simple low-pass filter +static LONG nLeftNR = 0; +static LONG nRightNR = 0; + +// Surround Encoding: 1 delay line + low-pass filter + high-pass filter +static LONG nSurroundSize = 0; +static LONG nSurroundPos = 0; +static LONG nDolbyDepth = 0; +// Surround Biquads +static LONG nDolbyHP_Y1 = 0; +static LONG nDolbyHP_X1 = 0; +static LONG nDolbyLP_Y1 = 0; +static LONG nDolbyHP_B0 = 0; +static LONG nDolbyHP_B1 = 0; +static LONG nDolbyHP_A1 = 0; +static LONG nDolbyLP_B0 = 0; +static LONG nDolbyLP_B1 = 0; +static LONG nDolbyLP_A1 = 0; + +// Bass Expansion: low-pass filter +static LONG nXBassFlt_Y1 = 0; +static LONG nXBassFlt_X1 = 0; +static LONG nXBassFlt_B0 = 0; +static LONG nXBassFlt_B1 = 0; +static LONG nXBassFlt_A1 = 0; + +// DC Removal Biquad +static LONG nDCRFlt_Y1l = 0; +static LONG nDCRFlt_X1l = 0; +static LONG nDCRFlt_Y1r = 0; +static LONG nDCRFlt_X1r = 0; + + +static LONG SurroundBuffer[SURROUNDBUFFERSIZE]; + + +// Access the main temporary mix buffer directly: avoids an extra pointer +extern int MixSoundBuffer[MIXBUFFERSIZE * 4]; +extern int MixRearBuffer[MIXBUFFERSIZE * 2]; + +extern VOID InitializeReverb(BOOL bReset); +extern VOID ProcessReverb(UINT nSamples); +extern VOID MPPASMCALL X86_InitMixBuffer(int *pBuffer, UINT nSamples); +extern VOID MPPASMCALL X86_StereoFill(int *pBuffer, UINT nSamples, LPLONG lpROfs, LPLONG lpLOfs); +extern VOID MPPASMCALL X86_StereoDCRemoval(int *, UINT count); +extern VOID MPPASMCALL X86_MonoDCRemoval(int *, UINT count); + +/////////////////////////////////////////////////////////////////////////////////// +// +// Biquad setup +// + + +#define PI 3.14159265358979323f +inline FLOAT Sgn(FLOAT x) { return (x >= 0) ? 1.0f : -1.0f; } +VOID ShelfEQ(LONG scale, + LONG *outA1, LONG *outB0, LONG *outB1, + LONG F_c, LONG F_s, FLOAT gainDC, FLOAT gainFT, FLOAT gainPI) +{ + FLOAT a1, b0, b1; + FLOAT gainFT2, gainDC2, gainPI2; + FLOAT alpha, beta0, beta1, rho; + FLOAT wT, quad; + + _asm { + // wT = PI*Fc/Fs + fild F_c + fldpi + fmulp ST(1), ST(0) + fild F_s + fdivp ST(1), ST(0) + fstp wT + // gain^2 + fld gainDC + fld gainFT + fld gainPI + fmul ST(0), ST(0) + fstp gainPI2 + fmul ST(0), ST(0) + fstp gainFT2 + fmul ST(0), ST(0) + fstp gainDC2 + } + + quad = gainPI2 + gainDC2 - (gainFT2*2); + + alpha = 0; + + if (quad != 0) + { + FLOAT lambda = (gainPI2 - gainDC2) / quad; + alpha = (FLOAT)(lambda - Sgn(lambda)*sqrt(lambda*lambda - 1.0f)); + } + + beta0 = 0.5f * ((gainDC + gainPI) + (gainDC - gainPI) * alpha); + beta1 = 0.5f * ((gainDC - gainPI) + (gainDC + gainPI) * alpha); + rho = (FLOAT)((sin((wT*0.5f) - (PI/4.0f))) / (sin((wT*0.5f) + (PI/4.0f)))); + + quad = 1.0f / (1.0f + rho*alpha); + + b0 = ((beta0 + rho*beta1) * quad); + b1 = ((beta1 + rho*beta0) * quad); + a1 = - ((rho + alpha) * quad); + + _asm { + fild scale + fld a1 + mov eax, outA1 + fmul ST(0), ST(1) + fistp dword ptr [eax] + fld b0 + mov eax, outB0 + fmul ST(0), ST(1) + fistp dword ptr [eax] + fld b1 + mov eax, outB1 + fmul ST(0), ST(1) + fistp dword ptr [eax] + fstp rho + } +} + + +void CSoundFile::InitializeDSP(BOOL bReset) +//----------------------------------------- +{ + if (gnReverbType >= NUM_REVERBTYPES) gnReverbType = 0; + if (!m_nProLogicDelay) m_nProLogicDelay = 20; + if (bReset) + { + // Noise Reduction + nLeftNR = nRightNR = 0; + } + // Pro-Logic Surround + nSurroundPos = nSurroundSize = 0; + if (gdwSoundSetup & SNDMIX_SURROUND) + { + memset(SurroundBuffer, 0, sizeof(SurroundBuffer)); + nSurroundSize = (gdwMixingFreq * m_nProLogicDelay) / 1000; + if (nSurroundSize > SURROUNDBUFFERSIZE) nSurroundSize = SURROUNDBUFFERSIZE; + nDolbyDepth = m_nProLogicDepth; + if (nDolbyDepth < 1) nDolbyDepth = 1; + if (nDolbyDepth > 16) nDolbyDepth = 16; + // Setup biquad filters + ShelfEQ(1024, &nDolbyHP_A1, &nDolbyHP_B0, &nDolbyHP_B1, 200, gdwMixingFreq, 0, 0.5f, 1); + ShelfEQ(1024, &nDolbyLP_A1, &nDolbyLP_B0, &nDolbyLP_B1, 7000, gdwMixingFreq, 1, 0.75f, 0); + nDolbyHP_X1 = nDolbyHP_Y1 = 0; + nDolbyLP_Y1 = 0; + // Surround Level + nDolbyHP_B0 = (nDolbyHP_B0 * nDolbyDepth) >> 5; + nDolbyHP_B1 = (nDolbyHP_B1 * nDolbyDepth) >> 5; + // +6dB + nDolbyLP_B0 *= 2; + nDolbyLP_B1 *= 2; + } + // Reverb Setup +#ifndef NO_REVERB + InitializeReverb(bReset); +#endif + // Bass Expansion Reset + if (gdwSoundSetup & SNDMIX_MEGABASS) + { + LONG a1 = 0, b0 = 1024, b1 = 0; + int nXBassCutOff = 50 + (m_nXBassRange+2) * 20; + int nXBassGain = m_nXBassDepth; + Limit(nXBassGain, 2, 8); + Limit(nXBassCutOff, 60, 600); + ShelfEQ(1024, &a1, &b0, &b1, nXBassCutOff, gdwMixingFreq, + 1.0f + (1.0f/16.0f) * (0x300 >> nXBassGain), + 1.0f, + 0.0000001f); + if (nXBassGain > 5) + { + b0 >>= (nXBassGain-5); + b1 >>= (nXBassGain-5); + } + nXBassFlt_A1 = a1; + nXBassFlt_B0 = b0; + nXBassFlt_B1 = b1; + //Log("b0=%d b1=%d a1=%d\n", b0, b1, a1); + } + if (bReset) + { + nXBassFlt_X1 = 0; + nXBassFlt_Y1 = 0; + nDCRFlt_X1l = 0; + nDCRFlt_X1r = 0; + nDCRFlt_Y1l = 0; + nDCRFlt_Y1r = 0; + } +} + + +// 2-channel surround +static void ProcessStereoSurround(int count) +//------------------------------------------ +{ + int *pr = MixSoundBuffer, hy1 = nDolbyHP_Y1; + for (int r=count; r; r--) + { + // Delay + int secho = SurroundBuffer[nSurroundPos]; + SurroundBuffer[nSurroundPos] = (pr[0]+pr[1]+256) >> 9; + // High-pass + int v0 = (nDolbyHP_B0 * secho + nDolbyHP_B1 * nDolbyHP_X1 + nDolbyHP_A1 * hy1) >> 10; + nDolbyHP_X1 = secho; + // Low-pass + int v = (nDolbyLP_B0 * v0 + nDolbyLP_B1 * hy1 + nDolbyLP_A1 * nDolbyLP_Y1) >> (10-8); + hy1 = v0; + nDolbyLP_Y1 = v >> 8; + // Add echo + pr[0] += v; + pr[1] -= v; + if (++nSurroundPos >= nSurroundSize) nSurroundPos = 0; + pr += 2; + } + nDolbyHP_Y1 = hy1; +} + + +// 4-channels surround +static void ProcessQuadSurround(int count) +//---------------------------------------- +{ + int *pr = MixSoundBuffer, hy1 = nDolbyHP_Y1; + for (int r=count; r; r--) + { + int vl = pr[0] >> 1; + int vr = pr[1] >> 1; + pr[(UINT)(MixRearBuffer-MixSoundBuffer)] += vl; + pr[((UINT)(MixRearBuffer-MixSoundBuffer))+1] += vr; + // Delay + int secho = SurroundBuffer[nSurroundPos]; + SurroundBuffer[nSurroundPos] = (vr+vl+256) >> 9; + // High-pass + int v0 = (nDolbyHP_B0 * secho + nDolbyHP_B1 * nDolbyHP_X1 + nDolbyHP_A1 * hy1) >> 10; + nDolbyHP_X1 = secho; + // Low-pass + int v = (nDolbyLP_B0 * v0 + nDolbyLP_B1 * hy1 + nDolbyLP_A1 * nDolbyLP_Y1) >> (10-8); + hy1 = v0; + nDolbyLP_Y1 = v >> 8; + // Add echo + pr[(UINT)(MixRearBuffer-MixSoundBuffer)] += v; + pr[((UINT)(MixRearBuffer-MixSoundBuffer))+1] += v; + if (++nSurroundPos >= nSurroundSize) nSurroundPos = 0; + pr += 2; + } + nDolbyHP_Y1 = hy1; +} + + +void CSoundFile::ProcessStereoDSP(int count) +//------------------------------------------ +{ + // Dolby Pro-Logic Surround + if (gdwSoundSetup & SNDMIX_SURROUND) + { + if (gnChannels > 2) ProcessQuadSurround(count); else + ProcessStereoSurround(count); + } + // DC Removal + if (gdwSoundSetup & SNDMIX_MEGABASS) + { + X86_StereoDCRemoval(MixSoundBuffer, count); + } + // Bass Expansion + if (gdwSoundSetup & SNDMIX_MEGABASS) + { + int *px = MixSoundBuffer; + int x1 = nXBassFlt_X1; + int y1 = nXBassFlt_Y1; + for (int x=count; x; x--) + { + int x_m = (px[0]+px[1]+0x100)>>9; + + y1 = (nXBassFlt_B0 * x_m + nXBassFlt_B1 * x1 + nXBassFlt_A1 * y1) >> (10-8); + x1 = x_m; + px[0] += y1; + px[1] += y1; + y1 = (y1+0x80) >> 8; + px += 2; + } + nXBassFlt_X1 = x1; + nXBassFlt_Y1 = y1; + } + // Noise Reduction + if (gdwSoundSetup & SNDMIX_NOISEREDUCTION) + { + int n1 = nLeftNR, n2 = nRightNR; + int *pnr = MixSoundBuffer; + for (int nr=count; nr; nr--) + { + int vnr = pnr[0] >> 1; + pnr[0] = vnr + n1; + n1 = vnr; + vnr = pnr[1] >> 1; + pnr[1] = vnr + n2; + n2 = vnr; + pnr += 2; + } + nLeftNR = n1; + nRightNR = n2; + } +} + + +void CSoundFile::ProcessMonoDSP(int count) +//---------------------------------------- +{ + // DC Removal + if (gdwSoundSetup & SNDMIX_MEGABASS) + { + X86_MonoDCRemoval(MixSoundBuffer, count); + } + // Bass Expansion + if (gdwSoundSetup & SNDMIX_MEGABASS) + { + int *px = MixSoundBuffer; + int x1 = nXBassFlt_X1; + int y1 = nXBassFlt_Y1; + for (int x=count; x; x--) + { + int x_m = (px[0]+0x80)>>8; + + y1 = (nXBassFlt_B0 * x_m + nXBassFlt_B1 * x1 + nXBassFlt_A1 * y1) >> (10-8); + x1 = x_m; + px[0] += y1; + y1 = (y1+0x40) >> 8; + px++; + } + nXBassFlt_X1 = x1; + nXBassFlt_Y1 = y1; + } + // Noise Reduction + if (gdwSoundSetup & SNDMIX_NOISEREDUCTION) + { + int n = nLeftNR; + int *pnr = MixSoundBuffer; + for (int nr=count; nr; pnr++, nr--) + { + int vnr = *pnr >> 1; + *pnr = vnr + n; + n = vnr; + } + nLeftNR = n; + } +} + + + +////////////////////////////////////////////////////////////////////////// +// +// DC Removal +// + +#define DCR_AMOUNT 9 + +VOID MPPASMCALL X86_StereoDCRemoval(int *pBuffer, UINT nSamples) +{ + int y1l=nDCRFlt_Y1l, x1l=nDCRFlt_X1l; + int y1r=nDCRFlt_Y1r, x1r=nDCRFlt_X1r; + + _asm { + mov esi, pBuffer + mov ecx, nSamples +stereodcr: + mov eax, [esi] + mov ebx, x1l + mov edx, [esi+4] + mov edi, x1r + add esi, 8 + sub ebx, eax + mov x1l, eax + mov eax, ebx + sar eax, DCR_AMOUNT+1 + sub edi, edx + sub eax, ebx + mov x1r, edx + add eax, y1l + mov edx, edi + sar edx, DCR_AMOUNT+1 + mov [esi-8], eax + sub edx, edi + mov ebx, eax + add edx, y1r + sar ebx, DCR_AMOUNT + mov [esi-4], edx + mov edi, edx + sub eax, ebx + sar edi, DCR_AMOUNT + mov y1l, eax + sub edx, edi + dec ecx + mov y1r, edx + jnz stereodcr + } + nDCRFlt_Y1l = y1l; + nDCRFlt_X1l = x1l; + nDCRFlt_Y1r = y1r; + nDCRFlt_X1r = x1r; +} + + +VOID MPPASMCALL X86_MonoDCRemoval(int *pBuffer, UINT nSamples) +{ + _asm { + mov esi, pBuffer + mov ecx, nSamples + mov edx, nDCRFlt_X1l + mov edi, nDCRFlt_Y1l +stereodcr: + mov eax, [esi] + mov ebx, edx + add esi, 4 + sub ebx, eax + mov edx, eax + mov eax, ebx + sar eax, DCR_AMOUNT+1 + sub eax, ebx + add eax, edi + mov [esi-4], eax + mov ebx, eax + sar ebx, DCR_AMOUNT + sub eax, ebx + dec ecx + mov edi, eax + jnz stereodcr + mov nDCRFlt_X1l, edx + mov nDCRFlt_Y1l, edi + } +} + + + + + +///////////////////////////////////////////////////////////////// +// Clean DSP Effects interface + +// [Reverb level 0(quiet)-100(loud)], [type = REVERBTYPE_XXXX] +BOOL CSoundFile::SetReverbParameters(UINT nDepth, UINT nType) +//----------------------------------------------------------- +{ + if (nDepth > 100) nDepth = 100; + UINT gain = (nDepth * 16) / 100; + if (gain > 16) gain = 16; + if (gain < 1) gain = 1; + m_nReverbDepth = gain; + if (nType < NUM_REVERBTYPES) gnReverbType = nType; + return TRUE; +} + + +// [XBass level 0(quiet)-100(loud)], [cutoff in Hz 20-100] +BOOL CSoundFile::SetXBassParameters(UINT nDepth, UINT nRange) +//----------------------------------------------------------- +{ + if (nDepth > 100) nDepth = 100; + UINT gain = nDepth / 20; + if (gain > 4) gain = 4; + m_nXBassDepth = 8 - gain; // filter attenuation 1/256 .. 1/16 + UINT range = nRange / 5; + if (range > 5) range -= 5; else range = 0; + if (nRange > 16) nRange = 16; + m_nXBassRange = 21 - range; // filter average on 0.5-1.6ms + return TRUE; +} + + +// [Surround level 0(quiet)-100(heavy)] [delay in ms, usually 5-50ms] +BOOL CSoundFile::SetSurroundParameters(UINT nDepth, UINT nDelay) +//-------------------------------------------------------------- +{ + UINT gain = (nDepth * 16) / 100; + if (gain > 16) gain = 16; + if (gain < 1) gain = 1; + m_nProLogicDepth = gain; + if (nDelay < 4) nDelay = 4; + if (nDelay > 50) nDelay = 50; + m_nProLogicDelay = nDelay; + return TRUE; +} + + + Copied: trunk/OpenMPT/sounddsp/EQ.cpp (from rev 1664, trunk/OpenMPT/soundlib/Snd_eq.cpp) =================================================================== --- trunk/OpenMPT/sounddsp/EQ.cpp (rev 0) +++ trunk/OpenMPT/sounddsp/EQ.cpp 2013-03-25 15:03:37 UTC (rev 1668) @@ -0,0 +1,532 @@ +/* + * EQ.cpp + * ---------- + * Purpose: Mixing code for equalizer. + * Notes : Ugh... This should really be removed at some point. + * Authors: Olivier Lapicque + * OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + + +#include "stdafx.h" +#include "../soundlib/sndfile.h" +#include "../mptrack/TrackerSettings.h" + +#define EQ_BANDWIDTH 2.0 +#define EQ_ZERO 0.000001 +#define REAL float + +extern REAL MixFloatBuffer[]; + +extern void X86_StereoMixToFloat(const int *pSrc, float *pOut1, float *pOut2, UINT nCount, const float _i2fc); +extern void X86_FloatToStereoMix(const float *pIn1, const float *pIn2, int *pOut, UINT nCount, const float _f2ic); +extern void X86_MonoMixToFloat(const int *pSrc, float *pOut, UINT nCount, const float _i2fc); +extern void X86_FloatToMonoMix(const float *pIn, int *pOut, UINT nCount, const float _f2ic); + +#ifdef ENABLE_SSE +extern void SSE_MonoMixToFloat(const int *pSrc, float *pOut, UINT nCount, const float _i2fc); +#endif +#ifdef ENABLE_3DNOW +extern void AMD_MonoMixToFloat(const int *pSrc, float *pOut, UINT nCount, const float _i2fc); +extern void AMD_FloatToMonoMix(const float *pIn, int *pOut, UINT nCount, const float _f2ic); +#endif + + + + +#pragma pack(push, 4) +typedef struct _EQBANDSTRUCT +{ + REAL a0, a1, a2, b1, b2; + REAL x1, x2, y1, y2; + REAL Gain, CenterFrequency; + BOOL bEnable; +} EQBANDSTRUCT, *PEQBANDSTRUCT; +#pragma pack(pop) + +UINT gEqLinearToDB[33] = +{ + 16, 19, 22, 25, 28, 31, 34, 37, + 40, 43, 46, 49, 52, 55, 58, 61, + 64, 76, 88, 100, 112, 124, 136, 148, + 160, 172, 184, 196, 208, 220, 232, 244, 256 +}; + + +static REAL f2ic = (REAL)(1 << 28); +static REAL i2fc = (REAL)(1.0 / (1 << 28)); + +static EQBANDSTRUCT gEQ[MAX_EQ_BANDS*2] = +{ + // Default: Flat EQ + {0,0,0,0,0, 0,0,0,0, 1, 120, FALSE}, + {0,0,0,0,0, 0,0,0,0, 1, 600, FALSE}, + {0,0,0,0,0, 0,0,0,0, 1, 1200, FALSE}, + {0,0,0,0,0, 0,0,0,0, 1, 3000, FALSE}, + {0,0,0,0,0, 0,0,0,0, 1, 6000, FALSE}, + {0,0,0,0,0, 0,0,0,0, 1, 10000, FALSE}, + {0,0,0,0,0, 0,0,0,0, 1, 120, FALSE}, + {0,0,0,0,0, 0,0,0,0, 1, 600, FALSE}, + {0,0,0,0,0, 0,0,0,0, 1, 1200, FALSE}, + {0,0,0,0,0, 0,0,0,0, 1, 3000, FALSE}, + {0,0,0,0,0, 0,0,0,0, 1, 6000, FALSE}, + {0,0,0,0,0, 0,0,0,0, 1, 10000, FALSE}, +}; + +#define ASM_EQ +#ifdef ASM_EQ + +#pragma warning(disable:4100) + +#define PBS_A0 DWORD PTR [eax] +#define PBS_A1 DWORD PTR [eax+4] +#define PBS_A2 DWORD PTR [eax+8] +#define PBS_B1 DWORD PTR [eax+12] +#define PBS_B2 DWORD PTR [eax+16] +#define PBS_X1 DWORD PTR [eax+20] +#define PBS_X2 DWORD PTR [eax+24] +#define PBS_Y1 DWORD PTR [eax+28] +#define PBS_Y2 DWORD PTR [eax+32] + +void __cdecl EQFilter(EQBANDSTRUCT *pbs, REAL *pbuffer, UINT nCount) +//------------------------------------------------------------------ +{ + _asm { + mov eax, pbs // eax = pbs + mov edx, nCount // edx = nCount + mov ecx, pbuffer // ecx = pbuffer + fld PBS_Y2 // ST(3)=y2 + fld PBS_Y1 // ST(2)=y1 + fld PBS_X2 // ST(1)=x2 + fld PBS_X1 // ST(0)=x1 +EQ_Loop: + fld DWORD PTR [ecx] // ST(0):x ST(1):x1 ST(2):x2 ST(3):y1 ST(4):y2 + fld PBS_A0 // ST(0):a0 ST(1):x ST(2):x1 ST(3):x2 ST(4):y1 ST(5):y2 + fmul ST(0), ST(1) // ST(0):a0*x + fld PBS_A1 // ST(0):a1 ST(1):a0*x ST(2):x ST(3):x1 ST(4):x2 ST(5):y1 ST(6):y2 + fmul ST(0), ST(3) // ST(0):a1*x1 + add ecx, 4 + + faddp ST(1), ST(0) + fld PBS_A2 + fmul ST(0), ST(4) + faddp ST(1), ST(0) + fld PBS_B1 + fmul ST(0), ST(5) + faddp ST(1), ST(0) + fld PBS_B2 + fmul ST(0), ST(6) + sub edx, 1 + faddp ST(1), ST(0) + fst DWORD PTR [ecx-4] // *pbuffer = a0*x+a1*x1+a2*x2+b1*y1+b2*y2 + // Here, ST(0)=y ST(1)=x ST(2)=x1 ST(3)=x2 ST(4)=y1 ST(5)=y2 + fxch ST(4) // y1=y + fstp ST(5) // y2=y1 + // Here, ST(0)=x ST(1)=x1 ST(2)=x2 ST(3)=y1 ST(4)=y2 + fxch ST(1) // x1=x + fstp ST(2) // x2=x1 + jnz EQ_Loop + // Store x1,y1,x2,y2 and pop FPU stack + fstp PBS_X1 + fstp PBS_X2 + fstp PBS_Y1 + fstp PBS_Y2 + } +} + + +void AMD_StereoEQ(EQBANDSTRUCT *pbl, EQBANDSTRUCT *pbr, REAL *pbuffer, UINT nCount) +//--------------------------------------------------------------------------------- +{ +#ifdef ENABLE_3DNOW + float tmp[16]; + + _asm { + mov eax, pbl + mov edx, pbr + mov ebx, pbuffer + mov ecx, nCount + lea edi, [tmp+8] + and edi, 0xfffffff8 + movd mm7, [eax+EQBANDSTRUCT.a0] + movd mm0, [edx+EQBANDSTRUCT.a0] + movd mm6, [eax+EQBANDSTRUCT.a1] + movd mm1, [edx+EQBANDSTRUCT.a1] + punpckldq mm7, mm0 + punpckldq mm6, mm1 + movq [edi], mm7 // [edi] = a0 + movq [edi+8], mm6 // [edi+8] = a1 + movd mm5, [eax+EQBANDSTRUCT.a2] + movd mm0, [edx+EQBANDSTRUCT.a2] + movd mm4, [eax+EQBANDSTRUCT.b1] + movd mm1, [edx+EQBANDSTRUCT.b1] + movd mm3, [eax+EQBANDSTRUCT.b2] + movd mm2, [edx+EQBANDSTRUCT.b2] + punpckldq mm5, mm0 + punpckldq mm4, mm1 + punpckldq mm3, mm2 + movq [edi+16], mm5 // [edi+16] = a2 + movq [edi+24], mm4 // [edi+24] = b1 + movq [edi+32], mm3 // [edi+32] = b2 + movd mm4, [eax+EQBANDSTRUCT.x1] + movd mm0, [edx+EQBANDSTRUCT.x1] + movd mm5, [eax+EQBANDSTRUCT.x2] + movd mm1, [edx+EQBANDSTRUCT.x2] + punpckldq mm4, mm0 // mm4 = x1 + punpckldq mm5, mm1 // mm5 = x2 + movd mm6, [eax+EQBANDSTRUCT.y1] + movd mm2, [edx+EQBANDSTRUCT.y1] + movd mm7, [eax+EQBANDSTRUCT.y2] + movd mm3, [edx+EQBANDSTRUCT.y2] + punpckldq mm6, mm2 // mm6 = y1 + punpckldq mm7, mm3 // mm7 = y2 +mainloop: + movq mm0, [ebx] + movq mm3, [edi+8] + add ebx, 8 + movq mm1, [edi+16] + pfmul mm3, mm4 // x1 * a1 + movq mm2, [edi+32] + pfmul mm1, mm5 // x2 * a2 + movq mm5, mm4 // x2 = x1 + pfmul mm2, mm7 // y2 * b2 + movq mm7, mm6 // y2 = y1 + pfmul mm6, [edi+24] // y1 * b1 + movq mm4, mm0 // x1 = x + pfmul mm0, [edi] // x * a0 + pfadd mm6, mm1 // x2*a2 + y1*b1 + pfadd mm6, mm2 // x2*a2 + y1*b1 + y2*b2 + pfadd mm6, mm3 // x1*a1 + x2*a2 + y1*b1 + y2*b2 + pfadd mm6, mm0 // x*a0 + x1*a1 + x2*a2 + y1*b1 + y2*b2 + dec ecx + movq [ebx-8], mm6 + jnz mainloop + movd [eax+EQBANDSTRUCT.x1], mm4 + punpckhdq mm4, mm4 + movd [eax+EQBANDSTRUCT.x2], mm5 + punpckhdq mm5, mm5 + movd [eax+EQBANDSTRUCT.y1], mm6 + punpckhdq mm6, mm6 + movd [eax+EQBANDSTRUCT.y2], mm7 + punpckhdq mm7, mm7 + movd [edx+EQBANDSTRUCT.x1], mm4 + movd [edx+EQBANDSTRUCT.x2], mm5 + movd [edx+EQBANDSTRUCT.y1], mm6 + movd [edx+EQBANDSTRUCT.y2], mm7 + emms + } +#endif +} + + +void SSE_StereoEQ(EQBANDSTRUCT *pbl, EQBANDSTRUCT *pbr, REAL *pbuffer, UINT nCount) +//--------------------------------------------------------------------------------- +{ +#ifdef ENABLE_SSE + static const float gk1 = 1.0f; + _asm { + mov eax, pbl + mov edx, pbr + mov ebx, pbuffer + mov ecx, nCount + movss xmm0, [eax+EQBANDSTRUCT.Gain] + movss xmm1, gk1 + comiss xmm0, xmm1 + jne doeq + movss xmm0, [edx+EQBANDSTRUCT.Gain] + comiss xmm0, xmm1 + je done +doeq: + test ecx, ecx + jz done + movss xmm6, [eax+EQBANDSTRUCT.a1] + movss xmm7, [eax+EQBANDSTRUCT.a2] + movss xmm4, [eax+EQBANDSTRUCT.x1] + movss xmm5, [eax+EQBANDSTRUCT.x2] + movlhps xmm6, xmm7 // xmm6 = [ 0 | a2 | 0 | a1 ] + movlhps xmm4, xmm5 // xmm4 = [ 0 | x2 | 0 | x1 ] + movss xmm2, [edx+EQBANDSTRUCT.a1] + movss xmm3, [edx+EQBANDSTRUCT.a2] + movss xmm0, [edx+EQBANDSTRUCT.x1] + movss xmm1, [edx+EQBANDSTRUCT.x2] + movlhps xmm2, xmm3 // xmm2 = [ 0 | a'2 | 0 | a'1 ] + movlhps xmm0, xmm1 // xmm0 = [ 0 | x'2 | 0 | x'1 ] + shufps xmm6, xmm2, 0x88 // xmm6 = [ a'2 | a'1 | a2 | a1 ] + shufps xmm4, xmm0, 0x88 // xmm4 = [ x'2 | x'1 | x2 | x1 ] + shufps xmm6, xmm6, 0xD8 // xmm6 = [ a'2 | a2 | a'1 | a1 ] + shufps xmm4, xmm4, 0xD8 // xmm4 = [ x'2 | x2 | x'1 | x1 ] + movss xmm7, [eax+EQBANDSTRUCT.b1] + movss xmm0, [eax+EQBANDSTRUCT.b2] + movss xmm2, [edx+EQBANDSTRUCT.b1] + movss xmm1, [edx+EQBANDSTRUCT.b2] + movlhps xmm7, xmm0 // xmm7 = [ 0 | b2 | 0 | b1 ] + movlhps xmm2, xmm1 // xmm2 = [ 0 | b'2 | 0 | b'1 ] + shufps xmm7, xmm2, 0x88 // xmm7 = [ b'2 | b'1 | b2 | b1 ] + shufps xmm7, xmm7, 0xD8 // xmm7 = [ b'2 | b2 | b'1 | b1 ] + movss xmm5, [eax+EQBANDSTRUCT.y1] + movss xmm1, [eax+EQBANDSTRUCT.y2] + movss xmm3, [edx+EQBANDSTRUCT.y1] + movss xmm0, [edx+EQBANDSTRUCT.y2] + movlhps xmm5, xmm1 // xmm5 = [ 0 | y2 | 0 | y1 ] + movlhps xmm3, xmm0 // xmm3 = [ 0 | y'2 | 0 | y'1 ] + shufps xmm5, xmm3, 0x88 // xmm5 = [ y'2 | y'1 | y2 | y1 ] + shufps xmm5, xmm5, 0xD8 // xmm5 = [ y'2 | y2 | y'1 | y1 ] + movss xmm3, [eax+EQBANDSTRUCT.a0] + movss xmm2, [edx+EQBANDSTRUCT.a0] + shufps xmm3, xmm2, 0x88 + shufps xmm3, xmm3, 0xD8 // xmm3 = [ 0 | 0 | a'0 | a0 ] +mainloop: + movlps xmm0, qword ptr [ebx] + add ebx, 8 + movaps xmm1, xmm5 // xmm1 = [ y2r | y2l | y1r | y1l ] + mulps xmm1, xmm7 // xmm1 = [b2r*y2r|b2l*y2l|b1r*y1r|b1l*y1l] + movaps xmm2, xmm4 // xmm2 = [ x2r | x2l | x1r | x1l ] + mulps xmm2, xmm6 // xmm6 = [a2r*x2r|a2l*x2l|a1r*x1r|a1l*x1l] + shufps xmm4, xmm0, 0x44 // xmm4 = [ xr | xl | x1r | x1l ] + mulps xmm0, xmm3 // xmm0 = [ 0 | 0 |a0r*xr|a0l*xl] + shufps xmm4, xmm4, 0x4E // xmm4 = [ x1r | x1l | xr | xl ] + addps xmm1, xmm2 // xmm1 = [b2r*y2r+a2r*x2r|b2l*y2l+a2l*x2l|b1r*y1r+a1r*x1r|b1l*y1l+a1l*x1l] + addps xmm1, xmm0 // xmm1 = [b2r*y2r+a2r*x2r|b2l*y2l+a2l*x2l|b1r*y1r+a1r*x1r+a0r*xr|b1l*y1l+a1l*x1l+a0l*xl] + sub ecx, 1 + movhlps xmm0, xmm1 + addps xmm0, xmm1 // xmm0 = [ ? | ? | yr(n) | yl(n) ] + movlps [ebx-8], xmm0 + shufps xmm0, xmm5, 0x44 + movaps xmm5, xmm0 + jnz mainloop + movhlps xmm0, xmm4 + movhlps xmm1, xmm5 + movss [eax+EQBANDSTRUCT.x1], xmm4 + movss [eax+EQBANDSTRUCT.x2], xmm0 + movss [eax+EQBANDSTRUCT.y1], xmm5 + movss [eax+EQBANDSTRUCT.y2], xmm1 + shufps xmm4, xmm4, 0x01 + shufps xmm0, xmm0, 0x01 + shufps xmm5, xmm5, 0x01 + shufps xmm1, xmm1, 0x01 + movss [edx+EQBANDSTRUCT.x1], xmm4 + movss [edx+EQBANDSTRUCT.x2], xmm0 + movss [edx+EQBANDSTRUCT.y1], xmm5 + movss [edx+EQBANDSTRUCT.y2], xmm1 +done:; + } +#endif SSE_SPECIFIC +} + +#pragma warning(default:4100) + +#else + +void EQFilter(EQBANDSTRUCT *pbs, REAL *pbuffer, UINT nCount) +//---------------------------------------------------------- +{ + for (UINT i=0; i<nCount; i++) + { + REAL x = pbuffer[i]; + REAL y = pbs->a1 * pbs->x1 + pbs->a2 * pbs->x2 + pbs->a0 * x + pbs->b1 * pbs->y1 + pbs->b2 * pbs->y2; + pbs->x2 = pbs->x1; + pbs->y2 = pbs->y1; + pbs->x1 = x; + pbuffer[i] = y; + pbs->y1 = y; + } +} + +#endif + + +void CSoundFile::EQMono(int *pbuffer, UINT nCount) +//------------------------------------------------ +{ + MonoMixToFloat(pbuffer, MixFloatBuffer, nCount); + for (UINT b=0; b<MAX_EQ_BANDS; b++) + { + if ((gEQ[b].bEnable) && (gEQ[b].Gain != 1.0f)) EQFilter(&gEQ[b], MixFloatBuffer, nCount); + } + FloatToMonoMix(MixFloatBuffer, pbuffer, nCount); +} + + +void CSoundFile::EQStereo(int *pbuffer, UINT nCount) +//-------------------------------------------------- +{ + +#ifdef ENABLE_SSE +#ifdef ENABLE_MMX + + // Still allow the check, because the user can turn this on/off + + if ((gdwSysInfo & SYSMIX_SSE) && (gdwSoundSetup & SNDMIX_ENABLEMMX)) + { + int sse_state, sse_eqstate; + SSE_MonoMixToFloat(pbuffer, MixFloatBuffer, nCount*2, m_pConfig->getIntToFloat()); + + _asm stmxcsr sse_state; + sse_eqstate = sse_state | 0xFF80; + _asm ldmxcsr sse_eqstate; + for (UINT b=0; b<MAX_EQ_BANDS; b++) + { + if ((gEQ[b].bEnable) || (gEQ[b+MAX_EQ_BANDS].bEnable)) + SSE_StereoEQ(&gEQ[b], &gEQ[b+MAX_EQ_BANDS], MixFloatBuffer, nCount); + } + _asm ldmxcsr sse_state; + + X86_FloatToMonoMix(MixFloatBuffer, pbuffer, nCount*2, m_pConfig->getFloatToInt()); + + } else + +#endif // ENABLE_MMX +#endif // ENABLE_SSE + +#ifdef ENABLE_3DNOW + + // We still perform the MMX check because the user can enable/disable this + + if ((gdwSysInfo & SYSMIX_3DNOW) && (gdwSoundSetup & SNDMIX_ENABLEMMX)) + { + AMD_MonoMixToFloat(pbuffer, MixFloatBuffer, nCount*2, m_pConfig->getIntToFloat()); + + for (UINT b=0; b<MAX_EQ_BANDS; b++) + { + if (((gEQ[b].bEnable) && (gEQ[b].Gain != 1.0f)) + || ((gEQ[b+MAX_EQ_BANDS].bEnable) && (gEQ[b+MAX_EQ_BANDS].Gain != 1.0f))) + AMD_StereoEQ(&gEQ[b], &gEQ[b+MAX_EQ_BANDS], MixFloatBuffer, nCount); + } + + AMD_FloatToMonoMix(MixFloatBuffer, pbuffer, nCount*2, m_pConfig->getFloatToInt()); + + } else +#endif // ENABLE_3DNOW + + { + X86_StereoMixToFloat(pbuffer, MixFloatBuffer, MixFloatBuffer+MIXBUFFERSIZE, nCount, m_pConfig->getIntToFloat()); + + for (UINT bl=0; bl<MAX_EQ_BANDS; bl++) + { + if ((gEQ[bl].bEnable) && (gEQ[bl].Gain != 1.0f)) EQFilter(&gEQ[bl], MixFloatBuffer, nCount); + } + for (UINT br=MAX_EQ_BANDS; br<MAX_EQ_BANDS*2; br++) + { + if ((gEQ[br].bEnable) && (gEQ[br].Gain != 1.0f)) EQFilter(&gEQ[br], MixFloatBuffer+MIXBUFFERSIZE, nCount); + } + + X86_FloatToStereoMix(MixFloatBuffer, MixFloatBuffer+MIXBUFFERSIZE, pbuffer, nCount, m_pConfig->getFloatToInt()); + } +} + + +void CSoundFile::InitializeEQ(BOOL bReset) +//---------------------------------------- +{ + REAL fMixingFreq = (REAL)gdwMixingFreq; + // Gain = 0.5 (-6dB) .. 2 (+6dB) + for (UINT band=0; band<MAX_EQ_BANDS*2; band++) if (gEQ[band].bEnable) + { + REAL k, k2, r, f; + REAL v0, v1; + BOOL b = bReset; + + f = gEQ[band].CenterFrequency / fMixingFreq; + if (f > 0.45f) gEQ[band].Gain = 1; + // if (f > 0.25) f = 0.25; + // k = tan(PI*f); + k = f * 3.141592654f; + k = k + k*f; +// if (k > (REAL)0.707) k = (REAL)0.707; + k2 = k*k; + v0 = gEQ[band].Gain; + v1 = 1; + if (gEQ[band].Gain < 1.0) + { + v0 *= (0.5f/EQ_BANDWIDTH); + v1 *= (0.5f/EQ_BANDWIDTH); + } else + { + v0 *= (1.0f/EQ_BANDWIDTH); + v1 *= (1.0f/EQ_BANDWIDTH); + } + r = (1 + v0*k + k2) / (1 + v1*k + k2); + if (r != gEQ[band].a0) + { + gEQ[band].a0 = r; + b = TRUE; + } + r = 2 * (k2 - 1) / (1 + v1*k + k2); + if (r != gEQ[band].a1) + { + gEQ[band].a1 = r; + b = TRUE; + } + r = (1 - v0*k + k2) / (1 + v1*k + k2); + if (r != gEQ[band].a2) + { + gEQ[band].a2 = r; + b = TRUE; + } + r = - 2 * (k2 - 1) / (1 + v1*k + k2); + if (r != gEQ[band].b1) + { + gEQ[band].b1 = r; + b = TRUE; + } + r = - (1 - v1*k + k2) / (1 + v1*k + k2); + if (r != gEQ[band].b2) + { + gEQ[band].b2 = r; + b = TRUE; + } + if (b) + { + gEQ[band].x1 = 0; + gEQ[band].x2 = 0; + gEQ[band].y1 = 0; + gEQ[band].y2 = 0; + } + } else + { + gEQ[band].a0 = 0; + gEQ[band].a1 = 0; + gEQ[band].a2 = 0; + gEQ[band].b1 = 0; + gEQ[band].b2 = 0; + gEQ[band].x1 = 0; + gEQ[band].x2 = 0; + gEQ[band].y1 = 0; + gEQ[band].y2 = 0; + } +} + + +void CSoundFile::SetEQGains(const UINT *pGains, UINT nGains, const UINT *pFreqs, BOOL bReset) +//------------------------------------------------------------------------------------------- +{ + for (UINT i=0; i<MAX_EQ_BANDS; i++) + { + REAL g, f = 0; + if (i < nGains) + { + UINT n = pGains[i]; + if (n > 32) n = 32; + g = ((REAL)gEqLinearToDB[n]) / 64.0f; + if (pFreqs) f = (REAL)(int)pFreqs[i]; + } else + { + g = 1; + } + gEQ[i].Gain = g; + gEQ[i].CenterFrequency = f; + gEQ[i+MAX_EQ_BANDS].Gain = g; + gEQ[i+MAX_EQ_BANDS].CenterFrequency = f; + if (f > 20.0f) + { + gEQ[i].bEnable = TRUE; + gEQ[i+MAX_EQ_BANDS].bEnable = TRUE; + } else + { + gEQ[i].bEnable = FALSE; + gEQ[i+MAX_EQ_BANDS].bEnable = FALSE; + } + } + InitializeEQ(bReset); +} Deleted: trunk/OpenMPT/soundlib/Snd_dsp.cpp =================================================================== --- trunk/OpenMPT/soundlib/Snd_dsp.cpp 2013-03-25 14:43:07 UTC (rev 1667) +++ trunk/OpenMPT/soundlib/Snd_dsp.cpp 2013-03-25 15:03:37 UTC (rev 1668) @@ -1,521 +0,0 @@ -/* - * snd_dsp.cpp - * ----------- - * Purpose: Mixing code for various DSPs (EQ, Mega-Bass, ...) - * Notes : Ugh... This should really be removed at some point. - * Authors: Olivier Lapicque - * OpenMPT Devs - * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. - */ - - -#include "stdafx.h" -#include "sndfile.h" -#include <math.h> - - -// Bass Expansion -#define DEFAULT_XBASS_RANGE 14 // (x+2)*20 Hz (320Hz) -#define DEFAULT_XBASS_DEPTH 6 // 1+(3>>(x-4)) (+6dB) - -// Buffer Sizes -#define XBASSBUFFERSIZE 64 // 2 ms at 50KHz -#define SURROUNDBUFFERSIZE 2048 // 50ms @ 48kHz - - -// DSP Effects: PUBLIC members -UINT CSoundFile::m_nXBassDepth = DEFAULT_XBASS_DEPTH; -UINT CSoundFile::m_nXBassRange = DEFAULT_XBASS_RANGE; -UINT CSoundFile::gnReverbType = 0; -UINT CSoundFile::m_nReverbDepth = 8; // 50% -UINT CSoundFile::m_nProLogicDepth = 12; -UINT CSoundFile::m_nProLogicDelay = 20; - -//////////////////////////////////////////////////////////////////// -// DSP Effects internal state - -// Noise Reduction: simple low-pass filter -static LONG nLeftNR = 0; -static LONG nRightNR = 0; - -// Surround Encoding: 1 delay line + low-pass filter + high-pass filter -static LONG nSurroundSize = 0; -static LONG nSurroundPos = 0; -static LONG nDolbyDepth = 0; -// Surround Biquads -static LONG nDolbyHP_Y1 = 0; -static LONG nDolbyHP_X1 = 0; -static LONG nDolbyLP_Y1 = 0; -static LONG nDolbyHP_B0 = 0; -static LONG nDolbyHP_B1 = 0; -static LONG nDolbyHP_A1 = 0; -static LONG nDolbyLP_B0 = 0; -static LONG nDolbyLP_B1 = 0; -static LONG nDolbyLP_A1 = 0; - -// Bass Expansion: low-pass filter -static LONG nXBassFlt_Y1 = 0; -static LONG nXBassFlt_X1 = 0; -static LONG nXBassFlt_B0 = 0; -static LONG nXBassFlt_B1 = 0; -static LONG nXBassFlt_A1 = 0; - -// DC Removal Biquad -static LONG nDCRFlt_Y1l = 0; -static LONG nDCRFlt_X1l = 0; -static LONG nDCRFlt_Y1r = 0; -static LONG nDCRFlt_X1r = 0; - - -static LONG SurroundBuffer[SURROUNDBUFFERSIZE]; - - -// Access the main temporary mix buffer directly: avoids an extra pointer -extern int MixSoundBuffer[MIXBUFFERSIZE * 4]; -extern int MixRearBuffer[MIXBUFFERSIZE * 2]; - -extern VOID InitializeReverb(BOOL bReset); -extern VOID ProcessReverb(UINT nSamples); -extern VOID MPPASMCALL X86_InitMixBuffer(int *pBuffer, UINT nSamples); -extern VOID MPPASMCALL X86_StereoFill(int *pBuffer, UINT nSamples, LPLONG lpROfs, LPLONG lpLOfs); -extern VOID MPPASMCALL X86_StereoDCRemoval(int *, UINT count); -extern VOID MPPASMCALL X86_MonoDCRemoval(int *, UINT count); - -/////////////////////////////////////////////////////////////////////////////////// -// -// Biquad setup -// - - -#define PI 3.14159265358979323f -inline FLOAT Sgn(FLOAT x) { return (x >= 0) ? 1.0f : -1.0f; } -VOID ShelfEQ(LONG scale, - LONG *outA1, LONG *outB0, LONG *outB1, - LONG F_c, LONG F_s, FLOAT gainDC, FLOAT gainFT, FLOAT gainPI) -{ - FLOAT a1, b0, b1; - FLOAT gainFT2, gainDC2, gainPI2; - FLOAT alpha, beta0, beta1, rho; - FLOAT wT, quad; - - _asm { - // wT = PI*Fc/Fs - fild F_c - fldpi - fmulp ST(1), ST(0) - fild F_s - fdivp ST(1), ST(0) - fstp wT - // gain^2 - fld gainDC - fld gainFT - fld gainPI - fmul ST(0), ST(0) - fstp gainPI2 - fmul ST(0), ST(0) - fstp gainFT2 - fmul ST(0), ST(0) - fstp gainDC2 - } - - quad = gainPI2 + gainDC2 - (gainFT2*2); - - alpha = 0; - - if (quad != 0) - { - FLOAT lambda = (gainPI2 - gainDC2) / quad; - alpha = (FLOAT)(lambda - Sgn(lambda)*sqrt(lambda*lambda - 1.0f)); - } - - beta0 = 0.5f * ((gainDC + gainPI) + (gainDC - gainPI) * alpha); - beta1 = 0.5f * ((gainDC - gainPI) + (gainDC + gainPI) * alpha); - rho = (FLOAT)((sin((wT*0.5f) - (PI/4.0f))) / (sin((wT*0.5f) + (PI/4.0f)))); - - quad = 1.0f / (1.0f + rho*alpha); - - b0 = ((beta0 + rho*beta1) * quad); - b1 = ((beta1 + rho*beta0) * quad); - a1 = - ((rho + alpha) * quad); - - _asm { - fild scale - fld a1 - mov eax, outA1 - fmul ST(0), ST(1) - fistp dword ptr [eax] - fld b0 - mov eax, outB0 - fmul ST(0), ST(1) - fistp dword ptr [eax] - fld b1 - mov eax, outB1 - fmul ST(0), ST(1) - fistp dword ptr [eax] - fstp rho - } -} - - -void CSoundFile::InitializeDSP(BOOL bReset) -//----------------------------------------- -{ - if (gnReverbType >= NUM_REVERBTYPES) gnReverbType = 0; - if (!m_nProLogicDelay) m_nProLogicDelay = 20; - if (bReset) - { - // Noise Reduction - nLeftNR = nRightNR = 0; - } - // Pro-Logic Surround - nSurroundPos = nSurroundSize = 0; - if (gdwSoundSetup & SNDMIX_SURROUND) - { - memset(SurroundBuffer, 0, sizeof(SurroundBuffer)); - nSurroundSize = (gdwMixingFreq * m_nProLogicDelay) / 1000; - if (nSurroundSize > SURROUNDBUFFERSIZE) nSurroundSize = SURROUNDBUFFERSIZE; - nDolbyDepth = m_nProLogicDepth; - if (nDolbyDepth < 1) nDolbyDepth = 1; - if (nDolbyDepth > 16) nDolbyDepth = 16; - // Setup biquad filters - ShelfEQ(1024, &nDolbyHP_A1, &nDolbyHP_B0, &nDolbyHP_B1, 200, gdwMixingFreq, 0, 0.5f, 1); - ShelfEQ(1024, &nDolbyLP_A1, &nDolbyLP_B0, &nDolbyLP_B1, 7000, gdwMixingFreq, 1, 0.75f, 0); - nDolbyHP_X1 = nDolbyHP_Y1 = 0; - nDolbyLP_Y1 = 0; - // Surround Level - nDolbyHP_B0 = (nDolbyHP_B0 * nDolbyDepth) >> 5; - nDolbyHP_B1 = (nDolbyHP_B1 * nDolbyDepth) >> 5; - // +6dB - nDolbyLP_B0 *= 2; - nDolbyLP_B1 *= 2; - } - // Reverb Setup -#ifndef NO_REVERB - InitializeReverb(bReset); -#endif - // Bass Expansion Reset - if (gdwSoundSetup & SNDMIX_MEGABASS) - { - LONG a1 = 0, b0 = 1024, b1 = 0; - int nXBassCutOff = 50 + (m_nXBassRange+2) * 20; - int nXBassGain = m_nXBassDepth; - Limit(nXBassGain, 2, 8); - Limit(nXBassCutOff, 60, 600); - ShelfEQ(1024, &a1, &b0, &b1, nXBassCutOff, gdwMixingFreq, - 1.0f + (1.0f/16.0f) * (0x300 >> nXBassGain), - 1.0f, - 0.0000001f); - if (nXBassGain > 5) - { - b0 >>= (nXBassGain-5); - b1 >>= (nXBassGain-5); - } - nXBassFlt_A1 = a1; - nXBassFlt_B0 = b0; - nXBassFlt_B1 = b1; - //Log("b0=%d b1=%d a1=%d\n", b0, b1, a1); - } - if (bReset) - { - nXBassFlt_X1 = 0; - nXBassFlt_Y1 = 0; - nDCRFlt_X1l = 0; - nDCRFlt_X1r = 0; - nDCRFlt_Y1l = 0; - nDCRFlt_Y1r = 0; - } -} - - -// 2-channel surround -static void ProcessStereoSurround(int count) -//------------------------------------------ -{ - int *pr = MixSoundBuffer, hy1 = nDolbyHP_Y1; - for (int r=count; r; r--) - { - // Delay - int secho = SurroundBuffer[nSurroundPos]; - SurroundBuffer[nSurroundPos] = (pr[0]+pr[1]+256) >> 9; - // High-pass - int v0 = (nDolbyHP_B0 * secho + nDolbyHP_B1 * nDolbyHP_X1 + nDolbyHP_A1 * hy1) >> 10; - nDolbyHP_X1 = secho; - // Low-pass - int v = (nDolbyLP_B0 * v0 + nDolbyLP_B1 * hy1 + nDolbyLP_A1 * nDolbyLP_Y1) >> (10-8); - hy1 = v0; - nDolbyLP_Y1 = v >> 8; - // Add echo - pr[0] += v; - pr[1] -= v; - if (++nSurroundPos >= nSurroundSize) nSurroundPos = 0; - pr += 2; - } - nDolbyHP_Y1 = hy1; -} - - -// 4-channels surround -static void ProcessQuadSurround(int count) -//---------------------------------------- -{ - int *pr = MixSoundBuffer, hy1 = nDolbyHP_Y1; - for (int r=count; r; r--) - { - int vl = pr[0] >> 1; - int vr = pr[1] >> 1; - pr[(UINT)(MixRearBuffer-MixSoundBuffer)] += vl; - pr[((UINT)(MixRearBuffer-MixSoundBuffer))+1] += vr; - // Delay - int secho = SurroundBuffer[nSurroundPos]; - SurroundBuffer[nSurroundPos] = (vr+vl+256) >> 9; - // High-pass - int v0 = (nDolbyHP_B0 * secho + nDolbyHP_B1 * nDolbyHP_X1 + nDolbyHP_A1 * hy1) >> 10; - nDolbyHP_X1 = secho; - // Low-pass - int v = (nDolbyLP_B0 * v0 + nDolbyLP_B1 * hy1 + nDolbyLP_A1 * nDolbyLP_Y1) >> (10-8); - hy1 = v0; - nDolbyLP_Y1 = v >> 8; - // Add echo - pr[(UINT)(MixRearBuffer-MixSoundBuffer)] += v; - pr[((UINT)(MixRearBuffer-MixSoundBuffer))+1] += v; - if (++nSurroundPos >= nSurroundSize) nSurroundPos = 0; - pr += 2; - } - nDolbyHP_Y1 = hy1; -} - - -void CSoundFile::ProcessStereoDSP(int count) -//------------------------------------------ -{ - // Dolby Pro-Logic Surround - if (gdwSoundSetup & SNDMIX_SURROUND) - { - if (gnChannels > 2) ProcessQuadSurround(count); else - ProcessStereoSurround(count); - } - // DC Removal - if (gdwSoundSetup & SNDMIX_MEGABASS) - { - X86_StereoDCRemoval(MixSoundBuffer, count); - } - // Bass Expansion - if (gdwSoundSetup & SNDMIX_MEGABASS) - { - int *px = MixSoundBuffer; - int x1 = nXBassFlt_X1; - int y1 = nXBassFlt_Y1; - for (int x=count; x; x--) - { - int x_m = (px[0]+px[1]+0x100)>>9; - - y1 = (nXBassFlt_B0 * x_m + nXBassFlt_B1 * x1 + nXBassFlt_A1 * y1) >> (10-8); - x1 = x_m; - px[0] += y1; - px[1] += y1; - y1 = (y1+0x80) >> 8; - px += 2; - } - nXBassFlt_X1 = x1; - nXBassFlt_Y1 = y1; - } - // Noise Reduction - if (gdwSoundSetup & SNDMIX_NOISEREDUCTION) - { - int n1 = nLeftNR, n2 = nRightNR; - int *pnr = MixSoundBuffer; - for (int nr=count; nr; nr--) - { - int vnr = pnr[0] >> 1; - pnr[0] = vnr + n1; - n1 = vnr; - vnr = pnr[1] >> 1; - pnr[1] = vnr + n2; - n2 = vnr; - pnr += 2; - } - nLeftNR = n1; - nRightNR = n2; - } -} - - -void CSoundFile::ProcessMonoDSP(int count) -//---------------------------------------- -{ - // DC Removal - if (gdwSoundSetup & SNDMIX_MEGABASS) - { - X86_MonoDCRemoval(MixSoundBuffer, count); - } - // Bass Expansion - if (gdwSoundSetup & SNDMIX_MEGABASS) - { - int *px = MixSoundBuffer; - int x1 = nXBassFlt_X1; - int y1 = nXBassFlt_Y1; - for (int x=count; x; x--) - { - int x_m = (px[0]+0x80)>>8; - - y1 = (nXBassFlt_B0 * x_m + nXBassFlt_B1 * x1 + nXBassFlt_A1 * y1) >> (10-8); - x1 = x_m; - px[0] += y1; - y1 = (y1+0x40) >> 8; - px++; - } - nXBassFlt_X1 = x1; - nXBassFlt_Y1 = y1; - } - // Noise Reduction - if (gdwSoundSetup & SNDMIX_NOISEREDUCTION) - { - int n = nLeftNR; - int *pnr = MixSoundBuffer; - for (int nr=count; nr; pnr++, nr--) - { - int vnr = *pnr >> 1; - *pnr = vnr + n; - n = vnr; - } - nLeftNR = n; - } -} - - - -////////////////////////////////////////////////////////////////////////// -// -// DC Removal -// - -#define DCR_AMOUNT 9 - -VOID MPPASMCALL X86_StereoDCRemoval(int *pBuffer, UINT nSamples) -{ - int y1l=nDCRFlt_Y1l, x1l=nDCRFlt_X1l; - int y1r=nDCRFlt_Y1r, x1r=nDCRFlt_X1r; - - _asm { - mov esi, pBuffer - mov ecx, nSamples -stereodcr: - mov eax, [esi] - mov ebx, x1l - mov edx, [esi+4] - mov edi, x1r - add esi, 8 - sub ebx, eax - mov x1l, eax - mov eax, ebx - sar eax, DCR_AMOUNT+1 - sub edi, edx - sub eax, ebx - mov x1r, edx - add eax, y1l - mov edx, edi - sar edx, DCR_AMOUNT+1 - mov [esi-8], eax - sub edx, edi - mov ebx, eax - add edx, y1r - sar ebx, DCR_AMOUNT - mov [esi-4], edx - mov edi, edx - sub eax, ebx - sar edi, DCR_AMOUNT - mov y1l, eax - sub edx, edi - dec ecx - mov y1r, edx - jnz stereodcr - } - nDCRFlt_Y1l = y1l; - nDCRFlt_X1l = x1l; - nDCRFlt_Y1r = y1r; - nDCRFlt_X1r = x1r; -} - - -VOID MPPASMCALL X86_MonoDCRemoval(int *pBuffer, UINT nSamples) -{ - _asm { - mov esi, pBuffer - mov ecx, nSamples - mov edx, nDCRFlt_X1l - mov edi, nDCRFlt_Y1l -stereodcr: - mov eax, [esi] - mov ebx, edx - add esi, 4 - sub ebx, eax - mov edx, eax - mov eax, ebx - sar eax, DCR_AMOUNT+1 - sub eax, ebx - add eax, edi - mov [esi-4], eax - mov ebx, eax - sar ebx, DCR_AMOUNT - sub eax, ebx - dec ecx - mov edi, eax - jnz stereodcr - mov nDCRFlt_X1l, edx - mov nDCRFlt_Y1l, edi - } -} - - - - - -///////////////////////////////////////////////////////////////// -// Clean DSP Effects interface - -// [Reverb level 0(quiet)-100(loud)], [type = REVERBTYPE_XXXX] -BOOL CSoundFile::SetReverbParameters(UINT nDepth, UINT nType) -//----------------------------------------------------------- -{ - if (nDepth > 100) nDepth = 100; - UINT gain = (nDepth * 16) / 100; - if (gain > 16) gain = 16; - if (gain < 1) gain = 1; - m_nReverbDepth = gain; - if (nType < NUM_REVERBTYPES) gnReverbType = nType; - return TRUE; -} - - -// [XBass level 0(quiet)-100(loud)], [cutoff in Hz 20-100] -BOOL CSoundFile::SetXBassParameters(UINT nDepth, UINT nRange) -//----------------------------------------------------------- -{ - if (nDepth > 100) nDepth = 100; - UINT gain = nDepth / 20; - if (gain > 4) gain = 4; - m_nXBassDepth = 8 - gain; // filter attenuation 1/256 .. 1/16 - UINT range = nRange / 5; - if (range > 5) range -= 5; else range = 0; - if (nRange > 16) nRange = 16; - m_nXBassRange = 21 - range; // filter average on 0.5-1.6ms - return TRUE; -} - - -// [Surround level 0(quiet)-100(heavy)] [delay in ms, usually 5-50ms] -BOOL CSoundFile::SetSurroundParameters(UINT nDepth, UINT nDelay) -//-------------------------------------------------------------- -{ - UINT gain = (nDepth * 16) / 100; - if (gain > 16) gain = 16; - if (gain < 1) gain = 1; - m_nProLogicDepth = gain; - if (nDelay < 4) nDelay = 4; - if (nDelay > 50) nDelay = 50; - m_nProLogicDelay = nDelay; - return TRUE; -} - - - Deleted: trunk/OpenMPT/soundlib/Snd_eq.cpp =================================================================== --- trunk/OpenMPT/soundlib/Snd_eq.cpp 2013-03-25 14:43:07 UTC (rev 1667) +++ trunk/OpenMPT/soundlib/Snd_eq.cpp 2013-03-25 15:03:37 UTC (rev 1668) @@ -1,532 +0,0 @@ -/* - * snd_eq.cpp - * ---------- - * Purpose: Mixing code for equalizer. - * Notes : Ugh... This should really be removed at some point. - * Authors: Olivier Lapicque - * OpenMPT Devs - * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. - */ - - -#include "stdafx.h" -#include "sndfile.h" -#include "../mptrack/TrackerSettings.h" - -#define EQ_BANDWIDTH 2.0 -#define EQ_ZERO 0.000001 -#define REAL float - -extern REAL MixFloatBuffer[]; - -extern void X86_StereoMixToFloat(const int *pSrc, float *pOut1, float *pOut2, UINT nCount, const float _i2fc); -extern void X86_FloatToStereoMix(const float *pIn1, const float *pIn2, int *pOut, UINT nCount, const float _f2ic); -extern void X86_MonoMixToFloat(const int *pSrc, float *pOut, UINT nCount, const float _i2fc); -extern void X86_FloatToMonoMix(const float *pIn, int *pOut, UINT nCount, const float _f2ic); - -#ifdef ENABLE_SSE -extern void SSE_MonoMixToFloat(const int *pSrc, float *pOut, UINT nCount, const float _i2fc); -#endif -#ifdef ENABLE_3DNOW -extern void AMD_MonoMixToFloat(const int *pSrc, float *pOut, UINT nCount, const float _i2fc); -extern void AMD_FloatToMonoMix(const float *pIn, int *pOut, UINT nCount, const float _f2ic); -#endif - - - - -#pragma pack(push, 4) -typedef struct _EQBANDSTRUCT -{ - REAL a0, a1, a2, b1, b2; - REAL x1, x2, y1, y2; - REAL Gain, CenterFrequency; - BOOL bEnable; -} EQBANDSTRUCT, *PEQBANDSTRUCT; -#pragma pack(pop) - -UINT gEqLinearToDB[33] = -{ - 16, 19, 22, 25, 28, 31, 34, 37, - 40, 43, 46, 49, 52, 55, 58, 61, - 64, 76, 88, 100, 112, 124, 136, 148, - 160, 172, 184, 196, 208, 220, 232, 244, 256 -}; - - -static REAL f2ic = (REAL)(1 << 28); -static REAL i2fc = (REAL)(1.0 / (1 << 28)); - -static EQBANDSTRUCT gEQ[MAX_EQ_BANDS*2] = -{ - // Default: Flat EQ - {0,0,0,0,0, 0,0,0,0, 1, 120, FALSE}, - {0,0,0,0,0, 0,0,0,0, 1, 600, FALSE}, - {0,0,0,0,0, 0,0,0,0, 1, 1200, FALSE}, - {0,0,0,0,0, 0,0,0,0, 1, 3000, FALSE}, - {0,0,0,0,0, 0,0,0,0, 1, 6000, FALSE}, - {0,0,0,0,0, 0,0,0,0, 1, 10000, FALSE}, - {0,0,0,0,0, 0,0,0,0, 1, 120, FALSE}, - {0,0,0,0,0, 0,0,0,0, 1, 600, FALSE}, - {0,0,0,0,0, 0,0,0,0, 1, 1200, FALSE}, - {0,0,0,0,0, 0,0,0,0, 1, 3000, FALSE}, - {0,0,0,0,0, 0,0,0,0, 1, 6000, FALSE}, - {0,0,0,0,0, 0,0,0,0, 1, 10000, FALSE}, -}; - -#define ASM_EQ -#ifdef ASM_EQ - -#pragma warning(disable:4100) - -#define PBS_A0 DWORD PTR [eax] -#define PBS_A1 DWORD PTR [eax+4] -#define PBS_A2 DWORD PTR [eax+8] -#define PBS_B1 DWORD PTR [eax+12] -#define PBS_B2 DWORD PTR [eax+16] -#define PBS_X1 DWORD PTR [eax+20] -#define PBS_X2 DWORD PTR [eax+24] -#define PBS_Y1 DWORD PTR [eax+28] -#define PBS_Y2 DWORD PTR [eax+32] - -void __cdecl EQFilter(EQBANDSTRUCT *pbs, REAL *pbuffer, UINT nCount) -//------------------------------------------------------------------ -{ - _asm { - mov eax, pbs // eax = pbs - mov edx, nCount // edx = nCount - mov ecx, pbuffer // ecx = pbuffer - fld PBS_Y2 // ST(3)=y2 - fld PBS_Y1 // ST(2)=y1 - fld PBS_X2 // ST(1)=x2 - fld PBS_X1 // ST(0)=x1 -EQ_Loop: - fld DWORD PTR [ecx] // ST(0):x ST(1):x1 ST(2):x2 ST(3):y1 ST(4):y2 - fld PBS_A0 // ST(0):a0 ST(1):x ST(2):x1 ST(3):x2 ST(4):y1 ST(5):y2 - fmul ST(0), ST(1) // ST(0):a0*x - fld PBS_A1 // ST(0):a1 ST(1):a0*x ST(2):x ST(3):x1 ST(4):x2 ST(5):y1 ST(6):y2 - fmul ST(0), ST(3) // ST(0):a1*x1 - add ecx, 4 - - faddp ST(1), ST(0) - fld PBS_A2 - fmul ST(0), ST(4) - faddp ST(1), ST(0) - fld PBS_B1 - fmul ST(0), ST(5) - faddp ST(1), ST(0) - fld PBS_B2 - fmul ST(0), ST(6) - sub edx, 1 - faddp ST(1), ST(0) - fst DWORD PTR [ecx-4] // *pbuffer = a0*x+a1*x1+a2*x2+b1*y1+b2*y2 - // Here, ST(0)=y ST(1)=x ST(2)=x1 ST(3)=x2 ST(4)=y1 ST(5)=y2 - fxch ST(4) // y1=y - fstp ST(5) // y2=y1 - // Here, ST(0)=x ST(1)=x1 ST(2)=x2 ST(3)=y1 ST(4)=y2 - fxch ST(1) // x1=x - fstp ST(2) // x2=x1 - jnz EQ_Loop - // Store x1,y1,x2,y2 and pop FPU stack - fstp PBS_X1 - fstp PBS_X2 - fstp PBS_Y1 - fstp PBS_Y2 - } -} - - -void AMD_StereoEQ(EQBANDSTRUCT *pbl, EQBANDSTRUCT *pbr, REAL *pbuffer, UINT nCount) -//--------------------------------------------------------------------------------- -{ -#ifdef ENABLE_3DNOW - float tmp[16]; - - _asm { - mov eax, pbl - mov edx, pbr - mov ebx, pbuffer - mov ecx, nCount - lea edi, [tmp+8] - and edi, 0xfffffff8 - movd mm7, [eax+EQBANDSTRUCT.a0] - movd mm0, [edx+EQBANDSTRUCT.a0] - movd mm6, [eax+EQBANDSTRUCT.a1] - movd mm1, [edx+EQBANDSTRUCT.a1] - punpckldq mm7, mm0 - punpckldq mm6, mm1 - movq [edi], mm7 // [edi] = a0 - movq [edi+8], mm6 // [edi+8] = a1 - movd mm5, [eax+EQBANDSTRUCT.a2] - movd mm0, [edx+EQBANDSTRUCT.a2] - movd mm4, [eax+EQBANDSTRUCT.b1] - movd mm1, [edx+EQBANDSTRUCT.b1] - movd mm3, [eax+EQBANDSTRUCT.b2] - movd mm2, [edx+EQBANDSTRUCT.b2] - punpckldq mm5, mm0 - punpckldq mm4, mm1 - punpckldq mm3, mm2 - movq [edi+16], mm5 // [edi+16] = a2 - movq [edi+24], mm4 // [edi+24] = b1 - movq [edi+32], mm3 // [edi+32] = b2 - movd mm4, [eax+EQBANDSTRUCT.x1] - movd mm0, [edx+EQBANDSTRUCT.x1] - movd mm5, [eax+EQBANDSTRUCT.x2] - movd mm1, [edx+EQBANDSTRUCT.x2] - punpckldq mm4, mm0 // mm4 = x1 - punpckldq mm5, mm1 // mm5 = x2 - movd mm6, [eax+EQBANDSTRUCT.y1] - movd mm2, [edx+EQBANDSTRUCT.y1] - movd mm7, [eax+EQBANDSTRUCT.y2] - movd mm3, [edx+EQBANDSTRUCT.y2] - punpckldq mm6, mm2 // mm6 = y1 - punpckldq mm7, mm3 // mm7 = y2 -mainloop: - movq mm0, [ebx] - movq mm3, [edi+8] - add ebx, 8 - movq mm1, [edi+16] - pfmul mm3, mm4 // x1 * a1 - movq mm2, [edi+32] - pfmul mm1, mm5 // x2 * a2 - movq mm5, mm4 // x2 = x1 - pfmul mm2, mm7 // y2 * b2 - movq mm7, mm6 // y2 = y1 - pfmul mm6, [edi+24] // y1 * b1 - movq mm4, mm0 // x1 = x - pfmul mm0, [edi] // x * a0 - pfadd mm6, mm1 // x2*a2 + y1*b1 - pfadd mm6, mm2 // x2*a2 + y1*b1 + y2*b2 - pfadd mm6, mm3 // x1*a1 + x2*a2 + y1*b1 + y2*b2 - pfadd mm6, mm0 // x*a0 + x1*a1 + x2*a2 + y1*b1 + y2*b2 - dec ecx - movq [ebx-8], mm6 - jnz mainloop - movd [eax+EQBANDSTRUCT.x1], mm4 - punpckhdq mm4, mm4 - movd [eax+EQBANDSTRUCT.x2], mm5 - punpckhdq mm5, mm5 - movd [eax+EQBANDSTRUCT.y1], mm6 - punpckhdq mm6, mm6 - movd [eax+EQBANDSTRUCT.y2], mm7 - punpckhdq mm7, mm7 - movd [edx+EQBANDSTRUCT.x1], mm4 - movd [edx+EQBANDSTRUCT.x2], mm5 - movd [edx+EQBANDSTRUCT.y1], mm6 - movd [edx+EQBANDSTRUCT.y2], mm7 - emms - } -#endif -} - - -void SSE_StereoEQ(EQBANDSTRUCT *pbl, EQBANDSTRUCT *pbr, REAL *pbuffer, UINT nCount) -//--------------------------------------------------------------------------------- -{ -#ifdef ENABLE_SSE - static const float gk1 = 1.0f; - _asm { - mov eax, pbl - mov edx, pbr - mov ebx, pbuffer - mov ecx, nCount - movss xmm0, [eax+EQBANDSTRUCT.Gain] - movss xmm1, gk1 - comiss xmm0, xmm1 - jne doeq - movss xmm0, [edx+EQBANDSTRUCT.Gain] - comiss xmm0, xmm1 - je done -doeq: - test ecx, ecx - jz done - movss xmm6, [eax+EQBANDSTRUCT.a1] - movss xmm7, [eax+EQBANDSTRUCT.a2] - movss xmm4, [eax+EQBANDSTRUCT.x1] - movss xmm5, [eax+EQBANDSTRUCT.x2] - movlhps xmm6, xmm7 // xmm6 = [ 0 | a2 | 0 | a1 ] - movlhps xmm4, xmm5 // xmm4 = [ 0 | x2 | 0 | x1 ] - movss xmm2, [edx+EQBANDSTRUCT.a1] - movss xmm3, [edx+EQBANDSTRUCT.a2] - movss xmm0, [edx+EQBANDSTRUCT.x1] - movss xmm1, [edx+EQBANDSTRUCT.x2] - movlhps xmm2, xmm3 // xmm2 = [ 0 | a'2 | 0 | a'1 ] - movlhps xmm0, xmm1 // xmm0 = [ 0 | x'2 | 0 | x'1 ] - shufps xmm6, xmm2, 0x88 // xmm6 = [ a'2 | a'1 | a2 | a1 ] - shufps xmm4, xmm0, 0x88 // xmm4 = [ x'2 | x'1 | x2 | x1 ] - shufps xmm6, xmm6, 0xD8 // xmm6 = [ a'2 | a2 | a'1 | a1 ] - shufps xmm4, xmm4, 0xD8 // xmm4 = [ x'2 | x2 | x'1 | x1 ] - movss xmm7, [eax+EQBANDSTRUCT.b1] - movss xmm0, [eax+EQBANDSTRUCT.b2] - movss xmm2, [edx+EQBANDSTRUCT.b1] - movss xmm1, [edx+EQBANDSTRUCT.b2] - movlhps xmm7, xmm0 // xmm7 = [ 0 | b2 | 0 | b1 ] - movlhps xmm2, xmm1 // xmm2 = [ 0 | b'2 | 0 | b'1 ] - shufps xmm7, xmm2, 0x88 // xmm7 = [ b'2 | b'1 | b2 | b1 ] - shufps xmm7, xmm7, 0xD8 // xmm7 = [ b'2 | b2 | b'1 | b1 ] - movss xmm5, [eax+EQBANDSTRUCT.y1] - movss xmm1, [eax+EQBANDSTRUCT.y2] - movss xmm3, [edx+EQBANDSTRUCT.y1] - movss xmm0, [edx+EQBANDSTRUCT.y2] - movlhps xmm5, xmm1 // xmm5 = [ 0 | y2 | 0 | y1 ] - movlhps xmm3, xmm0 // xmm3 = [ 0 | y'2 | 0 | y'1 ] - shufps xmm5, xmm3, 0x88 // xmm5 = [ y'2 | y'1 | y2 | y1 ] - shufps xmm5, xmm5, 0xD8 // xmm5 = [ y'2 | y2 | y'1 | y1 ] - movss xmm3, [eax+EQBANDSTRUCT.a0] - movss xmm2, [edx+EQBANDSTRUCT.a0] - shufps xmm3, xmm2, 0x88 - shufps xmm3, xmm3, 0xD8 // xmm3 = [ 0 | 0 | a'0 | a0 ] -mainloop: - movlps xmm0, qword ptr [ebx] - add ebx, 8 - movaps xmm1, xmm5 // xmm1 = [ y2r | y2l | y1r | y1l ] - mulps xmm1, xmm7 // xmm1 = [b2r*y2r|b2l*y2l|b1r*y1r|b1l*y1l] - movaps xmm2, xmm4 // xmm2 = [ x2r | x2l | x1r | x1l ] - mulps xmm2, xmm6 // xmm6 = [a2r*x2r|a2l*x2l|a1r*x1r|a1l*x1l] - shufps xmm4, xmm0, 0x44 // xmm4 = [ xr | xl | x1r | x1l ] - mulps xmm0, xmm3 // xmm0 = [ 0 | 0 |a0r*xr|a0l*xl] - shufps xmm4, xmm4, 0x4E // xmm4 = [ x1r | x1l | xr | xl ] - addps xmm1, xmm2 // xmm1 = [b2r*y2r+a2r*x2r|b2l*y2l+a2l*x2l|b1r*y1r+a1r*x1r|b1l*y1l+a1l*x1l] - addps xmm1, xmm0 // xmm1 = [b2r*y2r+a2r*x2r|b2l*y2l+a2l*x2l|b1r*y1r+a1r*x1r+a0r*xr|b1l*y1l+a1l*x1l+a0l*xl] - sub ecx, 1 - movhlps xmm0, xmm1 - addps xmm0, xmm1 // xmm0 = [ ? | ? | yr(n) | yl(n) ] - movlps [ebx-8], xmm0 - shufps xmm0, xmm5, 0x44 - movaps xmm5, xmm0 - jnz mainloop - movhlps xmm0, xmm4 - movhlps xmm1, xmm5 - movss [eax+EQBANDSTRUCT.x1], xmm4 - movss [eax+EQBANDSTRUCT.x2], xmm0 - movss [eax+EQBANDSTRUCT.y1], xmm5 - movss [eax+EQBANDSTRUCT.y2], xmm1 - shufps xmm4, xmm4, 0x01 - shufps xmm0, xmm0, 0x01 - shufps xmm5, xmm5, 0x01 - shufps xmm1, xmm1, 0x01 - movss [edx+EQBANDSTRUCT.x1], xmm4 - movss [edx+EQBANDSTRUCT.x2], xmm0 - movss [edx+EQBANDSTRUCT.y1], xmm5 - movss [edx+EQBANDSTRUCT.y2], xmm1 -done:; - } -#endif SSE_SPECIFIC -} - -#pragma warning(default:4100) - -#else - -void EQFilter(EQBANDSTRUCT *pbs, REAL *pbuffer, UINT nCount) -//---------------------------------------------------------- -{ - for (UINT i=0; i<nCount; i++) - { - REAL x = pbuffer[i]; - REAL y = pbs->a1 * pbs->x1 + pbs->a2 * pbs->x2 + pbs->a0 * x + pbs->b1 * pbs->y1 + pbs->b2 * pbs->y2; - pbs->x2 = pbs->x1; - pbs->y2 = pbs->y1; - pbs->x1 = x; - pbuffer[i] = y; - pbs->y1 = y; - } -} - -#endif - - -void CSoundFile::EQMono(int *pbuffer, UINT nCount) -//------------------------------------------------ -{ - MonoMixToFloat(pbuffer, MixFloatBuffer, nCount); - for (UINT b=0; b<MAX_EQ_BANDS; b++) - { - if ((gEQ[b].bEnable) && (gEQ[b].Gain != 1.0f)) EQFilter(&gEQ[b], MixFloatBuffer, nCount); - } - FloatToMonoMix(MixFloatBuffer, pbuffer, nCount); -} - - -void CSoundFile::EQStereo(int *pbuffer, UINT nCount) -//-------------------------------------------------- -{ - -#ifdef ENABLE_SSE -#ifdef ENABLE_MMX - - // Still allow the check, because the user can turn this on/off - - if ((gdwSysInfo & SYSMIX_SSE) && (gdwSoundSetup & SNDMIX_ENABLEMMX)) - { - int sse_state, sse_eqstate; - SSE_MonoMixToFloat(pbuffer, MixFloatBuffer, nCount*2, m_pConfig->getIntToFloat()); - - _asm stmxcsr sse_state; - sse_eqstate = sse_state | 0xFF80; - _asm ldmxcsr sse_eqstate; - for (UINT b=0; b<MAX_EQ_BANDS; b++) - { - if ((gEQ[b].bEnable) || (gEQ[b+MAX_EQ_BANDS].bEnable)) - SSE_StereoEQ(&gEQ[b], &gEQ[b+MAX_EQ_BANDS], MixFloatBuffer, nCount); - } - _asm ldmxcsr sse_state; - - X86_FloatToMonoMix(MixFloatBuffer, pbuffer, nCount*2, m_pConfig->getFloatToInt()); - - } else - -#endif // ENABLE_MMX -#endif // ENABLE_SSE - -#ifdef ENABLE_3DNOW - - // We still perform the MMX check because the user can enable/disable this - - if ((gdwSysInfo & SYSMIX_3DNOW) && (gdwSoundSetup & SNDMIX_ENABLEMMX)) - { - AMD_MonoMixToFloat(pbuffer, MixFloatBuffer, nCount*2, m_pConfig->getIntToFloat()); - - for (UINT b=0; b<MAX_EQ_BANDS; b++) - { - if (((gEQ[b].bEnable) && (gEQ[b].Gain != 1.0f)) - || ((gEQ[b+MAX_EQ_BANDS].bEnable) && (gEQ[b+MAX_EQ_BANDS].Gain != 1.0f))) - AMD_StereoEQ(&gEQ[b], &gEQ[b+MAX_EQ_BANDS], MixFloatBuffer, nCount); - } - - AMD_FloatToMonoMix(MixFloatBuffer, pbuffer, nCount*2, m_pConfig->getFloatToInt()); - - } else -#endif // ENABLE_3DNOW - - { - X86_StereoMixToFloat(pbuffer, MixFloatBuffer, MixFloatBuffer+MIXBUFFERSIZE, nCount, m_pConfig->getIntToFloat()); - - for (UINT bl=0; bl<MAX_EQ_BANDS; bl++) - { - if ((gEQ[bl].bEnable) && (gEQ[bl].Gain != 1.0f)) EQFilter(&gEQ[bl], MixFloatBuffer, nCount); - } - for (UINT br=MAX_EQ_BANDS; br<MAX_EQ_BANDS*2; br++) - { - if ((gEQ[br].bEnable) && (gEQ[br].Gain != 1.0f)) EQFilter(&gEQ[br], MixFloatBuffer+MIXBUFFERSIZE, nCount); - } - - X86_FloatToStereoMix(MixFloatBuffer, MixFloatBuffer+MIXBUFFERSIZE, pbuffer, nCount, m_pConfig->getFloatToInt()); - } -} - - -void CSoundFile::InitializeEQ(BOOL bReset) -//---------------------------------------- -{ - REAL fMixingFreq = (REAL)gdwMixingFreq; - // Gain = 0.5 (-6dB) .. 2 (+6dB) - for (UINT band=0; band<MAX_EQ_BANDS*2; band++) if (gEQ[band].bEnable) - { - REAL k, k2, r, f; - REAL v0, v1; - BOOL b = bReset; - - f = gEQ[band].CenterFrequency / fMixingFreq; - if (f > 0.45f) gEQ[band].Gain = 1; - // if (f > 0.25) f = 0.25; - // k = tan(PI*f); - k = f * 3.141592654f; - k = k + k*f; -// if (k > (REAL)0.707) k = (REAL)0.707; - k2 = k*k; - v0 = gEQ[band].Gain; - v1 = 1; - if (gEQ[band].Gain < 1.0) - { - v0 *= (0.5f/EQ_BANDWIDTH); - v1 *= (0.5f/EQ_BANDWIDTH); - } else - { - v0 *= (1.0f/EQ_BANDWIDTH); - v1 *= (1.0f/EQ_BANDWIDTH); - } - r = (1 + v0*k + k2) / (1 + v1*k + k2); - if (r != gEQ[band].a0) - { - gEQ[band].a0 = r; - b = TRUE; - } - r = 2 * (k2 - 1) / (1 + v1*k + k2); - if (r != gEQ[band].a1) - { - gEQ[band].a1 = r; - b = TRUE; - } - r = (1 - v0*k + k2) / (1 + v1*k + k2); - if (r != gEQ[band].a2) - { - gEQ[band].a2 = r; - b = TRUE; - } - r = - 2 * (k2 - 1) / (1 + v1*k + k2); - if (r != gEQ[band].b1) - { - gEQ[band].b1 = r; - b = TRUE; - } - r = - (1 - v1*k + k2) / (1 + v1*k + k2); - if (r != gEQ[band].b2) - { - gEQ[band].b2 = r; - b = TRUE; - } - if (b) - { - gEQ[band].x1 = 0; - gEQ[band].x2 = 0; - gEQ[band].y1 = 0; - gEQ[band].y2 = 0; - } - } else - { - gEQ[band].a0 = 0; - gEQ[band].a1 = 0; - gEQ[band].a2 = 0; - gEQ[band].b1 = 0; - gEQ[band].b2 = 0; - gEQ[band].x1 = 0; - gEQ[band].x2 = 0; - gEQ[band].y1 = 0; - gEQ[band].y2 = 0; - } -} - - -void CSoundFile::... [truncated message content] |