# HG changeset patch # User Chris Cannam # Date 1143471782 0 # Node ID 3086ff194ea0cb226470735c23fe15e2f9a6d949 # Parent 9705a1978ecc2ee445f696c96c2b3703f010f7bc * More structural work on feature extraction plugin C <-> C++ adapter * Allow use of LADSPA/DSSI plugins with control outputs as feature extraction plugins (DSSI with MIDI output still to come) * Reorder labels on spectrogram status box * Minor tweaks in doc etc. diff -r 9705a1978ecc -r 3086ff194ea0 base/ViewManager.cpp --- a/base/ViewManager.cpp Fri Mar 24 18:15:50 2006 +0000 +++ b/base/ViewManager.cpp Mon Mar 27 15:03:02 2006 +0000 @@ -76,10 +76,10 @@ { if (m_playbackFrame != f) { m_playbackFrame = f; + emit playbackFrameChanged(f); if (m_playSource && m_playSource->isPlaying()) { m_playSource->play(f); } - emit playbackFrameChanged(f); } } diff -r 9705a1978ecc -r 3086ff194ea0 plugin/DSSIPluginFactory.cpp --- a/plugin/DSSIPluginFactory.cpp Fri Mar 24 18:15:50 2006 +0000 +++ b/plugin/DSSIPluginFactory.cpp Mon Mar 27 15:03:02 2006 +0000 @@ -285,6 +285,18 @@ continue; } + RealTimePluginDescriptor *rtd = new RealTimePluginDescriptor; + rtd->name = ladspaDescriptor->Name; + rtd->label = ladspaDescriptor->Label; + rtd->maker = ladspaDescriptor->Maker; + rtd->copyright = ladspaDescriptor->Copyright; + rtd->category = ""; + rtd->isSynth = (descriptor->run_synth || + descriptor->run_multiple_synths); + rtd->parameterCount = 0; + rtd->audioInputPortCount = 0; + rtd->controlOutputPortCount = 0; + #ifdef HAVE_LRDF char *def_uri = 0; lrdf_defaults *defs = 0; @@ -303,6 +315,8 @@ m_taxonomy[ladspaDescriptor->UniqueID] = category; } } + + rtd->category = category.toStdString(); // std::cerr << "Plugin id is " << ladspaDescriptor->UniqueID // << ", category is \"" << (category ? category : QString("(none)")) @@ -337,10 +351,31 @@ } #endif // HAVE_LRDF + for (unsigned long i = 0; i < ladspaDescriptor->PortCount; i++) { + if (LADSPA_IS_PORT_CONTROL(ladspaDescriptor->PortDescriptors[i])) { + if (LADSPA_IS_PORT_INPUT(ladspaDescriptor->PortDescriptors[i])) { + ++rtd->parameterCount; + } else { + if (strcmp(ladspaDescriptor->PortNames[i], "latency") && + strcmp(ladspaDescriptor->PortNames[i], "_latency")) { + ++rtd->controlOutputPortCount; + rtd->controlOutputPortNames.push_back + (ladspaDescriptor->PortNames[i]); + } + } + } else { + if (LADSPA_IS_PORT_INPUT(ladspaDescriptor->PortDescriptors[i])) { + ++rtd->audioInputPortCount; + } + } + } + QString identifier = PluginIdentifier::createIdentifier ("dssi", soname, ladspaDescriptor->Label); m_identifiers.push_back(identifier); + m_rtDescriptors[identifier] = rtd; + ++index; } diff -r 9705a1978ecc -r 3086ff194ea0 plugin/DSSIPluginInstance.cpp --- a/plugin/DSSIPluginInstance.cpp Fri Mar 24 18:15:50 2006 +0000 +++ b/plugin/DSSIPluginInstance.cpp Mon Mar 27 15:03:02 2006 +0000 @@ -773,6 +773,13 @@ } float +DSSIPluginInstance::getControlOutputValue(unsigned int output) const +{ + if (output > m_controlPortsOut.size()) return 0.0; + return (*m_controlPortsOut[output].second); +} + +float DSSIPluginInstance::getParameterValue(unsigned int parameter) const { #ifdef DEBUG_DSSI diff -r 9705a1978ecc -r 3086ff194ea0 plugin/DSSIPluginInstance.h --- a/plugin/DSSIPluginInstance.h Fri Mar 24 18:15:50 2006 +0000 +++ b/plugin/DSSIPluginInstance.h Mon Mar 27 15:03:02 2006 +0000 @@ -75,6 +75,9 @@ virtual sample_t **getAudioInputBuffers() { return m_inputBuffers; } virtual sample_t **getAudioOutputBuffers() { return m_outputBuffers; } + virtual size_t getControlOutputCount() const { return m_controlPortsOut.size(); } + virtual float getControlOutputValue(size_t n) const; + virtual ProgramList getPrograms() const; virtual std::string getCurrentProgram() const; virtual std::string getProgram(int bank, int program) const; diff -r 9705a1978ecc -r 3086ff194ea0 plugin/FeatureExtractionPluginAdapter.cpp --- a/plugin/FeatureExtractionPluginAdapter.cpp Fri Mar 24 18:15:50 2006 +0000 +++ b/plugin/FeatureExtractionPluginAdapter.cpp Mon Mar 27 15:03:02 2006 +0000 @@ -1,34 +1,439 @@ /* -*- 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. + 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. + 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 "FeatureExtractionPluginAdapter.h" -#include "plugins/ChromagramPlugin.h" - -extern int blah() +FeatureExtractionPluginAdapterBase::FeatureExtractionPluginAdapterBase() : + m_populated(false) { - FeatureExtractionPluginAdapter adapter; - - const SVPPluginDescriptor *desc = adapter.getDescriptor(); - - SVPPluginHandle handle = desc->instantiate(desc, 48000); - - unsigned int preferredBlockSize = desc->getPreferredBlockSize(handle); - - SVPOutputDescriptor *od = desc->getOutputDescriptor(handle, 2); - - SVPFeatureList **feature = desc->process(handle, 0, 0, 0); } +const SVPPluginDescriptor * +FeatureExtractionPluginAdapterBase::getDescriptor() +{ + if (m_populated) return &m_descriptor; + + FeatureExtractionPlugin *plugin = createPlugin(48000); + + m_parameters = plugin->getParameterDescriptors(); + m_programs = plugin->getPrograms(); + + m_descriptor.name = strdup(plugin->getName().c_str()); + m_descriptor.description = strdup(plugin->getDescription().c_str()); + m_descriptor.maker = strdup(plugin->getMaker().c_str()); + m_descriptor.pluginVersion = plugin->getPluginVersion(); + m_descriptor.copyright = strdup(plugin->getCopyright().c_str()); + + m_descriptor.parameterCount = m_parameters.size(); + m_descriptor.parameters = (const SVPParameterDescriptor **) + malloc(m_parameters.size() * sizeof(SVPParameterDescriptor)); + + for (unsigned int i = 0; i < m_parameters.size(); ++i) { + SVPParameterDescriptor *desc = (SVPParameterDescriptor *) + malloc(sizeof(SVPParameterDescriptor)); + desc->name = strdup(m_parameters[i].name.c_str()); + desc->description = strdup(m_parameters[i].description.c_str()); + desc->unit = strdup(m_parameters[i].unit.c_str()); + desc->minValue = m_parameters[i].minValue; + desc->maxValue = m_parameters[i].maxValue; + desc->defaultValue = m_parameters[i].defaultValue; + desc->isQuantized = m_parameters[i].isQuantized; + desc->quantizeStep = m_parameters[i].quantizeStep; + m_descriptor.parameters[i] = desc; + } + + m_descriptor.programCount = m_programs.size(); + m_descriptor.programs = (const char **) + malloc(m_programs.size() * sizeof(const char *)); + + for (unsigned int i = 0; i < m_programs.size(); ++i) { + m_descriptor.programs[i] = strdup(m_programs[i].c_str()); + } + + m_descriptor.instantiate = svpInstantiate; + m_descriptor.cleanup = svpCleanup; + m_descriptor.initialise = svpInitialise; + m_descriptor.reset = svpReset; + m_descriptor.getParameter = svpGetParameter; + m_descriptor.setParameter = svpSetParameter; + m_descriptor.getCurrentProgram = svpGetCurrentProgram; + m_descriptor.selectProgram = svpSelectProgram; + m_descriptor.getPreferredStepSize = svpGetPreferredStepSize; + m_descriptor.getPreferredBlockSize = svpGetPreferredBlockSize; + m_descriptor.getMinChannelCount = svpGetMinChannelCount; + m_descriptor.getMaxChannelCount = svpGetMaxChannelCount; + m_descriptor.getOutputCount = svpGetOutputCount; + m_descriptor.getOutputDescriptor = svpGetOutputDescriptor; + m_descriptor.releaseOutputDescriptor = svpReleaseOutputDescriptor; + m_descriptor.process = svpProcess; + m_descriptor.getRemainingFeatures = svpGetRemainingFeatures; + m_descriptor.releaseFeatureSet = svpReleaseFeatureSet; + + m_adapterMap[&m_descriptor] = this; + + delete plugin; + + m_populated = true; + return &m_descriptor; +} + +FeatureExtractionPluginAdapterBase::~FeatureExtractionPluginAdapterBase() +{ + if (!m_populated) return; + + free((void *)m_descriptor.name); + free((void *)m_descriptor.description); + free((void *)m_descriptor.maker); + free((void *)m_descriptor.copyright); + + for (unsigned int i = 0; i < m_descriptor.parameterCount; ++i) { + const SVPParameterDescriptor *desc = m_descriptor.parameters[i]; + free((void *)desc->name); + free((void *)desc->description); + free((void *)desc->unit); + } + free((void *)m_descriptor.parameters); + + for (unsigned int i = 0; i < m_descriptor.programCount; ++i) { + free((void *)m_descriptor.programs[i]); + } + free((void *)m_descriptor.programs); + + m_adapterMap.erase(&m_descriptor); +} + +FeatureExtractionPluginAdapterBase * +FeatureExtractionPluginAdapterBase::lookupAdapter(SVPPluginHandle handle) +{ + AdapterMap::const_iterator i = m_adapterMap.find(handle); + if (i == m_adapterMap.end()) return 0; + return i->second; +} + +SVPPluginHandle +FeatureExtractionPluginAdapterBase::svpInstantiate(const SVPPluginDescriptor *desc, + float inputSampleRate) +{ + if (m_adapterMap.find(desc) == m_adapterMap.end()) return 0; + FeatureExtractionPluginAdapterBase *adapter = m_adapterMap[desc]; + if (desc != &adapter->m_descriptor) return 0; + + FeatureExtractionPlugin *plugin = adapter->createPlugin(inputSampleRate); + if (plugin) { + m_adapterMap[plugin] = adapter; + } + + return plugin; +} + +void +FeatureExtractionPluginAdapterBase::svpCleanup(SVPPluginHandle handle) +{ + FeatureExtractionPluginAdapterBase *adapter = lookupAdapter(handle); + if (!adapter) { + delete ((FeatureExtractionPlugin *)handle); + return; + } + adapter->cleanup(((FeatureExtractionPlugin *)handle)); +} + +int +FeatureExtractionPluginAdapterBase::svpInitialise(SVPPluginHandle handle, + unsigned int channels, + unsigned int stepSize, + unsigned int blockSize) +{ + bool result = ((FeatureExtractionPlugin *)handle)->initialise + (channels, stepSize, blockSize); + return result ? 1 : 0; +} + +void +FeatureExtractionPluginAdapterBase::svpReset(SVPPluginHandle handle) +{ + ((FeatureExtractionPlugin *)handle)->reset(); +} + +float +FeatureExtractionPluginAdapterBase::svpGetParameter(SVPPluginHandle handle, + int param) +{ + FeatureExtractionPluginAdapterBase *adapter = lookupAdapter(handle); + if (!adapter) return 0.0; + FeatureExtractionPlugin::ParameterList &list = adapter->m_parameters; + return ((FeatureExtractionPlugin *)handle)->getParameter(list[param].name); +} + +void +FeatureExtractionPluginAdapterBase::svpSetParameter(SVPPluginHandle handle, + int param, float value) +{ + FeatureExtractionPluginAdapterBase *adapter = lookupAdapter(handle); + if (!adapter) return; + FeatureExtractionPlugin::ParameterList &list = adapter->m_parameters; + ((FeatureExtractionPlugin *)handle)->setParameter(list[param].name, value); +} + +unsigned int +FeatureExtractionPluginAdapterBase::svpGetCurrentProgram(SVPPluginHandle handle) +{ + FeatureExtractionPluginAdapterBase *adapter = lookupAdapter(handle); + if (!adapter) return 0; + FeatureExtractionPlugin::ProgramList &list = adapter->m_programs; + std::string program = ((FeatureExtractionPlugin *)handle)->getCurrentProgram(); + for (unsigned int i = 0; i < list.size(); ++i) { + if (list[i] == program) return i; + } + return 0; +} + +void +FeatureExtractionPluginAdapterBase::svpSelectProgram(SVPPluginHandle handle, + unsigned int program) +{ + FeatureExtractionPluginAdapterBase *adapter = lookupAdapter(handle); + if (!adapter) return; + FeatureExtractionPlugin::ProgramList &list = adapter->m_programs; + ((FeatureExtractionPlugin *)handle)->selectProgram(list[program]); +} + +unsigned int +FeatureExtractionPluginAdapterBase::svpGetPreferredStepSize(SVPPluginHandle handle) +{ + return ((FeatureExtractionPlugin *)handle)->getPreferredStepSize(); +} + +unsigned int +FeatureExtractionPluginAdapterBase::svpGetPreferredBlockSize(SVPPluginHandle handle) +{ + return ((FeatureExtractionPlugin *)handle)->getPreferredBlockSize(); +} + +unsigned int +FeatureExtractionPluginAdapterBase::svpGetMinChannelCount(SVPPluginHandle handle) +{ + return ((FeatureExtractionPlugin *)handle)->getMinChannelCount(); +} + +unsigned int +FeatureExtractionPluginAdapterBase::svpGetMaxChannelCount(SVPPluginHandle handle) +{ + return ((FeatureExtractionPlugin *)handle)->getMaxChannelCount(); +} + +unsigned int +FeatureExtractionPluginAdapterBase::svpGetOutputCount(SVPPluginHandle handle) +{ + FeatureExtractionPluginAdapterBase *adapter = lookupAdapter(handle); + if (!adapter) return 0; + return adapter->getOutputCount((FeatureExtractionPlugin *)handle); +} + +SVPOutputDescriptor * +FeatureExtractionPluginAdapterBase::svpGetOutputDescriptor(SVPPluginHandle handle, + unsigned int i) +{ + FeatureExtractionPluginAdapterBase *adapter = lookupAdapter(handle); + if (!adapter) return 0; + return adapter->getOutputDescriptor((FeatureExtractionPlugin *)handle, i); +} + +void +FeatureExtractionPluginAdapterBase::svpReleaseOutputDescriptor(SVPOutputDescriptor *desc) +{ + if (desc->name) free((void *)desc->name); + if (desc->description) free((void *)desc->description); + if (desc->unit) free((void *)desc->unit); + for (unsigned int i = 0; i < desc->valueCount; ++i) { + free((void *)desc->valueNames[i]); + } + if (desc->valueNames) free((void *)desc->valueNames); + free((void *)desc); +} + +SVPFeatureList ** +FeatureExtractionPluginAdapterBase::svpProcess(SVPPluginHandle handle, + float **inputBuffers, + int sec, + int nsec) +{ + FeatureExtractionPluginAdapterBase *adapter = lookupAdapter(handle); + if (!adapter) return 0; + return adapter->process((FeatureExtractionPlugin *)handle, + inputBuffers, sec, nsec); +} + +SVPFeatureList ** +FeatureExtractionPluginAdapterBase::svpGetRemainingFeatures(SVPPluginHandle handle) +{ + FeatureExtractionPluginAdapterBase *adapter = lookupAdapter(handle); + if (!adapter) return 0; + return adapter->getRemainingFeatures((FeatureExtractionPlugin *)handle); +} + +void +FeatureExtractionPluginAdapterBase::svpReleaseFeatureSet(SVPFeatureList **fs) +{ + if (!fs) return; + for (unsigned int i = 0; fs[i]; ++i) { + for (unsigned int j = 0; j < fs[i]->featureCount; ++j) { + SVPFeature *feature = &fs[i]->features[j]; + if (feature->values) free((void *)feature->values); + if (feature->label) free((void *)feature->label); + free((void *)feature); + } + if (fs[i]->features) free((void *)fs[i]->features); + free((void *)fs[i]); + } + free((void *)fs); +} + +void +FeatureExtractionPluginAdapterBase::cleanup(FeatureExtractionPlugin *plugin) +{ + if (m_pluginOutputs.find(plugin) != m_pluginOutputs.end()) { + delete m_pluginOutputs[plugin]; + m_pluginOutputs.erase(plugin); + } + m_adapterMap.erase(plugin); + delete ((FeatureExtractionPlugin *)plugin); +} + +void +FeatureExtractionPluginAdapterBase::checkOutputMap(FeatureExtractionPlugin *plugin) +{ + if (!m_pluginOutputs[plugin]) { + m_pluginOutputs[plugin] = new FeatureExtractionPlugin::OutputList + (plugin->getOutputDescriptors()); + } +} + +unsigned int +FeatureExtractionPluginAdapterBase::getOutputCount(FeatureExtractionPlugin *plugin) +{ + checkOutputMap(plugin); + return m_pluginOutputs[plugin]->size(); +} + +SVPOutputDescriptor * +FeatureExtractionPluginAdapterBase::getOutputDescriptor(FeatureExtractionPlugin *plugin, + unsigned int i) +{ + checkOutputMap(plugin); + FeatureExtractionPlugin::OutputDescriptor &od = + (*m_pluginOutputs[plugin])[i]; + + SVPOutputDescriptor *desc = (SVPOutputDescriptor *) + malloc(sizeof(SVPOutputDescriptor)); + + desc->name = strdup(od.name.c_str()); + desc->description = strdup(od.description.c_str()); + desc->unit = strdup(od.unit.c_str()); + desc->hasFixedValueCount = od.hasFixedValueCount; + desc->valueCount = od.valueCount; + + desc->valueNames = (const char **) + malloc(od.valueCount * sizeof(const char *)); + + for (unsigned int i = 0; i < od.valueCount; ++i) { + desc->valueNames[i] = strdup(od.valueNames[i].c_str()); + } + + desc->hasKnownExtents = od.hasKnownExtents; + desc->minValue = od.minValue; + desc->maxValue = od.maxValue; + desc->isQuantized = od.isQuantized; + desc->quantizeStep = od.quantizeStep; + + switch (od.sampleType) { + case FeatureExtractionPlugin::OutputDescriptor::OneSamplePerStep: + desc->sampleType = svpOneSamplePerStep; break; + case FeatureExtractionPlugin::OutputDescriptor::FixedSampleRate: + desc->sampleType = svpFixedSampleRate; break; + case FeatureExtractionPlugin::OutputDescriptor::VariableSampleRate: + desc->sampleType = svpVariableSampleRate; break; + } + + desc->sampleRate = od.sampleRate; + + return desc; +} + +SVPFeatureList ** +FeatureExtractionPluginAdapterBase::process(FeatureExtractionPlugin *plugin, + float **inputBuffers, + int sec, int nsec) +{ + RealTime rt(sec, nsec); + return convertFeatures(plugin->process(inputBuffers, rt)); +} + +SVPFeatureList ** +FeatureExtractionPluginAdapterBase::getRemainingFeatures(FeatureExtractionPlugin *plugin) +{ + return convertFeatures(plugin->getRemainingFeatures()); +} + +SVPFeatureList ** +FeatureExtractionPluginAdapterBase::convertFeatures(const FeatureExtractionPlugin::FeatureSet &features) +{ + unsigned int n = 0; + if (features.begin() != features.end()) { + FeatureExtractionPlugin::FeatureSet::const_iterator i = features.end(); + --i; + n = i->first + 1; + } + + if (!n) return 0; + + SVPFeatureList **fs = (SVPFeatureList **) + malloc((n + 1) * sizeof(SVPFeatureList *)); + + for (unsigned int i = 0; i < n; ++i) { + fs[i] = (SVPFeatureList *)malloc(sizeof(SVPFeatureList)); + if (features.find(i) == features.end()) { + fs[i]->featureCount = 0; + fs[i]->features = 0; + } else { + FeatureExtractionPlugin::FeatureSet::const_iterator fi = + features.find(i); + const FeatureExtractionPlugin::FeatureList &fl = fi->second; + fs[i]->featureCount = fl.size(); + fs[i]->features = (SVPFeature *)malloc(fl.size() * + sizeof(SVPFeature)); + for (unsigned int j = 0; j < fl.size(); ++j) { + fs[i]->features[j].hasTimestamp = fl[j].hasTimestamp; + fs[i]->features[j].sec = fl[j].timestamp.sec; + fs[i]->features[j].nsec = fl[j].timestamp.nsec; + fs[i]->features[j].valueCount = fl[j].values.size(); + fs[i]->features[j].values = (float *)malloc + (fs[i]->features[j].valueCount * sizeof(float)); + for (unsigned int k = 0; k < fs[i]->features[j].valueCount; ++k) { + fs[i]->features[j].values[k] = fl[j].values[k]; + } + fs[i]->features[j].label = strdup(fl[j].label.c_str()); + } + } + } + + fs[n] = 0; + + return fs; +} + +FeatureExtractionPluginAdapterBase::AdapterMap +FeatureExtractionPluginAdapterBase::m_adapterMap; + + diff -r 9705a1978ecc -r 3086ff194ea0 plugin/FeatureExtractionPluginAdapter.h --- a/plugin/FeatureExtractionPluginAdapter.h Fri Mar 24 18:15:50 2006 +0000 +++ b/plugin/FeatureExtractionPluginAdapter.h Mon Mar 27 15:03:02 2006 +0000 @@ -21,365 +21,106 @@ #include -template -class FeatureExtractionPluginAdapter +class FeatureExtractionPluginAdapterBase { public: - FeatureExtractionPluginAdapter() { - - Plugin plugin(48000); - - m_parameters = plugin.getParameterDescriptors(); - m_programs = plugin.getPrograms(); - - m_descriptor.name = strdup(plugin.getName().c_str()); - m_descriptor.description = strdup(plugin.getDescription().c_str()); - m_descriptor.maker = strdup(plugin.getMaker().c_str()); - m_descriptor.pluginVersion = plugin.getPluginVersion(); - m_descriptor.copyright = strdup(plugin.getCopyright().c_str()); - - m_descriptor.parameterCount = m_parameters.size(); - m_descriptor.parameters = (const SVPParameterDescriptor **) - malloc(m_parameters.size() * sizeof(SVPParameterDescriptor)); - - for (unsigned int i = 0; i < m_parameters.size(); ++i) { - SVPParameterDescriptor *desc = (SVPParameterDescriptor *) - malloc(sizeof(SVPParameterDescriptor)); - desc->name = strdup(m_parameters[i].name.c_str()); - desc->description = strdup(m_parameters[i].description.c_str()); - desc->unit = strdup(m_parameters[i].unit.c_str()); - desc->minValue = m_parameters[i].minValue; - desc->maxValue = m_parameters[i].maxValue; - desc->defaultValue = m_parameters[i].defaultValue; - desc->isQuantized = m_parameters[i].isQuantized; - desc->quantizeStep = m_parameters[i].quantizeStep; - m_descriptor.parameters[i] = desc; - } - - m_descriptor.programCount = m_programs.size(); - m_descriptor.programs = (const char **) - malloc(m_programs.size() * sizeof(const char *)); - - for (unsigned int i = 0; i < m_programs.size(); ++i) { - m_descriptor.programs[i] = strdup(m_programs[i].c_str()); - } - - m_descriptor.instantiate = svpInstantiate; - m_descriptor.cleanup = svpCleanup; - m_descriptor.initialise = svpInitialise; - m_descriptor.reset = svpReset; - m_descriptor.getParameter = svpGetParameter; - m_descriptor.setParameter = svpSetParameter; - m_descriptor.getCurrentProgram = svpGetCurrentProgram; - m_descriptor.selectProgram = svpSelectProgram; - m_descriptor.getPreferredStepSize = svpGetPreferredStepSize; - m_descriptor.getPreferredBlockSize = svpGetPreferredBlockSize; - m_descriptor.getMinChannelCount = svpGetMinChannelCount; - m_descriptor.getMaxChannelCount = svpGetMaxChannelCount; - m_descriptor.getOutputCount = svpGetOutputCount; - m_descriptor.getOutputDescriptor = svpGetOutputDescriptor; - m_descriptor.releaseOutputDescriptor = svpReleaseOutputDescriptor; - m_descriptor.process = svpProcess; - m_descriptor.getRemainingFeatures = svpGetRemainingFeatures; - m_descriptor.releaseFeatureSet = svpReleaseFeatureSet; - - m_adapterMap[&m_descriptor] = this; - } - - virtual ~FeatureExtractionPluginAdapter() { - - free((void *)m_descriptor.name); - free((void *)m_descriptor.description); - free((void *)m_descriptor.maker); - free((void *)m_descriptor.copyright); - - for (unsigned int i = 0; i < m_descriptor.parameterCount; ++i) { - const SVPParameterDescriptor *desc = m_descriptor.parameters[i]; - free((void *)desc->name); - free((void *)desc->description); - free((void *)desc->unit); - } - free((void *)m_descriptor.parameters); - - for (unsigned int i = 0; i < m_descriptor.programCount; ++i) { - free((void *)m_descriptor.programs[i]); - } - free((void *)m_descriptor.programs); - - m_adapterMap.erase(&m_descriptor); - } - - const SVPPluginDescriptor *getDescriptor() const { - return &m_descriptor; - } + virtual ~FeatureExtractionPluginAdapterBase(); + const SVPPluginDescriptor *getDescriptor(); protected: + FeatureExtractionPluginAdapterBase(); + + virtual FeatureExtractionPlugin *createPlugin(float inputSampleRate) = 0; + static SVPPluginHandle svpInstantiate(const SVPPluginDescriptor *desc, - float inputSampleRate) { - if (m_adapterMap.find(desc) == m_adapterMap.end()) return 0; - FeatureExtractionPluginAdapter *adapter = m_adapterMap[desc]; - if (desc != &adapter->m_descriptor) return 0; - Plugin *plugin = new Plugin(inputSampleRate); - m_adapterMap[plugin] = adapter; - return plugin; - } + float inputSampleRate); - static void svpCleanup(SVPPluginHandle handle) { - if (m_adapterMap.find(handle) == m_adapterMap.end()) { - delete ((Plugin *)handle); - return; - } - m_adapterMap[handle]->cleanup(((Plugin *)handle)); - } + static void svpCleanup(SVPPluginHandle handle); static int svpInitialise(SVPPluginHandle handle, unsigned int channels, - unsigned int stepSize, unsigned int blockSize) { - bool result = ((Plugin *)handle)->initialise(channels, - stepSize, blockSize); - return result ? 1 : 0; - } + unsigned int stepSize, unsigned int blockSize); - static void svpReset(SVPPluginHandle handle) { - ((Plugin *)handle)->reset(); - } + static void svpReset(SVPPluginHandle handle); - static float svpGetParameter(SVPPluginHandle handle, int param) { - if (m_adapterMap.find(handle) == m_adapterMap.end()) return 0.0; - FeatureExtractionPlugin::ParameterList &list = - m_adapterMap[handle]->m_parameters; - return ((Plugin *)handle)->getParameter(list[param].name); - } + static float svpGetParameter(SVPPluginHandle handle, int param); + static void svpSetParameter(SVPPluginHandle handle, int param, float value); - static void svpSetParameter(SVPPluginHandle handle, int param, float value) { - if (m_adapterMap.find(handle) == m_adapterMap.end()) return; - FeatureExtractionPlugin::ParameterList &list = - m_adapterMap[handle]->m_parameters; - ((Plugin *)handle)->setParameter(list[param].name, value); - } + static unsigned int svpGetCurrentProgram(SVPPluginHandle handle); + static void svpSelectProgram(SVPPluginHandle handle, unsigned int program); - static unsigned int svpGetCurrentProgram(SVPPluginHandle handle) { - if (m_adapterMap.find(handle) == m_adapterMap.end()) return 0; - FeatureExtractionPlugin::ProgramList &list = - m_adapterMap[handle]->m_programs; - std::string program = ((Plugin *)handle)->getCurrentProgram(); - for (unsigned int i = 0; i < list.size(); ++i) { - if (list[i] == program) return i; - } - return 0; - } + static unsigned int svpGetPreferredStepSize(SVPPluginHandle handle); + static unsigned int svpGetPreferredBlockSize(SVPPluginHandle handle); + static unsigned int svpGetMinChannelCount(SVPPluginHandle handle); + static unsigned int svpGetMaxChannelCount(SVPPluginHandle handle); - static void svpSelectProgram(SVPPluginHandle handle, unsigned int program) { - if (m_adapterMap.find(handle) == m_adapterMap.end()) return; - FeatureExtractionPlugin::ProgramList &list = - m_adapterMap[handle]->m_programs; - ((Plugin *)handle)->selectProgram(list[program]); - } - - static unsigned int svpGetPreferredStepSize(SVPPluginHandle handle) { - return ((Plugin *)handle)->getPreferredStepSize(); - } - - static unsigned int svpGetPreferredBlockSize(SVPPluginHandle handle) { - return ((Plugin *)handle)->getPreferredBlockSize(); - } - - static unsigned int svpGetMinChannelCount(SVPPluginHandle handle) { - return ((Plugin *)handle)->getMinChannelCount(); - } - - static unsigned int svpGetMaxChannelCount(SVPPluginHandle handle) { - return ((Plugin *)handle)->getMaxChannelCount(); - } - - static unsigned int svpGetOutputCount(SVPPluginHandle handle) { - if (m_adapterMap.find(handle) == m_adapterMap.end()) return 0; - return m_adapterMap[handle]->getOutputCount((Plugin *)handle); - } + static unsigned int svpGetOutputCount(SVPPluginHandle handle); static SVPOutputDescriptor *svpGetOutputDescriptor(SVPPluginHandle handle, - unsigned int i) { - if (m_adapterMap.find(handle) == m_adapterMap.end()) return 0; - return m_adapterMap[handle]->getOutputDescriptor((Plugin *)handle, i); - } + unsigned int i); - static void svpReleaseOutputDescriptor(SVPOutputDescriptor *desc) { - if (desc->name) free((void *)desc->name); - if (desc->description) free((void *)desc->description); - if (desc->unit) free((void *)desc->unit); - for (unsigned int i = 0; i < desc->valueCount; ++i) { - free((void *)desc->valueNames[i]); - } - if (desc->valueNames) free((void *)desc->valueNames); - free((void *)desc); - } + static void svpReleaseOutputDescriptor(SVPOutputDescriptor *desc); static SVPFeatureList **svpProcess(SVPPluginHandle handle, float **inputBuffers, int sec, - int nsec) { - if (m_adapterMap.find(handle) == m_adapterMap.end()) return 0; - return m_adapterMap[handle]->process((Plugin *)handle, - inputBuffers, sec, nsec); - } + int nsec); - static SVPFeatureList **svpGetRemainingFeatures(SVPPluginHandle handle) { - if (m_adapterMap.find(handle) == m_adapterMap.end()) return 0; - return m_adapterMap[handle]->getRemainingFeatures((Plugin *)handle); - } + static SVPFeatureList **svpGetRemainingFeatures(SVPPluginHandle handle); - static void svpReleaseFeatureSet(SVPFeatureList **fs) { - if (!fs) return; - for (unsigned int i = 0; fs[i]; ++i) { - for (unsigned int j = 0; j < fs[i]->featureCount; ++j) { - SVPFeature *feature = &fs[i]->features[j]; - if (feature->values) free((void *)feature->values); - if (feature->label) free((void *)feature->label); - free((void *)feature); - } - if (fs[i]->features) free((void *)fs[i]->features); - free((void *)fs[i]); - } - free((void *)fs); - } + static void svpReleaseFeatureSet(SVPFeatureList **fs); - void cleanup(Plugin *plugin) { - if (m_pluginOutputs.find(plugin) != m_pluginOutputs.end()) { - delete m_pluginOutputs[plugin]; - m_pluginOutputs.erase(plugin); - } - m_adapterMap.erase(plugin); - delete ((Plugin *)plugin); - } + void cleanup(FeatureExtractionPlugin *plugin); + void checkOutputMap(FeatureExtractionPlugin *plugin); + unsigned int getOutputCount(FeatureExtractionPlugin *plugin); + SVPOutputDescriptor *getOutputDescriptor(FeatureExtractionPlugin *plugin, + unsigned int i); + SVPFeatureList **process(FeatureExtractionPlugin *plugin, + float **inputBuffers, + int sec, int nsec); + SVPFeatureList **getRemainingFeatures(FeatureExtractionPlugin *plugin); + SVPFeatureList **convertFeatures(const FeatureExtractionPlugin::FeatureSet &features); + + typedef std::map AdapterMap; + static AdapterMap m_adapterMap; + static FeatureExtractionPluginAdapterBase *lookupAdapter(SVPPluginHandle); - void checkOutputMap(Plugin *plugin) { - if (!m_pluginOutputs[plugin]) { - m_pluginOutputs[plugin] = new FeatureExtractionPlugin::OutputList - (plugin->getOutputDescriptors()); - } - } - - unsigned int getOutputCount(Plugin *plugin) { - checkOutputMap(plugin); - return m_pluginOutputs[plugin]->size(); - } - - SVPOutputDescriptor *getOutputDescriptor(Plugin *plugin, - unsigned int i) { - - checkOutputMap(plugin); - FeatureExtractionPlugin::OutputDescriptor &od = - (*m_pluginOutputs[plugin])[i]; - - SVPOutputDescriptor *desc = (SVPOutputDescriptor *) - malloc(sizeof(SVPOutputDescriptor)); - - desc->name = strdup(od.name.c_str()); - desc->description = strdup(od.description.c_str()); - desc->unit = strdup(od.unit.c_str()); - desc->hasFixedValueCount = od.hasFixedValueCount; - desc->valueCount = od.valueCount; - - desc->valueNames = (const char **) - malloc(od.valueCount * sizeof(const char *)); - - for (unsigned int i = 0; i < od.valueCount; ++i) { - desc->valueNames[i] = strdup(od.valueNames[i].c_str()); - } - - desc->hasKnownExtents = od.hasKnownExtents; - desc->minValue = od.minValue; - desc->maxValue = od.maxValue; - desc->isQuantized = od.isQuantized; - desc->quantizeStep = od.quantizeStep; - - switch (od.sampleType) { - case FeatureExtractionPlugin::OutputDescriptor::OneSamplePerStep: - desc->sampleType = svpOneSamplePerStep; break; - case FeatureExtractionPlugin::OutputDescriptor::FixedSampleRate: - desc->sampleType = svpFixedSampleRate; break; - case FeatureExtractionPlugin::OutputDescriptor::VariableSampleRate: - desc->sampleType = svpVariableSampleRate; break; - } - - desc->sampleRate = od.sampleRate; - - return desc; - } - - SVPFeatureList **process(Plugin *plugin, - float **inputBuffers, - int sec, int nsec) { - RealTime rt(sec, nsec); - return convertFeatures(plugin->process(inputBuffers, rt)); - } - - SVPFeatureList **getRemainingFeatures(Plugin *plugin) { - return convertFeatures(plugin->getRemainingFeatures()); - } - - SVPFeatureList **convertFeatures(const FeatureExtractionPlugin::FeatureSet &features) { - - unsigned int n = 0; - if (features.begin() != features.end()) { - FeatureExtractionPlugin::FeatureSet::const_iterator i = features.end(); - --i; - n = i->first + 1; - } - - if (!n) return 0; - - SVPFeatureList **fs = (SVPFeatureList **) - malloc((n + 1) * sizeof(SVPFeatureList *)); - - for (unsigned int i = 0; i < n; ++i) { - fs[i] = (SVPFeatureList *)malloc(sizeof(SVPFeatureList)); - if (features.find(i) == features.end()) { - fs[i]->featureCount = 0; - fs[i]->features = 0; - } else { - FeatureExtractionPlugin::FeatureSet::const_iterator fi = - features.find(i); - const FeatureExtractionPlugin::FeatureList &fl = fi->second; - fs[i]->featureCount = fl.size(); - fs[i]->features = (SVPFeature *)malloc(fl.size() * - sizeof(SVPFeature)); - for (unsigned int j = 0; j < fl.size(); ++j) { - fs[i]->features[j].hasTimestamp = fl[j].hasTimestamp; - fs[i]->features[j].sec = fl[j].timestamp.sec; - fs[i]->features[j].nsec = fl[j].timestamp.nsec; - fs[i]->features[j].valueCount = fl[j].values.size(); - fs[i]->features[j].values = (float *)malloc - (fs[i]->features[j].valueCount * sizeof(float)); - for (unsigned int k = 0; k < fs[i]->features[j].valueCount; ++k) { - fs[i]->features[j].values[k] = fl[j].values[k]; - } - fs[i]->features[j].label = strdup(fl[j].label.c_str()); - } - } - } - - fs[n] = 0; - - return fs; - } - - typedef std::map AdapterMap; - static AdapterMap m_adapterMap; - + bool m_populated; SVPPluginDescriptor m_descriptor; FeatureExtractionPlugin::ParameterList m_parameters; FeatureExtractionPlugin::ProgramList m_programs; - - typedef std::map OutputMap; + + typedef std::map OutputMap; OutputMap m_pluginOutputs; - typedef std::map FeatureBufferMap; + typedef std::map FeatureBufferMap; FeatureBufferMap m_pluginFeatures; }; template -typename FeatureExtractionPluginAdapter::AdapterMap -FeatureExtractionPluginAdapter::m_adapterMap; +class FeatureExtractionPluginAdapter : public FeatureExtractionPluginAdapterBase +{ +public: + FeatureExtractionPluginAdapter() : FeatureExtractionPluginAdapterBase() { } + ~FeatureExtractionPluginAdapter() { } + +protected: + FeatureExtractionPlugin *createPlugin(float inputSampleRate) { + Plugin *plugin = new Plugin(inputSampleRate); + FeatureExtractionPlugin *fep = + dynamic_cast(plugin); + if (!fep) { + std::cerr << "ERROR: FeatureExtractionPlugin::createPlugin: " + << "Plugin is not a feature extraction plugin" + << std::endl; + delete plugin; + return 0; + } + return fep; + } +}; + #endif diff -r 9705a1978ecc -r 3086ff194ea0 plugin/FeatureExtractionPluginHostAdapter.cpp --- a/plugin/FeatureExtractionPluginHostAdapter.cpp Fri Mar 24 18:15:50 2006 +0000 +++ b/plugin/FeatureExtractionPluginHostAdapter.cpp Mon Mar 27 15:03:02 2006 +0000 @@ -78,14 +78,34 @@ FeatureExtractionPluginHostAdapter::ParameterList FeatureExtractionPluginHostAdapter::getParameterDescriptors() const { - //!!! - return ParameterList(); + ParameterList list; + for (unsigned int i = 0; i < m_descriptor->parameterCount; ++i) { + const SVPParameterDescriptor *spd = m_descriptor->parameters[i]; + ParameterDescriptor pd; + pd.name = spd->name; + pd.description = spd->description; + pd.unit = spd->unit; + pd.minValue = spd->minValue; + pd.maxValue = spd->maxValue; + pd.defaultValue = spd->defaultValue; + pd.isQuantized = spd->isQuantized; + pd.quantizeStep = spd->quantizeStep; + list.push_back(pd); + } + return list; } float FeatureExtractionPluginHostAdapter::getParameter(std::string param) const { - //!!! + if (!m_handle) return 0.0; + + for (unsigned int i = 0; i < m_descriptor->parameterCount; ++i) { + if (param == m_descriptor->parameters[i]->name) { + return m_descriptor->getParameter(m_handle, i); + } + } + return 0.0; } @@ -93,27 +113,48 @@ FeatureExtractionPluginHostAdapter::setParameter(std::string param, float value) { - //!!! + if (!m_handle) return; + + for (unsigned int i = 0; i < m_descriptor->parameterCount; ++i) { + if (param == m_descriptor->parameters[i]->name) { + m_descriptor->setParameter(m_handle, i, value); + return; + } + } } FeatureExtractionPluginHostAdapter::ProgramList FeatureExtractionPluginHostAdapter::getPrograms() const { - //!!! - return ProgramList(); + ProgramList list; + + for (unsigned int i = 0; i < m_descriptor->programCount; ++i) { + list.push_back(m_descriptor->programs[i]); + } + + return list; } std::string FeatureExtractionPluginHostAdapter::getCurrentProgram() const { - //!!! - return ""; + if (!m_handle) return ""; + + int pn = m_descriptor->getCurrentProgram(m_handle); + return m_descriptor->programs[pn]; } void FeatureExtractionPluginHostAdapter::selectProgram(std::string program) { - //!!! + if (!m_handle) return; + + for (unsigned int i = 0; i < m_descriptor->programCount; ++i) { + if (program == m_descriptor->programs[i]) { + m_descriptor->selectProgram(m_handle, i); + return; + } + } } size_t @@ -133,22 +174,105 @@ FeatureExtractionPluginHostAdapter::OutputList FeatureExtractionPluginHostAdapter::getOutputDescriptors() const { - //!!! - return OutputList(); + OutputList list; + if (!m_handle) return list; + + unsigned int count = m_descriptor->getOutputCount(m_handle); + + for (unsigned int i = 0; i < count; ++i) { + SVPOutputDescriptor *sd = m_descriptor->getOutputDescriptor(m_handle, i); + OutputDescriptor d; + d.name = sd->name; + d.description = sd->description; + d.unit = sd->unit; + d.hasFixedValueCount = sd->hasFixedValueCount; + d.valueCount = sd->valueCount; + for (unsigned int j = 0; j < sd->valueCount; ++j) { + d.valueNames.push_back(sd->valueNames[i]); + } + d.hasKnownExtents = sd->hasKnownExtents; + d.minValue = sd->minValue; + d.maxValue = sd->maxValue; + d.isQuantized = sd->isQuantized; + d.quantizeStep = sd->quantizeStep; + + switch (sd->sampleType) { + case svpOneSamplePerStep: + d.sampleType = OutputDescriptor::OneSamplePerStep; break; + case svpFixedSampleRate: + d.sampleType = OutputDescriptor::FixedSampleRate; break; + case svpVariableSampleRate: + d.sampleType = OutputDescriptor::VariableSampleRate; break; + } + + d.sampleRate = sd->sampleRate; + + list.push_back(d); + + m_descriptor->releaseOutputDescriptor(sd); + } + + return list; } FeatureExtractionPluginHostAdapter::FeatureSet FeatureExtractionPluginHostAdapter::process(float **inputBuffers, RealTime timestamp) { - //!!! - return FeatureSet(); + FeatureSet fs; + if (!m_handle) return fs; + + int sec = timestamp.sec; + int nsec = timestamp.nsec; + + SVPFeatureList **features = m_descriptor->process(m_handle, + inputBuffers, + sec, nsec); + + convertFeatures(features, fs); + m_descriptor->releaseFeatureSet(features); + return fs; } FeatureExtractionPluginHostAdapter::FeatureSet FeatureExtractionPluginHostAdapter::getRemainingFeatures() { - //!!! - return FeatureSet(); + FeatureSet fs; + if (!m_handle) return fs; + + SVPFeatureList **features = m_descriptor->getRemainingFeatures(m_handle); + + convertFeatures(features, fs); + m_descriptor->releaseFeatureSet(features); + return fs; } +void +FeatureExtractionPluginHostAdapter::convertFeatures(SVPFeatureList **features, + FeatureSet &fs) +{ + for (unsigned int i = 0; features[i]; ++i) { + + SVPFeatureList &list = *features[i]; + + if (list.featureCount > 0) { + + for (unsigned int j = 0; j < list.featureCount; ++j) { + + Feature feature; + feature.hasTimestamp = list.features[j].hasTimestamp; + feature.timestamp = RealTime(list.features[j].sec, + list.features[j].nsec); + + for (unsigned int k = 0; k < list.features[j].valueCount; ++k) { + feature.values.push_back(list.features[j].values[k]); + } + + feature.label = list.features[j].label; + + fs[i].push_back(feature); + } + } + } +} + diff -r 9705a1978ecc -r 3086ff194ea0 plugin/FeatureExtractionPluginHostAdapter.h --- a/plugin/FeatureExtractionPluginHostAdapter.h Fri Mar 24 18:15:50 2006 +0000 +++ b/plugin/FeatureExtractionPluginHostAdapter.h Mon Mar 27 15:03:02 2006 +0000 @@ -54,6 +54,8 @@ FeatureSet getRemainingFeatures(); protected: + void convertFeatures(SVPFeatureList **, FeatureSet &); + const SVPPluginDescriptor *m_descriptor; SVPPluginHandle m_handle; }; diff -r 9705a1978ecc -r 3086ff194ea0 plugin/LADSPAPluginFactory.cpp --- a/plugin/LADSPAPluginFactory.cpp Fri Mar 24 18:15:50 2006 +0000 +++ b/plugin/LADSPAPluginFactory.cpp Mon Mar 27 15:03:02 2006 +0000 @@ -125,6 +125,19 @@ unloadUnusedLibraries(); } +const RealTimePluginDescriptor * +LADSPAPluginFactory::getPluginDescriptor(QString identifier) const +{ + std::map::const_iterator i = + m_rtDescriptors.find(identifier); + + if (i != m_rtDescriptors.end()) { + return i->second; + } + + return 0; +} + float LADSPAPluginFactory::getPortMinimum(const LADSPA_Descriptor *descriptor, int port) { @@ -573,6 +586,17 @@ int index = 0; while ((descriptor = fn(index))) { + RealTimePluginDescriptor *rtd = new RealTimePluginDescriptor; + rtd->name = descriptor->Name; + rtd->label = descriptor->Label; + rtd->maker = descriptor->Maker; + rtd->copyright = descriptor->Copyright; + rtd->category = ""; + rtd->isSynth = false; + rtd->parameterCount = 0; + rtd->audioInputPortCount = 0; + rtd->controlOutputPortCount = 0; + #ifdef HAVE_LRDF char *def_uri = 0; lrdf_defaults *defs = 0; @@ -588,6 +612,8 @@ } } + rtd->category = category.toStdString(); + // std::cerr << "Plugin id is " << descriptor->UniqueID // << ", category is \"" << (category ? category : QString("(none)")) // << "\", name is " << descriptor->Name @@ -621,10 +647,31 @@ } #endif // HAVE_LRDF + for (unsigned long i = 0; i < descriptor->PortCount; i++) { + if (LADSPA_IS_PORT_CONTROL(descriptor->PortDescriptors[i])) { + if (LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[i])) { + ++rtd->parameterCount; + } else { + if (strcmp(descriptor->PortNames[i], "latency") && + strcmp(descriptor->PortNames[i], "_latency")) { + ++rtd->controlOutputPortCount; + rtd->controlOutputPortNames.push_back + (descriptor->PortNames[i]); + } + } + } else { + if (LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[i])) { + ++rtd->audioInputPortCount; + } + } + } + QString identifier = PluginIdentifier::createIdentifier ("ladspa", soname, descriptor->Label); m_identifiers.push_back(identifier); + m_rtDescriptors[identifier] = rtd; + ++index; } diff -r 9705a1978ecc -r 3086ff194ea0 plugin/LADSPAPluginFactory.h --- a/plugin/LADSPAPluginFactory.h Fri Mar 24 18:15:50 2006 +0000 +++ b/plugin/LADSPAPluginFactory.h Mon Mar 27 15:03:02 2006 +0000 @@ -42,6 +42,8 @@ virtual void enumeratePlugins(std::vector &list); + virtual const RealTimePluginDescriptor *getPluginDescriptor(QString identifier) const; + virtual RealTimePluginInstance *instantiatePlugin(QString identifier, int clientId, int position, @@ -78,6 +80,7 @@ void unloadUnusedLibraries(); std::vector m_identifiers; + std::map m_rtDescriptors; std::map m_taxonomy; std::map m_fallbackCategories; diff -r 9705a1978ecc -r 3086ff194ea0 plugin/LADSPAPluginInstance.cpp --- a/plugin/LADSPAPluginInstance.cpp Fri Mar 24 18:15:50 2006 +0000 +++ b/plugin/LADSPAPluginInstance.cpp Mon Mar 27 15:03:02 2006 +0000 @@ -414,6 +414,13 @@ } float +LADSPAPluginInstance::getControlOutputValue(unsigned int output) const +{ + if (output > m_controlPortsOut.size()) return 0.0; + return (*m_controlPortsOut[output].second); +} + +float LADSPAPluginInstance::getParameterValue(unsigned int parameter) const { if (parameter >= m_controlPortsIn.size()) return 0.0; diff -r 9705a1978ecc -r 3086ff194ea0 plugin/LADSPAPluginInstance.h --- a/plugin/LADSPAPluginInstance.h Fri Mar 24 18:15:50 2006 +0000 +++ b/plugin/LADSPAPluginInstance.h Mon Mar 27 15:03:02 2006 +0000 @@ -66,6 +66,9 @@ virtual sample_t **getAudioInputBuffers() { return m_inputBuffers; } virtual sample_t **getAudioOutputBuffers() { return m_outputBuffers; } + virtual size_t getControlOutputCount() const { return m_controlPortsOut.size(); } + virtual float getControlOutputValue(size_t n) const; + virtual bool isBypassed() const { return m_bypassed; } virtual void setBypassed(bool bypassed) { m_bypassed = bypassed; } diff -r 9705a1978ecc -r 3086ff194ea0 plugin/RealTimePluginFactory.h --- a/plugin/RealTimePluginFactory.h Fri Mar 24 18:15:50 2006 +0000 +++ b/plugin/RealTimePluginFactory.h Mon Mar 27 15:03:02 2006 +0000 @@ -27,6 +27,21 @@ class RealTimePluginInstance; +class RealTimePluginDescriptor +{ +public: + std::string name; + std::string label; + std::string maker; + std::string copyright; + std::string category; + bool isSynth; + unsigned int parameterCount; + unsigned int audioInputPortCount; + unsigned int controlOutputPortCount; + std::vector controlOutputPortNames; +}; + class RealTimePluginFactory { public: @@ -57,6 +72,11 @@ virtual void enumeratePlugins(std::vector &list) = 0; /** + * Get some basic information about a plugin (rapidly). + */ + virtual const RealTimePluginDescriptor *getPluginDescriptor(QString identifier) const = 0; + + /** * Instantiate a plugin. */ virtual RealTimePluginInstance *instantiatePlugin(QString identifier, diff -r 9705a1978ecc -r 3086ff194ea0 plugin/RealTimePluginInstance.h --- a/plugin/RealTimePluginInstance.h Fri Mar 24 18:15:50 2006 +0000 +++ b/plugin/RealTimePluginInstance.h Mon Mar 27 15:03:02 2006 +0000 @@ -33,9 +33,9 @@ class RealTimePluginFactory; /** - * RealTimePluginInstance is a very trivial interface that an audio - * process can use to refer to an instance of a plugin without needing - * to know what type of plugin it is. + * RealTimePluginInstance is an interface that an audio process can + * use to refer to an instance of a plugin without needing to know + * what type of plugin it is. * * The audio code calls run() on an instance that has been passed to * it, and assumes that the passing code has already initialised the @@ -47,6 +47,13 @@ * which the subclass of RealTimePluginInstance must implement. */ +/* + * N.B. RealTimePluginInstance, RealTimePluginFactory and their + * subclasses are terrible code. They've been reused, cut and pasted + * and mangled too many times to fit too many different uses, and + * could do with a good tidy. + */ + // These names are taken from LADSPA, but the values are not // guaranteed to match @@ -91,6 +98,10 @@ virtual sample_t **getAudioInputBuffers() = 0; virtual sample_t **getAudioOutputBuffers() = 0; + // Control inputs are known as parameters here + virtual size_t getControlOutputCount() const = 0; + virtual float getControlOutputValue(size_t n) const = 0; + // virtual QStringList getPrograms() const { return QStringList(); } // virtual QString getCurrentProgram() const { return QString(); } virtual std::string getProgram(int /* bank */, int /* program */) const { return std::string(); } diff -r 9705a1978ecc -r 3086ff194ea0 plugin/api/svp.h --- a/plugin/api/svp.h Fri Mar 24 18:15:50 2006 +0000 +++ b/plugin/api/svp.h Mon Mar 27 15:03:02 2006 +0000 @@ -113,8 +113,8 @@ unsigned int (*getPreferredBlockSize)(SVPPluginHandle); unsigned int (*getMinChannelCount)(SVPPluginHandle); unsigned int (*getMaxChannelCount)(SVPPluginHandle); + unsigned int (*getOutputCount)(SVPPluginHandle); - SVPOutputDescriptor *(*getOutputDescriptor)(SVPPluginHandle, unsigned int); void (*releaseOutputDescriptor)(SVPOutputDescriptor *); diff -r 9705a1978ecc -r 3086ff194ea0 transform/RealTimePluginTransform.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/transform/RealTimePluginTransform.cpp Mon Mar 27 15:03:02 2006 +0000 @@ -0,0 +1,160 @@ + +/* -*- 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 "RealTimePluginTransform.h" + +#include "plugin/RealTimePluginFactory.h" +#include "plugin/RealTimePluginInstance.h" + +#include "base/Model.h" +#include "model/SparseTimeValueModel.h" +#include "model/DenseTimeValueModel.h" + +#include + +RealTimePluginTransform::RealTimePluginTransform(Model *inputModel, + QString pluginId, + QString configurationXml, + int output) : + Transform(inputModel), + m_plugin(0), + m_outputNo(output) +{ + std::cerr << "RealTimePluginTransform::RealTimePluginTransform: plugin " << pluginId.toStdString() << ", output " << output << std::endl; + + RealTimePluginFactory *factory = + RealTimePluginFactory::instanceFor(pluginId); + + if (!factory) { + std::cerr << "RealTimePluginTransform: No factory available for plugin id \"" + << pluginId.toStdString() << "\"" << std::endl; + return; + } + + DenseTimeValueModel *input = getInput(); + if (!input) return; + + m_plugin = factory->instantiatePlugin(pluginId, 0, 0, m_input->getSampleRate(), + 1024, //!!! wants to be configurable + input->getChannelCount()); + + if (!m_plugin) { + std::cerr << "RealTimePluginTransform: Failed to instantiate plugin \"" + << pluginId.toStdString() << "\"" << std::endl; + return; + } + + if (configurationXml != "") { + m_plugin->setParametersFromXml(configurationXml); + } + + if (m_outputNo >= m_plugin->getControlOutputCount()) { + std::cerr << "RealTimePluginTransform: Plugin has fewer than desired " << m_outputNo << " control outputs" << std::endl; + return; + } + + m_output = new SparseTimeValueModel(input->getSampleRate(), + 1024, //!!! + 0.0, 0.0, false); +} + +RealTimePluginTransform::~RealTimePluginTransform() +{ + delete m_plugin; +} + +DenseTimeValueModel * +RealTimePluginTransform::getInput() +{ + DenseTimeValueModel *dtvm = + dynamic_cast(getInputModel()); + if (!dtvm) { + std::cerr << "RealTimePluginTransform::getInput: WARNING: Input model is not conformable to DenseTimeValueModel" << std::endl; + } + return dtvm; +} + +void +RealTimePluginTransform::run() +{ + DenseTimeValueModel *input = getInput(); + if (!input) return; + + SparseTimeValueModel *model = dynamic_cast(m_output); + if (!model) return; + + if (m_outputNo >= m_plugin->getControlOutputCount()) return; + + size_t sampleRate = input->getSampleRate(); + int channelCount = input->getChannelCount(); + size_t blockSize = m_plugin->getBufferSize(); + + float **buffers = m_plugin->getAudioInputBuffers(); + + size_t startFrame = m_input->getStartFrame(); + size_t endFrame = m_input->getEndFrame(); + size_t blockFrame = startFrame; + + size_t prevCompletion = 0; + + int i = 0; + + while (blockFrame < endFrame) { + + std::cout << "RealTimePluginTransform::run: blockFrame " + << blockFrame; + + size_t completion = + (((blockFrame - startFrame) / blockSize) * 99) / + ( (endFrame - startFrame) / blockSize); + + size_t got = 0; + + if (channelCount == 1) { + got = input->getValues + (-1, blockFrame, blockFrame + blockSize, buffers[0]); + while (got < blockSize) { + buffers[0][got++] = 0.0; + } + } else { + for (size_t ch = 0; ch < channelCount; ++ch) { + got = input->getValues + (ch, blockFrame, blockFrame + blockSize, buffers[ch]); + while (got < blockSize) { + buffers[ch][got++] = 0.0; + } + } + } + + m_plugin->run(RealTime::frame2RealTime(blockFrame, sampleRate)); + + float value = m_plugin->getControlOutputValue(m_outputNo); + + std::cout << " value " << value << std::endl; + + model->addPoint(SparseTimeValueModel::Point(blockFrame, value, "")); + + if (blockFrame == startFrame || completion > prevCompletion) { + model->setCompletion(completion); + prevCompletion = completion; + } + + blockFrame += blockSize; + } + + model->setCompletion(100); +} + diff -r 9705a1978ecc -r 3086ff194ea0 transform/RealTimePluginTransform.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/transform/RealTimePluginTransform.h Mon Mar 27 15:03:02 2006 +0000 @@ -0,0 +1,44 @@ +/* -*- 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 _REAL_TIME_PLUGIN_TRANSFORM_H_ +#define _REAL_TIME_PLUGIN_TRANSFORM_H_ + +#include "Transform.h" +#include "RealTimePluginInstance.h" + +class DenseTimeValueModel; + +class RealTimePluginTransform : public Transform +{ +public: + RealTimePluginTransform(Model *inputModel, + QString plugin, + QString configurationXml = "", + int output = 0); + virtual ~RealTimePluginTransform(); + +protected: + virtual void run(); + + RealTimePluginInstance *m_plugin; + int m_outputNo; + + // just casts + DenseTimeValueModel *getInput(); +}; + +#endif + diff -r 9705a1978ecc -r 3086ff194ea0 transform/TransformFactory.cpp --- a/transform/TransformFactory.cpp Fri Mar 24 18:15:50 2006 +0000 +++ b/transform/TransformFactory.cpp Mon Mar 27 15:03:02 2006 +0000 @@ -16,8 +16,10 @@ #include "TransformFactory.h" #include "FeatureExtractionPluginTransform.h" +#include "RealTimePluginTransform.h" #include "plugin/FeatureExtractionPluginFactory.h" +#include "plugin/RealTimePluginFactory.h" #include "widgets/PluginParameterDialog.h" @@ -53,14 +55,57 @@ void TransformFactory::populateTransforms() { - std::vector fexplugs = + TransformDescriptionMap transforms; + + populateFeatureExtractionPlugins(transforms); + populateRealTimePlugins(transforms); + + // disambiguate plugins with similar descriptions + + std::map 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 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 plugs = FeatureExtractionPluginFactory::getAllPluginIdentifiers(); - std::map makers; + for (size_t i = 0; i < plugs.size(); ++i) { - for (size_t i = 0; i < fexplugs.size(); ++i) { - - QString pluginId = fexplugs[i]; + QString pluginId = plugs[i]; FeatureExtractionPluginFactory *factory = FeatureExtractionPluginFactory::instanceFor(pluginId); @@ -88,62 +133,92 @@ .arg(pluginId).arg(outputs[j].name.c_str()); QString userDescription; + QString friendlyName; 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()); - m_transforms[transformName] = + transforms[transformName] = TransformDesc(transformName, userDescription, + friendlyName, + plugin->getMaker().c_str(), configurable); - - makers[transformName] = plugin->getMaker().c_str(); } } +} - // disambiguate plugins with similar descriptions +void +TransformFactory::populateRealTimePlugins(TransformDescriptionMap &transforms) +{ + std::vector plugs = + RealTimePluginFactory::getAllPluginIdentifiers(); - std::map descriptions; + for (size_t i = 0; i < plugs.size(); ++i) { + + QString pluginId = plugs[i]; - for (TransformDescriptionMap::iterator i = m_transforms.begin(); - i != m_transforms.end(); ++i) { + RealTimePluginFactory *factory = + RealTimePluginFactory::instanceFor(pluginId); - TransformDesc desc = i->second; - - ++descriptions[desc.description]; - ++descriptions[QString("%1 [%2]").arg(desc.description).arg(makers[desc.name])]; - } - - std::map counts; - TransformDescriptionMap newMap; - - for (TransformDescriptionMap::iterator i = m_transforms.begin(); - i != m_transforms.end(); ++i) { - - TransformDesc desc = i->second; - QString name = desc.name, description = desc.description; - - if (descriptions[description] > 1) { - description = QString("%1 [%2]").arg(description).arg(makers[name]); - if (descriptions[description] > 1) { - description = QString("%1 <%2>") - .arg(description).arg(++counts[description]); - } + if (!factory) { + std::cerr << "WARNING: TransformFactory::populateTransforms: No real time plugin factory for instance " << pluginId.toLocal8Bit().data() << std::endl; + continue; } - desc.description = description; - newMap[name] = desc; - } - - m_transforms = newMap; + 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; + + if (j < descriptor->controlOutputPortNames.size() && + descriptor->controlOutputPortNames[j] != "") { + userDescription = tr("%1: %2") + .arg(pluginDescription) + .arg(descriptor->controlOutputPortNames[j].c_str()); + } 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(transformName, + userDescription, + userDescription, + descriptor->maker.c_str(), + configurable); + } + } } QString @@ -157,14 +232,9 @@ QString TransformFactory::getTransformFriendlyName(TransformName name) { - QString description = getTransformDescription(name); - - int i = description.indexOf(':'); - if (i >= 0) { - return description.remove(0, i + 2); - } else { - return description; - } + if (m_transforms.find(name) != m_transforms.end()) { + return m_transforms[name].friendlyName; + } else return ""; } bool @@ -188,22 +258,30 @@ std::cerr << "last configuration: " << configurationXml.toStdString() << std::endl; + PluginInstance *plugin = 0; + if (FeatureExtractionPluginFactory::instanceFor(id)) { - FeatureExtractionPlugin *plugin = - FeatureExtractionPluginFactory::instanceFor(id)->instantiatePlugin + + 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 dialog; - delete plugin; + + } else if (RealTimePluginFactory::instanceFor(id)) { + + plugin = RealTimePluginFactory::instanceFor(id)->instantiatePlugin + (id, 0, 0, inputModel->getSampleRate(), 1024, 1); + } + + if (plugin) { + if (configurationXml != "") { + plugin->setParametersFromXml(configurationXml); } + PluginParameterDialog *dialog = new PluginParameterDialog(plugin); + if (dialog->exec() == QDialog::Accepted) { + ok = true; + } + configurationXml = plugin->toXmlString(); + delete dialog; + delete plugin; } if (ok) m_lastConfigurations[name] = configurationXml; @@ -217,11 +295,6 @@ { Transform *transform = 0; - // 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); @@ -230,6 +303,11 @@ id, configurationXml, output); + } else if (RealTimePluginFactory::instanceFor(id)) { + transform = new RealTimePluginTransform(inputModel, + id, + configurationXml, + output.toInt()); } else { std::cerr << "TransformFactory::createTransform: Unknown transform " << name.toStdString() << std::endl; diff -r 9705a1978ecc -r 3086ff194ea0 transform/TransformFactory.h --- a/transform/TransformFactory.h Fri Mar 24 18:15:50 2006 +0000 +++ b/transform/TransformFactory.h Mon Mar 27 15:03:02 2006 +0000 @@ -33,14 +33,20 @@ // 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). + // same (just to avoid user confusion). The friendly name is a + // shorter version of the description. struct TransformDesc { TransformDesc() { } - TransformDesc(TransformName _name, QString _description, bool _configurable) : - name(_name), description(_description), configurable(_configurable) { } + TransformDesc(TransformName _name, QString _description, + QString _friendlyName, QString _maker, + bool _configurable) : + name(_name), description(_description), friendlyName(_friendlyName), + maker(_maker), configurable(_configurable) { } TransformName name; QString description; + QString friendlyName; + QString maker; bool configurable; }; typedef std::vector TransformList; @@ -116,6 +122,8 @@ TransformDescriptionMap m_transforms; void populateTransforms(); + void populateFeatureExtractionPlugins(TransformDescriptionMap &); + void populateRealTimePlugins(TransformDescriptionMap &); static TransformFactory *m_instance; };