123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487 |
- /*
- * 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 "DSP.h"
- #include "openmpt/soundbase/MixSample.hpp"
- #include <math.h>
- OPENMPT_NAMESPACE_BEGIN
- #ifndef NO_DSP
- // Bass Expansion
- #define DEFAULT_XBASS_RANGE 14 // (x+2)*20 Hz (320Hz)
- #define DEFAULT_XBASS_DEPTH 6 // 1+(3>>(x-4)) (+6dB)
- ////////////////////////////////////////////////////////////////////
- // DSP Effects internal state
- static void X86_StereoDCRemoval(int *, uint32 count, int32 &nDCRFlt_Y1l, int32 &nDCRFlt_X1l, int32 &nDCRFlt_Y1r, int32 &nDCRFlt_X1r);
- static void X86_MonoDCRemoval(int *, uint32 count, int32 &nDCRFlt_Y1l, int32 &nDCRFlt_X1l);
- ///////////////////////////////////////////////////////////////////////////////////
- //
- // Biquad setup
- //
- #define PI 3.14159265358979323f
- static inline float Sgn(float x) { return (x >= 0) ? 1.0f : -1.0f; }
- static void ShelfEQ(int32 scale,
- int32 &outA1, int32 &outB0, int32 &outB1,
- int32 F_c, int32 F_s, float gainDC, float gainFT, float gainPI)
- {
- float a1, b0, b1;
- float gainFT2, gainDC2, gainPI2;
- float alpha, beta0, beta1, rho;
- float wT, quad;
- wT = PI * F_c / F_s;
- gainPI2 = gainPI * gainPI;
- gainFT2 = gainFT * gainFT;
- gainDC2 = gainDC * gainDC;
- 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);
- outA1 = mpt::saturate_round<int32>(a1 * scale);
- outB0 = mpt::saturate_round<int32>(b0 * scale);
- outB1 = mpt::saturate_round<int32>(b1 * scale);
- }
- CSurroundSettings::CSurroundSettings() : m_nProLogicDepth(12), m_nProLogicDelay(20)
- {
- }
- CMegaBassSettings::CMegaBassSettings() : m_nXBassDepth(DEFAULT_XBASS_DEPTH), m_nXBassRange(DEFAULT_XBASS_RANGE)
- {
- }
- CSurround::CSurround()
- {
- // Surround Encoding: 1 delay line + low-pass filter + high-pass filter
- nSurroundSize = 0;
- nSurroundPos = 0;
- nDolbyDepth = 0;
- // Surround Biquads
- nDolbyHP_Y1 = 0;
- nDolbyHP_X1 = 0;
- nDolbyLP_Y1 = 0;
- nDolbyHP_B0 = 0;
- nDolbyHP_B1 = 0;
- nDolbyHP_A1 = 0;
- nDolbyLP_B0 = 0;
- nDolbyLP_B1 = 0;
- nDolbyLP_A1 = 0;
- MemsetZero(SurroundBuffer);
- }
- CMegaBass::CMegaBass()
- {
- // Bass Expansion: low-pass filter
- nXBassFlt_Y1 = 0;
- nXBassFlt_X1 = 0;
- nXBassFlt_B0 = 0;
- nXBassFlt_B1 = 0;
- nXBassFlt_A1 = 0;
- // DC Removal Biquad
- nDCRFlt_Y1lf = 0;
- nDCRFlt_X1lf = 0;
- nDCRFlt_Y1rf = 0;
- nDCRFlt_X1rf = 0;
- nDCRFlt_Y1lb = 0;
- nDCRFlt_X1lb = 0;
- nDCRFlt_Y1rb = 0;
- nDCRFlt_X1rb = 0;
- }
- void CSurround::Initialize(bool bReset, DWORD MixingFreq)
- {
- MPT_UNREFERENCED_PARAMETER(bReset);
- if (!m_Settings.m_nProLogicDelay) m_Settings.m_nProLogicDelay = 20;
- // Pro-Logic Surround
- nSurroundPos = nSurroundSize = 0;
- {
- memset(SurroundBuffer, 0, sizeof(SurroundBuffer));
- nSurroundSize = (MixingFreq * m_Settings.m_nProLogicDelay) / 1000;
- if (nSurroundSize > SURROUNDBUFFERSIZE) nSurroundSize = SURROUNDBUFFERSIZE;
- nDolbyDepth = m_Settings.m_nProLogicDepth;
- if (nDolbyDepth < 1) nDolbyDepth = 1;
- if (nDolbyDepth > 16) nDolbyDepth = 16;
- // Setup biquad filters
- ShelfEQ(1024, nDolbyHP_A1, nDolbyHP_B0, nDolbyHP_B1, 200, MixingFreq, 0, 0.5f, 1);
- ShelfEQ(1024, nDolbyLP_A1, nDolbyLP_B0, nDolbyLP_B1, 7000, MixingFreq, 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;
- }
- }
- void CMegaBass::Initialize(bool bReset, DWORD MixingFreq)
- {
- // Bass Expansion Reset
- {
- int32 a1 = 0, b0 = 1024, b1 = 0;
- int nXBassCutOff = 50 + (m_Settings.m_nXBassRange+2) * 20;
- int nXBassGain = m_Settings.m_nXBassDepth;
- nXBassGain = std::clamp(nXBassGain, 2, 8);
- nXBassCutOff = std::clamp(nXBassCutOff, 60, 600);
- ShelfEQ(1024, a1, b0, b1, nXBassCutOff, MixingFreq,
- 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_X1lf = 0;
- nDCRFlt_X1rf = 0;
- nDCRFlt_Y1lf = 0;
- nDCRFlt_Y1rf = 0;
- nDCRFlt_X1lb = 0;
- nDCRFlt_X1rb = 0;
- nDCRFlt_Y1lb = 0;
- nDCRFlt_Y1rb = 0;
- }
- }
- // 2-channel surround
- void CSurround::ProcessStereoSurround(int * MixSoundBuffer, 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
- void CSurround::ProcessQuadSurround(int * MixSoundBuffer, int * MixRearBuffer, 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[(uint32)(MixRearBuffer-MixSoundBuffer)] += vl;
- pr[((uint32)(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[(uint32)(MixRearBuffer-MixSoundBuffer)] += v;
- pr[((uint32)(MixRearBuffer-MixSoundBuffer))+1] += v;
- if (++nSurroundPos >= nSurroundSize) nSurroundPos = 0;
- pr += 2;
- }
- nDolbyHP_Y1 = hy1;
- }
- void CSurround::Process(int * MixSoundBuffer, int * MixRearBuffer, int count, uint32 nChannels)
- {
- if(nChannels >= 2)
- // Dolby Pro-Logic Surround
- {
- if (nChannels > 2) ProcessQuadSurround(MixSoundBuffer, MixRearBuffer, count); else
- ProcessStereoSurround(MixSoundBuffer, count);
- }
- }
- void CMegaBass::Process(int * MixSoundBuffer, int * MixRearBuffer, int count, uint32 nChannels)
- {
- if(nChannels >= 2)
- {
- X86_StereoDCRemoval(MixSoundBuffer, count, nDCRFlt_Y1lf, nDCRFlt_X1lf, nDCRFlt_Y1rf, nDCRFlt_X1rf);
- if(nChannels > 2) X86_StereoDCRemoval(MixRearBuffer, count, nDCRFlt_Y1lb, nDCRFlt_X1lb, nDCRFlt_Y1rb, nDCRFlt_X1rb);
- int *px = MixSoundBuffer;
- int *py = MixRearBuffer;
- int x1 = nXBassFlt_X1;
- int y1 = nXBassFlt_Y1;
- if(nChannels > 2) for (int x=count; x; x--)
- {
- int x_m = (px[0]+px[1]+py[0]+py[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;
- py[0] += y1;
- py[1] += y1;
- y1 = (y1+0x80) >> 8;
- px += 2;
- py += 2;
- } else 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;
- } else
- {
- X86_MonoDCRemoval(MixSoundBuffer, count, nDCRFlt_Y1lf, nDCRFlt_X1lf);
- 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;
- }
- }
- //////////////////////////////////////////////////////////////////////////
- //
- // DC Removal
- //
- #define DCR_AMOUNT 9
- static void X86_StereoDCRemoval(int *pBuffer, uint32 nSamples, int32 &nDCRFlt_Y1l, int32 &nDCRFlt_X1l, int32 &nDCRFlt_Y1r, int32 &nDCRFlt_X1r)
- {
- int y1l = nDCRFlt_Y1l, x1l = nDCRFlt_X1l;
- int y1r = nDCRFlt_Y1r, x1r = nDCRFlt_X1r;
- while(nSamples--)
- {
- int inL = pBuffer[0];
- int inR = pBuffer[1];
- int diffL = x1l - inL;
- int diffR = x1r - inR;
- x1l = inL;
- x1r = inR;
- int outL = diffL / (1 << (DCR_AMOUNT + 1)) - diffL + y1l;
- int outR = diffR / (1 << (DCR_AMOUNT + 1)) - diffR + y1r;
- pBuffer[0] = outL;
- pBuffer[1] = outR;
- pBuffer += 2;
- y1l = outL - outL / (1 << DCR_AMOUNT);
- y1r = outR - outR / (1 << DCR_AMOUNT);
- }
- nDCRFlt_Y1l = y1l;
- nDCRFlt_X1l = x1l;
- nDCRFlt_Y1r = y1r;
- nDCRFlt_X1r = x1r;
- }
- static void X86_MonoDCRemoval(int *pBuffer, uint32 nSamples, int32 &nDCRFlt_Y1l, int32 &nDCRFlt_X1l)
- {
- int y1l = nDCRFlt_Y1l, x1l = nDCRFlt_X1l;
- while(nSamples--)
- {
- int inM = pBuffer[0];
- int diff = x1l - inM;
- x1l = inM;
- pBuffer[0] = inM = diff / (1 << (DCR_AMOUNT + 1)) - diff + y1l;
- pBuffer++;
- y1l = inM - inM / (1 << DCR_AMOUNT);
- }
- nDCRFlt_Y1l = y1l;
- nDCRFlt_X1l = x1l;
- }
- /////////////////////////////////////////////////////////////////
- // Clean DSP Effects interface
- // [XBass level 0(quiet)-100(loud)], [cutoff in Hz 20-100]
- void CMegaBass::SetXBassParameters(uint32 nDepth, uint32 nRange)
- {
- if (nDepth > 100) nDepth = 100;
- uint32 gain = nDepth / 20;
- if (gain > 4) gain = 4;
- m_Settings.m_nXBassDepth = 8 - gain; // filter attenuation 1/256 .. 1/16
- uint32 range = nRange / 5;
- if (range > 5) range -= 5; else range = 0;
- if (nRange > 16) nRange = 16;
- m_Settings.m_nXBassRange = 21 - range; // filter average on 0.5-1.6ms
- }
- // [Surround level 0(quiet)-100(heavy)] [delay in ms, usually 5-50ms]
- void CSurround::SetSurroundParameters(uint32 nDepth, uint32 nDelay)
- {
- uint32 gain = (nDepth * 16) / 100;
- if (gain > 16) gain = 16;
- if (gain < 1) gain = 1;
- m_Settings.m_nProLogicDepth = gain;
- if (nDelay < 4) nDelay = 4;
- if (nDelay > 50) nDelay = 50;
- m_Settings.m_nProLogicDelay = nDelay;
- }
- BitCrushSettings::BitCrushSettings()
- : m_Bits(8)
- {
- return;
- }
- BitCrush::BitCrush()
- {
- }
- void BitCrush::Initialize(bool bReset, DWORD MixingFreq)
- {
- MPT_UNREFERENCED_PARAMETER(bReset);
- MPT_UNREFERENCED_PARAMETER(MixingFreq);
- }
- void BitCrush::Process(int * MixSoundBuffer, int * MixRearBuffer, int count, uint32 nChannels)
- {
- if(m_Settings.m_Bits <= 0)
- {
- return;
- }
- if(m_Settings.m_Bits > MixSampleIntTraits::mix_precision_bits)
- {
- return;
- }
- unsigned int mask = ~((1u << (MixSampleIntTraits::mix_precision_bits - m_Settings.m_Bits)) - 1u);
- if(nChannels == 4)
- {
- for(int frame = 0; frame < count; ++frame)
- {
- MixSoundBuffer[frame*2 + 0] &= mask;
- MixSoundBuffer[frame*2 + 1] &= mask;
- MixRearBuffer[frame*2 + 0] &= mask;
- MixRearBuffer[frame*2 + 1] &= mask;
- }
- } else if(nChannels == 2)
- {
- for(int frame = 0; frame < count; ++frame)
- {
- MixSoundBuffer[frame*2 + 0] &= mask;
- MixSoundBuffer[frame*2 + 1] &= mask;
- }
- } else if(nChannels == 1)
- {
- for(int frame = 0; frame < count; ++frame)
- {
- MixSoundBuffer[frame] &= mask;
- }
- }
- }
- #else
- MPT_MSVC_WORKAROUND_LNK4221(DSP)
- #endif // NO_DSP
- OPENMPT_NAMESPACE_END
|