Initial community commit
This commit is contained in:
parent
537bcbc862
commit
fc06254474
16440 changed files with 4239995 additions and 2 deletions
141
Src/external_dependencies/openmpt-trunk/sounddsp/AGC.cpp
Normal file
141
Src/external_dependencies/openmpt-trunk/sounddsp/AGC.cpp
Normal file
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* AGC.cpp
|
||||
* -------
|
||||
* Purpose: Automatic Gain Control
|
||||
* 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 "../sounddsp/AGC.h"
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// Automatic Gain Control
|
||||
|
||||
#ifndef NO_AGC
|
||||
|
||||
#define AGC_PRECISION 10
|
||||
#define AGC_UNITY (1 << AGC_PRECISION)
|
||||
|
||||
// Limiter
|
||||
#define MIXING_LIMITMAX (0x08100000)
|
||||
#define MIXING_LIMITMIN (-MIXING_LIMITMAX)
|
||||
|
||||
|
||||
static UINT ProcessAGC(int *pBuffer, int *pRearBuffer, std::size_t nSamples, std::size_t nChannels, int nAGC)
|
||||
{
|
||||
if(nChannels == 1)
|
||||
{
|
||||
while(nSamples--)
|
||||
{
|
||||
int val = (int)(((int64)*pBuffer * (int32)nAGC) >> AGC_PRECISION);
|
||||
if(val < MIXING_LIMITMIN || val > MIXING_LIMITMAX) nAGC--;
|
||||
*pBuffer = val;
|
||||
pBuffer++;
|
||||
}
|
||||
} else
|
||||
{
|
||||
if(nChannels == 2)
|
||||
{
|
||||
while(nSamples--)
|
||||
{
|
||||
int fl = (int)(((int64)pBuffer[0] * (int32)nAGC) >> AGC_PRECISION);
|
||||
int fr = (int)(((int64)pBuffer[1] * (int32)nAGC) >> AGC_PRECISION);
|
||||
bool dec = false;
|
||||
dec = dec || (fl < MIXING_LIMITMIN || fl > MIXING_LIMITMAX);
|
||||
dec = dec || (fr < MIXING_LIMITMIN || fr > MIXING_LIMITMAX);
|
||||
if(dec) nAGC--;
|
||||
pBuffer[0] = fl;
|
||||
pBuffer[1] = fr;
|
||||
pBuffer += 2;
|
||||
}
|
||||
} else if(nChannels == 4)
|
||||
{
|
||||
while(nSamples--)
|
||||
{
|
||||
int fl = (int)(((int64)pBuffer[0] * (int32)nAGC) >> AGC_PRECISION);
|
||||
int fr = (int)(((int64)pBuffer[1] * (int32)nAGC) >> AGC_PRECISION);
|
||||
int rl = (int)(((int64)pRearBuffer[0] * (int32)nAGC) >> AGC_PRECISION);
|
||||
int rr = (int)(((int64)pRearBuffer[1] * (int32)nAGC) >> AGC_PRECISION);
|
||||
bool dec = false;
|
||||
dec = dec || (fl < MIXING_LIMITMIN || fl > MIXING_LIMITMAX);
|
||||
dec = dec || (fr < MIXING_LIMITMIN || fr > MIXING_LIMITMAX);
|
||||
dec = dec || (rl < MIXING_LIMITMIN || rl > MIXING_LIMITMAX);
|
||||
dec = dec || (rr < MIXING_LIMITMIN || rr > MIXING_LIMITMAX);
|
||||
if(dec) nAGC--;
|
||||
pBuffer[0] = fl;
|
||||
pBuffer[1] = fr;
|
||||
pRearBuffer[0] = rl;
|
||||
pRearBuffer[1] = rr;
|
||||
pBuffer += 2;
|
||||
pRearBuffer += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nAGC;
|
||||
}
|
||||
|
||||
|
||||
CAGC::CAGC()
|
||||
{
|
||||
Initialize(true, 44100);
|
||||
}
|
||||
|
||||
|
||||
void CAGC::Process(int *MixSoundBuffer, int *RearSoundBuffer, std::size_t count, std::size_t nChannels)
|
||||
{
|
||||
UINT agc = ProcessAGC(MixSoundBuffer, RearSoundBuffer, count, nChannels, m_nAGC);
|
||||
// Some kind custom law, so that the AGC stays quite stable, but slowly
|
||||
// goes back up if the sound level stays below a level inversely proportional
|
||||
// to the AGC level. (J'me comprends)
|
||||
if((agc >= m_nAGC) && (m_nAGC < AGC_UNITY))
|
||||
{
|
||||
m_nAGCRecoverCount += count;
|
||||
if(m_nAGCRecoverCount >= m_Timeout)
|
||||
{
|
||||
m_nAGCRecoverCount = 0;
|
||||
m_nAGC++;
|
||||
}
|
||||
} else
|
||||
{
|
||||
m_nAGC = agc;
|
||||
m_nAGCRecoverCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CAGC::Adjust(UINT oldVol, UINT newVol)
|
||||
{
|
||||
m_nAGC = m_nAGC * oldVol / newVol;
|
||||
if (m_nAGC > AGC_UNITY) m_nAGC = AGC_UNITY;
|
||||
}
|
||||
|
||||
|
||||
void CAGC::Initialize(bool bReset, DWORD MixingFreq)
|
||||
{
|
||||
if(bReset)
|
||||
{
|
||||
m_nAGC = AGC_UNITY;
|
||||
m_nAGCRecoverCount = 0;
|
||||
}
|
||||
m_Timeout = (MixingFreq >> (AGC_PRECISION-8)) >> 1;
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
|
||||
MPT_MSVC_WORKAROUND_LNK4221(AGC)
|
||||
|
||||
|
||||
#endif // NO_AGC
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
38
Src/external_dependencies/openmpt-trunk/sounddsp/AGC.h
Normal file
38
Src/external_dependencies/openmpt-trunk/sounddsp/AGC.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* AGC.h
|
||||
* -----
|
||||
* Purpose: Automatic Gain Control
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "openmpt/all/BuildSettings.hpp"
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
#ifndef NO_AGC
|
||||
|
||||
class CAGC
|
||||
{
|
||||
private:
|
||||
UINT m_nAGC;
|
||||
std::size_t m_nAGCRecoverCount;
|
||||
UINT m_Timeout;
|
||||
public:
|
||||
CAGC();
|
||||
void Initialize(bool bReset, DWORD MixingFreq);
|
||||
public:
|
||||
void Process(int *MixSoundBuffer, int *RearSoundBuffer, std::size_t count, std::size_t nChannels);
|
||||
void Adjust(UINT oldVol, UINT newVol);
|
||||
};
|
||||
|
||||
#endif // NO_AGC
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
487
Src/external_dependencies/openmpt-trunk/sounddsp/DSP.cpp
Normal file
487
Src/external_dependencies/openmpt-trunk/sounddsp/DSP.cpp
Normal file
|
@ -0,0 +1,487 @@
|
|||
/*
|
||||
* 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
|
142
Src/external_dependencies/openmpt-trunk/sounddsp/DSP.h
Normal file
142
Src/external_dependencies/openmpt-trunk/sounddsp/DSP.h
Normal file
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* DSP.h
|
||||
* -----
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "openmpt/all/BuildSettings.hpp"
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
#ifndef NO_DSP
|
||||
|
||||
// Buffer Sizes
|
||||
#define SURROUNDBUFFERSIZE 2048 // 50ms @ 48kHz
|
||||
|
||||
|
||||
class CSurroundSettings
|
||||
{
|
||||
public:
|
||||
uint32 m_nProLogicDepth;
|
||||
uint32 m_nProLogicDelay;
|
||||
public:
|
||||
CSurroundSettings();
|
||||
};
|
||||
|
||||
|
||||
class CMegaBassSettings
|
||||
{
|
||||
public:
|
||||
uint32 m_nXBassDepth;
|
||||
uint32 m_nXBassRange;
|
||||
public:
|
||||
CMegaBassSettings();
|
||||
};
|
||||
|
||||
|
||||
struct BitCrushSettings
|
||||
{
|
||||
int m_Bits;
|
||||
BitCrushSettings();
|
||||
};
|
||||
|
||||
|
||||
class CSurround
|
||||
{
|
||||
public:
|
||||
CSurroundSettings m_Settings;
|
||||
|
||||
// Surround Encoding: 1 delay line + low-pass filter + high-pass filter
|
||||
int32 nSurroundSize;
|
||||
int32 nSurroundPos;
|
||||
int32 nDolbyDepth;
|
||||
|
||||
// Surround Biquads
|
||||
int32 nDolbyHP_Y1;
|
||||
int32 nDolbyHP_X1;
|
||||
int32 nDolbyLP_Y1;
|
||||
int32 nDolbyHP_B0;
|
||||
int32 nDolbyHP_B1;
|
||||
int32 nDolbyHP_A1;
|
||||
int32 nDolbyLP_B0;
|
||||
int32 nDolbyLP_B1;
|
||||
int32 nDolbyLP_A1;
|
||||
|
||||
int32 SurroundBuffer[SURROUNDBUFFERSIZE];
|
||||
|
||||
public:
|
||||
CSurround();
|
||||
public:
|
||||
void SetSettings(const CSurroundSettings &settings) { m_Settings = settings; }
|
||||
// [XBass level 0(quiet)-100(loud)], [cutoff in Hz 10-100]
|
||||
bool SetXBassParameters(uint32 nDepth, uint32 nRange);
|
||||
// [Surround level 0(quiet)-100(heavy)] [delay in ms, usually 5-40ms]
|
||||
void SetSurroundParameters(uint32 nDepth, uint32 nDelay);
|
||||
void Initialize(bool bReset, DWORD MixingFreq);
|
||||
void Process(int * MixSoundBuffer, int * MixRearBuffer, int count, uint32 nChannels);
|
||||
private:
|
||||
void ProcessStereoSurround(int * MixSoundBuffer, int count);
|
||||
void ProcessQuadSurround(int * MixSoundBuffer, int * MixRearBuffer, int count);
|
||||
};
|
||||
|
||||
|
||||
|
||||
class CMegaBass
|
||||
{
|
||||
public:
|
||||
CMegaBassSettings m_Settings;
|
||||
|
||||
// Bass Expansion: low-pass filter
|
||||
int32 nXBassFlt_Y1;
|
||||
int32 nXBassFlt_X1;
|
||||
int32 nXBassFlt_B0;
|
||||
int32 nXBassFlt_B1;
|
||||
int32 nXBassFlt_A1;
|
||||
|
||||
// DC Removal Biquad
|
||||
int32 nDCRFlt_Y1lf;
|
||||
int32 nDCRFlt_X1lf;
|
||||
int32 nDCRFlt_Y1rf;
|
||||
int32 nDCRFlt_X1rf;
|
||||
int32 nDCRFlt_Y1lb;
|
||||
int32 nDCRFlt_X1lb;
|
||||
int32 nDCRFlt_Y1rb;
|
||||
int32 nDCRFlt_X1rb;
|
||||
|
||||
public:
|
||||
CMegaBass();
|
||||
public:
|
||||
void SetSettings(const CMegaBassSettings &settings) { m_Settings = settings; }
|
||||
// [XBass level 0(quiet)-100(loud)], [cutoff in Hz 10-100]
|
||||
void SetXBassParameters(uint32 nDepth, uint32 nRange);
|
||||
void Initialize(bool bReset, DWORD MixingFreq);
|
||||
void Process(int * MixSoundBuffer, int * MixRearBuffer, int count, uint32 nChannels);
|
||||
};
|
||||
|
||||
|
||||
class BitCrush
|
||||
{
|
||||
public:
|
||||
BitCrushSettings m_Settings;
|
||||
public:
|
||||
BitCrush();
|
||||
public:
|
||||
void SetSettings(const BitCrushSettings &settings) { m_Settings = settings; }
|
||||
void Initialize(bool bReset, DWORD MixingFreq);
|
||||
void Process(int * MixSoundBuffer, int * MixRearBuffer, int count, uint32 nChannels);
|
||||
};
|
||||
|
||||
|
||||
#endif // NO_DSP
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
237
Src/external_dependencies/openmpt-trunk/sounddsp/EQ.cpp
Normal file
237
Src/external_dependencies/openmpt-trunk/sounddsp/EQ.cpp
Normal file
|
@ -0,0 +1,237 @@
|
|||
/*
|
||||
* 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 "EQ.h"
|
||||
|
||||
#include "mpt/audio/span.hpp"
|
||||
#include "mpt/base/numbers.hpp"
|
||||
#include "openmpt/base/Types.hpp"
|
||||
#include "openmpt/soundbase/MixSample.hpp"
|
||||
#include "openmpt/soundbase/MixSampleConvert.hpp"
|
||||
|
||||
#ifndef NO_EQ
|
||||
#include "../misc/mptCPU.h"
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#if defined(MPT_ENABLE_ARCH_INTRINSICS_SSE)
|
||||
#include <xmmintrin.h>
|
||||
#endif
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
#ifndef NO_EQ
|
||||
|
||||
|
||||
static constexpr float EQ_BANDWIDTH = 2.0f;
|
||||
|
||||
|
||||
static constexpr std::array<uint32, 33> gEqLinearToDB =
|
||||
{
|
||||
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 constexpr std::array<EQBANDSETTINGS, MAX_EQ_BANDS> gEQDefaults =
|
||||
{{
|
||||
// Default: Flat EQ
|
||||
{0,0,0,0,0, 1, 120},
|
||||
{0,0,0,0,0, 1, 600},
|
||||
{0,0,0,0,0, 1, 1200},
|
||||
{0,0,0,0,0, 1, 3000},
|
||||
{0,0,0,0,0, 1, 6000},
|
||||
{0,0,0,0,0, 1, 10000}
|
||||
}};
|
||||
|
||||
|
||||
template <std::size_t channels, typename Tbuf>
|
||||
static void EQFilter(Tbuf & buf, const std::array<EQBANDSETTINGS, MAX_EQ_BANDS> &bands, std::array<std::array<EQBANDSTATE, MAX_EQ_BANDS>, MAX_EQ_CHANNELS> &states)
|
||||
{
|
||||
for(std::size_t frame = 0; frame < buf.size_frames(); ++frame)
|
||||
{
|
||||
for(std::size_t channel = 0; channel < channels; ++channel)
|
||||
{
|
||||
float sample = mix_sample_cast<float>(buf(channel, frame));
|
||||
for(std::size_t b = 0; b < std::size(bands); ++b)
|
||||
{
|
||||
const EQBANDSETTINGS &band = bands[b];
|
||||
if(band.Gain != 1.0f)
|
||||
{
|
||||
EQBANDSTATE &bandState = states[channel][b];
|
||||
float x = sample;
|
||||
float y = band.a1 * bandState.x1 + band.a2 * bandState.x2 + band.a0 * x + band.b1 * bandState.y1 + band.b2 * bandState.y2;
|
||||
bandState.x2 = bandState.x1;
|
||||
bandState.y2 = bandState.y1;
|
||||
bandState.x1 = x;
|
||||
bandState.y1 = y;
|
||||
sample = y;
|
||||
}
|
||||
}
|
||||
buf(channel, frame) = mix_sample_cast<typename Tbuf::sample_type>(sample);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <typename TMixSample>
|
||||
void CEQ::ProcessTemplate(TMixSample *frontBuffer, TMixSample *rearBuffer, std::size_t countFrames, std::size_t numChannels)
|
||||
{
|
||||
#if defined(MPT_ENABLE_ARCH_INTRINSICS_SSE)
|
||||
unsigned int old_csr = 0;
|
||||
if(CPU::HasFeatureSet(CPU::feature::sse))
|
||||
{
|
||||
old_csr = _mm_getcsr();
|
||||
_mm_setcsr((old_csr & ~(_MM_DENORMALS_ZERO_MASK | _MM_FLUSH_ZERO_MASK)) | _MM_DENORMALS_ZERO_ON | _MM_FLUSH_ZERO_ON);
|
||||
}
|
||||
#endif
|
||||
if(numChannels == 1)
|
||||
{
|
||||
mpt::audio_span_interleaved<TMixSample> buf{ frontBuffer, 1, countFrames };
|
||||
EQFilter<1>(buf, m_Bands, m_ChannelState);
|
||||
} else if(numChannels == 2)
|
||||
{
|
||||
mpt::audio_span_interleaved<TMixSample> buf{ frontBuffer, 2, countFrames };
|
||||
EQFilter<2>(buf, m_Bands, m_ChannelState);
|
||||
} else if(numChannels == 4)
|
||||
{
|
||||
std::array<TMixSample*, 4> buffers = { &frontBuffer[0], &frontBuffer[1], &rearBuffer[0], &rearBuffer[1] };
|
||||
mpt::audio_span_planar_strided<TMixSample> buf{ buffers.data(), 4, countFrames, 2 };
|
||||
EQFilter<4>(buf, m_Bands, m_ChannelState);
|
||||
}
|
||||
#if defined(MPT_ENABLE_ARCH_INTRINSICS_SSE)
|
||||
if(CPU::HasFeatureSet(CPU::feature::sse))
|
||||
{
|
||||
_mm_setcsr(old_csr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void CEQ::Process(MixSampleInt *frontBuffer, MixSampleInt *rearBuffer, std::size_t countFrames, std::size_t numChannels)
|
||||
{
|
||||
ProcessTemplate<MixSampleInt>(frontBuffer, rearBuffer, countFrames, numChannels);
|
||||
}
|
||||
|
||||
|
||||
void CEQ::Process(MixSampleFloat *frontBuffer, MixSampleFloat *rearBuffer, std::size_t countFrames, std::size_t numChannels)
|
||||
{
|
||||
ProcessTemplate<MixSampleFloat>(frontBuffer, rearBuffer, countFrames, numChannels);
|
||||
}
|
||||
|
||||
|
||||
CEQ::CEQ()
|
||||
: m_Bands(gEQDefaults)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void CEQ::Initialize(bool bReset, uint32 MixingFreq)
|
||||
{
|
||||
float fMixingFreq = static_cast<float>(MixingFreq);
|
||||
// Gain = 0.5 (-6dB) .. 2 (+6dB)
|
||||
for(std::size_t band = 0; band < MAX_EQ_BANDS; ++band)
|
||||
{
|
||||
float k, k2, r, f;
|
||||
float v0, v1;
|
||||
bool b = bReset;
|
||||
f = m_Bands[band].CenterFrequency / fMixingFreq;
|
||||
if(f > 0.45f)
|
||||
{
|
||||
m_Bands[band].Gain = 1.0f;
|
||||
}
|
||||
k = f * mpt::numbers::pi_v<float>;
|
||||
k = k + k*f;
|
||||
k2 = k*k;
|
||||
v0 = m_Bands[band].Gain;
|
||||
v1 = 1;
|
||||
if(m_Bands[band].Gain < 1.0f)
|
||||
{
|
||||
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 != m_Bands[band].a0)
|
||||
{
|
||||
m_Bands[band].a0 = r;
|
||||
b = true;
|
||||
}
|
||||
r = 2 * (k2 - 1) / (1 + v1*k + k2);
|
||||
if(r != m_Bands[band].a1)
|
||||
{
|
||||
m_Bands[band].a1 = r;
|
||||
b = true;
|
||||
}
|
||||
r = (1 - v0*k + k2) / (1 + v1*k + k2);
|
||||
if(r != m_Bands[band].a2)
|
||||
{
|
||||
m_Bands[band].a2 = r;
|
||||
b = true;
|
||||
}
|
||||
r = - 2 * (k2 - 1) / (1 + v1*k + k2);
|
||||
if(r != m_Bands[band].b1)
|
||||
{
|
||||
m_Bands[band].b1 = r;
|
||||
b = true;
|
||||
}
|
||||
r = - (1 - v1*k + k2) / (1 + v1*k + k2);
|
||||
if(r != m_Bands[band].b2)
|
||||
{
|
||||
m_Bands[band].b2 = r;
|
||||
b = true;
|
||||
}
|
||||
if(b)
|
||||
{
|
||||
for(std::size_t channel = 0; channel < MAX_EQ_CHANNELS; ++channel)
|
||||
{
|
||||
m_ChannelState[channel][band] = EQBANDSTATE{};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CEQ::SetEQGains(const uint32 *pGains, const uint32 *pFreqs, bool bReset, uint32 MixingFreq)
|
||||
{
|
||||
for(std::size_t i = 0; i < MAX_EQ_BANDS; ++i)
|
||||
{
|
||||
m_Bands[i].Gain = static_cast<float>(gEqLinearToDB[std::clamp(pGains[i], static_cast<uint32>(0), static_cast<uint32>(std::size(gEqLinearToDB) - 1))]) / 64.0f;
|
||||
m_Bands[i].CenterFrequency = static_cast<float>(pFreqs[i]);
|
||||
}
|
||||
Initialize(bReset, MixingFreq);
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
|
||||
MPT_MSVC_WORKAROUND_LNK4221(EQ)
|
||||
|
||||
|
||||
#endif // !NO_EQ
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
66
Src/external_dependencies/openmpt-trunk/sounddsp/EQ.h
Normal file
66
Src/external_dependencies/openmpt-trunk/sounddsp/EQ.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* EQ.h
|
||||
* ----
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "openmpt/all/BuildSettings.hpp"
|
||||
|
||||
#include "openmpt/base/Types.hpp"
|
||||
#include "openmpt/soundbase/MixSample.hpp"
|
||||
|
||||
#include <array>
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
#ifndef NO_EQ
|
||||
|
||||
inline constexpr std::size_t MAX_EQ_CHANNELS = 4;
|
||||
inline constexpr std::size_t MAX_EQ_BANDS = 6;
|
||||
|
||||
struct EQBANDSTATE
|
||||
{
|
||||
float x1 = 0.0f;
|
||||
float x2 = 0.0f;
|
||||
float y1 = 0.0f;
|
||||
float y2 = 0.0f;
|
||||
};
|
||||
|
||||
struct EQBANDSETTINGS
|
||||
{
|
||||
float a0;
|
||||
float a1;
|
||||
float a2;
|
||||
float b1;
|
||||
float b2;
|
||||
float Gain;
|
||||
float CenterFrequency;
|
||||
};
|
||||
|
||||
class CEQ
|
||||
{
|
||||
private:
|
||||
std::array<std::array<EQBANDSTATE, MAX_EQ_BANDS>, MAX_EQ_CHANNELS> m_ChannelState;
|
||||
std::array<EQBANDSETTINGS, MAX_EQ_BANDS> m_Bands;
|
||||
template <typename TMixSample>
|
||||
void ProcessTemplate(TMixSample *frontBuffer, TMixSample *rearBuffer, std::size_t countFrames, std::size_t numChannels);
|
||||
public:
|
||||
CEQ();
|
||||
void Initialize(bool bReset, uint32 MixingFreq);
|
||||
void Process(MixSampleInt *frontBuffer, MixSampleInt *rearBuffer, std::size_t countFrames, std::size_t numChannels);
|
||||
void Process(MixSampleFloat *frontBuffer, MixSampleFloat *rearBuffer, std::size_t countFrames, std::size_t numChannels);
|
||||
void SetEQGains(const uint32 *pGains, const uint32 *pFreqs, bool bReset, uint32 MixingFreq);
|
||||
};
|
||||
|
||||
#endif // !NO_EQ
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
1040
Src/external_dependencies/openmpt-trunk/sounddsp/Reverb.cpp
Normal file
1040
Src/external_dependencies/openmpt-trunk/sounddsp/Reverb.cpp
Normal file
File diff suppressed because it is too large
Load diff
220
Src/external_dependencies/openmpt-trunk/sounddsp/Reverb.h
Normal file
220
Src/external_dependencies/openmpt-trunk/sounddsp/Reverb.h
Normal file
|
@ -0,0 +1,220 @@
|
|||
/*
|
||||
* Reverb.h
|
||||
* --------
|
||||
* Purpose: Mixing code for reverb.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "openmpt/all/BuildSettings.hpp"
|
||||
|
||||
#ifndef NO_REVERB
|
||||
|
||||
#include "../soundlib/Mixer.h" // For MIXBUFFERSIZE
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Reverberation
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SW Reverb structures
|
||||
//
|
||||
|
||||
// Length-1 (in samples) of the reflections delay buffer: 32K, 371ms@22kHz
|
||||
#define SNDMIX_REFLECTIONS_DELAY_MASK 0x1fff
|
||||
#define SNDMIX_PREDIFFUSION_DELAY_MASK 0x7f // 128 samples
|
||||
#define SNDMIX_REVERB_DELAY_MASK 0xfff // 4K samples (92ms @ 44kHz)
|
||||
|
||||
union LR16
|
||||
{
|
||||
struct { int16 l, r; } c;
|
||||
int32 lr;
|
||||
};
|
||||
|
||||
struct SWRvbReflection
|
||||
{
|
||||
uint32 Delay, DelayDest;
|
||||
LR16 Gains[2]; // g_ll, g_rl, g_lr, g_rr
|
||||
};
|
||||
|
||||
struct SWRvbRefDelay
|
||||
{
|
||||
uint32 nDelayPos, nPreDifPos, nRefOutPos;
|
||||
int32 lMasterGain; // reflections linear master gain
|
||||
LR16 nCoeffs; // room low-pass coefficients
|
||||
LR16 History; // room low-pass history
|
||||
LR16 nPreDifCoeffs; // prediffusion coefficients
|
||||
LR16 ReflectionsGain; // master reflections gain
|
||||
SWRvbReflection Reflections[8]; // Up to 8 SW Reflections
|
||||
LR16 RefDelayBuffer[SNDMIX_REFLECTIONS_DELAY_MASK + 1]; // reflections delay buffer
|
||||
LR16 PreDifBuffer[SNDMIX_PREDIFFUSION_DELAY_MASK + 1]; // pre-diffusion
|
||||
LR16 RefOut[SNDMIX_REVERB_DELAY_MASK + 1]; // stereo output of reflections
|
||||
};
|
||||
|
||||
struct SNDMIX_REVERB_PROPERTIES;
|
||||
|
||||
|
||||
// Late reverberation
|
||||
// Tank diffusers lengths
|
||||
#define RVBDIF1L_LEN (149*2) // 6.8ms
|
||||
#define RVBDIF1R_LEN (223*2) // 10.1ms
|
||||
#define RVBDIF2L_LEN (421*2) // 19.1ms
|
||||
#define RVBDIF2R_LEN (647*2) // 29.3ms
|
||||
// Tank delay lines lengths
|
||||
#define RVBDLY1L_LEN (683*2) // 30.9ms
|
||||
#define RVBDLY1R_LEN (811*2) // 36.7ms
|
||||
#define RVBDLY2L_LEN (773*2) // 35.1ms
|
||||
#define RVBDLY2R_LEN (1013*2) // 45.9ms
|
||||
// Tank delay lines mask
|
||||
#define RVBDLY_MASK 2047
|
||||
|
||||
// Min/Max reflections delay
|
||||
#define RVBMINREFDELAY 96 // 96 samples
|
||||
#define RVBMAXREFDELAY 7500 // 7500 samples
|
||||
// Min/Max reverb delay
|
||||
#define RVBMINRVBDELAY 128 // 256 samples (11.6ms @ 22kHz)
|
||||
#define RVBMAXRVBDELAY 3800 // 1900 samples (86ms @ 24kHz)
|
||||
|
||||
struct SWLateReverb
|
||||
{
|
||||
uint32 nReverbDelay; // Reverb delay (in samples)
|
||||
uint32 nDelayPos; // Delay line position
|
||||
LR16 nDifCoeffs[2]; // Reverb diffusion
|
||||
LR16 nDecayDC[2]; // Reverb DC decay
|
||||
LR16 nDecayLP[2]; // Reverb HF decay
|
||||
LR16 LPHistory[2]; // Low-pass history
|
||||
LR16 Dif2InGains[2]; // 2nd diffuser input gains
|
||||
LR16 RvbOutGains[2]; // 4x2 Reverb output gains
|
||||
int32 lMasterGain; // late reverb master gain
|
||||
int32 lDummyAlign;
|
||||
// Tank Delay lines
|
||||
LR16 Diffusion1[RVBDLY_MASK + 1]; // {dif1_l, dif1_r}
|
||||
LR16 Diffusion2[RVBDLY_MASK + 1]; // {dif2_l, dif2_r}
|
||||
LR16 Delay1[RVBDLY_MASK + 1]; // {dly1_l, dly1_r}
|
||||
LR16 Delay2[RVBDLY_MASK + 1]; // {dly2_l, dly2_r}
|
||||
};
|
||||
|
||||
#define ENVIRONMENT_NUMREFLECTIONS 8
|
||||
|
||||
struct EnvironmentReflection
|
||||
{
|
||||
int16 GainLL, GainRR, GainLR, GainRL; // +/- 32K scale
|
||||
uint32 Delay; // In samples
|
||||
};
|
||||
|
||||
struct EnvironmentReverb
|
||||
{
|
||||
int32 ReverbLevel; // Late reverb gain (mB)
|
||||
int32 ReflectionsLevel; // Master reflections gain (mB)
|
||||
int32 RoomHF; // Room gain HF (mB)
|
||||
uint32 ReverbDecay; // Reverb tank decay (0-7fff scale)
|
||||
int32 PreDiffusion; // Reverb pre-diffusion amount (+/- 32K scale)
|
||||
int32 TankDiffusion; // Reverb tank diffusion (+/- 32K scale)
|
||||
uint32 ReverbDelay; // Reverb delay (in samples)
|
||||
float flReverbDamping; // HF tank gain [0.0, 1.0]
|
||||
int32 ReverbDecaySamples; // Reverb decay time (in samples)
|
||||
EnvironmentReflection Reflections[ENVIRONMENT_NUMREFLECTIONS];
|
||||
};
|
||||
|
||||
|
||||
class CReverbSettings
|
||||
{
|
||||
public:
|
||||
uint32 m_nReverbDepth = 8; // 50%
|
||||
uint32 m_nReverbType = 0;
|
||||
};
|
||||
|
||||
|
||||
class CReverb
|
||||
{
|
||||
public:
|
||||
CReverbSettings m_Settings;
|
||||
|
||||
private:
|
||||
const SNDMIX_REVERB_PROPERTIES *m_currentPreset = nullptr;
|
||||
|
||||
bool gnReverbSend = false;
|
||||
|
||||
uint32 gnReverbSamples = 0;
|
||||
uint32 gnReverbDecaySamples = 0;
|
||||
|
||||
// Internal reverb state
|
||||
bool g_bLastInPresent = 0;
|
||||
bool g_bLastOutPresent = 0;
|
||||
int g_nLastRvbIn_xl = 0;
|
||||
int g_nLastRvbIn_xr = 0;
|
||||
int g_nLastRvbIn_yl = 0;
|
||||
int g_nLastRvbIn_yr = 0;
|
||||
int g_nLastRvbOut_xl = 0;
|
||||
int g_nLastRvbOut_xr = 0;
|
||||
int32 gnDCRRvb_Y1[2] = { 0, 0 };
|
||||
int32 gnDCRRvb_X1[2] = { 0, 0 };
|
||||
|
||||
// Reverb mix buffers
|
||||
SWRvbRefDelay g_RefDelay;
|
||||
SWLateReverb g_LateReverb;
|
||||
|
||||
public:
|
||||
CReverb();
|
||||
public:
|
||||
void Initialize(bool bReset, MixSampleInt &gnRvbROfsVol, MixSampleInt &gnRvbLOfsVol, uint32 MixingFreq);
|
||||
|
||||
// can be called multiple times or never (if no data is sent to reverb)
|
||||
void TouchReverbSendBuffer(MixSampleInt *MixReverbBuffer, MixSampleInt &gnRvbROfsVol, MixSampleInt &gnRvbLOfsVol, uint32 nSamples);
|
||||
|
||||
// call once after all data has been sent.
|
||||
void Process(MixSampleInt *MixSoundBuffer, MixSampleInt *MixReverbBuffer, MixSampleInt &gnRvbROfsVol, MixSampleInt &gnRvbLOfsVol, uint32 nSamples);
|
||||
|
||||
private:
|
||||
void Shutdown(MixSampleInt &gnRvbROfsVol, MixSampleInt &gnRvbLOfsVol);
|
||||
// Pre/Post resampling and filtering
|
||||
uint32 ReverbProcessPreFiltering1x(int32 *pWet, uint32 nSamples);
|
||||
uint32 ReverbProcessPreFiltering2x(int32 *pWet, uint32 nSamples);
|
||||
void ReverbProcessPostFiltering1x(const int32 *pRvb, int32 *pDry, uint32 nSamples);
|
||||
void ReverbProcessPostFiltering2x(const int32 *pRvb, int32 *pDry, uint32 nSamples);
|
||||
void ReverbDCRemoval(int32 *pBuffer, uint32 nSamples);
|
||||
void ReverbDryMix(int32 *pDry, int32 *pWet, int lDryVol, uint32 nSamples);
|
||||
// Process pre-diffusion and pre-delay
|
||||
static void ProcessPreDelay(SWRvbRefDelay *pPreDelay, const int32 *pIn, uint32 nSamples);
|
||||
// Process reflections
|
||||
static void ProcessReflections(SWRvbRefDelay *pPreDelay, LR16 *pRefOut, int32 *pMixOut, uint32 nSamples);
|
||||
// Process Late Reverb (SW Reflections): stereo reflections output, 32-bit reverb output, SW reverb gain
|
||||
static void ProcessLateReverb(SWLateReverb *pReverb, LR16 *pRefOut, int32 *pMixOut, uint32 nSamples);
|
||||
};
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// I3DL2 reverb presets
|
||||
//
|
||||
|
||||
struct SNDMIX_REVERB_PROPERTIES
|
||||
{
|
||||
int32 lRoom; // [-10000, 0] default: -10000 mB
|
||||
int32 lRoomHF; // [-10000, 0] default: 0 mB
|
||||
float flDecayTime; // [0.1, 20.0] default: 1.0 s
|
||||
float flDecayHFRatio; // [0.1, 2.0] default: 0.5
|
||||
int32 lReflections; // [-10000, 1000] default: -10000 mB
|
||||
float flReflectionsDelay; // [0.0, 0.3] default: 0.02 s
|
||||
int32 lReverb; // [-10000, 2000] default: -10000 mB
|
||||
float flReverbDelay; // [0.0, 0.1] default: 0.04 s
|
||||
float flDiffusion; // [0.0, 100.0] default: 100.0 %
|
||||
float flDensity; // [0.0, 100.0] default: 100.0 %
|
||||
};
|
||||
|
||||
enum : uint32
|
||||
{
|
||||
NUM_REVERBTYPES = 29
|
||||
};
|
||||
mpt::ustring GetReverbPresetName(uint32 preset);
|
||||
const SNDMIX_REVERB_PROPERTIES *GetReverbPreset(uint32 preset);
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
||||
|
||||
#endif // NO_REVERB
|
Loading…
Add table
Add a link
Reference in a new issue