Mercurial > hg > vampy
comparison PyTypeInterface.h @ 31:4f1894c7591b vampy2
Created Vampy2 branch
author | fazekasgy |
---|---|
date | Sun, 20 Sep 2009 17:31:20 +0000 |
parents | |
children | a8231788216c |
comparison
equal
deleted
inserted
replaced
28:5139bf30f208 | 31:4f1894c7591b |
---|---|
1 /* | |
2 | |
3 Type safe conversion utilities from Python types to C/C++ types, | |
4 mainly using Py/C API macros. | |
5 | |
6 */ | |
7 | |
8 #ifndef _PY_TYPE_INTERFACE_H_ | |
9 #define _PY_TYPE_INTERFACE_H_ | |
10 | |
11 #include "vamp-sdk/Plugin.h" | |
12 #include <Python.h> | |
13 #include "PyExtensionModule.h" | |
14 #include <vector> | |
15 #include <queue> | |
16 #include <string> | |
17 //#include <typeinfo> | |
18 | |
19 | |
20 using std::cerr; | |
21 using std::endl; | |
22 | |
23 namespace o { | |
24 enum eOutDescriptors { | |
25 not_found, | |
26 identifier, | |
27 name, | |
28 description, | |
29 unit, | |
30 hasFixedBinCount, | |
31 binCount, | |
32 binNames, | |
33 hasKnownExtents, | |
34 minValue, | |
35 maxValue, | |
36 isQuantized, | |
37 quantizeStep, | |
38 sampleType, | |
39 sampleRate, | |
40 hasDuration, | |
41 endNode | |
42 }; | |
43 } | |
44 | |
45 namespace p { | |
46 enum eParmDescriptors { | |
47 not_found, | |
48 identifier, | |
49 name, | |
50 description, | |
51 unit, | |
52 minValue, | |
53 maxValue, | |
54 defaultValue, | |
55 isQuantized, | |
56 quantizeStep | |
57 }; | |
58 } | |
59 | |
60 enum eSampleTypes { | |
61 OneSamplePerStep, | |
62 FixedSampleRate, | |
63 VariableSampleRate | |
64 }; | |
65 | |
66 enum eFeatureFields { | |
67 unknown, | |
68 hasTimestamp, | |
69 timeStamp, | |
70 hasDuration, | |
71 duration, | |
72 values, | |
73 label | |
74 }; | |
75 | |
76 | |
77 /// sutructure of NumPy array interface: | |
78 /// this is all we need to support numpy without direct dependency | |
79 typedef struct { | |
80 int two; /* contains the integer 2 -- simple sanity check */ | |
81 int nd; /* number of dimensions */ | |
82 char typekind; /* kind in array --- character code of typestr */ | |
83 int itemsize; /* size of each element */ | |
84 int flags; /* flags indicating how the data should be interpreted */ | |
85 /* must set ARR_HAS_DESCR bit to validate descr */ | |
86 Py_intptr_t *shape; /* A length-nd array of shape information */ | |
87 Py_intptr_t *strides; /* A length-nd array of stride information */ | |
88 void *data; /* A pointer to the first element of the array */ | |
89 PyObject *descr; /* NULL or data-description (same as descr key */ | |
90 /* of __array_interface__) -- must set ARR_HAS_DESCR */ | |
91 /* flag or this will be ignored. */ | |
92 } PyArrayInterface; | |
93 | |
94 /* C++ mapping of PyNone Type*/ | |
95 typedef struct NoneType {}; | |
96 | |
97 class PyTypeInterface | |
98 { | |
99 public: | |
100 PyTypeInterface(); | |
101 ~PyTypeInterface(); | |
102 | |
103 // Data | |
104 class ValueError | |
105 { | |
106 public: | |
107 ValueError() {} | |
108 ValueError(std::string m, bool s) : message(m),strict(s) {} | |
109 std::string location; | |
110 std::string message; | |
111 bool strict; | |
112 std::string get() const { return message + "\nLocation: " + location + "\n";} | |
113 void print() const { cerr << get(); } | |
114 }; | |
115 | |
116 // Utilities | |
117 void setStrictTypingFlag(bool b) {m_strict = b;} | |
118 const ValueError &lastError() const; | |
119 ValueError getError() const; | |
120 std::string PyValue_Get_TypeName(PyObject*) const; | |
121 bool initMaps() const; | |
122 | |
123 // Basic type conversion: Python to C++ | |
124 float PyValue_To_Float(PyObject*) const; | |
125 size_t PyValue_To_Size_t(PyObject*) const; | |
126 bool PyValue_To_Bool(PyObject*) const; | |
127 std::string PyValue_To_String(PyObject*) const; | |
128 // int PyValue_To_Int(PyObject*) const; | |
129 | |
130 // C++ to Python | |
131 PyObject *PyValue_From_CValue(const char*) const; | |
132 PyObject *PyValue_From_CValue(const std::string& x) const { return PyValue_From_CValue(x.c_str()); } | |
133 PyObject *PyValue_From_CValue(size_t) const; | |
134 PyObject *PyValue_From_CValue(double) const; | |
135 PyObject *PyValue_From_CValue(float x) const { return PyValue_From_CValue((double)x); } | |
136 PyObject *PyValue_From_CValue(bool) const; | |
137 | |
138 // Sequence types | |
139 std::vector<std::string> PyValue_To_StringVector (PyObject*) const; | |
140 std::vector<float> PyValue_To_FloatVector (PyObject*) const; | |
141 | |
142 // Numpy types | |
143 float* getNumPyObjectData(PyObject *object, int &length) const; | |
144 | |
145 | |
146 /* Template functions */ | |
147 | |
148 | |
149 /// Common wrappers to set a value in one of these structs. (to be used in template functions) | |
150 void SetValue(Vamp::Plugin::OutputDescriptor& od, std::string& key, PyObject* pyValue) const; | |
151 void SetValue(Vamp::Plugin::ParameterDescriptor& od, std::string& key, PyObject* pyValue) const; | |
152 bool SetValue(Vamp::Plugin::Feature& od, std::string& key, PyObject* pyValue) const; | |
153 PyObject* GetDescriptor_As_Dict(PyObject* pyValue) const | |
154 { | |
155 if PyFeature_CheckExact(pyValue) return PyFeature_AS_DICT(pyValue); | |
156 if PyOutputDescriptor_CheckExact(pyValue) return PyOutputDescriptor_AS_DICT(pyValue); | |
157 if PyParameterDescriptor_CheckExact(pyValue) return PyParameterDescriptor_AS_DICT(pyValue); | |
158 return NULL; | |
159 } | |
160 | |
161 | |
162 template<typename RET> | |
163 RET PyTypeInterface::PyValue_To_VampDescriptor(PyObject* pyValue) const | |
164 //returns e.g. Vamp::Plugin::OutputDescriptor or Vamp::Plugin::Feature | |
165 { | |
166 PyObject* pyDict; | |
167 | |
168 // Descriptors encoded as dicts | |
169 pyDict = GetDescriptor_As_Dict(pyValue); | |
170 if (!pyDict) pyDict = pyValue; | |
171 | |
172 // TODO: support full mapping protocol as fallback. | |
173 if (!PyDict_Check(pyDict)) { | |
174 setValueError("Error while converting descriptor or feature object.\nThe value is neither a dictionary nor a Vamp Feature or Descriptor type.",m_strict); | |
175 return RET(); | |
176 } | |
177 | |
178 Py_ssize_t pyPos = 0; | |
179 PyObject *pyKey, *pyDictValue; | |
180 initMaps(); | |
181 RET rd; | |
182 | |
183 //Python Dictionary Iterator: | |
184 while (PyDict_Next(pyDict, &pyPos, &pyKey, &pyDictValue)) | |
185 { | |
186 std::string key = PyValue_To_String(pyKey); | |
187 SetValue(rd,key,pyDictValue); | |
188 if (m_error) { | |
189 _lastError().location += "parameter: '" + key + "'";//"' descriptor: '" + rd.identifier + "'"; | |
190 } | |
191 } | |
192 if (!m_errorQueue.empty()) m_error = true; | |
193 return rd; | |
194 } | |
195 | |
196 /// Convert a sequence (tipically list) of PySomething to | |
197 /// OutputList,ParameterList or FeatureList | |
198 template<typename RET,typename ELEM> //<OutputList> <OutputDescriptor> | |
199 RET PyTypeInterface::PyValue_To_VampList(PyObject* pyList) const | |
200 { | |
201 // Vamp::Plugin::OutputList list; | |
202 // Vamp::Plugin::OutputDescriptor od; | |
203 RET list; | |
204 ELEM element; | |
205 | |
206 // Type checking | |
207 if (! PyList_Check(pyList) ) { | |
208 Py_CLEAR(pyList); | |
209 // cerr << "ERROR: In Python plugin [" << m_class << "::" << method | |
210 // << "] Expected List return type." << endl; | |
211 return list; | |
212 } | |
213 | |
214 //This reference will be borrowed | |
215 PyObject *pyDict; | |
216 | |
217 //Parse Output List | |
218 for (Py_ssize_t i = 0; i < PyList_GET_SIZE(pyList); ++i) { | |
219 //Get i-th Vamp output descriptor (Borrowed Reference) | |
220 pyDict = PyList_GET_ITEM(pyList,i); | |
221 element = PyValue_To_VampDescriptor<ELEM>(pyDict); | |
222 // Check for empty Feature/Descriptor as before? | |
223 list.push_back(element); | |
224 } | |
225 return list; | |
226 } | |
227 | |
228 | |
229 //Vamp specific types | |
230 | |
231 Vamp::Plugin::FeatureSet PyValue_To_FeatureSet(PyObject*) const; | |
232 inline void PyValue_To_rValue(PyObject *pyValue, Vamp::Plugin::FeatureSet &r) const | |
233 { r = this->PyValue_To_FeatureSet(pyValue); } | |
234 | |
235 Vamp::RealTime::RealTime PyValue_To_RealTime(PyObject*) const; | |
236 inline void PyValue_To_rValue(PyObject *pyValue, Vamp::RealTime::RealTime &r) const | |
237 { r = this->PyValue_To_RealTime(pyValue); } | |
238 | |
239 | |
240 /* Overloaded PyValue_To_rValue() to support generic functions */ | |
241 inline void PyValue_To_rValue(PyObject *pyValue, float &defValue) const | |
242 { float tmp = this->PyValue_To_Float(pyValue); | |
243 if(!m_error) defValue = tmp; } | |
244 inline void PyValue_To_rValue(PyObject *pyValue, size_t &defValue) const | |
245 { size_t tmp = this->PyValue_To_Size_t(pyValue); | |
246 if(!m_error) defValue = tmp; } | |
247 inline void PyValue_To_rValue(PyObject *pyValue, bool &defValue) const | |
248 { bool tmp = this->PyValue_To_Bool(pyValue); | |
249 if(!m_error) defValue = tmp; } | |
250 inline void PyValue_To_rValue(PyObject *pyValue, std::string &defValue) const | |
251 { std::string tmp = this->PyValue_To_String(pyValue); | |
252 if(!m_error) defValue = tmp; } | |
253 /*used by templates where we expect no return value, if there is one it will be ignored*/ | |
254 inline void PyValue_To_rValue(PyObject *pyValue, NoneType &defValue) const | |
255 { if (m_strict && pyValue != Py_None) | |
256 setValueError("Strict conversion error: expected 'None' type.",m_strict); | |
257 } | |
258 | |
259 /* convert sequence types to Vamp List types */ | |
260 inline void PyValue_To_rValue(PyObject *pyValue, Vamp::Plugin::OutputList &r) const | |
261 { r = this->PyValue_To_VampList<Vamp::Plugin::OutputList,Vamp::Plugin::OutputDescriptor>(pyValue); } | |
262 inline void PyValue_To_rValue(PyObject *pyValue, Vamp::Plugin::ParameterList &r) const | |
263 { r = this->PyValue_To_VampList<Vamp::Plugin::ParameterList,Vamp::Plugin::ParameterDescriptor>(pyValue); } | |
264 inline void PyValue_To_rValue(PyObject *pyValue, Vamp::Plugin::FeatureList &r) const | |
265 { r = this->PyValue_To_VampList<Vamp::Plugin::FeatureList,Vamp::Plugin::Feature>(pyValue); } | |
266 | |
267 /// this is only needed for RealTime->Frame conversion | |
268 void setInputSampleRate(float inputSampleRate) | |
269 { m_inputSampleRate = (unsigned int) inputSampleRate; } | |
270 | |
271 private: | |
272 bool m_strict; | |
273 ValueError m_noError; | |
274 mutable bool m_error; | |
275 mutable ValueError& m_lastError; | |
276 mutable std::queue<ValueError> m_errorQueue; | |
277 // we only use it for RealTime conversion which requires unsigned int | |
278 unsigned int m_inputSampleRate; | |
279 | |
280 void setValueError(std::string,bool) const; | |
281 ValueError& _lastError() const; | |
282 | |
283 /* Overloaded _convert(), bypasses error checking to avoid doing it twice in internals. */ | |
284 inline void _convert(PyObject *pyValue,float &r) const | |
285 { r = PyValue_To_Float(pyValue); } | |
286 inline void _convert(PyObject *pyValue,size_t &r) const | |
287 { r = PyValue_To_Size_t(pyValue); } | |
288 inline void _convert(PyObject *pyValue,bool &r) const | |
289 { r = PyValue_To_Bool(pyValue); } | |
290 inline void _convert(PyObject *pyValue,std::string &r) const | |
291 { r = PyValue_To_String(pyValue); } | |
292 inline void _convert(PyObject *pyValue,std::vector<std::string> &r) const | |
293 { r = PyValue_To_StringVector(pyValue); } | |
294 inline void _convert(PyObject *pyValue,std::vector<float> &r) const | |
295 { r = PyValue_To_FloatVector(pyValue); } | |
296 inline void _convert(PyObject *pyValue,Vamp::RealTime::RealTime &r) const | |
297 { r = PyValue_To_RealTime(pyValue); } | |
298 | |
299 public: | |
300 const bool& error; | |
301 | |
302 }; | |
303 | |
304 #endif |