annotate PyPlugin.cpp @ 27:046ba4183373

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