changeset 118:b4110b17bca8

* Fix #1672407 confused by plugin-named files in cwd (or home?) * Fix #1491848 crash when loading new file while transform plugin runs * Fix #1502287 Background remains black after spectrogram layer deleted * Fix #1604477 Replacing the main audio file silences secondary audio file * Fix failure to initialise property box layout to last preference on startup * Fix resample/wrong-rate display in Pane, ensure that right rate is chosen if all current models have an acceptable rate even if previous main model had a different one * Fix "global zoom" broken in previous commit * Some fixes to spectrogram cache area updating (makes spectrogram appear more quickly, previously it had a tendency to refresh with empty space) * Fixes to colour 3d plot normalization
author Chris Cannam
date Thu, 08 Mar 2007 16:53:08 +0000
parents 8089a394829a
children a7b88d07a836
files audioio/AudioCallbackPlaySource.cpp audioio/AudioCallbackPlaySource.h audioio/AudioGenerator.cpp document/Document.cpp document/SVFileReader.cpp main/MainWindow.cpp main/MainWindow.h main/main.cpp transform/FeatureExtractionPluginTransform.cpp transform/RealTimePluginTransform.cpp transform/Transform.cpp transform/Transform.h transform/TransformFactory.cpp transform/TransformFactory.h
diffstat 14 files changed, 111 insertions(+), 43 deletions(-) [+]
line wrap: on
line diff
--- a/audioio/AudioCallbackPlaySource.cpp	Wed Mar 07 18:00:49 2007 +0000
+++ b/audioio/AudioCallbackPlaySource.cpp	Thu Mar 08 16:53:08 2007 +0000
@@ -126,7 +126,9 @@
 	m_sourceChannelCount = modelChannels;
     }
 
-//    std::cout << "Adding model with " << modelChannels << " channels " << std::endl;
+#ifdef DEBUG_AUDIO_PLAY_SOURCE
+    std::cout << "Adding model with " << modelChannels << " channels " << std::endl;
+#endif
 
     if (m_sourceSampleRate == 0) {
 
@@ -144,7 +146,10 @@
 
             for (std::set<Model *>::const_iterator i = m_models.begin();
                  i != m_models.end(); ++i) {
-                if (*i != dtvm && dynamic_cast<DenseTimeValueModel *>(*i)) {
+                DenseTimeValueModel *dtvm2 =
+                    dynamic_cast<DenseTimeValueModel *>(*i);
+                if (dtvm2 && dtvm2 != dtvm &&
+                    dtvm2->getSampleRate() != model->getSampleRate()) {
                     std::cerr << "AudioCallbackPlaySource::addModel: Conflicting dense time-value model " << *i << " found" << std::endl;
                     conflicting = true;
                     break;
@@ -195,7 +200,7 @@
     }
 
 #ifdef DEBUG_AUDIO_PLAY_SOURCE
-    std::cout << "AudioCallbackPlaySource::addModel: emitting modelReplaced" << std::endl;
+    std::cout << "AudioCallbackPlaySource::addModel: now have " << m_models.size() << " model(s) -- emitting modelReplaced" << std::endl;
 #endif
 
     if (buffersChanged || srChanged) {
@@ -210,6 +215,10 @@
 {
     m_mutex.lock();
 
+#ifdef DEBUG_AUDIO_PLAY_SOURCE
+    std::cout << "AudioCallbackPlaySource::removeModel(" << model << ")" << std::endl;
+#endif
+
     m_models.erase(model);
 
     if (m_models.empty()) {
@@ -243,6 +252,10 @@
 {
     m_mutex.lock();
 
+#ifdef DEBUG_AUDIO_PLAY_SOURCE
+    std::cout << "AudioCallbackPlaySource::clearModels()" << std::endl;
+#endif
+
     m_models.clear();
 
     if (m_converter) {
--- a/audioio/AudioCallbackPlaySource.h	Wed Mar 07 18:00:49 2007 +0000
+++ b/audioio/AudioCallbackPlaySource.h	Thu Mar 08 16:53:08 2007 +0000
@@ -175,7 +175,7 @@
      * safely be called from a realtime thread.  Returns 0 if there is
      * no source yet available.
      */
-    size_t getSourceSampleRate() const;
+    virtual size_t getSourceSampleRate() const;
 
     /**
      * Get "count" samples (at the target sample rate) of the mixed
--- a/audioio/AudioGenerator.cpp	Wed Mar 07 18:00:49 2007 +0000
+++ b/audioio/AudioGenerator.cpp	Thu Mar 08 16:53:08 2007 +0000
@@ -368,7 +368,12 @@
     if (!parameters) return frameCount;
 
     bool playing = !parameters->isPlayMuted();
-    if (!playing) return frameCount;
+    if (!playing) {
+#ifdef DEBUG_AUDIO_GENERATOR
+        std::cout << "AudioGenerator::mixModel(" << model << "): muted" << std::endl;
+#endif
+        return frameCount;
+    }
 
     float gain = parameters->getPlayGain();
     float pan = parameters->getPlayPan();
--- a/document/Document.cpp	Wed Mar 07 18:00:49 2007 +0000
+++ b/document/Document.cpp	Thu Mar 08 16:53:08 2007 +0000
@@ -34,6 +34,9 @@
 Document::Document() :
     m_mainModel(0)
 {
+    connect(this, SIGNAL(modelAboutToBeDeleted(Model *)),
+            TransformFactory::getInstance(),
+            SLOT(modelAboutToBeDeleted(Model *)));
 }
 
 Document::~Document()
--- a/document/SVFileReader.cpp	Wed Mar 07 18:00:49 2007 +0000
+++ b/document/SVFileReader.cpp	Thu Mar 08 16:53:08 2007 +0000
@@ -673,7 +673,6 @@
     READ_MANDATORY(size_t, zoom, toUInt);
     READ_MANDATORY(int, followPan, toInt);
     READ_MANDATORY(int, followZoom, toInt);
-    READ_MANDATORY(int, light, toInt);
     QString tracking = attributes.value("tracking");
 
     // Specify the follow modes before we set the actual values
@@ -686,7 +685,6 @@
     // Then set these values
     view->setCentreFrame(centre);
     view->setZoomLevel(zoom);
-    view->setLightBackground(light);
 
     // And pane properties
     READ_MANDATORY(int, centreLineVisible, toInt);
--- a/main/MainWindow.cpp	Wed Mar 07 18:00:49 2007 +0000
+++ b/main/MainWindow.cpp	Thu Mar 08 16:53:08 2007 +0000
@@ -286,6 +286,8 @@
 
 MainWindow::~MainWindow()
 {
+    std::cerr << "MainWindow::~MainWindow()" << std::endl;
+
     if (!m_abandoning) {
         closeSession();
     }
@@ -2334,13 +2336,12 @@
     if (setAsMain) {
 
         Model *prevMain = getMainModel();
-        if (prevMain) m_playSource->removeModel(prevMain);
-
-	PlayParameterRepository::getInstance()->clear();
-
-	// The clear() call will have removed the parameters for the
-	// main model.  Re-add them with the new one.
-	PlayParameterRepository::getInstance()->addModel(newModel);
+        if (prevMain) {
+            m_playSource->removeModel(prevMain);
+            PlayParameterRepository::getInstance()->removeModel(prevMain);
+        }
+
+        PlayParameterRepository::getInstance()->addModel(newModel);
 
 	m_document->setMainModel(newModel);
 	setupMenus();
@@ -2787,7 +2788,10 @@
 void
 MainWindow::closeEvent(QCloseEvent *e)
 {
+    std::cerr << "MainWindow::closeEvent" << std::endl;
+
     if (!m_abandoning && !checkSaveModified()) {
+        std::cerr << "Ignoring close event" << std::endl;
 	e->ignore();
 	return;
     }
@@ -3771,19 +3775,10 @@
         //!!! more helpful message needed
         QMessageBox::information
             (this, tr("Sample rate mismatch"),
-             tr("The sample rate of this audio file (%1 Hz) does not match\nthe current playback rate (%2 Hz).\n\nThe file will play at the wrong speed.")
+             tr("The sample rate of this audio file (%1 Hz) does not match\nthe current playback rate (%2 Hz).\n\nThe file will play at the wrong speed and pitch.")
              .arg(requested).arg(actual));
     }        
 
-/*!!! Let's not do this for now, and see how we go -- now that we're putting
-      sample rate information in the status bar
-
-    QMessageBox::information
-	(this, tr("Sample rate mismatch"),
-	 tr("The sample rate of this audio file (%1 Hz) does not match\nthat of the output audio device (%2 Hz).\n\nThe file will be resampled automatically during playback.")
-	 .arg(requested).arg(actual));
-*/
-
     updateDescriptionLabel();
 }
 
--- a/main/MainWindow.h	Wed Mar 07 18:00:49 2007 +0000
+++ b/main/MainWindow.h	Thu Mar 08 16:53:08 2007 +0000
@@ -110,6 +110,9 @@
     void canPlaySelection(bool);
     void canSave(bool);
 
+public slots:
+    void preferenceChanged(PropertyContainer::PropertyName);
+
 protected slots:
     void openSession();
     void importAudio();
@@ -214,8 +217,6 @@
 
     void propertyStacksResized();
 
-    void preferenceChanged(PropertyContainer::PropertyName);
-
     void setupRecentFilesMenu();
     void setupRecentTransformsMenu();
 
--- a/main/main.cpp	Wed Mar 07 18:00:49 2007 +0000
+++ b/main/main.cpp	Thu Mar 08 16:53:08 2007 +0000
@@ -145,6 +145,11 @@
     
     gui.show();
 
+    // The MainWindow class seems to have trouble dealing with this if
+    // it tries to adapt to this preference before the constructor is
+    // complete.  As a lazy hack, apply it explicitly from here
+    gui.preferenceChanged("Property Box Layout");
+
     bool haveSession = false;
     bool haveMainModel = false;
 
--- a/transform/FeatureExtractionPluginTransform.cpp	Wed Mar 07 18:00:49 2007 +0000
+++ b/transform/FeatureExtractionPluginTransform.cpp	Thu Mar 08 16:53:08 2007 +0000
@@ -279,7 +279,7 @@
 
     long prevCompletion = 0;
 
-    while (1) {
+    while (!m_abandoned) {
 
         if (frequencyDomain) {
             if (blockFrame - int(m_context.blockSize)/2 > endFrame) break;
@@ -326,6 +326,8 @@
 	blockFrame += m_context.stepSize;
     }
 
+    if (m_abandoned) return;
+
     Vamp::Plugin::FeatureSet features = m_plugin->getRemainingFeatures();
 
     for (size_t fi = 0; fi < features[m_outputFeatureNo].size(); ++fi) {
--- a/transform/RealTimePluginTransform.cpp	Wed Mar 07 18:00:49 2007 +0000
+++ b/transform/RealTimePluginTransform.cpp	Thu Mar 08 16:53:08 2007 +0000
@@ -151,7 +151,7 @@
 
     int i = 0;
 
-    while (blockFrame < endFrame) {
+    while (blockFrame < endFrame && !m_abandoned) {
 
 	size_t completion =
 	    (((blockFrame - startFrame) / blockSize) * 99) /
@@ -245,6 +245,8 @@
         
 	blockFrame += blockSize;
     }
+
+    if (m_abandoned) return;
     
     if (stvm) stvm->setCompletion(100);
     if (wwfm) wwfm->setCompletion(100);
--- a/transform/Transform.cpp	Wed Mar 07 18:00:49 2007 +0000
+++ b/transform/Transform.cpp	Thu Mar 08 16:53:08 2007 +0000
@@ -19,13 +19,13 @@
     m_input(m),
     m_output(0),
     m_detached(false),
-    m_deleting(false)
+    m_abandoned(false)
 {
 }
 
 Transform::~Transform()
 {
-    m_deleting = true;
+    m_abandoned = true;
     wait();
     if (!m_detached) delete m_output;
 }
--- a/transform/Transform.h	Wed Mar 07 18:00:49 2007 +0000
+++ b/transform/Transform.h	Thu Mar 08 16:53:08 2007 +0000
@@ -40,6 +40,11 @@
 public:
     virtual ~Transform();
 
+    // Just a hint to the processing thread that it should give up.
+    // Caller should still wait() and/or delete the transform before
+    // assuming its input and output models are no longer required.
+    void abandon() { m_abandoned = true; }
+
     Model *getInputModel()  { return m_input; }
     Model *getOutputModel() { return m_output; }
     Model *detachOutputModel() { m_detached = true; return m_output; }
@@ -50,7 +55,7 @@
     Model *m_input; // I don't own this
     Model *m_output; // I own this, unless...
     bool m_detached; // ... this is true.
-    bool m_deleting;
+    bool m_abandoned;
 };
 
 #endif
--- a/transform/TransformFactory.cpp	Wed Mar 07 18:00:49 2007 +0000
+++ b/transform/TransformFactory.cpp	Thu Mar 08 16:53:08 2007 +0000
@@ -717,7 +717,7 @@
 Transform *
 TransformFactory::createTransform(TransformId identifier, Model *inputModel,
                                   const PluginTransform::ExecutionContext &context,
-                                  QString configurationXml, bool start)
+                                  QString configurationXml)
 {
     Transform *transform = 0;
 
@@ -744,8 +744,7 @@
         return transform;
     }
 
-    if (start && transform) transform->start();
-    transform->setObjectName(identifier);
+    if (transform) transform->setObjectName(identifier);
     return transform;
 }
 
@@ -755,12 +754,14 @@
                             QString configurationXml)
 {
     Transform *t = createTransform(identifier, inputModel, context,
-                                   configurationXml, false);
+                                   configurationXml);
 
     if (!t) return 0;
 
     connect(t, SIGNAL(finished()), this, SLOT(transformFinished()));
 
+    m_runningTransforms.insert(t);
+
     t->start();
     Model *model = t->detachOutputModel();
 
@@ -787,12 +788,51 @@
     QObject *s = sender();
     Transform *transform = dynamic_cast<Transform *>(s);
     
+    std::cerr << "TransformFactory::transformFinished(" << transform << ")" << std::endl;
+
     if (!transform) {
 	std::cerr << "WARNING: TransformFactory::transformFinished: sender is not a transform" << std::endl;
 	return;
     }
 
+    if (m_runningTransforms.find(transform) == m_runningTransforms.end()) {
+        std::cerr << "WARNING: TransformFactory::transformFinished(" 
+                  << transform
+                  << "): I have no record of this transform running!"
+                  << std::endl;
+    }
+
+    m_runningTransforms.erase(transform);
+
     transform->wait(); // unnecessary but reassuring
     delete transform;
 }
 
+void
+TransformFactory::modelAboutToBeDeleted(Model *m)
+{
+    TransformSet affected;
+
+    for (TransformSet::iterator i = m_runningTransforms.begin();
+         i != m_runningTransforms.end(); ++i) {
+
+        Transform *t = *i;
+
+        if (t->getInputModel() == m || t->getOutputModel() == m) {
+            affected.insert(t);
+        }
+    }
+
+    for (TransformSet::iterator i = affected.begin();
+         i != affected.end(); ++i) {
+
+        Transform *t = *i;
+
+        t->abandon();
+
+        t->wait(); // this should eventually call back on
+                   // transformFinished, which will remove from
+                   // m_runningTransforms and delete.
+    }
+}
+
--- a/transform/TransformFactory.h	Wed Mar 07 18:00:49 2007 +0000
+++ b/transform/TransformFactory.h	Thu Mar 08 16:53:08 2007 +0000
@@ -20,6 +20,7 @@
 #include "PluginTransform.h"
 
 #include <map>
+#include <set>
 
 namespace Vamp { class PluginBase; }
 
@@ -142,21 +143,16 @@
      */
     bool getTransformChannelRange(TransformId identifier,
                                   int &minChannels, int &maxChannels);
-
-    //!!! Need some way to indicate that the input model has changed /
-    //been deleted so as not to blow up backgrounded transform!  -- Or
-    //indeed, if the output model has been deleted -- could equally
-    //well happen!
-
-    //!!! Need transform category!
 	
 protected slots:
     void transformFinished();
 
+    void modelAboutToBeDeleted(Model *);
+
 protected:
     Transform *createTransform(TransformId identifier, Model *inputModel,
                                const PluginTransform::ExecutionContext &context,
-                               QString configurationXml, bool start);
+                               QString configurationXml);
 
     struct TransformIdent
     {
@@ -170,6 +166,9 @@
     typedef std::map<TransformId, TransformDesc> TransformDescriptionMap;
     TransformDescriptionMap m_transforms;
 
+    typedef std::set<Transform *> TransformSet;
+    TransformSet m_runningTransforms;
+
     void populateTransforms();
     void populateFeatureExtractionPlugins(TransformDescriptionMap &);
     void populateRealTimePlugins(TransformDescriptionMap &);