Chris@320: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@320: Chris@320: /* Chris@320: Sonic Visualiser Chris@320: An audio file viewer and annotation editor. Chris@320: Centre for Digital Music, Queen Mary, University of London. Chris@320: This file copyright 2006 Chris Cannam and QMUL. Chris@320: Chris@320: This program is free software; you can redistribute it and/or Chris@320: modify it under the terms of the GNU General Public License as Chris@320: published by the Free Software Foundation; either version 2 of the Chris@320: License, or (at your option) any later version. See the file Chris@320: COPYING included with this distribution for more information. Chris@320: */ Chris@320: Chris@331: #include "ModelTransformerFactory.h" Chris@320: Chris@331: #include "FeatureExtractionModelTransformer.h" Chris@331: #include "RealTimeEffectModelTransformer.h" Chris@320: Chris@332: #include "TransformFactory.h" Chris@332: Chris@389: #include "base/AudioPlaySource.h" Chris@389: Chris@320: #include "plugin/FeatureExtractionPluginFactory.h" Chris@320: #include "plugin/RealTimePluginFactory.h" Chris@320: #include "plugin/PluginXml.h" Chris@320: Chris@320: #include "data/model/DenseTimeValueModel.h" Chris@320: Chris@475: #include Chris@320: Chris@320: #include Chris@320: #include Chris@320: Chris@320: #include Chris@320: Chris@850: using std::vector; Chris@850: Chris@331: ModelTransformerFactory * Chris@331: ModelTransformerFactory::m_instance = new ModelTransformerFactory; Chris@320: Chris@331: ModelTransformerFactory * Chris@331: ModelTransformerFactory::getInstance() Chris@320: { Chris@320: return m_instance; Chris@320: } Chris@320: Chris@331: ModelTransformerFactory::~ModelTransformerFactory() Chris@320: { Chris@320: } Chris@320: Chris@350: ModelTransformer::Input Chris@350: ModelTransformerFactory::getConfigurationForTransform(Transform &transform, Chris@350: const std::vector &candidateInputModels, Chris@350: Model *defaultInputModel, Chris@389: AudioPlaySource *source, Chris@930: int startFrame, Chris@930: int duration, Chris@653: UserConfigurator *configurator) Chris@320: { Chris@350: ModelTransformer::Input input(0); Chris@350: Chris@350: if (candidateInputModels.empty()) return input; Chris@320: Chris@320: //!!! This will need revision -- we'll have to have a callback Chris@320: //from the dialog for when the candidate input model is changed, Chris@320: //as we'll need to reinitialise the channel settings in the dialog Chris@345: Model *inputModel = candidateInputModels[0]; Chris@320: QStringList candidateModelNames; Chris@345: QString defaultModelName; Chris@653: QMap modelMap; Chris@930: for (int i = 0; i < (int)candidateInputModels.size(); ++i) { Chris@320: QString modelName = candidateInputModels[i]->objectName(); Chris@320: QString origModelName = modelName; Chris@320: int dupcount = 1; Chris@653: while (modelMap.contains(modelName)) { Chris@320: modelName = tr("%1 <%2>").arg(origModelName).arg(++dupcount); Chris@320: } Chris@320: modelMap[modelName] = candidateInputModels[i]; Chris@320: candidateModelNames.push_back(modelName); Chris@345: if (candidateInputModels[i] == defaultInputModel) { Chris@345: defaultModelName = modelName; Chris@345: } Chris@320: } Chris@320: Chris@350: QString id = transform.getPluginIdentifier(); Chris@320: Chris@653: bool ok = true; Chris@350: QString configurationXml = m_lastConfigurations[transform.getIdentifier()]; Chris@320: Chris@843: cerr << "last configuration: " << configurationXml << endl; Chris@320: Chris@320: Vamp::PluginBase *plugin = 0; Chris@320: Chris@320: if (FeatureExtractionPluginFactory::instanceFor(id)) { Chris@320: Chris@843: cerr << "getConfigurationForTransform: instantiating Vamp plugin" << endl; Chris@320: Chris@320: Vamp::Plugin *vp = Chris@320: FeatureExtractionPluginFactory::instanceFor(id)->instantiatePlugin Chris@320: (id, inputModel->getSampleRate()); Chris@320: Chris@653: plugin = vp; Chris@320: Chris@320: } else if (RealTimePluginFactory::instanceFor(id)) { Chris@320: Chris@320: RealTimePluginFactory *factory = RealTimePluginFactory::instanceFor(id); Chris@320: Chris@930: int sampleRate = inputModel->getSampleRate(); Chris@930: int blockSize = 1024; Chris@930: int channels = 1; Chris@653: if (source) { Chris@320: sampleRate = source->getTargetSampleRate(); Chris@320: blockSize = source->getTargetBlockSize(); Chris@320: channels = source->getTargetChannelCount(); Chris@320: } Chris@320: Chris@320: RealTimePluginInstance *rtp = factory->instantiatePlugin Chris@320: (id, 0, 0, sampleRate, blockSize, channels); Chris@320: Chris@320: plugin = rtp; Chris@320: } Chris@320: Chris@320: if (plugin) { Chris@320: Chris@350: // Ensure block size etc are valid Chris@350: TransformFactory::getInstance()-> Chris@350: makeContextConsistentWithPlugin(transform, plugin); Chris@320: Chris@350: // Prepare the plugin with any existing parameters already Chris@350: // found in the transform Chris@350: TransformFactory::getInstance()-> Chris@350: setPluginParameters(transform, plugin); Chris@350: Chris@350: // For this interactive usage, we want to override those with Chris@350: // whatever the user chose last time around Chris@350: PluginXml(plugin).setParametersFromXml(configurationXml); Chris@320: Chris@653: if (configurator) { Chris@653: ok = configurator->configure(input, transform, plugin, Chris@653: inputModel, source, Chris@653: startFrame, duration, Chris@653: modelMap, Chris@653: candidateModelNames, Chris@653: defaultModelName); Chris@320: } Chris@320: Chris@516: Chris@350: TransformFactory::getInstance()-> Chris@350: makeContextConsistentWithPlugin(transform, plugin); Chris@350: Chris@350: configurationXml = PluginXml(plugin).toXmlString(); Chris@320: Chris@653: delete plugin; Chris@320: } Chris@320: Chris@350: if (ok) { Chris@350: m_lastConfigurations[transform.getIdentifier()] = configurationXml; Chris@350: input.setModel(inputModel); Chris@350: } Chris@320: Chris@350: return input; Chris@320: } Chris@320: Chris@331: ModelTransformer * Chris@850: ModelTransformerFactory::createTransformer(const Transforms &transforms, Chris@350: const ModelTransformer::Input &input) Chris@320: { Chris@331: ModelTransformer *transformer = 0; Chris@320: Chris@850: QString id = transforms[0].getPluginIdentifier(); Chris@320: Chris@320: if (FeatureExtractionPluginFactory::instanceFor(id)) { Chris@350: Chris@350: transformer = Chris@859: new FeatureExtractionModelTransformer(input, transforms); Chris@350: Chris@331: } else if (RealTimePluginFactory::instanceFor(id)) { Chris@350: Chris@350: transformer = Chris@850: new RealTimeEffectModelTransformer(input, transforms[0]); Chris@350: Chris@320: } else { Chris@690: SVDEBUG << "ModelTransformerFactory::createTransformer: Unknown transform \"" Chris@850: << transforms[0].getIdentifier() << "\"" << endl; Chris@331: return transformer; Chris@320: } Chris@320: Chris@850: if (transformer) transformer->setObjectName(transforms[0].getIdentifier()); Chris@331: return transformer; Chris@320: } Chris@320: Chris@320: Model * Chris@350: ModelTransformerFactory::transform(const Transform &transform, Chris@361: const ModelTransformer::Input &input, Chris@877: QString &message, Chris@877: AdditionalModelHandler *handler) Chris@320: { Chris@690: SVDEBUG << "ModelTransformerFactory::transform: Constructing transformer with input model " << input.getModel() << endl; Chris@408: Chris@850: Transforms transforms; Chris@850: transforms.push_back(transform); Chris@877: vector mm = transformMultiple(transforms, input, message, handler); Chris@850: if (mm.empty()) return 0; Chris@850: else return mm[0]; Chris@320: } Chris@320: Chris@849: vector Chris@849: ModelTransformerFactory::transformMultiple(const Transforms &transforms, Chris@849: const ModelTransformer::Input &input, Chris@877: QString &message, Chris@877: AdditionalModelHandler *handler) Chris@849: { Chris@849: SVDEBUG << "ModelTransformerFactory::transformMultiple: Constructing transformer with input model " << input.getModel() << endl; Chris@849: Chris@849: ModelTransformer *t = createTransformer(transforms, input); Chris@850: if (!t) return vector(); Chris@849: Chris@877: if (handler) { Chris@877: m_handlers[t] = handler; Chris@877: } Chris@849: Chris@849: m_runningTransformers.insert(t); Chris@849: Chris@877: connect(t, SIGNAL(finished()), this, SLOT(transformerFinished())); Chris@877: Chris@849: t->start(); Chris@850: vector models = t->detachOutputModels(); Chris@849: Chris@850: if (!models.empty()) { Chris@849: QString imn = input.getModel()->objectName(); Chris@849: QString trn = Chris@849: TransformFactory::getInstance()->getTransformFriendlyName Chris@850: (transforms[0].getIdentifier()); Chris@930: for (int i = 0; i < (int)models.size(); ++i) { Chris@850: if (imn != "") { Chris@850: if (trn != "") { Chris@850: models[i]->setObjectName(tr("%1: %2").arg(imn).arg(trn)); Chris@850: } else { Chris@850: models[i]->setObjectName(imn); Chris@850: } Chris@850: } else if (trn != "") { Chris@850: models[i]->setObjectName(trn); Chris@849: } Chris@849: } Chris@849: } else { Chris@849: t->wait(); Chris@849: } Chris@849: Chris@849: message = t->getMessage(); Chris@849: Chris@850: return models; Chris@849: } Chris@849: Chris@320: void Chris@331: ModelTransformerFactory::transformerFinished() Chris@320: { Chris@320: QObject *s = sender(); Chris@331: ModelTransformer *transformer = dynamic_cast(s); Chris@320: Chris@690: // SVDEBUG << "ModelTransformerFactory::transformerFinished(" << transformer << ")" << endl; Chris@320: Chris@331: if (!transformer) { Chris@843: cerr << "WARNING: ModelTransformerFactory::transformerFinished: sender is not a transformer" << endl; Chris@320: return; Chris@320: } Chris@320: Chris@331: if (m_runningTransformers.find(transformer) == m_runningTransformers.end()) { Chris@843: cerr << "WARNING: ModelTransformerFactory::transformerFinished(" Chris@331: << transformer Chris@331: << "): I have no record of this transformer running!" Chris@843: << endl; Chris@320: } Chris@320: Chris@331: m_runningTransformers.erase(transformer); Chris@320: Chris@877: if (m_handlers.find(transformer) != m_handlers.end()) { Chris@877: if (transformer->willHaveAdditionalOutputModels()) { Chris@877: vector mm = transformer->detachAdditionalOutputModels(); Chris@877: m_handlers[transformer]->moreModelsAvailable(mm); Chris@878: } else { Chris@878: m_handlers[transformer]->noMoreModelsAvailable(); Chris@877: } Chris@877: m_handlers.erase(transformer); Chris@877: } Chris@877: Chris@331: transformer->wait(); // unnecessary but reassuring Chris@331: delete transformer; Chris@320: } Chris@320: Chris@320: void Chris@331: ModelTransformerFactory::modelAboutToBeDeleted(Model *m) Chris@320: { Chris@328: TransformerSet affected; Chris@320: Chris@328: for (TransformerSet::iterator i = m_runningTransformers.begin(); Chris@328: i != m_runningTransformers.end(); ++i) { Chris@320: Chris@331: ModelTransformer *t = *i; Chris@320: Chris@850: if (t->getInputModel() == m) { Chris@320: affected.insert(t); Chris@850: } else { Chris@850: vector mm = t->getOutputModels(); Chris@850: for (int i = 0; i < (int)mm.size(); ++i) { Chris@850: if (mm[i] == m) affected.insert(t); Chris@850: } Chris@320: } Chris@320: } Chris@320: Chris@328: for (TransformerSet::iterator i = affected.begin(); Chris@320: i != affected.end(); ++i) { Chris@320: Chris@331: ModelTransformer *t = *i; Chris@320: Chris@320: t->abandon(); Chris@320: Chris@320: t->wait(); // this should eventually call back on Chris@331: // transformerFinished, which will remove from Chris@328: // m_runningTransformers and delete. Chris@320: } Chris@320: } Chris@320: