annotate PyPlugin.cpp @ 10:8e9fbe4dc94d

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