changeset 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
files audioio/PhaseVocoderTimeStretcher.cpp audioio/PhaseVocoderTimeStretcher.h main/MainWindow.cpp
diffstat 3 files changed, 68 insertions(+), 21 deletions(-) [+]
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;
 }
--- a/audioio/PhaseVocoderTimeStretcher.h	Thu Sep 14 13:41:56 2006 +0000
+++ b/audioio/PhaseVocoderTimeStretcher.h	Thu Sep 14 16:08:23 2006 +0000
@@ -140,11 +140,15 @@
     Window<float> *m_analysisWindow;
     Window<float> *m_synthesisWindow;
 
+    int m_totalCount;
+    int m_transientCount;
+    int m_n2sum;
+
     float **m_prevPhase;
     float **m_prevAdjustedPhase;
 
     float *m_prevTransientMag;
-    int  m_prevTransientCount;
+    int  m_prevTransientScore;
     bool m_prevTransient;
 
     float *m_tempbuf;
--- a/main/MainWindow.cpp	Thu Sep 14 13:41:56 2006 +0000
+++ b/main/MainWindow.cpp	Thu Sep 14 16:08:23 2006 +0000
@@ -169,7 +169,12 @@
     m_playSharpen = new QCheckBox(frame);
     m_playSharpen->setToolTip(tr("Sharpen percussive transients"));
     m_playSharpen->setEnabled(false);
-    m_playSharpen->setChecked(false);
+
+    QSettings settings;
+    settings.beginGroup("MainWindow");
+    m_playSharpen->setChecked(settings.value("playsharpen", false).toBool());
+    settings.endGroup();
+
     connect(m_playSharpen, SIGNAL(clicked()),
             this, SLOT(playSharpenToggled()));
 
@@ -2869,19 +2874,19 @@
         1.0, 1.1, 1.2, 1.3, 1.5, 1.7, 2.0, 3.0, 4.0, 6.0, 10.0
     };
     float factor = factors[speed >= 10 ? speed - 10 : 10 - speed];
-//    int factor = 11 - speed;
-    if (speed > 10) factor = 1.0 / factor;
+
+    int pc = lrintf((factor - 1.0) * 100);
+
+    if (speed > 10) {
+        factor = 1.0 / factor;
+    }
+
     std::cerr << "factor = " << factor << std::endl;
-/*
-    int iinc = 128;
-    int oinc = lrintf(iinc * factor);
-    factor = (float(oinc) + 0.01) / iinc;
-    std::cerr << "corrected factor = " << factor << std::endl;
-*/
-    m_playSpeed->setToolTip(tr("Playback speed: %1")
-			    .arg(factor != 1 ?
-				 QString("1/%1").arg(factor) :
-				 tr("Full")));
+
+    m_playSpeed->setToolTip(tr("Playback speed: %1%2%")
+                            .arg(speed >= 10 ? "+" : "-")
+			    .arg(pc));
+
     m_playSharpen->setEnabled(speed != 10);
     bool sharpen = (speed != 10 && m_playSharpen->isChecked());
     m_playSource->setSlowdownFactor(factor, sharpen);
@@ -2890,6 +2895,11 @@
 void
 MainWindow::playSharpenToggled()
 {
+    QSettings settings;
+    settings.beginGroup("MainWindow");
+    settings.setValue("playsharpen", m_playSharpen->isChecked());
+    settings.endGroup();
+
     playSpeedChanged(m_playSpeed->value());
 }