annotate PyPlugin.cpp @ 3:134313c59d82

* Add global mutex to PyPlugin -- all plugin method calls are strictly serialised in order to avoid problems with Python interpreter's lack of thread safety.
author cannam
date Fri, 14 Mar 2008 12:02:15 +0000
parents e20e214bdfb5
children e1b508f2f914
rev   line source
fazekasgy@0 1 /*
fazekasgy@0 2 Vamp
fazekasgy@0 3
fazekasgy@0 4 An API for audio analysis and feature extraction plugins.
fazekasgy@0 5
fazekasgy@0 6 Centre for Digital Music, Queen Mary, University of London.
fazekasgy@0 7 Copyright 2006 Chris Cannam.
fazekasgy@0 8
fazekasgy@0 9 Permission is hereby granted, free of charge, to any person
fazekasgy@0 10 obtaining a copy of this software and associated documentation
fazekasgy@0 11 files (the "Software"), to deal in the Software without
fazekasgy@0 12 restriction, including without limitation the rights to use, copy,
fazekasgy@0 13 modify, merge, publish, distribute, sublicense, and/or sell copies
fazekasgy@0 14 of the Software, and to permit persons to whom the Software is
fazekasgy@0 15 furnished to do so, subject to the following conditions:
fazekasgy@0 16
fazekasgy@0 17 The above copyright notice and this permission notice shall be
fazekasgy@0 18 included in all copies or substantial portions of the Software.
fazekasgy@0 19
fazekasgy@0 20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
fazekasgy@0 21 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
fazekasgy@0 22 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
fazekasgy@0 23 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
fazekasgy@0 24 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
fazekasgy@0 25 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
fazekasgy@0 26 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
fazekasgy@0 27
fazekasgy@0 28 Except as contained in this notice, the names of the Centre for
fazekasgy@0 29 Digital Music; Queen Mary, University of London; and Chris Cannam
fazekasgy@0 30 shall not be used in advertising or otherwise to promote the sale,
fazekasgy@0 31 use or other dealings in this Software without prior written
fazekasgy@0 32 authorization.
fazekasgy@0 33 */
fazekasgy@0 34
fazekasgy@0 35
fazekasgy@0 36
fazekasgy@0 37 /**
fazekasgy@0 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
fazekasgy@0 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@0 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;
cannam@3 75
fazekasgy@0 76 void initMaps()
fazekasgy@0 77 {
fazekasgy@0 78 outKeys["identifier"] = identifier;
fazekasgy@0 79 outKeys["name"] = name;
fazekasgy@0 80 outKeys["description"] = description;
fazekasgy@0 81 outKeys["unit"] = unit;
fazekasgy@0 82 outKeys["hasFixedBinCount"] = hasFixedBinCount;
fazekasgy@0 83 outKeys["binCount"] = binCount;
fazekasgy@0 84 outKeys["binNames"] = binNames;
fazekasgy@0 85 outKeys["hasKnownExtents"] = hasKnownExtents;
fazekasgy@0 86 outKeys["minValue"] = minValue;
fazekasgy@0 87 outKeys["maxValue"] = maxValue;
fazekasgy@0 88 outKeys["isQuantized"] = isQuantized;
fazekasgy@0 89 outKeys["quantizeStep"] = quantizeStep;
fazekasgy@0 90 outKeys["sampleType"] = sampleType;
fazekasgy@0 91 outKeys["sampleRate"] = sampleRate;
fazekasgy@0 92
fazekasgy@0 93 sampleKeys["OneSamplePerStep"] = OneSamplePerStep;
fazekasgy@0 94 sampleKeys["FixedSampleRate"] = FixedSampleRate;
fazekasgy@0 95 sampleKeys["VariableSampleRate"] = VariableSampleRate;
fazekasgy@0 96
fazekasgy@0 97 ffKeys["hasTimestamp"] = hasTimestamp;
fazekasgy@0 98 ffKeys["timeStamp"] = timeStamp;
fazekasgy@0 99 ffKeys["values"] = values;
fazekasgy@0 100 ffKeys["label"] = label;
fazekasgy@0 101
fazekasgy@0 102 parmKeys["identifier"] = p::identifier;
fazekasgy@0 103 parmKeys["name"] = p::name;
fazekasgy@0 104 parmKeys["description"] = p::description;
fazekasgy@0 105 parmKeys["unit"] = p::unit;
fazekasgy@0 106 parmKeys["minValue"] = p::minValue;
fazekasgy@0 107 parmKeys["maxValue"] = p::maxValue;
fazekasgy@0 108 parmKeys["defaultValue"] = p::defaultValue;
fazekasgy@0 109 parmKeys["isQuantized"] = p::isQuantized;
fazekasgy@0 110
fazekasgy@0 111 }
fazekasgy@0 112
fazekasgy@0 113
fazekasgy@0 114 //missing API helper: convert Python list to C++ vector of strings
fazekasgy@0 115 //TODO: these could be templates if we need more of this kind
fazekasgy@0 116 std::vector<std::string> PyList_To_StringVector (PyObject *inputList) {
fazekasgy@0 117
fazekasgy@0 118 std::vector<std::string> Output;
fazekasgy@0 119 std::string ListElement;
fazekasgy@0 120 PyObject *pyString = NULL;
fazekasgy@0 121
fazekasgy@0 122 if (!PyList_Check(inputList)) return Output;
fazekasgy@0 123
fazekasgy@0 124 for (Py_ssize_t i = 0; i < PyList_GET_SIZE(inputList); ++i) {
fazekasgy@0 125 //Get next list item (Borrowed Reference)
fazekasgy@0 126 pyString = PyList_GET_ITEM(inputList,i);
fazekasgy@0 127 ListElement = (string) PyString_AsString(PyObject_Str(pyString));
fazekasgy@0 128 Output.push_back(ListElement);
fazekasgy@0 129 }
fazekasgy@0 130 return Output;
fazekasgy@0 131 }
fazekasgy@0 132
fazekasgy@0 133 //missing API helper: convert Python list to C++ vector of floats
fazekasgy@0 134 std::vector<float> PyList_As_FloatVector (PyObject *inputList) {
fazekasgy@0 135
fazekasgy@0 136 std::vector<float> Output;
fazekasgy@0 137 float ListElement;
fazekasgy@0 138 PyObject *pyFloat = NULL;
fazekasgy@0 139
fazekasgy@0 140 if (!PyList_Check(inputList)) return Output;
fazekasgy@0 141
fazekasgy@0 142 for (Py_ssize_t k = 0; k < PyList_GET_SIZE(inputList); ++k) {
fazekasgy@0 143 //Get next list item (Borrowed Reference)
fazekasgy@0 144 pyFloat = PyList_GET_ITEM(inputList,k);
fazekasgy@0 145 ListElement = (float) PyFloat_AS_DOUBLE(pyFloat);
fazekasgy@0 146 Output.push_back(ListElement);
fazekasgy@0 147 }
fazekasgy@0 148
fazekasgy@0 149 return Output;
fazekasgy@0 150 }
fazekasgy@0 151
fazekasgy@0 152 /* TODO: find out why this produces error, also
fazekasgy@0 153 do sg more clever about handling RealTime
fazekasgy@0 154 Vamp::RealTime
fazekasgy@0 155 PyFrame_As_RealTime (PyObject *frameNo,size_t inputSampleRate) {
fazekasgy@0 156 Vamp::RealTime result =
fazekasgy@0 157 Vamp::RealTime::frame2RealTime((size_t)PyInt_AS_LONG(frameNo), inputSampleRate);
fazekasgy@0 158 return result;
fazekasgy@0 159 }
fazekasgy@0 160 */
fazekasgy@0 161
fazekasgy@0 162
fazekasgy@0 163 PyPlugin::PyPlugin(std::string pluginKey,float inputSampleRate, PyObject *pyInstance) :
fazekasgy@0 164 Plugin(inputSampleRate),
fazekasgy@0 165 m_pyInstance(pyInstance),
fazekasgy@0 166 m_stepSize(0),
fazekasgy@0 167 m_previousSample(0.0f),
fazekasgy@0 168 m_plugin(pluginKey),
fazekasgy@0 169 m_class(pluginKey.substr(pluginKey.rfind(':')+1,pluginKey.size()-1)),
fazekasgy@0 170 m_path((pluginKey.substr(0,pluginKey.rfind(pathsep))))
fazekasgy@0 171 {
fazekasgy@0 172 }
fazekasgy@0 173
fazekasgy@0 174 PyPlugin::~PyPlugin()
fazekasgy@0 175 {
fazekasgy@0 176 cerr << "PyPlugin::PyPlugin:" << m_class
fazekasgy@0 177 << " Instance deleted." << endl;
fazekasgy@0 178 }
fazekasgy@0 179
fazekasgy@0 180
fazekasgy@0 181 string
fazekasgy@0 182 PyPlugin::getIdentifier() const
fazekasgy@0 183 {
cannam@3 184 MutexLocker locker(&m_pythonInterpreterMutex);
cannam@3 185
fazekasgy@0 186 char method[]="getIdentifier";
fazekasgy@0 187 cerr << "[call] " << method << endl;
fazekasgy@0 188 string rString="VampPy-x";
fazekasgy@0 189
fazekasgy@0 190 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
fazekasgy@0 191
fazekasgy@0 192 //Call the method
fazekasgy@0 193 PyObject *pyString =
fazekasgy@0 194 PyObject_CallMethod(m_pyInstance, method, NULL);
fazekasgy@0 195
fazekasgy@0 196 //Check return value
fazekasgy@0 197 if (!PyString_Check(pyString)) {
fazekasgy@0 198 Py_CLEAR(pyString);
fazekasgy@0 199 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 200 << "] Expected String return value." << endl;
fazekasgy@0 201 return rString;
fazekasgy@0 202 }
fazekasgy@0 203
fazekasgy@0 204 rString=PyString_AsString(pyString);
fazekasgy@0 205 Py_CLEAR(pyString);
fazekasgy@0 206 }
fazekasgy@0 207 cerr << "Warning: Plugin must return a unique identifier." << endl;
fazekasgy@0 208 return rString;
fazekasgy@0 209 }
fazekasgy@0 210
fazekasgy@0 211
fazekasgy@0 212 string
fazekasgy@0 213 PyPlugin::getName() const
fazekasgy@0 214 {
cannam@3 215 MutexLocker locker(&m_pythonInterpreterMutex);
fazekasgy@0 216
fazekasgy@0 217 char method[]="getName";
fazekasgy@0 218 cerr << "[call] " << method << endl;
fazekasgy@0 219 string rString="VamPy Plugin (Noname)";
fazekasgy@0 220
fazekasgy@0 221 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
fazekasgy@0 222
fazekasgy@0 223 //Call the method
fazekasgy@0 224 PyObject *pyString =
fazekasgy@0 225 PyObject_CallMethod(m_pyInstance, method, NULL);
fazekasgy@0 226
fazekasgy@0 227 //Check return value
fazekasgy@0 228 if (!PyString_Check(pyString)) {
fazekasgy@0 229 Py_CLEAR(pyString);
fazekasgy@0 230 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 231 << "] Expected String return value." << endl;
fazekasgy@0 232 return rString;
fazekasgy@0 233 }
fazekasgy@0 234
fazekasgy@0 235 rString=PyString_AsString(pyString);
fazekasgy@0 236 Py_CLEAR(pyString);
fazekasgy@0 237 }
fazekasgy@0 238 return rString;
fazekasgy@0 239 }
fazekasgy@0 240
fazekasgy@0 241 string
fazekasgy@0 242 PyPlugin::getDescription() const
fazekasgy@0 243 {
cannam@3 244 MutexLocker locker(&m_pythonInterpreterMutex);
cannam@3 245
fazekasgy@0 246 char method[]="getDescription";
fazekasgy@0 247 cerr << "[call] " << method << endl;
fazekasgy@0 248 string rString="Not given. (Hint: Implement getDescription method.)";
fazekasgy@0 249
fazekasgy@0 250 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
fazekasgy@0 251
fazekasgy@0 252 //Call the method
fazekasgy@0 253 PyObject *pyString =
fazekasgy@0 254 PyObject_CallMethod(m_pyInstance, method, NULL);
fazekasgy@0 255
fazekasgy@0 256 //Check return value
fazekasgy@0 257 if (!PyString_Check(pyString)) {
fazekasgy@0 258 Py_CLEAR(pyString);
fazekasgy@0 259 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 260 << "] Expected String return value." << endl;
fazekasgy@0 261 return rString;
fazekasgy@0 262 }
fazekasgy@0 263
fazekasgy@0 264 rString=PyString_AsString(pyString);
fazekasgy@0 265 Py_CLEAR(pyString);
fazekasgy@0 266 }
fazekasgy@0 267 return rString;
fazekasgy@0 268 }
fazekasgy@0 269
fazekasgy@0 270 string
fazekasgy@0 271 PyPlugin::getMaker() const
fazekasgy@0 272 {
cannam@3 273 MutexLocker locker(&m_pythonInterpreterMutex);
cannam@3 274
fazekasgy@0 275 char method[]="getMaker";
fazekasgy@0 276 cerr << "[call] " << method << endl;
fazekasgy@0 277 string rString="Generic VamPy Plugin.";
fazekasgy@0 278
fazekasgy@0 279 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
fazekasgy@0 280
fazekasgy@0 281 //Call the method
fazekasgy@0 282 PyObject *pyString =
fazekasgy@0 283 PyObject_CallMethod(m_pyInstance, method, NULL);
fazekasgy@0 284
fazekasgy@0 285 //Check return value
fazekasgy@0 286 if (!PyString_Check(pyString)) {
fazekasgy@0 287 Py_CLEAR(pyString);
fazekasgy@0 288 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 289 << "] Expected String return value." << endl;
fazekasgy@0 290 return rString;
fazekasgy@0 291 }
fazekasgy@0 292
fazekasgy@0 293 rString=PyString_AsString(pyString);
fazekasgy@0 294 Py_CLEAR(pyString);
fazekasgy@0 295 }
fazekasgy@0 296 return rString;
fazekasgy@0 297 }
fazekasgy@0 298
fazekasgy@0 299 int
fazekasgy@0 300 PyPlugin::getPluginVersion() const
fazekasgy@0 301 {
fazekasgy@0 302 return 2;
fazekasgy@0 303 }
fazekasgy@0 304
fazekasgy@0 305 string
fazekasgy@0 306 PyPlugin::getCopyright() const
fazekasgy@0 307 {
cannam@3 308 MutexLocker locker(&m_pythonInterpreterMutex);
cannam@3 309
fazekasgy@0 310 char method[]="getCopyright";
fazekasgy@0 311 cerr << "[call] " << method << endl;
fazekasgy@0 312 string rString="BSD License";
fazekasgy@0 313
fazekasgy@0 314 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
fazekasgy@0 315
fazekasgy@0 316 //Call the method
fazekasgy@0 317 PyObject *pyString =
fazekasgy@0 318 PyObject_CallMethod(m_pyInstance, method, NULL);
fazekasgy@0 319
fazekasgy@0 320 //Check return value
fazekasgy@0 321 if (!PyString_Check(pyString)) {
fazekasgy@0 322 Py_CLEAR(pyString);
fazekasgy@0 323 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 324 << "] Expected String return value." << endl;
fazekasgy@0 325 return rString;
fazekasgy@0 326 }
fazekasgy@0 327
fazekasgy@0 328
fazekasgy@0 329 rString=PyString_AsString(pyString);
fazekasgy@0 330 Py_CLEAR(pyString);
fazekasgy@0 331 }
fazekasgy@0 332 return rString;
fazekasgy@0 333 }
fazekasgy@0 334
fazekasgy@0 335
fazekasgy@0 336 bool
fazekasgy@0 337 PyPlugin::initialise(size_t channels, size_t stepSize, size_t blockSize)
fazekasgy@0 338 {
cannam@3 339 MutexLocker locker(&m_pythonInterpreterMutex);
cannam@3 340
fazekasgy@0 341 if (channels < getMinChannelCount() ||
fazekasgy@0 342 channels > getMaxChannelCount()) return false;
fazekasgy@0 343
fazekasgy@0 344 m_stepSize = std::min(stepSize, blockSize);
fazekasgy@0 345 char method[]="initialise";
fazekasgy@0 346 cerr << "[call] " << method << endl;
fazekasgy@0 347
fazekasgy@0 348 //Check if the method is implemented in Python else return false
fazekasgy@0 349 if (PyObject_HasAttrString(m_pyInstance,method)) {
fazekasgy@0 350
fazekasgy@0 351 PyObject *pyMethod = PyString_FromString(method);
fazekasgy@0 352 PyObject *pyChannels = PyInt_FromSsize_t((Py_ssize_t)channels);
fazekasgy@0 353 PyObject *pyStepSize = PyInt_FromSsize_t((Py_ssize_t)m_stepSize);
fazekasgy@0 354 PyObject *pyBlockSize = PyInt_FromSsize_t((Py_ssize_t)blockSize);
fazekasgy@0 355 PyObject *pyInputSampleRate = PyFloat_FromDouble((double)m_inputSampleRate);
fazekasgy@0 356
fazekasgy@0 357 //Call the method
fazekasgy@0 358 PyObject *pyBool =
fazekasgy@0 359 PyObject_CallMethodObjArgs(m_pyInstance,pyMethod,pyChannels,pyStepSize,pyBlockSize,pyInputSampleRate,NULL);
fazekasgy@0 360
fazekasgy@0 361 Py_DECREF(pyMethod);
fazekasgy@0 362 Py_DECREF(pyChannels);
fazekasgy@0 363 Py_DECREF(pyStepSize);
fazekasgy@0 364 Py_DECREF(pyBlockSize);
fazekasgy@0 365 Py_DECREF(pyInputSampleRate);
fazekasgy@0 366
fazekasgy@0 367 //Check return value
fazekasgy@0 368 if (!PyBool_Check(pyBool)) {
fazekasgy@0 369 Py_CLEAR(pyBool);
fazekasgy@0 370 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 371 << "] Expected Bool return value." << endl;
fazekasgy@0 372 return false;
fazekasgy@0 373 }
fazekasgy@0 374
fazekasgy@0 375 if (pyBool == Py_True) {
fazekasgy@0 376 Py_CLEAR(pyBool);
fazekasgy@0 377 return true;
fazekasgy@0 378 } else {
fazekasgy@0 379 Py_CLEAR(pyBool);
fazekasgy@0 380 return false;}
fazekasgy@0 381 }
fazekasgy@0 382 return true;
fazekasgy@0 383 }
fazekasgy@0 384
fazekasgy@0 385 void
fazekasgy@0 386 PyPlugin::reset()
fazekasgy@0 387 {
cannam@3 388 //!!! implement this!
fazekasgy@0 389 m_previousSample = 0.0f;
fazekasgy@0 390 }
fazekasgy@0 391
fazekasgy@0 392 PyPlugin::InputDomain PyPlugin::getInputDomain() const
fazekasgy@0 393 {
cannam@3 394 MutexLocker locker(&m_pythonInterpreterMutex);
cannam@3 395
fazekasgy@0 396 char method[]="getInputDomain";
fazekasgy@0 397 cerr << "[call] " << method << endl;
fazekasgy@0 398 PyPlugin::InputDomain rValue = TimeDomain; // TimeDomain
fazekasgy@0 399
fazekasgy@0 400 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
fazekasgy@0 401
fazekasgy@0 402 PyObject *pyString = PyObject_CallMethod(m_pyInstance, method, NULL);
fazekasgy@0 403
fazekasgy@0 404 //Check return value
fazekasgy@0 405 if (!PyString_Check(pyString)) {
fazekasgy@0 406 Py_CLEAR(pyString);
fazekasgy@0 407 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 408 << "] Expected String return value." << endl;
fazekasgy@0 409 return rValue;
fazekasgy@0 410 }
fazekasgy@0 411
fazekasgy@0 412 string domain = (string) PyString_AsString(pyString);
fazekasgy@0 413 if (domain == "FrequencyDomain") rValue = FrequencyDomain;
fazekasgy@0 414 Py_CLEAR(pyString);
fazekasgy@0 415 }
fazekasgy@0 416 return rValue;
fazekasgy@0 417 }
fazekasgy@0 418
fazekasgy@0 419 size_t PyPlugin::getPreferredBlockSize() const
fazekasgy@0 420 {
cannam@3 421 MutexLocker locker(&m_pythonInterpreterMutex);
cannam@3 422
fazekasgy@0 423 char method[]="getPreferredBlockSize";
fazekasgy@0 424 cerr << "[call] " << method << endl;
fazekasgy@0 425 size_t rValue=0; //not set by default
fazekasgy@0 426 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
fazekasgy@0 427 PyObject *pyInt = PyObject_CallMethod(m_pyInstance, method, NULL);
fazekasgy@0 428
fazekasgy@0 429 //Check return value
fazekasgy@0 430 if (!PyInt_Check(pyInt)) {
fazekasgy@0 431 Py_CLEAR(pyInt);
fazekasgy@0 432 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 433 << "] Expected Integer return value." << endl;
fazekasgy@0 434 return rValue;
fazekasgy@0 435 }
fazekasgy@0 436
fazekasgy@0 437 rValue=(size_t)PyInt_AS_LONG(pyInt);
fazekasgy@0 438 Py_CLEAR(pyInt);
fazekasgy@0 439 }
fazekasgy@0 440 return rValue;
fazekasgy@0 441 }
fazekasgy@0 442
fazekasgy@0 443 //size_t PyPlugin::getPreferredStepSize() const { return 0; }
fazekasgy@0 444 size_t PyPlugin::getPreferredStepSize() const
fazekasgy@0 445 {
cannam@3 446 MutexLocker locker(&m_pythonInterpreterMutex);
cannam@3 447
fazekasgy@0 448 char method[]="getPreferredStepSize";
fazekasgy@0 449 cerr << "[call] " << method << endl;
fazekasgy@0 450 size_t rValue=0; //not set by default
fazekasgy@0 451 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
fazekasgy@0 452 PyObject *pyInt = PyObject_CallMethod(m_pyInstance, method, NULL);
fazekasgy@0 453
fazekasgy@0 454 //Check return value
fazekasgy@0 455 if (!PyInt_Check(pyInt)) {
fazekasgy@0 456 Py_CLEAR(pyInt);
fazekasgy@0 457 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 458 << "] Expected Integer return value." << endl;
fazekasgy@0 459 return rValue;
fazekasgy@0 460 }
fazekasgy@0 461
fazekasgy@0 462 rValue=(size_t)PyInt_AS_LONG(pyInt);
fazekasgy@0 463 Py_CLEAR(pyInt);
fazekasgy@0 464 }
fazekasgy@0 465 return rValue;
fazekasgy@0 466 }
fazekasgy@0 467
fazekasgy@0 468 size_t PyPlugin::getMinChannelCount() const
fazekasgy@0 469 {
cannam@3 470 MutexLocker locker(&m_pythonInterpreterMutex);
cannam@3 471
fazekasgy@0 472 char method[]="getMinChannelCount";
fazekasgy@0 473 cerr << "[call] " << method << endl;
fazekasgy@0 474 size_t rValue=1; //default value
fazekasgy@0 475 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
fazekasgy@0 476 PyObject *pyInt = PyObject_CallMethod(m_pyInstance, method, NULL);
fazekasgy@0 477
fazekasgy@0 478 //Check return value
fazekasgy@0 479 if (!PyInt_Check(pyInt)) {
fazekasgy@0 480 Py_CLEAR(pyInt);
fazekasgy@0 481 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 482 << "] Expected String return value." << endl;
fazekasgy@0 483 return rValue;
fazekasgy@0 484 }
fazekasgy@0 485
fazekasgy@0 486 rValue=(size_t)PyInt_AS_LONG(pyInt);
fazekasgy@0 487 Py_CLEAR(pyInt);
fazekasgy@0 488 }
fazekasgy@0 489 return rValue;
fazekasgy@0 490 }
fazekasgy@0 491
fazekasgy@0 492 size_t PyPlugin::getMaxChannelCount() const
fazekasgy@0 493 {
cannam@3 494 MutexLocker locker(&m_pythonInterpreterMutex);
cannam@3 495
fazekasgy@0 496 char method[]="getMaxChannelCount";
fazekasgy@0 497 cerr << "[call] " << method << endl;
fazekasgy@0 498 size_t rValue=1; //default value
fazekasgy@0 499 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
fazekasgy@0 500 PyObject *pyInt = PyObject_CallMethod(m_pyInstance, method, NULL);
fazekasgy@0 501
fazekasgy@0 502 //Check return value
fazekasgy@0 503 if (!PyInt_Check(pyInt)) {
fazekasgy@0 504 Py_CLEAR(pyInt);
fazekasgy@0 505 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 506 << "] Expected String return value." << endl;
fazekasgy@0 507 return rValue;
fazekasgy@0 508 }
fazekasgy@0 509
fazekasgy@0 510 rValue=(size_t)PyInt_AS_LONG(pyInt);
fazekasgy@0 511 Py_CLEAR(pyInt);
fazekasgy@0 512 }
fazekasgy@0 513 return rValue;
fazekasgy@0 514 }
fazekasgy@0 515
fazekasgy@0 516
fazekasgy@0 517 PyPlugin::OutputList
fazekasgy@0 518 PyPlugin::getOutputDescriptors() const
fazekasgy@0 519 {
cannam@3 520 MutexLocker locker(&m_pythonInterpreterMutex);
cannam@3 521
fazekasgy@0 522 //PyEval_AcquireThread(newThreadState);
fazekasgy@0 523 OutputList list;
fazekasgy@0 524 OutputDescriptor od;
fazekasgy@0 525 char method[]="getOutputDescriptors";
fazekasgy@0 526 cerr << "[call] " << method << endl;
fazekasgy@0 527
fazekasgy@0 528 //Check if the method is implemented in Python
fazekasgy@0 529 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
fazekasgy@0 530
fazekasgy@0 531 //Call the method: must return list object (new reference)
fazekasgy@0 532 PyObject *pyList =
fazekasgy@0 533 PyObject_CallMethod(m_pyInstance,method, NULL);
fazekasgy@0 534
fazekasgy@0 535 //Check return type
fazekasgy@0 536 if (! PyList_Check(pyList) ) {
fazekasgy@0 537 Py_CLEAR(pyList);
fazekasgy@0 538 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 539 << "] Expected List return type." << endl;
fazekasgy@0 540 return list;
fazekasgy@0 541 }
fazekasgy@0 542
fazekasgy@0 543 //These will all be borrowed references (no need to DECREF)
fazekasgy@0 544 PyObject *pyDict, *pyKey, *pyValue;
fazekasgy@0 545
fazekasgy@0 546 //Parse Output List
fazekasgy@0 547 for (Py_ssize_t i = 0; i < PyList_GET_SIZE(pyList); ++i) {
fazekasgy@0 548
fazekasgy@0 549 //Get i-th VAMP output descriptor (Borrowed Reference)
fazekasgy@0 550 pyDict = PyList_GET_ITEM(pyList,i);
fazekasgy@0 551
fazekasgy@0 552 //We only care about dictionaries holding output descriptors
fazekasgy@0 553 if ( !PyDict_Check(pyDict) ) continue;
fazekasgy@0 554
fazekasgy@0 555 Py_ssize_t pyPos = NULL;
fazekasgy@0 556 initMaps();
fazekasgy@0 557
fazekasgy@0 558 //Python Sequence Iterator
fazekasgy@0 559 while (PyDict_Next(pyDict, &pyPos, &pyKey, &pyValue))
fazekasgy@0 560 {
fazekasgy@0 561 switch (outKeys[PyString_AsString(pyKey)])
fazekasgy@0 562 {
fazekasgy@0 563 case not_found :
fazekasgy@0 564 cerr << "Unknown key in VAMP OutputDescriptor: " << PyString_AsString(pyKey) << endl;
fazekasgy@0 565 break;
fazekasgy@0 566 case identifier:
fazekasgy@0 567 od.identifier = PyString_AsString(pyValue);
fazekasgy@0 568 break;
fazekasgy@0 569 case name:
fazekasgy@0 570 od.name = PyString_AsString(pyValue);
fazekasgy@0 571 break;
fazekasgy@0 572 case description:
fazekasgy@0 573 od.description = PyString_AsString(pyValue);
fazekasgy@0 574 break;
fazekasgy@0 575 case unit:
fazekasgy@0 576 od.unit = PyString_AsString(pyValue);
fazekasgy@0 577 break;
fazekasgy@0 578 case hasFixedBinCount:
fazekasgy@0 579 od.hasFixedBinCount = (bool) PyInt_AS_LONG(pyValue);
fazekasgy@0 580 break;
fazekasgy@0 581 case binCount:
fazekasgy@0 582 od.binCount = (size_t) PyInt_AS_LONG(pyValue);
fazekasgy@0 583 break;
fazekasgy@0 584 case binNames:
fazekasgy@0 585 od.binNames = PyList_To_StringVector(pyValue);
fazekasgy@0 586 break;
fazekasgy@0 587 case hasKnownExtents:
fazekasgy@0 588 od.hasKnownExtents = (bool) PyInt_AS_LONG(pyValue);
fazekasgy@0 589 break;
fazekasgy@0 590 case minValue:
fazekasgy@0 591 od.minValue = (float) PyFloat_AS_DOUBLE(pyValue);
fazekasgy@0 592 break;
fazekasgy@0 593 case maxValue:
fazekasgy@0 594 od.maxValue = (float) PyFloat_AS_DOUBLE(pyValue);
fazekasgy@0 595 break;
fazekasgy@0 596 case isQuantized:
fazekasgy@0 597 od.isQuantized = (bool) PyInt_AS_LONG(pyValue);
fazekasgy@0 598 break;
fazekasgy@0 599 case quantizeStep:
fazekasgy@0 600 od.quantizeStep = (float) PyFloat_AS_DOUBLE(pyValue);
fazekasgy@0 601 break;
fazekasgy@0 602 case sampleType:
fazekasgy@0 603 od.sampleType = (OutputDescriptor::SampleType) sampleKeys[PyString_AsString(pyValue)];
fazekasgy@0 604 break;
fazekasgy@0 605 case sampleRate:
fazekasgy@0 606 od.sampleRate = (float) PyFloat_AS_DOUBLE(pyValue);
fazekasgy@0 607 break;
fazekasgy@0 608 default :
fazekasgy@0 609 cerr << "Invalid key in VAMP OutputDescriptor: " << PyString_AsString(pyKey) << endl;
fazekasgy@0 610 } // switch
fazekasgy@0 611 } // while dict keys
fazekasgy@0 612 list.push_back(od);
fazekasgy@0 613 } // for each memeber in outputlist
fazekasgy@0 614 Py_CLEAR(pyList);
fazekasgy@0 615 } // if method is implemented
fazekasgy@0 616 //PyEval_ReleaseThread(newThreadState);
fazekasgy@0 617 return list;
fazekasgy@0 618 }
fazekasgy@0 619
fazekasgy@0 620 PyPlugin::ParameterList
fazekasgy@0 621 PyPlugin::getParameterDescriptors() const
fazekasgy@0 622 {
cannam@3 623 MutexLocker locker(&m_pythonInterpreterMutex);
cannam@3 624
fazekasgy@0 625 ParameterList list;
fazekasgy@0 626 ParameterDescriptor pd;
fazekasgy@0 627 char method[]="getParameterDescriptors";
fazekasgy@0 628 cerr << "[call] " << method << endl;
fazekasgy@0 629
fazekasgy@0 630 //Check if the method is implemented in Python
fazekasgy@0 631 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
fazekasgy@0 632
fazekasgy@0 633 //Call the method: must return list object (new reference)
fazekasgy@0 634 PyObject *pyList =
fazekasgy@0 635 PyObject_CallMethod(m_pyInstance,method, NULL);
fazekasgy@0 636
fazekasgy@0 637 //Check return type
fazekasgy@0 638 if (! PyList_Check(pyList) ) {
fazekasgy@0 639 Py_CLEAR(pyList);
fazekasgy@0 640 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 641 << "] Expected List return type." << endl;
fazekasgy@0 642 return list;
fazekasgy@0 643 }
fazekasgy@0 644
fazekasgy@0 645
fazekasgy@0 646 //These will all be borrowed references (no need to DECREF)
fazekasgy@0 647 PyObject *pyDict, *pyKey, *pyValue;
fazekasgy@0 648
fazekasgy@0 649 //Parse Output List
fazekasgy@0 650 for (Py_ssize_t i = 0; i < PyList_GET_SIZE(pyList); ++i) {
fazekasgy@0 651
fazekasgy@0 652 //Get i-th VAMP output descriptor (Borrowed Reference)
fazekasgy@0 653 pyDict = PyList_GET_ITEM(pyList,i);
fazekasgy@0 654
fazekasgy@0 655 //We only care about dictionaries holding output descriptors
fazekasgy@0 656 if ( !PyDict_Check(pyDict) ) continue;
fazekasgy@0 657
fazekasgy@0 658 Py_ssize_t pyPos = NULL;
fazekasgy@0 659 initMaps();
fazekasgy@0 660
fazekasgy@0 661 //Python Sequence Iterator
fazekasgy@0 662 while (PyDict_Next(pyDict, &pyPos, &pyKey, &pyValue))
fazekasgy@0 663 {
fazekasgy@0 664 switch (parmKeys[PyString_AsString(pyKey)])
fazekasgy@0 665 {
fazekasgy@0 666 case not_found :
fazekasgy@0 667 cerr << "Unknown key in VAMP OutputDescriptor: " << PyString_AsString(pyKey) << endl;
fazekasgy@0 668 break;
fazekasgy@0 669 case p::identifier:
fazekasgy@0 670 pd.identifier = PyString_AsString(pyValue);
fazekasgy@0 671 break;
fazekasgy@0 672 case p::name:
fazekasgy@0 673 pd.name = PyString_AsString(pyValue);
fazekasgy@0 674 break;
fazekasgy@0 675 case p::description:
fazekasgy@0 676 pd.description = PyString_AsString(pyValue);
fazekasgy@0 677 break;
fazekasgy@0 678 case p::unit:
fazekasgy@0 679 pd.unit = PyString_AsString(pyValue);
fazekasgy@0 680 break;
fazekasgy@0 681 case p::minValue:
fazekasgy@0 682 pd.minValue = (float) PyFloat_AS_DOUBLE(pyValue);
fazekasgy@0 683 break;
fazekasgy@0 684 case p::maxValue:
fazekasgy@0 685 pd.maxValue = (float) PyFloat_AS_DOUBLE(pyValue);
fazekasgy@0 686 break;
fazekasgy@0 687 case p::defaultValue:
fazekasgy@0 688 pd.defaultValue = (float) PyFloat_AS_DOUBLE(pyValue);
fazekasgy@0 689 break;
fazekasgy@0 690 case p::isQuantized:
fazekasgy@0 691 pd.isQuantized = (bool) PyInt_AS_LONG(pyValue);
fazekasgy@0 692 break;
fazekasgy@0 693 default :
fazekasgy@0 694 cerr << "Invalid key in VAMP OutputDescriptor: " << PyString_AsString(pyKey) << endl;
fazekasgy@0 695 } // switch
fazekasgy@0 696 } // while dict keys
fazekasgy@0 697 list.push_back(pd);
fazekasgy@0 698 } // for each memeber in outputlist
fazekasgy@0 699 Py_CLEAR(pyList);
fazekasgy@0 700 } // if
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@0 782 if (m_stepSize == 0) {
fazekasgy@0 783 cerr << "ERROR: PyPlugin::process: "
fazekasgy@0 784 << "Plugin has not been initialised" << endl;
fazekasgy@0 785 return FeatureSet();
fazekasgy@0 786 }
fazekasgy@0 787 static char method[]="process";
fazekasgy@0 788
fazekasgy@0 789 #ifdef _DEBUG
fazekasgy@0 790 cerr << "[call] " << method << " frame:" << proccounter << endl;
fazekasgy@0 791 proccounter++;
fazekasgy@0 792 //cerr << "C: proc..." << proccounter << " " << endl;
fazekasgy@0 793 #endif
fazekasgy@0 794
fazekasgy@0 795 //proces::Check if the method is implemented in Python
fazekasgy@0 796 if ( PyObject_HasAttrString(m_pyInstance,method) )
fazekasgy@0 797 {
fazekasgy@0 798
fazekasgy@0 799 //Pack method name into Python Object
fazekasgy@0 800 PyObject *pyMethod = PyString_FromString(method);
fazekasgy@0 801
fazekasgy@0 802 //Declare new list object
fazekasgy@0 803 PyObject *pyFloat, *pyList;
fazekasgy@0 804 pyList = PyList_New((Py_ssize_t) m_stepSize);
fazekasgy@0 805
fazekasgy@0 806 //Pack samples into a Python List Object
fazekasgy@0 807 //pyFloat will always be new references,
fazekasgy@0 808 //these will be discarded when the list is deallocated
fazekasgy@0 809 for (size_t i = 0; i < m_stepSize; ++i) {
fazekasgy@0 810 pyFloat=PyFloat_FromDouble((double) inputBuffers[0][i]);
fazekasgy@0 811 PyList_SET_ITEM(pyList, (Py_ssize_t) i, pyFloat);
fazekasgy@0 812 }
fazekasgy@0 813
fazekasgy@0 814 //Call python process (returns new reference)
fazekasgy@0 815 PyObject *pyOutputList =
fazekasgy@0 816 PyObject_CallMethodObjArgs(m_pyInstance,pyMethod,pyList,NULL);
fazekasgy@0 817
fazekasgy@0 818 //Check return type
fazekasgy@0 819 if (pyOutputList == NULL || !PyList_Check(pyOutputList) ) {
fazekasgy@0 820 if (pyOutputList == NULL) {
fazekasgy@0 821 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 822 << "] Unexpected result." << endl;
fazekasgy@0 823 if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
fazekasgy@0 824 } else {
fazekasgy@0 825 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 826 << "] Expected List return type." << endl;
fazekasgy@0 827 }
fazekasgy@0 828 Py_CLEAR(pyMethod);
fazekasgy@0 829 Py_CLEAR(pyOutputList);
fazekasgy@0 830 return FeatureSet();
fazekasgy@0 831 }
fazekasgy@0 832
fazekasgy@0 833 Py_DECREF(pyMethod);
fazekasgy@0 834 // Py_DECREF(pyList);
fazekasgy@0 835 // This appears to be tracked by the cyclic garbage collector
fazekasgy@0 836 // hence decrefing produces GC error
fazekasgy@0 837 #ifdef _DEBUG
fazekasgy@0 838 cerr << "Process Returned Features" << endl;
fazekasgy@0 839 #endif
fazekasgy@0 840 // These will ALL be borrowed references
fazekasgy@0 841 PyObject *pyFeatureList, *pyDict, *pyKey, *pyValue;
fazekasgy@0 842
fazekasgy@0 843 FeatureSet returnFeatures;
fazekasgy@0 844
fazekasgy@0 845 //Parse Output List for each element (FeatureSet)
fazekasgy@0 846 for (Py_ssize_t i = 0;
fazekasgy@0 847 i < PyList_GET_SIZE(pyOutputList); ++i) {
fazekasgy@0 848 //cerr << "output (FeatureSet): " << i << endl;
fazekasgy@0 849
fazekasgy@0 850 //Get i-th FeatureList (Borrowed Reference)
fazekasgy@0 851 pyFeatureList = PyList_GET_ITEM(pyOutputList,i);
fazekasgy@0 852
fazekasgy@0 853 //Parse FeatureList for each element (Feature)
fazekasgy@0 854 for (Py_ssize_t j = 0; j < PyList_GET_SIZE(pyFeatureList); ++j) {
fazekasgy@0 855 //cerr << "element (FeatureList): " << j << endl;
fazekasgy@0 856
fazekasgy@0 857 //Get j-th Feature (Borrowed Reference)
fazekasgy@0 858 pyDict = PyList_GET_ITEM(pyFeatureList,j);
fazekasgy@0 859
fazekasgy@0 860 //We only care about dictionaries holding a Feature struct
fazekasgy@0 861 if ( !PyDict_Check(pyDict) ) continue;
fazekasgy@0 862
fazekasgy@0 863 Py_ssize_t pyPos = NULL;
fazekasgy@0 864 bool emptyFeature = true;
fazekasgy@0 865 Feature feature;
fazekasgy@0 866
fazekasgy@0 867 //process::Python Sequence Iterator for dictionary
fazekasgy@0 868 while (PyDict_Next(pyDict, &pyPos, &pyKey, &pyValue))
fazekasgy@0 869 {
fazekasgy@0 870 emptyFeature = false;
fazekasgy@0 871 switch (ffKeys[PyString_AsString(pyKey)])
fazekasgy@0 872 {
fazekasgy@0 873 case not_found :
fazekasgy@0 874 cerr << "Unknown key in VAMP FeatureSet: "
fazekasgy@0 875 << PyString_AsString(pyKey) << endl;
fazekasgy@0 876 break;
fazekasgy@0 877 case hasTimestamp:
fazekasgy@0 878 feature.hasTimestamp = (bool) PyInt_AS_LONG(pyValue);
fazekasgy@0 879 break;
fazekasgy@0 880 case timeStamp:
fazekasgy@0 881 feature.timestamp = timestamp +
fazekasgy@0 882 Vamp::RealTime::frame2RealTime
fazekasgy@0 883 ((size_t)PyInt_AS_LONG(pyValue), (size_t)m_inputSampleRate);
fazekasgy@0 884 break;
fazekasgy@0 885 case values:
fazekasgy@0 886 feature.values = PyList_As_FloatVector(pyValue);
fazekasgy@0 887 break;
fazekasgy@0 888 case label:
fazekasgy@0 889 feature.label = PyString_AsString(pyValue);
fazekasgy@0 890 break;
fazekasgy@0 891 default :
fazekasgy@0 892 cerr << "Invalid key in VAMP FeatureSet: "
fazekasgy@0 893 << PyString_AsString(pyKey) << endl;
fazekasgy@0 894 } // switch
fazekasgy@0 895
fazekasgy@0 896 } // while
fazekasgy@0 897 if (emptyFeature) cerr << "Warning: This feature is empty or badly formatted." << endl;
fazekasgy@0 898 else returnFeatures[i].push_back(feature);
fazekasgy@0 899
fazekasgy@0 900 }// for j = FeatureList
fazekasgy@0 901
fazekasgy@0 902 }//for i = FeatureSet
fazekasgy@0 903 Py_CLEAR(pyOutputList);
fazekasgy@0 904 return returnFeatures;
fazekasgy@0 905
fazekasgy@0 906 }//if (has_attribute)
fazekasgy@0 907 return FeatureSet();
fazekasgy@0 908 }
fazekasgy@0 909
fazekasgy@0 910
fazekasgy@0 911
fazekasgy@0 912 PyPlugin::FeatureSet
fazekasgy@0 913 PyPlugin::getRemainingFeatures()
fazekasgy@0 914 {
cannam@3 915 MutexLocker locker(&m_pythonInterpreterMutex);
cannam@3 916
fazekasgy@0 917 static char method[]="getRemainingFeatures";
fazekasgy@0 918 cerr << "[call] " << method << endl;
fazekasgy@0 919
fazekasgy@0 920 //check if the method is implemented
fazekasgy@0 921 if ( ! PyObject_HasAttrString(m_pyInstance,method) ) {
fazekasgy@0 922 return FeatureSet();
fazekasgy@0 923 }
fazekasgy@0 924
fazekasgy@0 925 PyObject *pyMethod = PyString_FromString(method);
fazekasgy@0 926
fazekasgy@0 927 PyObject *pyOutputList =
fazekasgy@0 928 PyObject_CallMethod(m_pyInstance,method, NULL);
fazekasgy@0 929
fazekasgy@0 930 //Check return type
fazekasgy@0 931 if (pyOutputList == NULL || !PyList_Check(pyOutputList) ) {
fazekasgy@0 932 if (pyOutputList == NULL) {
fazekasgy@0 933 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 934 << "] Unexpected result." << endl;
fazekasgy@0 935 if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
fazekasgy@0 936 } else {
fazekasgy@0 937 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 938 << "] Expected List return type." << endl;
fazekasgy@0 939 }
fazekasgy@0 940 Py_CLEAR(pyMethod);
fazekasgy@0 941 Py_CLEAR(pyOutputList);
fazekasgy@0 942 return FeatureSet();
fazekasgy@0 943 }
fazekasgy@0 944 Py_DECREF(pyMethod);
fazekasgy@0 945
fazekasgy@0 946 PyObject *pyFeatureList, *pyDict, *pyKey, *pyValue;
fazekasgy@0 947 FeatureSet returnFeatures;
fazekasgy@0 948
fazekasgy@0 949 for (Py_ssize_t i = 0; i < PyList_GET_SIZE(pyOutputList); ++i) {
fazekasgy@0 950
fazekasgy@0 951 pyFeatureList = PyList_GET_ITEM(pyOutputList,i);
fazekasgy@0 952
fazekasgy@0 953 for (Py_ssize_t j = 0; j < PyList_GET_SIZE(pyFeatureList); ++j) {
fazekasgy@0 954
fazekasgy@0 955 pyDict = PyList_GET_ITEM(pyFeatureList,j);
fazekasgy@0 956
fazekasgy@0 957 if ( !PyDict_Check(pyDict) ) continue;
fazekasgy@0 958
fazekasgy@0 959 Py_ssize_t pyPos = NULL;
fazekasgy@0 960 bool emptyFeature = true;
fazekasgy@0 961 Feature feature;
fazekasgy@0 962
fazekasgy@0 963 while (PyDict_Next(pyDict, &pyPos, &pyKey, &pyValue))
fazekasgy@0 964 {
fazekasgy@0 965 emptyFeature = false;
fazekasgy@0 966 switch (ffKeys[PyString_AsString(pyKey)])
fazekasgy@0 967 {
fazekasgy@0 968 case not_found :
fazekasgy@0 969 cerr << "Unknown key in VAMP FeatureSet: "
fazekasgy@0 970 << PyString_AsString(pyKey) << endl;
fazekasgy@0 971 break;
fazekasgy@0 972 case hasTimestamp:
fazekasgy@0 973 feature.hasTimestamp = (bool) PyInt_AS_LONG(pyValue);
fazekasgy@0 974 break;
fazekasgy@0 975 // TODO: clarify what to do here
fazekasgy@0 976 case timeStamp:
fazekasgy@0 977 feature.timestamp =
fazekasgy@0 978 Vamp::RealTime::frame2RealTime
fazekasgy@0 979 ((size_t)PyInt_AS_LONG(pyValue), (size_t)m_inputSampleRate);
fazekasgy@0 980 break;
fazekasgy@0 981 case values:
fazekasgy@0 982 feature.values = PyList_As_FloatVector(pyValue);
fazekasgy@0 983 break;
fazekasgy@0 984 case label:
fazekasgy@0 985 feature.label = PyString_AsString(pyValue);
fazekasgy@0 986 break;
fazekasgy@0 987 } // switch
fazekasgy@0 988 } // while
fazekasgy@0 989 if (emptyFeature) cerr << "Warning: This feature is empty or badly formatted." << endl;
fazekasgy@0 990 else returnFeatures[i].push_back(feature);
fazekasgy@0 991 }// for j
fazekasgy@0 992 }//for i
fazekasgy@0 993 Py_CLEAR(pyOutputList);
fazekasgy@0 994 return returnFeatures;
fazekasgy@0 995 }
fazekasgy@0 996