changeset 7:4d48ab57fbcc

A global/local version that works approximately as well in first tests as the global-only version (r8)
author Chris Cannam
date Tue, 22 Jul 2014 11:27:59 +0100
parents 231e20ba3168
children 355fb9ea3888
files flattendynamics-ladspa.cpp flattendynamics-ladspa.h
diffstat 2 files changed, 53 insertions(+), 27 deletions(-) [+]
line wrap: on
line diff
--- 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;
 }
 
--- 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;
 };