cannam@0: cannam@0:
cannam@0:00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ cannam@0: 00002 cannam@0: 00003 /* cannam@0: 00004 Vamp cannam@0: 00005 cannam@0: 00006 An API for audio analysis and feature extraction plugins. cannam@0: 00007 cannam@0: 00008 Centre for Digital Music, Queen Mary, University of London. cannam@0: 00009 Copyright 2006 Chris Cannam. cannam@0: 00010 cannam@0: 00011 Permission is hereby granted, free of charge, to any person cannam@0: 00012 obtaining a copy of this software and associated documentation cannam@0: 00013 files (the "Software"), to deal in the Software without cannam@0: 00014 restriction, including without limitation the rights to use, copy, cannam@0: 00015 modify, merge, publish, distribute, sublicense, and/or sell copies cannam@0: 00016 of the Software, and to permit persons to whom the Software is cannam@0: 00017 furnished to do so, subject to the following conditions: cannam@0: 00018 cannam@0: 00019 The above copyright notice and this permission notice shall be cannam@0: 00020 included in all copies or substantial portions of the Software. cannam@0: 00021 cannam@0: 00022 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, cannam@0: 00023 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF cannam@0: 00024 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND cannam@0: 00025 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR cannam@0: 00026 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF cannam@0: 00027 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION cannam@0: 00028 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. cannam@0: 00029 cannam@0: 00030 Except as contained in this notice, the names of the Centre for cannam@0: 00031 Digital Music; Queen Mary, University of London; and Chris Cannam cannam@0: 00032 shall not be used in advertising or otherwise to promote the sale, cannam@0: 00033 use or other dealings in this Software without prior written cannam@0: 00034 authorization. cannam@0: 00035 */ cannam@0: 00036 cannam@0: 00037 #include "PluginHostAdapter.h" cannam@0: 00038 #include <cstdlib> cannam@0: 00039 cannam@0: 00040 namespace Vamp cannam@0: 00041 { cannam@0: 00042 cannam@0: 00043 PluginHostAdapter::PluginHostAdapter(const VampPluginDescriptor *descriptor, cannam@0: 00044 float inputSampleRate) : cannam@0: 00045 Plugin(inputSampleRate), cannam@0: 00046 m_descriptor(descriptor) cannam@0: 00047 { cannam@0: 00048 // std::cerr << "PluginHostAdapter::PluginHostAdapter (plugin = " << descriptor->name << ")" << std::endl; cannam@0: 00049 m_handle = m_descriptor->instantiate(m_descriptor, inputSampleRate); cannam@0: 00050 if (!m_handle) { cannam@0: 00051 // std::cerr << "WARNING: PluginHostAdapter: Plugin instantiation failed for plugin " << m_descriptor->name << std::endl; cannam@0: 00052 } cannam@0: 00053 } cannam@0: 00054 cannam@0: 00055 PluginHostAdapter::~PluginHostAdapter() cannam@0: 00056 { cannam@0: 00057 // std::cerr << "PluginHostAdapter::~PluginHostAdapter (plugin = " << m_descriptor->name << ")" << std::endl; cannam@0: 00058 if (m_handle) m_descriptor->cleanup(m_handle); cannam@0: 00059 } cannam@0: 00060 cannam@0: 00061 std::vector<std::string> cannam@0: 00062 PluginHostAdapter::getPluginPath() cannam@0: 00063 { cannam@0: 00064 std::vector<std::string> path; cannam@0: 00065 std::string envPath; cannam@0: 00066 cannam@0: 00067 char *cpath = getenv("VAMP_PATH"); cannam@0: 00068 if (cpath) envPath = cpath; cannam@0: 00069 cannam@0: 00070 #ifdef _WIN32 cannam@0: 00071 #define PATH_SEPARATOR ';' cannam@0: 00072 #define DEFAULT_VAMP_PATH "%ProgramFiles%\\Vamp Plugins" cannam@0: 00073 #else cannam@0: 00074 #define PATH_SEPARATOR ':' cannam@0: 00075 #ifdef __APPLE__ cannam@0: 00076 #define DEFAULT_VAMP_PATH "$HOME/Library/Audio/Plug-Ins/Vamp:/Library/Audio/Plug-Ins/Vamp" cannam@0: 00077 #else cannam@0: 00078 #define DEFAULT_VAMP_PATH "$HOME/vamp:$HOME/.vamp:/usr/local/lib/vamp:/usr/lib/vamp" cannam@0: 00079 #endif cannam@0: 00080 #endif cannam@0: 00081 cannam@0: 00082 if (envPath == "") { cannam@0: 00083 envPath = DEFAULT_VAMP_PATH; cannam@0: 00084 char *chome = getenv("HOME"); cannam@0: 00085 if (chome) { cannam@0: 00086 std::string home(chome); cannam@0: 00087 std::string::size_type f; cannam@0: 00088 while ((f = envPath.find("$HOME")) != std::string::npos && cannam@0: 00089 f < envPath.length()) { cannam@0: 00090 envPath.replace(f, 5, home); cannam@0: 00091 } cannam@0: 00092 } cannam@0: 00093 #ifdef _WIN32 cannam@0: 00094 char *cpfiles = getenv("ProgramFiles"); cannam@0: 00095 if (!cpfiles) cpfiles = "C:\\Program Files"; cannam@0: 00096 std::string pfiles(cpfiles); cannam@0: 00097 std::string::size_type f; cannam@0: 00098 while ((f = envPath.find("%ProgramFiles%")) != std::string::npos && cannam@0: 00099 f < envPath.length()) { cannam@0: 00100 envPath.replace(f, 14, pfiles); cannam@0: 00101 } cannam@0: 00102 #endif cannam@0: 00103 } cannam@0: 00104 cannam@0: 00105 std::string::size_type index = 0, newindex = 0; cannam@0: 00106 cannam@0: 00107 while ((newindex = envPath.find(PATH_SEPARATOR, index)) < envPath.size()) { cannam@0: 00108 path.push_back(envPath.substr(index, newindex - index)); cannam@0: 00109 index = newindex + 1; cannam@0: 00110 } cannam@0: 00111 cannam@0: 00112 path.push_back(envPath.substr(index)); cannam@0: 00113 cannam@0: 00114 return path; cannam@0: 00115 } cannam@0: 00116 cannam@0: 00117 bool cannam@0: 00118 PluginHostAdapter::initialise(size_t channels, cannam@0: 00119 size_t stepSize, cannam@0: 00120 size_t blockSize) cannam@0: 00121 { cannam@0: 00122 if (!m_handle) return false; cannam@0: 00123 return m_descriptor->initialise(m_handle, channels, stepSize, blockSize) ? cannam@0: 00124 true : false; cannam@0: 00125 } cannam@0: 00126 cannam@0: 00127 void cannam@0: 00128 PluginHostAdapter::reset() cannam@0: 00129 { cannam@0: 00130 if (!m_handle) return; cannam@0: 00131 m_descriptor->reset(m_handle); cannam@0: 00132 } cannam@0: 00133 cannam@0: 00134 PluginHostAdapter::InputDomain cannam@0: 00135 PluginHostAdapter::getInputDomain() const cannam@0: 00136 { cannam@0: 00137 if (m_descriptor->inputDomain == vampFrequencyDomain) { cannam@0: 00138 return FrequencyDomain; cannam@0: 00139 } else { cannam@0: 00140 return TimeDomain; cannam@0: 00141 } cannam@0: 00142 } cannam@0: 00143 cannam@0: 00144 unsigned int cannam@0: 00145 PluginHostAdapter::getVampApiVersion() const cannam@0: 00146 { cannam@0: 00147 return m_descriptor->vampApiVersion; cannam@0: 00148 } cannam@0: 00149 cannam@0: 00150 std::string cannam@0: 00151 PluginHostAdapter::getIdentifier() const cannam@0: 00152 { cannam@0: 00153 return m_descriptor->identifier; cannam@0: 00154 } cannam@0: 00155 cannam@0: 00156 std::string cannam@0: 00157 PluginHostAdapter::getName() const cannam@0: 00158 { cannam@0: 00159 return m_descriptor->name; cannam@0: 00160 } cannam@0: 00161 cannam@0: 00162 std::string cannam@0: 00163 PluginHostAdapter::getDescription() const cannam@0: 00164 { cannam@0: 00165 return m_descriptor->description; cannam@0: 00166 } cannam@0: 00167 cannam@0: 00168 std::string cannam@0: 00169 PluginHostAdapter::getMaker() const cannam@0: 00170 { cannam@0: 00171 return m_descriptor->maker; cannam@0: 00172 } cannam@0: 00173 cannam@0: 00174 int cannam@0: 00175 PluginHostAdapter::getPluginVersion() const cannam@0: 00176 { cannam@0: 00177 return m_descriptor->pluginVersion; cannam@0: 00178 } cannam@0: 00179 cannam@0: 00180 std::string cannam@0: 00181 PluginHostAdapter::getCopyright() const cannam@0: 00182 { cannam@0: 00183 return m_descriptor->copyright; cannam@0: 00184 } cannam@0: 00185 cannam@0: 00186 PluginHostAdapter::ParameterList cannam@0: 00187 PluginHostAdapter::getParameterDescriptors() const cannam@0: 00188 { cannam@0: 00189 ParameterList list; cannam@0: 00190 for (unsigned int i = 0; i < m_descriptor->parameterCount; ++i) { cannam@0: 00191 const VampParameterDescriptor *spd = m_descriptor->parameters[i]; cannam@0: 00192 ParameterDescriptor pd; cannam@0: 00193 pd.identifier = spd->identifier; cannam@0: 00194 pd.name = spd->name; cannam@0: 00195 pd.description = spd->description; cannam@0: 00196 pd.unit = spd->unit; cannam@0: 00197 pd.minValue = spd->minValue; cannam@0: 00198 pd.maxValue = spd->maxValue; cannam@0: 00199 pd.defaultValue = spd->defaultValue; cannam@0: 00200 pd.isQuantized = spd->isQuantized; cannam@0: 00201 pd.quantizeStep = spd->quantizeStep; cannam@0: 00202 if (pd.isQuantized && spd->valueNames) { cannam@0: 00203 for (unsigned int j = 0; spd->valueNames[j]; ++j) { cannam@0: 00204 pd.valueNames.push_back(spd->valueNames[j]); cannam@0: 00205 } cannam@0: 00206 } cannam@0: 00207 list.push_back(pd); cannam@0: 00208 } cannam@0: 00209 return list; cannam@0: 00210 } cannam@0: 00211 cannam@0: 00212 float cannam@0: 00213 PluginHostAdapter::getParameter(std::string param) const cannam@0: 00214 { cannam@0: 00215 if (!m_handle) return 0.0; cannam@0: 00216 cannam@0: 00217 for (unsigned int i = 0; i < m_descriptor->parameterCount; ++i) { cannam@0: 00218 if (param == m_descriptor->parameters[i]->identifier) { cannam@0: 00219 return m_descriptor->getParameter(m_handle, i); cannam@0: 00220 } cannam@0: 00221 } cannam@0: 00222 cannam@0: 00223 return 0.0; cannam@0: 00224 } cannam@0: 00225 cannam@0: 00226 void cannam@0: 00227 PluginHostAdapter::setParameter(std::string param, cannam@0: 00228 float value) cannam@0: 00229 { cannam@0: 00230 if (!m_handle) return; cannam@0: 00231 cannam@0: 00232 for (unsigned int i = 0; i < m_descriptor->parameterCount; ++i) { cannam@0: 00233 if (param == m_descriptor->parameters[i]->identifier) { cannam@0: 00234 m_descriptor->setParameter(m_handle, i, value); cannam@0: 00235 return; cannam@0: 00236 } cannam@0: 00237 } cannam@0: 00238 } cannam@0: 00239 cannam@0: 00240 PluginHostAdapter::ProgramList cannam@0: 00241 PluginHostAdapter::getPrograms() const cannam@0: 00242 { cannam@0: 00243 ProgramList list; cannam@0: 00244 cannam@0: 00245 for (unsigned int i = 0; i < m_descriptor->programCount; ++i) { cannam@0: 00246 list.push_back(m_descriptor->programs[i]); cannam@0: 00247 } cannam@0: 00248 cannam@0: 00249 return list; cannam@0: 00250 } cannam@0: 00251 cannam@0: 00252 std::string cannam@0: 00253 PluginHostAdapter::getCurrentProgram() const cannam@0: 00254 { cannam@0: 00255 if (!m_handle) return ""; cannam@0: 00256 cannam@0: 00257 int pn = m_descriptor->getCurrentProgram(m_handle); cannam@0: 00258 return m_descriptor->programs[pn]; cannam@0: 00259 } cannam@0: 00260 cannam@0: 00261 void cannam@0: 00262 PluginHostAdapter::selectProgram(std::string program) cannam@0: 00263 { cannam@0: 00264 if (!m_handle) return; cannam@0: 00265 cannam@0: 00266 for (unsigned int i = 0; i < m_descriptor->programCount; ++i) { cannam@0: 00267 if (program == m_descriptor->programs[i]) { cannam@0: 00268 m_descriptor->selectProgram(m_handle, i); cannam@0: 00269 return; cannam@0: 00270 } cannam@0: 00271 } cannam@0: 00272 } cannam@0: 00273 cannam@0: 00274 size_t cannam@0: 00275 PluginHostAdapter::getPreferredStepSize() const cannam@0: 00276 { cannam@0: 00277 if (!m_handle) return 0; cannam@0: 00278 return m_descriptor->getPreferredStepSize(m_handle); cannam@0: 00279 } cannam@0: 00280 cannam@0: 00281 size_t cannam@0: 00282 PluginHostAdapter::getPreferredBlockSize() const cannam@0: 00283 { cannam@0: 00284 if (!m_handle) return 0; cannam@0: 00285 return m_descriptor->getPreferredBlockSize(m_handle); cannam@0: 00286 } cannam@0: 00287 cannam@0: 00288 size_t cannam@0: 00289 PluginHostAdapter::getMinChannelCount() const cannam@0: 00290 { cannam@0: 00291 if (!m_handle) return 0; cannam@0: 00292 return m_descriptor->getMinChannelCount(m_handle); cannam@0: 00293 } cannam@0: 00294 cannam@0: 00295 size_t cannam@0: 00296 PluginHostAdapter::getMaxChannelCount() const cannam@0: 00297 { cannam@0: 00298 if (!m_handle) return 0; cannam@0: 00299 return m_descriptor->getMaxChannelCount(m_handle); cannam@0: 00300 } cannam@0: 00301 cannam@0: 00302 PluginHostAdapter::OutputList cannam@0: 00303 PluginHostAdapter::getOutputDescriptors() const cannam@0: 00304 { cannam@0: 00305 OutputList list; cannam@0: 00306 if (!m_handle) { cannam@0: 00307 // std::cerr << "PluginHostAdapter::getOutputDescriptors: no handle " << std::endl; cannam@0: 00308 return list; cannam@0: 00309 } cannam@0: 00310 cannam@0: 00311 unsigned int count = m_descriptor->getOutputCount(m_handle); cannam@0: 00312 cannam@0: 00313 for (unsigned int i = 0; i < count; ++i) { cannam@0: 00314 VampOutputDescriptor *sd = m_descriptor->getOutputDescriptor(m_handle, i); cannam@0: 00315 OutputDescriptor d; cannam@0: 00316 d.identifier = sd->identifier; cannam@0: 00317 d.name = sd->name; cannam@0: 00318 d.description = sd->description; cannam@0: 00319 d.unit = sd->unit; cannam@0: 00320 d.hasFixedBinCount = sd->hasFixedBinCount; cannam@0: 00321 d.binCount = sd->binCount; cannam@0: 00322 if (d.hasFixedBinCount) { cannam@0: 00323 for (unsigned int j = 0; j < sd->binCount; ++j) { cannam@0: 00324 d.binNames.push_back(sd->binNames[j] ? sd->binNames[j] : ""); cannam@0: 00325 } cannam@0: 00326 } cannam@0: 00327 d.hasKnownExtents = sd->hasKnownExtents; cannam@0: 00328 d.minValue = sd->minValue; cannam@0: 00329 d.maxValue = sd->maxValue; cannam@0: 00330 d.isQuantized = sd->isQuantized; cannam@0: 00331 d.quantizeStep = sd->quantizeStep; cannam@0: 00332 cannam@0: 00333 switch (sd->sampleType) { cannam@0: 00334 case vampOneSamplePerStep: cannam@0: 00335 d.sampleType = OutputDescriptor::OneSamplePerStep; break; cannam@0: 00336 case vampFixedSampleRate: cannam@0: 00337 d.sampleType = OutputDescriptor::FixedSampleRate; break; cannam@0: 00338 case vampVariableSampleRate: cannam@0: 00339 d.sampleType = OutputDescriptor::VariableSampleRate; break; cannam@0: 00340 } cannam@0: 00341 cannam@0: 00342 d.sampleRate = sd->sampleRate; cannam@0: 00343 cannam@0: 00344 list.push_back(d); cannam@0: 00345 cannam@0: 00346 m_descriptor->releaseOutputDescriptor(sd); cannam@0: 00347 } cannam@0: 00348 cannam@0: 00349 return list; cannam@0: 00350 } cannam@0: 00351 cannam@0: 00352 PluginHostAdapter::FeatureSet cannam@0: 00353 PluginHostAdapter::process(const float *const *inputBuffers, cannam@0: 00354 RealTime timestamp) cannam@0: 00355 { cannam@0: 00356 FeatureSet fs; cannam@0: 00357 if (!m_handle) return fs; cannam@0: 00358 cannam@0: 00359 int sec = timestamp.sec; cannam@0: 00360 int nsec = timestamp.nsec; cannam@0: 00361 cannam@0: 00362 VampFeatureList *features = m_descriptor->process(m_handle, cannam@0: 00363 inputBuffers, cannam@0: 00364 sec, nsec); cannam@0: 00365 cannam@0: 00366 convertFeatures(features, fs); cannam@0: 00367 m_descriptor->releaseFeatureSet(features); cannam@0: 00368 return fs; cannam@0: 00369 } cannam@0: 00370 cannam@0: 00371 PluginHostAdapter::FeatureSet cannam@0: 00372 PluginHostAdapter::getRemainingFeatures() cannam@0: 00373 { cannam@0: 00374 FeatureSet fs; cannam@0: 00375 if (!m_handle) return fs; cannam@0: 00376 cannam@0: 00377 VampFeatureList *features = m_descriptor->getRemainingFeatures(m_handle); cannam@0: 00378 cannam@0: 00379 convertFeatures(features, fs); cannam@0: 00380 m_descriptor->releaseFeatureSet(features); cannam@0: 00381 return fs; cannam@0: 00382 } cannam@0: 00383 cannam@0: 00384 void cannam@0: 00385 PluginHostAdapter::convertFeatures(VampFeatureList *features, cannam@0: 00386 FeatureSet &fs) cannam@0: 00387 { cannam@0: 00388 if (!features) return; cannam@0: 00389 cannam@0: 00390 unsigned int outputs = m_descriptor->getOutputCount(m_handle); cannam@0: 00391 cannam@0: 00392 for (unsigned int i = 0; i < outputs; ++i) { cannam@0: 00393 cannam@0: 00394 VampFeatureList &list = features[i]; cannam@0: 00395 cannam@0: 00396 if (list.featureCount > 0) { cannam@0: 00397 cannam@0: 00398 Feature feature; cannam@0: 00399 feature.values.reserve(list.features[0].valueCount); cannam@0: 00400 cannam@0: 00401 for (unsigned int j = 0; j < list.featureCount; ++j) { cannam@0: 00402 cannam@0: 00403 feature.hasTimestamp = list.features[j].hasTimestamp; cannam@0: 00404 feature.timestamp = RealTime(list.features[j].sec, cannam@0: 00405 list.features[j].nsec); cannam@0: 00406 cannam@0: 00407 for (unsigned int k = 0; k < list.features[j].valueCount; ++k) { cannam@0: 00408 feature.values.push_back(list.features[j].values[k]); cannam@0: 00409 } cannam@0: 00410 cannam@0: 00411 if (list.features[j].label) { cannam@0: 00412 feature.label = list.features[j].label; cannam@0: 00413 } cannam@0: 00414 cannam@0: 00415 fs[i].push_back(feature); cannam@0: 00416 cannam@0: 00417 if (list.features[j].valueCount > 0) { cannam@0: 00418 feature.values.clear(); cannam@0: 00419 } cannam@0: 00420 cannam@0: 00421 if (list.features[j].label) { cannam@0: 00422 feature.label = ""; cannam@0: 00423 } cannam@0: 00424 } cannam@0: 00425 } cannam@0: 00426 } cannam@0: 00427 } cannam@0: 00428 cannam@0: 00429 } cannam@0: