annotate src/vamp-hostsdk/PluginHostAdapter.cpp @ 525:8c18bdaad04f c++11-mutex

Avoid simple static allocation of mutex, as it could lead to mutex being destroyed before last adapter that needs to use it (since adapters are usually also static)
author Chris Cannam
date Mon, 09 Sep 2019 10:24:13 +0100
parents df32b473b9b6
children db2cd87cef6f
rev   line source
cannam@1 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
cannam@1 2
cannam@1 3 /*
cannam@1 4 Vamp
cannam@1 5
cannam@1 6 An API for audio analysis and feature extraction plugins.
cannam@1 7
cannam@1 8 Centre for Digital Music, Queen Mary, University of London.
cannam@1 9 Copyright 2006 Chris Cannam.
cannam@1 10
cannam@1 11 Permission is hereby granted, free of charge, to any person
cannam@1 12 obtaining a copy of this software and associated documentation
cannam@1 13 files (the "Software"), to deal in the Software without
cannam@1 14 restriction, including without limitation the rights to use, copy,
cannam@1 15 modify, merge, publish, distribute, sublicense, and/or sell copies
cannam@1 16 of the Software, and to permit persons to whom the Software is
cannam@1 17 furnished to do so, subject to the following conditions:
cannam@1 18
cannam@1 19 The above copyright notice and this permission notice shall be
cannam@1 20 included in all copies or substantial portions of the Software.
cannam@1 21
cannam@1 22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
cannam@1 23 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
cannam@1 24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
cannam@6 25 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
cannam@1 26 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
cannam@1 27 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
cannam@1 28 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
cannam@1 29
cannam@1 30 Except as contained in this notice, the names of the Centre for
cannam@1 31 Digital Music; Queen Mary, University of London; and Chris Cannam
cannam@1 32 shall not be used in advertising or otherwise to promote the sale,
cannam@1 33 use or other dealings in this Software without prior written
cannam@1 34 authorization.
cannam@1 35 */
cannam@1 36
cannam@230 37 #include <vamp-hostsdk/PluginHostAdapter.h>
cannam@130 38 #include <cstdlib>
cannam@1 39
Chris@512 40 #include "Files.h"
Chris@512 41
Chris@516 42 #if ( VAMP_SDK_MAJOR_VERSION != 2 || VAMP_SDK_MINOR_VERSION != 8 )
cannam@308 43 #error Unexpected version of Vamp SDK header included
cannam@234 44 #endif
cannam@234 45
cannam@263 46 _VAMP_SDK_HOSTSPACE_BEGIN(PluginHostAdapter.cpp)
cannam@263 47
cannam@1 48 namespace Vamp
cannam@1 49 {
cannam@1 50
cannam@1 51 PluginHostAdapter::PluginHostAdapter(const VampPluginDescriptor *descriptor,
cannam@1 52 float inputSampleRate) :
cannam@1 53 Plugin(inputSampleRate),
cannam@1 54 m_descriptor(descriptor)
cannam@1 55 {
cannam@15 56 // std::cerr << "PluginHostAdapter::PluginHostAdapter (plugin = " << descriptor->name << ")" << std::endl;
cannam@1 57 m_handle = m_descriptor->instantiate(m_descriptor, inputSampleRate);
cannam@15 58 if (!m_handle) {
cannam@15 59 // std::cerr << "WARNING: PluginHostAdapter: Plugin instantiation failed for plugin " << m_descriptor->name << std::endl;
cannam@15 60 }
cannam@1 61 }
cannam@1 62
cannam@1 63 PluginHostAdapter::~PluginHostAdapter()
cannam@1 64 {
cannam@15 65 // std::cerr << "PluginHostAdapter::~PluginHostAdapter (plugin = " << m_descriptor->name << ")" << std::endl;
cannam@1 66 if (m_handle) m_descriptor->cleanup(m_handle);
cannam@1 67 }
cannam@1 68
cannam@32 69 std::vector<std::string>
cannam@32 70 PluginHostAdapter::getPluginPath()
cannam@32 71 {
cannam@32 72 std::vector<std::string> path;
cannam@32 73 std::string envPath;
cannam@32 74
Chris@513 75 if (Files::isNonNative32Bit()) {
Chris@513 76 (void)Files::getEnvUtf8("VAMP_PATH_32", envPath);
Chris@513 77 } else {
Chris@513 78 (void)Files::getEnvUtf8("VAMP_PATH", envPath);
Chris@513 79 }
cannam@32 80
cannam@32 81 #ifdef _WIN32
cannam@32 82 #define PATH_SEPARATOR ';'
cannam@32 83 #define DEFAULT_VAMP_PATH "%ProgramFiles%\\Vamp Plugins"
cannam@32 84 #else
cannam@32 85 #define PATH_SEPARATOR ':'
cannam@32 86 #ifdef __APPLE__
cannam@35 87 #define DEFAULT_VAMP_PATH "$HOME/Library/Audio/Plug-Ins/Vamp:/Library/Audio/Plug-Ins/Vamp"
cannam@32 88 #else
cannam@35 89 #define DEFAULT_VAMP_PATH "$HOME/vamp:$HOME/.vamp:/usr/local/lib/vamp:/usr/lib/vamp"
cannam@32 90 #endif
cannam@32 91 #endif
cannam@32 92
cannam@32 93 if (envPath == "") {
cannam@32 94 envPath = DEFAULT_VAMP_PATH;
Chris@512 95 std::string home;
Chris@512 96 if (Files::getEnvUtf8("HOME", home)) {
cannam@32 97 std::string::size_type f;
cannam@32 98 while ((f = envPath.find("$HOME")) != std::string::npos &&
cannam@32 99 f < envPath.length()) {
cannam@32 100 envPath.replace(f, 5, home);
cannam@32 101 }
cannam@32 102 }
cannam@32 103 #ifdef _WIN32
Chris@512 104 std::string pfiles;
Chris@512 105 if (!Files::getEnvUtf8("ProgramFiles", pfiles)) {
Chris@512 106 pfiles = "C:\\Program Files";
Chris@512 107 }
cannam@32 108 std::string::size_type f;
cannam@32 109 while ((f = envPath.find("%ProgramFiles%")) != std::string::npos &&
cannam@32 110 f < envPath.length()) {
cannam@32 111 envPath.replace(f, 14, pfiles);
cannam@32 112 }
cannam@32 113 #endif
cannam@32 114 }
cannam@32 115
cannam@32 116 std::string::size_type index = 0, newindex = 0;
cannam@32 117
cannam@32 118 while ((newindex = envPath.find(PATH_SEPARATOR, index)) < envPath.size()) {
cannam@32 119 path.push_back(envPath.substr(index, newindex - index));
cannam@32 120 index = newindex + 1;
cannam@32 121 }
cannam@32 122
cannam@32 123 path.push_back(envPath.substr(index));
cannam@32 124
cannam@32 125 return path;
cannam@32 126 }
cannam@32 127
cannam@1 128 bool
cannam@1 129 PluginHostAdapter::initialise(size_t channels,
cannam@1 130 size_t stepSize,
cannam@1 131 size_t blockSize)
cannam@1 132 {
cannam@1 133 if (!m_handle) return false;
Chris@421 134 return m_descriptor->initialise
Chris@421 135 (m_handle,
Chris@421 136 (unsigned int)channels,
Chris@421 137 (unsigned int)stepSize,
Chris@421 138 (unsigned int)blockSize) ?
cannam@1 139 true : false;
cannam@1 140 }
cannam@1 141
cannam@1 142 void
cannam@1 143 PluginHostAdapter::reset()
cannam@1 144 {
cannam@197 145 if (!m_handle) {
cannam@197 146 // std::cerr << "PluginHostAdapter::reset: no handle" << std::endl;
cannam@197 147 return;
cannam@197 148 }
cannam@197 149 // std::cerr << "PluginHostAdapter::reset(" << m_handle << ")" << std::endl;
cannam@1 150 m_descriptor->reset(m_handle);
cannam@1 151 }
cannam@1 152
cannam@1 153 PluginHostAdapter::InputDomain
cannam@1 154 PluginHostAdapter::getInputDomain() const
cannam@1 155 {
cannam@1 156 if (m_descriptor->inputDomain == vampFrequencyDomain) {
cannam@1 157 return FrequencyDomain;
cannam@1 158 } else {
cannam@1 159 return TimeDomain;
cannam@1 160 }
cannam@1 161 }
cannam@1 162
cannam@50 163 unsigned int
cannam@50 164 PluginHostAdapter::getVampApiVersion() const
cannam@50 165 {
cannam@50 166 return m_descriptor->vampApiVersion;
cannam@50 167 }
cannam@50 168
cannam@1 169 std::string
cannam@49 170 PluginHostAdapter::getIdentifier() const
cannam@49 171 {
cannam@49 172 return m_descriptor->identifier;
cannam@49 173 }
cannam@49 174
cannam@49 175 std::string
cannam@1 176 PluginHostAdapter::getName() const
cannam@1 177 {
cannam@1 178 return m_descriptor->name;
cannam@1 179 }
cannam@1 180
cannam@1 181 std::string
cannam@1 182 PluginHostAdapter::getDescription() const
cannam@1 183 {
cannam@1 184 return m_descriptor->description;
cannam@1 185 }
cannam@1 186
cannam@1 187 std::string
cannam@1 188 PluginHostAdapter::getMaker() const
cannam@1 189 {
cannam@1 190 return m_descriptor->maker;
cannam@1 191 }
cannam@1 192
cannam@1 193 int
cannam@1 194 PluginHostAdapter::getPluginVersion() const
cannam@1 195 {
cannam@1 196 return m_descriptor->pluginVersion;
cannam@1 197 }
cannam@1 198
cannam@1 199 std::string
cannam@1 200 PluginHostAdapter::getCopyright() const
cannam@1 201 {
cannam@1 202 return m_descriptor->copyright;
cannam@1 203 }
cannam@1 204
cannam@1 205 PluginHostAdapter::ParameterList
cannam@1 206 PluginHostAdapter::getParameterDescriptors() const
cannam@1 207 {
cannam@1 208 ParameterList list;
cannam@1 209 for (unsigned int i = 0; i < m_descriptor->parameterCount; ++i) {
cannam@1 210 const VampParameterDescriptor *spd = m_descriptor->parameters[i];
cannam@1 211 ParameterDescriptor pd;
cannam@49 212 pd.identifier = spd->identifier;
cannam@1 213 pd.name = spd->name;
cannam@1 214 pd.description = spd->description;
cannam@1 215 pd.unit = spd->unit;
cannam@1 216 pd.minValue = spd->minValue;
cannam@1 217 pd.maxValue = spd->maxValue;
cannam@1 218 pd.defaultValue = spd->defaultValue;
cannam@1 219 pd.isQuantized = spd->isQuantized;
cannam@1 220 pd.quantizeStep = spd->quantizeStep;
cannam@9 221 if (pd.isQuantized && spd->valueNames) {
cannam@9 222 for (unsigned int j = 0; spd->valueNames[j]; ++j) {
cannam@9 223 pd.valueNames.push_back(spd->valueNames[j]);
cannam@9 224 }
cannam@9 225 }
cannam@1 226 list.push_back(pd);
cannam@1 227 }
cannam@1 228 return list;
cannam@1 229 }
cannam@1 230
cannam@1 231 float
cannam@1 232 PluginHostAdapter::getParameter(std::string param) const
cannam@1 233 {
cannam@1 234 if (!m_handle) return 0.0;
cannam@1 235
cannam@1 236 for (unsigned int i = 0; i < m_descriptor->parameterCount; ++i) {
cannam@49 237 if (param == m_descriptor->parameters[i]->identifier) {
cannam@1 238 return m_descriptor->getParameter(m_handle, i);
cannam@1 239 }
cannam@1 240 }
cannam@1 241
cannam@1 242 return 0.0;
cannam@1 243 }
cannam@1 244
cannam@1 245 void
cannam@1 246 PluginHostAdapter::setParameter(std::string param,
cannam@1 247 float value)
cannam@1 248 {
cannam@1 249 if (!m_handle) return;
cannam@1 250
cannam@1 251 for (unsigned int i = 0; i < m_descriptor->parameterCount; ++i) {
cannam@49 252 if (param == m_descriptor->parameters[i]->identifier) {
cannam@1 253 m_descriptor->setParameter(m_handle, i, value);
cannam@1 254 return;
cannam@1 255 }
cannam@1 256 }
cannam@1 257 }
cannam@1 258
cannam@1 259 PluginHostAdapter::ProgramList
cannam@1 260 PluginHostAdapter::getPrograms() const
cannam@1 261 {
cannam@1 262 ProgramList list;
cannam@1 263
cannam@1 264 for (unsigned int i = 0; i < m_descriptor->programCount; ++i) {
cannam@1 265 list.push_back(m_descriptor->programs[i]);
cannam@1 266 }
cannam@1 267
cannam@1 268 return list;
cannam@1 269 }
cannam@1 270
cannam@1 271 std::string
cannam@1 272 PluginHostAdapter::getCurrentProgram() const
cannam@1 273 {
cannam@1 274 if (!m_handle) return "";
cannam@1 275
cannam@1 276 int pn = m_descriptor->getCurrentProgram(m_handle);
Chris@345 277 if (pn < (int)m_descriptor->programCount) {
Chris@345 278 return m_descriptor->programs[pn];
Chris@345 279 } else {
Chris@345 280 return "";
Chris@345 281 }
cannam@1 282 }
cannam@1 283
cannam@1 284 void
cannam@1 285 PluginHostAdapter::selectProgram(std::string program)
cannam@1 286 {
cannam@1 287 if (!m_handle) return;
cannam@1 288
cannam@1 289 for (unsigned int i = 0; i < m_descriptor->programCount; ++i) {
cannam@1 290 if (program == m_descriptor->programs[i]) {
cannam@1 291 m_descriptor->selectProgram(m_handle, i);
cannam@1 292 return;
cannam@1 293 }
cannam@1 294 }
cannam@1 295 }
cannam@1 296
cannam@1 297 size_t
cannam@1 298 PluginHostAdapter::getPreferredStepSize() const
cannam@1 299 {
cannam@1 300 if (!m_handle) return 0;
cannam@1 301 return m_descriptor->getPreferredStepSize(m_handle);
cannam@1 302 }
cannam@1 303
cannam@1 304 size_t
cannam@1 305 PluginHostAdapter::getPreferredBlockSize() const
cannam@1 306 {
cannam@1 307 if (!m_handle) return 0;
cannam@1 308 return m_descriptor->getPreferredBlockSize(m_handle);
cannam@1 309 }
cannam@1 310
cannam@26 311 size_t
cannam@26 312 PluginHostAdapter::getMinChannelCount() const
cannam@26 313 {
cannam@26 314 if (!m_handle) return 0;
cannam@26 315 return m_descriptor->getMinChannelCount(m_handle);
cannam@26 316 }
cannam@26 317
cannam@26 318 size_t
cannam@26 319 PluginHostAdapter::getMaxChannelCount() const
cannam@26 320 {
cannam@26 321 if (!m_handle) return 0;
cannam@26 322 return m_descriptor->getMaxChannelCount(m_handle);
cannam@26 323 }
cannam@26 324
cannam@1 325 PluginHostAdapter::OutputList
cannam@1 326 PluginHostAdapter::getOutputDescriptors() const
cannam@1 327 {
cannam@1 328 OutputList list;
cannam@15 329 if (!m_handle) {
cannam@15 330 // std::cerr << "PluginHostAdapter::getOutputDescriptors: no handle " << std::endl;
cannam@15 331 return list;
cannam@15 332 }
cannam@1 333
cannam@1 334 unsigned int count = m_descriptor->getOutputCount(m_handle);
cannam@1 335
cannam@1 336 for (unsigned int i = 0; i < count; ++i) {
cannam@1 337 VampOutputDescriptor *sd = m_descriptor->getOutputDescriptor(m_handle, i);
cannam@1 338 OutputDescriptor d;
cannam@49 339 d.identifier = sd->identifier;
cannam@1 340 d.name = sd->name;
cannam@1 341 d.description = sd->description;
cannam@1 342 d.unit = sd->unit;
cannam@9 343 d.hasFixedBinCount = sd->hasFixedBinCount;
cannam@9 344 d.binCount = sd->binCount;
cannam@240 345 if (d.hasFixedBinCount && sd->binNames) {
cannam@9 346 for (unsigned int j = 0; j < sd->binCount; ++j) {
cannam@9 347 d.binNames.push_back(sd->binNames[j] ? sd->binNames[j] : "");
cannam@9 348 }
cannam@1 349 }
cannam@1 350 d.hasKnownExtents = sd->hasKnownExtents;
cannam@1 351 d.minValue = sd->minValue;
cannam@1 352 d.maxValue = sd->maxValue;
cannam@1 353 d.isQuantized = sd->isQuantized;
cannam@1 354 d.quantizeStep = sd->quantizeStep;
cannam@1 355
cannam@1 356 switch (sd->sampleType) {
cannam@1 357 case vampOneSamplePerStep:
cannam@1 358 d.sampleType = OutputDescriptor::OneSamplePerStep; break;
cannam@1 359 case vampFixedSampleRate:
cannam@1 360 d.sampleType = OutputDescriptor::FixedSampleRate; break;
cannam@1 361 case vampVariableSampleRate:
cannam@1 362 d.sampleType = OutputDescriptor::VariableSampleRate; break;
cannam@1 363 }
cannam@1 364
cannam@1 365 d.sampleRate = sd->sampleRate;
cannam@1 366
cannam@192 367 if (m_descriptor->vampApiVersion >= 2) {
cannam@192 368 d.hasDuration = sd->hasDuration;
cannam@192 369 } else {
cannam@192 370 d.hasDuration = false;
cannam@192 371 }
cannam@192 372
cannam@1 373 list.push_back(d);
cannam@1 374
cannam@1 375 m_descriptor->releaseOutputDescriptor(sd);
cannam@1 376 }
cannam@1 377
cannam@1 378 return list;
cannam@1 379 }
cannam@1 380
cannam@1 381 PluginHostAdapter::FeatureSet
cannam@47 382 PluginHostAdapter::process(const float *const *inputBuffers,
cannam@47 383 RealTime timestamp)
cannam@1 384 {
cannam@1 385 FeatureSet fs;
cannam@1 386 if (!m_handle) return fs;
cannam@1 387
cannam@1 388 int sec = timestamp.sec;
cannam@1 389 int nsec = timestamp.nsec;
cannam@1 390
cannam@12 391 VampFeatureList *features = m_descriptor->process(m_handle,
cannam@1 392 inputBuffers,
cannam@1 393 sec, nsec);
cannam@1 394
cannam@1 395 convertFeatures(features, fs);
cannam@1 396 m_descriptor->releaseFeatureSet(features);
cannam@1 397 return fs;
cannam@1 398 }
cannam@1 399
cannam@1 400 PluginHostAdapter::FeatureSet
cannam@1 401 PluginHostAdapter::getRemainingFeatures()
cannam@1 402 {
cannam@1 403 FeatureSet fs;
cannam@1 404 if (!m_handle) return fs;
cannam@1 405
cannam@12 406 VampFeatureList *features = m_descriptor->getRemainingFeatures(m_handle);
cannam@1 407
cannam@1 408 convertFeatures(features, fs);
cannam@1 409 m_descriptor->releaseFeatureSet(features);
cannam@1 410 return fs;
cannam@1 411 }
cannam@1 412
cannam@1 413 void
cannam@12 414 PluginHostAdapter::convertFeatures(VampFeatureList *features,
cannam@1 415 FeatureSet &fs)
cannam@1 416 {
cannam@7 417 if (!features) return;
cannam@7 418
cannam@12 419 unsigned int outputs = m_descriptor->getOutputCount(m_handle);
cannam@12 420
cannam@12 421 for (unsigned int i = 0; i < outputs; ++i) {
cannam@1 422
cannam@12 423 VampFeatureList &list = features[i];
cannam@1 424
cannam@1 425 if (list.featureCount > 0) {
cannam@1 426
cannam@108 427 Feature feature;
cannam@168 428 feature.values.reserve(list.features[0].v1.valueCount);
cannam@108 429
cannam@1 430 for (unsigned int j = 0; j < list.featureCount; ++j) {
cannam@108 431
cannam@168 432 feature.hasTimestamp = list.features[j].v1.hasTimestamp;
cannam@168 433 feature.timestamp = RealTime(list.features[j].v1.sec,
cannam@168 434 list.features[j].v1.nsec);
cannam@168 435 feature.hasDuration = false;
cannam@1 436
cannam@167 437 if (m_descriptor->vampApiVersion >= 2) {
cannam@168 438 unsigned int j2 = j + list.featureCount;
cannam@168 439 feature.hasDuration = list.features[j2].v2.hasDuration;
cannam@168 440 feature.duration = RealTime(list.features[j2].v2.durationSec,
cannam@168 441 list.features[j2].v2.durationNsec);
cannam@167 442 }
cannam@167 443
cannam@168 444 for (unsigned int k = 0; k < list.features[j].v1.valueCount; ++k) {
cannam@168 445 feature.values.push_back(list.features[j].v1.values[k]);
cannam@1 446 }
cannam@7 447
cannam@168 448 if (list.features[j].v1.label) {
cannam@168 449 feature.label = list.features[j].v1.label;
cannam@7 450 }
cannam@1 451
cannam@1 452 fs[i].push_back(feature);
cannam@108 453
cannam@168 454 if (list.features[j].v1.valueCount > 0) {
cannam@108 455 feature.values.clear();
cannam@108 456 }
cannam@108 457
cannam@168 458 if (list.features[j].v1.label) {
cannam@108 459 feature.label = "";
cannam@108 460 }
cannam@1 461 }
cannam@1 462 }
cannam@1 463 }
cannam@1 464 }
cannam@1 465
cannam@1 466 }
cannam@263 467
cannam@263 468 _VAMP_SDK_HOSTSPACE_END(PluginHostAdapter.cpp)
cannam@263 469