# HG changeset patch # User Chris Cannam # Date 1143049109 0 # Node ID 2157fa46c1e74f5cba1ddb4b2f5ca25e24b5e00f # Parent 6befca60ab4e614bce8fe232112821e71d770b34 * Add plugin parameter dialog, and use it to set up parameters for feature extraction plugins via a semi-opaque (translucent?) configurationXml string which is associated with a given transform instance. This is not yet saved to and restored from the SV file properly. * Remove no-longer-relevant BeatDetect and BeatDetectionFunction transforms (replaced a long time ago with the beat detector plugin). diff -r 6befca60ab4e -r 2157fa46c1e7 plugin/PluginInstance.cpp --- a/plugin/PluginInstance.cpp Wed Mar 22 13:23:50 2006 +0000 +++ b/plugin/PluginInstance.cpp Wed Mar 22 17:38:29 2006 +0000 @@ -18,6 +18,11 @@ #include #include +#include +#include +#include +#include + #include QString @@ -83,17 +88,59 @@ for (ParameterList::const_iterator i = parameters.begin(); i != parameters.end(); ++i) { - QString name = stripInvalidParameterNameCharacters - (QString(i->name.c_str())); + QString name = QString("param-%1") + .arg(stripInvalidParameterNameCharacters + (QString(i->name.c_str()))); bool ok; float value = attrs.value(name).trimmed().toFloat(&ok); if (ok) { setParameter(i->name, value); } else { - std::cerr << "WARNING: PluginInstance::setParameters: Invalid value \"" << attrs.value(name).toStdString() << "\" for parameter \"" << i->name << "\"" << std::endl; + std::cerr << "WARNING: PluginInstance::setParameters: Invalid value \"" << attrs.value(name).toStdString() << "\" for parameter \"" << i->name << "\" (attribute \"" << name.toStdString() << "\")" << std::endl; } } } + +void +PluginInstance::setParametersFromXml(QString xml) +{ + QDomDocument doc; + + QString error; + int errorLine; + int errorColumn; + + if (!doc.setContent(xml, false, &error, &errorLine, &errorColumn)) { + std::cerr << "PluginInstance::setParametersFromXml: 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 pluginElt = doc.firstChildElement("plugin"); + + if (pluginElt.isNull()) { + std::cerr << "pluginElt is null" << std::endl; + pluginElt = doc.documentElement(); + if (pluginElt.isNull()) { + std::cerr << "pluginElt is still null" << std::endl; + } + } + + QDomNamedNodeMap attrNodes = pluginElt.attributes(); + QXmlAttributes attrs; + + for (int i = 0; i < attrNodes.length(); ++i) { + QDomAttr attr = attrNodes.item(i).toAttr(); + if (attr.isNull()) continue; + std::cerr << "Adding attribute \"" << attr.name().toStdString() + << "\" with value \"" << attr.value().toStdString() << "\"" << std::endl; + attrs.append(attr.name(), "", "", attr.value()); + } + + setParameters(attrs); +} QString PluginInstance::stripInvalidParameterNameCharacters(QString s) const diff -r 6befca60ab4e -r 2157fa46c1e7 plugin/PluginInstance.h --- a/plugin/PluginInstance.h Wed Mar 22 13:23:50 2006 +0000 +++ b/plugin/PluginInstance.h Wed Mar 22 17:38:29 2006 +0000 @@ -171,6 +171,13 @@ */ virtual void setParameters(const QXmlAttributes &); + /** + * Set the parameters and program of a plugin from an XML plugin + * element as returned by toXmlString. This is a partial inverse + * of toXmlString. + */ + virtual void setParametersFromXml(QString xml); + protected: QString stripInvalidParameterNameCharacters(QString) const; }; diff -r 6befca60ab4e -r 2157fa46c1e7 transform/BeatDetectTransform.cpp --- a/transform/BeatDetectTransform.cpp Wed Mar 22 13:23:50 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,209 +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 Chris Cannam. - - 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 "BeatDetectTransform.h" - -#include "model/DenseTimeValueModel.h" -#include "model/SparseOneDimensionalModel.h" - -#include -#include "dsp/onsets/DetectionFunction.h" -#include "dsp/tempotracking/TempoTrack.h" - - -BeatDetectTransform::BeatDetectTransform(Model *inputModel) : - Transform(inputModel) -{ - // Step resolution for the detection function in seconds - double stepSecs = 0.01161; - - // Step resolution for the detection function in samples - size_t stepSize = (size_t)floor((double)inputModel->getSampleRate() * - stepSecs); - - -// m_w->m_bdf->setResolution(stepSize); -// output->setResolution(stepSize); - - std::cerr << "BeatDetectTransform::BeatDetectTransform: input sample rate " << inputModel->getSampleRate() << ", stepSecs " << stepSecs << ", stepSize " << stepSize << ", unrounded stepSize " << double(inputModel->getSampleRate()) * stepSecs << ", output sample rate " << inputModel->getSampleRate() / stepSize << ", unrounded output sample rate " << double(inputModel->getSampleRate()) / double(stepSize) << std::endl; - - m_output = new SparseOneDimensionalModel(inputModel->getSampleRate(), 1); -} - -BeatDetectTransform::~BeatDetectTransform() -{ - // parent does it all -} - -TransformName -BeatDetectTransform::getName() -{ - return tr("Beats"); -} - -void -BeatDetectTransform::run() -{ - SparseOneDimensionalModel *output = getOutput(); - DenseTimeValueModel *input = getInput(); - if (!input) return; - - DFConfig config; - - config.DFType = DF_COMPLEXSD; - - // Step resolution for the detection function in seconds - config.stepSecs = 0.01161; - - // Step resolution for the detection function in samples - config.stepSize = (unsigned int)floor((double)input->getSampleRate() * - config.stepSecs ); - - config.frameLength = 2 * config.stepSize; - - unsigned int stepSize = config.stepSize; - unsigned int frameLength = config.frameLength; - -// m_w->m_bdf->setResolution(stepSize); - output->setResolution(stepSize); - - //Tempo Tracking Configuration Parameters - TTParams ttparams; - - // Low Pass filter coefficients for detection function smoothing - double* aCoeffs = new double[3]; - double* bCoeffs = new double[3]; - - aCoeffs[ 0 ] = 1; - aCoeffs[ 1 ] = -0.5949; - aCoeffs[ 2 ] = 0.2348; - bCoeffs[ 0 ] = 0.1600; - bCoeffs[ 1 ] = 0.3200; - bCoeffs[ 2 ] = 0.1600; - - ttparams.winLength = 512; - ttparams.lagLength = 128; - ttparams.LPOrd = 2; - ttparams.LPACoeffs = aCoeffs; - ttparams.LPBCoeffs = bCoeffs; - ttparams.alpha = 9; - ttparams.WinT.post = 8; - ttparams.WinT.pre = 7; - - //////////////////////////////////////////////////////////// - // DetectionFunction - //////////////////////////////////////////////////////////// - // Instantiate and configure detection function object - - DetectionFunction df(config); - - size_t origin = input->getStartFrame(); - size_t frameCount = input->getEndFrame() - origin; - size_t blocks = (frameCount / stepSize); - if (blocks * stepSize < frameCount) ++blocks; - - double *buffer = new double[frameLength]; - - // DF output with causal extension - unsigned int clen = blocks + ttparams.winLength; - double *dfOutput = new double[clen]; - - std::cerr << "Detecting beats at step size " << stepSize << "..." << std::endl; - - for (size_t i = 0; i < clen; ++i) { - -// std::cerr << "block " << i << "/" << clen << std::endl; -// std::cerr << "."; - - if (i < blocks) { - size_t got = input->getValues(-1, //!!! needs to come from parent layer -- which is not supposed to be in scope at this point - origin + i * stepSize, - origin + i * stepSize + frameLength, - buffer); - while (got < frameLength) buffer[got++] = 0.0; - dfOutput[i] = df.process(buffer); - } else { - dfOutput[i] = 0.0; - } - -// m_w->m_bdf->addPoint(SparseTimeValueModel::Point -// (i * stepSize, dfOutput[i], -// QString("%1").arg(dfOutput[i]))); -// m_w->m_bdf->setCompletion(i * 99 / clen); - output->setCompletion(i * 99 / clen); - - if (m_deleting) { - delete [] buffer; - delete [] dfOutput; - delete [] aCoeffs; - delete [] bCoeffs; - return; - } - } - -// m_w->m_bdf->setCompletion(100); - - // Tempo Track Object instantiation and configuration - TempoTrack tempoTracker(ttparams); - - // Vector of detected onsets - vector beats; - - std::cerr << "Running tempo tracker..." << std::endl; - - beats = tempoTracker.process(dfOutput, blocks); - - delete [] buffer; - delete [] dfOutput; - delete [] aCoeffs; - delete [] bCoeffs; - - for (size_t i = 0; i < beats.size(); ++i) { -// std::cerr << "Beat value " << beats[i] << ", multiplying out to " << beats[i] * stepSize << std::endl; - float bpm = 0.0; - int fdiff = 0; - if (i < beats.size() - 1) { - fdiff = (beats[i+1] - beats[i]) * stepSize; - // one beat is fdiff frames, so there are samplerate/fdiff bps, - // so 60*samplerate/fdiff bpm - if (fdiff > 0) { - bpm = (60.0 * input->getSampleRate()) / fdiff; - } - } - output->addPoint(SparseOneDimensionalModel::Point - (origin + beats[i] * stepSize, QString("%1").arg(bpm))); - if (m_deleting) return; - } - - output->setCompletion(100); -} - -DenseTimeValueModel * -BeatDetectTransform::getInput() -{ - DenseTimeValueModel *dtvm = - dynamic_cast(getInputModel()); - if (!dtvm) { - std::cerr << "BeatDetectTransform::getInput: WARNING: Input model is not conformable to DenseTimeValueModel" << std::endl; - } - return dtvm; -} - -SparseOneDimensionalModel * -BeatDetectTransform::getOutput() -{ - return static_cast(getOutputModel()); -} - diff -r 6befca60ab4e -r 2157fa46c1e7 transform/BeatDetectTransform.h --- a/transform/BeatDetectTransform.h Wed Mar 22 13:23:50 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,44 +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 Chris Cannam. - - 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 _BEAT_DETECT_TRANSFORM_H_ -#define _BEAT_DETECT_TRANSFORM_H_ - -#include "Transform.h" - -//!!! This should be replaced by a plugin, when we have a plugin -// transform. But it's easier to start by testing concrete examples. - -class DenseTimeValueModel; -class SparseOneDimensionalModel; - -class BeatDetectTransform : public Transform -{ -public: - BeatDetectTransform(Model *inputModel); - virtual ~BeatDetectTransform(); - - static TransformName getName(); - -protected: - virtual void run(); - - // just casts - DenseTimeValueModel *getInput(); - SparseOneDimensionalModel *getOutput(); -}; - -#endif - diff -r 6befca60ab4e -r 2157fa46c1e7 transform/BeatDetectionFunctionTransform.cpp --- a/transform/BeatDetectionFunctionTransform.cpp Wed Mar 22 13:23:50 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,160 +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 Chris Cannam. - - 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 "BeatDetectionFunctionTransform.h" - -#include "model/DenseTimeValueModel.h" -#include "model/SparseTimeValueModel.h" - -#include -#include "dsp/onsets/DetectionFunction.h" -#include "dsp/tempotracking/TempoTrack.h" - - -BeatDetectionFunctionTransform::BeatDetectionFunctionTransform(Model *inputModel) : - Transform(inputModel) -{ - m_output = new SparseTimeValueModel(inputModel->getSampleRate(), 1, - 0.0, 0.0, false); -} - -BeatDetectionFunctionTransform::~BeatDetectionFunctionTransform() -{ - // parent does it all -} - -TransformName -BeatDetectionFunctionTransform::getName() -{ - return tr("Beat Detection Function"); -} - -void -BeatDetectionFunctionTransform::run() -{ - SparseTimeValueModel *output = getOutput(); - DenseTimeValueModel *input = getInput(); - if (!input) { - std::cerr << "BeatDetectionFunctionTransform::run: WARNING: Input model is not conformable to DenseTimeValueModel" << std::endl; - return; - } - - DFConfig config; - - config.DFType = DF_COMPLEXSD; - - // Step resolution for the detection function in seconds - config.stepSecs = 0.01161; - - // Step resolution for the detection function in samples - config.stepSize = (unsigned int)floor((double)input->getSampleRate() * - config.stepSecs ); - - config.frameLength = 2 * config.stepSize; - - unsigned int stepSize = config.stepSize; - unsigned int frameLength = config.frameLength; - - output->setResolution(stepSize); - - //Tempo Tracking Configuration Parameters - TTParams ttparams; - - // Low Pass filter coefficients for detection function smoothing - double* aCoeffs = new double[3]; - double* bCoeffs = new double[3]; - - aCoeffs[ 0 ] = 1; - aCoeffs[ 1 ] = -0.5949; - aCoeffs[ 2 ] = 0.2348; - bCoeffs[ 0 ] = 0.1600; - bCoeffs[ 1 ] = 0.3200; - bCoeffs[ 2 ] = 0.1600; - - ttparams.winLength = 512; - ttparams.lagLength = 128; - ttparams.LPOrd = 2; - ttparams.LPACoeffs = aCoeffs; - ttparams.LPBCoeffs = bCoeffs; - ttparams.alpha = 9; - ttparams.WinT.post = 8; - ttparams.WinT.pre = 7; - - //////////////////////////////////////////////////////////// - // DetectionFunction - //////////////////////////////////////////////////////////// - // Instantiate and configure detection function object - - DetectionFunction df(config); - - size_t origin = input->getStartFrame(); - size_t frameCount = input->getEndFrame() - origin; - size_t blocks = (frameCount / stepSize); - if (blocks * stepSize < frameCount) ++blocks; - - double *buffer = new double[frameLength]; - - // DF output with causal extension - unsigned int clen = blocks + ttparams.winLength; - double *dfOutput = new double[clen]; - - std::cerr << "Running beat detection function at step size " << stepSize << "..." << std::endl; - - for (size_t i = 0; i < clen; ++i) { - -// std::cerr << "block " << i << "/" << clen << std::endl; -// std::cerr << "."; - - if (i < blocks) { - size_t got = input->getValues(-1, //!!! needs to come from parent layer -- which is not supposed to be in scope at this point - origin + i * stepSize, - origin + i * stepSize + frameLength, - buffer); - while (got < frameLength) buffer[got++] = 0.0; - dfOutput[i] = df.process(buffer); - } else { - dfOutput[i] = 0.0; - } - - output->addPoint(SparseTimeValueModel::Point - (i * stepSize, dfOutput[i], - QString("%1").arg(dfOutput[i]))); -// m_w->m_bdf->setCompletion(i * 99 / clen); - output->setCompletion(i * 99 / clen); - - if (m_deleting) { - delete [] buffer; - delete [] dfOutput; - delete [] aCoeffs; - delete [] bCoeffs; - return; - } - } - - output->setCompletion(100); -} - -DenseTimeValueModel * -BeatDetectionFunctionTransform::getInput() -{ - return dynamic_cast(getInputModel()); -} - -SparseTimeValueModel * -BeatDetectionFunctionTransform::getOutput() -{ - return static_cast(getOutputModel()); -} - diff -r 6befca60ab4e -r 2157fa46c1e7 transform/BeatDetectionFunctionTransform.h --- a/transform/BeatDetectionFunctionTransform.h Wed Mar 22 13:23:50 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,44 +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 Chris Cannam. - - 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 _BEAT_DETECTION_FUNCTION_TRANSFORM_H_ -#define _BEAT_DETECTION_FUNCTION_TRANSFORM_H_ - -#include "Transform.h" - -//!!! This should be replaced by a plugin, when we have a plugin -// transform. But it's easier to start by testing concrete examples. - -class DenseTimeValueModel; -class SparseTimeValueModel; - -class BeatDetectionFunctionTransform : public Transform -{ -public: - BeatDetectionFunctionTransform(Model *inputModel); - virtual ~BeatDetectionFunctionTransform(); - - static TransformName getName(); - -protected: - virtual void run(); - - // just casts - DenseTimeValueModel *getInput(); - SparseTimeValueModel *getOutput(); -}; - -#endif - diff -r 6befca60ab4e -r 2157fa46c1e7 transform/FeatureExtractionPluginTransform.cpp --- a/transform/FeatureExtractionPluginTransform.cpp Wed Mar 22 13:23:50 2006 +0000 +++ b/transform/FeatureExtractionPluginTransform.cpp Wed Mar 22 17:38:29 2006 +0000 @@ -29,6 +29,7 @@ FeatureExtractionPluginTransform::FeatureExtractionPluginTransform(Model *inputModel, QString pluginId, + QString configurationXml, QString outputName) : Transform(inputModel), m_plugin(0), @@ -54,6 +55,10 @@ return; } + if (configurationXml != "") { + m_plugin->setParametersFromXml(configurationXml); + } + FeatureExtractionPlugin::OutputList outputs = m_plugin->getOutputDescriptors(); diff -r 6befca60ab4e -r 2157fa46c1e7 transform/FeatureExtractionPluginTransform.h --- a/transform/FeatureExtractionPluginTransform.h Wed Mar 22 13:23:50 2006 +0000 +++ b/transform/FeatureExtractionPluginTransform.h Wed Mar 22 17:38:29 2006 +0000 @@ -26,6 +26,7 @@ public: FeatureExtractionPluginTransform(Model *inputModel, QString plugin, + QString configurationXml = "", QString outputName = ""); virtual ~FeatureExtractionPluginTransform(); diff -r 6befca60ab4e -r 2157fa46c1e7 transform/TransformFactory.cpp --- a/transform/TransformFactory.cpp Wed Mar 22 13:23:50 2006 +0000 +++ b/transform/TransformFactory.cpp Wed Mar 22 17:38:29 2006 +0000 @@ -15,12 +15,12 @@ #include "TransformFactory.h" -#include "BeatDetectTransform.h" -#include "BeatDetectionFunctionTransform.h" #include "FeatureExtractionPluginTransform.h" #include "plugin/FeatureExtractionPluginFactory.h" +#include "widgets/PluginParameterDialog.h" + #include TransformFactory * @@ -42,9 +42,9 @@ if (m_transforms.empty()) populateTransforms(); TransformList list; - for (TransformMap::const_iterator i = m_transforms.begin(); + for (TransformDescriptionMap::const_iterator i = m_transforms.begin(); i != m_transforms.end(); ++i) { - list.push_back(TransformDesc(i->first, i->second)); + list.push_back(i->second); } return list; @@ -97,7 +97,13 @@ .arg(outputs[j].description.c_str()); } - m_transforms[transformName] = userDescription; + bool configurable = (!plugin->getPrograms().empty() || + !plugin->getParameterDescriptors().empty()); + + m_transforms[transformName] = + TransformDesc(transformName, + userDescription, + configurable); makers[transformName] = plugin->getMaker().c_str(); } @@ -107,22 +113,23 @@ std::map descriptions; - for (TransformMap::iterator i = m_transforms.begin(); i != m_transforms.end(); - ++i) { + for (TransformDescriptionMap::iterator i = m_transforms.begin(); + i != m_transforms.end(); ++i) { - QString name = i->first, description = i->second; + TransformDesc desc = i->second; - ++descriptions[description]; - ++descriptions[QString("%1 [%2]").arg(description).arg(makers[name])]; + ++descriptions[desc.description]; + ++descriptions[QString("%1 [%2]").arg(desc.description).arg(makers[desc.name])]; } std::map counts; - TransformMap newMap; + TransformDescriptionMap newMap; - for (TransformMap::iterator i = m_transforms.begin(); i != m_transforms.end(); - ++i) { + for (TransformDescriptionMap::iterator i = m_transforms.begin(); + i != m_transforms.end(); ++i) { - QString name = i->first, description = i->second; + TransformDesc desc = i->second; + QString name = desc.name, description = desc.description; if (descriptions[description] > 1) { description = QString("%1 [%2]").arg(description).arg(makers[name]); @@ -132,7 +139,8 @@ } } - newMap[name] = description; + desc.description = description; + newMap[name] = desc; } m_transforms = newMap; @@ -142,7 +150,7 @@ TransformFactory::getTransformDescription(TransformName name) { if (m_transforms.find(name) != m_transforms.end()) { - return m_transforms[name]; + return m_transforms[name].description; } else return ""; } @@ -159,32 +167,63 @@ } } -Transform * -TransformFactory::createTransform(TransformName name, Model *inputModel) +bool +TransformFactory::getConfigurationForTransform(TransformName name, + Model *inputModel, + QString &configurationXml) { - return createTransform(name, inputModel, true); + QString id = name.section(':', 0, 2); + QString output = name.section(':', 3); + + bool ok = false; + configurationXml = m_lastConfigurations[name]; + + std::cerr << "last configuration: " << configurationXml.toStdString() << std::endl; + + if (FeatureExtractionPluginFactory::instanceFor(id)) { + FeatureExtractionPlugin *plugin = + FeatureExtractionPluginFactory::instanceFor(id)->instantiatePlugin + (id, inputModel->getSampleRate()); + if (plugin) { + if (configurationXml != "") { + plugin->setParametersFromXml(configurationXml); + } + PluginParameterDialog *dialog = new PluginParameterDialog(plugin); + if (dialog->exec() == QDialog::Accepted) { + ok = true; + } + configurationXml = plugin->toXmlString(); + delete plugin; + } + } + + if (ok) m_lastConfigurations[name] = configurationXml; + + return ok; } Transform * TransformFactory::createTransform(TransformName name, Model *inputModel, - bool start) + QString configurationXml, bool start) { Transform *transform = 0; - if (name == BeatDetectTransform::getName()) { - transform = new BeatDetectTransform(inputModel); - } else if (name == BeatDetectionFunctionTransform::getName()) { - transform = new BeatDetectionFunctionTransform(inputModel); + // The only transform type we support at the moment is the + // FeatureExtractionPluginTransform. In future we may wish to + // support e.g. RealTimePluginTransform for audio->audio or + // audio->midi transforms using standard effects plugins. + + QString id = name.section(':', 0, 2); + QString output = name.section(':', 3); + + if (FeatureExtractionPluginFactory::instanceFor(id)) { + transform = new FeatureExtractionPluginTransform(inputModel, + id, + configurationXml, + output); } else { - QString id = name.section(':', 0, 2); - QString output = name.section(':', 3); - if (FeatureExtractionPluginFactory::instanceFor(id)) { - transform = new FeatureExtractionPluginTransform(inputModel, - id, output); - } else { - std::cerr << "TransformFactory::createTransform: Unknown transform " - << name.toStdString() << std::endl; - } + std::cerr << "TransformFactory::createTransform: Unknown transform " + << name.toStdString() << std::endl; } if (start && transform) transform->start(); @@ -193,9 +232,10 @@ } Model * -TransformFactory::transform(TransformName name, Model *inputModel) +TransformFactory::transform(TransformName name, Model *inputModel, + QString configurationXml) { - Transform *t = createTransform(name, inputModel, false); + Transform *t = createTransform(name, inputModel, configurationXml, false); if (!t) return 0; diff -r 6befca60ab4e -r 2157fa46c1e7 transform/TransformFactory.h --- a/transform/TransformFactory.h Wed Mar 22 13:23:50 2006 +0000 +++ b/transform/TransformFactory.h Wed Mar 22 17:38:29 2006 +0000 @@ -29,23 +29,33 @@ static TransformFactory *instance(); - // The name is intended to be computer-referencable, and unique + // The name is intended to be computer-referenceable, and unique // within the application. The description is intended to be // human readable. In principle it doesn't have to be unique, but // the factory will add suffixes to ensure that it is, all the // same (just to avoid user confusion). struct TransformDesc { - TransformDesc(TransformName _name, QString _description = "") : - name(_name), description(_description) { } + TransformDesc() { } + TransformDesc(TransformName _name, QString _description, bool _configurable) : + name(_name), description(_description), configurable(_configurable) { } TransformName name; QString description; + bool configurable; }; typedef std::vector TransformList; TransformList getAllTransforms(); /** + * Get a configuration XML string for the given transform (by + * asking the user, most likely). Returns true if the transform + * is acceptable, false if the operation should be cancelled. + */ + bool getConfigurationForTransform(TransformName name, Model *inputModel, + QString &configurationXml); + + /** * Return the output model resulting from applying the named * transform to the given input model. The transform may still be * working in the background when the model is returned; check the @@ -58,7 +68,8 @@ * The returned model is owned by the caller and must be deleted * when no longer needed. */ - Model *transform(TransformName name, Model *inputModel); + Model *transform(TransformName name, Model *inputModel, + QString configurationXml = ""); /** * Full description of a transform, suitable for putting on a menu. @@ -82,12 +93,21 @@ void transformFinished(); protected: - Transform *createTransform(TransformName name, Model *inputModel); Transform *createTransform(TransformName name, Model *inputModel, - bool start); + QString configurationXml, bool start); - typedef std::map TransformMap; - TransformMap m_transforms; + struct TransformIdent + { + TransformName name; + QString configurationXml; + }; + + typedef std::map TransformConfigurationMap; + TransformConfigurationMap m_lastConfigurations; + + typedef std::map TransformDescriptionMap; + TransformDescriptionMap m_transforms; + void populateTransforms(); static TransformFactory *m_instance;