annotate PyPlugin.cpp @ 0:e20e214bdfb5

Added VAMP-Python binding project vampy
author fazekasgy
date Tue, 11 Mar 2008 19:47:34 +0000
parents
children 134313c59d82
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
fazekasgy@0 51 //#include "Python.h"
fazekasgy@0 52 #include "/usr/include/python/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@0 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 extern volatile bool mutex;
fazekasgy@0 70
fazekasgy@0 71 // Maps to associate strings with enum values
fazekasgy@0 72 static std::map<std::string, eOutDescriptors> outKeys;
fazekasgy@0 73 static std::map<std::string, eSampleTypes> sampleKeys;
fazekasgy@0 74 static std::map<std::string, eFeatureFields> ffKeys;
fazekasgy@0 75 static std::map<std::string, p::eParmDescriptors> parmKeys;
fazekasgy@0 76
fazekasgy@0 77 void initMaps()
fazekasgy@0 78 {
fazekasgy@0 79 outKeys["identifier"] = identifier;
fazekasgy@0 80 outKeys["name"] = name;
fazekasgy@0 81 outKeys["description"] = description;
fazekasgy@0 82 outKeys["unit"] = unit;
fazekasgy@0 83 outKeys["hasFixedBinCount"] = hasFixedBinCount;
fazekasgy@0 84 outKeys["binCount"] = binCount;
fazekasgy@0 85 outKeys["binNames"] = binNames;
fazekasgy@0 86 outKeys["hasKnownExtents"] = hasKnownExtents;
fazekasgy@0 87 outKeys["minValue"] = minValue;
fazekasgy@0 88 outKeys["maxValue"] = maxValue;
fazekasgy@0 89 outKeys["isQuantized"] = isQuantized;
fazekasgy@0 90 outKeys["quantizeStep"] = quantizeStep;
fazekasgy@0 91 outKeys["sampleType"] = sampleType;
fazekasgy@0 92 outKeys["sampleRate"] = sampleRate;
fazekasgy@0 93
fazekasgy@0 94 sampleKeys["OneSamplePerStep"] = OneSamplePerStep;
fazekasgy@0 95 sampleKeys["FixedSampleRate"] = FixedSampleRate;
fazekasgy@0 96 sampleKeys["VariableSampleRate"] = VariableSampleRate;
fazekasgy@0 97
fazekasgy@0 98 ffKeys["hasTimestamp"] = hasTimestamp;
fazekasgy@0 99 ffKeys["timeStamp"] = timeStamp;
fazekasgy@0 100 ffKeys["values"] = values;
fazekasgy@0 101 ffKeys["label"] = label;
fazekasgy@0 102
fazekasgy@0 103 parmKeys["identifier"] = p::identifier;
fazekasgy@0 104 parmKeys["name"] = p::name;
fazekasgy@0 105 parmKeys["description"] = p::description;
fazekasgy@0 106 parmKeys["unit"] = p::unit;
fazekasgy@0 107 parmKeys["minValue"] = p::minValue;
fazekasgy@0 108 parmKeys["maxValue"] = p::maxValue;
fazekasgy@0 109 parmKeys["defaultValue"] = p::defaultValue;
fazekasgy@0 110 parmKeys["isQuantized"] = p::isQuantized;
fazekasgy@0 111
fazekasgy@0 112 }
fazekasgy@0 113
fazekasgy@0 114
fazekasgy@0 115 //missing API helper: convert Python list to C++ vector of strings
fazekasgy@0 116 //TODO: these could be templates if we need more of this kind
fazekasgy@0 117 std::vector<std::string> PyList_To_StringVector (PyObject *inputList) {
fazekasgy@0 118
fazekasgy@0 119 std::vector<std::string> Output;
fazekasgy@0 120 std::string ListElement;
fazekasgy@0 121 PyObject *pyString = NULL;
fazekasgy@0 122
fazekasgy@0 123 if (!PyList_Check(inputList)) return Output;
fazekasgy@0 124
fazekasgy@0 125 for (Py_ssize_t i = 0; i < PyList_GET_SIZE(inputList); ++i) {
fazekasgy@0 126 //Get next list item (Borrowed Reference)
fazekasgy@0 127 pyString = PyList_GET_ITEM(inputList,i);
fazekasgy@0 128 ListElement = (string) PyString_AsString(PyObject_Str(pyString));
fazekasgy@0 129 Output.push_back(ListElement);
fazekasgy@0 130 }
fazekasgy@0 131 return Output;
fazekasgy@0 132 }
fazekasgy@0 133
fazekasgy@0 134 //missing API helper: convert Python list to C++ vector of floats
fazekasgy@0 135 std::vector<float> PyList_As_FloatVector (PyObject *inputList) {
fazekasgy@0 136
fazekasgy@0 137 std::vector<float> Output;
fazekasgy@0 138 float ListElement;
fazekasgy@0 139 PyObject *pyFloat = NULL;
fazekasgy@0 140
fazekasgy@0 141 if (!PyList_Check(inputList)) return Output;
fazekasgy@0 142
fazekasgy@0 143 for (Py_ssize_t k = 0; k < PyList_GET_SIZE(inputList); ++k) {
fazekasgy@0 144 //Get next list item (Borrowed Reference)
fazekasgy@0 145 pyFloat = PyList_GET_ITEM(inputList,k);
fazekasgy@0 146 ListElement = (float) PyFloat_AS_DOUBLE(pyFloat);
fazekasgy@0 147 Output.push_back(ListElement);
fazekasgy@0 148 }
fazekasgy@0 149
fazekasgy@0 150 return Output;
fazekasgy@0 151 }
fazekasgy@0 152
fazekasgy@0 153 /* TODO: find out why this produces error, also
fazekasgy@0 154 do sg more clever about handling RealTime
fazekasgy@0 155 Vamp::RealTime
fazekasgy@0 156 PyFrame_As_RealTime (PyObject *frameNo,size_t inputSampleRate) {
fazekasgy@0 157 Vamp::RealTime result =
fazekasgy@0 158 Vamp::RealTime::frame2RealTime((size_t)PyInt_AS_LONG(frameNo), inputSampleRate);
fazekasgy@0 159 return result;
fazekasgy@0 160 }
fazekasgy@0 161 */
fazekasgy@0 162
fazekasgy@0 163
fazekasgy@0 164 PyPlugin::PyPlugin(std::string pluginKey,float inputSampleRate, PyObject *pyInstance) :
fazekasgy@0 165 Plugin(inputSampleRate),
fazekasgy@0 166 m_pyInstance(pyInstance),
fazekasgy@0 167 m_stepSize(0),
fazekasgy@0 168 m_previousSample(0.0f),
fazekasgy@0 169 m_plugin(pluginKey),
fazekasgy@0 170 m_class(pluginKey.substr(pluginKey.rfind(':')+1,pluginKey.size()-1)),
fazekasgy@0 171 m_path((pluginKey.substr(0,pluginKey.rfind(pathsep))))
fazekasgy@0 172 {
fazekasgy@0 173
fazekasgy@0 174 /*TODO: this is a nasty way of ensuring the process is
fazekasgy@0 175 finished before we create a new instance accessing the Python/C API.
fazekasgy@0 176 The Python/C API is not fully thread safe.
fazekasgy@0 177 Calling into a python class while the process is doing heavy
fazekasgy@0 178 computation may cause segmentation fault.
fazekasgy@0 179 Manipulating the GIL and thread states only gave me a grief so far.*/
fazekasgy@0 180
fazekasgy@0 181 if (mutex) {
fazekasgy@0 182 cerr << "PyPlugin::PyPlugin:" << m_class
fazekasgy@0 183 << " Warning: Waiting for clear signal from parallel process." << endl;
fazekasgy@0 184 while (mutex) { }
fazekasgy@0 185 }
fazekasgy@0 186 }
fazekasgy@0 187
fazekasgy@0 188 PyPlugin::~PyPlugin()
fazekasgy@0 189 {
fazekasgy@0 190 cerr << "PyPlugin::PyPlugin:" << m_class
fazekasgy@0 191 << " Instance deleted." << endl;
fazekasgy@0 192 //for safety only. has been cleared after process.
fazekasgy@0 193 mutex = false;
fazekasgy@0 194 }
fazekasgy@0 195
fazekasgy@0 196
fazekasgy@0 197 string
fazekasgy@0 198 PyPlugin::getIdentifier() const
fazekasgy@0 199 {
fazekasgy@0 200 char method[]="getIdentifier";
fazekasgy@0 201 cerr << "[call] " << method << endl;
fazekasgy@0 202 string rString="VampPy-x";
fazekasgy@0 203
fazekasgy@0 204 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
fazekasgy@0 205
fazekasgy@0 206 //Call the method
fazekasgy@0 207 PyObject *pyString =
fazekasgy@0 208 PyObject_CallMethod(m_pyInstance, method, NULL);
fazekasgy@0 209
fazekasgy@0 210 //Check return value
fazekasgy@0 211 if (!PyString_Check(pyString)) {
fazekasgy@0 212 Py_CLEAR(pyString);
fazekasgy@0 213 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 214 << "] Expected String return value." << endl;
fazekasgy@0 215 return rString;
fazekasgy@0 216 }
fazekasgy@0 217
fazekasgy@0 218 rString=PyString_AsString(pyString);
fazekasgy@0 219 Py_CLEAR(pyString);
fazekasgy@0 220 }
fazekasgy@0 221 cerr << "Warning: Plugin must return a unique identifier." << endl;
fazekasgy@0 222 return rString;
fazekasgy@0 223 }
fazekasgy@0 224
fazekasgy@0 225
fazekasgy@0 226 string
fazekasgy@0 227 PyPlugin::getName() const
fazekasgy@0 228 {
fazekasgy@0 229
fazekasgy@0 230 char method[]="getName";
fazekasgy@0 231 cerr << "[call] " << method << endl;
fazekasgy@0 232 string rString="VamPy Plugin (Noname)";
fazekasgy@0 233
fazekasgy@0 234 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
fazekasgy@0 235
fazekasgy@0 236 //Call the method
fazekasgy@0 237 PyObject *pyString =
fazekasgy@0 238 PyObject_CallMethod(m_pyInstance, method, NULL);
fazekasgy@0 239
fazekasgy@0 240 //Check return value
fazekasgy@0 241 if (!PyString_Check(pyString)) {
fazekasgy@0 242 Py_CLEAR(pyString);
fazekasgy@0 243 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 244 << "] Expected String return value." << endl;
fazekasgy@0 245 return rString;
fazekasgy@0 246 }
fazekasgy@0 247
fazekasgy@0 248 rString=PyString_AsString(pyString);
fazekasgy@0 249 Py_CLEAR(pyString);
fazekasgy@0 250 }
fazekasgy@0 251 return rString;
fazekasgy@0 252 }
fazekasgy@0 253
fazekasgy@0 254 string
fazekasgy@0 255 PyPlugin::getDescription() const
fazekasgy@0 256 {
fazekasgy@0 257 char method[]="getDescription";
fazekasgy@0 258 cerr << "[call] " << method << endl;
fazekasgy@0 259 string rString="Not given. (Hint: Implement getDescription method.)";
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 rString=PyString_AsString(pyString);
fazekasgy@0 276 Py_CLEAR(pyString);
fazekasgy@0 277 }
fazekasgy@0 278 return rString;
fazekasgy@0 279 }
fazekasgy@0 280
fazekasgy@0 281 string
fazekasgy@0 282 PyPlugin::getMaker() const
fazekasgy@0 283 {
fazekasgy@0 284 char method[]="getMaker";
fazekasgy@0 285 cerr << "[call] " << method << endl;
fazekasgy@0 286 string rString="Generic VamPy Plugin.";
fazekasgy@0 287
fazekasgy@0 288 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
fazekasgy@0 289
fazekasgy@0 290 //Call the method
fazekasgy@0 291 PyObject *pyString =
fazekasgy@0 292 PyObject_CallMethod(m_pyInstance, method, NULL);
fazekasgy@0 293
fazekasgy@0 294 //Check return value
fazekasgy@0 295 if (!PyString_Check(pyString)) {
fazekasgy@0 296 Py_CLEAR(pyString);
fazekasgy@0 297 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 298 << "] Expected String return value." << endl;
fazekasgy@0 299 return rString;
fazekasgy@0 300 }
fazekasgy@0 301
fazekasgy@0 302 rString=PyString_AsString(pyString);
fazekasgy@0 303 Py_CLEAR(pyString);
fazekasgy@0 304 }
fazekasgy@0 305 return rString;
fazekasgy@0 306 }
fazekasgy@0 307
fazekasgy@0 308 int
fazekasgy@0 309 PyPlugin::getPluginVersion() const
fazekasgy@0 310 {
fazekasgy@0 311 return 2;
fazekasgy@0 312 }
fazekasgy@0 313
fazekasgy@0 314 string
fazekasgy@0 315 PyPlugin::getCopyright() const
fazekasgy@0 316 {
fazekasgy@0 317 char method[]="getCopyright";
fazekasgy@0 318 cerr << "[call] " << method << endl;
fazekasgy@0 319 string rString="BSD License";
fazekasgy@0 320
fazekasgy@0 321 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
fazekasgy@0 322
fazekasgy@0 323 //Call the method
fazekasgy@0 324 PyObject *pyString =
fazekasgy@0 325 PyObject_CallMethod(m_pyInstance, method, NULL);
fazekasgy@0 326
fazekasgy@0 327 //Check return value
fazekasgy@0 328 if (!PyString_Check(pyString)) {
fazekasgy@0 329 Py_CLEAR(pyString);
fazekasgy@0 330 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 331 << "] Expected String return value." << endl;
fazekasgy@0 332 return rString;
fazekasgy@0 333 }
fazekasgy@0 334
fazekasgy@0 335
fazekasgy@0 336 rString=PyString_AsString(pyString);
fazekasgy@0 337 Py_CLEAR(pyString);
fazekasgy@0 338 }
fazekasgy@0 339 return rString;
fazekasgy@0 340 }
fazekasgy@0 341
fazekasgy@0 342
fazekasgy@0 343 bool
fazekasgy@0 344 PyPlugin::initialise(size_t channels, size_t stepSize, size_t blockSize)
fazekasgy@0 345 {
fazekasgy@0 346 if (channels < getMinChannelCount() ||
fazekasgy@0 347 channels > getMaxChannelCount()) return false;
fazekasgy@0 348
fazekasgy@0 349 m_stepSize = std::min(stepSize, blockSize);
fazekasgy@0 350 char method[]="initialise";
fazekasgy@0 351 cerr << "[call] " << method << endl;
fazekasgy@0 352
fazekasgy@0 353 //Check if the method is implemented in Python else return false
fazekasgy@0 354 if (PyObject_HasAttrString(m_pyInstance,method)) {
fazekasgy@0 355
fazekasgy@0 356 PyObject *pyMethod = PyString_FromString(method);
fazekasgy@0 357 PyObject *pyChannels = PyInt_FromSsize_t((Py_ssize_t)channels);
fazekasgy@0 358 PyObject *pyStepSize = PyInt_FromSsize_t((Py_ssize_t)m_stepSize);
fazekasgy@0 359 PyObject *pyBlockSize = PyInt_FromSsize_t((Py_ssize_t)blockSize);
fazekasgy@0 360 PyObject *pyInputSampleRate = PyFloat_FromDouble((double)m_inputSampleRate);
fazekasgy@0 361
fazekasgy@0 362 //Call the method
fazekasgy@0 363 PyObject *pyBool =
fazekasgy@0 364 PyObject_CallMethodObjArgs(m_pyInstance,pyMethod,pyChannels,pyStepSize,pyBlockSize,pyInputSampleRate,NULL);
fazekasgy@0 365
fazekasgy@0 366 Py_DECREF(pyMethod);
fazekasgy@0 367 Py_DECREF(pyChannels);
fazekasgy@0 368 Py_DECREF(pyStepSize);
fazekasgy@0 369 Py_DECREF(pyBlockSize);
fazekasgy@0 370 Py_DECREF(pyInputSampleRate);
fazekasgy@0 371
fazekasgy@0 372 //Check return value
fazekasgy@0 373 if (!PyBool_Check(pyBool)) {
fazekasgy@0 374 Py_CLEAR(pyBool);
fazekasgy@0 375 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 376 << "] Expected Bool return value." << endl;
fazekasgy@0 377 return false;
fazekasgy@0 378 }
fazekasgy@0 379
fazekasgy@0 380 if (pyBool == Py_True) {
fazekasgy@0 381 Py_CLEAR(pyBool);
fazekasgy@0 382 return true;
fazekasgy@0 383 } else {
fazekasgy@0 384 Py_CLEAR(pyBool);
fazekasgy@0 385 return false;}
fazekasgy@0 386 }
fazekasgy@0 387 return true;
fazekasgy@0 388 }
fazekasgy@0 389
fazekasgy@0 390 void
fazekasgy@0 391 PyPlugin::reset()
fazekasgy@0 392 {
fazekasgy@0 393 m_previousSample = 0.0f;
fazekasgy@0 394 }
fazekasgy@0 395
fazekasgy@0 396 PyPlugin::InputDomain PyPlugin::getInputDomain() const
fazekasgy@0 397 {
fazekasgy@0 398 char method[]="getInputDomain";
fazekasgy@0 399 cerr << "[call] " << method << endl;
fazekasgy@0 400 PyPlugin::InputDomain rValue = TimeDomain; // TimeDomain
fazekasgy@0 401
fazekasgy@0 402 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
fazekasgy@0 403
fazekasgy@0 404 PyObject *pyString = PyObject_CallMethod(m_pyInstance, method, NULL);
fazekasgy@0 405
fazekasgy@0 406 //Check return value
fazekasgy@0 407 if (!PyString_Check(pyString)) {
fazekasgy@0 408 Py_CLEAR(pyString);
fazekasgy@0 409 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 410 << "] Expected String return value." << endl;
fazekasgy@0 411 return rValue;
fazekasgy@0 412 }
fazekasgy@0 413
fazekasgy@0 414 string domain = (string) PyString_AsString(pyString);
fazekasgy@0 415 if (domain == "FrequencyDomain") rValue = FrequencyDomain;
fazekasgy@0 416 Py_CLEAR(pyString);
fazekasgy@0 417 }
fazekasgy@0 418 return rValue;
fazekasgy@0 419 }
fazekasgy@0 420
fazekasgy@0 421 size_t PyPlugin::getPreferredBlockSize() const
fazekasgy@0 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 {
fazekasgy@0 446 char method[]="getPreferredStepSize";
fazekasgy@0 447 cerr << "[call] " << method << endl;
fazekasgy@0 448 size_t rValue=0; //not set by default
fazekasgy@0 449 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
fazekasgy@0 450 PyObject *pyInt = PyObject_CallMethod(m_pyInstance, method, NULL);
fazekasgy@0 451
fazekasgy@0 452 //Check return value
fazekasgy@0 453 if (!PyInt_Check(pyInt)) {
fazekasgy@0 454 Py_CLEAR(pyInt);
fazekasgy@0 455 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 456 << "] Expected Integer return value." << endl;
fazekasgy@0 457 return rValue;
fazekasgy@0 458 }
fazekasgy@0 459
fazekasgy@0 460 rValue=(size_t)PyInt_AS_LONG(pyInt);
fazekasgy@0 461 Py_CLEAR(pyInt);
fazekasgy@0 462 }
fazekasgy@0 463 return rValue;
fazekasgy@0 464 }
fazekasgy@0 465
fazekasgy@0 466 size_t PyPlugin::getMinChannelCount() const
fazekasgy@0 467 {
fazekasgy@0 468 char method[]="getMinChannelCount";
fazekasgy@0 469 cerr << "[call] " << method << endl;
fazekasgy@0 470 size_t rValue=1; //default value
fazekasgy@0 471 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
fazekasgy@0 472 PyObject *pyInt = PyObject_CallMethod(m_pyInstance, method, NULL);
fazekasgy@0 473
fazekasgy@0 474 //Check return value
fazekasgy@0 475 if (!PyInt_Check(pyInt)) {
fazekasgy@0 476 Py_CLEAR(pyInt);
fazekasgy@0 477 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 478 << "] Expected String return value." << endl;
fazekasgy@0 479 return rValue;
fazekasgy@0 480 }
fazekasgy@0 481
fazekasgy@0 482 rValue=(size_t)PyInt_AS_LONG(pyInt);
fazekasgy@0 483 Py_CLEAR(pyInt);
fazekasgy@0 484 }
fazekasgy@0 485 return rValue;
fazekasgy@0 486 }
fazekasgy@0 487
fazekasgy@0 488 size_t PyPlugin::getMaxChannelCount() const
fazekasgy@0 489 {
fazekasgy@0 490 char method[]="getMaxChannelCount";
fazekasgy@0 491 cerr << "[call] " << method << endl;
fazekasgy@0 492 size_t rValue=1; //default value
fazekasgy@0 493 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
fazekasgy@0 494 PyObject *pyInt = PyObject_CallMethod(m_pyInstance, method, NULL);
fazekasgy@0 495
fazekasgy@0 496 //Check return value
fazekasgy@0 497 if (!PyInt_Check(pyInt)) {
fazekasgy@0 498 Py_CLEAR(pyInt);
fazekasgy@0 499 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 500 << "] Expected String return value." << endl;
fazekasgy@0 501 return rValue;
fazekasgy@0 502 }
fazekasgy@0 503
fazekasgy@0 504 rValue=(size_t)PyInt_AS_LONG(pyInt);
fazekasgy@0 505 Py_CLEAR(pyInt);
fazekasgy@0 506 }
fazekasgy@0 507 return rValue;
fazekasgy@0 508 }
fazekasgy@0 509
fazekasgy@0 510
fazekasgy@0 511 PyPlugin::OutputList
fazekasgy@0 512 PyPlugin::getOutputDescriptors() const
fazekasgy@0 513 {
fazekasgy@0 514 //PyEval_AcquireThread(newThreadState);
fazekasgy@0 515 OutputList list;
fazekasgy@0 516 OutputDescriptor od;
fazekasgy@0 517 char method[]="getOutputDescriptors";
fazekasgy@0 518 cerr << "[call] " << method << endl;
fazekasgy@0 519
fazekasgy@0 520 //Check if the method is implemented in Python
fazekasgy@0 521 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
fazekasgy@0 522
fazekasgy@0 523 //Call the method: must return list object (new reference)
fazekasgy@0 524 PyObject *pyList =
fazekasgy@0 525 PyObject_CallMethod(m_pyInstance,method, NULL);
fazekasgy@0 526
fazekasgy@0 527 //Check return type
fazekasgy@0 528 if (! PyList_Check(pyList) ) {
fazekasgy@0 529 Py_CLEAR(pyList);
fazekasgy@0 530 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 531 << "] Expected List return type." << endl;
fazekasgy@0 532 return list;
fazekasgy@0 533 }
fazekasgy@0 534
fazekasgy@0 535 //These will all be borrowed references (no need to DECREF)
fazekasgy@0 536 PyObject *pyDict, *pyKey, *pyValue;
fazekasgy@0 537
fazekasgy@0 538 //Parse Output List
fazekasgy@0 539 for (Py_ssize_t i = 0; i < PyList_GET_SIZE(pyList); ++i) {
fazekasgy@0 540
fazekasgy@0 541 //Get i-th VAMP output descriptor (Borrowed Reference)
fazekasgy@0 542 pyDict = PyList_GET_ITEM(pyList,i);
fazekasgy@0 543
fazekasgy@0 544 //We only care about dictionaries holding output descriptors
fazekasgy@0 545 if ( !PyDict_Check(pyDict) ) continue;
fazekasgy@0 546
fazekasgy@0 547 Py_ssize_t pyPos = NULL;
fazekasgy@0 548 initMaps();
fazekasgy@0 549
fazekasgy@0 550 //Python Sequence Iterator
fazekasgy@0 551 while (PyDict_Next(pyDict, &pyPos, &pyKey, &pyValue))
fazekasgy@0 552 {
fazekasgy@0 553 switch (outKeys[PyString_AsString(pyKey)])
fazekasgy@0 554 {
fazekasgy@0 555 case not_found :
fazekasgy@0 556 cerr << "Unknown key in VAMP OutputDescriptor: " << PyString_AsString(pyKey) << endl;
fazekasgy@0 557 break;
fazekasgy@0 558 case identifier:
fazekasgy@0 559 od.identifier = PyString_AsString(pyValue);
fazekasgy@0 560 break;
fazekasgy@0 561 case name:
fazekasgy@0 562 od.name = PyString_AsString(pyValue);
fazekasgy@0 563 break;
fazekasgy@0 564 case description:
fazekasgy@0 565 od.description = PyString_AsString(pyValue);
fazekasgy@0 566 break;
fazekasgy@0 567 case unit:
fazekasgy@0 568 od.unit = PyString_AsString(pyValue);
fazekasgy@0 569 break;
fazekasgy@0 570 case hasFixedBinCount:
fazekasgy@0 571 od.hasFixedBinCount = (bool) PyInt_AS_LONG(pyValue);
fazekasgy@0 572 break;
fazekasgy@0 573 case binCount:
fazekasgy@0 574 od.binCount = (size_t) PyInt_AS_LONG(pyValue);
fazekasgy@0 575 break;
fazekasgy@0 576 case binNames:
fazekasgy@0 577 od.binNames = PyList_To_StringVector(pyValue);
fazekasgy@0 578 break;
fazekasgy@0 579 case hasKnownExtents:
fazekasgy@0 580 od.hasKnownExtents = (bool) PyInt_AS_LONG(pyValue);
fazekasgy@0 581 break;
fazekasgy@0 582 case minValue:
fazekasgy@0 583 od.minValue = (float) PyFloat_AS_DOUBLE(pyValue);
fazekasgy@0 584 break;
fazekasgy@0 585 case maxValue:
fazekasgy@0 586 od.maxValue = (float) PyFloat_AS_DOUBLE(pyValue);
fazekasgy@0 587 break;
fazekasgy@0 588 case isQuantized:
fazekasgy@0 589 od.isQuantized = (bool) PyInt_AS_LONG(pyValue);
fazekasgy@0 590 break;
fazekasgy@0 591 case quantizeStep:
fazekasgy@0 592 od.quantizeStep = (float) PyFloat_AS_DOUBLE(pyValue);
fazekasgy@0 593 break;
fazekasgy@0 594 case sampleType:
fazekasgy@0 595 od.sampleType = (OutputDescriptor::SampleType) sampleKeys[PyString_AsString(pyValue)];
fazekasgy@0 596 break;
fazekasgy@0 597 case sampleRate:
fazekasgy@0 598 od.sampleRate = (float) PyFloat_AS_DOUBLE(pyValue);
fazekasgy@0 599 break;
fazekasgy@0 600 default :
fazekasgy@0 601 cerr << "Invalid key in VAMP OutputDescriptor: " << PyString_AsString(pyKey) << endl;
fazekasgy@0 602 } // switch
fazekasgy@0 603 } // while dict keys
fazekasgy@0 604 list.push_back(od);
fazekasgy@0 605 } // for each memeber in outputlist
fazekasgy@0 606 Py_CLEAR(pyList);
fazekasgy@0 607 } // if method is implemented
fazekasgy@0 608 //PyEval_ReleaseThread(newThreadState);
fazekasgy@0 609 return list;
fazekasgy@0 610 }
fazekasgy@0 611
fazekasgy@0 612 PyPlugin::ParameterList
fazekasgy@0 613 PyPlugin::getParameterDescriptors() const
fazekasgy@0 614 {
fazekasgy@0 615 ParameterList list;
fazekasgy@0 616 ParameterDescriptor pd;
fazekasgy@0 617 char method[]="getParameterDescriptors";
fazekasgy@0 618 cerr << "[call] " << method << endl;
fazekasgy@0 619
fazekasgy@0 620 //Check if the method is implemented in Python
fazekasgy@0 621 if ( PyObject_HasAttrString(m_pyInstance,method) ) {
fazekasgy@0 622
fazekasgy@0 623 //Call the method: must return list object (new reference)
fazekasgy@0 624 PyObject *pyList =
fazekasgy@0 625 PyObject_CallMethod(m_pyInstance,method, NULL);
fazekasgy@0 626
fazekasgy@0 627 //Check return type
fazekasgy@0 628 if (! PyList_Check(pyList) ) {
fazekasgy@0 629 Py_CLEAR(pyList);
fazekasgy@0 630 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 631 << "] Expected List return type." << endl;
fazekasgy@0 632 return list;
fazekasgy@0 633 }
fazekasgy@0 634
fazekasgy@0 635
fazekasgy@0 636 //These will all be borrowed references (no need to DECREF)
fazekasgy@0 637 PyObject *pyDict, *pyKey, *pyValue;
fazekasgy@0 638
fazekasgy@0 639 //Parse Output List
fazekasgy@0 640 for (Py_ssize_t i = 0; i < PyList_GET_SIZE(pyList); ++i) {
fazekasgy@0 641
fazekasgy@0 642 //Get i-th VAMP output descriptor (Borrowed Reference)
fazekasgy@0 643 pyDict = PyList_GET_ITEM(pyList,i);
fazekasgy@0 644
fazekasgy@0 645 //We only care about dictionaries holding output descriptors
fazekasgy@0 646 if ( !PyDict_Check(pyDict) ) continue;
fazekasgy@0 647
fazekasgy@0 648 Py_ssize_t pyPos = NULL;
fazekasgy@0 649 initMaps();
fazekasgy@0 650
fazekasgy@0 651 //Python Sequence Iterator
fazekasgy@0 652 while (PyDict_Next(pyDict, &pyPos, &pyKey, &pyValue))
fazekasgy@0 653 {
fazekasgy@0 654 switch (parmKeys[PyString_AsString(pyKey)])
fazekasgy@0 655 {
fazekasgy@0 656 case not_found :
fazekasgy@0 657 cerr << "Unknown key in VAMP OutputDescriptor: " << PyString_AsString(pyKey) << endl;
fazekasgy@0 658 break;
fazekasgy@0 659 case p::identifier:
fazekasgy@0 660 pd.identifier = PyString_AsString(pyValue);
fazekasgy@0 661 break;
fazekasgy@0 662 case p::name:
fazekasgy@0 663 pd.name = PyString_AsString(pyValue);
fazekasgy@0 664 break;
fazekasgy@0 665 case p::description:
fazekasgy@0 666 pd.description = PyString_AsString(pyValue);
fazekasgy@0 667 break;
fazekasgy@0 668 case p::unit:
fazekasgy@0 669 pd.unit = PyString_AsString(pyValue);
fazekasgy@0 670 break;
fazekasgy@0 671 case p::minValue:
fazekasgy@0 672 pd.minValue = (float) PyFloat_AS_DOUBLE(pyValue);
fazekasgy@0 673 break;
fazekasgy@0 674 case p::maxValue:
fazekasgy@0 675 pd.maxValue = (float) PyFloat_AS_DOUBLE(pyValue);
fazekasgy@0 676 break;
fazekasgy@0 677 case p::defaultValue:
fazekasgy@0 678 pd.defaultValue = (float) PyFloat_AS_DOUBLE(pyValue);
fazekasgy@0 679 break;
fazekasgy@0 680 case p::isQuantized:
fazekasgy@0 681 pd.isQuantized = (bool) PyInt_AS_LONG(pyValue);
fazekasgy@0 682 break;
fazekasgy@0 683 default :
fazekasgy@0 684 cerr << "Invalid key in VAMP OutputDescriptor: " << PyString_AsString(pyKey) << endl;
fazekasgy@0 685 } // switch
fazekasgy@0 686 } // while dict keys
fazekasgy@0 687 list.push_back(pd);
fazekasgy@0 688 } // for each memeber in outputlist
fazekasgy@0 689 Py_CLEAR(pyList);
fazekasgy@0 690 } // if
fazekasgy@0 691 return list;
fazekasgy@0 692 }
fazekasgy@0 693
fazekasgy@0 694 void PyPlugin::setParameter(std::string paramid, float newval)
fazekasgy@0 695 {
fazekasgy@0 696 char method[]="setParameter";
fazekasgy@0 697 cerr << "[call] " << method << endl;
fazekasgy@0 698
fazekasgy@0 699 //Check if the method is implemented in Python
fazekasgy@0 700 if (PyObject_HasAttrString(m_pyInstance,method)) {
fazekasgy@0 701
fazekasgy@0 702 PyObject *pyMethod = PyString_FromString(method);
fazekasgy@0 703 PyObject *pyParamid = PyString_FromString(paramid.c_str());
fazekasgy@0 704 PyObject *pyNewval = PyFloat_FromDouble((double)newval);
fazekasgy@0 705
fazekasgy@0 706 //Call the method
fazekasgy@0 707 PyObject *pyBool =
fazekasgy@0 708 PyObject_CallMethodObjArgs(m_pyInstance,pyMethod,pyParamid,pyNewval,NULL);
fazekasgy@0 709
fazekasgy@0 710 //This only happens if there is a syntax error or so
fazekasgy@0 711 if (pyBool == NULL) {
fazekasgy@0 712 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 713 << "] Error setting parameter: " << paramid << endl;
fazekasgy@0 714 if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
fazekasgy@0 715 }
fazekasgy@0 716
fazekasgy@0 717 Py_DECREF(pyMethod);
fazekasgy@0 718 Py_DECREF(pyParamid);
fazekasgy@0 719 Py_DECREF(pyNewval);
fazekasgy@0 720 }
fazekasgy@0 721 }
fazekasgy@0 722
fazekasgy@0 723 float PyPlugin::getParameter(std::string paramid) const
fazekasgy@0 724 {
fazekasgy@0 725 char method[]="getParameter";
fazekasgy@0 726 cerr << "[call] " << method << endl;
fazekasgy@0 727 float rValue = 0.0f;
fazekasgy@0 728
fazekasgy@0 729 //Check if the method is implemented in Python
fazekasgy@0 730 if (PyObject_HasAttrString(m_pyInstance,method)) {
fazekasgy@0 731
fazekasgy@0 732 PyObject *pyMethod = PyString_FromString(method);
fazekasgy@0 733 PyObject *pyParamid = PyString_FromString(paramid.c_str());
fazekasgy@0 734
fazekasgy@0 735 //Call the method
fazekasgy@0 736 PyObject *pyFloat =
fazekasgy@0 737 PyObject_CallMethodObjArgs(m_pyInstance,pyMethod,pyParamid,NULL);
fazekasgy@0 738
fazekasgy@0 739 //Check return type
fazekasgy@0 740 if (! PyFloat_Check(pyFloat) ) {
fazekasgy@0 741 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 742 << "] Expected Float return type." << endl;
fazekasgy@0 743 if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
fazekasgy@0 744 Py_CLEAR(pyFloat);
fazekasgy@0 745 return rValue;
fazekasgy@0 746 }
fazekasgy@0 747
fazekasgy@0 748 rValue = (float) PyFloat_AS_DOUBLE(pyFloat);
fazekasgy@0 749
fazekasgy@0 750 Py_DECREF(pyMethod);
fazekasgy@0 751 Py_DECREF(pyParamid);
fazekasgy@0 752 Py_DECREF(pyFloat);
fazekasgy@0 753 }
fazekasgy@0 754
fazekasgy@0 755 return rValue;
fazekasgy@0 756 }
fazekasgy@0 757
fazekasgy@0 758 #ifdef _DEBUG
fazekasgy@0 759 static int proccounter = 0;
fazekasgy@0 760 #endif
fazekasgy@0 761
fazekasgy@0 762 PyPlugin::FeatureSet
fazekasgy@0 763 PyPlugin::process(const float *const *inputBuffers,
fazekasgy@0 764 Vamp::RealTime timestamp)
fazekasgy@0 765 {
fazekasgy@0 766 if (m_stepSize == 0) {
fazekasgy@0 767 cerr << "ERROR: PyPlugin::process: "
fazekasgy@0 768 << "Plugin has not been initialised" << endl;
fazekasgy@0 769 return FeatureSet();
fazekasgy@0 770 }
fazekasgy@0 771 mutex = true;
fazekasgy@0 772 static char method[]="process";
fazekasgy@0 773
fazekasgy@0 774 #ifdef _DEBUG
fazekasgy@0 775 cerr << "[call] " << method << " frame:" << proccounter << endl;
fazekasgy@0 776 proccounter++;
fazekasgy@0 777 //cerr << "C: proc..." << proccounter << " " << endl;
fazekasgy@0 778 #endif
fazekasgy@0 779
fazekasgy@0 780 //proces::Check if the method is implemented in Python
fazekasgy@0 781 if ( PyObject_HasAttrString(m_pyInstance,method) )
fazekasgy@0 782 {
fazekasgy@0 783
fazekasgy@0 784 //Pack method name into Python Object
fazekasgy@0 785 PyObject *pyMethod = PyString_FromString(method);
fazekasgy@0 786
fazekasgy@0 787 //Declare new list object
fazekasgy@0 788 PyObject *pyFloat, *pyList;
fazekasgy@0 789 pyList = PyList_New((Py_ssize_t) m_stepSize);
fazekasgy@0 790
fazekasgy@0 791 //Pack samples into a Python List Object
fazekasgy@0 792 //pyFloat will always be new references,
fazekasgy@0 793 //these will be discarded when the list is deallocated
fazekasgy@0 794 for (size_t i = 0; i < m_stepSize; ++i) {
fazekasgy@0 795 pyFloat=PyFloat_FromDouble((double) inputBuffers[0][i]);
fazekasgy@0 796 PyList_SET_ITEM(pyList, (Py_ssize_t) i, pyFloat);
fazekasgy@0 797 }
fazekasgy@0 798
fazekasgy@0 799 //Call python process (returns new reference)
fazekasgy@0 800 PyObject *pyOutputList =
fazekasgy@0 801 PyObject_CallMethodObjArgs(m_pyInstance,pyMethod,pyList,NULL);
fazekasgy@0 802
fazekasgy@0 803 //Check return type
fazekasgy@0 804 if (pyOutputList == NULL || !PyList_Check(pyOutputList) ) {
fazekasgy@0 805 if (pyOutputList == NULL) {
fazekasgy@0 806 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 807 << "] Unexpected result." << endl;
fazekasgy@0 808 if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
fazekasgy@0 809 } else {
fazekasgy@0 810 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 811 << "] Expected List return type." << endl;
fazekasgy@0 812 }
fazekasgy@0 813 Py_CLEAR(pyMethod);
fazekasgy@0 814 Py_CLEAR(pyOutputList);
fazekasgy@0 815 mutex = false;
fazekasgy@0 816 return FeatureSet();
fazekasgy@0 817 }
fazekasgy@0 818
fazekasgy@0 819 Py_DECREF(pyMethod);
fazekasgy@0 820 // Py_DECREF(pyList);
fazekasgy@0 821 // This appears to be tracked by the cyclic garbage collector
fazekasgy@0 822 // hence decrefing produces GC error
fazekasgy@0 823 #ifdef _DEBUG
fazekasgy@0 824 cerr << "Process Returned Features" << endl;
fazekasgy@0 825 #endif
fazekasgy@0 826 // These will ALL be borrowed references
fazekasgy@0 827 PyObject *pyFeatureList, *pyDict, *pyKey, *pyValue;
fazekasgy@0 828
fazekasgy@0 829 FeatureSet returnFeatures;
fazekasgy@0 830
fazekasgy@0 831 //Parse Output List for each element (FeatureSet)
fazekasgy@0 832 for (Py_ssize_t i = 0;
fazekasgy@0 833 i < PyList_GET_SIZE(pyOutputList); ++i) {
fazekasgy@0 834 //cerr << "output (FeatureSet): " << i << endl;
fazekasgy@0 835
fazekasgy@0 836 //Get i-th FeatureList (Borrowed Reference)
fazekasgy@0 837 pyFeatureList = PyList_GET_ITEM(pyOutputList,i);
fazekasgy@0 838
fazekasgy@0 839 //Parse FeatureList for each element (Feature)
fazekasgy@0 840 for (Py_ssize_t j = 0; j < PyList_GET_SIZE(pyFeatureList); ++j) {
fazekasgy@0 841 //cerr << "element (FeatureList): " << j << endl;
fazekasgy@0 842
fazekasgy@0 843 //Get j-th Feature (Borrowed Reference)
fazekasgy@0 844 pyDict = PyList_GET_ITEM(pyFeatureList,j);
fazekasgy@0 845
fazekasgy@0 846 //We only care about dictionaries holding a Feature struct
fazekasgy@0 847 if ( !PyDict_Check(pyDict) ) continue;
fazekasgy@0 848
fazekasgy@0 849 Py_ssize_t pyPos = NULL;
fazekasgy@0 850 bool emptyFeature = true;
fazekasgy@0 851 Feature feature;
fazekasgy@0 852
fazekasgy@0 853 //process::Python Sequence Iterator for dictionary
fazekasgy@0 854 while (PyDict_Next(pyDict, &pyPos, &pyKey, &pyValue))
fazekasgy@0 855 {
fazekasgy@0 856 emptyFeature = false;
fazekasgy@0 857 switch (ffKeys[PyString_AsString(pyKey)])
fazekasgy@0 858 {
fazekasgy@0 859 case not_found :
fazekasgy@0 860 cerr << "Unknown key in VAMP FeatureSet: "
fazekasgy@0 861 << PyString_AsString(pyKey) << endl;
fazekasgy@0 862 break;
fazekasgy@0 863 case hasTimestamp:
fazekasgy@0 864 feature.hasTimestamp = (bool) PyInt_AS_LONG(pyValue);
fazekasgy@0 865 break;
fazekasgy@0 866 case timeStamp:
fazekasgy@0 867 feature.timestamp = timestamp +
fazekasgy@0 868 Vamp::RealTime::frame2RealTime
fazekasgy@0 869 ((size_t)PyInt_AS_LONG(pyValue), (size_t)m_inputSampleRate);
fazekasgy@0 870 break;
fazekasgy@0 871 case values:
fazekasgy@0 872 feature.values = PyList_As_FloatVector(pyValue);
fazekasgy@0 873 break;
fazekasgy@0 874 case label:
fazekasgy@0 875 feature.label = PyString_AsString(pyValue);
fazekasgy@0 876 break;
fazekasgy@0 877 default :
fazekasgy@0 878 cerr << "Invalid key in VAMP FeatureSet: "
fazekasgy@0 879 << PyString_AsString(pyKey) << endl;
fazekasgy@0 880 } // switch
fazekasgy@0 881
fazekasgy@0 882 } // while
fazekasgy@0 883 if (emptyFeature) cerr << "Warning: This feature is empty or badly formatted." << endl;
fazekasgy@0 884 else returnFeatures[i].push_back(feature);
fazekasgy@0 885
fazekasgy@0 886 }// for j = FeatureList
fazekasgy@0 887
fazekasgy@0 888 }//for i = FeatureSet
fazekasgy@0 889 Py_CLEAR(pyOutputList);
fazekasgy@0 890 mutex = false;
fazekasgy@0 891 return returnFeatures;
fazekasgy@0 892
fazekasgy@0 893 }//if (has_attribute)
fazekasgy@0 894 mutex = false;
fazekasgy@0 895 return FeatureSet();
fazekasgy@0 896 }
fazekasgy@0 897
fazekasgy@0 898
fazekasgy@0 899
fazekasgy@0 900 PyPlugin::FeatureSet
fazekasgy@0 901 PyPlugin::getRemainingFeatures()
fazekasgy@0 902 {
fazekasgy@0 903 static char method[]="getRemainingFeatures";
fazekasgy@0 904 cerr << "[call] " << method << endl;
fazekasgy@0 905
fazekasgy@0 906 //check if the method is implemented
fazekasgy@0 907 mutex = true;
fazekasgy@0 908 if ( ! PyObject_HasAttrString(m_pyInstance,method) ) {
fazekasgy@0 909 return FeatureSet();
fazekasgy@0 910 }
fazekasgy@0 911
fazekasgy@0 912 PyObject *pyMethod = PyString_FromString(method);
fazekasgy@0 913
fazekasgy@0 914 PyObject *pyOutputList =
fazekasgy@0 915 PyObject_CallMethod(m_pyInstance,method, NULL);
fazekasgy@0 916
fazekasgy@0 917 //Check return type
fazekasgy@0 918 if (pyOutputList == NULL || !PyList_Check(pyOutputList) ) {
fazekasgy@0 919 if (pyOutputList == NULL) {
fazekasgy@0 920 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 921 << "] Unexpected result." << endl;
fazekasgy@0 922 if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
fazekasgy@0 923 } else {
fazekasgy@0 924 cerr << "ERROR: In Python plugin [" << m_class << "::" << method
fazekasgy@0 925 << "] Expected List return type." << endl;
fazekasgy@0 926 }
fazekasgy@0 927 Py_CLEAR(pyMethod);
fazekasgy@0 928 Py_CLEAR(pyOutputList);
fazekasgy@0 929 mutex = false;
fazekasgy@0 930 return FeatureSet();
fazekasgy@0 931 }
fazekasgy@0 932 Py_DECREF(pyMethod);
fazekasgy@0 933
fazekasgy@0 934 PyObject *pyFeatureList, *pyDict, *pyKey, *pyValue;
fazekasgy@0 935 FeatureSet returnFeatures;
fazekasgy@0 936
fazekasgy@0 937 for (Py_ssize_t i = 0; i < PyList_GET_SIZE(pyOutputList); ++i) {
fazekasgy@0 938
fazekasgy@0 939 pyFeatureList = PyList_GET_ITEM(pyOutputList,i);
fazekasgy@0 940
fazekasgy@0 941 for (Py_ssize_t j = 0; j < PyList_GET_SIZE(pyFeatureList); ++j) {
fazekasgy@0 942
fazekasgy@0 943 pyDict = PyList_GET_ITEM(pyFeatureList,j);
fazekasgy@0 944
fazekasgy@0 945 if ( !PyDict_Check(pyDict) ) continue;
fazekasgy@0 946
fazekasgy@0 947 Py_ssize_t pyPos = NULL;
fazekasgy@0 948 bool emptyFeature = true;
fazekasgy@0 949 Feature feature;
fazekasgy@0 950
fazekasgy@0 951 while (PyDict_Next(pyDict, &pyPos, &pyKey, &pyValue))
fazekasgy@0 952 {
fazekasgy@0 953 emptyFeature = false;
fazekasgy@0 954 switch (ffKeys[PyString_AsString(pyKey)])
fazekasgy@0 955 {
fazekasgy@0 956 case not_found :
fazekasgy@0 957 cerr << "Unknown key in VAMP FeatureSet: "
fazekasgy@0 958 << PyString_AsString(pyKey) << endl;
fazekasgy@0 959 break;
fazekasgy@0 960 case hasTimestamp:
fazekasgy@0 961 feature.hasTimestamp = (bool) PyInt_AS_LONG(pyValue);
fazekasgy@0 962 break;
fazekasgy@0 963 // TODO: clarify what to do here
fazekasgy@0 964 case timeStamp:
fazekasgy@0 965 feature.timestamp =
fazekasgy@0 966 Vamp::RealTime::frame2RealTime
fazekasgy@0 967 ((size_t)PyInt_AS_LONG(pyValue), (size_t)m_inputSampleRate);
fazekasgy@0 968 break;
fazekasgy@0 969 case values:
fazekasgy@0 970 feature.values = PyList_As_FloatVector(pyValue);
fazekasgy@0 971 break;
fazekasgy@0 972 case label:
fazekasgy@0 973 feature.label = PyString_AsString(pyValue);
fazekasgy@0 974 break;
fazekasgy@0 975 } // switch
fazekasgy@0 976 } // while
fazekasgy@0 977 if (emptyFeature) cerr << "Warning: This feature is empty or badly formatted." << endl;
fazekasgy@0 978 else returnFeatures[i].push_back(feature);
fazekasgy@0 979 }// for j
fazekasgy@0 980 }//for i
fazekasgy@0 981 Py_CLEAR(pyOutputList);
fazekasgy@0 982 mutex = false;
fazekasgy@0 983 return returnFeatures;
fazekasgy@0 984 }
fazekasgy@0 985