93 lines
2.4 KiB
C++
93 lines
2.4 KiB
C++
// 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;
|
|
}
|
|
// Master fader (T15): sau limiter+clip, linear, khong re-clip — mirror
|
|
// WebAudio masterBus.output.gain (gain node cuoi cung sau mastering).
|
|
outL[i] = l * m_masterGain;
|
|
outR[i] = r * m_masterGain;
|
|
}
|
|
}
|
|
|
|
} // namespace sonicforge
|