changeset 301:055ff09f7a08 tonioni

Merge from default branch
author Chris Cannam
date Tue, 03 Dec 2013 17:58:53 +0000
parents ae1eedd6951f (diff) 47964f188bd9 (current diff)
children febd49356ef3
files audioio/AudioCallbackPlaySource.cpp
diffstat 6 files changed, 184 insertions(+), 165 deletions(-) [+]
line wrap: on
line diff
--- a/audioio/AudioCallbackPlaySource.cpp	Tue Dec 03 12:35:39 2013 +0000
+++ b/audioio/AudioCallbackPlaySource.cpp	Tue Dec 03 17:58:53 2013 +0000
@@ -167,7 +167,7 @@
     }
 
 #ifdef DEBUG_AUDIO_PLAY_SOURCE
-    cout << "Adding model with " << modelChannels << " channels at rate " << model->getSampleRate() << endl;
+    cout << "AudioCallbackPlaySource: Adding model with " << modelChannels << " channels at rate " << model->getSampleRate() << endl;
 #endif
 
     if (m_sourceSampleRate == 0) {
--- a/audioio/AudioGenerator.cpp	Tue Dec 03 12:35:39 2013 +0000
+++ b/audioio/AudioGenerator.cpp	Tue Dec 03 17:58:53 2013 +0000
@@ -22,8 +22,10 @@
 #include "base/Exceptions.h"
 
 #include "data/model/NoteModel.h"
+#include "data/model/FlexiNoteModel.h"
 #include "data/model/DenseTimeValueModel.h"
 #include "data/model/SparseOneDimensionalModel.h"
+#include "data/model/NoteData.h"
 
 #include "plugin/RealTimePluginFactory.h"
 #include "plugin/RealTimePluginInstance.h"
@@ -204,11 +206,19 @@
         configurationXml = parameters->getPlayPluginConfiguration();
     }
 
-    if (pluginId == "") return 0;
+    std::cerr << "AudioGenerator::loadPluginFor(" << model << "): id = " << pluginId << std::endl;
+
+    if (pluginId == "") {
+        SVDEBUG << "AudioGenerator::loadPluginFor(" << model << "): parameters contain empty plugin ID, skipping" << endl;
+        return 0;
+    }
 
     RealTimePluginInstance *plugin = loadPlugin(pluginId, "");
     if (!plugin) return 0;
 
+    std::cerr << "AudioGenerator::loadPluginFor(" << model << "): loaded plugin "
+              << plugin << std::endl;
+
     if (configurationXml != "") {
         PluginXml(plugin).setParametersFromXml(configurationXml);
         setSampleDir(plugin);
@@ -251,11 +261,11 @@
     }
     std::string defaultProgram = instance->getProgram(0, 0);
     if (defaultProgram != "") {
-//        cerr << "first selecting default program " << defaultProgram << endl;
+        cerr << "first selecting default program " << defaultProgram << endl;
         instance->selectProgram(defaultProgram);
     }
     if (program != "") {
-//        cerr << "now selecting desired program " << program << endl;
+        cerr << "now selecting desired program " << program << endl;
         instance->selectProgram(program.toStdString());
     }
     instance->setIdealChannelCount(m_targetChannelCount); // reset!
@@ -389,13 +399,16 @@
 
     bool synthetic = 
         (qobject_cast<SparseOneDimensionalModel *>(model) ||
-         qobject_cast<NoteModel *>(model));
+         qobject_cast<NoteModel *>(model) ||
+         qobject_cast<FlexiNoteModel *>(model));
 
     if (synthetic) {
         return mixSyntheticNoteModel(model, startFrame, frameCount,
                                      buffer, gain, pan, fadeIn, fadeOut);
     }
 
+    std::cerr << "AudioGenerator::mixModel: WARNING: Model " << model << " of type " << model->getTypeName() << " is marked as playable, but I have no mechanism to play it" << std::endl;
+
     return frameCount;
 }
 
@@ -539,9 +552,12 @@
 
 	size_t reqStart = startFrame + i * m_pluginBlockSize;
 
-        NoteList notes = getNotes(model,
-                                  reqStart + latency,
-                                  reqStart + latency + m_pluginBlockSize);
+        NoteList notes;
+        NoteExportable *exportable = dynamic_cast<NoteExportable *>(model);
+        if (exportable) {
+            notes = exportable->getNotes(reqStart + latency,
+                                         reqStart + latency + m_pluginBlockSize);
+        }
 
         Vamp::RealTime blockTime = Vamp::RealTime::frame2RealTime
 	    (startFrame + i * m_pluginBlockSize, m_sourceSampleRate);
@@ -641,73 +657,3 @@
 
     return got;
 }
-
-AudioGenerator::NoteList
-AudioGenerator::getNotes(Model *model,
-                         size_t startFrame,
-                         size_t endFrame)
-{
-    NoteList notes;
-
-    SparseOneDimensionalModel *sodm = 
-        qobject_cast<SparseOneDimensionalModel *>(model);
-
-    if (sodm) {
-        
-	SparseOneDimensionalModel::PointList points =
-	    sodm->getPoints(startFrame, endFrame);
-
-	for (SparseOneDimensionalModel::PointList::iterator pli =
-		 points.begin(); pli != points.end(); ++pli) {
-
-            notes.push_back
-                (NoteData(pli->frame,
-                          m_sourceSampleRate / 6, // arbitrary short duration
-                          64,   // default pitch
-                          100)); // default velocity
-        }
-
-        return notes;
-    }
-
-    NoteModel *nm = qobject_cast<NoteModel *>(model);
-
-    if (nm) {
-        
-	NoteModel::PointList points =
-	    nm->getPoints(startFrame, endFrame);
-
-        for (NoteModel::PointList::iterator pli =
-		 points.begin(); pli != points.end(); ++pli) {
-
-	    size_t duration = pli->duration;
-            if (duration == 0 || duration == 1) {
-                duration = m_sourceSampleRate / 20;
-            }
-
-            int pitch = lrintf(pli->value);
-
-            int velocity = 100;
-            if (pli->level > 0.f && pli->level <= 1.f) {
-                velocity = lrintf(pli->level * 127);
-            }
-
-            NoteData note(pli->frame,
-                          duration,
-                          pitch,
-                          velocity);
-
-            if (nm->getScaleUnits() == "Hz") {
-                note.frequency = pli->value;
-                note.isMidiPitchQuantized = false;
-            }
-        
-            notes.push_back(note);
-        }
-
-        return notes;
-    }
-
-    return notes;
-}
-
--- a/audioio/AudioGenerator.h	Tue Dec 03 12:35:39 2013 +0000
+++ b/audioio/AudioGenerator.h	Tue Dec 03 17:58:53 2013 +0000
@@ -18,6 +18,7 @@
 
 class Model;
 class NoteModel;
+class FlexiNoteModel;
 class DenseTimeValueModel;
 class SparseOneDimensionalModel;
 class RealTimePluginInstance;
@@ -102,22 +103,6 @@
     bool m_soloing;
     std::set<Model *> m_soloModelSet;
 
-    struct NoteData {
-
-        NoteData(size_t _start, size_t _dur, int _mp, int _vel) :
-            start(_start), duration(_dur), midiPitch(_mp), frequency(0),
-            isMidiPitchQuantized(true), velocity(_vel) { };
-            
-        size_t start;     // audio sample frame
-        size_t duration;  // in audio sample frames
-        int midiPitch; // 0-127
-        int frequency; // Hz, to be used if isMidiPitchQuantized false
-        bool isMidiPitchQuantized;
-        int velocity;  // MIDI-style 0-127
-    };
-
-    typedef std::vector<NoteData> NoteList;
-    
     struct NoteOff {
 
         NoteOff(int _p, size_t _f) : pitch(_p), frame(_f) { }
@@ -155,8 +140,6 @@
     (Model *model, size_t startFrame, size_t frameCount,
      float **buffer, float gain, float pan, size_t fadeIn, size_t fadeOut);
     
-    NoteList getNotes(Model *model, size_t startFrame, size_t endFrame);
-
     static const size_t m_pluginBlockSize;
 };
 
--- a/framework/Document.cpp	Tue Dec 03 12:35:39 2013 +0000
+++ b/framework/Document.cpp	Tue Dec 03 17:58:53 2013 +0000
@@ -19,6 +19,8 @@
 #include "data/model/WritableWaveFileModel.h"
 #include "data/model/DenseThreeDimensionalModel.h"
 #include "data/model/DenseTimeValueModel.h"
+#include "data/model/FlexiNoteModel.h"
+
 #include "layer/Layer.h"
 #include "widgets/CommandHistory.h"
 #include "base/Command.h"
@@ -27,6 +29,7 @@
 #include "base/PlayParameters.h"
 #include "transform/TransformFactory.h"
 #include "transform/ModelTransformerFactory.h"
+#include "transform/FeatureExtractionModelTransformer.h"
 #include <QApplication>
 #include <QTextStream>
 #include <QSettings>
@@ -38,6 +41,8 @@
 #include "data/model/SparseTimeValueModel.h"
 #include "data/model/AlignmentModel.h"
 
+using std::vector;
+
 //#define DEBUG_DOCUMENT 1
 
 //!!! still need to handle command history, documentRestored/documentModified
@@ -207,56 +212,80 @@
 Document::createDerivedLayer(const Transform &transform,
                              const ModelTransformer::Input &input)
 {
+    Transforms transforms;
+    transforms.push_back(transform);
+    vector<Layer *> layers = createDerivedLayers(transforms, input);
+    if (layers.empty()) return 0;
+    else return layers[0];
+}
+
+vector<Layer *>
+Document::createDerivedLayers(const Transforms &transforms,
+                              const ModelTransformer::Input &input)
+{
     QString message;
-    Model *newModel = addDerivedModel(transform, input, message);
-    if (!newModel) {
-        emit modelGenerationFailed(transform.getIdentifier(), message);
-        return 0;
+    vector<Model *> newModels = addDerivedModels(transforms, input, message);
+
+    if (newModels.empty()) {
+        //!!! This identifier may be wrong!
+        emit modelGenerationFailed(transforms[0].getIdentifier(), message);
+        return vector<Layer *>();
     } else if (message != "") {
-        emit modelGenerationWarning(transform.getIdentifier(), message);
+        //!!! This identifier may be wrong!
+        emit modelGenerationWarning(transforms[0].getIdentifier(), message);
     }
 
-    LayerFactory::LayerTypeSet types =
-	LayerFactory::getInstance()->getValidLayerTypes(newModel);
+    vector<Layer *> layers;
 
-    if (types.empty()) {
-	cerr << "WARNING: Document::createLayerForTransformer: no valid display layer for output of transform " << transform.getIdentifier() << endl;
-        newModel->aboutToDelete();
-        emit modelAboutToBeDeleted(newModel);
-        m_models.erase(newModel);
-	delete newModel;
-	return 0;
+    for (int i = 0; i < (int)newModels.size(); ++i) {
+
+        Model *newModel = newModels[i];
+
+        LayerFactory::LayerTypeSet types =
+            LayerFactory::getInstance()->getValidLayerTypes(newModel);
+
+        if (types.empty()) {
+            cerr << "WARNING: Document::createLayerForTransformer: no valid display layer for output of transform " << transforms[i].getIdentifier() << endl;
+            //!!! inadequate cleanup:
+            newModel->aboutToDelete();
+            emit modelAboutToBeDeleted(newModel);
+            m_models.erase(newModel);
+            delete newModel;
+            return vector<Layer *>();
+        }
+
+        //!!! for now, just use the first suitable layer type
+
+        Layer *newLayer = createLayer(*types.begin());
+        setModel(newLayer, newModel);
+
+        //!!! We need to clone the model when adding the layer, so that it
+        //can be edited without affecting other layers that are based on
+        //the same model.  Unfortunately we can't just clone it now,
+        //because it probably hasn't been completed yet -- the transform
+        //runs in the background.  Maybe the transform has to handle
+        //cloning and cacheing models itself.
+        //
+        // Once we do clone models here, of course, we'll have to avoid
+        // leaking them too.
+        //
+        // We want the user to be able to add a model to a second layer
+        // _while it's still being calculated in the first_ and have it
+        // work quickly.  That means we need to put the same physical
+        // model pointer in both layers, so they can't actually be cloned.
+    
+        if (newLayer) {
+            newLayer->setObjectName(getUniqueLayerName
+                                    (TransformFactory::getInstance()->
+                                     getTransformFriendlyName
+                                     (transforms[i].getIdentifier())));
+        }
+
+        emit layerAdded(newLayer);
+        layers.push_back(newLayer);
     }
 
-    //!!! for now, just use the first suitable layer type
-
-    Layer *newLayer = createLayer(*types.begin());
-    setModel(newLayer, newModel);
-
-    //!!! We need to clone the model when adding the layer, so that it
-    //can be edited without affecting other layers that are based on
-    //the same model.  Unfortunately we can't just clone it now,
-    //because it probably hasn't been completed yet -- the transform
-    //runs in the background.  Maybe the transform has to handle
-    //cloning and cacheing models itself.
-    //
-    // Once we do clone models here, of course, we'll have to avoid
-    // leaking them too.
-    //
-    // We want the user to be able to add a model to a second layer
-    // _while it's still being calculated in the first_ and have it
-    // work quickly.  That means we need to put the same physical
-    // model pointer in both layers, so they can't actually be cloned.
-    
-    if (newLayer) {
-	newLayer->setObjectName(getUniqueLayerName
-                                (TransformFactory::getInstance()->
-                                 getTransformFriendlyName
-                                 (transform.getIdentifier())));
-    }
-
-    emit layerAdded(newLayer);
-    return newLayer;
+    return layers;
 }
 
 void
@@ -503,40 +532,58 @@
                           const ModelTransformer::Input &input,
                           QString &message)
 {
-    Model *model = 0;
-
     for (ModelMap::iterator i = m_models.begin(); i != m_models.end(); ++i) {
-	if (i->second.transform == transform &&
-	    i->second.source == input.getModel() && 
+        if (i->second.transform == transform &&
+            i->second.source == input.getModel() && 
             i->second.channel == input.getChannel()) {
-	    return i->first;
-	}
+            std::cerr << "derived model taken from map " << std::endl;
+            return i->first;
+        }
     }
 
-    model = ModelTransformerFactory::getInstance()->transform
-        (transform, input, message);
+    Transforms tt;
+    tt.push_back(transform);
+    vector<Model *> mm = addDerivedModels(tt, input, message);
+    if (mm.empty()) return 0;
+    else return mm[0];
+}
 
-    // The transform we actually used was presumably identical to the
-    // one asked for, except that the version of the plugin may
-    // differ.  It's possible that the returned message contains a
-    // warning about this; that doesn't concern us here, but we do
-    // need to ensure that the transform we remember is correct for
-    // what was actually applied, with the current plugin version.
+vector<Model *>
+Document::addDerivedModels(const Transforms &transforms,
+                           const ModelTransformer::Input &input,
+                           QString &message)
+{
+    vector<Model *> mm = 
+        ModelTransformerFactory::getInstance()->transformMultiple
+        (transforms, input, message);
 
-    Transform applied = transform;
-    applied.setPluginVersion
-        (TransformFactory::getInstance()->
-         getDefaultTransformFor(transform.getIdentifier(),
-                                lrintf(transform.getSampleRate()))
-         .getPluginVersion());
+    for (int j = 0; j < (int)mm.size(); ++j) {
 
-    if (!model) {
-	cerr << "WARNING: Document::addDerivedModel: no output model for transform " << transform.getIdentifier() << endl;
-    } else {
-	addDerivedModel(applied, input, model);
+        Model *model = mm[j];
+
+        // The transform we actually used was presumably identical to
+        // the one asked for, except that the version of the plugin
+        // may differ.  It's possible that the returned message
+        // contains a warning about this; that doesn't concern us
+        // here, but we do need to ensure that the transform we
+        // remember is correct for what was actually applied, with the
+        // current plugin version.
+
+        Transform applied = transforms[j];
+        applied.setPluginVersion
+            (TransformFactory::getInstance()->
+             getDefaultTransformFor(applied.getIdentifier(),
+                                    lrintf(applied.getSampleRate()))
+             .getPluginVersion());
+
+        if (!model) {
+            cerr << "WARNING: Document::addDerivedModel: no output model for transform " << applied.getIdentifier() << endl;
+        } else {
+            addDerivedModel(applied, input, model);
+        }
     }
-
-    return model;
+	
+    return mm;
 }
 
 void
@@ -690,6 +737,7 @@
     }
 
     LayerFactory::getInstance()->setModel(layer, model);
+	// std::cerr << "layer type: " << LayerFactory::getInstance()->getLayerTypeName(LayerFactory::getInstance()->getLayerType(layer)) << std::endl;
 
     if (previousModel) {
         releaseModel(previousModel);
--- a/framework/Document.h	Tue Dec 03 12:35:39 2013 +0000
+++ b/framework/Document.h	Tue Dec 03 17:58:53 2013 +0000
@@ -19,6 +19,7 @@
 #include "layer/LayerFactory.h"
 #include "transform/Transform.h"
 #include "transform/ModelTransformer.h"
+#include "transform/FeatureExtractionModelTransformer.h"
 #include "base/Command.h"
 
 #include <map>
@@ -117,6 +118,15 @@
                               const ModelTransformer::Input &);
 
     /**
+     * Create and return suitable layers for the given transforms,
+     * which must be identical apart from the output (i.e. must use
+     * the same plugin and configuration). The layers are returned in
+     * the same order as the transformed are supplied.
+     */
+    std::vector<Layer *> createDerivedLayers(const Transforms &,
+                                             const ModelTransformer::Input &);
+
+    /**
      * Delete the given layer, and also its associated model if no
      * longer used by any other layer.  In general, this should be the
      * only method used to delete layers -- doing so directly is a bit
@@ -154,6 +164,15 @@
                            QString &returnedMessage);
 
     /**
+     * Add derived models associated with the given set of related
+     * transforms, running the transforms and returning the resulting
+     * models.
+     */
+    std::vector<Model *> addDerivedModels(const Transforms &transforms,
+                                          const ModelTransformer::Input &input,
+                                          QString &returnedMessage);
+
+    /**
      * Add a derived model associated with the given transform.  This
      * is necessary to register any derived model that was not created
      * by the document using createDerivedModel or createDerivedLayer.
--- a/framework/MainWindowBase.cpp	Tue Dec 03 12:35:39 2013 +0000
+++ b/framework/MainWindowBase.cpp	Tue Dec 03 17:58:53 2013 +0000
@@ -22,6 +22,7 @@
 #include "data/model/WaveFileModel.h"
 #include "data/model/SparseOneDimensionalModel.h"
 #include "data/model/NoteModel.h"
+#include "data/model/FlexiNoteModel.h"
 #include "data/model/Labeller.h"
 #include "data/model/TabularModel.h"
 #include "view/ViewManager.h"
@@ -35,6 +36,7 @@
 #include "layer/SliceableLayer.h"
 #include "layer/ImageLayer.h"
 #include "layer/NoteLayer.h"
+#include "layer/FlexiNoteLayer.h"
 #include "layer/RegionLayer.h"
 
 #include "widgets/ListInputDialog.h"
@@ -428,6 +430,7 @@
     bool haveCurrentDurationLayer = 
 	(haveCurrentLayer &&
 	 (dynamic_cast<NoteLayer *>(currentLayer) ||
+	  dynamic_cast<FlexiNoteLayer *>(currentLayer) ||
           dynamic_cast<RegionLayer *>(currentLayer)));
     bool haveCurrentColour3DPlot =
         (haveCurrentLayer &&
@@ -1013,6 +1016,25 @@
         CommandHistory::getInstance()->addCommand(c, false);
         return;
     }
+
+    FlexiNoteModel *fnm = dynamic_cast<FlexiNoteModel *>(layer->getModel());
+    if (fnm) {
+        FlexiNoteModel::Point point(alignedStart,
+                               rm->getValueMinimum(),
+                               alignedDuration,
+                               1.f,
+                               "");
+        FlexiNoteModel::EditCommand *command =
+            new FlexiNoteModel::EditCommand(fnm, tr("Add Point"));
+        command->addPoint(point);
+        command->setName(name);
+        c = command->finish();
+    }
+
+    if (c) {
+        CommandHistory::getInstance()->addCommand(c, false);
+        return;
+    }
 }
 
 void
@@ -3089,6 +3111,7 @@
 MainWindowBase::modelAdded(Model *model)
 {
 //    SVDEBUG << "MainWindowBase::modelAdded(" << model << ")" << endl;
+	std::cerr << "\nAdding model " << model->getTypeName() << " to playsource " << std::endl;
     m_playSource->addModel(model);
 }