annotate PyPlugin.cpp @ 28:5139bf30f208

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