T13: NativeMixer mirror server pipeline (track gain/pan constant-power + brickwall limiter tanh, wired VST2/VST3 bridge, golden test 0.0001dB)
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
// NativeMixer.cpp — xem NativeMixer.h cho cong thuc mirror.
|
||||
#include "NativeMixer.h"
|
||||
|
||||
namespace sonicforge {
|
||||
|
||||
namespace {
|
||||
|
||||
// Mirror _clamp(v, lo, hi, default) cua mastering_engine.py: NaN -> default.
|
||||
float clampDb (float v, float lo, float hi, float def)
|
||||
{
|
||||
if (!(v == v)) // NaN
|
||||
return def;
|
||||
if (v < lo)
|
||||
return lo;
|
||||
if (v > hi)
|
||||
return hi;
|
||||
return v;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TrackGainPan TrackGainPan::fromDbPan (float gainDb, float pan)
|
||||
{
|
||||
TrackGainPan t;
|
||||
t.gainLin = std::pow (10.0f, gainDb / 20.0f);
|
||||
float p = pan;
|
||||
if (p < -1.0f)
|
||||
p = -1.0f;
|
||||
else if (p > 1.0f)
|
||||
p = 1.0f;
|
||||
if (p == 0.0f)
|
||||
{
|
||||
t.panL = 1.0f;
|
||||
t.panR = 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
const float theta = ((p + 1.0f) / 2.0f) * (3.14159265358979323846f / 2.0f);
|
||||
t.panL = std::cos (theta);
|
||||
t.panR = std::sin (theta);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
void NativeMixer::setLimiter (bool active, float thresholdDb)
|
||||
{
|
||||
m_limActive = active;
|
||||
if (!active)
|
||||
{
|
||||
m_limK = 1.0f;
|
||||
m_limTk = 1.0f;
|
||||
return;
|
||||
}
|
||||
const float t = clampDb (thresholdDb, -24.0f, 0.0f, -1.0f);
|
||||
const float tLin = std::pow (10.0f, t / 20.0f);
|
||||
m_limK = 1.0f / (tLin > 0.02f ? tLin : 0.02f);
|
||||
m_limTk = std::tanh (m_limK);
|
||||
}
|
||||
|
||||
void NativeMixer::processInPlace (float* outL, float* outR, int32 frames) const
|
||||
{
|
||||
if (!outL || !outR || frames <= 0)
|
||||
return;
|
||||
const float gl = m_track.gainLin * m_track.panL;
|
||||
const float gr = m_track.gainLin * m_track.panR;
|
||||
for (int32 i = 0; i < frames; ++i)
|
||||
{
|
||||
float l = outL[i] * gl;
|
||||
float r = outR[i] * gr;
|
||||
if (m_limActive)
|
||||
{
|
||||
l = std::tanh (l * m_limK) / m_limTk;
|
||||
r = std::tanh (r * m_limK) / m_limTk;
|
||||
// Hard clip [-1,1] — mirror render_project sau apply_mastering
|
||||
// (chi khi mastering on; limiter off => khong clip).
|
||||
if (l > 1.0f)
|
||||
l = 1.0f;
|
||||
else if (l < -1.0f)
|
||||
l = -1.0f;
|
||||
if (r > 1.0f)
|
||||
r = 1.0f;
|
||||
else if (r < -1.0f)
|
||||
r = -1.0f;
|
||||
}
|
||||
outL[i] = l;
|
||||
outR[i] = r;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sonicforge
|
||||
Reference in New Issue
Block a user