annotate PyPlugin.cpp @ 26:ba3686eb697c

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