cannam@1: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ cannam@1: cannam@1: /* cannam@1: Vamp cannam@1: cannam@1: An API for audio analysis and feature extraction plugins. cannam@1: cannam@1: Centre for Digital Music, Queen Mary, University of London. cannam@1: Copyright 2006 Chris Cannam. cannam@1: cannam@1: Permission is hereby granted, free of charge, to any person cannam@1: obtaining a copy of this software and associated documentation cannam@1: files (the "Software"), to deal in the Software without cannam@1: restriction, including without limitation the rights to use, copy, cannam@1: modify, merge, publish, distribute, sublicense, and/or sell copies cannam@1: of the Software, and to permit persons to whom the Software is cannam@1: furnished to do so, subject to the following conditions: cannam@1: cannam@1: The above copyright notice and this permission notice shall be cannam@1: included in all copies or substantial portions of the Software. cannam@1: cannam@1: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, cannam@1: EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF cannam@1: MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND cannam@6: NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR cannam@1: ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF cannam@1: CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION cannam@1: WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. cannam@1: cannam@1: Except as contained in this notice, the names of the Centre for cannam@1: Digital Music; Queen Mary, University of London; and Chris Cannam cannam@1: shall not be used in advertising or otherwise to promote the sale, cannam@1: use or other dealings in this Software without prior written cannam@1: authorization. cannam@1: */ cannam@1: cannam@230: #include cannam@130: #include cannam@1: Chris@512: #include "Files.h" Chris@512: Chris@516: #if ( VAMP_SDK_MAJOR_VERSION != 2 || VAMP_SDK_MINOR_VERSION != 8 ) cannam@308: #error Unexpected version of Vamp SDK header included cannam@234: #endif cannam@234: cannam@263: _VAMP_SDK_HOSTSPACE_BEGIN(PluginHostAdapter.cpp) cannam@263: cannam@1: namespace Vamp cannam@1: { cannam@1: cannam@1: PluginHostAdapter::PluginHostAdapter(const VampPluginDescriptor *descriptor, cannam@1: float inputSampleRate) : cannam@1: Plugin(inputSampleRate), cannam@1: m_descriptor(descriptor) cannam@1: { cannam@15: // std::cerr << "PluginHostAdapter::PluginHostAdapter (plugin = " << descriptor->name << ")" << std::endl; cannam@1: m_handle = m_descriptor->instantiate(m_descriptor, inputSampleRate); cannam@15: if (!m_handle) { cannam@15: // std::cerr << "WARNING: PluginHostAdapter: Plugin instantiation failed for plugin " << m_descriptor->name << std::endl; cannam@15: } cannam@1: } cannam@1: cannam@1: PluginHostAdapter::~PluginHostAdapter() cannam@1: { cannam@15: // std::cerr << "PluginHostAdapter::~PluginHostAdapter (plugin = " << m_descriptor->name << ")" << std::endl; cannam@1: if (m_handle) m_descriptor->cleanup(m_handle); cannam@1: } cannam@1: cannam@32: std::vector cannam@32: PluginHostAdapter::getPluginPath() cannam@32: { cannam@32: std::vector path; cannam@32: std::string envPath; cannam@32: Chris@513: if (Files::isNonNative32Bit()) { Chris@513: (void)Files::getEnvUtf8("VAMP_PATH_32", envPath); Chris@513: } else { Chris@513: (void)Files::getEnvUtf8("VAMP_PATH", envPath); Chris@513: } cannam@32: cannam@32: #ifdef _WIN32 cannam@32: #define PATH_SEPARATOR ';' cannam@32: #define DEFAULT_VAMP_PATH "%ProgramFiles%\\Vamp Plugins" cannam@32: #else cannam@32: #define PATH_SEPARATOR ':' cannam@32: #ifdef __APPLE__ cannam@35: #define DEFAULT_VAMP_PATH "$HOME/Library/Audio/Plug-Ins/Vamp:/Library/Audio/Plug-Ins/Vamp" cannam@32: #else cannam@35: #define DEFAULT_VAMP_PATH "$HOME/vamp:$HOME/.vamp:/usr/local/lib/vamp:/usr/lib/vamp" cannam@32: #endif cannam@32: #endif cannam@32: cannam@32: if (envPath == "") { cannam@32: envPath = DEFAULT_VAMP_PATH; Chris@512: std::string home; Chris@512: if (Files::getEnvUtf8("HOME", home)) { cannam@32: std::string::size_type f; cannam@32: while ((f = envPath.find("$HOME")) != std::string::npos && cannam@32: f < envPath.length()) { cannam@32: envPath.replace(f, 5, home); cannam@32: } cannam@32: } cannam@32: #ifdef _WIN32 Chris@512: std::string pfiles; Chris@512: if (!Files::getEnvUtf8("ProgramFiles", pfiles)) { Chris@512: pfiles = "C:\\Program Files"; Chris@512: } cannam@32: std::string::size_type f; cannam@32: while ((f = envPath.find("%ProgramFiles%")) != std::string::npos && cannam@32: f < envPath.length()) { cannam@32: envPath.replace(f, 14, pfiles); cannam@32: } cannam@32: #endif cannam@32: } cannam@32: cannam@32: std::string::size_type index = 0, newindex = 0; cannam@32: cannam@32: while ((newindex = envPath.find(PATH_SEPARATOR, index)) < envPath.size()) { cannam@32: path.push_back(envPath.substr(index, newindex - index)); cannam@32: index = newindex + 1; cannam@32: } cannam@32: cannam@32: path.push_back(envPath.substr(index)); cannam@32: cannam@32: return path; cannam@32: } cannam@32: cannam@1: bool cannam@1: PluginHostAdapter::initialise(size_t channels, cannam@1: size_t stepSize, cannam@1: size_t blockSize) cannam@1: { cannam@1: if (!m_handle) return false; Chris@421: return m_descriptor->initialise Chris@421: (m_handle, Chris@421: (unsigned int)channels, Chris@421: (unsigned int)stepSize, Chris@421: (unsigned int)blockSize) ? cannam@1: true : false; cannam@1: } cannam@1: cannam@1: void cannam@1: PluginHostAdapter::reset() cannam@1: { cannam@197: if (!m_handle) { cannam@197: // std::cerr << "PluginHostAdapter::reset: no handle" << std::endl; cannam@197: return; cannam@197: } cannam@197: // std::cerr << "PluginHostAdapter::reset(" << m_handle << ")" << std::endl; cannam@1: m_descriptor->reset(m_handle); cannam@1: } cannam@1: cannam@1: PluginHostAdapter::InputDomain cannam@1: PluginHostAdapter::getInputDomain() const cannam@1: { cannam@1: if (m_descriptor->inputDomain == vampFrequencyDomain) { cannam@1: return FrequencyDomain; cannam@1: } else { cannam@1: return TimeDomain; cannam@1: } cannam@1: } cannam@1: cannam@50: unsigned int cannam@50: PluginHostAdapter::getVampApiVersion() const cannam@50: { cannam@50: return m_descriptor->vampApiVersion; cannam@50: } cannam@50: cannam@1: std::string cannam@49: PluginHostAdapter::getIdentifier() const cannam@49: { cannam@49: return m_descriptor->identifier; cannam@49: } cannam@49: cannam@49: std::string cannam@1: PluginHostAdapter::getName() const cannam@1: { cannam@1: return m_descriptor->name; cannam@1: } cannam@1: cannam@1: std::string cannam@1: PluginHostAdapter::getDescription() const cannam@1: { cannam@1: return m_descriptor->description; cannam@1: } cannam@1: cannam@1: std::string cannam@1: PluginHostAdapter::getMaker() const cannam@1: { cannam@1: return m_descriptor->maker; cannam@1: } cannam@1: cannam@1: int cannam@1: PluginHostAdapter::getPluginVersion() const cannam@1: { cannam@1: return m_descriptor->pluginVersion; cannam@1: } cannam@1: cannam@1: std::string cannam@1: PluginHostAdapter::getCopyright() const cannam@1: { cannam@1: return m_descriptor->copyright; cannam@1: } cannam@1: cannam@1: PluginHostAdapter::ParameterList cannam@1: PluginHostAdapter::getParameterDescriptors() const cannam@1: { cannam@1: ParameterList list; cannam@1: for (unsigned int i = 0; i < m_descriptor->parameterCount; ++i) { cannam@1: const VampParameterDescriptor *spd = m_descriptor->parameters[i]; cannam@1: ParameterDescriptor pd; cannam@49: pd.identifier = spd->identifier; cannam@1: pd.name = spd->name; cannam@1: pd.description = spd->description; cannam@1: pd.unit = spd->unit; cannam@1: pd.minValue = spd->minValue; cannam@1: pd.maxValue = spd->maxValue; cannam@1: pd.defaultValue = spd->defaultValue; cannam@1: pd.isQuantized = spd->isQuantized; cannam@1: pd.quantizeStep = spd->quantizeStep; cannam@9: if (pd.isQuantized && spd->valueNames) { cannam@9: for (unsigned int j = 0; spd->valueNames[j]; ++j) { cannam@9: pd.valueNames.push_back(spd->valueNames[j]); cannam@9: } cannam@9: } cannam@1: list.push_back(pd); cannam@1: } cannam@1: return list; cannam@1: } cannam@1: cannam@1: float cannam@1: PluginHostAdapter::getParameter(std::string param) const cannam@1: { cannam@1: if (!m_handle) return 0.0; cannam@1: cannam@1: for (unsigned int i = 0; i < m_descriptor->parameterCount; ++i) { cannam@49: if (param == m_descriptor->parameters[i]->identifier) { cannam@1: return m_descriptor->getParameter(m_handle, i); cannam@1: } cannam@1: } cannam@1: cannam@1: return 0.0; cannam@1: } cannam@1: cannam@1: void cannam@1: PluginHostAdapter::setParameter(std::string param, cannam@1: float value) cannam@1: { cannam@1: if (!m_handle) return; cannam@1: cannam@1: for (unsigned int i = 0; i < m_descriptor->parameterCount; ++i) { cannam@49: if (param == m_descriptor->parameters[i]->identifier) { cannam@1: m_descriptor->setParameter(m_handle, i, value); cannam@1: return; cannam@1: } cannam@1: } cannam@1: } cannam@1: cannam@1: PluginHostAdapter::ProgramList cannam@1: PluginHostAdapter::getPrograms() const cannam@1: { cannam@1: ProgramList list; cannam@1: cannam@1: for (unsigned int i = 0; i < m_descriptor->programCount; ++i) { cannam@1: list.push_back(m_descriptor->programs[i]); cannam@1: } cannam@1: cannam@1: return list; cannam@1: } cannam@1: cannam@1: std::string cannam@1: PluginHostAdapter::getCurrentProgram() const cannam@1: { cannam@1: if (!m_handle) return ""; cannam@1: cannam@1: int pn = m_descriptor->getCurrentProgram(m_handle); Chris@345: if (pn < (int)m_descriptor->programCount) { Chris@345: return m_descriptor->programs[pn]; Chris@345: } else { Chris@345: return ""; Chris@345: } cannam@1: } cannam@1: cannam@1: void cannam@1: PluginHostAdapter::selectProgram(std::string program) cannam@1: { cannam@1: if (!m_handle) return; cannam@1: cannam@1: for (unsigned int i = 0; i < m_descriptor->programCount; ++i) { cannam@1: if (program == m_descriptor->programs[i]) { cannam@1: m_descriptor->selectProgram(m_handle, i); cannam@1: return; cannam@1: } cannam@1: } cannam@1: } cannam@1: cannam@1: size_t cannam@1: PluginHostAdapter::getPreferredStepSize() const cannam@1: { cannam@1: if (!m_handle) return 0; cannam@1: return m_descriptor->getPreferredStepSize(m_handle); cannam@1: } cannam@1: cannam@1: size_t cannam@1: PluginHostAdapter::getPreferredBlockSize() const cannam@1: { cannam@1: if (!m_handle) return 0; cannam@1: return m_descriptor->getPreferredBlockSize(m_handle); cannam@1: } cannam@1: cannam@26: size_t cannam@26: PluginHostAdapter::getMinChannelCount() const cannam@26: { cannam@26: if (!m_handle) return 0; cannam@26: return m_descriptor->getMinChannelCount(m_handle); cannam@26: } cannam@26: cannam@26: size_t cannam@26: PluginHostAdapter::getMaxChannelCount() const cannam@26: { cannam@26: if (!m_handle) return 0; cannam@26: return m_descriptor->getMaxChannelCount(m_handle); cannam@26: } cannam@26: cannam@1: PluginHostAdapter::OutputList cannam@1: PluginHostAdapter::getOutputDescriptors() const cannam@1: { cannam@1: OutputList list; cannam@15: if (!m_handle) { cannam@15: // std::cerr << "PluginHostAdapter::getOutputDescriptors: no handle " << std::endl; cannam@15: return list; cannam@15: } cannam@1: cannam@1: unsigned int count = m_descriptor->getOutputCount(m_handle); cannam@1: cannam@1: for (unsigned int i = 0; i < count; ++i) { cannam@1: VampOutputDescriptor *sd = m_descriptor->getOutputDescriptor(m_handle, i); cannam@1: OutputDescriptor d; cannam@49: d.identifier = sd->identifier; cannam@1: d.name = sd->name; cannam@1: d.description = sd->description; cannam@1: d.unit = sd->unit; cannam@9: d.hasFixedBinCount = sd->hasFixedBinCount; cannam@9: d.binCount = sd->binCount; cannam@240: if (d.hasFixedBinCount && sd->binNames) { cannam@9: for (unsigned int j = 0; j < sd->binCount; ++j) { cannam@9: d.binNames.push_back(sd->binNames[j] ? sd->binNames[j] : ""); cannam@9: } cannam@1: } cannam@1: d.hasKnownExtents = sd->hasKnownExtents; cannam@1: d.minValue = sd->minValue; cannam@1: d.maxValue = sd->maxValue; cannam@1: d.isQuantized = sd->isQuantized; cannam@1: d.quantizeStep = sd->quantizeStep; cannam@1: cannam@1: switch (sd->sampleType) { cannam@1: case vampOneSamplePerStep: cannam@1: d.sampleType = OutputDescriptor::OneSamplePerStep; break; cannam@1: case vampFixedSampleRate: cannam@1: d.sampleType = OutputDescriptor::FixedSampleRate; break; cannam@1: case vampVariableSampleRate: cannam@1: d.sampleType = OutputDescriptor::VariableSampleRate; break; cannam@1: } cannam@1: cannam@1: d.sampleRate = sd->sampleRate; cannam@1: cannam@192: if (m_descriptor->vampApiVersion >= 2) { cannam@192: d.hasDuration = sd->hasDuration; cannam@192: } else { cannam@192: d.hasDuration = false; cannam@192: } cannam@192: cannam@1: list.push_back(d); cannam@1: cannam@1: m_descriptor->releaseOutputDescriptor(sd); cannam@1: } cannam@1: cannam@1: return list; cannam@1: } cannam@1: cannam@1: PluginHostAdapter::FeatureSet cannam@47: PluginHostAdapter::process(const float *const *inputBuffers, cannam@47: RealTime timestamp) cannam@1: { cannam@1: FeatureSet fs; cannam@1: if (!m_handle) return fs; cannam@1: cannam@1: int sec = timestamp.sec; cannam@1: int nsec = timestamp.nsec; cannam@1: cannam@12: VampFeatureList *features = m_descriptor->process(m_handle, cannam@1: inputBuffers, cannam@1: sec, nsec); cannam@1: cannam@1: convertFeatures(features, fs); cannam@1: m_descriptor->releaseFeatureSet(features); cannam@1: return fs; cannam@1: } cannam@1: cannam@1: PluginHostAdapter::FeatureSet cannam@1: PluginHostAdapter::getRemainingFeatures() cannam@1: { cannam@1: FeatureSet fs; cannam@1: if (!m_handle) return fs; cannam@1: cannam@12: VampFeatureList *features = m_descriptor->getRemainingFeatures(m_handle); cannam@1: cannam@1: convertFeatures(features, fs); cannam@1: m_descriptor->releaseFeatureSet(features); cannam@1: return fs; cannam@1: } cannam@1: cannam@1: void cannam@12: PluginHostAdapter::convertFeatures(VampFeatureList *features, cannam@1: FeatureSet &fs) cannam@1: { cannam@7: if (!features) return; cannam@7: cannam@12: unsigned int outputs = m_descriptor->getOutputCount(m_handle); cannam@12: cannam@12: for (unsigned int i = 0; i < outputs; ++i) { cannam@1: cannam@12: VampFeatureList &list = features[i]; cannam@1: cannam@1: if (list.featureCount > 0) { cannam@1: cannam@108: Feature feature; cannam@168: feature.values.reserve(list.features[0].v1.valueCount); cannam@108: cannam@1: for (unsigned int j = 0; j < list.featureCount; ++j) { cannam@108: cannam@168: feature.hasTimestamp = list.features[j].v1.hasTimestamp; cannam@168: feature.timestamp = RealTime(list.features[j].v1.sec, cannam@168: list.features[j].v1.nsec); cannam@168: feature.hasDuration = false; cannam@1: cannam@167: if (m_descriptor->vampApiVersion >= 2) { cannam@168: unsigned int j2 = j + list.featureCount; cannam@168: feature.hasDuration = list.features[j2].v2.hasDuration; cannam@168: feature.duration = RealTime(list.features[j2].v2.durationSec, cannam@168: list.features[j2].v2.durationNsec); cannam@167: } cannam@167: cannam@168: for (unsigned int k = 0; k < list.features[j].v1.valueCount; ++k) { cannam@168: feature.values.push_back(list.features[j].v1.values[k]); cannam@1: } cannam@7: cannam@168: if (list.features[j].v1.label) { cannam@168: feature.label = list.features[j].v1.label; cannam@7: } cannam@1: cannam@1: fs[i].push_back(feature); cannam@108: cannam@168: if (list.features[j].v1.valueCount > 0) { cannam@108: feature.values.clear(); cannam@108: } cannam@108: cannam@168: if (list.features[j].v1.label) { cannam@108: feature.label = ""; cannam@108: } cannam@1: } cannam@1: } cannam@1: } cannam@1: } cannam@1: cannam@1: } cannam@263: cannam@263: _VAMP_SDK_HOSTSPACE_END(PluginHostAdapter.cpp) cannam@263: