# HG changeset patch # User Chris Cannam # Date 1386093533 0 # Node ID 055ff09f7a0897863299642f7d14814a05fcd9ac # Parent ae1eedd6951fcdb1424ff1c082f4ac789e371e1d# Parent 47964f188bd9cb2a75ad5c3783a86db76950a392 Merge from default branch diff -r 47964f188bd9 -r 055ff09f7a08 audioio/AudioCallbackPlaySource.cpp --- 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) { diff -r 47964f188bd9 -r 055ff09f7a08 audioio/AudioGenerator.cpp --- 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(model) || - qobject_cast(model)); + qobject_cast(model) || + qobject_cast(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(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(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(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; -} - diff -r 47964f188bd9 -r 055ff09f7a08 audioio/AudioGenerator.h --- 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 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 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; }; diff -r 47964f188bd9 -r 055ff09f7a08 framework/Document.cpp --- 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 #include #include @@ -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 layers = createDerivedLayers(transforms, input); + if (layers.empty()) return 0; + else return layers[0]; +} + +vector +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 newModels = addDerivedModels(transforms, input, message); + + if (newModels.empty()) { + //!!! This identifier may be wrong! + emit modelGenerationFailed(transforms[0].getIdentifier(), message); + return vector(); } 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 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(); + } + + //!!! 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 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 +Document::addDerivedModels(const Transforms &transforms, + const ModelTransformer::Input &input, + QString &message) +{ + vector 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); diff -r 47964f188bd9 -r 055ff09f7a08 framework/Document.h --- 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 @@ -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 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 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. diff -r 47964f188bd9 -r 055ff09f7a08 framework/MainWindowBase.cpp --- 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(currentLayer) || + dynamic_cast(currentLayer) || dynamic_cast(currentLayer))); bool haveCurrentColour3DPlot = (haveCurrentLayer && @@ -1013,6 +1016,25 @@ CommandHistory::getInstance()->addCommand(c, false); return; } + + FlexiNoteModel *fnm = dynamic_cast(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); }