| 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@528 | 42 #if ( VAMP_SDK_MAJOR_VERSION != 2 || VAMP_SDK_MINOR_VERSION != 9 ) | 
| 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 |