Mercurial > hg > vampy
comparison PyTypeInterface.h @ 37:27bab3a16c9a vampy2final
new branch Vampy2final
author | fazekasgy |
---|---|
date | Mon, 05 Oct 2009 11:28:00 +0000 |
parents | |
children | 8b2eddf686da |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 37:27bab3a16c9a |
---|---|
1 /* | |
2 | |
3 * Vampy : This plugin is a wrapper around the Vamp plugin API. | |
4 * It allows for writing Vamp plugins in Python. | |
5 | |
6 * Centre for Digital Music, Queen Mary University of London. | |
7 * Copyright (C) 2008-2009 Gyorgy Fazekas, QMUL. (See Vamp sources | |
8 * for licence information.) | |
9 | |
10 */ | |
11 | |
12 /* | |
13 PyTypeInterface: Type safe conversion utilities between Python types | |
14 and basic C/C++ types and Vamp API types. | |
15 */ | |
16 | |
17 #ifndef _PY_TYPE_INTERFACE_H_ | |
18 #define _PY_TYPE_INTERFACE_H_ | |
19 #include <Python.h> | |
20 #ifdef HAVE_NUMPY | |
21 #define PY_ARRAY_UNIQUE_SYMBOL VAMPY_ARRAY_API | |
22 #define NO_IMPORT_ARRAY | |
23 #include "numpy/arrayobject.h" | |
24 #endif | |
25 #include "PyExtensionModule.h" | |
26 #include <vector> | |
27 #include <queue> | |
28 #include <string> | |
29 #include <sstream> | |
30 #include "vamp-sdk/Plugin.h" | |
31 | |
32 using std::cerr; | |
33 using std::endl; | |
34 | |
35 #ifdef HAVE_NUMPY | |
36 enum eArrayDataType { | |
37 dtype_float32 = (int) NPY_FLOAT, | |
38 dtype_complex64 = (int) NPY_CFLOAT | |
39 }; | |
40 #endif | |
41 | |
42 namespace o { | |
43 enum eOutDescriptors { | |
44 not_found, | |
45 identifier, | |
46 name, | |
47 description, | |
48 unit, | |
49 hasFixedBinCount, | |
50 binCount, | |
51 binNames, | |
52 hasKnownExtents, | |
53 minValue, | |
54 maxValue, | |
55 isQuantized, | |
56 quantizeStep, | |
57 sampleType, | |
58 sampleRate, | |
59 hasDuration, | |
60 endNode | |
61 }; | |
62 } | |
63 | |
64 namespace p { | |
65 enum eParmDescriptors { | |
66 not_found, | |
67 identifier, | |
68 name, | |
69 description, | |
70 unit, | |
71 minValue, | |
72 maxValue, | |
73 defaultValue, | |
74 isQuantized, | |
75 quantizeStep | |
76 }; | |
77 } | |
78 | |
79 enum eSampleTypes { | |
80 OneSamplePerStep, | |
81 FixedSampleRate, | |
82 VariableSampleRate | |
83 }; | |
84 | |
85 enum eFeatureFields { | |
86 unknown, | |
87 hasTimestamp, | |
88 timestamp, | |
89 hasDuration, | |
90 duration, | |
91 values, | |
92 label | |
93 }; | |
94 | |
95 /* C++ mapping of PyNone Type */ | |
96 struct NoneType {}; | |
97 | |
98 class PyTypeInterface | |
99 { | |
100 public: | |
101 PyTypeInterface(); | |
102 ~PyTypeInterface(); | |
103 | |
104 // Data | |
105 class ValueError | |
106 { | |
107 public: | |
108 ValueError() {} | |
109 ValueError(std::string m, bool s) : message(m),strict(s) {} | |
110 std::string location; | |
111 std::string message; | |
112 bool strict; | |
113 std::string str() const { | |
114 return (location.empty()) ? message : message + "\nLocation: " + location;} | |
115 void print() const { cerr << str() << endl; } | |
116 template<typename V> ValueError &operator<< (const V& v) | |
117 { | |
118 std::ostringstream ss; | |
119 ss << v; | |
120 location += ss.str(); | |
121 return *this; | |
122 } | |
123 }; | |
124 | |
125 // Utilities | |
126 void setStrictTypingFlag(bool b) {m_strict = b;} | |
127 ValueError getError() const; | |
128 std::string PyValue_Get_TypeName(PyObject*) const; | |
129 bool initMaps() const; | |
130 | |
131 // Basic type conversion: Python to C++ | |
132 float PyValue_To_Float(PyObject*) const; | |
133 size_t PyValue_To_Size_t(PyObject*) const; | |
134 bool PyValue_To_Bool(PyObject*) const; | |
135 std::string PyValue_To_String(PyObject*) const; | |
136 long PyValue_To_Long(PyObject*) const; | |
137 // int PyValue_To_Int(PyObject* pyValue) const; | |
138 | |
139 | |
140 // C++ to Python | |
141 PyObject *PyValue_From_CValue(const char*) const; | |
142 PyObject *PyValue_From_CValue(const std::string& x) const { return PyValue_From_CValue(x.c_str()); } | |
143 PyObject *PyValue_From_CValue(size_t) const; | |
144 PyObject *PyValue_From_CValue(double) const; | |
145 PyObject *PyValue_From_CValue(float x) const { return PyValue_From_CValue((double)x); } | |
146 PyObject *PyValue_From_CValue(bool) const; | |
147 | |
148 // Sequence types | |
149 std::vector<std::string> PyValue_To_StringVector (PyObject*) const; | |
150 std::vector<float> PyValue_To_FloatVector (PyObject*) const; | |
151 std::vector<float> PyList_To_FloatVector (PyObject*) const; | |
152 | |
153 // Input buffers to Python | |
154 PyObject* InputBuffers_As_PythonLists(const float *const *inputBuffers,const size_t& channels, const size_t& blockSize, const Vamp::Plugin::InputDomain& dtype); | |
155 PyObject* InputBuffers_As_SharedMemoryList(const float *const *inputBuffers,const size_t& channels, const size_t& blockSize); | |
156 | |
157 // Numpy types | |
158 #ifdef HAVE_NUMPY | |
159 std::vector<float> PyArray_To_FloatVector (PyObject *pyValue) const; | |
160 PyObject* InputBuffers_As_NumpyArray(const float *const *inputBuffers, const size_t&, const size_t&, const Vamp::Plugin::InputDomain& dtype); | |
161 #endif | |
162 | |
163 | |
164 | |
165 | |
166 /* Template functions */ | |
167 | |
168 | |
169 /// Common wrappers to set values in Vamp API structs. (to be used in template functions) | |
170 void SetValue(Vamp::Plugin::OutputDescriptor& od, std::string& key, PyObject* pyValue) const; | |
171 void SetValue(Vamp::Plugin::ParameterDescriptor& od, std::string& key, PyObject* pyValue) const; | |
172 bool SetValue(Vamp::Plugin::Feature& od, std::string& key, PyObject* pyValue) const; | |
173 PyObject* GetDescriptor_As_Dict(PyObject* pyValue) const | |
174 { | |
175 if PyFeature_CheckExact(pyValue) return PyFeature_AS_DICT(pyValue); | |
176 if PyOutputDescriptor_CheckExact(pyValue) return PyOutputDescriptor_AS_DICT(pyValue); | |
177 if PyParameterDescriptor_CheckExact(pyValue) return PyParameterDescriptor_AS_DICT(pyValue); | |
178 return NULL; | |
179 } | |
180 | |
181 //returns e.g. Vamp::Plugin::OutputDescriptor or Vamp::Plugin::Feature | |
182 template<typename RET> | |
183 RET PyValue_To_VampDescriptor(PyObject* pyValue) const | |
184 { | |
185 PyObject* pyDict; | |
186 | |
187 // Descriptors encoded as dicts | |
188 pyDict = GetDescriptor_As_Dict(pyValue); | |
189 if (!pyDict) pyDict = pyValue; | |
190 | |
191 // TODO: support full mapping protocol as fallback. | |
192 if (!PyDict_Check(pyDict)) { | |
193 setValueError("Error while converting descriptor or feature object.\nThe value is neither a dictionary nor a Vamp Feature or Descriptor type.",m_strict); | |
194 #ifdef _DEBUG | |
195 cerr << "PyTypeInterface::PyValue_To_VampDescriptor failed. Error: Unexpected return type." << endl; | |
196 #endif | |
197 return RET(); | |
198 } | |
199 | |
200 Py_ssize_t pyPos = 0; | |
201 PyObject *pyKey, *pyDictValue; | |
202 initMaps(); | |
203 int errors = 0; | |
204 m_error = false; | |
205 RET rd; | |
206 | |
207 //Python Dictionary Iterator: | |
208 while (PyDict_Next(pyDict, &pyPos, &pyKey, &pyDictValue)) | |
209 { | |
210 std::string key = PyValue_To_String(pyKey); | |
211 #ifdef _DEBUG_VALUES | |
212 cerr << "key: '" << key << "' value: '" << PyValue_To_String(pyDictValue) << "' " << endl; | |
213 #endif | |
214 SetValue(rd,key,pyDictValue); | |
215 if (m_error) { | |
216 errors++; | |
217 lastError() << "attribute '" << key << "'";// << " of " << getDescriptorId(rd); | |
218 } | |
219 } | |
220 if (errors) { | |
221 lastError() << " of " << getDescriptorId(rd); | |
222 m_error = true; | |
223 #ifdef _DEBUG | |
224 cerr << "PyTypeInterface::PyValue_To_VampDescriptor: Warning: Value error in descriptor." << endl; | |
225 #endif | |
226 } | |
227 return rd; | |
228 } | |
229 | |
230 /// Convert a sequence (tipically list) of PySomething to | |
231 /// OutputList,ParameterList or FeatureList | |
232 /// <OutputList> <OutputDescriptor> | |
233 template<typename RET,typename ELEM> | |
234 RET PyValue_To_VampList(PyObject* pyValue) const | |
235 { | |
236 RET list; // e.g. Vamp::Plugin::OutputList | |
237 ELEM element; // e.g. Vamp::Plugin::OutputDescriptor | |
238 | |
239 /// convert lists (ParameterList, OutputList, FeatureList) | |
240 if (PyList_Check(pyValue)) { | |
241 PyObject *pyDict; //This reference will be borrowed | |
242 m_error = false; int errors = 0; | |
243 for (Py_ssize_t i = 0; i < PyList_GET_SIZE(pyValue); ++i) { | |
244 //Get i-th Vamp output descriptor (Borrowed Reference) | |
245 pyDict = PyList_GET_ITEM(pyValue,i); | |
246 element = PyValue_To_VampDescriptor<ELEM>(pyDict); | |
247 if (m_error) errors++; | |
248 // Check for empty Feature/Descriptor as before? | |
249 list.push_back(element); | |
250 } | |
251 if (errors) m_error=true; | |
252 return list; | |
253 } | |
254 | |
255 /// convert other types implementing the sequence protocol | |
256 if (PySequence_Check(pyValue)) { | |
257 PyObject *pySequence = PySequence_Fast(pyValue,"Returned value can not be converted to list or tuple."); | |
258 PyObject **pyElements = PySequence_Fast_ITEMS(pySequence); | |
259 m_error = false; int errors = 0; | |
260 for (Py_ssize_t i = 0; i < PySequence_Fast_GET_SIZE(pySequence); ++i) | |
261 { | |
262 element = PyValue_To_VampDescriptor<ELEM>(pyElements[i]); | |
263 if (m_error) errors++; | |
264 list.push_back(element); | |
265 } | |
266 if (errors) m_error=true; | |
267 Py_XDECREF(pySequence); | |
268 return list; | |
269 } | |
270 | |
271 // accept None as an empty list | |
272 if (pyValue == Py_None) return list; | |
273 | |
274 // in strict mode, returning a single value is not allowed | |
275 if (m_strict) { | |
276 setValueError("Strict conversion error: object is not list or iterable sequence.",m_strict); | |
277 return list; | |
278 } | |
279 | |
280 /// try to insert single, non-iterable values. i.e. feature <- [feature] | |
281 element = PyValue_To_VampDescriptor<ELEM>(pyValue); | |
282 if (m_error) { | |
283 setValueError("Could not insert returned value to Vamp List.",m_strict); | |
284 return list; | |
285 } | |
286 list.push_back(element); | |
287 return list; | |
288 | |
289 #ifdef _DEBUG | |
290 cerr << "PyTypeInterface::PyValue_To_VampList failed. Expected iterable return type." << endl; | |
291 #endif | |
292 | |
293 } | |
294 | |
295 /// Convert DTYPE type 1D NumpyArray to std::vector<RET> | |
296 template<typename RET, typename DTYPE> | |
297 std::vector<RET> PyArray_Convert(char* raw_data_ptr, long length, size_t strides) const | |
298 { | |
299 std::vector<RET> rValue; | |
300 | |
301 /// check if the array is continuous, if not use strides info | |
302 if (sizeof(DTYPE)!=strides) { | |
303 #ifdef _DEBUG_VALUES | |
304 cerr << "Warning: discontinuous numpy array. Strides: " << strides << " bytes. sizeof(dtype): " << sizeof(DTYPE) << endl; | |
305 #endif | |
306 char* data = (char*) raw_data_ptr; | |
307 for (long i = 0; i<length; ++i){ | |
308 rValue.push_back((RET)(*((DTYPE*)data))); | |
309 #ifdef _DEBUG_VALUES | |
310 cerr << "value: " << (RET)(*((DTYPE*)data)) << endl; | |
311 #endif | |
312 data+=strides; | |
313 } | |
314 return rValue; | |
315 } | |
316 | |
317 DTYPE* data = (DTYPE*) raw_data_ptr; | |
318 for (long i = 0; i<length; ++i){ | |
319 #ifdef _DEBUG_VALUES | |
320 cerr << "value: " << (RET)data[i] << endl; | |
321 #endif | |
322 rValue.push_back((RET)data[i]); | |
323 } | |
324 return rValue; | |
325 } | |
326 | |
327 /// this is a special case. numpy.float64 has an array interface but no array descriptor | |
328 inline std::vector<float> PyArray0D_Convert(PyArrayInterface *ai) const | |
329 { | |
330 std::vector<float> rValue; | |
331 if ((ai->typekind) == *"f") | |
332 rValue.push_back((float)*(double*)(ai->data)); | |
333 else { | |
334 setValueError("Unsupported NumPy data type.",m_strict); | |
335 return rValue; | |
336 } | |
337 #ifdef _DEBUG_VALUES | |
338 cerr << "value: " << rValue[0] << endl; | |
339 #endif | |
340 return rValue; | |
341 } | |
342 | |
343 //Vamp specific types | |
344 Vamp::Plugin::FeatureSet PyValue_To_FeatureSet(PyObject*) const; | |
345 inline void PyValue_To_rValue(PyObject *pyValue, Vamp::Plugin::FeatureSet &r) const | |
346 { r = this->PyValue_To_FeatureSet(pyValue); } | |
347 | |
348 Vamp::RealTime PyValue_To_RealTime(PyObject*) const; | |
349 inline void PyValue_To_rValue(PyObject *pyValue, Vamp::RealTime &r) const | |
350 { r = this->PyValue_To_RealTime(pyValue); } | |
351 | |
352 Vamp::Plugin::OutputDescriptor::SampleType PyValue_To_SampleType(PyObject*) const; | |
353 | |
354 Vamp::Plugin::InputDomain PyValue_To_InputDomain(PyObject*) const; | |
355 inline void PyValue_To_rValue(PyObject *pyValue, Vamp::Plugin::InputDomain &r) const | |
356 { r = this->PyValue_To_InputDomain(pyValue); } | |
357 | |
358 | |
359 /* Overloaded PyValue_To_rValue() to support generic functions */ | |
360 inline void PyValue_To_rValue(PyObject *pyValue, float &defValue) const | |
361 { float tmp = this->PyValue_To_Float(pyValue); | |
362 if(!m_error) defValue = tmp; } | |
363 inline void PyValue_To_rValue(PyObject *pyValue, size_t &defValue) const | |
364 { size_t tmp = this->PyValue_To_Size_t(pyValue); | |
365 if(!m_error) defValue = tmp; } | |
366 inline void PyValue_To_rValue(PyObject *pyValue, bool &defValue) const | |
367 { bool tmp = this->PyValue_To_Bool(pyValue); | |
368 if(!m_error) defValue = tmp; } | |
369 inline void PyValue_To_rValue(PyObject *pyValue, std::string &defValue) const | |
370 { std::string tmp = this->PyValue_To_String(pyValue); | |
371 if(!m_error) defValue = tmp; } | |
372 /*used by templates where we expect no return value, if there is one it will be ignored*/ | |
373 inline void PyValue_To_rValue(PyObject *pyValue, NoneType &defValue) const | |
374 { if (m_strict && pyValue != Py_None) | |
375 setValueError("Strict conversion error: Expected 'None' type.",m_strict); | |
376 } | |
377 | |
378 /* convert sequence types to Vamp List types */ | |
379 inline void PyValue_To_rValue(PyObject *pyValue, Vamp::Plugin::OutputList &r) const | |
380 { r = this->PyValue_To_VampList<Vamp::Plugin::OutputList,Vamp::Plugin::OutputDescriptor>(pyValue); } | |
381 inline void PyValue_To_rValue(PyObject *pyValue, Vamp::Plugin::ParameterList &r) const | |
382 { r = this->PyValue_To_VampList<Vamp::Plugin::ParameterList,Vamp::Plugin::ParameterDescriptor>(pyValue); } | |
383 inline void PyValue_To_rValue(PyObject *pyValue, Vamp::Plugin::FeatureList &r) const | |
384 { r = this->PyValue_To_VampList<Vamp::Plugin::FeatureList,Vamp::Plugin::Feature>(pyValue); } | |
385 | |
386 /// this is only needed for RealTime->Frame conversion | |
387 void setInputSampleRate(float inputSampleRate) | |
388 { m_inputSampleRate = (unsigned int) inputSampleRate; } | |
389 | |
390 private: | |
391 bool m_strict; | |
392 mutable bool m_error; | |
393 mutable std::queue<ValueError> m_errorQueue; | |
394 unsigned int m_inputSampleRate; | |
395 | |
396 void setValueError(std::string,bool) const; | |
397 ValueError& lastError() const; | |
398 | |
399 /* Overloaded _convert(), bypasses error checking to avoid doing it twice in internals. */ | |
400 inline void _convert(PyObject *pyValue,float &r) const | |
401 { r = PyValue_To_Float(pyValue); } | |
402 inline void _convert(PyObject *pyValue,size_t &r) const | |
403 { r = PyValue_To_Size_t(pyValue); } | |
404 inline void _convert(PyObject *pyValue,bool &r) const | |
405 { r = PyValue_To_Bool(pyValue); } | |
406 inline void _convert(PyObject *pyValue,std::string &r) const | |
407 { r = PyValue_To_String(pyValue); } | |
408 inline void _convert(PyObject *pyValue,std::vector<std::string> &r) const | |
409 { r = PyValue_To_StringVector(pyValue); } | |
410 inline void _convert(PyObject *pyValue,std::vector<float> &r) const | |
411 { r = PyValue_To_FloatVector(pyValue); } | |
412 inline void _convert(PyObject *pyValue,Vamp::RealTime &r) const | |
413 { r = PyValue_To_RealTime(pyValue); } | |
414 inline void _convert(PyObject *pyValue,Vamp::Plugin::OutputDescriptor::SampleType &r) const | |
415 { r = PyValue_To_SampleType(pyValue); } | |
416 // inline void _convert(PyObject *pyValue,Vamp::Plugin::InputDomain &r) const | |
417 // { r = PyValue_To_InputDomain(pyValue); } | |
418 | |
419 | |
420 /* Identify descriptors for error reporting */ | |
421 inline std::string getDescriptorId(Vamp::Plugin::OutputDescriptor d) const | |
422 {return std::string("Output Descriptor '") + d.identifier +"' ";} | |
423 inline std::string getDescriptorId(Vamp::Plugin::ParameterDescriptor d) const | |
424 {return std::string("Parameter Descriptor '") + d.identifier +"' ";} | |
425 inline std::string getDescriptorId(Vamp::Plugin::Feature f) const | |
426 {return std::string("Feature (") + f.label + ")"; } | |
427 | |
428 public: | |
429 const bool& error; | |
430 | |
431 }; | |
432 | |
433 /* Convert Sample Buffers to Python */ | |
434 | |
435 /// passing the sample buffers as buitin python lists | |
436 /// Optimization: using fast sequence protocol | |
437 inline PyObject* | |
438 PyTypeInterface::InputBuffers_As_PythonLists(const float *const *inputBuffers,const size_t& channels, const size_t& blockSize, const Vamp::Plugin::InputDomain& dtype) | |
439 { | |
440 //create a list of lists (new references) | |
441 PyObject *pyChannelList = PyList_New((Py_ssize_t) channels); | |
442 | |
443 // Pack samples into a Python List Object | |
444 // pyFloat/pyComplex types will always be new references, | |
445 // they will be freed when the lists are deallocated. | |
446 | |
447 PyObject **pyChannelListArray = PySequence_Fast_ITEMS(pyChannelList); | |
448 for (size_t i=0; i < channels; ++i) { | |
449 | |
450 PyObject *pySampleList = PyList_New((Py_ssize_t) blockSize); | |
451 PyObject **pySampleListArray = PySequence_Fast_ITEMS(pySampleList); | |
452 | |
453 // Note: passing a complex list crashes the C-style plugin | |
454 // when it tries to convert it to a numpy array directly. | |
455 // This plugin will be obsolete, but we have to find a way | |
456 // to prevent such crash. | |
457 | |
458 switch (Vamp::Plugin::TimeDomain) //(dtype) | |
459 { | |
460 case Vamp::Plugin::TimeDomain : | |
461 | |
462 for (size_t j = 0; j < blockSize; ++j) { | |
463 PyObject *pyFloat=PyFloat_FromDouble( | |
464 (double) inputBuffers[i][j]); | |
465 pySampleListArray[j] = pyFloat; | |
466 } | |
467 break; | |
468 | |
469 case Vamp::Plugin::FrequencyDomain : | |
470 | |
471 size_t k = 0; | |
472 for (size_t j = 0; j < blockSize/2; ++j) { | |
473 PyObject *pyComplex=PyComplex_FromDoubles( | |
474 (double) inputBuffers[i][k], | |
475 (double) inputBuffers[i][k+1]); | |
476 pySampleListArray[j] = pyComplex; | |
477 k += 2; | |
478 } | |
479 break; | |
480 | |
481 } | |
482 pyChannelListArray[i] = pySampleList; | |
483 } | |
484 return pyChannelList; | |
485 } | |
486 | |
487 /// numpy buffer interface: passing the sample buffers as shared memory buffers | |
488 /// Optimization: using sequence protocol for creating the buffer list | |
489 inline PyObject* | |
490 PyTypeInterface::InputBuffers_As_SharedMemoryList(const float *const *inputBuffers,const size_t& channels, const size_t& blockSize) | |
491 { | |
492 //create a list of buffers (returns new references) | |
493 PyObject *pyChannelList = PyList_New((Py_ssize_t) channels); | |
494 PyObject **pyChannelListArray = PySequence_Fast_ITEMS(pyChannelList); | |
495 | |
496 // Expose memory using the Buffer Interface. | |
497 // This will pass a pointer which can be recasted in Python code | |
498 // as complex or float array using Numpy's frombuffer() method | |
499 // (this will not copy values just keep the starting adresses | |
500 // for each channel in a list) | |
501 Py_ssize_t bufferSize = (Py_ssize_t) sizeof(float) * blockSize; | |
502 | |
503 for (size_t i=0; i < channels; ++i) { | |
504 PyObject *pyBuffer = PyBuffer_FromMemory | |
505 ((void *) (float *) inputBuffers[i],bufferSize); | |
506 pyChannelListArray[i] = pyBuffer; | |
507 } | |
508 return pyChannelList; | |
509 } | |
510 | |
511 | |
512 /// numpy array interface: passing the sample buffers as 2D numpy array | |
513 /// Optimization: using array API (needs numpy headers) | |
514 #ifdef HAVE_NUMPY | |
515 inline PyObject* | |
516 PyTypeInterface::InputBuffers_As_NumpyArray(const float *const *inputBuffers,const size_t& channels, const size_t& blockSize, const Vamp::Plugin::InputDomain& dtype) | |
517 { | |
518 /* | |
519 NOTE: We create a list of 1D Numpy arrays for each channel instead | |
520 of a matrix, because the address space of inputBuffers doesn't seem | |
521 to be continuous. Although the array strides could be calculated for | |
522 2 channels (i.e. inputBuffers[1] - inputBuffers[0]) i'm not sure | |
523 if this can be trusted, especially for more than 2 channels. | |
524 | |
525 cerr << "First channel: " << inputBuffers[0][0] << " address: " << inputBuffers[0] << endl; | |
526 if (channels == 2) | |
527 cerr << "Second channel: " << inputBuffers[1][0] << " address: " << inputBuffers[1] << endl; | |
528 | |
529 */ | |
530 | |
531 // create a list of arrays (returns new references) | |
532 PyObject *pyChannelList = PyList_New((Py_ssize_t) channels); | |
533 PyObject **pyChannelListArray = PySequence_Fast_ITEMS(pyChannelList); | |
534 | |
535 // Expose memory using the Numpy Array Interface. | |
536 // This will wrap an array objects around the data. | |
537 // (will not copy values just steal the starting adresses) | |
538 | |
539 int arraySize, typenum; | |
540 | |
541 switch (dtype) | |
542 { | |
543 case Vamp::Plugin::TimeDomain : | |
544 typenum = dtype_float32; //NPY_FLOAT; | |
545 arraySize = (int) blockSize; | |
546 break; | |
547 | |
548 case Vamp::Plugin::FrequencyDomain : | |
549 typenum = dtype_complex64; //NPY_CFLOAT; | |
550 arraySize = (int) blockSize / 2; | |
551 break; | |
552 | |
553 default : | |
554 cerr << "PyTypeInterface::InputBuffers_As_NumpyArray: Error: Unsupported numpy array data type." << endl; | |
555 return pyChannelList; | |
556 } | |
557 | |
558 // size for each dimension | |
559 npy_intp ndims[1]={arraySize}; | |
560 | |
561 for (size_t i=0; i < channels; ++i) { | |
562 PyObject *pyChannelArray = | |
563 //args: (dimensions, size in each dim, type kind, pointer to continuous array) | |
564 PyArray_SimpleNewFromData(1, ndims, typenum, (void*) inputBuffers[i]); | |
565 // make it read-only: set all flags to false except NPY_C_CONTIGUOUS | |
566 ((PyArrayObject*)pyChannelArray)->flags = NPY_C_CONTIGUOUS; | |
567 pyChannelListArray[i] = pyChannelArray; | |
568 } | |
569 return pyChannelList; | |
570 } | |
571 #endif | |
572 | |
573 | |
574 | |
575 #ifdef NUMPY_REFERENCE | |
576 /// This should be all we need to compile without direct dependency, | |
577 /// but we don't do that. (it may not work on some platforms) | |
578 typedef struct { | |
579 int two; /* contains the integer 2 -- simple sanity check */ | |
580 int nd; /* number of dimensions */ | |
581 char typekind; /* kind in array --- character code of typestr */ | |
582 int itemsize; /* size of each element */ | |
583 int flags; /* flags indicating how the data should be interpreted */ | |
584 /* must set ARR_HAS_DESCR bit to validate descr */ | |
585 Py_intptr_t *shape; /* A length-nd array of shape information */ | |
586 Py_intptr_t *strides; /* A length-nd array of stride information */ | |
587 void *data; /* A pointer to the first element of the array */ | |
588 PyObject *descr; /* NULL or data-description (same as descr key */ | |
589 /* of __array_interface__) -- must set ARR_HAS_DESCR */ | |
590 /* flag or this will be ignored. */ | |
591 } PyArrayInterface; | |
592 | |
593 typedef struct PyArrayObject { | |
594 PyObject_HEAD | |
595 char *data; /* pointer to raw data buffer */ | |
596 int nd; /* number of dimensions, also called ndim */ | |
597 npy_intp *dimensions; /* size in each dimension */ | |
598 npy_intp *strides; /* bytes to jump to get to the | |
599 next element in each dimension */ | |
600 PyObject *base; /* This object should be decref'd | |
601 upon deletion of array */ | |
602 /* For views it points to the original array */ | |
603 /* For creation from buffer object it points | |
604 to an object that shold be decref'd on | |
605 deletion */ | |
606 /* For UPDATEIFCOPY flag this is an array | |
607 to-be-updated upon deletion of this one */ | |
608 PyArray_Descr *descr; /* Pointer to type structure */ | |
609 int flags; /* Flags describing array -- see below*/ | |
610 PyObject *weakreflist; /* For weakreferences */ | |
611 } PyArrayObject; | |
612 | |
613 typedef struct _PyArray_Descr { | |
614 PyObject_HEAD | |
615 PyTypeObject *typeobj; /* the type object representing an | |
616 instance of this type -- should not | |
617 be two type_numbers with the same type | |
618 object. */ | |
619 char kind; /* kind for this type */ | |
620 char type; /* unique-character representing this type */ | |
621 char byteorder; /* '>' (big), '<' (little), '|' | |
622 (not-applicable), or '=' (native). */ | |
623 char hasobject; /* non-zero if it has object arrays | |
624 in fields */ | |
625 int type_num; /* number representing this type */ | |
626 int elsize; /* element size for this type */ | |
627 int alignment; /* alignment needed for this type */ | |
628 struct _arr_descr \ | |
629 *subarray; /* Non-NULL if this type is | |
630 is an array (C-contiguous) | |
631 of some other type | |
632 */ | |
633 PyObject *fields; /* The fields dictionary for this type */ | |
634 /* For statically defined descr this | |
635 is always Py_None */ | |
636 | |
637 PyObject *names; /* An ordered tuple of field names or NULL | |
638 if no fields are defined */ | |
639 | |
640 PyArray_ArrFuncs *f; /* a table of functions specific for each | |
641 basic data descriptor */ | |
642 } PyArray_Descr; | |
643 | |
644 enum NPY_TYPES { NPY_BOOL=0, | |
645 NPY_BYTE, NPY_UBYTE, | |
646 NPY_SHORT, NPY_USHORT, | |
647 NPY_INT, NPY_UINT, | |
648 NPY_LONG, NPY_ULONG, | |
649 NPY_LONGLONG, NPY_ULONGLONG, | |
650 NPY_FLOAT, NPY_DOUBLE, NPY_LONGDOUBLE, | |
651 NPY_CFLOAT, NPY_CDOUBLE, NPY_CLONGDOUBLE, | |
652 NPY_OBJECT=17, | |
653 NPY_STRING, NPY_UNICODE, | |
654 NPY_VOID, | |
655 NPY_NTYPES, | |
656 NPY_NOTYPE, | |
657 NPY_CHAR, /* special flag */ | |
658 NPY_USERDEF=256 /* leave room for characters */ | |
659 }; | |
660 #endif /*NUMPY_REFERENCE*/ | |
661 #endif |