diff transform/TransformFactory.cpp @ 0:cd5d7ff8ef38

* Reorganising code base. This revision will not compile.
author Chris Cannam
date Mon, 31 Jul 2006 12:03:45 +0000
parents
children 40116f709d3b
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/transform/TransformFactory.cpp	Mon Jul 31 12:03:45 2006 +0000
@@ -0,0 +1,480 @@
+/* -*- 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 "TransformFactory.h"
+
+#include "FeatureExtractionPluginTransform.h"
+#include "RealTimePluginTransform.h"
+
+#include "plugin/FeatureExtractionPluginFactory.h"
+#include "plugin/RealTimePluginFactory.h"
+#include "plugin/PluginXml.h"
+
+#include "widgets/PluginParameterDialog.h"
+
+#include "model/DenseTimeValueModel.h"
+
+#include <iostream>
+#include <set>
+
+#include <QRegExp>
+
+TransformFactory *
+TransformFactory::m_instance = new TransformFactory;
+
+TransformFactory *
+TransformFactory::getInstance()
+{
+    return m_instance;
+}
+
+TransformFactory::~TransformFactory()
+{
+}
+
+TransformFactory::TransformList
+TransformFactory::getAllTransforms()
+{
+    if (m_transforms.empty()) populateTransforms();
+
+    TransformList list;
+    for (TransformDescriptionMap::const_iterator i = m_transforms.begin();
+	 i != m_transforms.end(); ++i) {
+	list.push_back(i->second);
+    }
+
+    return list;
+}
+
+std::vector<QString>
+TransformFactory::getAllTransformTypes()
+{
+    if (m_transforms.empty()) populateTransforms();
+
+    std::set<QString> types;
+    for (TransformDescriptionMap::const_iterator i = m_transforms.begin();
+	 i != m_transforms.end(); ++i) {
+        types.insert(i->second.type);
+    }
+
+    std::vector<QString> rv;
+    for (std::set<QString>::iterator i = types.begin(); i != types.end(); ++i) {
+        rv.push_back(*i);
+    }
+
+    return rv;
+}
+
+void
+TransformFactory::populateTransforms()
+{
+    TransformDescriptionMap transforms;
+
+    populateFeatureExtractionPlugins(transforms);
+    populateRealTimePlugins(transforms);
+
+    // disambiguate plugins with similar descriptions
+
+    std::map<QString, int> descriptions;
+
+    for (TransformDescriptionMap::iterator i = transforms.begin();
+         i != transforms.end(); ++i) {
+
+        TransformDesc desc = i->second;
+
+	++descriptions[desc.description];
+	++descriptions[QString("%1 [%2]").arg(desc.description).arg(desc.maker)];
+    }
+
+    std::map<QString, int> counts;
+    m_transforms.clear();
+
+    for (TransformDescriptionMap::iterator i = transforms.begin();
+         i != transforms.end(); ++i) {
+
+        TransformDesc desc = i->second;
+	QString name = desc.name;
+        QString description = desc.description;
+        QString maker = desc.maker;
+
+	if (descriptions[description] > 1) {
+	    description = QString("%1 [%2]").arg(description).arg(maker);
+	    if (descriptions[description] > 1) {
+		description = QString("%1 <%2>")
+		    .arg(description).arg(++counts[description]);
+	    }
+	}
+
+        desc.description = description;
+	m_transforms[name] = desc;
+    }	    
+}
+
+void
+TransformFactory::populateFeatureExtractionPlugins(TransformDescriptionMap &transforms)
+{
+    std::vector<QString> plugs =
+	FeatureExtractionPluginFactory::getAllPluginIdentifiers();
+
+    for (size_t i = 0; i < plugs.size(); ++i) {
+
+	QString pluginId = plugs[i];
+
+	FeatureExtractionPluginFactory *factory =
+	    FeatureExtractionPluginFactory::instanceFor(pluginId);
+
+	if (!factory) {
+	    std::cerr << "WARNING: TransformFactory::populateTransforms: No feature extraction plugin factory for instance " << pluginId.toLocal8Bit().data() << std::endl;
+	    continue;
+	}
+
+	Vamp::Plugin *plugin = 
+	    factory->instantiatePlugin(pluginId, 48000);
+
+	if (!plugin) {
+	    std::cerr << "WARNING: TransformFactory::populateTransforms: Failed to instantiate plugin " << pluginId.toLocal8Bit().data() << std::endl;
+	    continue;
+	}
+		
+	QString pluginDescription = plugin->getDescription().c_str();
+	Vamp::Plugin::OutputList outputs =
+	    plugin->getOutputDescriptors();
+
+	for (size_t j = 0; j < outputs.size(); ++j) {
+
+	    QString transformName = QString("%1:%2")
+		    .arg(pluginId).arg(outputs[j].name.c_str());
+
+	    QString userDescription;
+            QString friendlyName;
+            QString units = outputs[j].unit.c_str();
+
+	    if (outputs.size() == 1) {
+		userDescription = pluginDescription;
+                friendlyName = pluginDescription;
+	    } else {
+		userDescription = QString("%1: %2")
+		    .arg(pluginDescription)
+		    .arg(outputs[j].description.c_str());
+                friendlyName = outputs[j].description.c_str();
+	    }
+
+            bool configurable = (!plugin->getPrograms().empty() ||
+                                 !plugin->getParameterDescriptors().empty());
+
+	    transforms[transformName] = 
+                TransformDesc(tr("Analysis Plugins"),
+                              transformName,
+                              userDescription,
+                              friendlyName,
+                              plugin->getMaker().c_str(),
+                              units,
+                              configurable);
+	}
+    }
+}
+
+void
+TransformFactory::populateRealTimePlugins(TransformDescriptionMap &transforms)
+{
+    std::vector<QString> plugs =
+	RealTimePluginFactory::getAllPluginIdentifiers();
+
+    QRegExp unitRE("[\\[\\(]([A-Za-z0-9/]+)[\\)\\]]$");
+
+    for (size_t i = 0; i < plugs.size(); ++i) {
+        
+	QString pluginId = plugs[i];
+
+        RealTimePluginFactory *factory =
+            RealTimePluginFactory::instanceFor(pluginId);
+
+	if (!factory) {
+	    std::cerr << "WARNING: TransformFactory::populateTransforms: No real time plugin factory for instance " << pluginId.toLocal8Bit().data() << std::endl;
+	    continue;
+	}
+
+        const RealTimePluginDescriptor *descriptor =
+            factory->getPluginDescriptor(pluginId);
+
+        if (!descriptor) {
+	    std::cerr << "WARNING: TransformFactory::populateTransforms: Failed to query plugin " << pluginId.toLocal8Bit().data() << std::endl;
+	    continue;
+	}
+	
+        if (descriptor->controlOutputPortCount == 0 ||
+            descriptor->audioInputPortCount == 0) continue;
+
+//        std::cout << "TransformFactory::populateRealTimePlugins: plugin " << pluginId.toStdString() << " has " << descriptor->controlOutputPortCount << " output ports" << std::endl;
+	
+	QString pluginDescription = descriptor->name.c_str();
+
+	for (size_t j = 0; j < descriptor->controlOutputPortCount; ++j) {
+
+	    QString transformName = QString("%1:%2").arg(pluginId).arg(j);
+	    QString userDescription;
+            QString units;
+
+	    if (j < descriptor->controlOutputPortNames.size() &&
+                descriptor->controlOutputPortNames[j] != "") {
+
+                QString portName = descriptor->controlOutputPortNames[j].c_str();
+
+		userDescription = tr("%1: %2")
+                    .arg(pluginDescription)
+                    .arg(portName);
+
+                if (unitRE.indexIn(portName) >= 0) {
+                    units = unitRE.cap(1);
+                }
+
+	    } else if (descriptor->controlOutputPortCount > 1) {
+
+		userDescription = tr("%1: Output %2")
+		    .arg(pluginDescription)
+		    .arg(j + 1);
+
+	    } else {
+
+                userDescription = pluginDescription;
+            }
+
+
+            bool configurable = (descriptor->parameterCount > 0);
+
+	    transforms[transformName] = 
+                TransformDesc(tr("Other Plugins"),
+                              transformName,
+                              userDescription,
+                              userDescription,
+                              descriptor->maker.c_str(),
+                              units,
+                              configurable);
+	}
+    }
+}
+
+QString
+TransformFactory::getTransformDescription(TransformName name)
+{
+    if (m_transforms.find(name) != m_transforms.end()) {
+	return m_transforms[name].description;
+    } else return "";
+}
+
+QString
+TransformFactory::getTransformFriendlyName(TransformName name)
+{
+    if (m_transforms.find(name) != m_transforms.end()) {
+	return m_transforms[name].friendlyName;
+    } else return "";
+}
+
+QString
+TransformFactory::getTransformUnits(TransformName name)
+{
+    if (m_transforms.find(name) != m_transforms.end()) {
+	return m_transforms[name].units;
+    } else return "";
+}
+
+bool
+TransformFactory::isTransformConfigurable(TransformName name)
+{
+    if (m_transforms.find(name) != m_transforms.end()) {
+	return m_transforms[name].configurable;
+    } else return false;
+}
+
+bool
+TransformFactory::getTransformChannelRange(TransformName name,
+                                           int &min, int &max)
+{
+    QString id = name.section(':', 0, 2);
+
+    if (FeatureExtractionPluginFactory::instanceFor(id)) {
+
+        Vamp::Plugin *plugin = 
+            FeatureExtractionPluginFactory::instanceFor(id)->
+            instantiatePlugin(id, 48000);
+        if (!plugin) return false;
+
+        min = plugin->getMinChannelCount();
+        max = plugin->getMaxChannelCount();
+        delete plugin;
+
+        return true;
+
+    } else if (RealTimePluginFactory::instanceFor(id)) {
+
+        const RealTimePluginDescriptor *descriptor = 
+            RealTimePluginFactory::instanceFor(id)->
+            getPluginDescriptor(id);
+        if (!descriptor) return false;
+
+        min = descriptor->audioInputPortCount;
+        max = descriptor->audioInputPortCount;
+
+        return true;
+    }
+
+    return false;
+}
+
+bool
+TransformFactory::getChannelRange(TransformName name, Vamp::PluginBase *plugin,
+                                  int &minChannels, int &maxChannels)
+{
+    Vamp::Plugin *vp = 0;
+    if ((vp = dynamic_cast<Vamp::Plugin *>(plugin))) {
+        minChannels = vp->getMinChannelCount();
+        maxChannels = vp->getMaxChannelCount();
+        return true;
+    } else {
+        return getTransformChannelRange(name, minChannels, maxChannels);
+    }
+}
+
+bool
+TransformFactory::getConfigurationForTransform(TransformName name,
+                                               Model *inputModel,
+                                               int &channel,
+                                               QString &configurationXml)
+{
+    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;
+
+    Vamp::PluginBase *plugin = 0;
+
+    if (FeatureExtractionPluginFactory::instanceFor(id)) {
+
+        plugin = FeatureExtractionPluginFactory::instanceFor(id)->instantiatePlugin
+            (id, inputModel->getSampleRate());
+
+    } else if (RealTimePluginFactory::instanceFor(id)) {
+
+        plugin = RealTimePluginFactory::instanceFor(id)->instantiatePlugin
+            (id, 0, 0, inputModel->getSampleRate(), 1024, 1);
+    }
+
+    if (plugin) {
+        if (configurationXml != "") {
+            PluginXml(plugin).setParametersFromXml(configurationXml);
+        }
+
+        int sourceChannels = 1;
+        if (dynamic_cast<DenseTimeValueModel *>(inputModel)) {
+            sourceChannels = dynamic_cast<DenseTimeValueModel *>(inputModel)
+                ->getChannelCount();
+        }
+
+        int minChannels = 1, maxChannels = sourceChannels;
+        getChannelRange(name, plugin, minChannels, maxChannels);
+
+        int targetChannels = sourceChannels;
+        if (sourceChannels < minChannels) targetChannels = minChannels;
+        if (sourceChannels > maxChannels) targetChannels = maxChannels;
+
+        int defaultChannel = channel;
+
+        PluginParameterDialog *dialog = new PluginParameterDialog(plugin,
+                                                                  sourceChannels,
+                                                                  targetChannels,
+                                                                  defaultChannel,
+                                                                  output);
+        if (dialog->exec() == QDialog::Accepted) {
+            ok = true;
+        }
+        configurationXml = PluginXml(plugin).toXmlString();
+        channel = dialog->getChannel();
+        delete dialog;
+        delete plugin;
+    }
+
+    if (ok) m_lastConfigurations[name] = configurationXml;
+
+    return ok;
+}
+
+Transform *
+TransformFactory::createTransform(TransformName name, Model *inputModel,
+                                  int channel, QString configurationXml, bool start)
+{
+    Transform *transform = 0;
+
+    //!!! use channel
+    
+    QString id = name.section(':', 0, 2);
+    QString output = name.section(':', 3);
+
+    if (FeatureExtractionPluginFactory::instanceFor(id)) {
+        transform = new FeatureExtractionPluginTransform(inputModel,
+                                                         id,
+                                                         channel,
+                                                         configurationXml,
+                                                         output);
+    } else if (RealTimePluginFactory::instanceFor(id)) {
+        transform = new RealTimePluginTransform(inputModel,
+                                                id,
+                                                channel,
+                                                configurationXml,
+                                                getTransformUnits(name),
+                                                output.toInt());
+    } else {
+        std::cerr << "TransformFactory::createTransform: Unknown transform \""
+                  << name.toStdString() << "\"" << std::endl;
+        return transform;
+    }
+
+    if (start && transform) transform->start();
+    transform->setObjectName(name);
+    return transform;
+}
+
+Model *
+TransformFactory::transform(TransformName name, Model *inputModel,
+                            int channel, QString configurationXml)
+{
+    Transform *t = createTransform(name, inputModel, channel,
+                                   configurationXml, false);
+
+    if (!t) return 0;
+
+    connect(t, SIGNAL(finished()), this, SLOT(transformFinished()));
+
+    t->start();
+    return t->detachOutputModel();
+}
+
+void
+TransformFactory::transformFinished()
+{
+    QObject *s = sender();
+    Transform *transform = dynamic_cast<Transform *>(s);
+    
+    if (!transform) {
+	std::cerr << "WARNING: TransformFactory::transformFinished: sender is not a transform" << std::endl;
+	return;
+    }
+
+    transform->wait(); // unnecessary but reassuring
+    delete transform;
+}
+