annotate PyPlugin.cpp @ 35:2ba482378038 vampy2

* Fix compile error with VC++. I am totally at a loss to explain why this should have compiled with any other compiler! * Update VC project file. This code does now build with VC++ without HAVE_NUMPY -- I haven't installed Numpy yet
author cannam
date Thu, 24 Sep 2009 08:52:04 +0000
parents a8231788216c
children
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@31 54 #include "PyTypeInterface.h"
fazekasgy@31 55 #include <stdlib.h>
fazekasgy@31 56 #include "PyExtensionModule.h"
fazekasgy@31 57 //#include "PyRealTime.h"
fazekasgy@31 58
fazekasgy@0 59
fazekasgy@0 60 #ifdef _WIN32
fazekasgy@31 61 #define PATHSEP ('\\')
fazekasgy@0 62 #else
fazekasgy@31 63 #define PATHSEP ('/')
fazekasgy@0 64 #endif
fazekasgy@0 65
fazekasgy@6 66 //#define _DEBUG
fazekasgy@0 67
fazekasgy@0 68 using std::string;
fazekasgy@0 69 using std::vector;
fazekasgy@0 70 using std::cerr;
fazekasgy@0 71 using std::endl;
fazekasgy@0 72 using std::map;
fazekasgy@0 73
fazekasgy@31 74 Mutex PyPlugin::m_pythonInterpreterMutex;
fazekasgy@0 75
fazekasgy@31 76 PyPlugin::PyPlugin(std::string pluginKey, float inputSampleRate, PyObject *pyClass, int &instcount) :
cannam@24 77 Plugin(inputSampleRate),
cannam@24 78 m_pyClass(pyClass),
fazekasgy@31 79 m_instcount(instcount),
fazekasgy@0 80 m_stepSize(0),
fazekasgy@6 81 m_blockSize(0),
cannam@24 82 m_channels(0),
fazekasgy@0 83 m_plugin(pluginKey),
fazekasgy@0 84 m_class(pluginKey.substr(pluginKey.rfind(':')+1,pluginKey.size()-1)),
fazekasgy@31 85 m_path((pluginKey.substr(0,pluginKey.rfind(PATHSEP)))),
fazekasgy@6 86 m_processType(0),
fazekasgy@6 87 m_pyProcess(NULL),
fazekasgy@31 88 m_inputDomain(TimeDomain),
fazekasgy@31 89 m_quitOnErrorFlag(false),
fazekasgy@31 90 m_debugFlag(false)
fazekasgy@0 91 {
fazekasgy@31 92 m_ti.setInputSampleRate(inputSampleRate);
fazekasgy@31 93 MutexLocker locker(&m_pythonInterpreterMutex);
fazekasgy@31 94 cerr << "Creating instance " << m_instcount << " of " << pluginKey << endl;
fazekasgy@31 95
fazekasgy@31 96 if (m_instcount == 0) initvampy();
fazekasgy@31 97 m_instcount++;
fazekasgy@31 98
fazekasgy@31 99 // if (!PyImport_ImportModule("vampy"))
fazekasgy@31 100 // cerr << "Could not import extension." << endl;
fazekasgy@31 101
cannam@24 102 // Create an instance
fazekasgy@27 103 Py_INCREF(m_pyClass);
cannam@24 104 PyObject *pyInputSampleRate = PyFloat_FromDouble(inputSampleRate);
cannam@24 105 PyObject *args = PyTuple_Pack(1, pyInputSampleRate);
fazekasgy@27 106 m_pyInstance = PyObject_Call(m_pyClass, args, NULL);
fazekasgy@27 107
fazekasgy@27 108 if (!m_pyInstance || PyErr_Occurred()) {
fazekasgy@27 109 if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
fazekasgy@28 110 Py_DECREF(m_pyClass);
fazekasgy@27 111 Py_CLEAR(args);
fazekasgy@27 112 Py_CLEAR(pyInputSampleRate);
fazekasgy@31 113 cerr << "PyPlugin::PyPlugin: Failed to create Python plugin instance for key \""
fazekasgy@31 114 << pluginKey << "\" (is the 1-arg class constructor from sample rate correctly provided?)" << endl;
cannam@24 115 throw std::string("Constructor failed");
cannam@24 116 }
fazekasgy@27 117 Py_INCREF(m_pyInstance);
cannam@24 118 Py_DECREF(args);
cannam@24 119 Py_DECREF(pyInputSampleRate);
fazekasgy@31 120
fazekasgy@31 121 //query the debug flag
fazekasgy@31 122 m_debugFlag = getBooleanFlag("vampy_debug_messages",true);
fazekasgy@31 123 if (m_debugFlag) cerr << "Debug messages ON for Vampy plugin: " << m_class << endl;
fazekasgy@31 124 else cerr << "Debug messages OFF for Vampy plugin: " << m_class << endl;
fazekasgy@31 125
fazekasgy@31 126 //query the quit on error flag
fazekasgy@31 127 m_quitOnErrorFlag = getBooleanFlag("quit_on_type_error",false);
fazekasgy@31 128 if (m_debugFlag && m_quitOnErrorFlag) cerr << "Quit on type error ON for: " << m_class << endl;
fazekasgy@31 129
fazekasgy@31 130 //query the type conversion mode flag
fazekasgy@31 131 bool st_flag = getBooleanFlag("use_strict_type_conversion",false);
fazekasgy@31 132 if (m_debugFlag && st_flag) cerr << "Strict type conversion ON for: " << m_class << endl;
fazekasgy@31 133 m_ti.setStrictTypingFlag(st_flag);
fazekasgy@0 134 }
fazekasgy@0 135
fazekasgy@0 136 PyPlugin::~PyPlugin()
fazekasgy@0 137 {
fazekasgy@31 138 MutexLocker locker(&m_pythonInterpreterMutex);
fazekasgy@31 139 m_instcount--;
fazekasgy@31 140 cerr << "Deleting plugin instance. Count: " << m_instcount << endl;
fazekasgy@31 141
cannam@24 142 if (m_pyInstance) Py_DECREF(m_pyInstance);
fazekasgy@31 143 //we increase the class refcount before creating an instance
fazekasgy@31 144 if (m_pyClass) Py_DECREF(m_pyClass);
fazekasgy@27 145 if (m_pyProcess) Py_CLEAR(m_pyProcess);
fazekasgy@31 146 if (m_instcount == 0) cleanModule();
cannam@24 147
fazekasgy@6 148 #ifdef _DEBUG
fazekasgy@31 149 cerr << "PyPlugin::PyPlugin:" << m_class << " instance " << m_instcount << " deleted." << endl;
fazekasgy@6 150 #endif
fazekasgy@0 151 }
fazekasgy@0 152
fazekasgy@0 153
fazekasgy@0 154 string
fazekasgy@0 155 PyPlugin::getIdentifier() const
fazekasgy@0 156 {
cannam@3 157 MutexLocker locker(&m_pythonInterpreterMutex);
fazekasgy@31 158 string rString="vampy-xxx";
fazekasgy@31 159 if (!m_debugFlag) return genericMethodCall("getIdentifier",rString);
cannam@3 160
fazekasgy@31 161 rString = genericMethodCall("getIdentifier",rString);
fazekasgy@31 162 if (rString == "vampy-xxx")
fazekasgy@31 163 cerr << "Warning: Plugin must return a unique identifier." << endl;
fazekasgy@0 164 return rString;
fazekasgy@0 165 }
fazekasgy@0 166
fazekasgy@0 167 string
fazekasgy@0 168 PyPlugin::getName() const
fazekasgy@0 169 {
cannam@3 170 MutexLocker locker(&m_pythonInterpreterMutex);
fazekasgy@0 171 string rString="VamPy Plugin (Noname)";
fazekasgy@31 172 return genericMethodCall("getName",rString);
fazekasgy@0 173 }
fazekasgy@0 174
fazekasgy@0 175 string
fazekasgy@0 176 PyPlugin::getDescription() const
fazekasgy@0 177 {
cannam@3 178 MutexLocker locker(&m_pythonInterpreterMutex);
fazekasgy@31 179 string rString="Not given. (Hint: Implement getDescription method.)";
fazekasgy@31 180 return genericMethodCall("getDescription",rString);
fazekasgy@31 181 }
cannam@3 182
fazekasgy@0 183
fazekasgy@0 184 string
fazekasgy@0 185 PyPlugin::getMaker() const
fazekasgy@0 186 {
cannam@3 187 MutexLocker locker(&m_pythonInterpreterMutex);
fazekasgy@31 188 string rString="VamPy Plugin.";
fazekasgy@31 189 return genericMethodCall("getMaker",rString);
fazekasgy@0 190 }
fazekasgy@0 191
fazekasgy@0 192 int
fazekasgy@0 193 PyPlugin::getPluginVersion() const
fazekasgy@0 194 {
fazekasgy@31 195 MutexLocker locker(&m_pythonInterpreterMutex);
fazekasgy@31 196 size_t rValue=2;
fazekasgy@31 197 return genericMethodCall("getPluginVersion",rValue);
fazekasgy@0 198 }
fazekasgy@0 199
fazekasgy@0 200 string
fazekasgy@0 201 PyPlugin::getCopyright() const
fazekasgy@0 202 {
cannam@3 203 MutexLocker locker(&m_pythonInterpreterMutex);
fazekasgy@31 204 string rString="Licence information not available.";
fazekasgy@31 205 return genericMethodCall("getCopyright",rString);
fazekasgy@0 206 }
fazekasgy@0 207
fazekasgy@0 208
fazekasgy@0 209 bool
fazekasgy@0 210 PyPlugin::initialise(size_t channels, size_t stepSize, size_t blockSize)
fazekasgy@0 211 {
fazekasgy@31 212
cannam@24 213 if (channels < getMinChannelCount() ||
cannam@24 214 channels > getMaxChannelCount()) return false;
fazekasgy@31 215
fazekasgy@6 216 m_inputDomain = getInputDomain();
fazekasgy@6 217
fazekasgy@31 218 //Note: placing Mutex before the calls above causes deadlock !!
cannam@3 219 MutexLocker locker(&m_pythonInterpreterMutex);
cannam@3 220
fazekasgy@6 221 m_stepSize = stepSize;
fazekasgy@6 222 m_blockSize = blockSize;
fazekasgy@6 223 m_channels = channels;
fazekasgy@6 224
fazekasgy@31 225 //query the process implementation type
fazekasgy@31 226 //two optional flags can be used: 'use_numpy_interface' or 'use_legacy_interface'
fazekasgy@31 227 //if they are not provided, we fall back to the original method
fazekasgy@31 228 setProcessType();
fazekasgy@6 229
fazekasgy@31 230 return genericMethodCallArgs<bool>("initialise",channels,stepSize,blockSize);
fazekasgy@0 231 }
fazekasgy@0 232
fazekasgy@0 233 void
fazekasgy@0 234 PyPlugin::reset()
fazekasgy@0 235 {
fazekasgy@6 236 MutexLocker locker(&m_pythonInterpreterMutex);
fazekasgy@31 237 genericMethodCall("reset");
fazekasgy@0 238 }
fazekasgy@0 239
fazekasgy@31 240 PyPlugin::InputDomain
fazekasgy@31 241 PyPlugin::getInputDomain() const
fazekasgy@0 242 {
cannam@3 243 MutexLocker locker(&m_pythonInterpreterMutex);
fazekasgy@31 244 // Note: Vamp enum type is mapped to Python string !!
fazekasgy@31 245 // Is there a better way? (Enums are not native to Python)
fazekasgy@31 246 string rValue = "TimeDomain";
fazekasgy@31 247 genericMethodCall("getInputDomain",rValue);
fazekasgy@31 248 return (rValue == "FrequencyDomain")?FrequencyDomain:TimeDomain;
fazekasgy@0 249 }
fazekasgy@0 250
fazekasgy@31 251 size_t
fazekasgy@31 252 PyPlugin::getPreferredBlockSize() const
fazekasgy@0 253 {
cannam@3 254 MutexLocker locker(&m_pythonInterpreterMutex);
fazekasgy@31 255 size_t rValue = 0;
fazekasgy@31 256 return genericMethodCall("getPreferredBlockSize",rValue);
fazekasgy@0 257 }
fazekasgy@0 258
fazekasgy@31 259 size_t
fazekasgy@31 260 PyPlugin::getPreferredStepSize() const
fazekasgy@0 261 {
cannam@3 262 MutexLocker locker(&m_pythonInterpreterMutex);
fazekasgy@31 263 size_t rValue = 0;
fazekasgy@31 264 return genericMethodCall("getPreferredStepSize",rValue);
fazekasgy@0 265 }
fazekasgy@0 266
fazekasgy@31 267 size_t
fazekasgy@31 268 PyPlugin::getMinChannelCount() const
fazekasgy@0 269 {
cannam@3 270 MutexLocker locker(&m_pythonInterpreterMutex);
fazekasgy@31 271 size_t rValue = 1;
fazekasgy@31 272 return genericMethodCall("getMinChannelCount",rValue);
fazekasgy@0 273 }
fazekasgy@0 274
fazekasgy@31 275 size_t
fazekasgy@31 276 PyPlugin::getMaxChannelCount() const
fazekasgy@0 277 {
cannam@3 278 MutexLocker locker(&m_pythonInterpreterMutex);
fazekasgy@31 279 size_t rValue = 1;
fazekasgy@31 280 return genericMethodCall("getMaxChannelCount",rValue);
fazekasgy@31 281 }
fazekasgy@0 282
fazekasgy@0 283 PyPlugin::OutputList
fazekasgy@0 284 PyPlugin::getOutputDescriptors() const
fazekasgy@0 285 {
cannam@3 286 MutexLocker locker(&m_pythonInterpreterMutex);
fazekasgy@0 287 OutputList list;
fazekasgy@31 288 return genericMethodCall("getOutputDescriptors",list);
fazekasgy@0 289 }
fazekasgy@0 290
fazekasgy@0 291 PyPlugin::ParameterList
fazekasgy@0 292 PyPlugin::getParameterDescriptors() const
fazekasgy@0 293 {
cannam@3 294 MutexLocker locker(&m_pythonInterpreterMutex);
fazekasgy@0 295 ParameterList list;
fazekasgy@31 296 ///Note: This function is often called first by the host.
fazekasgy@27 297 if (!m_pyInstance) {cerr << "Error: pyInstance is NULL" << endl; return list;}
fazekasgy@31 298 return genericMethodCall("getParameterDescriptors",list);
fazekasgy@0 299 }
fazekasgy@0 300
fazekasgy@0 301 void PyPlugin::setParameter(std::string paramid, float newval)
fazekasgy@0 302 {
cannam@3 303 MutexLocker locker(&m_pythonInterpreterMutex);
fazekasgy@31 304 genericMethodCallArgs<NoneType>("setParameter",paramid,newval);
fazekasgy@0 305 }
fazekasgy@0 306
fazekasgy@0 307 float PyPlugin::getParameter(std::string paramid) const
fazekasgy@0 308 {
cannam@3 309 MutexLocker locker(&m_pythonInterpreterMutex);
fazekasgy@31 310 return genericMethodCallArgs<float>("getParameter",paramid);
fazekasgy@0 311 }
fazekasgy@0 312
fazekasgy@0 313 #ifdef _DEBUG
fazekasgy@0 314 static int proccounter = 0;
fazekasgy@0 315 #endif
fazekasgy@0 316
fazekasgy@0 317 PyPlugin::FeatureSet
fazekasgy@31 318 PyPlugin::process(const float *const *inputBuffers,Vamp::RealTime timestamp)
fazekasgy@0 319 {
cannam@3 320 MutexLocker locker(&m_pythonInterpreterMutex);
cannam@3 321
fazekasgy@6 322 #ifdef _DEBUG
fazekasgy@6 323 cerr << "[call] process, frame:" << proccounter << endl;
fazekasgy@6 324 proccounter++;
fazekasgy@6 325 #endif
fazekasgy@6 326
fazekasgy@8 327 if (m_blockSize == 0 || m_channels == 0) {
fazekasgy@0 328 cerr << "ERROR: PyPlugin::process: "
fazekasgy@0 329 << "Plugin has not been initialised" << endl;
fazekasgy@0 330 return FeatureSet();
fazekasgy@0 331 }
fazekasgy@0 332
fazekasgy@6 333 if (m_processType == not_implemented) {
fazekasgy@6 334 cerr << "ERROR: In Python plugin [" << m_class
fazekasgy@6 335 << "] No process implementation found. Returning empty feature set." << endl;
fazekasgy@6 336 return FeatureSet();
fazekasgy@6 337 }
fazekasgy@0 338
fazekasgy@31 339 // string method=PyString_AsString(m_pyProcess);
fazekasgy@6 340
fazekasgy@6 341 PyObject *pyOutputList = NULL;
fazekasgy@0 342
fazekasgy@6 343 if (m_processType == numpyProcess) {
fazekasgy@31 344 pyOutputList = numpyProcessCall(inputBuffers,timestamp);
fazekasgy@6 345 }
fazekasgy@6 346
fazekasgy@6 347 if (m_processType == legacyProcess) {
fazekasgy@31 348 pyOutputList = legacyProcessCall(inputBuffers,timestamp);
fazekasgy@0 349 }
fazekasgy@6 350
fazekasgy@31 351 FeatureSet rFeatureset;
fazekasgy@31 352 rFeatureset = m_ti.PyValue_To_FeatureSet(pyOutputList);
fazekasgy@0 353 Py_CLEAR(pyOutputList);
fazekasgy@31 354 return rFeatureset;
fazekasgy@31 355
fazekasgy@0 356 }
fazekasgy@0 357
fazekasgy@31 358 PyObject*
fazekasgy@31 359 PyPlugin::numpyProcessCall(const float *const *inputBuffers,Vamp::RealTime timestamp)
fazekasgy@31 360 {
fazekasgy@31 361 PyObject *pyOutputList = NULL;
fazekasgy@31 362
fazekasgy@31 363 //create a list of buffers
fazekasgy@31 364 PyObject *pyChannelList = PyList_New((Py_ssize_t) m_channels);
fazekasgy@31 365 for (size_t i=0; i < m_channels; ++i) {
fazekasgy@31 366 //Expose memory using the Buffer Interface of C/API
fazekasgy@32 367 //This will pass a pointer which can be recasted
fazekasgy@32 368 //in Python code as float or complex array
fazekasgy@31 369 PyObject *pyBuffer = PyBuffer_FromMemory
fazekasgy@31 370 ((void *) (float *) inputBuffers[i],
fazekasgy@31 371 (Py_ssize_t) sizeof(float) * m_blockSize);
fazekasgy@0 372
fazekasgy@31 373 PyList_SET_ITEM(pyChannelList, (Py_ssize_t) i, pyBuffer);
fazekasgy@31 374 }
fazekasgy@31 375 /*
fazekasgy@31 376 //(1) pass RealTime as frameCount
fazekasgy@31 377 PyObject *pyLongSample = PyLong_FromLong (
fazekasgy@31 378 Vamp::RealTime::realTime2Frame
fazekasgy@31 379 (timestamp, (unsigned int) m_inputSampleRate));
fazekasgy@31 380
fazekasgy@31 381 //Call python process (returns new reference)
fazekasgy@31 382 pyOutputList = PyObject_CallMethodObjArgs
fazekasgy@31 383 (m_pyInstance,m_pyProcess,pyChannelList,pyLongSample,NULL);
fazekasgy@31 384 */
fazekasgy@31 385 //(2) pass RealTime as PyRealTime
fazekasgy@31 386 PyObject *pyRealTime = PyRealTime_FromRealTime(timestamp);
fazekasgy@31 387
fazekasgy@31 388 //Call python process (returns new reference)
fazekasgy@31 389 pyOutputList = PyObject_CallMethodObjArgs
fazekasgy@31 390 (m_pyInstance,m_pyProcess,pyChannelList,pyRealTime,NULL);
fazekasgy@31 391
fazekasgy@31 392 Py_DECREF(pyChannelList);
fazekasgy@31 393 // Py_DECREF(pyLongSample);
fazekasgy@31 394 Py_DECREF(pyRealTime);
fazekasgy@31 395 return pyOutputList;
fazekasgy@31 396 }
fazekasgy@31 397
fazekasgy@31 398 PyObject*
fazekasgy@31 399 PyPlugin::legacyProcessCall(const float *const *inputBuffers,Vamp::RealTime timestamp)
fazekasgy@31 400 {
fazekasgy@31 401 PyObject *pyOutputList = NULL;
fazekasgy@31 402
fazekasgy@31 403 //create a list of lists
fazekasgy@31 404 PyObject *pyChannelList = PyList_New((Py_ssize_t) m_channels);
fazekasgy@31 405 for (size_t i=0; i < m_channels; ++i) {
fazekasgy@31 406 //New list object
fazekasgy@31 407 PyObject *pyFloat, *pyList;
fazekasgy@31 408 pyList = PyList_New((Py_ssize_t) m_blockSize);
fazekasgy@31 409
fazekasgy@31 410 //Pack samples into a Python List Object
fazekasgy@31 411 //pyFloat types will always be new references,
fazekasgy@31 412 //these will be discarded when the list is deallocated
fazekasgy@31 413 for (size_t j = 0; j < m_blockSize; ++j) {
fazekasgy@31 414 pyFloat=PyFloat_FromDouble(
fazekasgy@31 415 (double) inputBuffers[i][j]);
fazekasgy@31 416 PyList_SET_ITEM(pyList, (Py_ssize_t) j, pyFloat);
fazekasgy@31 417 }
fazekasgy@31 418 PyList_SET_ITEM(pyChannelList, (Py_ssize_t) i, pyList);
fazekasgy@31 419 }
fazekasgy@31 420
fazekasgy@31 421 //pass RealTime as frameCount
fazekasgy@31 422 PyObject *pyLongSample = PyLong_FromLong (
fazekasgy@31 423 Vamp::RealTime::realTime2Frame
fazekasgy@31 424 (timestamp, (unsigned int) m_inputSampleRate));
fazekasgy@31 425
fazekasgy@31 426 //Call python process (returns new reference)
fazekasgy@31 427 pyOutputList = PyObject_CallMethodObjArgs
fazekasgy@31 428 (m_pyInstance,m_pyProcess,pyChannelList,pyLongSample,NULL);
fazekasgy@31 429
fazekasgy@31 430 Py_DECREF(pyChannelList);
fazekasgy@31 431 Py_DECREF(pyLongSample);
fazekasgy@31 432 return pyOutputList;
fazekasgy@31 433 }
fazekasgy@0 434
fazekasgy@0 435 PyPlugin::FeatureSet
fazekasgy@0 436 PyPlugin::getRemainingFeatures()
fazekasgy@0 437 {
cannam@3 438 MutexLocker locker(&m_pythonInterpreterMutex);
fazekasgy@31 439 FeatureSet rValue;
fazekasgy@31 440 return genericMethodCall("getRemainingFeatures",rValue);
fazekasgy@0 441 }
fazekasgy@0 442
fazekasgy@31 443
fazekasgy@6 444 bool
fazekasgy@31 445 PyPlugin::getBooleanFlag(char flagName[], bool defValue = false) const
fazekasgy@6 446 {
fazekasgy@31 447 bool rValue = defValue;
fazekasgy@31 448 if (PyObject_HasAttrString(m_pyInstance,flagName))
fazekasgy@31 449 {
fazekasgy@31 450 PyObject *pyValue = PyObject_GetAttrString(m_pyInstance,flagName);
fazekasgy@31 451 if (!pyValue)
fazekasgy@31 452 {
fazekasgy@31 453 if (PyErr_Occurred()) {PyErr_Print(); PyErr_Clear();}
fazekasgy@31 454 } else {
fazekasgy@31 455 rValue = m_ti.PyValue_To_Bool(pyValue);
fazekasgy@31 456 if (m_ti.error) {
fazekasgy@31 457 cerr << m_ti.lastError().message << endl;
fazekasgy@31 458 Py_CLEAR(pyValue);
fazekasgy@31 459 rValue = defValue;
fazekasgy@31 460 } else Py_DECREF(pyValue);
fazekasgy@31 461 }
fazekasgy@31 462 }
fazekasgy@31 463 if (m_debugFlag) cerr << FLAG_VALUE << endl;
fazekasgy@31 464 return rValue;
fazekasgy@6 465 }
fazekasgy@6 466
fazekasgy@31 467 void
fazekasgy@31 468 PyPlugin::setProcessType()
fazekasgy@31 469 {
fazekasgy@31 470 //quering process implementation type
fazekasgy@31 471 char legacyMethod[]="process";
fazekasgy@31 472 char numpyMethod[]="processN";
fazekasgy@6 473
fazekasgy@31 474 if (PyObject_HasAttrString(m_pyInstance,legacyMethod) &&
fazekasgy@31 475 m_processType == 0)
fazekasgy@31 476 {
fazekasgy@31 477 m_processType = legacyProcess;
fazekasgy@31 478 m_pyProcess = PyString_FromString(legacyMethod);
fazekasgy@31 479 }
fazekasgy@31 480
fazekasgy@31 481 if (PyObject_HasAttrString(m_pyInstance,numpyMethod) &&
fazekasgy@31 482 m_processType == 0)
fazekasgy@31 483 {
fazekasgy@31 484 m_processType = numpyProcess;
fazekasgy@31 485 m_pyProcess = PyString_FromString(numpyMethod);
fazekasgy@31 486 }
fazekasgy@31 487
fazekasgy@31 488 // These flags are optional. If provided, they override the
fazekasgy@31 489 // implementation type making the use of the odd processN()
fazekasgy@31 490 // function redundant.
fazekasgy@31 491 // However, the code above provides backwards compatibility.
fazekasgy@31 492 if (getBooleanFlag("use_numpy_interface",false))
fazekasgy@31 493 m_processType = numpyProcess;
fazekasgy@31 494 if (getBooleanFlag("use_legacy_interface",false))
fazekasgy@31 495 m_processType = legacyProcess;
fazekasgy@31 496 if (m_debugFlag && m_processType)
fazekasgy@31 497 cerr << "Process type: " << ((m_processType==numpyProcess)?"numpy process":"legacy process") << endl;
fazekasgy@6 498
fazekasgy@31 499 if (!m_processType)
fazekasgy@31 500 {
fazekasgy@31 501 m_processType = not_implemented;
fazekasgy@31 502 m_pyProcess = NULL;
fazekasgy@31 503 char method[]="initialise::setProcessType";
fazekasgy@31 504 cerr << PLUGIN_ERROR << " No process implementation found. Plugin will do nothing." << endl;
fazekasgy@6 505 }
fazekasgy@6 506 }
fazekasgy@6 507