# HG changeset patch # User Chris Cannam # Date 1406024879 -3600 # Node ID 4d48ab57fbcc9c18ef6c132668e4c475f1bbf948 # Parent 231e20ba316801f67eeb3ccc23477cd2045316b3 A global/local version that works approximately as well in first tests as the global-only version (r8) diff -r 231e20ba3168 -r 4d48ab57fbcc flattendynamics-ladspa.cpp --- a/flattendynamics-ladspa.cpp Tue Jul 22 08:11:45 2014 +0100 +++ b/flattendynamics-ladspa.cpp Tue Jul 22 11:27:59 2014 +0100 @@ -8,9 +8,10 @@ using std::cerr; using std::endl; -const float historySeconds = 2.f; -const float catchUpSeconds = 0.2f; -const float targetMaxRMS = 0.08f; +const float longTermSeconds = 4.f; +const float shortTermSeconds = 0.5f; +const float catchUpSeconds = 0.1f; +const float targetMaxRMS = 0.07f; const float maxGain = 20.f; const char *const @@ -80,9 +81,11 @@ m_histlen(0), m_histwrite(0), m_histread(0), - m_sumOfSquares(0.f), - m_rms(0.f), - m_maxRms(0.f), + m_sumOfSquaresLongTerm(0.f), + m_sumOfSquaresShortTerm(0.f), + m_rmsLongTerm(0.f), + m_rmsShortTerm(0.f), + m_maxRmsLongTerm(0.f), m_gain(1.f) { reset(); @@ -145,15 +148,20 @@ FlattenDynamics::reset() { delete[] m_history; - m_histlen = int(round(m_sampleRate * historySeconds)); + m_histlen = int(round(m_sampleRate * longTermSeconds)); if (m_histlen < 1) m_histlen = 1; m_history = new float[m_histlen]; + for (int i = 0; i < m_histlen; ++i) { + m_history[i] = 0.f; + } m_histwrite = 0; m_histread = 0; - m_sumOfSquares = 0.0; - m_rms = 0.f; - m_maxRms = 0.f; + m_sumOfSquaresLongTerm = 0.0; + m_sumOfSquaresShortTerm = 0.0; + m_rmsLongTerm = 0.f; + m_rmsShortTerm = 0.f; + m_maxRmsLongTerm = 0.f; m_gain = 1.f; } @@ -184,30 +192,33 @@ { updateRMS(f); - if (m_rms == 0.f) { + if (m_rmsLongTerm == 0.f) { return f; } - if (m_rms > m_maxRms) { - m_maxRms = m_rms; + if (m_rmsLongTerm > m_maxRmsLongTerm) { + m_maxRmsLongTerm = m_rmsLongTerm; } - float frac = m_rms / m_maxRms; + float frac = m_rmsShortTerm / m_maxRmsLongTerm; // push up toward top of 0,1 range - frac = pow(frac, 0.2); + frac = pow(frac, 0.5); float targetRMS = targetMaxRMS * frac; - float targetGain = targetRMS / m_rms; + float targetGain = targetRMS / m_rmsShortTerm; if (targetGain > maxGain) { targetGain = maxGain; } + float catchUpSamples = catchUpSeconds * m_sampleRate; // asymptotic, could improve? m_gain = m_gain + (targetGain - m_gain) / catchUpSamples; + if (fabsf(f) * m_gain > 1.f) { m_gain = 1.f / fabsf(f); } + // cerr << "target gain = " << targetGain << ", gain = " << m_gain << endl; return f * m_gain; } @@ -217,26 +228,36 @@ { int nextWrite = (m_histwrite + 1) % m_histlen; - float lose; + float loseLongTerm = 0.f; + float loseShortTerm = 0.f; if (nextWrite == m_histread) { // full - lose = m_history[m_histread]; + loseLongTerm = m_history[m_histread]; m_histread = (m_histread + 1) % m_histlen; - } else { - // not full - lose = 0.f; } + int shortTermLength = round(shortTermSeconds * m_sampleRate); + int shortTermLoseIndex = nextWrite - shortTermLength; + if (shortTermLoseIndex < 0) { + shortTermLoseIndex += m_histlen; + } + // This depends on history being zero-initialised, to be correct at start: + loseShortTerm = m_history[shortTermLoseIndex]; + m_history[m_histwrite] = f; m_histwrite = nextWrite; int fill = (m_histwrite - m_histread + m_histlen) % m_histlen; - m_sumOfSquares -= lose * lose; - m_sumOfSquares += f * f; + m_sumOfSquaresLongTerm -= loseLongTerm * loseLongTerm; + m_sumOfSquaresLongTerm += f * f; - m_rms = sqrt(m_sumOfSquares / fill); + m_sumOfSquaresShortTerm -= loseShortTerm * loseShortTerm; + m_sumOfSquaresShortTerm += f * f; + + m_rmsLongTerm = sqrt(m_sumOfSquaresLongTerm / fill); + m_rmsShortTerm = sqrt(m_sumOfSquaresShortTerm / shortTermLength); // cerr << "rms = " << m_rms << " (from " << fill << " samples of " << m_histlen << ", latest " << f << ")" << endl; } diff -r 231e20ba3168 -r 4d48ab57fbcc flattendynamics-ladspa.h --- a/flattendynamics-ladspa.h Tue Jul 22 08:11:45 2014 +0100 +++ b/flattendynamics-ladspa.h Tue Jul 22 11:27:59 2014 +0100 @@ -50,9 +50,14 @@ int m_histwrite; int m_histread; - double m_sumOfSquares; - float m_rms; - float m_maxRms; + double m_sumOfSquaresLongTerm; + double m_sumOfSquaresShortTerm; + + float m_rmsLongTerm; + float m_rmsShortTerm; + + float m_maxRmsLongTerm; + float m_gain; };