# HG changeset patch # User Chris Cannam # Date 1173372788 0 # Node ID b4110b17bca85e0f1bb50e0a306d3de00d7a5e8b # Parent 8089a394829a7aa178a2f9f2baafd1d799390a5d * 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 diff -r 8089a394829a -r b4110b17bca8 audioio/AudioCallbackPlaySource.cpp --- 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::const_iterator i = m_models.begin(); i != m_models.end(); ++i) { - if (*i != dtvm && dynamic_cast(*i)) { + DenseTimeValueModel *dtvm2 = + dynamic_cast(*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) { diff -r 8089a394829a -r b4110b17bca8 audioio/AudioCallbackPlaySource.h --- 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 diff -r 8089a394829a -r b4110b17bca8 audioio/AudioGenerator.cpp --- 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(); diff -r 8089a394829a -r b4110b17bca8 document/Document.cpp --- 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() diff -r 8089a394829a -r b4110b17bca8 document/SVFileReader.cpp --- 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); diff -r 8089a394829a -r b4110b17bca8 main/MainWindow.cpp --- 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(); } diff -r 8089a394829a -r b4110b17bca8 main/MainWindow.h --- 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(); diff -r 8089a394829a -r b4110b17bca8 main/main.cpp --- 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; diff -r 8089a394829a -r b4110b17bca8 transform/FeatureExtractionPluginTransform.cpp --- 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) { diff -r 8089a394829a -r b4110b17bca8 transform/RealTimePluginTransform.cpp --- 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); diff -r 8089a394829a -r b4110b17bca8 transform/Transform.cpp --- 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; } diff -r 8089a394829a -r b4110b17bca8 transform/Transform.h --- 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 diff -r 8089a394829a -r b4110b17bca8 transform/TransformFactory.cpp --- 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(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. + } +} + diff -r 8089a394829a -r b4110b17bca8 transform/TransformFactory.h --- 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 +#include 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 TransformDescriptionMap; TransformDescriptionMap m_transforms; + typedef std::set TransformSet; + TransformSet m_runningTransforms; + void populateTransforms(); void populateFeatureExtractionPlugins(TransformDescriptionMap &); void populateRealTimePlugins(TransformDescriptionMap &);