diff plugin/FeatureExtractionPluginAdapter.h @ 58:0a34d529f8e0

* Add C API for feature extraction plugins * First cut of an adapter class to make C++ feature extraction plugins available using the C API. This will probably mutate quite a bit and likely move to its own SDK tree.
author Chris Cannam
date Fri, 24 Mar 2006 17:36:10 +0000
parents
children 3086ff194ea0
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin/FeatureExtractionPluginAdapter.h	Fri Mar 24 17:36:10 2006 +0000
@@ -0,0 +1,385 @@
+/* -*- 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 _FEATURE_EXTRACTION_PLUGIN_ADAPTER_H_
+#define _FEATURE_EXTRACTION_PLUGIN_ADAPTER_H_
+
+#include "api/svp.h"
+#include "FeatureExtractionPlugin.h"
+
+#include <map>
+
+template <typename Plugin>
+class FeatureExtractionPluginAdapter
+{
+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;
+    }
+
+protected:
+    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;
+    }
+
+    static void svpCleanup(SVPPluginHandle handle) {
+        if (m_adapterMap.find(handle) == m_adapterMap.end()) {
+            delete ((Plugin *)handle);
+            return;
+        }
+        m_adapterMap[handle]->cleanup(((Plugin *)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;
+    }
+
+    static void svpReset(SVPPluginHandle handle) {
+        ((Plugin *)handle)->reset();
+    }
+
+    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 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) {
+        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 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 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);
+    }
+
+    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 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);
+    }
+
+    static SVPFeatureList **svpGetRemainingFeatures(SVPPluginHandle handle) {
+        if (m_adapterMap.find(handle) == m_adapterMap.end()) return 0;
+        return m_adapterMap[handle]->getRemainingFeatures((Plugin *)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);
+    }
+
+    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 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<const void *, FeatureExtractionPluginAdapter *> AdapterMap;
+    static AdapterMap m_adapterMap;
+
+    SVPPluginDescriptor m_descriptor;
+    FeatureExtractionPlugin::ParameterList m_parameters;
+    FeatureExtractionPlugin::ProgramList m_programs;
+
+    typedef std::map<Plugin *, FeatureExtractionPlugin::OutputList *> OutputMap;
+    OutputMap m_pluginOutputs;
+
+    typedef std::map<Plugin *, SVPFeature ***> FeatureBufferMap;
+    FeatureBufferMap m_pluginFeatures;
+};
+
+template <typename Plugin>
+typename FeatureExtractionPluginAdapter<Plugin>::AdapterMap 
+FeatureExtractionPluginAdapter<Plugin>::m_adapterMap;
+
+#endif
+