annotate PyTypeInterface.cpp @ 73:76355b91cd92 vampyhost

Add vector<string> -> Python converter
author Chris Cannam
date Mon, 24 Nov 2014 11:02:20 +0000
parents ffaa1fb3d7de
children
rev   line source
Chris@66 1 /* -*- c-basic-offset: 8 indent-tabs-mode: t -*- */
fazekasgy@37 2 /*
fazekasgy@37 3
fazekasgy@37 4 * Vampy : This plugin is a wrapper around the Vamp plugin API.
fazekasgy@37 5 * It allows for writing Vamp plugins in Python.
fazekasgy@37 6
fazekasgy@37 7 * Centre for Digital Music, Queen Mary University of London.
fazekasgy@37 8 * Copyright (C) 2008-2009 Gyorgy Fazekas, QMUL. (See Vamp sources
fazekasgy@37 9 * for licence information.)
fazekasgy@37 10
fazekasgy@37 11 */
fazekasgy@37 12
fazekasgy@37 13 #include <Python.h>
fazekasgy@37 14
fazekasgy@37 15 #ifdef HAVE_NUMPY
fazekasgy@37 16 #define PY_ARRAY_UNIQUE_SYMBOL VAMPY_ARRAY_API
fazekasgy@37 17 #define NO_IMPORT_ARRAY
Chris@66 18 #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
fazekasgy@37 19 #include "numpy/arrayobject.h"
fazekasgy@37 20 #endif
fazekasgy@37 21
fazekasgy@37 22 #include "PyTypeInterface.h"
fazekasgy@37 23 #include "PyRealTime.h"
fazekasgy@37 24 #include "PyExtensionModule.h"
fazekasgy@37 25 #include <math.h>
fazekasgy@37 26 #include <float.h>
fazekasgy@37 27 #include <limits.h>
fazekasgy@37 28 #ifndef SIZE_T_MAX
fazekasgy@37 29 #define SIZE_T_MAX ((size_t) -1)
fazekasgy@37 30 #endif
fazekasgy@37 31
fazekasgy@37 32 using std::string;
fazekasgy@37 33 using std::vector;
fazekasgy@37 34 using std::cerr;
fazekasgy@37 35 using std::endl;
fazekasgy@37 36 using std::map;
fazekasgy@37 37
fazekasgy@37 38 static std::map<std::string, o::eOutDescriptors> outKeys;
fazekasgy@37 39 static std::map<std::string, p::eParmDescriptors> parmKeys;
fazekasgy@37 40 static std::map<std::string, eSampleTypes> sampleKeys;
fazekasgy@37 41 static std::map<std::string, eFeatureFields> ffKeys;
fazekasgy@37 42 static bool isMapInitialised = false;
fazekasgy@37 43
fazekasgy@37 44 /* Note: NO FUNCTION IN THIS CLASS SHOULD ALTER REFERENCE COUNTS
Chris@66 45 (EXCEPT FOR TEMPORARY PYTHON OBJECTS)! */
fazekasgy@37 46
fazekasgy@37 47 PyTypeInterface::PyTypeInterface() :
fazekasgy@37 48 m_strict(false),
fazekasgy@37 49 m_error(false),
fazekasgy@51 50 m_numpyInstalled(false),
fazekasgy@37 51 error(m_error) // const public reference for easy access
fazekasgy@37 52 {
fazekasgy@37 53 }
fazekasgy@37 54
fazekasgy@37 55 PyTypeInterface::~PyTypeInterface()
fazekasgy@37 56 {
fazekasgy@37 57 }
fazekasgy@37 58
fazekasgy@51 59 /// FeatureSet (an integer map of FeatureLists)
fazekasgy@37 60 Vamp::Plugin::FeatureSet
fazekasgy@37 61 PyTypeInterface::PyValue_To_FeatureSet(PyObject* pyValue) const
fazekasgy@37 62 {
fazekasgy@37 63 Vamp::Plugin::FeatureSet rFeatureSet;
fazekasgy@37 64
fazekasgy@37 65 /// Convert PyFeatureSet
fazekasgy@37 66 if (PyFeatureSet_CheckExact(pyValue)) {
fazekasgy@37 67
fazekasgy@37 68 Py_ssize_t pyPos = 0;
fazekasgy@37 69 PyObject *pyKey, *pyDictValue; // Borrowed References
fazekasgy@37 70 int key;
fazekasgy@37 71 // bool it_error = false;
fazekasgy@37 72
fazekasgy@37 73 m_error = false;
fazekasgy@37 74 while (PyDict_Next(pyValue, &pyPos, &pyKey, &pyDictValue))
fazekasgy@37 75 {
fazekasgy@37 76 key = (int) PyInt_AS_LONG(pyKey);
fazekasgy@37 77 #ifdef _DEBUG_VALUES
fazekasgy@37 78 cerr << "key: '" << key << "' value: '" << PyValue_To_String(pyDictValue) << "' " << endl;
fazekasgy@37 79 #endif
fazekasgy@37 80 // DictValue -> Vamp::FeatureList
fazekasgy@37 81 PyValue_To_rValue(pyDictValue,rFeatureSet[key]);
fazekasgy@37 82 if (m_error) {
fazekasgy@37 83 // it_error = true;
fazekasgy@37 84 lastError() << " in output number: " << key;
fazekasgy@37 85 }
fazekasgy@37 86 }
fazekasgy@37 87 // if (it_error) m_error = true;
fazekasgy@37 88 if (!m_errorQueue.empty()) {
fazekasgy@37 89 setValueError("Error while converting FeatureSet.",m_strict);
fazekasgy@37 90 }
fazekasgy@37 91 return rFeatureSet;
fazekasgy@37 92 }
fazekasgy@37 93
fazekasgy@37 94 /// Convert Python list (backward compatibility)
fazekasgy@37 95 if (PyList_Check(pyValue)) {
fazekasgy@37 96
fazekasgy@37 97 PyObject *pyFeatureList; // This will be borrowed reference
fazekasgy@37 98
fazekasgy@37 99 //Parse Output List for each element (FeatureSet)
fazekasgy@37 100 m_error = false;
fazekasgy@37 101 for (Py_ssize_t i = 0; i < PyList_GET_SIZE(pyValue); ++i) {
fazekasgy@37 102 //Get i-th FeatureList (Borrowed Reference)
fazekasgy@37 103 pyFeatureList = PyList_GET_ITEM(pyValue,i);
fazekasgy@37 104 PyValue_To_rValue(pyFeatureList,rFeatureSet[i]);
fazekasgy@37 105 if (m_error) {
fazekasgy@37 106 lastError() << " in output number: " << i;
fazekasgy@37 107 }
fazekasgy@37 108 }
fazekasgy@37 109 if (!m_errorQueue.empty()) m_error = true;
fazekasgy@37 110 return rFeatureSet;
fazekasgy@37 111 }
fazekasgy@37 112
fazekasgy@51 113 /// accept None return values
fazekasgy@37 114 if (pyValue == Py_None) return rFeatureSet;
fazekasgy@37 115
fazekasgy@37 116 /// give up
fazekasgy@37 117 std::string msg = "Unsupported return type. Expected list or vampy.FeatureSet(). ";
fazekasgy@37 118 setValueError(msg,m_strict);
fazekasgy@37 119 #ifdef _DEBUG
fazekasgy@37 120 cerr << "PyTypeInterface::PyValue_To_FeatureSet failed. Error: " << msg << endl;
fazekasgy@37 121 #endif
fazekasgy@37 122 return rFeatureSet;
fazekasgy@37 123 }
fazekasgy@37 124
fazekasgy@37 125 Vamp::RealTime
fazekasgy@37 126 PyTypeInterface::PyValue_To_RealTime(PyObject* pyValue) const
fazekasgy@37 127 {
fazekasgy@37 128 // We accept integer sample counts (for backward compatibility)
fazekasgy@37 129 // or PyRealTime objects and convert them to Vamp::RealTime
fazekasgy@37 130
fazekasgy@37 131 if (PyRealTime_CheckExact(pyValue))
fazekasgy@37 132 {
fazekasgy@37 133 /// just create a copy of the wrapped object
fazekasgy@37 134 return Vamp::RealTime(*PyRealTime_AS_REALTIME(pyValue));
fazekasgy@37 135 }
fazekasgy@37 136
fazekasgy@37 137 // assume integer sample count
Chris@71 138 long sampleCount = m_conv.PyValue_To_Long(pyValue);
Chris@71 139 if (m_conv.error) {
fazekasgy@37 140 std::string msg = "Unexpected value passed as RealTime.\nMust be vampy.RealTime type or integer sample count.";
fazekasgy@37 141 setValueError(msg,m_strict);
fazekasgy@37 142 #ifdef _DEBUG
fazekasgy@37 143 cerr << "PyTypeInterface::PyValue_To_RealTime failed. " << msg << endl;
fazekasgy@37 144 #endif
fazekasgy@37 145 return Vamp::RealTime();
fazekasgy@37 146 }
fazekasgy@37 147
fazekasgy@37 148 #ifdef _DEBUG_VALUES
fazekasgy@37 149 Vamp::RealTime rt =
fazekasgy@37 150 Vamp::RealTime::frame2RealTime(sampleCount,m_inputSampleRate );
fazekasgy@37 151 cerr << "RealTime: " << (long)sampleCount << ", ->" << rt.toString() << endl;
fazekasgy@37 152 return rt;
fazekasgy@37 153 #else
fazekasgy@37 154 return Vamp::RealTime::frame2RealTime(sampleCount,m_inputSampleRate );
fazekasgy@37 155 #endif
fazekasgy@37 156
fazekasgy@37 157 }
fazekasgy@37 158
fazekasgy@37 159 Vamp::Plugin::OutputDescriptor::SampleType
fazekasgy@37 160 PyTypeInterface::PyValue_To_SampleType(PyObject* pyValue) const
fazekasgy@37 161 {
fazekasgy@37 162 /// convert simulated enum values
fazekasgy@37 163 /// { OneSamplePerStep,FixedSampleRate,VariableSampleRate }
fazekasgy@37 164 if (PyInt_CheckExact(pyValue)) {
fazekasgy@37 165 long lst = PyInt_AS_LONG(pyValue);
fazekasgy@37 166 if (lst<0 || lst>2) {
fazekasgy@37 167 setValueError("Overflow error. SampleType has to be one of { OneSamplePerStep,FixedSampleRate,VariableSampleRate }\n(an integer in the range of 0..2) or a string value naming the type.",m_strict);
fazekasgy@37 168 return Vamp::Plugin::OutputDescriptor::SampleType();
fazekasgy@37 169 }
fazekasgy@37 170 return (Vamp::Plugin::OutputDescriptor::SampleType) lst;
fazekasgy@37 171 }
fazekasgy@37 172
fazekasgy@37 173 /// convert string (backward compatible)
fazekasgy@37 174 if (PyString_CheckExact(pyValue)) {
fazekasgy@37 175 Vamp::Plugin::OutputDescriptor::SampleType st;
Chris@71 176 st = (Vamp::Plugin::OutputDescriptor::SampleType) sampleKeys[m_conv.PyValue_To_String(pyValue)];
Chris@71 177 if (m_conv.error) {
fazekasgy@37 178 std::string msg = "Unexpected value passed as SampleType. Must be one of { OneSamplePerStep,FixedSampleRate,VariableSampleRate }\n(an integer in the range of 0..2) or a string value naming the type.";
fazekasgy@37 179 setValueError(msg,m_strict);
fazekasgy@37 180 return Vamp::Plugin::OutputDescriptor::SampleType();
fazekasgy@37 181 }
fazekasgy@37 182 return st;
fazekasgy@37 183 }
fazekasgy@37 184
fazekasgy@37 185 /// give up
fazekasgy@37 186 std::string msg = "Unsupported return type. Expected one of { OneSamplePerStep,FixedSampleRate,VariableSampleRate }\n(an integer in the range of 0..2) or a string value naming the type.";
fazekasgy@37 187 setValueError(msg,m_strict);
fazekasgy@37 188 #ifdef _DEBUG
fazekasgy@37 189 cerr << "PyTypeInterface::PyValue_To_SampleType failed. Error: " << msg << endl;
fazekasgy@37 190 #endif
fazekasgy@37 191 return Vamp::Plugin::OutputDescriptor::SampleType();
fazekasgy@37 192 }
fazekasgy@37 193
fazekasgy@37 194 Vamp::Plugin::InputDomain
fazekasgy@37 195 PyTypeInterface::PyValue_To_InputDomain(PyObject* pyValue) const
fazekasgy@37 196 {
fazekasgy@37 197 /// convert simulated enum values { TimeDomain,FrequencyDomain }
fazekasgy@37 198 if (PyInt_CheckExact(pyValue)) {
fazekasgy@37 199 long lst = PyInt_AS_LONG(pyValue);
fazekasgy@37 200 if (lst!=0 && lst!=1) {
fazekasgy@37 201 setValueError("Overflow error. InputDomain has to be one of { TimeDomain,FrequencyDomain }\n(an integer in the range of 0..1) or a string value naming the type.",m_strict);
fazekasgy@37 202 return Vamp::Plugin::InputDomain();
fazekasgy@37 203 }
fazekasgy@37 204 return (Vamp::Plugin::InputDomain) lst;
fazekasgy@37 205 }
fazekasgy@37 206
fazekasgy@37 207 /// convert string (backward compatible)
fazekasgy@37 208 if (PyString_CheckExact(pyValue)) {
fazekasgy@37 209 Vamp::Plugin::InputDomain id;
Chris@71 210 id = (m_conv.PyValue_To_String(pyValue) == "FrequencyDomain")?Vamp::Plugin::FrequencyDomain:Vamp::Plugin::TimeDomain;
Chris@71 211 if (m_conv.error)
fazekasgy@37 212 {
fazekasgy@37 213 std::string msg = "Unexpected value passed as SampleType. Must be one of { TimeDomain,FrequencyDomain }\n(an integer in the range of 0..1) or a string value naming the type.";
fazekasgy@37 214 setValueError(msg,m_strict);
fazekasgy@37 215 return Vamp::Plugin::InputDomain();
fazekasgy@37 216 }
fazekasgy@37 217 return id;
fazekasgy@37 218 }
fazekasgy@37 219
fazekasgy@37 220 /// give up
fazekasgy@37 221 std::string msg = "Unsupported return type. Expected one of { TimeDomain,FrequencyDomain }\n(an integer in the range of 0..1) or a string value naming the type.";
fazekasgy@37 222 setValueError(msg,m_strict);
fazekasgy@37 223 #ifdef _DEBUG
fazekasgy@37 224 cerr << "PyTypeInterface::PyValue_To_InputDomain failed. Error: " << msg << endl;
fazekasgy@37 225 #endif
fazekasgy@37 226 return Vamp::Plugin::InputDomain();
fazekasgy@37 227 }
fazekasgy@37 228
Chris@71 229 /* Convert Sample Buffers to Python */
Chris@71 230
Chris@71 231 /// passing the sample buffers as builtin python lists
Chris@71 232 /// Optimization: using fast sequence protocol
Chris@72 233 PyObject*
Chris@71 234 PyTypeInterface::InputBuffers_As_PythonLists(const float *const *inputBuffers,const size_t& channels, const size_t& blockSize, const Vamp::Plugin::InputDomain& dtype)
Chris@71 235 {
Chris@71 236 //create a list of lists (new references)
Chris@71 237 PyObject *pyChannelList = PyList_New((Py_ssize_t) channels);
Chris@71 238
Chris@71 239 // Pack samples into a Python List Object
Chris@71 240 // pyFloat/pyComplex types will always be new references,
Chris@71 241 // they will be freed when the lists are deallocated.
Chris@71 242
Chris@71 243 PyObject **pyChannelListArray = PySequence_Fast_ITEMS(pyChannelList);
Chris@71 244 for (size_t i=0; i < channels; ++i) {
Chris@71 245
Chris@71 246 size_t arraySize;
Chris@71 247 if (dtype==Vamp::Plugin::FrequencyDomain)
Chris@71 248 arraySize = (blockSize / 2) + 1; //blockSize + 2; if cplx list isn't used
Chris@71 249 else
Chris@71 250 arraySize = blockSize;
Chris@71 251
Chris@71 252 PyObject *pySampleList = PyList_New((Py_ssize_t) arraySize);
Chris@71 253 PyObject **pySampleListArray = PySequence_Fast_ITEMS(pySampleList);
Chris@71 254
Chris@71 255 // Note: passing a complex list crashes the C-style plugin
Chris@71 256 // when it tries to convert it to a numpy array directly.
Chris@71 257 // This plugin will be obsolete, but we have to find a way
Chris@71 258 // to prevent such crash: possibly a numpy bug,
Chris@71 259 // works fine above 1.0.4
Chris@71 260
Chris@71 261 switch (dtype) //(Vamp::Plugin::TimeDomain)
Chris@71 262 {
Chris@71 263 case Vamp::Plugin::TimeDomain :
Chris@71 264
Chris@71 265 for (size_t j = 0; j < arraySize; ++j) {
Chris@71 266 PyObject *pyFloat=PyFloat_FromDouble(
Chris@71 267 (double) inputBuffers[i][j]);
Chris@71 268 pySampleListArray[j] = pyFloat;
Chris@71 269 }
Chris@71 270 break;
Chris@71 271
Chris@71 272 case Vamp::Plugin::FrequencyDomain :
Chris@71 273
Chris@71 274 size_t k = 0;
Chris@71 275 for (size_t j = 0; j < arraySize; ++j) {
Chris@71 276 PyObject *pyComplex=PyComplex_FromDoubles(
Chris@71 277 (double) inputBuffers[i][k],
Chris@71 278 (double) inputBuffers[i][k+1]);
Chris@71 279 pySampleListArray[j] = pyComplex;
Chris@71 280 k += 2;
Chris@71 281 }
Chris@71 282 break;
Chris@71 283
Chris@71 284 }
Chris@71 285 pyChannelListArray[i] = pySampleList;
Chris@71 286 }
Chris@71 287 return pyChannelList;
Chris@71 288 }
Chris@71 289
Chris@71 290 /// numpy buffer interface: passing the sample buffers as shared memory buffers
Chris@71 291 /// Optimization: using sequence protocol for creating the buffer list
Chris@72 292 PyObject*
Chris@71 293 PyTypeInterface::InputBuffers_As_SharedMemoryList(const float *const *inputBuffers,const size_t& channels, const size_t& blockSize, const Vamp::Plugin::InputDomain& dtype)
Chris@71 294 {
Chris@71 295 //create a list of buffers (returns new references)
Chris@71 296 PyObject *pyChannelList = PyList_New((Py_ssize_t) channels);
Chris@71 297 PyObject **pyChannelListArray = PySequence_Fast_ITEMS(pyChannelList);
Chris@71 298
Chris@71 299 // Expose memory using the Buffer Interface.
Chris@71 300 // This will pass a pointer which can be recasted in Python code
Chris@71 301 // as complex or float array using Numpy's frombuffer() method
Chris@71 302 // (this will not copy values just keep the starting adresses
Chris@71 303 // for each channel in a list)
Chris@71 304 Py_ssize_t bufferSize;
Chris@71 305
Chris@71 306 if (dtype==Vamp::Plugin::FrequencyDomain)
Chris@71 307 bufferSize = (Py_ssize_t) sizeof(float) * (blockSize+2);
Chris@71 308 else
Chris@71 309 bufferSize = (Py_ssize_t) sizeof(float) * blockSize;
Chris@71 310
Chris@71 311 for (size_t i=0; i < channels; ++i) {
Chris@71 312 PyObject *pyBuffer = PyBuffer_FromMemory
Chris@71 313 ((void *) (float *) inputBuffers[i],bufferSize);
Chris@71 314 pyChannelListArray[i] = pyBuffer;
Chris@71 315 }
Chris@71 316 return pyChannelList;
Chris@71 317 }
Chris@71 318
Chris@71 319
Chris@71 320 /// numpy array interface: passing the sample buffers as 2D numpy array
Chris@71 321 /// Optimization: using array API (needs numpy headers)
Chris@71 322 #ifdef HAVE_NUMPY
Chris@72 323 PyObject*
Chris@71 324 PyTypeInterface::InputBuffers_As_NumpyArray(const float *const *inputBuffers,const size_t& channels, const size_t& blockSize, const Vamp::Plugin::InputDomain& dtype)
Chris@71 325 {
Chris@71 326 /*
Chris@71 327 NOTE: We create a list of 1D Numpy arrays for each channel instead
Chris@71 328 of a matrix, because the address space of inputBuffers doesn't seem
Chris@71 329 to be continuous. Although the array strides could be calculated for
Chris@71 330 2 channels (i.e. inputBuffers[1] - inputBuffers[0]) i'm not sure
Chris@71 331 if this can be trusted, especially for more than 2 channels.
Chris@71 332
Chris@71 333 cerr << "First channel: " << inputBuffers[0][0] << " address: " << inputBuffers[0] << endl;
Chris@71 334 if (channels == 2)
Chris@71 335 cerr << "Second channel: " << inputBuffers[1][0] << " address: " << inputBuffers[1] << endl;
Chris@71 336
Chris@71 337 */
Chris@71 338
Chris@71 339 // create a list of arrays (returns new references)
Chris@71 340 PyObject *pyChannelList = PyList_New((Py_ssize_t) channels);
Chris@71 341 PyObject **pyChannelListArray = PySequence_Fast_ITEMS(pyChannelList);
Chris@71 342
Chris@71 343 // Expose memory using the Numpy Array Interface.
Chris@71 344 // This will wrap an array objects around the data.
Chris@71 345 // (will not copy values just steal the starting adresses)
Chris@71 346
Chris@71 347 int arraySize, typenum;
Chris@71 348
Chris@71 349 switch (dtype)
Chris@71 350 {
Chris@71 351 case Vamp::Plugin::TimeDomain :
Chris@71 352 typenum = dtype_float32; //NPY_FLOAT;
Chris@71 353 arraySize = (int) blockSize;
Chris@71 354 break;
Chris@71 355
Chris@71 356 case Vamp::Plugin::FrequencyDomain :
Chris@71 357 typenum = dtype_complex64; //NPY_CFLOAT;
Chris@71 358 arraySize = (int) (blockSize / 2) + 1;
Chris@71 359 break;
Chris@71 360
Chris@71 361 default :
Chris@71 362 cerr << "PyTypeInterface::InputBuffers_As_NumpyArray: Error: Unsupported numpy array data type." << endl;
Chris@71 363 return pyChannelList;
Chris@71 364 }
Chris@71 365
Chris@71 366 // size for each dimension
Chris@71 367 npy_intp ndims[1]={arraySize};
Chris@71 368
Chris@71 369 for (size_t i=0; i < channels; ++i) {
Chris@71 370 PyObject *pyChannelArray =
Chris@71 371 //args: (dimensions, size in each dim, type kind, pointer to continuous array)
Chris@71 372 PyArray_SimpleNewFromData(1, ndims, typenum, (void*) inputBuffers[i]);
Chris@71 373 // make it read-only: set all flags to false except NPY_C_CONTIGUOUS
Chris@71 374 //!!! what about NPY_ARRAY_OWNDATA?
Chris@71 375 PyArray_CLEARFLAGS((PyArrayObject *)pyChannelArray, 0xff);
Chris@71 376 PyArray_ENABLEFLAGS((PyArrayObject *)pyChannelArray, NPY_ARRAY_C_CONTIGUOUS);
Chris@71 377 pyChannelListArray[i] = pyChannelArray;
Chris@71 378 }
Chris@71 379 return pyChannelList;
Chris@71 380 }
Chris@71 381 #endif
fazekasgy@37 382
fazekasgy@37 383 /// OutputDescriptor
fazekasgy@37 384 void
fazekasgy@37 385 PyTypeInterface::SetValue(Vamp::Plugin::OutputDescriptor& od, std::string& key, PyObject* pyValue) const
fazekasgy@37 386 {
fazekasgy@37 387 switch (outKeys[key])
fazekasgy@37 388 {
fazekasgy@37 389 case o::not_found:
fazekasgy@37 390 setValueError("Unknown key in Vamp OutputDescriptor",m_strict);
fazekasgy@37 391 cerr << "Unknown key in Vamp OutputDescriptor: " << key << endl;
fazekasgy@37 392 break;
fazekasgy@37 393 case o::identifier:
fazekasgy@37 394 _convert(pyValue,od.identifier);
fazekasgy@37 395 break;
fazekasgy@37 396 case o::name:
fazekasgy@37 397 _convert(pyValue,od.name);
fazekasgy@37 398 break;
fazekasgy@37 399 case o::description:
fazekasgy@37 400 _convert(pyValue,od.description);
fazekasgy@37 401 break;
fazekasgy@37 402 case o::unit:
fazekasgy@37 403 _convert(pyValue,od.unit);
fazekasgy@37 404 break;
fazekasgy@37 405 case o::hasFixedBinCount:
fazekasgy@37 406 _convert(pyValue,od.hasFixedBinCount);
fazekasgy@37 407 break;
fazekasgy@37 408 case o::binCount:
fazekasgy@37 409 _convert(pyValue,od.binCount);
fazekasgy@37 410 break;
fazekasgy@37 411 case o::binNames:
fazekasgy@37 412 _convert(pyValue,od.binNames);
fazekasgy@37 413 break;
fazekasgy@37 414 case o::hasKnownExtents:
fazekasgy@37 415 _convert(pyValue,od.hasKnownExtents);
fazekasgy@37 416 break;
fazekasgy@37 417 case o::minValue:
fazekasgy@37 418 _convert(pyValue,od.minValue);
fazekasgy@37 419 break;
fazekasgy@37 420 case o::maxValue:
fazekasgy@37 421 _convert(pyValue,od.maxValue);
fazekasgy@37 422 break;
fazekasgy@37 423 case o::isQuantized:
fazekasgy@37 424 _convert(pyValue,od.isQuantized);
fazekasgy@37 425 break;
fazekasgy@37 426 case o::quantizeStep:
fazekasgy@37 427 _convert(pyValue,od.quantizeStep);
fazekasgy@37 428 break;
fazekasgy@37 429 case o::sampleType:
fazekasgy@37 430 _convert(pyValue,od.sampleType);
fazekasgy@37 431 break;
fazekasgy@37 432 case o::sampleRate:
fazekasgy@37 433 _convert(pyValue,od.sampleRate);
fazekasgy@37 434 break;
fazekasgy@37 435 case o::hasDuration:
fazekasgy@37 436 _convert(pyValue,od.hasDuration);
fazekasgy@37 437 break;
fazekasgy@37 438 default:
fazekasgy@37 439 setValueError("Unknown key in Vamp OutputDescriptor",m_strict);
fazekasgy@37 440 cerr << "Invalid key in Vamp OutputDescriptor: " << key << endl;
fazekasgy@37 441 }
fazekasgy@37 442 }
fazekasgy@37 443
fazekasgy@37 444 /// ParameterDescriptor
fazekasgy@37 445 void
fazekasgy@37 446 PyTypeInterface::SetValue(Vamp::Plugin::ParameterDescriptor& pd, std::string& key, PyObject* pyValue) const
fazekasgy@37 447 {
fazekasgy@37 448 switch (parmKeys[key])
fazekasgy@37 449 {
fazekasgy@37 450 case p::not_found :
fazekasgy@37 451 setValueError("Unknown key in Vamp ParameterDescriptor",m_strict);
fazekasgy@37 452 cerr << "Unknown key in Vamp ParameterDescriptor: " << key << endl;
fazekasgy@37 453 break;
fazekasgy@37 454 case p::identifier:
fazekasgy@37 455 _convert(pyValue,pd.identifier);
fazekasgy@37 456 break;
fazekasgy@37 457 case p::name:
fazekasgy@37 458 _convert(pyValue,pd.name);
fazekasgy@37 459 break;
fazekasgy@37 460 case p::description:
fazekasgy@37 461 _convert(pyValue,pd.description);
fazekasgy@37 462 break;
fazekasgy@37 463 case p::unit:
fazekasgy@37 464 _convert(pyValue,pd.unit);
fazekasgy@37 465 break;
fazekasgy@37 466 case p::minValue:
fazekasgy@37 467 _convert(pyValue,pd.minValue);
fazekasgy@37 468 break;
fazekasgy@37 469 case p::maxValue:
fazekasgy@37 470 _convert(pyValue,pd.maxValue);
fazekasgy@37 471 break;
fazekasgy@37 472 case p::defaultValue:
fazekasgy@37 473 _convert(pyValue,pd.defaultValue);
fazekasgy@37 474 break;
fazekasgy@37 475 case p::isQuantized:
fazekasgy@37 476 _convert(pyValue,pd.isQuantized);
fazekasgy@37 477 break;
fazekasgy@37 478 case p::quantizeStep:
fazekasgy@37 479 _convert(pyValue,pd.quantizeStep);
fazekasgy@37 480 break;
gyorgyf@62 481 case p::valueNames:
gyorgyf@62 482 _convert(pyValue,pd.valueNames);
gyorgyf@62 483 break;
fazekasgy@37 484 default :
fazekasgy@37 485 setValueError("Unknown key in Vamp ParameterDescriptor",m_strict);
fazekasgy@37 486 cerr << "Invalid key in Vamp ParameterDescriptor: " << key << endl;
fazekasgy@37 487 }
fazekasgy@37 488 }
fazekasgy@37 489
fazekasgy@37 490 /// Feature (it's like a Descriptor)
fazekasgy@37 491 bool
fazekasgy@37 492 PyTypeInterface::SetValue(Vamp::Plugin::Feature& feature, std::string& key, PyObject* pyValue) const
fazekasgy@37 493 {
fazekasgy@37 494 bool found = true;
fazekasgy@37 495 switch (ffKeys[key])
fazekasgy@37 496 {
fazekasgy@37 497 case unknown :
fazekasgy@37 498 setValueError("Unknown key in Vamp Feature",m_strict);
fazekasgy@37 499 cerr << "Unknown key in Vamp Feature: " << key << endl;
fazekasgy@37 500 found = false;
fazekasgy@37 501 break;
fazekasgy@37 502 case hasTimestamp:
fazekasgy@37 503 _convert(pyValue,feature.hasTimestamp);
fazekasgy@37 504 break;
fazekasgy@37 505 case timestamp:
fazekasgy@37 506 _convert(pyValue,feature.timestamp);
fazekasgy@37 507 break;
fazekasgy@37 508 case hasDuration:
fazekasgy@37 509 _convert(pyValue,feature.hasDuration);
fazekasgy@37 510 break;
fazekasgy@37 511 case duration:
fazekasgy@37 512 _convert(pyValue,feature.duration);
fazekasgy@37 513 break;
fazekasgy@37 514 case values:
fazekasgy@37 515 _convert(pyValue,feature.values);
fazekasgy@37 516 break;
fazekasgy@37 517 case label:
fazekasgy@37 518 _convert(pyValue,feature.label);
fazekasgy@37 519 break;
fazekasgy@37 520 default:
fazekasgy@37 521 setValueError("Unknown key in Vamp Feature",m_strict);
fazekasgy@37 522 found = false;
fazekasgy@37 523 }
fazekasgy@37 524 return found;
fazekasgy@37 525 }
fazekasgy@37 526
fazekasgy@37 527
Chris@71 528 /* Error handling */
fazekasgy@37 529
fazekasgy@37 530 void
fazekasgy@37 531 PyTypeInterface::setValueError (std::string message, bool strict) const
fazekasgy@37 532 {
fazekasgy@37 533 m_error = true;
fazekasgy@37 534 m_errorQueue.push(ValueError(message,strict));
fazekasgy@37 535 }
fazekasgy@37 536
fazekasgy@37 537 /// return a reference to the last error or creates a new one.
Chris@71 538 ValueError&
fazekasgy@37 539 PyTypeInterface::lastError() const
fazekasgy@37 540 {
fazekasgy@37 541 m_error = false;
fazekasgy@37 542 if (!m_errorQueue.empty()) return m_errorQueue.back();
fazekasgy@37 543 else {
fazekasgy@37 544 m_errorQueue.push(ValueError("Type conversion error.",m_strict));
fazekasgy@37 545 return m_errorQueue.back();
fazekasgy@37 546 }
fazekasgy@37 547 }
fazekasgy@37 548
fazekasgy@37 549 /// helper function to iterate over the error message queue:
fazekasgy@37 550 /// pops the oldest item
Chris@71 551 ValueError
fazekasgy@37 552 PyTypeInterface::getError() const
fazekasgy@37 553 {
fazekasgy@37 554 if (!m_errorQueue.empty()) {
Chris@71 555 ValueError e = m_errorQueue.front();
fazekasgy@37 556 m_errorQueue.pop();
fazekasgy@37 557 if (m_errorQueue.empty()) m_error = false;
fazekasgy@37 558 return e;
fazekasgy@37 559 }
fazekasgy@37 560 else {
fazekasgy@37 561 m_error = false;
Chris@71 562 return ValueError();
fazekasgy@37 563 }
fazekasgy@37 564 }
fazekasgy@37 565
Chris@71 566 /* Utilities */
fazekasgy@37 567
fazekasgy@37 568 bool
fazekasgy@37 569 PyTypeInterface::initMaps() const
fazekasgy@37 570 {
fazekasgy@37 571
fazekasgy@37 572 if (isMapInitialised) return true;
fazekasgy@37 573
fazekasgy@37 574 outKeys["identifier"] = o::identifier;
fazekasgy@37 575 outKeys["name"] = o::name;
fazekasgy@37 576 outKeys["description"] = o::description;
fazekasgy@37 577 outKeys["unit"] = o::unit;
fazekasgy@37 578 outKeys["hasFixedBinCount"] = o::hasFixedBinCount;
fazekasgy@37 579 outKeys["binCount"] = o::binCount;
fazekasgy@37 580 outKeys["binNames"] = o::binNames;
fazekasgy@37 581 outKeys["hasKnownExtents"] = o::hasKnownExtents;
fazekasgy@37 582 outKeys["minValue"] = o::minValue;
fazekasgy@37 583 outKeys["maxValue"] = o::maxValue;
fazekasgy@37 584 outKeys["isQuantized"] = o::isQuantized;
fazekasgy@37 585 outKeys["quantizeStep"] = o::quantizeStep;
fazekasgy@37 586 outKeys["sampleType"] = o::sampleType;
fazekasgy@37 587 outKeys["sampleRate"] = o::sampleRate;
fazekasgy@37 588 outKeys["hasDuration"] = o::hasDuration;
fazekasgy@37 589
fazekasgy@37 590 sampleKeys["OneSamplePerStep"] = OneSamplePerStep;
fazekasgy@37 591 sampleKeys["FixedSampleRate"] = FixedSampleRate;
fazekasgy@37 592 sampleKeys["VariableSampleRate"] = VariableSampleRate;
fazekasgy@37 593
fazekasgy@37 594 ffKeys["hasTimestamp"] = hasTimestamp;
fazekasgy@37 595 ffKeys["timestamp"] = timestamp; // this is the correct one
fazekasgy@37 596 ffKeys["timeStamp"] = timestamp; // backward compatible
fazekasgy@37 597 ffKeys["hasDuration"] = hasDuration;
fazekasgy@37 598 ffKeys["duration"] = duration;
fazekasgy@37 599 ffKeys["values"] = values;
fazekasgy@37 600 ffKeys["label"] = label;
fazekasgy@37 601
fazekasgy@37 602 parmKeys["identifier"] = p::identifier;
fazekasgy@37 603 parmKeys["name"] = p::name;
fazekasgy@37 604 parmKeys["description"] = p::description;
fazekasgy@37 605 parmKeys["unit"] = p::unit;
fazekasgy@37 606 parmKeys["minValue"] = p::minValue;
fazekasgy@37 607 parmKeys["maxValue"] = p::maxValue;
fazekasgy@37 608 parmKeys["defaultValue"] = p::defaultValue;
fazekasgy@37 609 parmKeys["isQuantized"] = p::isQuantized;
fazekasgy@37 610 parmKeys["quantizeStep"] = p::quantizeStep;
gyorgyf@62 611 parmKeys["valueNames"] = p::valueNames;
fazekasgy@37 612
fazekasgy@37 613 isMapInitialised = true;
fazekasgy@37 614 return true;
fazekasgy@37 615 }