diff audioio/PhaseVocoderTimeStretcher.cpp @ 21:7da85e0b85e9

* Add some internal feedback to the time stretcher to try to make it maintain tempo within variable timestretching situations -- not ideal but perhaps better than nothing. * Better tooltip text for play speeed control; make play sharpening control remember its last state
author Chris Cannam
date Thu, 14 Sep 2006 16:08:23 +0000
parents e125f0dde7a3
children 80126455d169
line wrap: on
line diff
--- a/audioio/PhaseVocoderTimeStretcher.cpp	Thu Sep 14 13:41:56 2006 +0000
+++ b/audioio/PhaseVocoderTimeStretcher.cpp	Thu Sep 14 16:08:23 2006 +0000
@@ -26,10 +26,17 @@
                                                      size_t maxProcessInputBlockSize) :
     m_channels(channels),
     m_ratio(ratio),
-    m_sharpen(sharpen)
+    m_sharpen(sharpen),
+    m_totalCount(0),
+    m_transientCount(0),
+    m_n2sum(0)
 {
     m_wlen = 1024;
 
+    //!!! In transient sharpening mode, we need to pick the window
+    //length so as to be more or less fixed in audio duration (i.e. we
+    //need to know the sample rate)
+
     if (ratio < 1) {
         if (ratio < 0.4) {
             m_n1 = 1024;
@@ -40,7 +47,6 @@
             m_n1 = 256;
         }
         if (m_sharpen) {
-//            m_n1 /= 2;
             m_wlen = 2048;
         }
         m_n2 = m_n1 * ratio;
@@ -55,7 +61,6 @@
             m_n2 = 256;
         }
         if (m_sharpen) {
-//            m_n2 /= 2;
             if (m_wlen < 2048) m_wlen = 2048;
         }
         m_n1 = m_n2 / ratio;
@@ -68,7 +73,7 @@
     m_prevAdjustedPhase = new float *[m_channels];
 
     m_prevTransientMag = (float *)fftwf_malloc(sizeof(float) * (m_wlen / 2 + 1));
-    m_prevTransientCount = 0;
+    m_prevTransientScore = 0;
     m_prevTransient = false;
 
     m_tempbuf = (float *)fftwf_malloc(sizeof(float) * m_wlen);
@@ -249,6 +254,29 @@
                 n2 = m_n1;
             }
 
+            ++m_totalCount;
+            if (transient) ++m_transientCount;
+            m_n2sum += n2;
+
+//            std::cerr << "ratio for last 10: " <<last10num << "/" << (10 * m_n1) << " = " << float(last10num) / float(10 * m_n1) << " (should be " << m_ratio << ")" << std::endl;
+            
+            if (m_totalCount > 50 && m_transientCount < m_totalCount) {
+
+                int fixed = lrintf(m_transientCount * m_n1);
+                int squashy = m_n2sum - fixed;
+
+                int idealTotal = lrintf(m_totalCount * m_n1 * m_ratio);
+                int idealSquashy = idealTotal - fixed;
+
+                int squashyCount = m_totalCount - m_transientCount;
+                
+                n2 = lrintf(idealSquashy / squashyCount);
+
+                if (n2 != m_n2) {
+                    std::cerr << m_n2 << " -> " << n2 << std::endl;
+                }
+            }
+
             for (size_t c = 0; c < m_channels; ++c) {
 
                 synthesiseBlock(c, m_mashbuf[c],
@@ -287,6 +315,8 @@
 	    for (size_t i = m_wlen - n2; i < m_wlen; ++i) {
                 m_modulationbuf[i] = 0.0f;
 	    }
+
+            if (!transient) m_n2 = n2;
 	}
 
 
@@ -298,6 +328,9 @@
 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER
     std::cerr << "PhaseVocoderTimeStretcher::putInput returning" << std::endl;
 #endif
+
+//    std::cerr << "ratio: nominal: " << getRatio() << " actual: "
+//              << m_total2 << "/" << m_total1 << " = " << float(m_total2) / float(m_total1) << " ideal: " << m_ratio << std::endl;
 }
 
 size_t
@@ -385,12 +418,12 @@
     bool isTransient = false;
 
     if (count > m_wlen / 4.5 && //!!!
-        count > m_prevTransientCount * 1.2) {
+        count > m_prevTransientScore * 1.2) {
         isTransient = true;
-        std::cerr << "isTransient (count = " << count << ", prev = " << m_prevTransientCount << ")" << std::endl;
+        std::cerr << "isTransient (count = " << count << ", prev = " << m_prevTransientScore << ")" << std::endl;
     }
 
-    m_prevTransientCount = count;
+    m_prevTransientScore = count;
 
     return isTransient;
 }