Mercurial > hg > svcore
changeset 350:d7c41483af8f
* Merge from transforms branch -- switch over to using Transform object
properly
author | Chris Cannam |
---|---|
date | Fri, 07 Dec 2007 16:47:31 +0000 |
parents | edda24bb85fc |
children | 7263e37d8913 |
files | base/RealTime.cpp base/RealTime.h base/Window.h plugin/plugin.pro plugin/transform/FeatureExtractionModelTransformer.cpp plugin/transform/FeatureExtractionModelTransformer.h plugin/transform/ModelTransformer.cpp plugin/transform/ModelTransformer.h plugin/transform/ModelTransformerFactory.cpp plugin/transform/ModelTransformerFactory.h plugin/transform/PluginTransformer.cpp plugin/transform/PluginTransformer.h plugin/transform/RealTimeEffectModelTransformer.cpp plugin/transform/RealTimeEffectModelTransformer.h plugin/transform/Transform.cpp plugin/transform/Transform.h plugin/transform/TransformDescription.h plugin/transform/TransformFactory.cpp plugin/transform/TransformFactory.h |
diffstat | 19 files changed, 983 insertions(+), 498 deletions(-) [+] |
line wrap: on
line diff
--- a/base/RealTime.cpp Fri Nov 30 17:31:09 2007 +0000 +++ b/base/RealTime.cpp Fri Dec 07 16:47:31 2007 +0000 @@ -122,6 +122,51 @@ return s.substr(0, s.length() - 1); } +RealTime +RealTime::fromString(std::string s) +{ + bool negative = false; + bool faulty = false; + bool section = 0; + std::string ssec, snsec; + + for (size_t i = 0; i < s.length(); ++i) { + + char c = s[i]; + if (isspace(c)) continue; + + if (section == 0) { + + if (c == '-') negative = true; + else if (isdigit(c)) { section = 1; ssec += c; } + else if (c == '.') section = 2; + else break; + + } else if (section == 1) { + + if (c == '.') section = 2; + else if (isdigit(c)) ssec += c; + else break; + + } else if (section == 2) { + + if (isdigit(c)) snsec += c; + else break; + } + } + + while (snsec.length() < 8) snsec += '0'; + + int sec = atoi(ssec.c_str()); + int nsec = atoi(snsec.c_str()); + if (negative) sec = -sec; + + std::cerr << "RealTime::fromString: string " << s << " -> " + << sec << " sec, " << nsec << " nsec" << std::endl; + + return RealTime(sec, nsec); +} + std::string RealTime::toText(bool fixedDp) const {
--- a/base/RealTime.h Fri Nov 30 17:31:09 2007 +0000 +++ b/base/RealTime.h Fri Dec 07 16:47:31 2007 +0000 @@ -95,30 +95,45 @@ RealTime operator*(int m) const; RealTime operator/(int d) const; - // Find the fractional difference between times - // + /** + * Return the ratio of two times. + */ double operator/(const RealTime &r) const; - // Return a human-readable debug-type string to full precision - // (probably not a format to show to a user directly). If align - // is true, prepend " " to the start of positive values so that - // they line up with negative ones (which start with "-"). - // + /** + * Return a human-readable debug-type string to full precision + * (probably not a format to show to a user directly). If align + * is true, prepend " " to the start of positive values so that + * they line up with negative ones (which start with "-"). + */ std::string toString(bool align = false) const; - // Return a user-readable string to the nearest millisecond - // in a form like HH:MM:SS.mmm - // + /** + * Convert a string as obtained from toString back to a RealTime + * object. + */ + static RealTime fromString(std::string); + + /** + * Return a user-readable string to the nearest millisecond, in a + * form like HH:MM:SS.mmm + */ std::string toText(bool fixedDp = false) const; - // Return a user-readable string to the nearest second in a form - // like "6s" (for less than a minute) or "2:21" (for more). - // + /** + * Return a user-readable string to the nearest second, in a form + * like "6s" (for less than a minute) or "2:21" (for more). + */ std::string toSecText() const; - // Convenience functions for handling sample frames - // + /** + * Convert a RealTime into a sample frame at the given sample rate. + */ static long realTime2Frame(const RealTime &r, unsigned int sampleRate); + + /** + * Convert a sample frame at the given sample rate into a RealTime. + */ static RealTime frame2RealTime(long frame, unsigned int sampleRate); static const RealTime zeroTime;
--- a/base/Window.h Fri Nov 30 17:31:09 2007 +0000 +++ b/base/Window.h Fri Dec 07 16:47:31 2007 +0000 @@ -18,6 +18,7 @@ #include <cmath> #include <iostream> +#include <string> #include <map> enum WindowType { @@ -61,6 +62,12 @@ WindowType getType() const { return m_type; } size_t getSize() const { return m_size; } + // The names used by these functions are un-translated, for use in + // e.g. XML I/O. Use Preferences::getPropertyValueLabel if you + // want translated names for use in the user interface. + static std::string getNameForType(WindowType type); + static WindowType getTypeForName(std::string name); + protected: WindowType m_type; size_t m_size; @@ -159,4 +166,46 @@ } } +template <typename T> +std::string +Window<T>::getNameForType(WindowType type) +{ + switch (type) { + case RectangularWindow: return "rectangular"; + case BartlettWindow: return "bartlett"; + case HammingWindow: return "hamming"; + case HanningWindow: return "hanning"; + case BlackmanWindow: return "blackman"; + case GaussianWindow: return "gaussian"; + case ParzenWindow: return "parzen"; + case NuttallWindow: return "nuttall"; + case BlackmanHarrisWindow: return "blackman-harris"; + } + + std::cerr << "WARNING: Window::getNameForType: unknown type " + << type << std::endl; + + return "unknown"; +} + +template <typename T> +WindowType +Window<T>::getTypeForName(std::string name) +{ + if (name == "rectangular") return RectangularWindow; + if (name == "bartlett") return BartlettWindow; + if (name == "hamming") return HammingWindow; + if (name == "hanning") return HanningWindow; + if (name == "blackman") return BlackmanWindow; + if (name == "gaussian") return GaussianWindow; + if (name == "parzen") return ParzenWindow; + if (name == "nuttall") return NuttallWindow; + if (name == "blackman-harris") return BlackmanHarrisWindow; + + std::cerr << "WARNING: Window::getTypeForName: unknown name \"" + << name << "\", defaulting to \"hanning\"" << std::endl; + + return HanningWindow; +} + #endif
--- a/plugin/plugin.pro Fri Nov 30 17:31:09 2007 +0000 +++ b/plugin/plugin.pro Fri Dec 07 16:47:31 2007 +0000 @@ -36,7 +36,6 @@ api/alsa/seq_midi_event.h \ api/alsa/sound/asequencer.h \ transform/FeatureExtractionModelTransformer.h \ - transform/PluginTransformer.h \ transform/RealTimeEffectModelTransformer.h \ transform/Transform.h \ transform/TransformDescription.h \ @@ -55,7 +54,6 @@ api/dssi_alsa_compat.c \ plugins/SamplePlayer.cpp \ transform/FeatureExtractionModelTransformer.cpp \ - transform/PluginTransformer.cpp \ transform/RealTimeEffectModelTransformer.cpp \ transform/Transform.cpp \ transform/TransformFactory.cpp \
--- a/plugin/transform/FeatureExtractionModelTransformer.cpp Fri Nov 30 17:31:09 2007 +0000 +++ b/plugin/transform/FeatureExtractionModelTransformer.cpp Fri Dec 07 16:47:31 2007 +0000 @@ -29,21 +29,22 @@ #include "data/model/FFTModel.h" #include "data/model/WaveFileModel.h" +#include "TransformFactory.h" + #include <QMessageBox> #include <iostream> -FeatureExtractionModelTransformer::FeatureExtractionModelTransformer(Model *inputModel, - QString pluginId, - const ExecutionContext &context, - QString configurationXml, - QString outputName) : - PluginTransformer(inputModel, context), +FeatureExtractionModelTransformer::FeatureExtractionModelTransformer(Input in, + const Transform &transform) : + ModelTransformer(in, transform), m_plugin(0), m_descriptor(0), m_outputFeatureNo(0) { -// std::cerr << "FeatureExtractionModelTransformer::FeatureExtractionModelTransformer: plugin " << pluginId.toStdString() << ", outputName " << outputName.toStdString() << std::endl; +// std::cerr << "FeatureExtractionModelTransformer::FeatureExtractionModelTransformer: plugin " << pluginId.toStdString() << ", outputName " << m_transform.getOutput().toStdString() << std::endl; + + QString pluginId = transform.getPluginIdentifier(); FeatureExtractionPluginFactory *factory = FeatureExtractionPluginFactory::instanceFor(pluginId); @@ -54,22 +55,24 @@ return; } - m_plugin = factory->instantiatePlugin(pluginId, m_input->getSampleRate()); + DenseTimeValueModel *input = getConformingInput(); + if (!input) { + std::cerr << "FeatureExtractionModelTransformer: Input model not conformable" << std::endl; + return; + } + m_plugin = factory->instantiatePlugin(pluginId, input->getSampleRate()); if (!m_plugin) { std::cerr << "FeatureExtractionModelTransformer: Failed to instantiate plugin \"" << pluginId.toStdString() << "\"" << std::endl; return; } - m_context.makeConsistentWithPlugin(m_plugin); + TransformFactory::getInstance()->makeContextConsistentWithPlugin + (m_transform, m_plugin); - if (configurationXml != "") { - PluginXml(m_plugin).setParametersFromXml(configurationXml); - } - - DenseTimeValueModel *input = getInput(); - if (!input) return; + TransformFactory::getInstance()->setPluginParameters + (m_transform, m_plugin); size_t channelCount = input->getChannelCount(); if (m_plugin->getMaxChannelCount() < channelCount) { @@ -85,14 +88,14 @@ } std::cerr << "Initialising feature extraction plugin with channels = " - << channelCount << ", step = " << m_context.stepSize - << ", block = " << m_context.blockSize << std::endl; + << channelCount << ", step = " << m_transform.getStepSize() + << ", block = " << m_transform.getBlockSize() << std::endl; if (!m_plugin->initialise(channelCount, - m_context.stepSize, - m_context.blockSize)) { + m_transform.getStepSize(), + m_transform.getBlockSize())) { std::cerr << "FeatureExtractionModelTransformer: Plugin " - << m_plugin->getIdentifier() << " failed to initialise!" << std::endl; + << pluginId.toStdString() << " failed to initialise!" << std::endl; return; } @@ -105,7 +108,8 @@ } for (size_t i = 0; i < outputs.size(); ++i) { - if (outputName == "" || outputs[i].identifier == outputName.toStdString()) { + if (m_transform.getOutput() == "" || + outputs[i].identifier == m_transform.getOutput().toStdString()) { m_outputFeatureNo = i; m_descriptor = new Vamp::Plugin::OutputDescriptor (outputs[i]); @@ -116,7 +120,7 @@ if (!m_descriptor) { std::cerr << "FeatureExtractionModelTransformer: Plugin \"" << pluginId.toStdString() << "\" has no output named \"" - << outputName.toStdString() << "\"" << std::endl; + << m_transform.getOutput().toStdString() << "\"" << std::endl; return; } @@ -140,7 +144,7 @@ haveExtents = true; } - size_t modelRate = m_input->getSampleRate(); + size_t modelRate = input->getSampleRate(); size_t modelResolution = 1; switch (m_descriptor->sampleType) { @@ -152,7 +156,7 @@ break; case Vamp::Plugin::OutputDescriptor::OneSamplePerStep: - modelResolution = m_context.stepSize; + modelResolution = m_transform.getStepSize(); break; case Vamp::Plugin::OutputDescriptor::FixedSampleRate: @@ -219,7 +223,7 @@ m_output = model; } - if (m_output) m_output->setSourceModel(m_input); + if (m_output) m_output->setSourceModel(input); } FeatureExtractionModelTransformer::~FeatureExtractionModelTransformer() @@ -230,12 +234,12 @@ } DenseTimeValueModel * -FeatureExtractionModelTransformer::getInput() +FeatureExtractionModelTransformer::getConformingInput() { DenseTimeValueModel *dtvm = dynamic_cast<DenseTimeValueModel *>(getInputModel()); if (!dtvm) { - std::cerr << "FeatureExtractionModelTransformer::getInput: WARNING: Input model is not conformable to DenseTimeValueModel" << std::endl; + std::cerr << "FeatureExtractionModelTransformer::getConformingInput: WARNING: Input model is not conformable to DenseTimeValueModel" << std::endl; } return dtvm; } @@ -243,7 +247,7 @@ void FeatureExtractionModelTransformer::run() { - DenseTimeValueModel *input = getInput(); + DenseTimeValueModel *input = getConformingInput(); if (!input) return; if (!m_output) return; @@ -260,7 +264,7 @@ sleep(1); } - size_t sampleRate = m_input->getSampleRate(); + size_t sampleRate = input->getSampleRate(); size_t channelCount = input->getChannelCount(); if (m_plugin->getMaxChannelCount() < channelCount) { @@ -269,9 +273,12 @@ float **buffers = new float*[channelCount]; for (size_t ch = 0; ch < channelCount; ++ch) { - buffers[ch] = new float[m_context.blockSize + 2]; + buffers[ch] = new float[m_transform.getBlockSize() + 2]; } + size_t stepSize = m_transform.getStepSize(); + size_t blockSize = m_transform.getBlockSize(); + bool frequencyDomain = (m_plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain); std::vector<FFTModel *> fftModels; @@ -279,12 +286,12 @@ if (frequencyDomain) { for (size_t ch = 0; ch < channelCount; ++ch) { FFTModel *model = new FFTModel - (getInput(), - channelCount == 1 ? m_context.channel : ch, - m_context.windowType, - m_context.blockSize, - m_context.stepSize, - m_context.blockSize, + (getConformingInput(), + channelCount == 1 ? m_input.getChannel() : ch, + m_transform.getWindowType(), + blockSize, + stepSize, + blockSize, false, StorageAdviser::PrecisionCritical); if (!model->isOK()) { @@ -301,11 +308,17 @@ } } - long startFrame = m_input->getStartFrame(); - long endFrame = m_input->getEndFrame(); + long startFrame = m_input.getModel()->getStartFrame(); + long endFrame = m_input.getModel()->getEndFrame(); - long contextStart = m_context.startFrame; - long contextDuration = m_context.duration; + RealTime contextStartRT = m_transform.getStartTime(); + RealTime contextDurationRT = m_transform.getDuration(); + + long contextStart = + RealTime::realTime2Frame(contextStartRT, sampleRate); + + long contextDuration = + RealTime::realTime2Frame(contextDurationRT, sampleRate); if (contextStart == 0 || contextStart < startFrame) { contextStart = startFrame; @@ -327,7 +340,7 @@ while (!m_abandoned) { if (frequencyDomain) { - if (blockFrame - int(m_context.blockSize)/2 > + if (blockFrame - int(blockSize)/2 > contextStart + contextDuration) break; } else { if (blockFrame >= @@ -336,24 +349,24 @@ // std::cerr << "FeatureExtractionModelTransformer::run: blockFrame " // << blockFrame << ", endFrame " << endFrame << ", blockSize " -// << m_context.blockSize << std::endl; +// << blockSize << std::endl; long completion = - (((blockFrame - contextStart) / m_context.stepSize) * 99) / - (contextDuration / m_context.stepSize); + (((blockFrame - contextStart) / stepSize) * 99) / + (contextDuration / stepSize); - // channelCount is either m_input->channelCount or 1 + // channelCount is either m_input.getModel()->channelCount or 1 for (size_t ch = 0; ch < channelCount; ++ch) { if (frequencyDomain) { - int column = (blockFrame - startFrame) / m_context.stepSize; - for (size_t i = 0; i <= m_context.blockSize/2; ++i) { + int column = (blockFrame - startFrame) / stepSize; + for (size_t i = 0; i <= blockSize/2; ++i) { fftModels[ch]->getValuesAt (column, i, buffers[ch][i*2], buffers[ch][i*2+1]); } } else { getFrames(ch, channelCount, - blockFrame, m_context.blockSize, buffers[ch]); + blockFrame, blockSize, buffers[ch]); } } @@ -371,7 +384,7 @@ prevCompletion = completion; } - blockFrame += m_context.stepSize; + blockFrame += stepSize; } if (m_abandoned) return; @@ -410,8 +423,11 @@ startFrame = 0; } - long got = getInput()->getData - ((channelCount == 1 ? m_context.channel : channel), + DenseTimeValueModel *input = getConformingInput(); + if (!input) return; + + long got = input->getData + ((channelCount == 1 ? m_input.getChannel() : channel), startFrame, size, buffer + offset); while (got < size) { @@ -419,10 +435,10 @@ ++got; } - if (m_context.channel == -1 && channelCount == 1 && - getInput()->getChannelCount() > 1) { + if (m_input.getChannel() == -1 && channelCount == 1 && + input->getChannelCount() > 1) { // use mean instead of sum, as plugin input - int cc = getInput()->getChannelCount(); + int cc = input->getChannelCount(); for (long i = 0; i < size; ++i) { buffer[i] /= cc; } @@ -433,7 +449,7 @@ FeatureExtractionModelTransformer::addFeature(size_t blockFrame, const Vamp::Plugin::Feature &feature) { - size_t inputRate = m_input->getSampleRate(); + size_t inputRate = m_input.getModel()->getSampleRate(); // std::cerr << "FeatureExtractionModelTransformer::addFeature(" // << blockFrame << ")" << std::endl; @@ -472,8 +488,10 @@ if (binCount == 0) { - SparseOneDimensionalModel *model = getOutput<SparseOneDimensionalModel>(); + SparseOneDimensionalModel *model = + getConformingOutput<SparseOneDimensionalModel>(); if (!model) return; + model->addPoint(SparseOneDimensionalModel::Point(frame, feature.label.c_str())); } else if (binCount == 1) { @@ -481,8 +499,10 @@ float value = 0.0; if (feature.values.size() > 0) value = feature.values[0]; - SparseTimeValueModel *model = getOutput<SparseTimeValueModel>(); + SparseTimeValueModel *model = + getConformingOutput<SparseTimeValueModel>(); if (!model) return; + model->addPoint(SparseTimeValueModel::Point(frame, value, feature.label.c_str())); // std::cerr << "SparseTimeValueModel::addPoint(" << frame << ", " << value << "), " << feature.label.c_str() << std::endl; @@ -500,7 +520,7 @@ if (velocity < 0) velocity = 127; if (velocity > 127) velocity = 127; - NoteModel *model = getOutput<NoteModel>(); + NoteModel *model = getConformingOutput<NoteModel>(); if (!model) return; model->addPoint(NoteModel::Point(frame, pitch, @@ -513,7 +533,7 @@ DenseThreeDimensionalModel::Column values = feature.values; EditableDenseThreeDimensionalModel *model = - getOutput<EditableDenseThreeDimensionalModel>(); + getConformingOutput<EditableDenseThreeDimensionalModel>(); if (!model) return; model->setColumn(frame / model->getResolution(), values); @@ -533,29 +553,32 @@ if (binCount == 0) { - SparseOneDimensionalModel *model = getOutput<SparseOneDimensionalModel>(); + SparseOneDimensionalModel *model = + getConformingOutput<SparseOneDimensionalModel>(); if (!model) return; - model->setCompletion(completion, m_context.updates); + model->setCompletion(completion, true); //!!!m_context.updates); } else if (binCount == 1) { - SparseTimeValueModel *model = getOutput<SparseTimeValueModel>(); + SparseTimeValueModel *model = + getConformingOutput<SparseTimeValueModel>(); if (!model) return; - model->setCompletion(completion, m_context.updates); + model->setCompletion(completion, true); //!!!m_context.updates); } else if (m_descriptor->sampleType == Vamp::Plugin::OutputDescriptor::VariableSampleRate) { - NoteModel *model = getOutput<NoteModel>(); + NoteModel *model = + getConformingOutput<NoteModel>(); if (!model) return; - model->setCompletion(completion, m_context.updates); + model->setCompletion(completion, true); //!!!m_context.updates); } else { EditableDenseThreeDimensionalModel *model = - getOutput<EditableDenseThreeDimensionalModel>(); + getConformingOutput<EditableDenseThreeDimensionalModel>(); if (!model) return; - model->setCompletion(completion, m_context.updates); + model->setCompletion(completion, true); //!!!m_context.updates); } }
--- a/plugin/transform/FeatureExtractionModelTransformer.h Fri Nov 30 17:31:09 2007 +0000 +++ b/plugin/transform/FeatureExtractionModelTransformer.h Fri Dec 07 16:47:31 2007 +0000 @@ -16,20 +16,21 @@ #ifndef _FEATURE_EXTRACTION_PLUGIN_TRANSFORMER_H_ #define _FEATURE_EXTRACTION_PLUGIN_TRANSFORMER_H_ -#include "PluginTransformer.h" +#include "ModelTransformer.h" + +#include <vamp-sdk/Plugin.h> + +#include <iostream> class DenseTimeValueModel; -class FeatureExtractionModelTransformer : public PluginTransformer +class FeatureExtractionModelTransformer : public ModelTransformer { Q_OBJECT public: - FeatureExtractionModelTransformer(Model *inputModel, - QString plugin, - const ExecutionContext &context, - QString configurationXml = "", - QString outputName = ""); + FeatureExtractionModelTransformer(Input input, + const Transform &transform); virtual ~FeatureExtractionModelTransformer(); protected: @@ -48,8 +49,8 @@ long startFrame, long size, float *buffer); // just casts - DenseTimeValueModel *getInput(); - template <typename ModelClass> ModelClass *getOutput() { + DenseTimeValueModel *getConformingInput(); + template <typename ModelClass> ModelClass *getConformingOutput() { ModelClass *mc = dynamic_cast<ModelClass *>(m_output); if (!mc) { std::cerr << "FeatureExtractionModelTransformer::getOutput: Output model not conformable" << std::endl;
--- a/plugin/transform/ModelTransformer.cpp Fri Nov 30 17:31:09 2007 +0000 +++ b/plugin/transform/ModelTransformer.cpp Fri Dec 07 16:47:31 2007 +0000 @@ -15,8 +15,9 @@ #include "ModelTransformer.h" -ModelTransformer::ModelTransformer(Model *m) : - m_input(m), +ModelTransformer::ModelTransformer(Input input, const Transform &transform) : + m_transform(transform), + m_input(input), m_output(0), m_detached(false), m_abandoned(false)
--- a/plugin/transform/ModelTransformer.h Fri Nov 30 17:31:09 2007 +0000 +++ b/plugin/transform/ModelTransformer.h Fri Dec 07 16:47:31 2007 +0000 @@ -20,6 +20,8 @@ #include "data/model/Model.h" +#include "Transform.h" + /** * A ModelTransformer turns one data model into another. * @@ -38,19 +40,38 @@ public: virtual ~ModelTransformer(); + class Input { + public: + Input(Model *m) : m_model(m), m_channel(-1) { } + Input(Model *m, int c) : m_model(m), m_channel(c) { } + + Model *getModel() const { return m_model; } + void setModel(Model *m) { m_model = m; } + + int getChannel() const { return m_channel; } + void setChannel(int c) { m_channel = c; } + + protected: + Model *m_model; + int m_channel; + }; + // 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 *getInputModel() { return m_input.getModel(); } + int getInputChannel() { return m_input.getChannel(); } + Model *getOutputModel() { return m_output; } Model *detachOutputModel() { m_detached = true; return m_output; } protected: - ModelTransformer(Model *m); + ModelTransformer(Input input, const Transform &transform); - Model *m_input; // I don't own this + Transform m_transform; + Input m_input; // I don't own the model in this Model *m_output; // I own this, unless... bool m_detached; // ... this is true. bool m_abandoned;
--- a/plugin/transform/ModelTransformerFactory.cpp Fri Nov 30 17:31:09 2007 +0000 +++ b/plugin/transform/ModelTransformerFactory.cpp Fri Dec 07 16:47:31 2007 +0000 @@ -51,7 +51,8 @@ } bool -ModelTransformerFactory::getChannelRange(TransformId identifier, Vamp::PluginBase *plugin, +ModelTransformerFactory::getChannelRange(TransformId identifier, + Vamp::PluginBase *plugin, int &minChannels, int &maxChannels) { Vamp::Plugin *vp = 0; @@ -66,17 +67,17 @@ } } -Model * -ModelTransformerFactory::getConfigurationForTransformer(TransformId identifier, - const std::vector<Model *> &candidateInputModels, - Model *defaultInputModel, - PluginTransformer::ExecutionContext &context, - QString &configurationXml, - AudioCallbackPlaySource *source, - size_t startFrame, - size_t duration) +ModelTransformer::Input +ModelTransformerFactory::getConfigurationForTransform(Transform &transform, + const std::vector<Model *> &candidateInputModels, + Model *defaultInputModel, + AudioCallbackPlaySource *source, + size_t startFrame, + size_t duration) { - if (candidateInputModels.empty()) return 0; + ModelTransformer::Input input(0); + + if (candidateInputModels.empty()) return input; //!!! This will need revision -- we'll have to have a callback //from the dialog for when the candidate input model is changed, @@ -99,15 +100,15 @@ } } - QString id = identifier.section(':', 0, 2); - QString output = identifier.section(':', 3); + QString id = transform.getPluginIdentifier(); + QString output = transform.getOutput(); QString outputLabel = ""; QString outputDescription = ""; bool ok = false; - configurationXml = m_lastConfigurations[identifier]; + QString configurationXml = m_lastConfigurations[transform.getIdentifier()]; -// std::cerr << "last configuration: " << configurationXml.toStdString() << std::endl; + std::cerr << "last configuration: " << configurationXml.toStdString() << std::endl; Vamp::PluginBase *plugin = 0; @@ -117,7 +118,7 @@ if (FeatureExtractionPluginFactory::instanceFor(id)) { - std::cerr << "getConfigurationForTransformer: instantiating Vamp plugin" << std::endl; + std::cerr << "getConfigurationForTransform: instantiating Vamp plugin" << std::endl; Vamp::Plugin *vp = FeatureExtractionPluginFactory::instanceFor(id)->instantiatePlugin @@ -184,11 +185,18 @@ if (plugin) { - context = PluginTransformer::ExecutionContext(context.channel, plugin); + // Ensure block size etc are valid + TransformFactory::getInstance()-> + makeContextConsistentWithPlugin(transform, plugin); - if (configurationXml != "") { - PluginXml(plugin).setParametersFromXml(configurationXml); - } + // Prepare the plugin with any existing parameters already + // found in the transform + TransformFactory::getInstance()-> + setPluginParameters(transform, plugin); + + // For this interactive usage, we want to override those with + // whatever the user chose last time around + PluginXml(plugin).setParametersFromXml(configurationXml); int sourceChannels = 1; if (dynamic_cast<DenseTimeValueModel *>(inputModel)) { @@ -197,7 +205,8 @@ } int minChannels = 1, maxChannels = sourceChannels; - getChannelRange(identifier, plugin, minChannels, maxChannels); + getChannelRange(transform.getIdentifier(), plugin, + minChannels, maxChannels); int targetChannels = sourceChannels; if (!effect) { @@ -205,7 +214,7 @@ if (sourceChannels > maxChannels) targetChannels = maxChannels; } - int defaultChannel = context.channel; + int defaultChannel = -1; //!!! no longer saved! [was context.channel] PluginParameterDialog *dialog = new PluginParameterDialog(plugin); @@ -242,22 +251,42 @@ } else { std::cerr << "Selected input empty: \"" << selectedInput.toStdString() << "\"" << std::endl; } + + // Write parameters back to transform object + TransformFactory::getInstance()-> + setParametersFromPlugin(transform, plugin); - configurationXml = PluginXml(plugin).toXmlString(); - context.channel = dialog->getChannel(); + input.setChannel(dialog->getChannel()); + //!!! The dialog ought to be taking & returning transform + //objects and input objects and stuff rather than passing + //around all this misc stuff, but that's for tomorrow + //(whenever that may be) + if (startFrame != 0 || duration != 0) { if (dialog->getSelectionOnly()) { - context.startFrame = startFrame; - context.duration = duration; + transform.setStartTime(RealTime::frame2RealTime + (startFrame, inputModel->getSampleRate())); + transform.setDuration(RealTime::frame2RealTime + (duration, inputModel->getSampleRate())); } } - dialog->getProcessingParameters(context.stepSize, - context.blockSize, - context.windowType); + size_t stepSize = 0, blockSize = 0; + WindowType windowType = HanningWindow; - context.makeConsistentWithPlugin(plugin); + dialog->getProcessingParameters(stepSize, + blockSize, + windowType); + + transform.setStepSize(stepSize); + transform.setBlockSize(blockSize); + transform.setWindowType(windowType); + + TransformFactory::getInstance()-> + makeContextConsistentWithPlugin(transform, plugin); + + configurationXml = PluginXml(plugin).toXmlString(); delete dialog; @@ -268,11 +297,14 @@ } } - if (ok) m_lastConfigurations[identifier] = configurationXml; + if (ok) { + m_lastConfigurations[transform.getIdentifier()] = configurationXml; + input.setModel(inputModel); + } - return ok ? inputModel : 0; + return input; } - +/*!!! PluginTransformer::ExecutionContext ModelTransformerFactory::getDefaultContextForTransformer(TransformId identifier, Model *inputModel) @@ -295,43 +327,40 @@ return context; } - +*/ ModelTransformer * -ModelTransformerFactory::createTransformer(TransformId identifier, Model *inputModel, - const PluginTransformer::ExecutionContext &context, - QString configurationXml) +ModelTransformerFactory::createTransformer(const Transform &transform, + const ModelTransformer::Input &input) { ModelTransformer *transformer = 0; - QString id = identifier.section(':', 0, 2); - QString output = identifier.section(':', 3); + QString id = transform.getPluginIdentifier(); if (FeatureExtractionPluginFactory::instanceFor(id)) { - transformer = new FeatureExtractionModelTransformer - (inputModel, id, context, configurationXml, output); + + transformer = + new FeatureExtractionModelTransformer(input, transform); + } else if (RealTimePluginFactory::instanceFor(id)) { - transformer = new RealTimeEffectModelTransformer - (inputModel, id, context, configurationXml, - TransformFactory::getInstance()->getTransformUnits(identifier), - output == "A" ? -1 : output.toInt()); + + transformer = + new RealTimeEffectModelTransformer(input, transform); + } else { std::cerr << "ModelTransformerFactory::createTransformer: Unknown transform \"" - << identifier.toStdString() << "\"" << std::endl; + << transform.getIdentifier().toStdString() << "\"" << std::endl; return transformer; } - if (transformer) transformer->setObjectName(identifier); + if (transformer) transformer->setObjectName(transform.getIdentifier()); return transformer; } Model * -ModelTransformerFactory::transform(TransformId identifier, Model *inputModel, - const PluginTransformer::ExecutionContext &context, - QString configurationXml) +ModelTransformerFactory::transform(const Transform &transform, + const ModelTransformer::Input &input) { - ModelTransformer *t = createTransformer(identifier, inputModel, context, - configurationXml); - + ModelTransformer *t = createTransformer(transform, input); if (!t) return 0; connect(t, SIGNAL(finished()), this, SLOT(transformerFinished())); @@ -342,10 +371,10 @@ Model *model = t->detachOutputModel(); if (model) { - QString imn = inputModel->objectName(); + QString imn = input.getModel()->objectName(); QString trn = TransformFactory::getInstance()->getTransformFriendlyName - (identifier); + (transform.getIdentifier()); if (imn != "") { if (trn != "") { model->setObjectName(tr("%1: %2").arg(imn).arg(trn));
--- a/plugin/transform/ModelTransformerFactory.h Fri Nov 30 17:31:09 2007 +0000 +++ b/plugin/transform/ModelTransformerFactory.h Fri Dec 07 16:47:31 2007 +0000 @@ -21,8 +21,6 @@ #include "ModelTransformer.h" -#include "PluginTransformer.h" - #include <map> #include <set> @@ -40,28 +38,29 @@ static ModelTransformerFactory *getInstance(); /** - * Get a configuration XML string for the given transform (by - * asking the user, most likely). Returns the selected input - * model if the transform is acceptable, 0 if the operation should - * be cancelled. Audio callback play source may be used to - * audition effects plugins, if provided. + * Fill out the configuration for the given transform (by asking + * the user, most likely). Returns the selected input model and + * channel if the transform is acceptable, or an input with a null + * model if the operation should be cancelled. Audio callback + * play source may be used to audition effects plugins, if + * provided. */ - Model *getConfigurationForTransformer(TransformId identifier, - const std::vector<Model *> &candidateInputModels, - Model *defaultInputModel, - PluginTransformer::ExecutionContext &context, - QString &configurationXml, - AudioCallbackPlaySource *source = 0, - size_t startFrame = 0, - size_t duration = 0); - + ModelTransformer::Input + getConfigurationForTransform(Transform &transform, + const std::vector<Model *> &candidateInputModels, + Model *defaultInputModel, + AudioCallbackPlaySource *source = 0, + size_t startFrame = 0, + size_t duration = 0); + /** * Get the default execution context for the given transform * and input model (if known). */ +/*!!! PluginTransformer::ExecutionContext getDefaultContextForTransformer(TransformId identifier, Model *inputModel = 0); - +*/ /** * Return the output model resulting from applying the named * transform to the given input model. The transform may still be @@ -75,9 +74,8 @@ * The returned model is owned by the caller and must be deleted * when no longer needed. */ - Model *transform(TransformId identifier, Model *inputModel, - const PluginTransformer::ExecutionContext &context, - QString configurationXml = ""); + Model *transform(const Transform &transform, + const ModelTransformer::Input &input); protected slots: void transformerFinished(); @@ -85,9 +83,8 @@ void modelAboutToBeDeleted(Model *); protected: - ModelTransformer *createTransformer(TransformId identifier, Model *inputModel, - const PluginTransformer::ExecutionContext &context, - QString configurationXml); + ModelTransformer *createTransformer(const Transform &transform, + const ModelTransformer::Input &input); typedef std::map<TransformId, QString> TransformerConfigurationMap; TransformerConfigurationMap m_lastConfigurations;
--- a/plugin/transform/PluginTransformer.cpp Fri Nov 30 17:31:09 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,127 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Sonic Visualiser - An audio file viewer and annotation editor. - Centre for Digital Music, Queen Mary, University of London. - This file copyright 2006 QMUL. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. See the file - COPYING included with this distribution for more information. -*/ - -#include "PluginTransformer.h" - -#include "vamp-sdk/PluginHostAdapter.h" -#include "vamp-sdk/hostext/PluginWrapper.h" - -PluginTransformer::PluginTransformer(Model *inputModel, - const ExecutionContext &context) : - ModelTransformer(inputModel), - m_context(context) -{ -} - -PluginTransformer::ExecutionContext::ExecutionContext(int _c, size_t _bs) : - channel(_c), - domain(Vamp::Plugin::TimeDomain), - stepSize(_bs ? _bs : 1024), - blockSize(_bs ? _bs : 1024), - windowType(HanningWindow), - startFrame(0), - duration(0), - sampleRate(0), - updates(true) -{ -} - -PluginTransformer::ExecutionContext::ExecutionContext(int _c, size_t _ss, - size_t _bs, WindowType _wt) : - channel(_c), - domain(Vamp::Plugin::FrequencyDomain), - stepSize(_ss ? _ss : (_bs ? _bs / 2 : 512)), - blockSize(_bs ? _bs : 1024), - windowType(_wt), - startFrame(0), - duration(0), - sampleRate(0), - updates(true) -{ -} - -PluginTransformer::ExecutionContext::ExecutionContext(int _c, - const Vamp::PluginBase *_plugin) : - channel(_c), - domain(Vamp::Plugin::TimeDomain), - stepSize(0), - blockSize(0), - windowType(HanningWindow), - startFrame(0), - duration(0), - sampleRate(0) -{ - makeConsistentWithPlugin(_plugin); -} - -bool -PluginTransformer::ExecutionContext::operator==(const ExecutionContext &c) -{ - return (c.channel == channel && - c.domain == domain && - c.stepSize == stepSize && - c.blockSize == blockSize && - c.windowType == windowType && - c.startFrame == startFrame && - c.duration == duration && - c.sampleRate == sampleRate); -} - -void -PluginTransformer::ExecutionContext::makeConsistentWithPlugin(const Vamp::PluginBase *_plugin) -{ - const Vamp::Plugin *vp = dynamic_cast<const Vamp::Plugin *>(_plugin); - if (!vp) { -// std::cerr << "makeConsistentWithPlugin: not a Vamp::Plugin" << std::endl; - vp = dynamic_cast<const Vamp::PluginHostAdapter *>(_plugin); //!!! why? -} - if (!vp) { -// std::cerr << "makeConsistentWithPlugin: not a Vamp::PluginHostAdapter" << std::endl; - vp = dynamic_cast<const Vamp::HostExt::PluginWrapper *>(_plugin); //!!! no, I mean really why? - } - if (!vp) { -// std::cerr << "makeConsistentWithPlugin: not a Vamp::HostExt::PluginWrapper" << std::endl; - } - -// std::cerr << "makeConsistentWithPlugin: stepSize = " << stepSize << ", blockSize = " << blockSize << std::endl; - - if (!vp) { - domain = Vamp::Plugin::TimeDomain; -// std::cerr << "time domain RT plugin" << std::endl; - if (!stepSize) { - if (!blockSize) blockSize = 1024; - stepSize = blockSize; - } else { - if (!blockSize) blockSize = stepSize; - } - } else { - domain = vp->getInputDomain(); -// std::cerr << "feature extraction plugin" << std::endl; - if (!stepSize) stepSize = vp->getPreferredStepSize(); - if (!blockSize) blockSize = vp->getPreferredBlockSize(); - if (!blockSize) blockSize = 1024; - if (!stepSize) { - if (domain == Vamp::Plugin::FrequencyDomain) { -// std::cerr << "frequency domain, step = " << blockSize/2 << std::endl; - stepSize = blockSize/2; - } else { -// std::cerr << "time domain, step = " << blockSize/2 << std::endl; - stepSize = blockSize; - } - } - } -} - -
--- a/plugin/transform/PluginTransformer.h Fri Nov 30 17:31:09 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Sonic Visualiser - An audio file viewer and annotation editor. - Centre for Digital Music, Queen Mary, University of London. - This file copyright 2006 QMUL. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. See the file - COPYING included with this distribution for more information. -*/ - -#ifndef _PLUGIN_TRANSFORMER_H_ -#define _PLUGIN_TRANSFORMER_H_ - -#include "ModelTransformer.h" - -#include "base/Window.h" - -#include "vamp-sdk/Plugin.h" - -//!!! should this just move back up to Transformer? It is after all used -//directly in all sorts of generic places, like Document - -class PluginTransformer : public ModelTransformer -{ -public: - class ExecutionContext { - public: - // Time domain: - ExecutionContext(int _c = -1, size_t _bs = 0); - - // Frequency domain: - ExecutionContext(int _c, size_t _ss, size_t _bs, WindowType _wt); - - // From plugin defaults: - ExecutionContext(int _c, const Vamp::PluginBase *_plugin); - - bool operator==(const ExecutionContext &); - - void makeConsistentWithPlugin(const Vamp::PluginBase *_plugin); - - int channel; - Vamp::Plugin::InputDomain domain; - size_t stepSize; - size_t blockSize; - WindowType windowType; - size_t startFrame; - size_t duration; // 0 -> whole thing - float sampleRate; // 0 -> model's rate - bool updates; - }; - -protected: - PluginTransformer(Model *inputModel, - const ExecutionContext &context); - - ExecutionContext m_context; -}; - -#endif
--- a/plugin/transform/RealTimeEffectModelTransformer.cpp Fri Nov 30 17:31:09 2007 +0000 +++ b/plugin/transform/RealTimeEffectModelTransformer.cpp Fri Dec 07 16:47:31 2007 +0000 @@ -25,22 +25,23 @@ #include "data/model/WritableWaveFileModel.h" #include "data/model/WaveFileModel.h" +#include "TransformFactory.h" + #include <iostream> -RealTimeEffectModelTransformer::RealTimeEffectModelTransformer(Model *inputModel, - QString pluginId, - const ExecutionContext &context, - QString configurationXml, - QString units, - int output) : - PluginTransformer(inputModel, context), - m_pluginId(pluginId), - m_configurationXml(configurationXml), - m_units(units), - m_plugin(0), - m_outputNo(output) +RealTimeEffectModelTransformer::RealTimeEffectModelTransformer(Input in, + const Transform &transform) : + ModelTransformer(in, transform), + m_plugin(0) { - if (!m_context.blockSize) m_context.blockSize = 1024; + m_units = TransformFactory::getInstance()->getTransformUnits + (transform.getIdentifier()); + m_outputNo = + (transform.getOutput() == "A") ? -1 : transform.getOutput().toInt(); + + QString pluginId = transform.getPluginIdentifier(); + + if (!m_transform.getBlockSize()) m_transform.setBlockSize(1024); // std::cerr << "RealTimeEffectModelTransformer::RealTimeEffectModelTransformer: plugin " << pluginId.toStdString() << ", output " << output << std::endl; @@ -53,12 +54,12 @@ return; } - DenseTimeValueModel *input = getInput(); + DenseTimeValueModel *input = getConformingInput(); if (!input) return; m_plugin = factory->instantiatePlugin(pluginId, 0, 0, - m_input->getSampleRate(), - m_context.blockSize, + input->getSampleRate(), + m_transform.getBlockSize(), input->getChannelCount()); if (!m_plugin) { @@ -67,9 +68,7 @@ return; } - if (configurationXml != "") { - PluginXml(m_plugin).setParametersFromXml(configurationXml); - } + TransformFactory::getInstance()->setPluginParameters(m_transform, m_plugin); if (m_outputNo >= 0 && m_outputNo >= int(m_plugin->getControlOutputCount())) { @@ -92,9 +91,9 @@ } else { SparseTimeValueModel *model = new SparseTimeValueModel - (input->getSampleRate(), m_context.blockSize, 0.0, 0.0, false); + (input->getSampleRate(), m_transform.getBlockSize(), 0.0, 0.0, false); - if (units != "") model->setScaleUnits(units); + if (m_units != "") model->setScaleUnits(m_units); m_output = model; } @@ -106,12 +105,12 @@ } DenseTimeValueModel * -RealTimeEffectModelTransformer::getInput() +RealTimeEffectModelTransformer::getConformingInput() { DenseTimeValueModel *dtvm = dynamic_cast<DenseTimeValueModel *>(getInputModel()); if (!dtvm) { - std::cerr << "RealTimeEffectModelTransformer::getInput: WARNING: Input model is not conformable to DenseTimeValueModel" << std::endl; + std::cerr << "RealTimeEffectModelTransformer::getConformingInput: WARNING: Input model is not conformable to DenseTimeValueModel" << std::endl; } return dtvm; } @@ -119,7 +118,7 @@ void RealTimeEffectModelTransformer::run() { - DenseTimeValueModel *input = getInput(); + DenseTimeValueModel *input = getConformingInput(); if (!input) return; while (!input->isReady()) { @@ -136,17 +135,23 @@ size_t sampleRate = input->getSampleRate(); size_t channelCount = input->getChannelCount(); - if (!wwfm && m_context.channel != -1) channelCount = 1; + if (!wwfm && m_input.getChannel() != -1) channelCount = 1; long blockSize = m_plugin->getBufferSize(); float **inbufs = m_plugin->getAudioInputBuffers(); - long startFrame = m_input->getStartFrame(); - long endFrame = m_input->getEndFrame(); + long startFrame = m_input.getModel()->getStartFrame(); + long endFrame = m_input.getModel()->getEndFrame(); - long contextStart = m_context.startFrame; - long contextDuration = m_context.duration; + RealTime contextStartRT = m_transform.getStartTime(); + RealTime contextDurationRT = m_transform.getDuration(); + + long contextStart = + RealTime::realTime2Frame(contextStartRT, sampleRate); + + long contextDuration = + RealTime::realTime2Frame(contextDurationRT, sampleRate); if (contextStart == 0 || contextStart < startFrame) { contextStart = startFrame; @@ -179,7 +184,7 @@ if (channelCount == 1) { if (inbufs && inbufs[0]) { got = input->getData - (m_context.channel, blockFrame, blockSize, inbufs[0]); + (m_input.getChannel(), blockFrame, blockSize, inbufs[0]); while (got < blockSize) { inbufs[0][got++] = 0.0; }
--- a/plugin/transform/RealTimeEffectModelTransformer.h Fri Nov 30 17:31:09 2007 +0000 +++ b/plugin/transform/RealTimeEffectModelTransformer.h Fri Dec 07 16:47:31 2007 +0000 @@ -16,34 +16,27 @@ #ifndef _REAL_TIME_PLUGIN_TRANSFORMER_H_ #define _REAL_TIME_PLUGIN_TRANSFORMER_H_ -#include "PluginTransformer.h" +#include "ModelTransformer.h" #include "plugin/RealTimePluginInstance.h" class DenseTimeValueModel; -class RealTimeEffectModelTransformer : public PluginTransformer +class RealTimeEffectModelTransformer : public ModelTransformer { public: - RealTimeEffectModelTransformer(Model *inputModel, - QString plugin, - const ExecutionContext &context, - QString configurationXml = "", - QString units = "", - int output = -1); // -1 -> audio, 0+ -> data + RealTimeEffectModelTransformer(Input input, + const Transform &transform); virtual ~RealTimeEffectModelTransformer(); protected: virtual void run(); - QString m_pluginId; - QString m_configurationXml; QString m_units; - RealTimePluginInstance *m_plugin; int m_outputNo; // just casts - DenseTimeValueModel *getInput(); + DenseTimeValueModel *getConformingInput(); }; #endif
--- a/plugin/transform/Transform.cpp Fri Nov 30 17:31:09 2007 +0000 +++ b/plugin/transform/Transform.cpp Fri Dec 07 16:47:31 2007 +0000 @@ -19,6 +19,17 @@ #include "plugin/FeatureExtractionPluginFactory.h" +#include <QXmlAttributes> + +#include <QDomDocument> +#include <QDomElement> +#include <QDomNamedNodeMap> +#include <QDomAttr> + +#include <QTextStream> + +#include <iostream> + Transform::Transform() : m_stepSize(0), m_blockSize(0), @@ -27,10 +38,102 @@ { } +Transform::Transform(QString xml) : + m_stepSize(0), + m_blockSize(0), + m_windowType(HanningWindow), + m_sampleRate(0) +{ + QDomDocument doc; + + QString error; + int errorLine; + int errorColumn; + + if (!doc.setContent(xml, false, &error, &errorLine, &errorColumn)) { + std::cerr << "Transform::Transform: Error in parsing XML: " + << error.toStdString() << " at line " << errorLine + << ", column " << errorColumn << std::endl; + std::cerr << "Input follows:" << std::endl; + std::cerr << xml.toStdString() << std::endl; + std::cerr << "Input ends." << std::endl; + return; + } + + QDomElement transformElt = doc.firstChildElement("transform"); + QDomNamedNodeMap attrNodes = transformElt.attributes(); + QXmlAttributes attrs; + + for (unsigned int i = 0; i < attrNodes.length(); ++i) { + QDomAttr attr = attrNodes.item(i).toAttr(); + if (!attr.isNull()) attrs.append(attr.name(), "", "", attr.value()); + } + + setFromXmlAttributes(attrs); + + for (QDomElement paramElt = transformElt.firstChildElement("parameter"); + !paramElt.isNull(); + paramElt = paramElt.nextSiblingElement("parameter")) { + + QDomNamedNodeMap paramAttrs = paramElt.attributes(); + + QDomAttr nameAttr = paramAttrs.namedItem("name").toAttr(); + if (nameAttr.isNull() || nameAttr.value() == "") continue; + + QDomAttr valueAttr = paramAttrs.namedItem("value").toAttr(); + if (valueAttr.isNull() || valueAttr.value() == "") continue; + + setParameter(nameAttr.value(), valueAttr.value().toFloat()); + } + + for (QDomElement configElt = transformElt.firstChildElement("configuration"); + !configElt.isNull(); + configElt = configElt.nextSiblingElement("configuration")) { + + QDomNamedNodeMap configAttrs = configElt.attributes(); + + QDomAttr nameAttr = configAttrs.namedItem("name").toAttr(); + if (nameAttr.isNull() || nameAttr.value() == "") continue; + + QDomAttr valueAttr = configAttrs.namedItem("value").toAttr(); + if (valueAttr.isNull() || valueAttr.value() == "") continue; + + setConfigurationValue(nameAttr.value(), valueAttr.value()); + } +} + Transform::~Transform() { } +bool +Transform::operator==(const Transform &t) +{ + return + m_id == t.m_id && + m_parameters == t.m_parameters && + m_configuration == t.m_configuration && + m_program == t.m_program && + m_stepSize == t.m_stepSize && + m_blockSize == t.m_blockSize && + m_windowType == t.m_windowType && + m_startTime == t.m_startTime && + m_duration == t.m_duration && + m_sampleRate == t.m_sampleRate; +} + +void +Transform::setIdentifier(TransformId id) +{ + m_id = id; +} + +TransformId +Transform::getIdentifier() const +{ + return m_id; +} + QString Transform::createIdentifier(QString type, QString soName, QString label, QString output) @@ -73,8 +176,212 @@ return m_id.section(':', 3); } +const Transform::ParameterMap & +Transform::getParameters() const +{ + return m_parameters; +} + void -Transform::toXml(QTextStream &stream, QString indent, QString extraAttributes) const +Transform::setParameters(const ParameterMap &pm) { + m_parameters = pm; +} + +void +Transform::setParameter(QString name, float value) +{ + std::cerr << "Transform::setParameter(" << name.toStdString() + << ") -> " << value << std::endl; + m_parameters[name] = value; +} + +const Transform::ConfigurationMap & +Transform::getConfiguration() const +{ + return m_configuration; +} + +void +Transform::setConfiguration(const ConfigurationMap &cm) +{ + m_configuration = cm; +} + +void +Transform::setConfigurationValue(QString name, QString value) +{ + std::cerr << "Transform::setConfigurationValue(" << name.toStdString() + << ") -> " << value.toStdString() << std::endl; + m_configuration[name] = value; +} + +QString +Transform::getProgram() const +{ + return m_program; +} + +void +Transform::setProgram(QString program) +{ + m_program = program; +} + +size_t +Transform::getStepSize() const +{ + return m_stepSize; } + +void +Transform::setStepSize(size_t s) +{ + m_stepSize = s; +} + +size_t +Transform::getBlockSize() const +{ + return m_blockSize; +} + +void +Transform::setBlockSize(size_t s) +{ + m_blockSize = s; +} + +WindowType +Transform::getWindowType() const +{ + return m_windowType; +} + +void +Transform::setWindowType(WindowType type) +{ + m_windowType = type; +} + +RealTime +Transform::getStartTime() const +{ + return m_startTime; +} + +void +Transform::setStartTime(RealTime t) +{ + m_startTime = t; +} + +RealTime +Transform::getDuration() const +{ + return m_duration; +} + +void +Transform::setDuration(RealTime d) +{ + m_duration = d; +} + +float +Transform::getSampleRate() const +{ + return m_sampleRate; +} + +void +Transform::setSampleRate(float rate) +{ + m_sampleRate = rate; +} + +void +Transform::toXml(QTextStream &out, QString indent, QString extraAttributes) const +{ + out << indent; + + bool haveContent = true; + if (m_parameters.empty() && m_configuration.empty()) haveContent = false; + + out << QString("<transform id=\"%1\" program=\"%2\" stepSize=\"%3\" blockSize=\"%4\" windowType=\"%5\" startTime=\"%6\" duration=\"%7\" sampleRate=\"%8\" %9") + .arg(encodeEntities(m_id)) + .arg(encodeEntities(m_program)) + .arg(m_stepSize) + .arg(m_blockSize) + .arg(encodeEntities(Window<float>::getNameForType(m_windowType).c_str())) + .arg(encodeEntities(m_startTime.toString().c_str())) + .arg(encodeEntities(m_duration.toString().c_str())) + .arg(m_sampleRate) + .arg(extraAttributes); + + if (haveContent) { + + out << ">\n"; + + for (ParameterMap::const_iterator i = m_parameters.begin(); + i != m_parameters.end(); ++i) { + out << indent << " " + << QString("<parameter name=\"%1\" value=\"%2\"/>\n") + .arg(encodeEntities(i->first)) + .arg(i->second); + } + + for (ConfigurationMap::const_iterator i = m_configuration.begin(); + i != m_configuration.end(); ++i) { + out << indent << " " + << QString("<configuration name=\"%1\" value=\"%2\"/>\n") + .arg(encodeEntities(i->first)) + .arg(encodeEntities(i->second)); + } + + out << indent << "</transform>\n"; + + } else { + + out << "/>\n"; + } +} + +void +Transform::setFromXmlAttributes(const QXmlAttributes &attrs) +{ + if (attrs.value("id") != "") { + setIdentifier(attrs.value("id")); + } + + if (attrs.value("program") != "") { + setProgram(attrs.value("program")); + } + + if (attrs.value("stepSize") != "") { + setStepSize(attrs.value("stepSize").toInt()); + } + + if (attrs.value("blockSize") != "") { + setBlockSize(attrs.value("blockSize").toInt()); + } + + if (attrs.value("windowType") != "") { + setWindowType(Window<float>::getTypeForName + (attrs.value("windowType").toStdString())); + } + + if (attrs.value("startTime") != "") { + setStartTime(RealTime::fromString(attrs.value("startTime").toStdString())); + } + + if (attrs.value("duration") != "") { + setStartTime(RealTime::fromString(attrs.value("duration").toStdString())); + } + + if (attrs.value("sampleRate") != "") { + setSampleRate(attrs.value("sampleRate").toFloat()); + } +} +
--- a/plugin/transform/Transform.h Fri Nov 30 17:31:09 2007 +0000 +++ b/plugin/transform/Transform.h Fri Dec 07 16:47:31 2007 +0000 @@ -18,13 +18,14 @@ #include "base/XmlExportable.h" #include "base/Window.h" - -#include <vamp-sdk/RealTime.h> +#include "base/RealTime.h" #include <QString> typedef QString TransformId; +class QXmlAttributes; + namespace Vamp { class PluginBase; } @@ -32,11 +33,32 @@ class Transform : public XmlExportable { public: + /** + * Construct a new Transform with default data and no identifier. + * The Transform object will be meaningless until some data and an + * identifier have been set on it. + * + * To construct a Transform for use with a particular transform + * identifier, use TransformFactory::getDefaultTransformFor. + */ Transform(); + + /** + * Construct a Transform by parsing the given XML data string. + * This is the inverse of toXml. + */ + Transform(QString xml); + virtual ~Transform(); - void setIdentifier(TransformId id) { m_id = id; } - TransformId getIdentifier() const { return m_id; } + /** + * Compare two Transforms. They only compare equal if every data + * element matches. + */ + bool operator==(const Transform &); + + void setIdentifier(TransformId id); + TransformId getIdentifier() const; void setPlugin(QString pluginIdentifier); void setOutput(QString output); @@ -49,39 +71,47 @@ typedef std::map<QString, float> ParameterMap; - ParameterMap getParameters() const { return m_parameters; } - void setParameters(const ParameterMap &pm) { m_parameters = pm; } + const ParameterMap &getParameters() const; + void setParameters(const ParameterMap &pm); + void setParameter(QString name, float value); typedef std::map<QString, QString> ConfigurationMap; - ConfigurationMap getConfiguration() const { return m_configuration; } - void setConfiguration(const ConfigurationMap &cm) { m_configuration = cm; } + const ConfigurationMap &getConfiguration() const; + void setConfiguration(const ConfigurationMap &cm); + void setConfigurationValue(QString name, QString value); - QString getProgram() const { return m_program; } - void setProgram(QString program) { m_program = program; } + QString getProgram() const; + void setProgram(QString program); - size_t getStepSize() const { return m_stepSize; } - void setStepSize(size_t s) { m_stepSize = s; } + size_t getStepSize() const; + void setStepSize(size_t s); - size_t getBlockSize() const { return m_blockSize; } - void setBlockSize(size_t s) { m_blockSize = s; } - - WindowType getWindowType() const { return m_windowType; } - void setWindowType(WindowType type) { m_windowType = type; } - - Vamp::RealTime getStartTime() const { return m_startTime; } - void setStartTime(Vamp::RealTime t) { m_startTime = t; } - - Vamp::RealTime getDuration() const { return m_duration; } // 0 -> all - void setDuration(Vamp::RealTime d) { m_duration = d; } + size_t getBlockSize() const; + void setBlockSize(size_t s); - float getSampleRate() const { return m_sampleRate; } // 0 -> as input - void setSampleRate(float rate) { m_sampleRate = rate; } + WindowType getWindowType() const; + void setWindowType(WindowType type); + + RealTime getStartTime() const; + void setStartTime(RealTime t); + + RealTime getDuration() const; // 0 -> all + void setDuration(RealTime d); + + float getSampleRate() const; // 0 -> as input + void setSampleRate(float rate); void toXml(QTextStream &stream, QString indent = "", QString extraAttributes = "") const; - static Transform fromXmlString(QString xml); + /** + * Set the main transform data from the given XML attributes. + * This does not set the parameters or configuration, which are + * exported to separate XML elements rather than attributes of the + * transform element. + */ + void setFromXmlAttributes(const QXmlAttributes &); protected: TransformId m_id; // pluginid:output, that is type:soname:label:output @@ -99,8 +129,8 @@ size_t m_stepSize; size_t m_blockSize; WindowType m_windowType; - Vamp::RealTime m_startTime; - Vamp::RealTime m_duration; + RealTime m_startTime; + RealTime m_duration; float m_sampleRate; };
--- a/plugin/transform/TransformDescription.h Fri Nov 30 17:31:09 2007 +0000 +++ b/plugin/transform/TransformDescription.h Fri Dec 07 16:47:31 2007 +0000 @@ -37,6 +37,10 @@ * The friendly name is a shorter version of the name. * * The type is also intended to be user-readable, for use in menus. + * + * To obtain these objects, use + * TransformFactory::getAllTransformDescriptions and + * TransformFactory::getTransformDescription. */ struct TransformDescription
--- a/plugin/transform/TransformFactory.cpp Fri Nov 30 17:31:09 2007 +0000 +++ b/plugin/transform/TransformFactory.cpp Fri Dec 07 16:47:31 2007 +0000 @@ -28,6 +28,7 @@ #include <set> #include <QRegExp> +#include <QTextStream> TransformFactory * TransformFactory::m_instance = new TransformFactory; @@ -43,7 +44,7 @@ } TransformList -TransformFactory::getAllTransforms() +TransformFactory::getAllTransformDescriptions() { if (m_transforms.empty()) populateTransforms(); @@ -62,6 +63,18 @@ return list; } +TransformDescription +TransformFactory::getTransformDescription(TransformId id) +{ + if (m_transforms.empty()) populateTransforms(); + + if (m_transforms.find(id) == m_transforms.end()) { + return TransformDescription(); + } + + return m_transforms[id]; +} + std::vector<QString> TransformFactory::getAllTransformTypes() { @@ -217,7 +230,7 @@ } Vamp::Plugin *plugin = - factory->instantiatePlugin(pluginId, 48000); + factory->instantiatePlugin(pluginId, 44100); if (!plugin) { std::cerr << "WARNING: TransformFactory::populateTransforms: Failed to instantiate plugin " << pluginId.toLocal8Bit().data() << std::endl; @@ -423,6 +436,71 @@ } } + +Transform +TransformFactory::getDefaultTransformFor(TransformId id, size_t rate) +{ + Transform t; + t.setIdentifier(id); + if (rate != 0) t.setSampleRate(rate); + + Vamp::PluginBase *plugin = instantiatePluginFor(id, rate); + + if (plugin) { + setParametersFromPlugin(t, plugin); + makeContextConsistentWithPlugin(t, plugin); + delete plugin; + } + + return t; +} + +Vamp::PluginBase * +TransformFactory::instantiatePluginFor(TransformId identifier, size_t rate) +{ + Transform t; + t.setIdentifier(identifier); + if (rate == 0) rate = 44100; + QString pluginId = t.getPluginIdentifier(); + + Vamp::PluginBase *plugin = 0; + + if (t.getType() == Transform::FeatureExtraction) { + + FeatureExtractionPluginFactory *factory = + FeatureExtractionPluginFactory::instanceFor(pluginId); + + plugin = factory->instantiatePlugin(pluginId, rate); + + } else { + + RealTimePluginFactory *factory = + RealTimePluginFactory::instanceFor(pluginId); + + plugin = factory->instantiatePlugin(pluginId, 0, 0, rate, 1024, 1); + } + + return plugin; +} + +Vamp::Plugin * +TransformFactory::downcastVampPlugin(Vamp::PluginBase *plugin) +{ + Vamp::Plugin *vp = dynamic_cast<Vamp::Plugin *>(plugin); + if (!vp) { +// std::cerr << "makeConsistentWithPlugin: not a Vamp::Plugin" << std::endl; + vp = dynamic_cast<Vamp::PluginHostAdapter *>(plugin); //!!! why? +} + if (!vp) { +// std::cerr << "makeConsistentWithPlugin: not a Vamp::PluginHostAdapter" << std::endl; + vp = dynamic_cast<Vamp::HostExt::PluginWrapper *>(plugin); //!!! no, I mean really why? + } + if (!vp) { +// std::cerr << "makeConsistentWithPlugin: not a Vamp::HostExt::PluginWrapper" << std::endl; + } + return vp; +} + bool TransformFactory::haveTransform(TransformId identifier) { @@ -454,6 +532,28 @@ } else return ""; } +Vamp::Plugin::InputDomain +TransformFactory::getTransformInputDomain(TransformId identifier) +{ + Transform transform; + transform.setIdentifier(identifier); + + if (transform.getType() != Transform::FeatureExtraction) { + return Vamp::Plugin::TimeDomain; + } + + Vamp::Plugin *plugin = + downcastVampPlugin(instantiatePluginFor(identifier, 0)); + + if (plugin) { + Vamp::Plugin::InputDomain d = plugin->getInputDomain(); + delete plugin; + return d; + } + + return Vamp::Plugin::TimeDomain; +} + bool TransformFactory::isTransformConfigurable(TransformId identifier) { @@ -472,7 +572,7 @@ Vamp::Plugin *plugin = FeatureExtractionPluginFactory::instanceFor(id)-> - instantiatePlugin(id, 48000); + instantiatePlugin(id, 44100); if (!plugin) return false; min = plugin->getMinChannelCount(); @@ -483,6 +583,8 @@ } else if (RealTimePluginFactory::instanceFor(id)) { + // don't need to instantiate + const RealTimePluginDescriptor *descriptor = RealTimePluginFactory::instanceFor(id)-> getPluginDescriptor(id); @@ -503,6 +605,10 @@ { Transform::ParameterMap pmap; + //!!! record plugin & API version + + //!!! check that this is the right plugin! + Vamp::PluginBase::ParameterList parameters = plugin->getParameterDescriptors(); @@ -539,21 +645,48 @@ } void +TransformFactory::setPluginParameters(const Transform &transform, + Vamp::PluginBase *plugin) +{ + //!!! check plugin & API version (see e.g. PluginXml::setParameters) + + //!!! check that this is the right plugin! + + RealTimePluginInstance *rtpi = + dynamic_cast<RealTimePluginInstance *>(plugin); + + if (rtpi) { + const Transform::ConfigurationMap &cmap = transform.getConfiguration(); + for (Transform::ConfigurationMap::const_iterator i = cmap.begin(); + i != cmap.end(); ++i) { + rtpi->configure(i->first.toStdString(), i->second.toStdString()); + } + } + + if (transform.getProgram() != "") { + plugin->selectProgram(transform.getProgram().toStdString()); + } + + const Transform::ParameterMap &pmap = transform.getParameters(); + + Vamp::PluginBase::ParameterList parameters = + plugin->getParameterDescriptors(); + + for (Vamp::PluginBase::ParameterList::const_iterator i = parameters.begin(); + i != parameters.end(); ++i) { + QString key = i->identifier.c_str(); + Transform::ParameterMap::const_iterator pmi = pmap.find(key); + if (pmi != pmap.end()) { + plugin->setParameter(i->identifier, pmi->second); + } + } +} + +void TransformFactory::makeContextConsistentWithPlugin(Transform &transform, Vamp::PluginBase *plugin) { - const Vamp::Plugin *vp = dynamic_cast<const Vamp::Plugin *>(plugin); - if (!vp) { -// std::cerr << "makeConsistentWithPlugin: not a Vamp::Plugin" << std::endl; - vp = dynamic_cast<const Vamp::PluginHostAdapter *>(plugin); //!!! why? -} - if (!vp) { -// std::cerr << "makeConsistentWithPlugin: not a Vamp::PluginHostAdapter" << std::endl; - vp = dynamic_cast<const Vamp::HostExt::PluginWrapper *>(plugin); //!!! no, I mean really why? - } - if (!vp) { -// std::cerr << "makeConsistentWithPlugin: not a Vamp::HostExt::PluginWrapper" << std::endl; - } + const Vamp::Plugin *vp = downcastVampPlugin(plugin); if (!vp) { // time domain input for real-time effects plugin @@ -586,49 +719,40 @@ } } -Transform -TransformFactory::getDefaultTransformFor(TransformId id, size_t rate) +QString +TransformFactory::getPluginConfigurationXml(const Transform &t) { - Transform t; - t.setIdentifier(id); - - if (rate == 0) { - rate = 44100; - } else { - t.setSampleRate(rate); + QString xml; + + Vamp::PluginBase *plugin = instantiatePluginFor(t.getIdentifier(), 0); + if (!plugin) { + std::cerr << "TransformFactory::getPluginConfigurationXml: " + << "Unable to instantiate plugin for transform \"" + << t.getIdentifier().toStdString() << "\"" << std::endl; + return xml; } - QString pluginId = t.getPluginIdentifier(); + QTextStream out(&xml); + PluginXml(plugin).toXml(out); + delete plugin; - if (t.getType() == Transform::FeatureExtraction) { + return xml; +} - FeatureExtractionPluginFactory *factory = - FeatureExtractionPluginFactory::instanceFor(pluginId); - - Vamp::Plugin *plugin = factory->instantiatePlugin - (pluginId, rate); - - if (plugin) { - setParametersFromPlugin(t, plugin); - makeContextConsistentWithPlugin(t, plugin); - delete plugin; - } - - } else { - - RealTimePluginFactory *factory = - RealTimePluginFactory::instanceFor(pluginId); - - RealTimePluginInstance *plugin = factory->instantiatePlugin - (pluginId, 0, 0, rate, 1024, 1); - - if (plugin) { - setParametersFromPlugin(t, plugin); - makeContextConsistentWithPlugin(t, plugin); - delete plugin; - } +void +TransformFactory::setParametersFromPluginConfigurationXml(Transform &t, + QString xml) +{ + Vamp::PluginBase *plugin = instantiatePluginFor(t.getIdentifier(), 0); + if (!plugin) { + std::cerr << "TransformFactory::setParametersFromPluginConfigurationXml: " + << "Unable to instantiate plugin for transform \"" + << t.getIdentifier().toStdString() << "\"" << std::endl; + return; } - return t; + PluginXml(plugin).setParametersFromXml(xml); + setParametersFromPlugin(t, plugin); + delete plugin; }
--- a/plugin/transform/TransformFactory.h Fri Nov 30 17:31:09 2007 +0000 +++ b/plugin/transform/TransformFactory.h Fri Dec 07 16:47:31 2007 +0000 @@ -18,11 +18,11 @@ #include "TransformDescription.h" +#include <vamp-sdk/Plugin.h> + #include <map> #include <set> -namespace Vamp { class PluginBase; } - class TransformFactory : public QObject { Q_OBJECT @@ -32,10 +32,10 @@ static TransformFactory *getInstance(); - TransformList getAllTransforms(); + TransformList getAllTransformDescriptions(); + TransformDescription getTransformDescription(TransformId id); std::vector<QString> getAllTransformTypes(); - std::vector<QString> getTransformCategories(QString transformType); std::vector<QString> getTransformMakers(QString transformType); @@ -45,6 +45,13 @@ bool haveTransform(TransformId identifier); /** + * A single transform ID can lead to many possible Transforms, + * with different parameters and execution context settings. + * Return the default one for the given transform. + */ + Transform getDefaultTransformFor(TransformId identifier, size_t rate = 0); + + /** * Full name of a transform, suitable for putting on a menu. */ QString getTransformName(TransformId identifier); @@ -57,6 +64,8 @@ QString getTransformUnits(TransformId identifier); + Vamp::Plugin::InputDomain getTransformInputDomain(TransformId identifier); + /** * Return true if the transform has any configurable parameters, * i.e. if getConfigurationForTransform can ever return a non-trivial @@ -82,6 +91,12 @@ void setParametersFromPlugin(Transform &transform, Vamp::PluginBase *plugin); /** + * Set the parameters, program and configuration strings on the + * given plugin from the given Transform object. + */ + void setPluginParameters(const Transform &transform, Vamp::PluginBase *plugin); + + /** * If the given Transform object has no processing step and block * sizes set, set them to appropriate defaults for the given * plugin. @@ -89,11 +104,27 @@ void makeContextConsistentWithPlugin(Transform &transform, Vamp::PluginBase *plugin); /** - * A single transform ID can lead to many possible Transforms, - * with different parameters and execution context settings. - * Return the default one for the given transform. + * Retrieve a <plugin ... /> XML fragment that describes the + * plugin parameters, program and configuration data for the given + * transform. + * + * This function is provided for backward compatibility only. Use + * Transform::toXml where compatibility with PluginXml + * descriptions of transforms is not required. */ - Transform getDefaultTransformFor(TransformId identifier, size_t rate = 0); + QString getPluginConfigurationXml(const Transform &transform); + + /** + * Set the plugin parameters, program and configuration strings on + * the given Transform object from the given <plugin ... /> XML + * fragment. + * + * This function is provided for backward compatibility only. Use + * Transform(QString) where compatibility with PluginXml + * descriptions of transforms is not required. + */ + void setParametersFromPluginConfigurationXml(Transform &transform, + QString xml); protected: typedef std::map<TransformId, TransformDescription> TransformDescriptionMap; @@ -103,6 +134,9 @@ void populateFeatureExtractionPlugins(TransformDescriptionMap &); void populateRealTimePlugins(TransformDescriptionMap &); + Vamp::PluginBase *instantiatePluginFor(TransformId id, size_t rate); + Vamp::Plugin *downcastVampPlugin(Vamp::PluginBase *); + static TransformFactory *m_instance; };