changeset 26:d88d117e0c34

* Add mono timestretch toggle button; some more work on getting blocksize etc parameters through to plugins
author Chris Cannam
date Mon, 18 Sep 2006 16:43:17 +0000
parents e74f508db18c
children 61259228d029
files audioio/AudioCallbackPlaySource.cpp audioio/AudioCallbackPlaySource.h audioio/PhaseVocoderTimeStretcher.cpp audioio/PhaseVocoderTimeStretcher.h icons/mono.png icons/sharpen.png icons/stereo.png main/MainWindow.cpp main/MainWindow.h sonic-visualiser.qrc transform/FeatureExtractionPluginTransform.cpp transform/FeatureExtractionPluginTransform.h transform/RealTimePluginTransform.cpp transform/RealTimePluginTransform.h transform/TransformFactory.cpp transform/TransformFactory.h
diffstat 16 files changed, 154 insertions(+), 48 deletions(-) [+]
line wrap: on
line diff
--- a/audioio/AudioCallbackPlaySource.cpp	Fri Sep 15 15:35:06 2006 +0000
+++ b/audioio/AudioCallbackPlaySource.cpp	Mon Sep 18 16:43:17 2006 +0000
@@ -588,34 +588,41 @@
 }
 
 void
-AudioCallbackPlaySource::setSlowdownFactor(float factor, bool sharpen)
+AudioCallbackPlaySource::setTimeStretch(float factor, bool sharpen, bool mono)
 {
     // Avoid locks -- create, assign, mark old one for scavenging
     // later (as a call to getSourceSamples may still be using it)
 
     PhaseVocoderTimeStretcher *existingStretcher = m_timeStretcher;
 
+    size_t channels = getTargetChannelCount();
+    if (mono) channels = 1;
+
     if (existingStretcher &&
         existingStretcher->getRatio() == factor &&
-        existingStretcher->getSharpening() == sharpen) {
+        existingStretcher->getSharpening() == sharpen &&
+        existingStretcher->getChannelCount() == channels) {
 	return;
     }
 
     if (factor != 1) {
 
         if (existingStretcher &&
-            existingStretcher->getSharpening() == sharpen) {
+            existingStretcher->getSharpening() == sharpen &&
+            existingStretcher->getChannelCount() == channels) {
             existingStretcher->setRatio(factor);
             return;
         }
 
 	PhaseVocoderTimeStretcher *newStretcher = new PhaseVocoderTimeStretcher
 	    (getTargetSampleRate(),
-             getTargetChannelCount(),
+             channels,
              factor,
              sharpen,
              lrintf(getTargetBlockSize() / factor));
+
 	m_timeStretcher = newStretcher;
+
     } else {
 	m_timeStretcher = 0;
     }
@@ -624,7 +631,7 @@
 	m_timeStretcherScavenger.claim(existingStretcher);
     }
 }
-	    
+
 size_t
 AudioCallbackPlaySource::getSourceSamples(size_t count, float **buffer)
 {
@@ -676,6 +683,9 @@
 
 //            std::cout << "ratio = " << ratio << std::endl;
 
+    size_t channels = getTargetChannelCount();
+    bool mix = (channels > 1 && ts->getChannelCount() == 1);
+
     size_t available;
 
     while ((available = ts->getAvailableOutputSamples()) < count) {
@@ -684,18 +694,30 @@
         reqd = std::max(reqd, ts->getRequiredInputSamples());
         if (reqd == 0) reqd = 1;
                 
-        size_t channels = getTargetChannelCount();
-
         float *ib[channels];
 
         size_t got = reqd;
 
-        for (size_t c = 0; c < channels; ++c) {
-            ib[c] = new float[reqd]; //!!! fix -- this is a rt function
-            RingBuffer<float> *rb = getReadRingBuffer(c);
-            if (rb) {
-                size_t gotHere = rb->read(ib[c], got);
-                if (gotHere < got) got = gotHere;
+        if (mix) {
+            for (size_t c = 0; c < channels; ++c) {
+                if (c == 0) ib[c] = new float[reqd]; //!!! fix -- this is a rt function
+                else ib[c] = 0;
+                RingBuffer<float> *rb = getReadRingBuffer(c);
+                if (rb) {
+                    size_t gotHere;
+                    if (c > 0) gotHere = rb->readAdding(ib[0], got);
+                    else gotHere = rb->read(ib[0], got);
+                    if (gotHere < got) got = gotHere;
+                }
+            }
+        } else {
+            for (size_t c = 0; c < channels; ++c) {
+                ib[c] = new float[reqd]; //!!! fix -- this is a rt function
+                RingBuffer<float> *rb = getReadRingBuffer(c);
+                if (rb) {
+                    size_t gotHere = rb->read(ib[c], got);
+                    if (gotHere < got) got = gotHere;
+                }
             }
         }
 
@@ -720,6 +742,17 @@
 
     ts->getOutput(buffer, count);
 
+    if (mix) {
+        for (size_t c = 1; c < channels; ++c) {
+            for (size_t i = 0; i < count; ++i) {
+                buffer[c][i] = buffer[0][i] / channels;
+            }
+        }
+        for (size_t i = 0; i < count; ++i) {
+            buffer[0][i] /= channels;
+        }
+    }
+
     m_condition.wakeAll();
 
     return count;
--- a/audioio/AudioCallbackPlaySource.h	Fri Sep 15 15:35:06 2006 +0000
+++ b/audioio/AudioCallbackPlaySource.h	Mon Sep 18 16:43:17 2006 +0000
@@ -177,7 +177,7 @@
      */
     size_t getSourceSamples(size_t count, float **buffer);
 
-    void setSlowdownFactor(float factor, bool sharpen);
+    void setTimeStretch(float factor, bool sharpen, bool mono);
 
 signals:
     void modelReplaced();
--- a/audioio/PhaseVocoderTimeStretcher.cpp	Fri Sep 15 15:35:06 2006 +0000
+++ b/audioio/PhaseVocoderTimeStretcher.cpp	Mon Sep 18 16:43:17 2006 +0000
@@ -39,11 +39,6 @@
 {
     initialise();
 
-    std::cerr << "PhaseVocoderTimeStretcher: channels = " << m_channels
-              << ", ratio = " << m_ratio
-              << ", n1 = " << m_n1 << ", n2 = " << m_n2 << ", wlen = "
-              << m_wlen << ", max = " << maxProcessInputBlockSize
-              << ", outbuflen = " << m_outbuf[0]->getSize() << std::endl;
 }
 
 PhaseVocoderTimeStretcher::~PhaseVocoderTimeStretcher()
@@ -166,6 +161,17 @@
     }
 
     m_transientThreshold = m_wlen / 4.5;
+
+    m_totalCount = 0;
+    m_transientCount = 0;
+    m_n2sum = 0;
+
+
+    std::cerr << "PhaseVocoderTimeStretcher: channels = " << m_channels
+              << ", ratio = " << m_ratio
+              << ", n1 = " << m_n1 << ", n2 = " << m_n2 << ", wlen = "
+              << m_wlen << ", max = " << m_maxProcessInputBlockSize << std::endl;
+//              << ", outbuflen = " << m_outbuf[0]->getSize() << std::endl;
 }
 
 void
@@ -516,10 +522,17 @@
 
     bool isTransient = false;
 
-    if (count > m_transientThreshold &&
-        count > m_prevTransientScore * 1.2) {
+//    if (count > m_transientThreshold &&
+//        count > m_prevTransientScore * 1.2) {
+    if (count > m_prevTransientScore &&
+        count > m_transientThreshold &&
+        count - m_prevTransientScore > m_wlen / 20) {
         isTransient = true;
-        std::cerr << "isTransient (count = " << count << ", prev = " << m_prevTransientScore << ")" << std::endl;
+
+
+        std::cerr << "isTransient (count = " << count << ", prev = " << m_prevTransientScore << ", diff = " << count - m_prevTransientScore << ", ratio = " << (m_totalCount > 0 ? (float (m_n2sum) / float(m_totalCount * m_n1)) : 1.f) << ", ideal = " << m_ratio << ")" << std::endl;
+//    } else {
+//        std::cerr << " !transient (count = " << count << ", prev = " << m_prevTransientScore << ", diff = " << count - m_prevTransientScore << ")" << std::endl;
     }
 
     m_prevTransientScore = count;
--- a/audioio/PhaseVocoderTimeStretcher.h	Fri Sep 15 15:35:06 2006 +0000
+++ b/audioio/PhaseVocoderTimeStretcher.h	Mon Sep 18 16:43:17 2006 +0000
@@ -119,6 +119,11 @@
     bool getSharpening() const { return m_sharpen; }
 
     /**
+     * Return the number of channels for this time stretcher.
+     */
+    size_t getChannelCount() const { return m_channels; }
+
+    /**
      * Get the latency added by the time stretcher, in sample frames.
      * This will be exact if transient sharpening is off, or approximate
      * if it is on.
Binary file icons/mono.png has changed
Binary file icons/sharpen.png has changed
Binary file icons/stereo.png has changed
--- a/main/MainWindow.cpp	Fri Sep 15 15:35:06 2006 +0000
+++ b/main/MainWindow.cpp	Mon Sep 18 16:43:17 2006 +0000
@@ -166,23 +166,38 @@
     connect(m_playSpeed, SIGNAL(valueChanged(int)),
 	    this, SLOT(playSpeedChanged(int)));
 
-    m_playSharpen = new QCheckBox(frame);
+    m_playSharpen = new QPushButton(frame);
     m_playSharpen->setToolTip(tr("Sharpen percussive transients"));
+    m_playSharpen->setFixedSize(20, 20);
+//    m_playSharpen->setFlat(true);
     m_playSharpen->setEnabled(false);
+    m_playSharpen->setCheckable(true);
+    m_playSharpen->setChecked(false);
+    m_playSharpen->setIcon(QIcon(":icons/sharpen.png"));
+    connect(m_playSharpen, SIGNAL(clicked()), this, SLOT(playSharpenToggled()));
+
+    m_playMono = new QPushButton(frame);
+    m_playMono->setToolTip(tr("Run time stretcher in mono only"));
+    m_playMono->setFixedSize(20, 20);
+//    m_playMono->setFlat(true);
+    m_playMono->setEnabled(false);
+    m_playMono->setCheckable(true);
+    m_playMono->setChecked(false);
+    m_playMono->setIcon(QIcon(":icons/mono.png"));
+    connect(m_playMono, SIGNAL(clicked()), this, SLOT(playMonoToggled()));
 
     QSettings settings;
     settings.beginGroup("MainWindow");
     m_playSharpen->setChecked(settings.value("playsharpen", true).toBool());
+    m_playMono->setChecked(settings.value("playmono", false).toBool());
     settings.endGroup();
 
-    connect(m_playSharpen, SIGNAL(clicked()),
-            this, SLOT(playSharpenToggled()));
-
-    layout->addWidget(m_paneStack, 0, 0, 1, 4);
+    layout->addWidget(m_paneStack, 0, 0, 1, 5);
     layout->addWidget(m_panner, 1, 0);
     layout->addWidget(m_fader, 1, 1);
     layout->addWidget(m_playSpeed, 1, 2);
     layout->addWidget(m_playSharpen, 1, 3);
+    layout->addWidget(m_playMono, 1, 4);
 
     layout->setColumnStretch(0, 10);
 
@@ -2870,11 +2885,6 @@
 void
 MainWindow::playSpeedChanged(int speed)
 {
-//    static float factors[] = {
-//        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];
-
     bool slow = false;
     bool something = false;
     float factor;
@@ -2907,8 +2917,10 @@
 			    .arg(pc));
 
     m_playSharpen->setEnabled(something);
+    m_playMono->setEnabled(something);
     bool sharpen = (something && m_playSharpen->isChecked());
-    m_playSource->setSlowdownFactor(factor, sharpen);
+    bool mono = (something && m_playMono->isChecked());
+    m_playSource->setTimeStretch(factor, sharpen, mono);
 }
 
 void
@@ -2923,6 +2935,17 @@
 }
 
 void
+MainWindow::playMonoToggled()
+{
+    QSettings settings;
+    settings.beginGroup("MainWindow");
+    settings.setValue("playmono", m_playMono->isChecked());
+    settings.endGroup();
+
+    playSpeedChanged(m_playSpeed->value());
+}    
+
+void
 MainWindow::outputLevelsChanged(float left, float right)
 {
     m_fader->setPeakLeft(left);
--- a/main/MainWindow.h	Fri Sep 15 15:35:06 2006 +0000
+++ b/main/MainWindow.h	Mon Sep 18 16:43:17 2006 +0000
@@ -46,6 +46,7 @@
 class QLabel;
 class QCheckBox;
 class PreferencesDialog;
+class QPushButton;
 
 
 class MainWindow : public QMainWindow
@@ -141,6 +142,7 @@
     void playSelectionToggled();
     void playSpeedChanged(int);
     void playSharpenToggled();
+    void playMonoToggled();
     void sampleRateMismatch(size_t, size_t, bool);
 
     void outputLevelsChanged(float, float);
@@ -205,7 +207,8 @@
     Panner                  *m_panner;
     Fader                   *m_fader;
     AudioDial               *m_playSpeed;
-    QCheckBox               *m_playSharpen;
+    QPushButton             *m_playSharpen;
+    QPushButton             *m_playMono;
     WaveformLayer           *m_panLayer;
     Layer                   *m_timeRulerLayer;
 
--- a/sonic-visualiser.qrc	Fri Sep 15 15:35:06 2006 +0000
+++ b/sonic-visualiser.qrc	Mon Sep 18 16:43:17 2006 +0000
@@ -48,6 +48,9 @@
     <file>icons/editcut.png</file>
     <file>icons/editcopy.png</file>
     <file>icons/editpaste.png</file>
+    <file>icons/mono.png</file>
+    <file>icons/stereo.png</file>
+    <file>icons/sharpen.png</file>
     <file>samples/bass.wav</file>
     <file>samples/beep.wav</file>
     <file>samples/bounce.wav</file>
--- a/transform/FeatureExtractionPluginTransform.cpp	Fri Sep 15 15:35:06 2006 +0000
+++ b/transform/FeatureExtractionPluginTransform.cpp	Mon Sep 18 16:43:17 2006 +0000
@@ -36,12 +36,16 @@
 								   QString pluginId,
                                                                    int channel,
                                                                    QString configurationXml,
-								   QString outputName) :
+								   QString outputName,
+                                                                   size_t stepSize,
+                                                                   size_t blockSize,
+                                                                   WindowType windowType) :
     Transform(inputModel),
     m_plugin(0),
     m_channel(channel),
     m_stepSize(0),
     m_blockSize(0),
+    m_windowType(windowType),
     m_descriptor(0),
     m_outputFeatureNo(0)
 {
@@ -68,11 +72,17 @@
         PluginXml(m_plugin).setParametersFromXml(configurationXml);
     }
 
-    m_blockSize = m_plugin->getPreferredBlockSize();
-    m_stepSize = m_plugin->getPreferredStepSize();
+    if (m_blockSize == 0) m_blockSize = m_plugin->getPreferredBlockSize();
+    if (m_stepSize == 0) m_stepSize = m_plugin->getPreferredStepSize();
 
-    if (m_blockSize == 0) m_blockSize = 1024; //!!! todo: ask user
-    if (m_stepSize == 0) m_stepSize = m_blockSize; //!!! likewise
+    if (m_blockSize == 0) m_blockSize = 1024;
+    if (m_stepSize == 0) {
+        if (m_plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain) {
+            m_stepSize = m_blockSize / 2;
+        } else {
+            m_stepSize = m_blockSize;
+        }
+    }
 
     DenseTimeValueModel *input = getInput();
     if (!input) return;
@@ -250,7 +260,7 @@
             fftModels.push_back(new FFTModel
                                   (getInput(),
                                    channelCount == 1 ? m_channel : ch,
-                                   HanningWindow,
+                                   m_windowType,
                                    m_blockSize,
                                    m_stepSize,
                                    m_blockSize,
--- a/transform/FeatureExtractionPluginTransform.h	Fri Sep 15 15:35:06 2006 +0000
+++ b/transform/FeatureExtractionPluginTransform.h	Mon Sep 18 16:43:17 2006 +0000
@@ -18,6 +18,8 @@
 
 #include "Transform.h"
 
+#include "base/Window.h"
+
 #include "vamp-sdk/Plugin.h"
 
 class DenseTimeValueModel;
@@ -29,7 +31,10 @@
 				     QString plugin,
                                      int channel,
                                      QString configurationXml = "",
-				     QString outputName = "");
+				     QString outputName = "",
+                                     size_t stepSize = 0,
+                                     size_t blockSize = 0,
+                                     WindowType windowType = HanningWindow);
     virtual ~FeatureExtractionPluginTransform();
 
 protected:
@@ -39,6 +44,7 @@
     int m_channel;
     size_t m_stepSize;
     size_t m_blockSize;
+    WindowType m_windowType;
     Vamp::Plugin::OutputDescriptor *m_descriptor;
     int m_outputFeatureNo;
 
--- a/transform/RealTimePluginTransform.cpp	Fri Sep 15 15:35:06 2006 +0000
+++ b/transform/RealTimePluginTransform.cpp	Mon Sep 18 16:43:17 2006 +0000
@@ -31,12 +31,16 @@
                                                  int channel,
                                                  QString configurationXml,
                                                  QString units,
-                                                 int output) :
+                                                 int output,
+                                                 size_t blockSize) :
     Transform(inputModel),
     m_plugin(0),
     m_channel(channel),
-    m_outputNo(output)
+    m_outputNo(output),
+    m_blockSize(blockSize)
 {
+    if (!m_blockSize) m_blockSize = 1024;
+
     std::cerr << "RealTimePluginTransform::RealTimePluginTransform: plugin " << pluginId.toStdString() << ", output " << output << std::endl;
 
     RealTimePluginFactory *factory =
@@ -52,7 +56,7 @@
     if (!input) return;
 
     m_plugin = factory->instantiatePlugin(pluginId, 0, 0, m_input->getSampleRate(),
-                                          1024, //!!! wants to be configurable
+                                          m_blockSize,
                                           input->getChannelCount());
 
     if (!m_plugin) {
@@ -71,8 +75,7 @@
     }
 	
     SparseTimeValueModel *model = new SparseTimeValueModel
-        (input->getSampleRate(), 1024, //!!!
-         0.0, 0.0, false);
+        (input->getSampleRate(), m_blockSize, 0.0, 0.0, false);
 
     if (units != "") model->setScaleUnits(units);
 
--- a/transform/RealTimePluginTransform.h	Fri Sep 15 15:35:06 2006 +0000
+++ b/transform/RealTimePluginTransform.h	Mon Sep 18 16:43:17 2006 +0000
@@ -29,7 +29,8 @@
                             int channel,
 			    QString configurationXml = "",
                             QString units = "",
-			    int output = 0);
+			    int output = 0,
+                            size_t blockSize = 0);
     virtual ~RealTimePluginTransform();
 
 protected:
@@ -38,6 +39,7 @@
     RealTimePluginInstance *m_plugin;
     int m_channel;
     int m_outputNo;
+    size_t m_blockSize;
 
     // just casts
     DenseTimeValueModel *getInput();
--- a/transform/TransformFactory.cpp	Fri Sep 15 15:35:06 2006 +0000
+++ b/transform/TransformFactory.cpp	Mon Sep 18 16:43:17 2006 +0000
@@ -413,6 +413,10 @@
         }
         configurationXml = PluginXml(plugin).toXmlString();
         channel = dialog->getChannel();
+
+        //!!! where now for step size, block size, etc?
+//        dialog->getProcessingParameters(stepSize, blockSize, windowType);
+
         delete dialog;
         delete plugin;
     }
--- a/transform/TransformFactory.h	Fri Sep 15 15:35:06 2006 +0000
+++ b/transform/TransformFactory.h	Mon Sep 18 16:43:17 2006 +0000
@@ -66,7 +66,8 @@
      * asking the user, most likely).  Returns true if the transform
      * is acceptable, false if the operation should be cancelled.
      */
-    bool getConfigurationForTransform(TransformName name, Model *inputModel,
+    bool getConfigurationForTransform(TransformName name,
+                                      Model *inputModel,
                                       int &channel,
                                       QString &configurationXml);