annotate PyPlugin.cpp @ 18:e9cf443b18f5

* Add duration support (Vamp 2.0)
author cannam
date Fri, 10 Jul 2009 15:14:24 +0000
parents 3af6b5990ad8
children 1ae350e97f93
rev   line source
cannam@18 1 /* -*- c-basic-offset: 8 indent-tabs-mode: t -*- */
fazekasgy@0 2 /*
fazekasgy@0 3 Vamp
fazekasgy@0 4
fazekasgy@0 5 An API for audio analysis and feature extraction plugins.
fazekasgy@0 6
fazekasgy@0 7 Centre for Digital Music, Queen Mary, University of London.
fazekasgy@0 8 Copyright 2006 Chris Cannam.
fazekasgy@0 9
fazekasgy@0 10 Permission is hereby granted, free of charge, to any person
fazekasgy@0 11 obtaining a copy of this software and associated documentation
fazekasgy@0 12 files (the "Software"), to deal in the Software without
fazekasgy@0 13 restriction, including without limitation the rights to use, copy,
fazekasgy@0 14 modify, merge, publish, distribute, sublicense, and/or sell copies
fazekasgy@0 15 of the Software, and to permit persons to whom the Software is
fazekasgy@0 16 furnished to do so, subject to the following conditions:
fazekasgy@0 17
fazekasgy@0 18 The above copyright notice and this permission notice shall be
fazekasgy@0 19 included in all copies or substantial portions of the Software.
fazekasgy@0 20
fazekasgy@0 21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
fazekasgy@0 22 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
fazekasgy@0 23 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
fazekasgy@0 24 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
fazekasgy@0 25 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
fazekasgy@0 26 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
fazekasgy@0 27 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
fazekasgy@0 28
fazekasgy@0 29 Except as contained in this notice, the names of the Centre for
fazekasgy@0 30 Digital Music; Queen Mary, University of London; and Chris Cannam
fazekasgy@0 31 shall not be used in advertising or otherwise to promote the sale,
fazekasgy@0 32 use or other dealings in this Software without prior written
fazekasgy@0 33 authorization.
fazekasgy@0 34 */
fazekasgy@0 35
fazekasgy@0 36
fazekasgy@0 37
fazekasgy@0 38 /**
fazekasgy@8 39 * This Vamp plugin is a wrapper for Python Scripts. (VamPy)
fazekasgy@0 40 * Centre for Digital Music, Queen Mary, University of London.
fazekasgy@0 41 * Copyright 2008, George Fazekas.
fazekasgy@0 42
fazekasgy@0 43 TODO: needs more complete error checking
fazekasgy@0 44 needs correct implementation of Python threading
fazekasgy@0 45 more efficient data conversion using the buffering interface or ctypes
cannam@7 46 Vamp programs not implemented
fazekasgy@0 47 support multiple plugins per script in scanner
fazekasgy@0 48 ensure proper cleanup, host do a good job though
fazekasgy@0 49
fazekasgy@0 50 */
fazekasgy@0 51
cannam@3 52 #include <Python.h>
fazekasgy@0 53 #include "PyPlugin.h"
fazekasgy@0 54
fazekasgy@0 55 #ifdef _WIN32
fazekasgy@0 56 #define pathsep ('\\')
fazekasgy@0 57 #else
fazekasgy@0 58 #define pathsep ('/')
fazekasgy@0 59 #endif
fazekasgy@0 60
fazekasgy@6 61 //#define _DEBUG
fazekasgy@0 62
fazekasgy@0 63 using std::string;
fazekasgy@0 64 using std::vector;
fazekasgy@0 65 using std::cerr;
fazekasgy@0 66 using std::endl;
fazekasgy@0 67 using std::map;
fazekasgy@0 68
fazekasgy@0 69 // Maps to associate strings with enum values
cannam@18 70 static std::map<std::string, o::eOutDescriptors> outKeys;
fazekasgy@0 71 static std::map<std::string, eSampleTypes> sampleKeys;
fazekasgy@0 72 static std::map<std::string, eFeatureFields> ffKeys;
fazekasgy@0 73 static std::map<std::string, p::eParmDescriptors> parmKeys;
fazekasgy@0 74
cannam@3 75 Mutex PyPlugin::m_pythonInterpreterMutex;
fazekasgy@6 76 static bool isMapInitialised = false;
fazekasgy@0 77
fazekasgy@0 78 PyPlugin::PyPlugin(std::string pluginKey,float inputSampleRate, PyObject *pyInstance) :
fazekasgy@0 79 Plugin(inputSampleRate),
fazekasgy@0 80 m_pyInstance(pyInstance),
fazekasgy@0 81 m_stepSize(0),
fazekasgy@6 82 m_blockSize(0),
fazekasgy@6 83 m_channels(0),
fazekasgy@0 84 m_plugin(pluginKey),
fazekasgy@0 85 m_class(pluginKey.substr(pluginKey.rfind(':')+1,pluginKey.size()-1)),
fazekasgy@6 86 m_path((pluginKey.substr(0,pluginKey.rfind(pathsep)))),
fazekasgy@6 87 m_processType(0),
fazekasgy@6 88 m_pyProcess(NULL),
fazekasgy@6 89 m_inputDomain(TimeDomain)
fazekasgy@0 90 {
fazekasgy@0 91 }
fazekasgy@0 92
fazekasgy@0 93 PyPlugin::~PyPlugin()
fazekasgy@0 94 {
fazekasgy@6 95 Py_CLEAR(m_pyProcess);
fazekasgy@6 96 #ifdef _DEBUG
fazekasgy@0 97 cerr << "PyPlugin::PyPlugin:" << m_class
fazekasgy@0 98 << " Instance deleted." << endl;
fazekasgy@6 99 #endif
fazekasgy@0 100 }
fazekasgy@0 101
fazekasgy@0 102
fazekasgy@0 103 string
fazekasgy@0 104 PyPlugin::getIdentifier() const
fazekasgy@0 105 {
cannam@3 106 MutexLocker locker(&m_pythonInterpreterMutex);
cannam@3 107
fazekasgy@0 108 char method[]="getIdentifier";
fazekasgy@0 109 cerr << "[call] " << method << endl;
fazekasgy@6 110 string rString="vampy-x";
fazekasgy@0 111
fazekasgy@0 112 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
fazekasgy@0 113
fazekasgy@0 114 //Call the method
fazekasgy@0 115 PyObject *pyString =
fazekasgy@0 116 PyObject_CallMethod(m_pyInstance, method, NULL);
fazekasgy@0 117
fazekasgy@0 118 //Check return value
fazekasgy@0 119 if (!PyString_Check(pyString)) {
fazekasgy@0 120 Py_CLEAR(pyString);
fazekasgy@0 121 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 122 << "] Expected String return value." << endl;
fazekasgy@0 123 return rString;
fazekasgy@0 124 }
fazekasgy@0 125
fazekasgy@0 126 rString=PyString_AsString(pyString);
fazekasgy@0 127 Py_CLEAR(pyString);
fazekasgy@6 128 return rString;
fazekasgy@0 129 }
fazekasgy@0 130 cerr << "Warning: Plugin must return a unique identifier." << endl;
fazekasgy@0 131 return rString;
fazekasgy@0 132 }
fazekasgy@0 133
fazekasgy@0 134
fazekasgy@0 135 string
fazekasgy@0 136 PyPlugin::getName() const
fazekasgy@0 137 {
cannam@3 138 MutexLocker locker(&m_pythonInterpreterMutex);
fazekasgy@0 139
fazekasgy@0 140 char method[]="getName";
fazekasgy@0 141 cerr << "[call] " << method << endl;
fazekasgy@0 142 string rString="VamPy Plugin (Noname)";
fazekasgy@0 143
fazekasgy@0 144 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
fazekasgy@0 145
fazekasgy@0 146 //Call the method
fazekasgy@0 147 PyObject *pyString =
fazekasgy@0 148 PyObject_CallMethod(m_pyInstance, method, NULL);
fazekasgy@0 149
fazekasgy@0 150 //Check return value
fazekasgy@0 151 if (!PyString_Check(pyString)) {
fazekasgy@0 152 Py_CLEAR(pyString);
fazekasgy@0 153 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 154 << "] Expected String return value." << endl;
fazekasgy@0 155 return rString;
fazekasgy@0 156 }
fazekasgy@0 157
fazekasgy@0 158 rString=PyString_AsString(pyString);
fazekasgy@0 159 Py_CLEAR(pyString);
fazekasgy@0 160 }
fazekasgy@0 161 return rString;
fazekasgy@0 162 }
fazekasgy@0 163
fazekasgy@0 164 string
fazekasgy@0 165 PyPlugin::getDescription() const
fazekasgy@0 166 {
cannam@3 167 MutexLocker locker(&m_pythonInterpreterMutex);
cannam@3 168
fazekasgy@0 169 char method[]="getDescription";
fazekasgy@0 170 cerr << "[call] " << method << endl;
fazekasgy@0 171 string rString="Not given. (Hint: Implement getDescription method.)";
fazekasgy@0 172
fazekasgy@0 173 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
fazekasgy@0 174
fazekasgy@0 175 //Call the method
fazekasgy@0 176 PyObject *pyString =
fazekasgy@0 177 PyObject_CallMethod(m_pyInstance, method, NULL);
fazekasgy@0 178
fazekasgy@0 179 //Check return value
fazekasgy@0 180 if (!PyString_Check(pyString)) {
fazekasgy@0 181 Py_CLEAR(pyString);
fazekasgy@0 182 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 183 << "] Expected String return value." << endl;
fazekasgy@0 184 return rString;
fazekasgy@0 185 }
fazekasgy@0 186
fazekasgy@0 187 rString=PyString_AsString(pyString);
fazekasgy@0 188 Py_CLEAR(pyString);
fazekasgy@0 189 }
fazekasgy@0 190 return rString;
fazekasgy@0 191 }
fazekasgy@0 192
fazekasgy@0 193 string
fazekasgy@0 194 PyPlugin::getMaker() const
fazekasgy@0 195 {
cannam@3 196 MutexLocker locker(&m_pythonInterpreterMutex);
cannam@3 197
fazekasgy@0 198 char method[]="getMaker";
fazekasgy@0 199 cerr << "[call] " << method << endl;
fazekasgy@0 200 string rString="Generic VamPy Plugin.";
fazekasgy@0 201
fazekasgy@0 202 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
fazekasgy@0 203
fazekasgy@0 204 //Call the method
fazekasgy@0 205 PyObject *pyString =
fazekasgy@0 206 PyObject_CallMethod(m_pyInstance, method, NULL);
fazekasgy@0 207
fazekasgy@0 208 //Check return value
fazekasgy@0 209 if (!PyString_Check(pyString)) {
fazekasgy@0 210 Py_CLEAR(pyString);
fazekasgy@0 211 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 212 << "] Expected String return value." << endl;
fazekasgy@0 213 return rString;
fazekasgy@0 214 }
fazekasgy@0 215
fazekasgy@0 216 rString=PyString_AsString(pyString);
fazekasgy@0 217 Py_CLEAR(pyString);
fazekasgy@0 218 }
fazekasgy@0 219 return rString;
fazekasgy@0 220 }
fazekasgy@0 221
fazekasgy@0 222 int
fazekasgy@0 223 PyPlugin::getPluginVersion() const
fazekasgy@0 224 {
fazekasgy@0 225 return 2;
fazekasgy@0 226 }
fazekasgy@0 227
fazekasgy@0 228 string
fazekasgy@0 229 PyPlugin::getCopyright() const
fazekasgy@0 230 {
cannam@3 231 MutexLocker locker(&m_pythonInterpreterMutex);
cannam@3 232
fazekasgy@0 233 char method[]="getCopyright";
fazekasgy@0 234 cerr << "[call] " << method << endl;
fazekasgy@0 235 string rString="BSD License";
fazekasgy@0 236
fazekasgy@0 237 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
fazekasgy@0 238
fazekasgy@0 239 //Call the method
fazekasgy@0 240 PyObject *pyString =
fazekasgy@0 241 PyObject_CallMethod(m_pyInstance, method, NULL);
fazekasgy@0 242
fazekasgy@0 243 //Check return value
fazekasgy@0 244 if (!PyString_Check(pyString)) {
fazekasgy@0 245 Py_CLEAR(pyString);
fazekasgy@0 246 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 247 << "] Expected String return value." << endl;
fazekasgy@0 248 return rString;
fazekasgy@0 249 }
fazekasgy@0 250
fazekasgy@0 251
fazekasgy@0 252 rString=PyString_AsString(pyString);
fazekasgy@0 253 Py_CLEAR(pyString);
fazekasgy@0 254 }
fazekasgy@0 255 return rString;
fazekasgy@0 256 }
fazekasgy@0 257
fazekasgy@0 258
fazekasgy@0 259 bool
fazekasgy@0 260 PyPlugin::initialise(size_t channels, size_t stepSize, size_t blockSize)
fazekasgy@0 261 {
fazekasgy@8 262 //useful for debugging Python plugins
fazekasgy@8 263 char method[]="initialise";
fazekasgy@8 264 cerr << "[call] " << method << endl;
fazekasgy@6 265
fazekasgy@6 266 //placing Mutex before these calls causes deadlock
fazekasgy@6 267 if (channels < getMinChannelCount() ||
fazekasgy@6 268 channels > getMaxChannelCount()) return false;
fazekasgy@6 269
fazekasgy@6 270 m_inputDomain = getInputDomain();
fazekasgy@6 271
cannam@3 272 MutexLocker locker(&m_pythonInterpreterMutex);
cannam@3 273
fazekasgy@6 274 initMaps();
fazekasgy@6 275
fazekasgy@6 276 m_stepSize = stepSize;
fazekasgy@6 277 m_blockSize = blockSize;
fazekasgy@6 278 m_channels = channels;
fazekasgy@6 279
fazekasgy@6 280 //quering process implementation type
fazekasgy@6 281 char legacyMethod[]="process";
fazekasgy@6 282 char numpyMethod[]="processN";
fazekasgy@6 283
cannam@18 284 if (PyObject_HasAttrString(m_pyInstance,legacyMethod) &&
cannam@18 285 m_processType == 0)
fazekasgy@6 286 {
fazekasgy@6 287 m_processType = legacyProcess;
fazekasgy@6 288 m_pyProcess = PyString_FromString(legacyMethod);
fazekasgy@6 289 }
fazekasgy@6 290
cannam@18 291 if (PyObject_HasAttrString(m_pyInstance,numpyMethod) &&
cannam@18 292 m_processType == 0)
fazekasgy@6 293 {
fazekasgy@6 294 m_processType = numpyProcess;
fazekasgy@6 295 m_pyProcess = PyString_FromString(numpyMethod);
fazekasgy@6 296 }
fazekasgy@6 297
fazekasgy@6 298 if (!m_processType)
fazekasgy@6 299 {
fazekasgy@6 300 m_processType = not_implemented;
fazekasgy@6 301 m_pyProcess = NULL;
fazekasgy@6 302 cerr << "Warning: Python plugin [" << m_class << "::" << method
fazekasgy@6 303 << "] No process implementation found. Plugin will do nothing." << endl;
fazekasgy@6 304 }
fazekasgy@6 305
fazekasgy@6 306
fazekasgy@0 307 //Check if the method is implemented in Python else return false
fazekasgy@0 308 if (PyObject_HasAttrString(m_pyInstance,method)) {
fazekasgy@0 309
fazekasgy@0 310 PyObject *pyMethod = PyString_FromString(method);
fazekasgy@0 311 PyObject *pyChannels = PyInt_FromSsize_t((Py_ssize_t)channels);
fazekasgy@0 312 PyObject *pyStepSize = PyInt_FromSsize_t((Py_ssize_t)m_stepSize);
fazekasgy@0 313 PyObject *pyBlockSize = PyInt_FromSsize_t((Py_ssize_t)blockSize);
fazekasgy@0 314 PyObject *pyInputSampleRate = PyFloat_FromDouble((double)m_inputSampleRate);
fazekasgy@0 315
fazekasgy@0 316 //Call the method
fazekasgy@0 317 PyObject *pyBool =
fazekasgy@0 318 PyObject_CallMethodObjArgs(m_pyInstance,pyMethod,pyChannels,pyStepSize,pyBlockSize,pyInputSampleRate,NULL);
fazekasgy@8 319
fazekasgy@0 320 Py_DECREF(pyMethod);
fazekasgy@0 321 Py_DECREF(pyChannels);
fazekasgy@0 322 Py_DECREF(pyStepSize);
fazekasgy@0 323 Py_DECREF(pyBlockSize);
fazekasgy@0 324 Py_DECREF(pyInputSampleRate);
fazekasgy@0 325
fazekasgy@0 326 //Check return value
fazekasgy@8 327 if (PyErr_Occurred() || !PyBool_Check(pyBool)) {
fazekasgy@8 328 PyErr_Print(); PyErr_Clear();
fazekasgy@0 329 Py_CLEAR(pyBool);
fazekasgy@0 330 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 331 << "] Expected Bool return value." << endl;
fazekasgy@0 332 return false;
fazekasgy@0 333 }
fazekasgy@0 334
fazekasgy@0 335 if (pyBool == Py_True) {
fazekasgy@0 336 Py_CLEAR(pyBool);
fazekasgy@0 337 return true;
fazekasgy@0 338 } else {
fazekasgy@0 339 Py_CLEAR(pyBool);
fazekasgy@0 340 return false;}
fazekasgy@0 341 }
fazekasgy@6 342 return false;
fazekasgy@0 343 }
fazekasgy@0 344
fazekasgy@0 345 void
fazekasgy@0 346 PyPlugin::reset()
fazekasgy@0 347 {
fazekasgy@6 348 MutexLocker locker(&m_pythonInterpreterMutex);
fazekasgy@6 349
fazekasgy@6 350 char method[]="reset";
fazekasgy@6 351 cerr << "[call] " << method << endl;
fazekasgy@6 352
fazekasgy@6 353 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
fazekasgy@6 354
fazekasgy@6 355 PyObject_CallMethod(m_pyInstance, method, NULL);
fazekasgy@6 356 if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
fazekasgy@6 357
fazekasgy@6 358 }
fazekasgy@0 359 }
fazekasgy@0 360
fazekasgy@6 361 PyPlugin::InputDomain PyPlugin::getInputDomain() const
fazekasgy@0 362 {
cannam@3 363 MutexLocker locker(&m_pythonInterpreterMutex);
cannam@3 364
fazekasgy@0 365 char method[]="getInputDomain";
fazekasgy@0 366 cerr << "[call] " << method << endl;
fazekasgy@0 367 PyPlugin::InputDomain rValue = TimeDomain; // TimeDomain
fazekasgy@0 368
fazekasgy@0 369 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
fazekasgy@0 370
fazekasgy@0 371 PyObject *pyString = PyObject_CallMethod(m_pyInstance, method, NULL);
fazekasgy@0 372
fazekasgy@0 373 //Check return value
fazekasgy@0 374 if (!PyString_Check(pyString)) {
fazekasgy@0 375 Py_CLEAR(pyString);
fazekasgy@0 376 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 377 << "] Expected String return value." << endl;
fazekasgy@0 378 return rValue;
fazekasgy@0 379 }
fazekasgy@0 380
fazekasgy@0 381 string domain = (string) PyString_AsString(pyString);
fazekasgy@0 382 if (domain == "FrequencyDomain") rValue = FrequencyDomain;
fazekasgy@0 383 Py_CLEAR(pyString);
fazekasgy@0 384 }
fazekasgy@0 385 return rValue;
fazekasgy@0 386 }
fazekasgy@0 387
fazekasgy@6 388
fazekasgy@0 389 size_t PyPlugin::getPreferredBlockSize() const
fazekasgy@0 390 {
cannam@3 391 MutexLocker locker(&m_pythonInterpreterMutex);
cannam@3 392
fazekasgy@0 393 char method[]="getPreferredBlockSize";
fazekasgy@0 394 cerr << "[call] " << method << endl;
fazekasgy@0 395 size_t rValue=0; //not set by default
fazekasgy@0 396 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
fazekasgy@0 397 PyObject *pyInt = PyObject_CallMethod(m_pyInstance, method, NULL);
fazekasgy@0 398
fazekasgy@0 399 //Check return value
fazekasgy@0 400 if (!PyInt_Check(pyInt)) {
fazekasgy@0 401 Py_CLEAR(pyInt);
fazekasgy@0 402 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 403 << "] Expected Integer return value." << endl;
fazekasgy@0 404 return rValue;
fazekasgy@0 405 }
fazekasgy@0 406
fazekasgy@0 407 rValue=(size_t)PyInt_AS_LONG(pyInt);
fazekasgy@0 408 Py_CLEAR(pyInt);
fazekasgy@0 409 }
fazekasgy@0 410 return rValue;
fazekasgy@0 411 }
fazekasgy@0 412
fazekasgy@0 413 //size_t PyPlugin::getPreferredStepSize() const { return 0; }
fazekasgy@0 414 size_t PyPlugin::getPreferredStepSize() const
fazekasgy@0 415 {
cannam@3 416 MutexLocker locker(&m_pythonInterpreterMutex);
cannam@3 417
fazekasgy@0 418 char method[]="getPreferredStepSize";
fazekasgy@0 419 cerr << "[call] " << method << endl;
fazekasgy@8 420 size_t rValue=1024; //not set by default
fazekasgy@0 421 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
fazekasgy@0 422 PyObject *pyInt = PyObject_CallMethod(m_pyInstance, method, NULL);
fazekasgy@0 423
fazekasgy@0 424 //Check return value
fazekasgy@0 425 if (!PyInt_Check(pyInt)) {
fazekasgy@0 426 Py_CLEAR(pyInt);
fazekasgy@0 427 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 428 << "] Expected Integer return value." << endl;
fazekasgy@0 429 return rValue;
fazekasgy@0 430 }
fazekasgy@0 431
fazekasgy@0 432 rValue=(size_t)PyInt_AS_LONG(pyInt);
fazekasgy@0 433 Py_CLEAR(pyInt);
fazekasgy@0 434 }
fazekasgy@0 435 return rValue;
fazekasgy@0 436 }
fazekasgy@0 437
fazekasgy@0 438 size_t PyPlugin::getMinChannelCount() const
fazekasgy@0 439 {
cannam@3 440 MutexLocker locker(&m_pythonInterpreterMutex);
cannam@3 441
fazekasgy@0 442 char method[]="getMinChannelCount";
fazekasgy@0 443 cerr << "[call] " << method << endl;
fazekasgy@0 444 size_t rValue=1; //default value
fazekasgy@0 445 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
fazekasgy@0 446 PyObject *pyInt = PyObject_CallMethod(m_pyInstance, method, NULL);
fazekasgy@0 447
fazekasgy@0 448 //Check return value
fazekasgy@0 449 if (!PyInt_Check(pyInt)) {
fazekasgy@0 450 Py_CLEAR(pyInt);
fazekasgy@0 451 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 452 << "] Expected String return value." << endl;
fazekasgy@0 453 return rValue;
fazekasgy@0 454 }
fazekasgy@0 455
fazekasgy@0 456 rValue=(size_t)PyInt_AS_LONG(pyInt);
fazekasgy@0 457 Py_CLEAR(pyInt);
fazekasgy@0 458 }
fazekasgy@0 459 return rValue;
fazekasgy@0 460 }
fazekasgy@0 461
fazekasgy@0 462 size_t PyPlugin::getMaxChannelCount() const
fazekasgy@0 463 {
cannam@3 464 MutexLocker locker(&m_pythonInterpreterMutex);
cannam@3 465
fazekasgy@0 466 char method[]="getMaxChannelCount";
fazekasgy@0 467 cerr << "[call] " << method << endl;
fazekasgy@0 468 size_t rValue=1; //default value
fazekasgy@0 469 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
fazekasgy@0 470 PyObject *pyInt = PyObject_CallMethod(m_pyInstance, method, NULL);
fazekasgy@0 471
fazekasgy@0 472 //Check return value
fazekasgy@0 473 if (!PyInt_Check(pyInt)) {
fazekasgy@0 474 Py_CLEAR(pyInt);
fazekasgy@0 475 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 476 << "] Expected String return value." << endl;
fazekasgy@0 477 return rValue;
fazekasgy@0 478 }
fazekasgy@0 479
fazekasgy@0 480 rValue=(size_t)PyInt_AS_LONG(pyInt);
fazekasgy@0 481 Py_CLEAR(pyInt);
fazekasgy@0 482 }
fazekasgy@0 483 return rValue;
fazekasgy@0 484 }
fazekasgy@0 485
fazekasgy@0 486
fazekasgy@0 487 PyPlugin::OutputList
fazekasgy@0 488 PyPlugin::getOutputDescriptors() const
fazekasgy@0 489 {
fazekasgy@6 490
cannam@3 491 MutexLocker locker(&m_pythonInterpreterMutex);
fazekasgy@6 492
fazekasgy@0 493 //PyEval_AcquireThread(newThreadState);
fazekasgy@0 494 OutputList list;
fazekasgy@0 495 OutputDescriptor od;
fazekasgy@0 496 char method[]="getOutputDescriptors";
fazekasgy@0 497 cerr << "[call] " << method << endl;
fazekasgy@0 498
fazekasgy@0 499 //Check if the method is implemented in Python
fazekasgy@6 500 if ( ! PyObject_HasAttrString(m_pyInstance,method) ) return list;
fazekasgy@0 501
fazekasgy@0 502 //Call the method: must return list object (new reference)
fazekasgy@0 503 PyObject *pyList =
fazekasgy@0 504 PyObject_CallMethod(m_pyInstance,method, NULL);
fazekasgy@0 505
fazekasgy@0 506 //Check return type
fazekasgy@0 507 if (! PyList_Check(pyList) ) {
fazekasgy@0 508 Py_CLEAR(pyList);
fazekasgy@0 509 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 510 << "] Expected List return type." << endl;
fazekasgy@0 511 return list;
fazekasgy@0 512 }
fazekasgy@0 513
fazekasgy@0 514 //These will all be borrowed references (no need to DECREF)
fazekasgy@0 515 PyObject *pyDict, *pyKey, *pyValue;
fazekasgy@0 516
fazekasgy@0 517 //Parse Output List
fazekasgy@0 518 for (Py_ssize_t i = 0; i < PyList_GET_SIZE(pyList); ++i) {
fazekasgy@0 519
cannam@18 520 //Get i-th Vamp output descriptor (Borrowed Reference)
fazekasgy@0 521 pyDict = PyList_GET_ITEM(pyList,i);
fazekasgy@0 522
fazekasgy@0 523 //We only care about dictionaries holding output descriptors
fazekasgy@0 524 if ( !PyDict_Check(pyDict) ) continue;
fazekasgy@0 525
fazekasgy@0 526 Py_ssize_t pyPos = NULL;
fazekasgy@0 527 initMaps();
fazekasgy@0 528
fazekasgy@0 529 //Python Sequence Iterator
fazekasgy@0 530 while (PyDict_Next(pyDict, &pyPos, &pyKey, &pyValue))
fazekasgy@0 531 {
fazekasgy@0 532 switch (outKeys[PyString_AsString(pyKey)])
fazekasgy@0 533 {
cannam@18 534 case o::not_found :
cannam@18 535 cerr << "Unknown key in Vamp OutputDescriptor: " << PyString_AsString(pyKey) << endl;
fazekasgy@0 536 break;
cannam@18 537 case o::identifier:
fazekasgy@0 538 od.identifier = PyString_AsString(pyValue);
fazekasgy@0 539 break;
cannam@18 540 case o::name:
fazekasgy@0 541 od.name = PyString_AsString(pyValue);
fazekasgy@0 542 break;
cannam@18 543 case o::description:
fazekasgy@0 544 od.description = PyString_AsString(pyValue);
fazekasgy@0 545 break;
cannam@18 546 case o::unit:
fazekasgy@0 547 od.unit = PyString_AsString(pyValue);
fazekasgy@0 548 break;
cannam@18 549 case o::hasFixedBinCount:
fazekasgy@0 550 od.hasFixedBinCount = (bool) PyInt_AS_LONG(pyValue);
fazekasgy@0 551 break;
cannam@18 552 case o::binCount:
fazekasgy@0 553 od.binCount = (size_t) PyInt_AS_LONG(pyValue);
fazekasgy@0 554 break;
cannam@18 555 case o::binNames:
fazekasgy@0 556 od.binNames = PyList_To_StringVector(pyValue);
fazekasgy@0 557 break;
cannam@18 558 case o::hasKnownExtents:
fazekasgy@0 559 od.hasKnownExtents = (bool) PyInt_AS_LONG(pyValue);
fazekasgy@0 560 break;
cannam@18 561 case o::minValue:
fazekasgy@0 562 od.minValue = (float) PyFloat_AS_DOUBLE(pyValue);
fazekasgy@0 563 break;
cannam@18 564 case o::maxValue:
fazekasgy@0 565 od.maxValue = (float) PyFloat_AS_DOUBLE(pyValue);
fazekasgy@0 566 break;
cannam@18 567 case o::isQuantized:
fazekasgy@0 568 od.isQuantized = (bool) PyInt_AS_LONG(pyValue);
fazekasgy@0 569 break;
cannam@18 570 case o::quantizeStep:
fazekasgy@0 571 od.quantizeStep = (float) PyFloat_AS_DOUBLE(pyValue);
fazekasgy@0 572 break;
cannam@18 573 case o::sampleType:
fazekasgy@0 574 od.sampleType = (OutputDescriptor::SampleType) sampleKeys[PyString_AsString(pyValue)];
fazekasgy@0 575 break;
cannam@18 576 case o::sampleRate:
fazekasgy@0 577 od.sampleRate = (float) PyFloat_AS_DOUBLE(pyValue);
fazekasgy@8 578 // od.sampleRate = m_inputSampleRate / m_stepSize;
fazekasgy@8 579 cerr << od.sampleRate << endl;
fazekasgy@0 580 break;
cannam@18 581 case o::hasDuration:
cannam@18 582 od.hasDuration = (bool)PyInt_AS_LONG(pyValue);
cannam@18 583 break;
fazekasgy@0 584 default :
cannam@18 585 cerr << "Invalid key in Vamp OutputDescriptor: " << PyString_AsString(pyKey) << endl;
fazekasgy@6 586 }
fazekasgy@6 587 } // while dict
fazekasgy@0 588 list.push_back(od);
fazekasgy@6 589 } // for list
fazekasgy@0 590 Py_CLEAR(pyList);
fazekasgy@0 591 return list;
fazekasgy@0 592 }
fazekasgy@0 593
fazekasgy@0 594 PyPlugin::ParameterList
fazekasgy@0 595 PyPlugin::getParameterDescriptors() const
fazekasgy@0 596 {
cannam@3 597 MutexLocker locker(&m_pythonInterpreterMutex);
cannam@3 598
fazekasgy@0 599 ParameterList list;
fazekasgy@0 600 ParameterDescriptor pd;
fazekasgy@0 601 char method[]="getParameterDescriptors";
fazekasgy@0 602 cerr << "[call] " << method << endl;
fazekasgy@0 603
fazekasgy@0 604 //Check if the method is implemented in Python
fazekasgy@6 605 if ( ! PyObject_HasAttrString(m_pyInstance,method) ) return list;
fazekasgy@0 606
fazekasgy@0 607 //Call the method: must return list object (new reference)
fazekasgy@0 608 PyObject *pyList =
fazekasgy@0 609 PyObject_CallMethod(m_pyInstance,method, NULL);
fazekasgy@0 610
fazekasgy@0 611 //Check return type
fazekasgy@0 612 if (! PyList_Check(pyList) ) {
fazekasgy@0 613 Py_CLEAR(pyList);
fazekasgy@0 614 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 615 << "] Expected List return type." << endl;
fazekasgy@0 616 return list;
fazekasgy@0 617 }
fazekasgy@0 618
fazekasgy@0 619
fazekasgy@0 620 //These will all be borrowed references (no need to DECREF)
fazekasgy@0 621 PyObject *pyDict, *pyKey, *pyValue;
fazekasgy@0 622
fazekasgy@0 623 //Parse Output List
fazekasgy@0 624 for (Py_ssize_t i = 0; i < PyList_GET_SIZE(pyList); ++i) {
fazekasgy@0 625
cannam@18 626 //Get i-th Vamp output descriptor (Borrowed Reference)
fazekasgy@0 627 pyDict = PyList_GET_ITEM(pyList,i);
fazekasgy@0 628
fazekasgy@0 629 //We only care about dictionaries holding output descriptors
fazekasgy@0 630 if ( !PyDict_Check(pyDict) ) continue;
fazekasgy@0 631
fazekasgy@0 632 Py_ssize_t pyPos = NULL;
fazekasgy@0 633 initMaps();
fazekasgy@0 634
fazekasgy@0 635 //Python Sequence Iterator
fazekasgy@0 636 while (PyDict_Next(pyDict, &pyPos, &pyKey, &pyValue))
fazekasgy@0 637 {
fazekasgy@0 638 switch (parmKeys[PyString_AsString(pyKey)])
fazekasgy@0 639 {
cannam@18 640 case p::not_found :
cannam@18 641 cerr << "Unknown key in Vamp OutputDescriptor: " << PyString_AsString(pyKey) << endl;
fazekasgy@0 642 break;
fazekasgy@0 643 case p::identifier:
fazekasgy@0 644 pd.identifier = PyString_AsString(pyValue);
fazekasgy@0 645 break;
fazekasgy@0 646 case p::name:
fazekasgy@0 647 pd.name = PyString_AsString(pyValue);
fazekasgy@0 648 break;
fazekasgy@0 649 case p::description:
fazekasgy@0 650 pd.description = PyString_AsString(pyValue);
fazekasgy@0 651 break;
fazekasgy@0 652 case p::unit:
fazekasgy@0 653 pd.unit = PyString_AsString(pyValue);
fazekasgy@0 654 break;
fazekasgy@0 655 case p::minValue:
fazekasgy@0 656 pd.minValue = (float) PyFloat_AS_DOUBLE(pyValue);
fazekasgy@0 657 break;
fazekasgy@0 658 case p::maxValue:
fazekasgy@0 659 pd.maxValue = (float) PyFloat_AS_DOUBLE(pyValue);
fazekasgy@0 660 break;
fazekasgy@0 661 case p::defaultValue:
fazekasgy@0 662 pd.defaultValue = (float) PyFloat_AS_DOUBLE(pyValue);
fazekasgy@0 663 break;
fazekasgy@0 664 case p::isQuantized:
fazekasgy@0 665 pd.isQuantized = (bool) PyInt_AS_LONG(pyValue);
fazekasgy@0 666 break;
fazekasgy@0 667 default :
cannam@18 668 cerr << "Invalid key in Vamp OutputDescriptor: " << PyString_AsString(pyKey) << endl;
fazekasgy@6 669 }
fazekasgy@6 670 } // while dict
fazekasgy@0 671 list.push_back(pd);
fazekasgy@6 672 } // for list
fazekasgy@0 673 Py_CLEAR(pyList);
fazekasgy@0 674 return list;
fazekasgy@0 675 }
fazekasgy@0 676
fazekasgy@0 677 void PyPlugin::setParameter(std::string paramid, float newval)
fazekasgy@0 678 {
cannam@3 679 MutexLocker locker(&m_pythonInterpreterMutex);
cannam@3 680
fazekasgy@0 681 char method[]="setParameter";
fazekasgy@0 682 cerr << "[call] " << method << endl;
fazekasgy@0 683
fazekasgy@0 684 //Check if the method is implemented in Python
fazekasgy@0 685 if (PyObject_HasAttrString(m_pyInstance,method)) {
fazekasgy@0 686
fazekasgy@0 687 PyObject *pyMethod = PyString_FromString(method);
fazekasgy@0 688 PyObject *pyParamid = PyString_FromString(paramid.c_str());
fazekasgy@0 689 PyObject *pyNewval = PyFloat_FromDouble((double)newval);
fazekasgy@0 690
fazekasgy@0 691 //Call the method
fazekasgy@0 692 PyObject *pyBool =
fazekasgy@0 693 PyObject_CallMethodObjArgs(m_pyInstance,pyMethod,pyParamid,pyNewval,NULL);
fazekasgy@0 694
fazekasgy@0 695 //This only happens if there is a syntax error or so
fazekasgy@0 696 if (pyBool == NULL) {
fazekasgy@0 697 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 698 << "] Error setting parameter: " << paramid << endl;
fazekasgy@0 699 if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
fazekasgy@0 700 }
fazekasgy@0 701
fazekasgy@0 702 Py_DECREF(pyMethod);
fazekasgy@0 703 Py_DECREF(pyParamid);
fazekasgy@0 704 Py_DECREF(pyNewval);
fazekasgy@0 705 }
fazekasgy@0 706 }
fazekasgy@0 707
fazekasgy@0 708 float PyPlugin::getParameter(std::string paramid) const
fazekasgy@0 709 {
cannam@3 710 MutexLocker locker(&m_pythonInterpreterMutex);
cannam@3 711
fazekasgy@0 712 char method[]="getParameter";
fazekasgy@0 713 cerr << "[call] " << method << endl;
fazekasgy@0 714 float rValue = 0.0f;
fazekasgy@0 715
fazekasgy@0 716 //Check if the method is implemented in Python
fazekasgy@0 717 if (PyObject_HasAttrString(m_pyInstance,method)) {
fazekasgy@0 718
fazekasgy@0 719 PyObject *pyMethod = PyString_FromString(method);
fazekasgy@0 720 PyObject *pyParamid = PyString_FromString(paramid.c_str());
fazekasgy@0 721
fazekasgy@0 722 //Call the method
fazekasgy@0 723 PyObject *pyFloat =
fazekasgy@0 724 PyObject_CallMethodObjArgs(m_pyInstance,pyMethod,pyParamid,NULL);
fazekasgy@0 725
fazekasgy@0 726 //Check return type
fazekasgy@0 727 if (! PyFloat_Check(pyFloat) ) {
fazekasgy@0 728 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 729 << "] Expected Float return type." << endl;
fazekasgy@0 730 if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
fazekasgy@0 731 Py_CLEAR(pyFloat);
fazekasgy@0 732 return rValue;
fazekasgy@0 733 }
fazekasgy@0 734
fazekasgy@0 735 rValue = (float) PyFloat_AS_DOUBLE(pyFloat);
fazekasgy@0 736
fazekasgy@0 737 Py_DECREF(pyMethod);
fazekasgy@0 738 Py_DECREF(pyParamid);
fazekasgy@0 739 Py_DECREF(pyFloat);
fazekasgy@0 740 }
fazekasgy@0 741
fazekasgy@0 742 return rValue;
fazekasgy@0 743 }
fazekasgy@0 744
fazekasgy@0 745 #ifdef _DEBUG
fazekasgy@0 746 static int proccounter = 0;
fazekasgy@0 747 #endif
fazekasgy@0 748
fazekasgy@0 749 PyPlugin::FeatureSet
fazekasgy@0 750 PyPlugin::process(const float *const *inputBuffers,
fazekasgy@0 751 Vamp::RealTime timestamp)
fazekasgy@0 752 {
cannam@3 753 MutexLocker locker(&m_pythonInterpreterMutex);
cannam@3 754
fazekasgy@6 755 #ifdef _DEBUG
fazekasgy@6 756 cerr << "[call] process, frame:" << proccounter << endl;
fazekasgy@6 757 proccounter++;
fazekasgy@6 758 #endif
fazekasgy@6 759
fazekasgy@8 760 if (m_blockSize == 0 || m_channels == 0) {
fazekasgy@0 761 cerr << "ERROR: PyPlugin::process: "
fazekasgy@0 762 << "Plugin has not been initialised" << endl;
fazekasgy@0 763 return FeatureSet();
fazekasgy@0 764 }
fazekasgy@0 765
fazekasgy@6 766 if (m_processType == not_implemented) {
fazekasgy@6 767 cerr << "ERROR: In Python plugin [" << m_class
fazekasgy@6 768 << "] No process implementation found. Returning empty feature set." << endl;
fazekasgy@6 769 return FeatureSet();
fazekasgy@6 770 }
fazekasgy@0 771
fazekasgy@6 772 string method=PyString_AsString(m_pyProcess);
fazekasgy@6 773
fazekasgy@6 774 PyObject *pyOutputList = NULL;
fazekasgy@0 775
fazekasgy@6 776 /*new numPy support*/
fazekasgy@6 777 if (m_processType == numpyProcess) {
fazekasgy@8 778
fazekasgy@8 779 //create a list of buffers
fazekasgy@8 780 PyObject *pyChannelList = PyList_New((Py_ssize_t) m_channels);
fazekasgy@8 781 for (size_t i=0; i < m_channels; ++i) {
fazekasgy@6 782
fazekasgy@8 783 //Expose memory using the Buffer Interface of C/API
fazekasgy@8 784 //This will virtually pass a pointer which can be
fazekasgy@8 785 //recasted in Python code as float or complex array
fazekasgy@8 786 PyObject *pyBuffer = PyBuffer_FromMemory
fazekasgy@8 787 ((void *) (float *) inputBuffers[i],
fazekasgy@8 788 (Py_ssize_t) sizeof(float) * m_blockSize);
fazekasgy@6 789
fazekasgy@8 790 PyList_SET_ITEM(pyChannelList, (Py_ssize_t) i, pyBuffer);
fazekasgy@8 791 }
fazekasgy@8 792
fazekasgy@8 793 //pass RealTime as frameCount
fazekasgy@8 794 PyObject *pyLongSample = PyLong_FromLong (
fazekasgy@8 795 Vamp::RealTime::realTime2Frame
fazekasgy@8 796 (timestamp, (unsigned int) m_inputSampleRate));
fazekasgy@6 797
fazekasgy@8 798 //Call python process (returns new reference)
fazekasgy@8 799 pyOutputList = PyObject_CallMethodObjArgs
fazekasgy@8 800 (m_pyInstance,m_pyProcess,pyChannelList,pyLongSample,NULL);
fazekasgy@8 801
fazekasgy@8 802 Py_DECREF(pyChannelList);
fazekasgy@8 803 Py_DECREF(pyLongSample);
fazekasgy@6 804
fazekasgy@6 805 }
fazekasgy@6 806
fazekasgy@6 807 if (m_processType == legacyProcess) {
fazekasgy@0 808
fazekasgy@8 809 //create a list of lists
fazekasgy@8 810 PyObject *pyChannelList = PyList_New((Py_ssize_t) m_channels);
fazekasgy@8 811 for (size_t i=0; i < m_channels; ++i) {
fazekasgy@0 812
fazekasgy@8 813 //Declare new list object
fazekasgy@8 814 PyObject *pyFloat, *pyList;
fazekasgy@8 815 pyList = PyList_New((Py_ssize_t) m_blockSize);
fazekasgy@8 816
fazekasgy@8 817 //Pack samples into a Python List Object
fazekasgy@8 818 //pyFloat types will always be new references,
fazekasgy@8 819 //these will be discarded when the list is deallocated
fazekasgy@8 820 for (size_t j = 0; j < m_blockSize; ++j) {
fazekasgy@8 821 pyFloat=PyFloat_FromDouble(
fazekasgy@8 822 (double) inputBuffers[i][j]);
fazekasgy@8 823 PyList_SET_ITEM(pyList, (Py_ssize_t) j, pyFloat);
fazekasgy@8 824 }
fazekasgy@8 825 PyList_SET_ITEM(pyChannelList, (Py_ssize_t) i, pyList);
fazekasgy@8 826 }
fazekasgy@8 827
fazekasgy@8 828 //pass RealTime as frameCount
fazekasgy@8 829 PyObject *pyLongSample = PyLong_FromLong (
fazekasgy@8 830 Vamp::RealTime::realTime2Frame
fazekasgy@8 831 (timestamp, (unsigned int) m_inputSampleRate));
fazekasgy@8 832
fazekasgy@8 833 //Call python process (returns new reference)
fazekasgy@8 834 pyOutputList = PyObject_CallMethodObjArgs
fazekasgy@8 835 (m_pyInstance,m_pyProcess,pyChannelList,pyLongSample,NULL);
fazekasgy@8 836
fazekasgy@8 837 Py_DECREF(pyChannelList);
fazekasgy@8 838 Py_DECREF(pyLongSample);
fazekasgy@8 839
fazekasgy@0 840 }
fazekasgy@6 841
fazekasgy@8 842 //return nothing
fazekasgy@8 843 //Py_CLEAR(pyOutputList);
fazekasgy@8 844 //return FeatureSet();
fazekasgy@0 845
fazekasgy@0 846 //Check return type
fazekasgy@0 847 if (pyOutputList == NULL || !PyList_Check(pyOutputList) ) {
fazekasgy@0 848 if (pyOutputList == NULL) {
fazekasgy@0 849 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 850 << "] Unexpected result." << endl;
fazekasgy@0 851 if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
fazekasgy@0 852 } else {
fazekasgy@0 853 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 854 << "] Expected List return type." << endl;
fazekasgy@0 855 }
fazekasgy@0 856 Py_CLEAR(pyOutputList);
fazekasgy@0 857 return FeatureSet();
fazekasgy@0 858 }
fazekasgy@0 859
fazekasgy@0 860 // Py_DECREF(pyList);
fazekasgy@0 861 // This appears to be tracked by the cyclic garbage collector
fazekasgy@0 862 // hence decrefing produces GC error
fazekasgy@0 863 #ifdef _DEBUG
fazekasgy@0 864 cerr << "Process Returned Features" << endl;
fazekasgy@0 865 #endif
fazekasgy@0 866 // These will ALL be borrowed references
fazekasgy@0 867 PyObject *pyFeatureList, *pyDict, *pyKey, *pyValue;
fazekasgy@0 868
fazekasgy@0 869 FeatureSet returnFeatures;
fazekasgy@0 870
fazekasgy@0 871 //Parse Output List for each element (FeatureSet)
fazekasgy@0 872 for (Py_ssize_t i = 0;
fazekasgy@0 873 i < PyList_GET_SIZE(pyOutputList); ++i) {
fazekasgy@0 874 //cerr << "output (FeatureSet): " << i << endl;
fazekasgy@0 875
fazekasgy@0 876 //Get i-th FeatureList (Borrowed Reference)
fazekasgy@0 877 pyFeatureList = PyList_GET_ITEM(pyOutputList,i);
fazekasgy@0 878
fazekasgy@0 879 //Parse FeatureList for each element (Feature)
fazekasgy@0 880 for (Py_ssize_t j = 0; j < PyList_GET_SIZE(pyFeatureList); ++j) {
fazekasgy@0 881 //cerr << "element (FeatureList): " << j << endl;
fazekasgy@0 882
fazekasgy@0 883 //Get j-th Feature (Borrowed Reference)
fazekasgy@0 884 pyDict = PyList_GET_ITEM(pyFeatureList,j);
fazekasgy@0 885
fazekasgy@0 886 //We only care about dictionaries holding a Feature struct
fazekasgy@0 887 if ( !PyDict_Check(pyDict) ) continue;
fazekasgy@0 888
fazekasgy@0 889 Py_ssize_t pyPos = NULL;
fazekasgy@0 890 bool emptyFeature = true;
fazekasgy@0 891 Feature feature;
fazekasgy@0 892
fazekasgy@0 893 //process::Python Sequence Iterator for dictionary
fazekasgy@0 894 while (PyDict_Next(pyDict, &pyPos, &pyKey, &pyValue))
fazekasgy@0 895 {
fazekasgy@0 896 emptyFeature = false;
fazekasgy@0 897 switch (ffKeys[PyString_AsString(pyKey)])
fazekasgy@0 898 {
cannam@18 899 case unknown:
cannam@18 900 cerr << "Unknown key in Vamp FeatureSet: "
fazekasgy@0 901 << PyString_AsString(pyKey) << endl;
fazekasgy@0 902 break;
fazekasgy@0 903 case hasTimestamp:
fazekasgy@0 904 feature.hasTimestamp = (bool) PyInt_AS_LONG(pyValue);
fazekasgy@0 905 break;
fazekasgy@0 906 case timeStamp:
fazekasgy@8 907 feature.timestamp =
fazekasgy@8 908 Vamp::RealTime::frame2RealTime(
fazekasgy@8 909 PyLong_AsLong(pyValue),
fazekasgy@8 910 (unsigned int) m_inputSampleRate );
fazekasgy@8 911 #ifdef _DEBUG
fazekasgy@8 912 cerr << "Timestamp: "
fazekasgy@8 913 << (long)PyLong_AsLong(pyValue) << ", ->"
fazekasgy@8 914 << feature.timestamp.toString() << endl;
fazekasgy@8 915 #endif
fazekasgy@0 916 break;
cannam@18 917 case hasDuration:
cannam@18 918 feature.hasDuration = (bool) PyInt_AS_LONG(pyValue);
cannam@18 919 break;
cannam@18 920 case duration:
cannam@18 921 feature.duration =
cannam@18 922 Vamp::RealTime::frame2RealTime(
cannam@18 923 PyLong_AsLong(pyValue),
cannam@18 924 (unsigned int) m_inputSampleRate );
cannam@18 925 #ifdef _DEBUG
cannam@18 926 cerr << "Duration: "
cannam@18 927 << (long)PyLong_AsLong(pyValue) << ", ->"
cannam@18 928 << feature.duration.toString() << endl;
cannam@18 929 #endif
cannam@18 930 break;
fazekasgy@0 931 case values:
fazekasgy@0 932 feature.values = PyList_As_FloatVector(pyValue);
fazekasgy@0 933 break;
fazekasgy@0 934 case label:
fazekasgy@0 935 feature.label = PyString_AsString(pyValue);
fazekasgy@0 936 break;
fazekasgy@0 937 default :
cannam@18 938 cerr << "Invalid key in Vamp FeatureSet: "
fazekasgy@0 939 << PyString_AsString(pyKey) << endl;
fazekasgy@0 940 } // switch
fazekasgy@0 941
fazekasgy@0 942 } // while
fazekasgy@0 943 if (emptyFeature) cerr << "Warning: This feature is empty or badly formatted." << endl;
fazekasgy@0 944 else returnFeatures[i].push_back(feature);
fazekasgy@0 945
fazekasgy@0 946 }// for j = FeatureList
fazekasgy@0 947
fazekasgy@0 948 }//for i = FeatureSet
fazekasgy@0 949 Py_CLEAR(pyOutputList);
fazekasgy@0 950 return returnFeatures;
fazekasgy@0 951 }
fazekasgy@0 952
fazekasgy@0 953
fazekasgy@0 954
fazekasgy@0 955 PyPlugin::FeatureSet
fazekasgy@0 956 PyPlugin::getRemainingFeatures()
fazekasgy@0 957 {
cannam@3 958 MutexLocker locker(&m_pythonInterpreterMutex);
cannam@3 959
fazekasgy@0 960 static char method[]="getRemainingFeatures";
fazekasgy@0 961 cerr << "[call] " << method << endl;
fazekasgy@0 962
fazekasgy@0 963 //check if the method is implemented
fazekasgy@0 964 if ( ! PyObject_HasAttrString(m_pyInstance,method) ) {
fazekasgy@0 965 return FeatureSet();
fazekasgy@0 966 }
fazekasgy@0 967
fazekasgy@0 968 PyObject *pyMethod = PyString_FromString(method);
fazekasgy@0 969
fazekasgy@0 970 PyObject *pyOutputList =
fazekasgy@0 971 PyObject_CallMethod(m_pyInstance,method, NULL);
fazekasgy@0 972
fazekasgy@0 973 //Check return type
fazekasgy@0 974 if (pyOutputList == NULL || !PyList_Check(pyOutputList) ) {
fazekasgy@0 975 if (pyOutputList == NULL) {
fazekasgy@0 976 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 977 << "] Unexpected result." << endl;
fazekasgy@0 978 if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
fazekasgy@0 979 } else {
fazekasgy@0 980 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 981 << "] Expected List return type." << endl;
fazekasgy@0 982 }
fazekasgy@0 983 Py_CLEAR(pyMethod);
fazekasgy@0 984 Py_CLEAR(pyOutputList);
fazekasgy@0 985 return FeatureSet();
fazekasgy@0 986 }
fazekasgy@0 987 Py_DECREF(pyMethod);
fazekasgy@0 988
fazekasgy@0 989 PyObject *pyFeatureList, *pyDict, *pyKey, *pyValue;
fazekasgy@0 990 FeatureSet returnFeatures;
fazekasgy@8 991
fazekasgy@8 992 //iterate through list of outputs
fazekasgy@0 993 for (Py_ssize_t i = 0; i < PyList_GET_SIZE(pyOutputList); ++i) {
fazekasgy@0 994
fazekasgy@0 995 pyFeatureList = PyList_GET_ITEM(pyOutputList,i);
fazekasgy@0 996
fazekasgy@8 997 //iterate list of Features
fazekasgy@0 998 for (Py_ssize_t j = 0; j < PyList_GET_SIZE(pyFeatureList); ++j) {
fazekasgy@8 999 #ifdef _DEBUG
fazekasgy@8 1000 cerr << "feature: " << j << endl;
fazekasgy@8 1001 #endif
fazekasgy@0 1002 pyDict = PyList_GET_ITEM(pyFeatureList,j);
fazekasgy@0 1003
fazekasgy@0 1004 if ( !PyDict_Check(pyDict) ) continue;
fazekasgy@0 1005
fazekasgy@0 1006 Py_ssize_t pyPos = NULL;
fazekasgy@0 1007 bool emptyFeature = true;
fazekasgy@0 1008 Feature feature;
fazekasgy@0 1009
fazekasgy@0 1010 while (PyDict_Next(pyDict, &pyPos, &pyKey, &pyValue))
fazekasgy@0 1011 {
fazekasgy@0 1012 emptyFeature = false;
fazekasgy@0 1013 switch (ffKeys[PyString_AsString(pyKey)])
fazekasgy@0 1014 {
cannam@18 1015 case unknown :
cannam@18 1016 cerr << "Unknown key in Vamp FeatureSet: "
fazekasgy@0 1017 << PyString_AsString(pyKey) << endl;
fazekasgy@0 1018 break;
fazekasgy@0 1019 case hasTimestamp:
fazekasgy@0 1020 feature.hasTimestamp = (bool) PyInt_AS_LONG(pyValue);
fazekasgy@0 1021 break;
fazekasgy@0 1022 case timeStamp:
fazekasgy@0 1023 feature.timestamp =
fazekasgy@8 1024 Vamp::RealTime::frame2RealTime(
fazekasgy@8 1025 PyLong_AsLong(pyValue),
fazekasgy@8 1026 (unsigned int) m_inputSampleRate );
fazekasgy@8 1027 #ifdef _DEBUG
fazekasgy@8 1028 cerr << "Timestamp: "
fazekasgy@8 1029 << (long)PyLong_AsLong(pyValue) << ", ->"
fazekasgy@8 1030 << feature.timestamp.toString() << endl;
fazekasgy@8 1031 #endif
fazekasgy@0 1032 break;
cannam@18 1033 case hasDuration:
cannam@18 1034 feature.hasDuration = (bool) PyInt_AS_LONG(pyValue);
cannam@18 1035 break;
cannam@18 1036 case duration:
cannam@18 1037 feature.duration =
cannam@18 1038 Vamp::RealTime::frame2RealTime(
cannam@18 1039 PyLong_AsLong(pyValue),
cannam@18 1040 (unsigned int) m_inputSampleRate );
cannam@18 1041 #ifdef _DEBUG
cannam@18 1042 cerr << "Duration: "
cannam@18 1043 << (long)PyLong_AsLong(pyValue) << ", ->"
cannam@18 1044 << feature.duration.toString() << endl;
cannam@18 1045 #endif
cannam@18 1046 break;
fazekasgy@0 1047 case values:
fazekasgy@0 1048 feature.values = PyList_As_FloatVector(pyValue);
fazekasgy@0 1049 break;
fazekasgy@0 1050 case label:
fazekasgy@0 1051 feature.label = PyString_AsString(pyValue);
fazekasgy@0 1052 break;
fazekasgy@0 1053 } // switch
fazekasgy@0 1054 } // while
fazekasgy@0 1055 if (emptyFeature) cerr << "Warning: This feature is empty or badly formatted." << endl;
fazekasgy@0 1056 else returnFeatures[i].push_back(feature);
fazekasgy@0 1057 }// for j
fazekasgy@0 1058 }//for i
fazekasgy@0 1059 Py_CLEAR(pyOutputList);
fazekasgy@0 1060 return returnFeatures;
fazekasgy@0 1061 }
fazekasgy@0 1062
fazekasgy@6 1063 bool
fazekasgy@6 1064 PyPlugin::initMaps() const
fazekasgy@6 1065 {
fazekasgy@6 1066
fazekasgy@6 1067 if (isMapInitialised) return true;
fazekasgy@6 1068
cannam@18 1069 outKeys["identifier"] = o::identifier;
cannam@18 1070 outKeys["name"] = o::name;
cannam@18 1071 outKeys["description"] = o::description;
cannam@18 1072 outKeys["unit"] = o::unit;
cannam@18 1073 outKeys["hasFixedBinCount"] = o::hasFixedBinCount;
cannam@18 1074 outKeys["binCount"] = o::binCount;
cannam@18 1075 outKeys["binNames"] = o::binNames;
cannam@18 1076 outKeys["hasKnownExtents"] = o::hasKnownExtents;
cannam@18 1077 outKeys["minValue"] = o::minValue;
cannam@18 1078 outKeys["maxValue"] = o::maxValue;
cannam@18 1079 outKeys["isQuantized"] = o::isQuantized;
cannam@18 1080 outKeys["quantizeStep"] = o::quantizeStep;
cannam@18 1081 outKeys["sampleType"] = o::sampleType;
cannam@18 1082 outKeys["sampleRate"] = o::sampleRate;
cannam@18 1083 outKeys["hasDuration"] = o::hasDuration;
fazekasgy@6 1084
fazekasgy@6 1085 sampleKeys["OneSamplePerStep"] = OneSamplePerStep;
fazekasgy@6 1086 sampleKeys["FixedSampleRate"] = FixedSampleRate;
fazekasgy@6 1087 sampleKeys["VariableSampleRate"] = VariableSampleRate;
fazekasgy@6 1088
fazekasgy@6 1089 ffKeys["hasTimestamp"] = hasTimestamp;
fazekasgy@6 1090 ffKeys["timeStamp"] = timeStamp;
cannam@18 1091 ffKeys["hasDuration"] = hasDuration;
cannam@18 1092 ffKeys["duration"] = duration;
fazekasgy@6 1093 ffKeys["values"] = values;
fazekasgy@6 1094 ffKeys["label"] = label;
fazekasgy@6 1095
fazekasgy@6 1096 parmKeys["identifier"] = p::identifier;
fazekasgy@6 1097 parmKeys["name"] = p::name;
fazekasgy@6 1098 parmKeys["description"] = p::description;
fazekasgy@6 1099 parmKeys["unit"] = p::unit;
fazekasgy@6 1100 parmKeys["minValue"] = p::minValue;
fazekasgy@6 1101 parmKeys["maxValue"] = p::maxValue;
fazekasgy@6 1102 parmKeys["defaultValue"] = p::defaultValue;
fazekasgy@6 1103 parmKeys["isQuantized"] = p::isQuantized;
fazekasgy@6 1104
fazekasgy@6 1105 isMapInitialised = true;
fazekasgy@6 1106 return true;
fazekasgy@6 1107 }
fazekasgy@6 1108
fazekasgy@6 1109
fazekasgy@6 1110 //missing API helper: convert Python list to C++ vector of strings
fazekasgy@6 1111 //TODO: these could be templates if we need more of this kind
fazekasgy@6 1112 std::vector<std::string>
fazekasgy@6 1113 PyPlugin::PyList_To_StringVector (PyObject *inputList) const {
fazekasgy@6 1114
fazekasgy@6 1115 std::vector<std::string> Output;
fazekasgy@6 1116 std::string ListElement;
fazekasgy@6 1117 PyObject *pyString = NULL;
fazekasgy@6 1118
fazekasgy@6 1119 if (!PyList_Check(inputList)) return Output;
fazekasgy@6 1120
fazekasgy@6 1121 for (Py_ssize_t i = 0; i < PyList_GET_SIZE(inputList); ++i) {
fazekasgy@6 1122 //Get next list item (Borrowed Reference)
fazekasgy@6 1123 pyString = PyList_GET_ITEM(inputList,i);
fazekasgy@6 1124 ListElement = (string) PyString_AsString(PyObject_Str(pyString));
fazekasgy@6 1125 Output.push_back(ListElement);
fazekasgy@6 1126 }
fazekasgy@6 1127 return Output;
fazekasgy@6 1128 }
fazekasgy@6 1129
fazekasgy@6 1130 //missing API helper: convert Python list to C++ vector of floats
fazekasgy@6 1131 std::vector<float>
fazekasgy@6 1132 PyPlugin::PyList_As_FloatVector (PyObject *inputList) const {
fazekasgy@6 1133
fazekasgy@6 1134 std::vector<float> Output;
fazekasgy@6 1135 float ListElement;
fazekasgy@6 1136 PyObject *pyFloat = NULL;
fazekasgy@6 1137
fazekasgy@6 1138 if (!PyList_Check(inputList)) return Output;
fazekasgy@6 1139
fazekasgy@6 1140 for (Py_ssize_t k = 0; k < PyList_GET_SIZE(inputList); ++k) {
fazekasgy@6 1141 //Get next list item (Borrowed Reference)
fazekasgy@6 1142 pyFloat = PyList_GET_ITEM(inputList,k);
fazekasgy@6 1143 ListElement = (float) PyFloat_AS_DOUBLE(pyFloat);
fazekasgy@8 1144 #ifdef _DEBUG
fazekasgy@8 1145 cerr << "value: " << ListElement << endl;
fazekasgy@8 1146 #endif
fazekasgy@6 1147 Output.push_back(ListElement);
fazekasgy@6 1148 }
fazekasgy@6 1149
fazekasgy@6 1150 return Output;
fazekasgy@6 1151 }
fazekasgy@6 1152
fazekasgy@6 1153 /* TODO: find out why this produces error, also
fazekasgy@6 1154 do sg more clever about handling RealTime
fazekasgy@6 1155 Vamp::RealTime
fazekasgy@6 1156 PyFrame_As_RealTime (PyObject *frameNo,size_t inputSampleRate) {
fazekasgy@6 1157 Vamp::RealTime result =
fazekasgy@6 1158 Vamp::RealTime::frame2RealTime((size_t)PyInt_AS_LONG(frameNo), inputSampleRate);
fazekasgy@6 1159 return result;
fazekasgy@6 1160 }
fazekasgy@6 1161 */
fazekasgy@6 1162