annotate PyPlugin.cpp @ 23:535d559300dc

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