Mercurial > hg > vampy
comparison PyTypeInterface.h @ 71:40a01bb24209 vampyhost
Pull apart some type conversion classes for possible use in VamPy Host
author | Chris Cannam |
---|---|
date | Thu, 20 Nov 2014 13:02:50 +0000 |
parents | 5664fe298af2 |
children | ffaa1fb3d7de |
comparison
equal
deleted
inserted
replaced
70:6c755f3e1173 | 71:40a01bb24209 |
---|---|
10 | 10 |
11 */ | 11 */ |
12 | 12 |
13 /* | 13 /* |
14 PyTypeInterface: Type safe conversion utilities between Python types | 14 PyTypeInterface: Type safe conversion utilities between Python types |
15 and basic C/C++ types and Vamp API types. | 15 and Vamp API types. See PyTypeConversions for basic C/C++ types. |
16 */ | 16 */ |
17 | 17 |
18 #ifndef _PY_TYPE_INTERFACE_H_ | 18 #ifndef _PY_TYPE_INTERFACE_H_ |
19 #define _PY_TYPE_INTERFACE_H_ | 19 #define _PY_TYPE_INTERFACE_H_ |
20 #include <Python.h> | 20 #include <Python.h> |
23 #define NO_IMPORT_ARRAY | 23 #define NO_IMPORT_ARRAY |
24 #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION | 24 #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION |
25 #include "numpy/arrayobject.h" | 25 #include "numpy/arrayobject.h" |
26 #endif | 26 #endif |
27 #include "PyExtensionModule.h" | 27 #include "PyExtensionModule.h" |
28 #include "PyTypeConversions.h" | |
28 #include <vector> | 29 #include <vector> |
29 #include <queue> | 30 #include <queue> |
30 #include <string> | 31 #include <string> |
31 #include <sstream> | 32 #include <sstream> |
32 #include "vamp-sdk/Plugin.h" | 33 #include "vamp-sdk/Plugin.h" |
33 | 34 |
34 using std::cerr; | 35 using std::cerr; |
35 using std::endl; | 36 using std::endl; |
36 | |
37 #ifdef HAVE_NUMPY | |
38 enum eArrayDataType { | |
39 dtype_float32 = (int) NPY_FLOAT, | |
40 dtype_complex64 = (int) NPY_CFLOAT | |
41 }; | |
42 #endif | |
43 | 37 |
44 namespace o { | 38 namespace o { |
45 enum eOutDescriptors { | 39 enum eOutDescriptors { |
46 not_found, | 40 not_found, |
47 identifier, | 41 identifier, |
93 duration, | 87 duration, |
94 values, | 88 values, |
95 label | 89 label |
96 }; | 90 }; |
97 | 91 |
98 /* C++ mapping of PyNone Type */ | |
99 struct NoneType {}; | |
100 | |
101 class PyTypeInterface | 92 class PyTypeInterface |
102 { | 93 { |
94 PyTypeConversions m_conv; | |
95 | |
103 public: | 96 public: |
104 PyTypeInterface(); | 97 PyTypeInterface(); |
105 ~PyTypeInterface(); | 98 ~PyTypeInterface(); |
106 | 99 |
107 // Data | |
108 class ValueError | |
109 { | |
110 public: | |
111 ValueError() {} | |
112 ValueError(std::string m, bool s) : message(m),strict(s) {} | |
113 std::string location; | |
114 std::string message; | |
115 bool strict; | |
116 std::string str() const { | |
117 return (location.empty()) ? message : message + "\nLocation: " + location;} | |
118 void print() const { cerr << str() << endl; } | |
119 template<typename V> ValueError &operator<< (const V& v) | |
120 { | |
121 std::ostringstream ss; | |
122 ss << v; | |
123 location += ss.str(); | |
124 return *this; | |
125 } | |
126 }; | |
127 | |
128 // Utilities | 100 // Utilities |
129 void setStrictTypingFlag(bool b) {m_strict = b;} | 101 void setStrictTypingFlag(bool b) {m_strict = b; m_conv.setStrictTypingFlag(b);} |
130 void setNumpyInstalled(bool b) {m_numpyInstalled = b;} | 102 void setNumpyInstalled(bool b) {m_numpyInstalled = b; m_conv.setNumpyInstalled(b); } |
131 ValueError getError() const; | 103 ValueError getError() const; |
132 std::string PyValue_Get_TypeName(PyObject*) const; | 104 std::string PyValue_Get_TypeName(PyObject*) const; |
133 bool initMaps() const; | 105 bool initMaps() const; |
134 | 106 |
135 // Basic type conversion: Python to C++ | |
136 float PyValue_To_Float(PyObject*) const; | |
137 size_t PyValue_To_Size_t(PyObject*) const; | |
138 bool PyValue_To_Bool(PyObject*) const; | |
139 std::string PyValue_To_String(PyObject*) const; | |
140 long PyValue_To_Long(PyObject*) const; | |
141 // int PyValue_To_Int(PyObject* pyValue) const; | |
142 | |
143 | |
144 // C++ to Python | |
145 PyObject *PyValue_From_CValue(const char*) const; | |
146 PyObject *PyValue_From_CValue(const std::string& x) const { return PyValue_From_CValue(x.c_str()); } | |
147 PyObject *PyValue_From_CValue(size_t) const; | |
148 PyObject *PyValue_From_CValue(double) const; | |
149 PyObject *PyValue_From_CValue(float x) const { return PyValue_From_CValue((double)x); } | |
150 PyObject *PyValue_From_CValue(bool) const; | |
151 | |
152 // Sequence types | |
153 std::vector<std::string> PyValue_To_StringVector (PyObject*) const; | |
154 std::vector<float> PyValue_To_FloatVector (PyObject*) const; | |
155 std::vector<float> PyList_To_FloatVector (PyObject*) const; | |
156 | |
157 // Input buffers to Python | 107 // Input buffers to Python |
158 PyObject* InputBuffers_As_PythonLists(const float *const *inputBuffers,const size_t& channels, const size_t& blockSize, const Vamp::Plugin::InputDomain& dtype); | 108 PyObject* InputBuffers_As_PythonLists(const float *const *inputBuffers,const size_t& channels, const size_t& blockSize, const Vamp::Plugin::InputDomain& dtype); |
159 PyObject* InputBuffers_As_SharedMemoryList(const float *const *inputBuffers,const size_t& channels, const size_t& blockSize, const Vamp::Plugin::InputDomain& dtype); | 109 PyObject* InputBuffers_As_SharedMemoryList(const float *const *inputBuffers,const size_t& channels, const size_t& blockSize, const Vamp::Plugin::InputDomain& dtype); |
160 | 110 |
161 // Numpy types | 111 // Numpy types |
162 #ifdef HAVE_NUMPY | 112 #ifdef HAVE_NUMPY |
163 std::vector<float> PyArray_To_FloatVector (PyObject *pyValue) const; | |
164 PyObject* InputBuffers_As_NumpyArray(const float *const *inputBuffers, const size_t&, const size_t&, const Vamp::Plugin::InputDomain& dtype); | 113 PyObject* InputBuffers_As_NumpyArray(const float *const *inputBuffers, const size_t&, const size_t&, const Vamp::Plugin::InputDomain& dtype); |
165 #endif | 114 #endif |
166 | 115 |
167 | 116 /* Template functions */ |
168 | |
169 | |
170 /* Template functions */ | |
171 | 117 |
172 | 118 |
173 /// Common wrappers to set values in Vamp API structs. (to be used in template functions) | 119 /// Common wrappers to set values in Vamp API structs. (to be used in template functions) |
174 void SetValue(Vamp::Plugin::OutputDescriptor& od, std::string& key, PyObject* pyValue) const; | 120 void SetValue(Vamp::Plugin::OutputDescriptor& od, std::string& key, PyObject* pyValue) const; |
175 void SetValue(Vamp::Plugin::ParameterDescriptor& od, std::string& key, PyObject* pyValue) const; | 121 void SetValue(Vamp::Plugin::ParameterDescriptor& od, std::string& key, PyObject* pyValue) const; |
209 RET rd; | 155 RET rd; |
210 | 156 |
211 //Python Dictionary Iterator: | 157 //Python Dictionary Iterator: |
212 while (PyDict_Next(pyDict, &pyPos, &pyKey, &pyDictValue)) | 158 while (PyDict_Next(pyDict, &pyPos, &pyKey, &pyDictValue)) |
213 { | 159 { |
214 std::string key = PyValue_To_String(pyKey); | 160 std::string key = m_conv.PyValue_To_String(pyKey); |
215 #ifdef _DEBUG_VALUES | 161 #ifdef _DEBUG_VALUES |
216 cerr << "key: '" << key << "' value: '" << PyValue_To_String(pyDictValue) << "' " << endl; | 162 cerr << "key: '" << key << "' value: '" << m_conv.PyValue_To_String(pyDictValue) << "' " << endl; |
217 #endif | 163 #endif |
218 SetValue(rd,key,pyDictValue); | 164 SetValue(rd,key,pyDictValue); |
219 if (m_error) { | 165 if (m_error) { |
220 errors++; | 166 errors++; |
221 lastError() << "attribute '" << key << "'";// << " of " << getDescriptorId(rd); | 167 lastError() << "attribute '" << key << "'";// << " of " << getDescriptorId(rd); |
294 cerr << "PyTypeInterface::PyValue_To_VampList failed. Expected iterable return type." << endl; | 240 cerr << "PyTypeInterface::PyValue_To_VampList failed. Expected iterable return type." << endl; |
295 #endif | 241 #endif |
296 | 242 |
297 } | 243 } |
298 | 244 |
299 /// Convert DTYPE type 1D NumpyArray to std::vector<RET> | |
300 template<typename RET, typename DTYPE> | |
301 std::vector<RET> PyArray_Convert(void* raw_data_ptr, long length, size_t strides) const | |
302 { | |
303 std::vector<RET> rValue; | |
304 | |
305 /// check if the array is continuous, if not use strides info | |
306 if (sizeof(DTYPE)!=strides) { | |
307 #ifdef _DEBUG_VALUES | |
308 cerr << "Warning: discontinuous numpy array. Strides: " << strides << " bytes. sizeof(dtype): " << sizeof(DTYPE) << endl; | |
309 #endif | |
310 char* data = (char*) raw_data_ptr; | |
311 for (long i = 0; i<length; ++i){ | |
312 rValue.push_back((RET)(*((DTYPE*)data))); | |
313 #ifdef _DEBUG_VALUES | |
314 cerr << "value: " << (RET)(*((DTYPE*)data)) << endl; | |
315 #endif | |
316 data+=strides; | |
317 } | |
318 return rValue; | |
319 } | |
320 | |
321 DTYPE* data = (DTYPE*) raw_data_ptr; | |
322 for (long i = 0; i<length; ++i){ | |
323 #ifdef _DEBUG_VALUES | |
324 cerr << "value: " << (RET)data[i] << endl; | |
325 #endif | |
326 rValue.push_back((RET)data[i]); | |
327 } | |
328 return rValue; | |
329 } | |
330 | |
331 /// this is a special case. numpy.float64 has an array interface but no array descriptor | |
332 inline std::vector<float> PyArray0D_Convert(PyArrayInterface *ai) const | |
333 { | |
334 std::vector<float> rValue; | |
335 if ((ai->typekind) == *"f") | |
336 rValue.push_back((float)*(double*)(ai->data)); | |
337 else { | |
338 setValueError("Unsupported NumPy data type.",m_strict); | |
339 return rValue; | |
340 } | |
341 #ifdef _DEBUG_VALUES | |
342 cerr << "value: " << rValue[0] << endl; | |
343 #endif | |
344 return rValue; | |
345 } | |
346 | |
347 //Vamp specific types | 245 //Vamp specific types |
348 Vamp::Plugin::FeatureSet PyValue_To_FeatureSet(PyObject*) const; | 246 Vamp::Plugin::FeatureSet PyValue_To_FeatureSet(PyObject*) const; |
349 inline void PyValue_To_rValue(PyObject *pyValue, Vamp::Plugin::FeatureSet &r) const | 247 inline void PyValue_To_rValue(PyObject *pyValue, Vamp::Plugin::FeatureSet &r) const |
350 { r = this->PyValue_To_FeatureSet(pyValue); } | 248 { r = this->PyValue_To_FeatureSet(pyValue); } |
351 | 249 |
357 | 255 |
358 Vamp::Plugin::InputDomain PyValue_To_InputDomain(PyObject*) const; | 256 Vamp::Plugin::InputDomain PyValue_To_InputDomain(PyObject*) const; |
359 inline void PyValue_To_rValue(PyObject *pyValue, Vamp::Plugin::InputDomain &r) const | 257 inline void PyValue_To_rValue(PyObject *pyValue, Vamp::Plugin::InputDomain &r) const |
360 { r = this->PyValue_To_InputDomain(pyValue); } | 258 { r = this->PyValue_To_InputDomain(pyValue); } |
361 | 259 |
362 | |
363 /* Overloaded PyValue_To_rValue() to support generic functions */ | 260 /* Overloaded PyValue_To_rValue() to support generic functions */ |
364 inline void PyValue_To_rValue(PyObject *pyValue, float &defValue) const | 261 inline void PyValue_To_rValue(PyObject *pyValue, float &defValue) const |
365 { float tmp = this->PyValue_To_Float(pyValue); | 262 { float tmp = m_conv.PyValue_To_Float(pyValue); |
366 if(!m_error) defValue = tmp; } | 263 if(!m_error) defValue = tmp; } |
367 inline void PyValue_To_rValue(PyObject *pyValue, size_t &defValue) const | 264 inline void PyValue_To_rValue(PyObject *pyValue, size_t &defValue) const |
368 { size_t tmp = this->PyValue_To_Size_t(pyValue); | 265 { size_t tmp = m_conv.PyValue_To_Size_t(pyValue); |
369 if(!m_error) defValue = tmp; } | 266 if(!m_error) defValue = tmp; } |
370 inline void PyValue_To_rValue(PyObject *pyValue, bool &defValue) const | 267 inline void PyValue_To_rValue(PyObject *pyValue, bool &defValue) const |
371 { bool tmp = this->PyValue_To_Bool(pyValue); | 268 { bool tmp = m_conv.PyValue_To_Bool(pyValue); |
372 if(!m_error) defValue = tmp; } | 269 if(!m_error) defValue = tmp; } |
373 inline void PyValue_To_rValue(PyObject *pyValue, std::string &defValue) const | 270 inline void PyValue_To_rValue(PyObject *pyValue, std::string &defValue) const |
374 { std::string tmp = this->PyValue_To_String(pyValue); | 271 { std::string tmp = m_conv.PyValue_To_String(pyValue); |
375 if(!m_error) defValue = tmp; } | 272 if(!m_error) defValue = tmp; } |
376 /*used by templates where we expect no return value, if there is one it will be ignored*/ | 273 /*used by templates where we expect no return value, if there is one it will be ignored*/ |
377 inline void PyValue_To_rValue(PyObject *pyValue, NoneType &defValue) const | 274 inline void PyValue_To_rValue(PyObject *pyValue, NoneType &defValue) const |
378 { if (m_strict && pyValue != Py_None) | 275 { if (m_strict && pyValue != Py_None) |
379 setValueError("Strict conversion error: Expected 'None' type.",m_strict); | 276 setValueError("Strict conversion error: Expected 'None' type.",m_strict); |
380 } | 277 } |
381 | 278 |
382 /* convert sequence types to Vamp List types */ | 279 /* convert sequence types to Vamp List types */ |
383 inline void PyValue_To_rValue(PyObject *pyValue, Vamp::Plugin::OutputList &r) const | 280 inline void PyValue_To_rValue(PyObject *pyValue, Vamp::Plugin::OutputList &r) const |
384 { r = this->PyValue_To_VampList<Vamp::Plugin::OutputList,Vamp::Plugin::OutputDescriptor>(pyValue); } | 281 { r = this->PyValue_To_VampList<Vamp::Plugin::OutputList,Vamp::Plugin::OutputDescriptor>(pyValue); } |
385 inline void PyValue_To_rValue(PyObject *pyValue, Vamp::Plugin::ParameterList &r) const | 282 inline void PyValue_To_rValue(PyObject *pyValue, Vamp::Plugin::ParameterList &r) const |
386 { r = this->PyValue_To_VampList<Vamp::Plugin::ParameterList,Vamp::Plugin::ParameterDescriptor>(pyValue); } | 283 { r = this->PyValue_To_VampList<Vamp::Plugin::ParameterList,Vamp::Plugin::ParameterDescriptor>(pyValue); } |
401 void setValueError(std::string,bool) const; | 298 void setValueError(std::string,bool) const; |
402 ValueError& lastError() const; | 299 ValueError& lastError() const; |
403 | 300 |
404 /* Overloaded _convert(), bypasses error checking to avoid doing it twice in internals. */ | 301 /* Overloaded _convert(), bypasses error checking to avoid doing it twice in internals. */ |
405 inline void _convert(PyObject *pyValue,float &r) const | 302 inline void _convert(PyObject *pyValue,float &r) const |
406 { r = PyValue_To_Float(pyValue); } | 303 { r = m_conv.PyValue_To_Float(pyValue); } |
407 inline void _convert(PyObject *pyValue,size_t &r) const | 304 inline void _convert(PyObject *pyValue,size_t &r) const |
408 { r = PyValue_To_Size_t(pyValue); } | 305 { r = m_conv.PyValue_To_Size_t(pyValue); } |
409 inline void _convert(PyObject *pyValue,bool &r) const | 306 inline void _convert(PyObject *pyValue,bool &r) const |
410 { r = PyValue_To_Bool(pyValue); } | 307 { r = m_conv.PyValue_To_Bool(pyValue); } |
411 inline void _convert(PyObject *pyValue,std::string &r) const | 308 inline void _convert(PyObject *pyValue,std::string &r) const |
412 { r = PyValue_To_String(pyValue); } | 309 { r = m_conv.PyValue_To_String(pyValue); } |
413 inline void _convert(PyObject *pyValue,std::vector<std::string> &r) const | 310 inline void _convert(PyObject *pyValue,std::vector<std::string> &r) const |
414 { r = PyValue_To_StringVector(pyValue); } | 311 { r = m_conv.PyValue_To_StringVector(pyValue); } |
415 inline void _convert(PyObject *pyValue,std::vector<float> &r) const | 312 inline void _convert(PyObject *pyValue,std::vector<float> &r) const |
416 { r = PyValue_To_FloatVector(pyValue); } | 313 { r = m_conv.PyValue_To_FloatVector(pyValue); } |
417 inline void _convert(PyObject *pyValue,Vamp::RealTime &r) const | 314 inline void _convert(PyObject *pyValue,Vamp::RealTime &r) const |
418 { r = PyValue_To_RealTime(pyValue); } | 315 { r = PyValue_To_RealTime(pyValue); } |
419 inline void _convert(PyObject *pyValue,Vamp::Plugin::OutputDescriptor::SampleType &r) const | 316 inline void _convert(PyObject *pyValue,Vamp::Plugin::OutputDescriptor::SampleType &r) const |
420 { r = PyValue_To_SampleType(pyValue); } | 317 { r = PyValue_To_SampleType(pyValue); } |
421 // inline void _convert(PyObject *pyValue,Vamp::Plugin::InputDomain &r) const | 318 // inline void _convert(PyObject *pyValue,Vamp::Plugin::InputDomain &r) const |
422 // { r = PyValue_To_InputDomain(pyValue); } | 319 // { r = m_conv.PyValue_To_InputDomain(pyValue); } |
423 | 320 |
424 | 321 |
425 /* Identify descriptors for error reporting */ | 322 /* Identify descriptors for error reporting */ |
426 inline std::string getDescriptorId(Vamp::Plugin::OutputDescriptor d) const | 323 inline std::string getDescriptorId(Vamp::Plugin::OutputDescriptor d) const |
427 {return std::string("Output Descriptor '") + d.identifier +"' ";} | 324 {return std::string("Output Descriptor '") + d.identifier +"' ";} |
433 public: | 330 public: |
434 const bool& error; | 331 const bool& error; |
435 | 332 |
436 }; | 333 }; |
437 | 334 |
438 /* Convert Sample Buffers to Python */ | |
439 | |
440 /// passing the sample buffers as builtin python lists | |
441 /// Optimization: using fast sequence protocol | |
442 inline PyObject* | |
443 PyTypeInterface::InputBuffers_As_PythonLists(const float *const *inputBuffers,const size_t& channels, const size_t& blockSize, const Vamp::Plugin::InputDomain& dtype) | |
444 { | |
445 //create a list of lists (new references) | |
446 PyObject *pyChannelList = PyList_New((Py_ssize_t) channels); | |
447 | |
448 // Pack samples into a Python List Object | |
449 // pyFloat/pyComplex types will always be new references, | |
450 // they will be freed when the lists are deallocated. | |
451 | |
452 PyObject **pyChannelListArray = PySequence_Fast_ITEMS(pyChannelList); | |
453 for (size_t i=0; i < channels; ++i) { | |
454 | |
455 size_t arraySize; | |
456 if (dtype==Vamp::Plugin::FrequencyDomain) | |
457 arraySize = (blockSize / 2) + 1; //blockSize + 2; if cplx list isn't used | |
458 else | |
459 arraySize = blockSize; | |
460 | |
461 PyObject *pySampleList = PyList_New((Py_ssize_t) arraySize); | |
462 PyObject **pySampleListArray = PySequence_Fast_ITEMS(pySampleList); | |
463 | |
464 // Note: passing a complex list crashes the C-style plugin | |
465 // when it tries to convert it to a numpy array directly. | |
466 // This plugin will be obsolete, but we have to find a way | |
467 // to prevent such crash: possibly a numpy bug, | |
468 // works fine above 1.0.4 | |
469 | |
470 switch (dtype) //(Vamp::Plugin::TimeDomain) | |
471 { | |
472 case Vamp::Plugin::TimeDomain : | |
473 | |
474 for (size_t j = 0; j < arraySize; ++j) { | |
475 PyObject *pyFloat=PyFloat_FromDouble( | |
476 (double) inputBuffers[i][j]); | |
477 pySampleListArray[j] = pyFloat; | |
478 } | |
479 break; | |
480 | |
481 case Vamp::Plugin::FrequencyDomain : | |
482 | |
483 size_t k = 0; | |
484 for (size_t j = 0; j < arraySize; ++j) { | |
485 PyObject *pyComplex=PyComplex_FromDoubles( | |
486 (double) inputBuffers[i][k], | |
487 (double) inputBuffers[i][k+1]); | |
488 pySampleListArray[j] = pyComplex; | |
489 k += 2; | |
490 } | |
491 break; | |
492 | |
493 } | |
494 pyChannelListArray[i] = pySampleList; | |
495 } | |
496 return pyChannelList; | |
497 } | |
498 | |
499 /// numpy buffer interface: passing the sample buffers as shared memory buffers | |
500 /// Optimization: using sequence protocol for creating the buffer list | |
501 inline PyObject* | |
502 PyTypeInterface::InputBuffers_As_SharedMemoryList(const float *const *inputBuffers,const size_t& channels, const size_t& blockSize, const Vamp::Plugin::InputDomain& dtype) | |
503 { | |
504 //create a list of buffers (returns new references) | |
505 PyObject *pyChannelList = PyList_New((Py_ssize_t) channels); | |
506 PyObject **pyChannelListArray = PySequence_Fast_ITEMS(pyChannelList); | |
507 | |
508 // Expose memory using the Buffer Interface. | |
509 // This will pass a pointer which can be recasted in Python code | |
510 // as complex or float array using Numpy's frombuffer() method | |
511 // (this will not copy values just keep the starting adresses | |
512 // for each channel in a list) | |
513 Py_ssize_t bufferSize; | |
514 | |
515 if (dtype==Vamp::Plugin::FrequencyDomain) | |
516 bufferSize = (Py_ssize_t) sizeof(float) * (blockSize+2); | |
517 else | |
518 bufferSize = (Py_ssize_t) sizeof(float) * blockSize; | |
519 | |
520 for (size_t i=0; i < channels; ++i) { | |
521 PyObject *pyBuffer = PyBuffer_FromMemory | |
522 ((void *) (float *) inputBuffers[i],bufferSize); | |
523 pyChannelListArray[i] = pyBuffer; | |
524 } | |
525 return pyChannelList; | |
526 } | |
527 | |
528 | |
529 /// numpy array interface: passing the sample buffers as 2D numpy array | |
530 /// Optimization: using array API (needs numpy headers) | |
531 #ifdef HAVE_NUMPY | |
532 inline PyObject* | |
533 PyTypeInterface::InputBuffers_As_NumpyArray(const float *const *inputBuffers,const size_t& channels, const size_t& blockSize, const Vamp::Plugin::InputDomain& dtype) | |
534 { | |
535 /* | |
536 NOTE: We create a list of 1D Numpy arrays for each channel instead | |
537 of a matrix, because the address space of inputBuffers doesn't seem | |
538 to be continuous. Although the array strides could be calculated for | |
539 2 channels (i.e. inputBuffers[1] - inputBuffers[0]) i'm not sure | |
540 if this can be trusted, especially for more than 2 channels. | |
541 | |
542 cerr << "First channel: " << inputBuffers[0][0] << " address: " << inputBuffers[0] << endl; | |
543 if (channels == 2) | |
544 cerr << "Second channel: " << inputBuffers[1][0] << " address: " << inputBuffers[1] << endl; | |
545 | |
546 */ | |
547 | |
548 // create a list of arrays (returns new references) | |
549 PyObject *pyChannelList = PyList_New((Py_ssize_t) channels); | |
550 PyObject **pyChannelListArray = PySequence_Fast_ITEMS(pyChannelList); | |
551 | |
552 // Expose memory using the Numpy Array Interface. | |
553 // This will wrap an array objects around the data. | |
554 // (will not copy values just steal the starting adresses) | |
555 | |
556 int arraySize, typenum; | |
557 | |
558 switch (dtype) | |
559 { | |
560 case Vamp::Plugin::TimeDomain : | |
561 typenum = dtype_float32; //NPY_FLOAT; | |
562 arraySize = (int) blockSize; | |
563 break; | |
564 | |
565 case Vamp::Plugin::FrequencyDomain : | |
566 typenum = dtype_complex64; //NPY_CFLOAT; | |
567 arraySize = (int) (blockSize / 2) + 1; | |
568 break; | |
569 | |
570 default : | |
571 cerr << "PyTypeInterface::InputBuffers_As_NumpyArray: Error: Unsupported numpy array data type." << endl; | |
572 return pyChannelList; | |
573 } | |
574 | |
575 // size for each dimension | |
576 npy_intp ndims[1]={arraySize}; | |
577 | |
578 for (size_t i=0; i < channels; ++i) { | |
579 PyObject *pyChannelArray = | |
580 //args: (dimensions, size in each dim, type kind, pointer to continuous array) | |
581 PyArray_SimpleNewFromData(1, ndims, typenum, (void*) inputBuffers[i]); | |
582 // make it read-only: set all flags to false except NPY_C_CONTIGUOUS | |
583 //!!! what about NPY_ARRAY_OWNDATA? | |
584 PyArray_CLEARFLAGS((PyArrayObject *)pyChannelArray, 0xff); | |
585 PyArray_ENABLEFLAGS((PyArrayObject *)pyChannelArray, NPY_ARRAY_C_CONTIGUOUS); | |
586 pyChannelListArray[i] = pyChannelArray; | |
587 } | |
588 return pyChannelList; | |
589 } | |
590 #endif | 335 #endif |
591 | |
592 | |
593 | |
594 #ifdef NUMPY_REFERENCE | |
595 /// This should be all we need to compile without direct dependency, | |
596 /// but we don't do that. (it may not work on some platforms) | |
597 typedef struct { | |
598 int two; /* contains the integer 2 -- simple sanity check */ | |
599 int nd; /* number of dimensions */ | |
600 char typekind; /* kind in array --- character code of typestr */ | |
601 int itemsize; /* size of each element */ | |
602 int flags; /* flags indicating how the data should be interpreted */ | |
603 /* must set ARR_HAS_DESCR bit to validate descr */ | |
604 Py_intptr_t *shape; /* A length-nd array of shape information */ | |
605 Py_intptr_t *strides; /* A length-nd array of stride information */ | |
606 void *data; /* A pointer to the first element of the array */ | |
607 PyObject *descr; /* NULL or data-description (same as descr key */ | |
608 /* of __array_interface__) -- must set ARR_HAS_DESCR */ | |
609 /* flag or this will be ignored. */ | |
610 } PyArrayInterface; | |
611 | |
612 typedef struct PyArrayObject { | |
613 PyObject_HEAD | |
614 char *data; /* pointer to raw data buffer */ | |
615 int nd; /* number of dimensions, also called ndim */ | |
616 npy_intp *dimensions; /* size in each dimension */ | |
617 npy_intp *strides; /* bytes to jump to get to the | |
618 next element in each dimension */ | |
619 PyObject *base; /* This object should be decref'd | |
620 upon deletion of array */ | |
621 /* For views it points to the original array */ | |
622 /* For creation from buffer object it points | |
623 to an object that shold be decref'd on | |
624 deletion */ | |
625 /* For UPDATEIFCOPY flag this is an array | |
626 to-be-updated upon deletion of this one */ | |
627 PyArray_Descr *descr; /* Pointer to type structure */ | |
628 int flags; /* Flags describing array -- see below*/ | |
629 PyObject *weakreflist; /* For weakreferences */ | |
630 } PyArrayObject; | |
631 | |
632 typedef struct _PyArray_Descr { | |
633 PyObject_HEAD | |
634 PyTypeObject *typeobj; /* the type object representing an | |
635 instance of this type -- should not | |
636 be two type_numbers with the same type | |
637 object. */ | |
638 char kind; /* kind for this type */ | |
639 char type; /* unique-character representing this type */ | |
640 char byteorder; /* '>' (big), '<' (little), '|' | |
641 (not-applicable), or '=' (native). */ | |
642 char hasobject; /* non-zero if it has object arrays | |
643 in fields */ | |
644 int type_num; /* number representing this type */ | |
645 int elsize; /* element size for this type */ | |
646 int alignment; /* alignment needed for this type */ | |
647 struct _arr_descr \ | |
648 *subarray; /* Non-NULL if this type is | |
649 is an array (C-contiguous) | |
650 of some other type | |
651 */ | |
652 PyObject *fields; /* The fields dictionary for this type */ | |
653 /* For statically defined descr this | |
654 is always Py_None */ | |
655 | |
656 PyObject *names; /* An ordered tuple of field names or NULL | |
657 if no fields are defined */ | |
658 | |
659 PyArray_ArrFuncs *f; /* a table of functions specific for each | |
660 basic data descriptor */ | |
661 } PyArray_Descr; | |
662 | |
663 enum NPY_TYPES { NPY_BOOL=0, | |
664 NPY_BYTE, NPY_UBYTE, | |
665 NPY_SHORT, NPY_USHORT, | |
666 NPY_INT, NPY_UINT, | |
667 NPY_LONG, NPY_ULONG, | |
668 NPY_LONGLONG, NPY_ULONGLONG, | |
669 NPY_FLOAT, NPY_DOUBLE, NPY_LONGDOUBLE, | |
670 NPY_CFLOAT, NPY_CDOUBLE, NPY_CLONGDOUBLE, | |
671 NPY_OBJECT=17, | |
672 NPY_STRING, NPY_UNICODE, | |
673 NPY_VOID, | |
674 NPY_NTYPES, | |
675 NPY_NOTYPE, | |
676 NPY_CHAR, /* special flag */ | |
677 NPY_USERDEF=256 /* leave room for characters */ | |
678 }; | |
679 #endif /*NUMPY_REFERENCE*/ | |
680 #endif |