annotate PyPlugin.cpp @ 7:a4c955e9a70b

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