Chris@0
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@0
|
2
|
Chris@0
|
3 //include for python extension module: must be first
|
Chris@0
|
4 #include <Python.h>
|
Chris@0
|
5 #include <vampyhost.h>
|
Chris@0
|
6 #include <pyRealTime.h>
|
Chris@0
|
7
|
Chris@4
|
8 //!!! NB all our NumPy stuff is currently using the deprecated API --
|
Chris@4
|
9 //!!! need to work out how to update this
|
Chris@4
|
10 #include "numpy/arrayobject.h"
|
Chris@4
|
11
|
Chris@0
|
12 //includes for vamp host
|
Chris@1
|
13 #include "vamp-hostsdk/Plugin.h"
|
Chris@1
|
14 #include "vamp-hostsdk/PluginHostAdapter.h"
|
Chris@1
|
15 #include "vamp-hostsdk/PluginChannelAdapter.h"
|
Chris@1
|
16 #include "vamp-hostsdk/PluginInputDomainAdapter.h"
|
Chris@1
|
17 #include "vamp-hostsdk/PluginLoader.h"
|
Chris@0
|
18 //#include "vamp/vamp.h"
|
Chris@0
|
19
|
Chris@0
|
20 #include <iostream>
|
Chris@0
|
21 #include <fstream>
|
Chris@0
|
22 #include <set>
|
Chris@0
|
23 #include <sndfile.h>
|
Chris@0
|
24
|
Chris@0
|
25 #include <cstring>
|
Chris@0
|
26 #include <cstdlib>
|
Chris@0
|
27 #include <string>
|
Chris@0
|
28
|
Chris@0
|
29 #include "system.h"
|
Chris@0
|
30
|
Chris@0
|
31 #include <cmath>
|
Chris@0
|
32
|
Chris@0
|
33
|
Chris@0
|
34 using namespace std;
|
Chris@0
|
35 using namespace Vamp;
|
Chris@0
|
36
|
Chris@0
|
37 using Vamp::Plugin;
|
Chris@0
|
38 using Vamp::PluginHostAdapter;
|
Chris@0
|
39 using Vamp::RealTime;
|
Chris@0
|
40 using Vamp::HostExt::PluginLoader;
|
Chris@0
|
41
|
Chris@0
|
42 #define HOST_VERSION "1.1"
|
Chris@0
|
43
|
Chris@0
|
44
|
Chris@0
|
45 /* MODULE HELPER FUNCTIONS */
|
Chris@2
|
46 PyDoc_STRVAR(xx_foo_doc, "Some description"); //!!!
|
Chris@0
|
47
|
Chris@0
|
48 /*obtain C plugin handle and key from pyCobject */
|
luis@7
|
49 bool getPluginHandle
|
Chris@0
|
50 (PyObject *pyPluginHandle, Plugin **plugin, string **pKey=NULL) {
|
Chris@0
|
51
|
Chris@0
|
52 //char errormsg[]="Wrong input argument: Plugin Handle required.";
|
Chris@0
|
53
|
Chris@0
|
54 *plugin = NULL;
|
Chris@2
|
55 if (!PyCObject_Check(pyPluginHandle)) return false;
|
Chris@0
|
56
|
Chris@0
|
57 //try to convert to Plugin pointer
|
Chris@0
|
58 Plugin *p = (Plugin*) PyCObject_AsVoidPtr(pyPluginHandle);
|
luis@7
|
59 if (!p) return false;
|
Chris@0
|
60
|
Chris@0
|
61 string pId;
|
Chris@0
|
62
|
Chris@0
|
63 if (pKey) {
|
Chris@0
|
64 *pKey = (string*) PyCObject_GetDesc(pyPluginHandle);
|
Chris@2
|
65 if (!*pKey) return false;
|
Chris@0
|
66 pId = *(string*) *pKey;
|
Chris@0
|
67
|
Chris@0
|
68 } else {
|
Chris@0
|
69
|
Chris@0
|
70 void *pKey = PyCObject_GetDesc(pyPluginHandle);
|
Chris@2
|
71 if (!pKey) return false;
|
Chris@0
|
72 pId = *(string*) pKey;
|
Chris@0
|
73 }
|
luis@7
|
74
|
Chris@0
|
75 string::size_type pos = pId.find(':');
|
Chris@2
|
76 if (pos == string::npos) return false;
|
Chris@0
|
77
|
Chris@0
|
78 pId = pId.substr(pId.rfind(':')+1);
|
luis@7
|
79 string identifier = p->getIdentifier();
|
luis@7
|
80
|
Chris@2
|
81 if (pId.compare(identifier)) return false;
|
Chris@0
|
82
|
Chris@0
|
83 *plugin = p;
|
Chris@0
|
84 return true;
|
Chris@0
|
85 }
|
Chris@0
|
86
|
Chris@0
|
87 /*
|
Chris@0
|
88 ----------------------------------------------------------------
|
Chris@0
|
89 */
|
Chris@0
|
90
|
Chris@0
|
91
|
Chris@0
|
92
|
Chris@0
|
93 /*
|
luis@7
|
94 VAMPYHOST MAIN
|
luis@7
|
95 ---------------------------------------------------------------------
|
Chris@0
|
96 */
|
Chris@0
|
97
|
Chris@0
|
98 /* ENUMERATE PLUGINS*/
|
Chris@0
|
99
|
Chris@0
|
100 static PyObject *
|
Chris@0
|
101 vampyhost_enumeratePlugins(PyObject *self, PyObject *args)
|
Chris@0
|
102 {
|
Chris@0
|
103 string retType;
|
luis@7
|
104
|
Chris@0
|
105 if (!PyArg_ParseTuple(args, "|s:enumeratePlugins", &retType))
|
Chris@0
|
106 return NULL;
|
Chris@0
|
107
|
Chris@0
|
108 //list available plugins
|
Chris@0
|
109 PluginLoader *loader = PluginLoader::getInstance();
|
Chris@0
|
110 vector<PluginLoader::PluginKey> plugins = loader->listPlugins();
|
Chris@0
|
111
|
Chris@0
|
112 //library Map
|
Chris@0
|
113 typedef multimap<string, PluginLoader::PluginKey> LibraryMap;
|
Chris@0
|
114 LibraryMap libraryMap;
|
Chris@0
|
115
|
Chris@0
|
116 //New list object
|
Chris@0
|
117 PyObject *pyList = PyList_New(plugins.size());
|
Chris@0
|
118
|
Chris@0
|
119 for (size_t i = 0; i < plugins.size(); ++i) {
|
Chris@0
|
120 string path = loader->getLibraryPathForPlugin(plugins[i]);
|
Chris@0
|
121 libraryMap.insert(LibraryMap::value_type(path, plugins[i]));
|
Chris@0
|
122
|
Chris@0
|
123 PyObject *pyPluginKey = PyString_FromString(plugins[i].c_str());
|
Chris@0
|
124 PyList_SET_ITEM(pyList,i,pyPluginKey);
|
luis@7
|
125
|
Chris@0
|
126 }
|
Chris@0
|
127
|
Chris@0
|
128 PyList_Sort(pyList);
|
Chris@0
|
129 return pyList;
|
Chris@0
|
130 }
|
Chris@0
|
131
|
Chris@0
|
132
|
Chris@0
|
133 /* GET PLUGIN LIBRARY PATH*/
|
Chris@0
|
134
|
Chris@0
|
135 static PyObject *
|
Chris@0
|
136 vampyhost_getLibraryPath(PyObject *self, PyObject *args)
|
Chris@0
|
137 {
|
Chris@0
|
138 PyObject *pyPluginKey;
|
Chris@0
|
139
|
Chris@0
|
140 if (!PyArg_ParseTuple(args, "S", &pyPluginKey)) {
|
Chris@0
|
141 PyErr_SetString(PyExc_TypeError,
|
Chris@0
|
142 "String input argument required: pluginKey");
|
Chris@0
|
143 return NULL; }
|
Chris@0
|
144
|
Chris@0
|
145 //convert to stl string
|
Chris@0
|
146 string pluginKey(PyString_AS_STRING(pyPluginKey));
|
Chris@0
|
147
|
Chris@0
|
148 //check pluginKey Validity
|
Chris@0
|
149 string::size_type ki = pluginKey.find(':');
|
Chris@0
|
150 if (ki == string::npos) {
|
Chris@0
|
151 PyErr_SetString(PyExc_TypeError,
|
luis@7
|
152 "String input argument required: pluginLibrary:Identifier");
|
Chris@0
|
153 return NULL;
|
Chris@0
|
154 }
|
Chris@0
|
155
|
Chris@0
|
156 PluginLoader *loader = PluginLoader::getInstance();
|
Chris@0
|
157 string path = loader->getLibraryPathForPlugin(pluginKey);
|
Chris@0
|
158 PyObject *pyPath = PyString_FromString(path.c_str());
|
Chris@0
|
159 return pyPath;
|
Chris@0
|
160 }
|
Chris@0
|
161
|
Chris@0
|
162
|
Chris@0
|
163 /* GET PLUGIN CATEGORY*/
|
Chris@0
|
164
|
Chris@0
|
165 static PyObject *
|
Chris@0
|
166 vampyhost_getPluginCategory(PyObject *self, PyObject *args)
|
Chris@0
|
167 {
|
Chris@0
|
168 PyObject *pyPluginKey;
|
Chris@0
|
169
|
Chris@0
|
170 if (!PyArg_ParseTuple(args, "S", &pyPluginKey)) {
|
Chris@0
|
171 PyErr_SetString(PyExc_TypeError,
|
Chris@0
|
172 "String input argument required: pluginKey");
|
Chris@0
|
173 return NULL; }
|
Chris@0
|
174
|
Chris@0
|
175 //convert to stl string
|
Chris@0
|
176 string pluginKey(PyString_AS_STRING(pyPluginKey));
|
Chris@0
|
177
|
Chris@0
|
178 //check pluginKey Validity
|
Chris@0
|
179 string::size_type ki = pluginKey.find(':');
|
Chris@0
|
180 if (ki == string::npos) {
|
Chris@0
|
181 PyErr_SetString(PyExc_TypeError,
|
luis@7
|
182 "String input argument required: pluginLibrary:Identifier");
|
Chris@0
|
183 return NULL;
|
Chris@0
|
184 }
|
Chris@0
|
185
|
Chris@0
|
186 PluginLoader *loader = PluginLoader::getInstance();
|
luis@7
|
187 PluginLoader::PluginCategoryHierarchy
|
Chris@0
|
188 category = loader->getPluginCategory(pluginKey);
|
Chris@0
|
189 string catstring;
|
Chris@0
|
190
|
Chris@0
|
191 if (!category.empty()) {
|
Chris@0
|
192 catstring = "";
|
Chris@0
|
193 for (size_t ci = 0; ci < category.size(); ++ci) {
|
Chris@0
|
194 catstring.append(category[ci]);
|
Chris@0
|
195 catstring.append(" ");
|
Chris@0
|
196 }
|
Chris@0
|
197 PyObject *pyCat = PyString_FromString(catstring.c_str());
|
Chris@0
|
198 return pyCat;
|
Chris@0
|
199 }
|
Chris@0
|
200 PyObject *pyCat = PyString_FromString("");
|
Chris@0
|
201 return pyCat;
|
Chris@0
|
202 }
|
Chris@0
|
203
|
Chris@0
|
204
|
Chris@0
|
205
|
Chris@0
|
206 /* GET PLUGIN OUTPUT LIST*/
|
Chris@0
|
207
|
Chris@0
|
208 static PyObject *
|
Chris@0
|
209 vampyhost_getOutputList(PyObject *self, PyObject *args)
|
Chris@0
|
210 {
|
Chris@0
|
211 PyObject *pyPluginHandle;
|
Chris@0
|
212 string pluginKey;
|
Chris@0
|
213
|
Chris@0
|
214 if (!PyArg_ParseTuple(args, "O", &pyPluginHandle)) {
|
Chris@0
|
215 PyErr_SetString(PyExc_TypeError,
|
Chris@0
|
216 "Invalid argument: plugin handle or plugin key required.");
|
luis@7
|
217 return NULL;
|
Chris@0
|
218 }
|
Chris@0
|
219
|
Chris@0
|
220 //check if we have a plugin key string or a handle object
|
Chris@0
|
221 if (PyString_Check(pyPluginHandle) ) {
|
Chris@0
|
222
|
Chris@0
|
223 pluginKey.assign(PyString_AS_STRING(pyPluginHandle));
|
Chris@0
|
224 //check pluginKey Validity
|
Chris@0
|
225 string::size_type ki = pluginKey.find(':');
|
Chris@0
|
226 if (ki == string::npos) {
|
Chris@0
|
227 PyErr_SetString(PyExc_TypeError,
|
luis@7
|
228 "String input argument required: pluginLibrary:Identifier");
|
Chris@0
|
229 return NULL;
|
Chris@0
|
230 }
|
Chris@0
|
231
|
Chris@0
|
232 } else {
|
luis@7
|
233
|
luis@7
|
234 string *key;
|
luis@7
|
235 Plugin *plugin;
|
Chris@0
|
236
|
Chris@0
|
237 if ( !getPluginHandle(pyPluginHandle, &plugin, &key) ) {
|
Chris@0
|
238 PyErr_SetString(PyExc_TypeError,
|
Chris@0
|
239 "Invalid or deleted plugin handle.");
|
Chris@0
|
240 return NULL; }
|
Chris@0
|
241 pluginKey.assign(*key);
|
luis@7
|
242 }
|
luis@7
|
243
|
Chris@0
|
244 //This code creates new instance of the plugin anyway
|
Chris@0
|
245 PluginLoader *loader = PluginLoader::getInstance();
|
luis@7
|
246
|
Chris@0
|
247 //load plugin
|
Chris@3
|
248 Plugin *plugin = loader->loadPlugin
|
Chris@3
|
249 (pluginKey, 48000, PluginLoader::ADAPT_ALL_SAFE);
|
luis@7
|
250 if (!plugin) {
|
Chris@0
|
251 string pyerr("Failed to load plugin: "); pyerr += pluginKey;
|
luis@7
|
252 PyErr_SetString(PyExc_TypeError,pyerr.c_str());
|
Chris@0
|
253 return NULL;
|
luis@7
|
254 }
|
Chris@0
|
255
|
Chris@0
|
256 Plugin::OutputList outputs = plugin->getOutputDescriptors();
|
Chris@0
|
257 //Plugin::OutputDescriptor od;
|
Chris@0
|
258
|
Chris@0
|
259 if (outputs.size()<1) {
|
Chris@0
|
260 string pyerr("Plugin has no output: "); pyerr += pluginKey;
|
luis@7
|
261 PyErr_SetString(PyExc_TypeError,pyerr.c_str());
|
Chris@0
|
262 return NULL;
|
Chris@0
|
263 }
|
Chris@0
|
264
|
Chris@0
|
265 //New list object
|
Chris@0
|
266 PyObject *pyList = PyList_New(outputs.size());
|
Chris@0
|
267
|
Chris@0
|
268 for (size_t i = 0; i < outputs.size(); ++i) {
|
luis@7
|
269 PyObject *pyOutputId =
|
Chris@0
|
270 PyString_FromString(outputs[i].identifier.c_str());
|
luis@7
|
271 PyList_SET_ITEM(pyList,i,pyOutputId);
|
Chris@0
|
272 }
|
Chris@0
|
273
|
Chris@0
|
274 delete plugin;
|
Chris@0
|
275 return pyList;
|
Chris@0
|
276 }
|
Chris@0
|
277
|
Chris@0
|
278
|
Chris@0
|
279
|
Chris@0
|
280 /* LOAD PLUGIN */
|
Chris@0
|
281
|
Chris@0
|
282 static PyObject *
|
Chris@0
|
283 vampyhost_loadPlugin(PyObject *self, PyObject *args)
|
Chris@0
|
284 {
|
Chris@0
|
285 PyObject *pyPluginKey;
|
Chris@0
|
286 float inputSampleRate;
|
Chris@0
|
287
|
luis@7
|
288 if (!PyArg_ParseTuple(args, "Sf",
|
Chris@0
|
289 &pyPluginKey,
|
Chris@0
|
290 &inputSampleRate)) {
|
Chris@0
|
291 PyErr_SetString(PyExc_TypeError,
|
Chris@0
|
292 "String input argument required: pluginKey");
|
Chris@0
|
293 return NULL; }
|
Chris@0
|
294
|
Chris@0
|
295 //convert to stl string
|
Chris@0
|
296 string pluginKey(PyString_AS_STRING(pyPluginKey));
|
Chris@0
|
297
|
Chris@0
|
298 //check pluginKey Validity
|
Chris@0
|
299 string::size_type ki = pluginKey.find(':');
|
Chris@0
|
300 if (ki == string::npos) {
|
Chris@0
|
301 PyErr_SetString(PyExc_TypeError,
|
luis@7
|
302 "String input argument required: pluginLibrary:Identifier");
|
Chris@0
|
303 return NULL;
|
Chris@0
|
304 }
|
Chris@0
|
305
|
Chris@0
|
306 PluginLoader *loader = PluginLoader::getInstance();
|
luis@7
|
307
|
Chris@0
|
308 //load plugin
|
luis@7
|
309 Plugin *plugin = loader->loadPlugin (pluginKey, inputSampleRate,
|
Chris@6
|
310 PluginLoader::ADAPT_ALL_SAFE);
|
luis@7
|
311 if (!plugin) {
|
Chris@0
|
312 string pyerr("Failed to load plugin: "); pyerr += pluginKey;
|
luis@7
|
313 PyErr_SetString(PyExc_TypeError,pyerr.c_str());
|
Chris@0
|
314 return NULL;
|
luis@7
|
315 }
|
Chris@0
|
316 //void *identifier = (void*) new string(pluginKey);
|
Chris@0
|
317 PyPluginDescriptor *pd = new PyPluginDescriptor;
|
luis@7
|
318
|
Chris@0
|
319 pd->key = pluginKey;
|
Chris@0
|
320 pd->isInitialised = false;
|
Chris@0
|
321 pd->inputSampleRate = inputSampleRate;
|
luis@7
|
322
|
Chris@0
|
323 //New PyCObject
|
luis@7
|
324 //PyObject *pyPluginHandle = PyCObject_FromVoidPtrAndDesc(
|
luis@7
|
325 //(void*) plugin, identifier, NULL);
|
Chris@0
|
326
|
luis@7
|
327 PyObject *pyPluginHandle = PyCObject_FromVoidPtrAndDesc(
|
luis@7
|
328 (void*) plugin, (void*) pd, NULL);
|
luis@7
|
329
|
Chris@0
|
330 return pyPluginHandle;
|
Chris@0
|
331 }
|
Chris@0
|
332
|
Chris@0
|
333
|
Chris@0
|
334
|
Chris@0
|
335 /* UNLOAD PLUGIN */
|
Chris@0
|
336
|
Chris@0
|
337 static PyObject *
|
Chris@0
|
338 vampyhost_unloadPlugin(PyObject *self, PyObject *args)
|
Chris@0
|
339 {
|
Chris@0
|
340 PyObject *pyPluginHandle;
|
Chris@0
|
341
|
Chris@0
|
342 if (!PyArg_ParseTuple(args, "O", &pyPluginHandle)) {
|
Chris@0
|
343 PyErr_SetString(PyExc_TypeError,
|
Chris@0
|
344 "Wrong input argument: Plugin Handle required.");
|
Chris@0
|
345 return NULL; }
|
Chris@0
|
346
|
luis@7
|
347 string *key;
|
luis@7
|
348 Plugin *plugin;
|
Chris@0
|
349
|
Chris@0
|
350 if ( !getPluginHandle(pyPluginHandle, &plugin, &key) ) {
|
Chris@0
|
351 PyErr_SetString(PyExc_TypeError,
|
Chris@0
|
352 "Invalid or already deleted plugin handle.");
|
Chris@0
|
353 return NULL; }
|
Chris@0
|
354
|
Chris@0
|
355 /* Prevent repeated calls from causing segfault
|
Chris@0
|
356 sice it will fail type checking the 2nd time: */
|
Chris@0
|
357 PyCObject_SetVoidPtr(pyPluginHandle,NULL);
|
luis@7
|
358
|
Chris@0
|
359 PyPluginDescriptor *pd = (PyPluginDescriptor*) key;
|
luis@7
|
360
|
Chris@0
|
361 delete plugin;
|
Chris@0
|
362 delete pd;
|
Chris@0
|
363 return pyPluginHandle;
|
Chris@0
|
364
|
Chris@0
|
365 }
|
Chris@0
|
366
|
Chris@0
|
367
|
Chris@0
|
368 /* INITIALISE PLUGIN */
|
Chris@0
|
369
|
Chris@0
|
370 static PyObject *
|
Chris@0
|
371 vampyhost_initialise(PyObject *self, PyObject *args)
|
Chris@0
|
372 {
|
Chris@0
|
373 PyObject *pyPluginHandle;
|
luis@7
|
374 size_t channels, blockSize, stepSize;
|
Chris@0
|
375
|
luis@7
|
376 if (!PyArg_ParseTuple (args, "Onnn", &pyPluginHandle,
|
luis@7
|
377 (size_t) &channels,
|
luis@7
|
378 (size_t) &stepSize,
|
luis@7
|
379 (size_t) &blockSize))
|
Chris@0
|
380 {
|
Chris@0
|
381 PyErr_SetString(PyExc_TypeError,
|
Chris@0
|
382 "Wrong input arguments: requires a valid plugin handle,channels,stepSize,blockSize.");
|
luis@7
|
383 return NULL;
|
Chris@0
|
384 }
|
Chris@0
|
385
|
luis@7
|
386 Plugin *plugin;
|
luis@7
|
387 string *key;
|
Chris@0
|
388
|
Chris@0
|
389 if ( !getPluginHandle(pyPluginHandle, &plugin, &key) ) {
|
Chris@0
|
390 PyErr_SetString(PyExc_TypeError,
|
Chris@0
|
391 "Invalid plugin handle.");
|
Chris@0
|
392 return NULL; }
|
Chris@0
|
393
|
Chris@0
|
394 // here we cast the void pointer as PyPluginDescriptor instead of string
|
luis@7
|
395 PyPluginDescriptor *plugDesc = (PyPluginDescriptor*) key;
|
Chris@0
|
396
|
Chris@0
|
397 plugDesc->channels = channels;
|
Chris@0
|
398 plugDesc->stepSize = stepSize;
|
Chris@0
|
399 plugDesc->blockSize = blockSize;
|
Chris@3
|
400
|
Chris@0
|
401 if (!plugin->initialise(channels, stepSize, blockSize)) {
|
Chris@6
|
402 std::cerr << "Failed to initialise native plugin adapter with channels = " << channels << ", stepSize = " << stepSize << ", blockSize = " << blockSize << " and ADAPT_ALL_SAFE set" << std::endl;
|
Chris@0
|
403 PyErr_SetString(PyExc_TypeError,
|
Chris@0
|
404 "Plugin initialization failed.");
|
Chris@6
|
405 return NULL;
|
Chris@6
|
406 }
|
Chris@0
|
407
|
luis@7
|
408 plugDesc->identifier =
|
Chris@0
|
409 plugDesc->key.substr(plugDesc->key.rfind(':')+1);
|
Chris@0
|
410 plugDesc->isInitialised = true;
|
luis@7
|
411
|
Chris@0
|
412 return Py_True;
|
Chris@0
|
413 }
|
Chris@0
|
414
|
Chris@4
|
415 // These conversion functions are borrowed from PyTypeInterface in VamPy
|
Chris@4
|
416
|
Chris@4
|
417 template<typename RET, typename DTYPE>
|
Chris@4
|
418 static
|
Chris@4
|
419 RET *pyArrayConvert(char* raw_data_ptr, long length, size_t strides)
|
Chris@4
|
420 {
|
Chris@4
|
421 RET *rValue = new RET[length];
|
luis@7
|
422
|
Chris@4
|
423 /// check if the array is continuous, if not use strides info
|
Chris@4
|
424 if (sizeof(DTYPE)!=strides) {
|
Chris@4
|
425 char* data = (char*) raw_data_ptr;
|
Chris@4
|
426 for (long i = 0; i<length; ++i){
|
Chris@4
|
427 rValue[i] = (RET)(*((DTYPE*)data));
|
Chris@4
|
428 data += strides;
|
Chris@4
|
429 }
|
Chris@4
|
430 return rValue;
|
Chris@4
|
431 }
|
Chris@4
|
432
|
Chris@4
|
433 DTYPE* data = (DTYPE*) raw_data_ptr;
|
Chris@4
|
434 for (long i = 0; i<length; ++i){
|
Chris@4
|
435 rValue[i] = (RET)data[i];
|
Chris@4
|
436 }
|
luis@7
|
437
|
Chris@4
|
438 return rValue;
|
Chris@4
|
439 }
|
Chris@4
|
440
|
Chris@4
|
441 static float *
|
Chris@4
|
442 pyArrayToFloatArray(PyObject *pyValue)
|
Chris@4
|
443 {
|
Chris@4
|
444 if (!PyArray_Check(pyValue)) {
|
Chris@4
|
445 cerr << "pyArrayToFloatArray: Failed, object has no array interface" << endl;
|
Chris@4
|
446 return 0;
|
luis@7
|
447 }
|
Chris@4
|
448
|
Chris@4
|
449 PyArrayObject* pyArray = (PyArrayObject*) pyValue;
|
Chris@4
|
450 PyArray_Descr* descr = pyArray->descr;
|
luis@7
|
451
|
Chris@4
|
452 /// check raw data and descriptor pointers
|
Chris@4
|
453 if (pyArray->data == 0 || descr == 0) {
|
Chris@4
|
454 cerr << "pyArrayToFloatArray: Failed, NumPy array has NULL data or descriptor" << endl;
|
Chris@4
|
455 return 0;
|
Chris@4
|
456 }
|
Chris@4
|
457
|
Chris@4
|
458 /// check dimensions
|
Chris@4
|
459 if (pyArray->nd != 1) {
|
Chris@4
|
460 cerr << "pyArrayToFloatArray: Failed, NumPy array is multi-dimensional" << endl;
|
Chris@4
|
461 return 0;
|
Chris@4
|
462 }
|
Chris@4
|
463
|
Chris@4
|
464 /// check strides (useful if array is not continuous)
|
Chris@4
|
465 size_t strides = *((size_t*) pyArray->strides);
|
luis@7
|
466
|
Chris@4
|
467 /// convert the array
|
Chris@4
|
468 switch (descr->type_num) {
|
Chris@4
|
469 case NPY_FLOAT : // dtype='float32'
|
Chris@4
|
470 return pyArrayConvert<float,float>(pyArray->data,pyArray->dimensions[0],strides);
|
Chris@4
|
471 case NPY_DOUBLE : // dtype='float64'
|
Chris@4
|
472 return pyArrayConvert<float,double>(pyArray->data,pyArray->dimensions[0],strides);
|
Chris@4
|
473 default:
|
Chris@4
|
474 cerr << "pyArrayToFloatArray: Failed: Unsupported value type " << descr->type_num << " in NumPy array object (only float32, float64 supported)" << endl;
|
Chris@4
|
475 return 0;
|
Chris@4
|
476 }
|
Chris@4
|
477 }
|
Chris@4
|
478
|
Chris@0
|
479
|
Chris@0
|
480 /* RUN PROCESS */
|
Chris@0
|
481
|
Chris@0
|
482 static PyObject *
|
Chris@0
|
483 vampyhost_process(PyObject *self, PyObject *args)
|
Chris@0
|
484 {
|
Chris@0
|
485 PyObject *pyPluginHandle;
|
luis@8
|
486 PyArrayObject *pyBuffer;
|
Chris@0
|
487 PyObject *pyRealTime;
|
Chris@0
|
488
|
luis@7
|
489 if (!PyArg_ParseTuple(args, "OOO",
|
Chris@0
|
490 &pyPluginHandle, // C object holding a pointer to a plugin and its descriptor
|
luis@8
|
491 &pyBuffer, // Audio data (NumPy ndim array)
|
Chris@0
|
492 &pyRealTime)) { // TimeStamp
|
Chris@0
|
493 PyErr_SetString(PyExc_TypeError,
|
Chris@0
|
494 "Required: plugin handle, buffer, timestmap.");
|
Chris@0
|
495 return NULL; }
|
Chris@0
|
496
|
Chris@0
|
497 if (!PyRealTime_Check(pyRealTime)) {
|
Chris@0
|
498 PyErr_SetString(PyExc_TypeError,"Valid timestamp required.");
|
Chris@0
|
499 return NULL; }
|
Chris@0
|
500
|
Chris@4
|
501 string *key;
|
luis@7
|
502 Plugin *plugin;
|
Chris@0
|
503
|
Chris@4
|
504 if (!getPluginHandle(pyPluginHandle, &plugin, &key)) {
|
luis@8
|
505 PyErr_SetString(PyExc_AttributeError,
|
luis@8
|
506 "Invalid or already deleted plugin handle.");
|
luis@8
|
507 return NULL;
|
Chris@4
|
508 }
|
Chris@0
|
509
|
Chris@0
|
510 PyPluginDescriptor *pd = (PyPluginDescriptor*) key;
|
Chris@0
|
511
|
Chris@0
|
512 if (!pd->isInitialised) {
|
luis@8
|
513 PyErr_SetString(PyExc_StandardError,
|
luis@8
|
514 "Plugin has not been initialised.");
|
luis@8
|
515 return NULL; }
|
Chris@0
|
516
|
luis@7
|
517 size_t channels = pd->channels;
|
Chris@0
|
518 size_t blockSize = pd->blockSize;
|
Chris@0
|
519
|
luis@8
|
520 if (!PyArray_Check(pyBuffer)) {
|
luis@8
|
521 PyErr_SetString(PyExc_TypeError, "Argument is not a Numpy array.");
|
Chris@4
|
522 return NULL;
|
Chris@0
|
523 }
|
Chris@0
|
524
|
luis@8
|
525 if (pyBuffer->nd != channels) {
|
luis@8
|
526 cerr << "Wrong number of channels: got " << pyBuffer->nd << ", expected " << channels << endl;
|
Chris@4
|
527 PyErr_SetString(PyExc_TypeError, "Wrong number of channels");
|
Chris@4
|
528 return NULL;
|
Chris@4
|
529 }
|
Chris@0
|
530
|
luis@8
|
531 int n = pyBuffer->dimensions[0];
|
luis@8
|
532 int m = pyBuffer->dimensions[1];
|
luis@8
|
533
|
luis@10
|
534 // Domain Type, either Vamp::Plugin::FrequencyDomain
|
luis@10
|
535 // or Vamp::Plugin::TimeDomain
|
luis@10
|
536 Vamp::Plugin::InputDomain dtype = plugin->getInputDomain();
|
luis@10
|
537
|
luis@8
|
538 cout << "Kind :" << pyBuffer->descr->kind << endl;
|
luis@8
|
539 cout << "Strides 0 :" << pyBuffer->strides[0] << endl;
|
luis@8
|
540 cout << "Strides 1 :" << pyBuffer->strides[1] << endl;
|
luis@8
|
541 cout << "Flags:" << pyBuffer->flags << endl;
|
luis@8
|
542
|
luis@10
|
543 cout << "Input Domain" << dtype << endl;
|
luis@10
|
544 cout << "Plugin Maker" << plugin->getMaker() << endl;
|
luis@10
|
545
|
Chris@4
|
546 float **inbuf = new float *[channels];
|
luis@8
|
547 cout << "Created inbuf with #channels: " << channels << endl;
|
Chris@0
|
548
|
luis@11
|
549
|
luis@11
|
550
|
Chris@4
|
551 for (int c = 0; c < channels; ++c) {
|
luis@8
|
552
|
luis@8
|
553 // cout << "[Host] Converting channel #" << c << endl;
|
luis@8
|
554 // PyObject *cbuf = PyList_GET_ITEM(pyBuffer, c);
|
luis@8
|
555 // cout << "Ok1..." << endl;
|
luis@8
|
556 // inbuf[c] = pyArrayToFloatArray(cbuf);
|
luis@8
|
557
|
luis@8
|
558 inbuf[c] = pyArrayToFloatArray((PyObject*) pyBuffer);
|
luis@8
|
559
|
luis@11
|
560 cout << "Converted " << endl;
|
luis@8
|
561
|
Chris@4
|
562 if (!inbuf[c]) {
|
Chris@4
|
563 PyErr_SetString(PyExc_TypeError,"NumPy Array required for each channel in process input.");
|
Chris@4
|
564 return NULL;
|
Chris@0
|
565 }
|
luis@8
|
566
|
luis@8
|
567 cout << "[Host] Converted channel #" << c << endl;
|
luis@8
|
568
|
Chris@4
|
569 }
|
Chris@0
|
570
|
Chris@0
|
571 RealTime timeStamp = *PyRealTime_AsPointer(pyRealTime);
|
Chris@0
|
572
|
luis@8
|
573 cout << "[Host] Gonna call plugin->process" << endl;
|
luis@8
|
574
|
Chris@0
|
575 //Call process and store the output
|
Chris@4
|
576 pd->output = plugin->process(inbuf, timeStamp);
|
Chris@0
|
577
|
luis@8
|
578 cout << "[Host] Called plugin->process" << endl;
|
luis@8
|
579
|
Chris@0
|
580 /* TODO: DO SOMETHONG WITH THE FEATURE SET HERE */
|
luis@9
|
581 /// convert to appropriate python objects, reuse types and conversion utilities from Vampy ...
|
Chris@0
|
582
|
luis@10
|
583
|
luis@10
|
584 size_t featListOutLength = pd->output.size();
|
luis@10
|
585
|
luis@10
|
586 //New PyList for the featurelist
|
luis@10
|
587 PyObject *pyFeatureList = PyList_New(featListOutLength);
|
luis@10
|
588
|
luis@10
|
589 PyArrayObject *aaaa;
|
luis@10
|
590
|
luis@10
|
591 npy_intp *dims[2];
|
luis@10
|
592
|
luis@10
|
593 // Plugin::FeatureList features = pd->output[0];
|
luis@10
|
594
|
luis@9
|
595 // Loop FeatureLists
|
luis@9
|
596 for(int i = 0; i < pd->output.size(); i++ ){
|
luis@10
|
597 //New PyList for the features
|
luis@10
|
598 size_t outLength = pd->output[i].size();
|
luis@10
|
599 PyObject *pyFeatureList = PyList_New(outLength);
|
luis@10
|
600
|
luis@9
|
601 cout << "FeatureList #" << i << " has size " << pd->output[i].size() << endl;
|
luis@9
|
602
|
luis@9
|
603 // loop Features
|
luis@9
|
604 for(int j = 0; j < pd->output[i].size(); j++ ){
|
luis@10
|
605
|
luis@10
|
606 // debug - printing some features
|
luis@9
|
607 cout << "Feature #" << j << endl;
|
luis@9
|
608 cout << " Label: " << pd->output[i][j].label << endl;
|
luis@9
|
609 cout << " hasTimestamp? " << pd->output[i][j].hasTimestamp << endl;
|
luis@9
|
610 cout << " hasDuration? " << pd->output[i][j].hasDuration << endl;
|
luis@9
|
611 cout << " values.size " << pd->output[i][j].values.size() << endl;
|
luis@9
|
612 cout << " values[0] " << pd->output[i][j].values[0] << endl;
|
luis@9
|
613 }
|
luis@9
|
614 }
|
luis@9
|
615
|
luis@9
|
616
|
luis@10
|
617 // Gonna print just one
|
luis@9
|
618
|
luis@10
|
619 size_t arraySize = pd->output[0][0].values.size();
|
luis@10
|
620 PyObject *pySampleList = PyList_New((Py_ssize_t) arraySize);
|
luis@10
|
621 PyObject **pySampleListArray = PySequence_Fast_ITEMS(pySampleList);
|
luis@10
|
622
|
luis@10
|
623 for (size_t idx = 0; idx < arraySize; ++idx) {
|
luis@10
|
624 PyObject *pyFloat=PyFloat_FromDouble((double) pd->output[0][0].values[idx]);
|
luis@10
|
625 pySampleListArray[idx] = pyFloat;
|
luis@10
|
626 }
|
Chris@0
|
627
|
Chris@4
|
628 for (int c = 0; c < channels; ++c){
|
Chris@4
|
629 delete[] inbuf[c];
|
Chris@0
|
630 }
|
Chris@4
|
631 delete[] inbuf;
|
Chris@0
|
632
|
luis@10
|
633 return PyArray_Return((PyArrayObject*) pySampleList);
|
luis@10
|
634 // return pySampleList;
|
luis@10
|
635
|
luis@10
|
636 // return pyFeatureList; //!!! Need to return actual features!
|
Chris@0
|
637 }
|
Chris@0
|
638
|
Chris@0
|
639 /* GET / SET OUTPUT */
|
Chris@0
|
640
|
Chris@0
|
641 //getOutput(plugin,outputNo)
|
Chris@0
|
642 static PyObject *
|
Chris@0
|
643 vampyhost_getOutput(PyObject *self, PyObject *args) {
|
Chris@0
|
644
|
Chris@0
|
645 PyObject *pyPluginHandle;
|
Chris@0
|
646 // PyObject *pyBuffer;
|
Chris@0
|
647 // PyObject *pyRealTime;
|
Chris@0
|
648 PyObject *pyOutput;
|
Chris@0
|
649
|
luis@7
|
650 if (!PyArg_ParseTuple(args, "OO",
|
Chris@0
|
651 &pyPluginHandle, // C object holding a pointer to a plugin and its descriptor
|
Chris@0
|
652 &pyOutput)) { // Output reference
|
Chris@0
|
653 PyErr_SetString(PyExc_TypeError,
|
Chris@0
|
654 "Required: plugin handle, buffer, timestmap.");
|
Chris@0
|
655 return NULL; }
|
Chris@0
|
656
|
luis@7
|
657 string *key;
|
luis@7
|
658 Plugin *plugin;
|
Chris@0
|
659
|
Chris@0
|
660 if ( !getPluginHandle(pyPluginHandle, &plugin, &key) ) {
|
Chris@0
|
661 PyErr_SetString(PyExc_AttributeError,
|
Chris@0
|
662 "Invalid or already deleted plugin handle.");
|
Chris@0
|
663 return NULL; }
|
Chris@0
|
664
|
Chris@0
|
665 PyPluginDescriptor *pd = (PyPluginDescriptor*) key;
|
Chris@0
|
666
|
Chris@0
|
667 unsigned int outputNo = (unsigned int) PyInt_AS_LONG(pyOutput);
|
Chris@0
|
668
|
Chris@0
|
669 //Get output list: but we don't need it
|
Chris@0
|
670 //Plugin::FeatureList features = pd->output[outputNo];
|
Chris@0
|
671
|
Chris@0
|
672 size_t outLength = pd->output[outputNo].size();
|
Chris@0
|
673
|
Chris@0
|
674 //New PyList for the featurelist
|
Chris@0
|
675 PyObject *pyFeatureList = PyList_New(outLength);
|
Chris@0
|
676
|
Chris@0
|
677 for (size_t i = 0; i < outLength; ++i) {
|
Chris@0
|
678 // Test:
|
Chris@0
|
679 /*
|
luis@7
|
680 XxoObject *pyFeature = PyObject_New(XxoObject, &Xxo_Type);
|
Chris@0
|
681 if (pyFeature == NULL) break; //return NULL;
|
Chris@0
|
682
|
Chris@0
|
683 pyFeature->x_attr = NULL;
|
Chris@0
|
684 pyFeature->feature = &pd->output[outputNo][i];
|
Chris@0
|
685
|
luis@7
|
686 PyList_SET_ITEM(pyFeatureList,i,(PyObject*)pyFeature);
|
Chris@0
|
687 */
|
Chris@0
|
688 }
|
Chris@0
|
689
|
Chris@0
|
690 Py_INCREF(pyFeatureList);
|
Chris@0
|
691 return pyFeatureList;
|
Chris@0
|
692
|
Chris@0
|
693 // EXPLAIN WHAT WE NEED TO DO HERE:
|
Chris@0
|
694 // We have the block output in pd->output
|
luis@7
|
695 // FeatureSet[output] -> [Feature[x]] -> Feature.hasTimestamp = v
|
luis@7
|
696 // Vamp::Plugin::FeatureSet output; = pd->output
|
Chris@0
|
697 // typedef std::vector<Feature> FeatureList;
|
Chris@0
|
698 // typedef std::map<int, FeatureList> FeatureSet; // key is output no
|
Chris@0
|
699
|
luis@7
|
700 // THIS IS FOR OUTPUT id LOOKUP LATER
|
Chris@0
|
701 // Plugin::OutputList outputs = plugin->getOutputDescriptors();
|
luis@7
|
702 //
|
Chris@0
|
703 // if (outputs.size()<1) {
|
Chris@0
|
704 // string pyerr("Plugin has no output: "); pyerr += pluginKey;
|
luis@7
|
705 // PyErr_SetString(PyExc_TypeError,pyerr.c_str());
|
Chris@0
|
706 // return NULL;
|
Chris@0
|
707 // }
|
luis@7
|
708 //
|
Chris@0
|
709 // //New list object
|
Chris@0
|
710 // PyObject *pyList = PyList_New(outputs.size());
|
luis@7
|
711 //
|
Chris@0
|
712 // for (size_t i = 0; i < outputs.size(); ++i) {
|
luis@7
|
713 // PyObject *pyOutputId =
|
Chris@0
|
714 // PyString_FromString(outputs[i].identifier.c_str());
|
luis@7
|
715 // PyList_SET_ITEM(pyList,i,pyOutputId);
|
Chris@0
|
716 // }
|
luis@7
|
717
|
Chris@0
|
718 }
|
Chris@0
|
719
|
Chris@0
|
720
|
Chris@0
|
721
|
Chris@0
|
722
|
Chris@0
|
723 /* List of functions defined in this module */
|
Chris@0
|
724 //module methods table
|
Chris@0
|
725 static PyMethodDef vampyhost_methods[] = {
|
Chris@0
|
726
|
Chris@0
|
727 {"enumeratePlugins", vampyhost_enumeratePlugins, METH_VARARGS,
|
Chris@0
|
728 xx_foo_doc},
|
Chris@0
|
729
|
Chris@0
|
730 {"getLibraryPath", vampyhost_getLibraryPath, METH_VARARGS,
|
Chris@0
|
731 xx_foo_doc},
|
Chris@0
|
732
|
Chris@0
|
733 {"getPluginCategory", vampyhost_getPluginCategory, METH_VARARGS,
|
Chris@0
|
734 xx_foo_doc},
|
Chris@0
|
735
|
Chris@0
|
736 {"getOutputList", vampyhost_getOutputList, METH_VARARGS,
|
Chris@0
|
737 xx_foo_doc},
|
Chris@0
|
738
|
Chris@0
|
739 {"loadPlugin", vampyhost_loadPlugin, METH_VARARGS,
|
Chris@0
|
740 xx_foo_doc},
|
Chris@0
|
741
|
Chris@0
|
742 {"process", vampyhost_process, METH_VARARGS,
|
Chris@0
|
743 xx_foo_doc},
|
Chris@0
|
744
|
Chris@0
|
745 {"unloadPlugin", vampyhost_unloadPlugin, METH_VARARGS,
|
Chris@0
|
746 xx_foo_doc},
|
Chris@0
|
747
|
Chris@0
|
748 {"initialise", vampyhost_initialise, METH_VARARGS,
|
Chris@0
|
749 xx_foo_doc},
|
Chris@0
|
750
|
Chris@0
|
751 {"getOutput", vampyhost_getOutput, METH_VARARGS,
|
Chris@0
|
752 xx_foo_doc},
|
Chris@0
|
753
|
Chris@0
|
754 /* Add RealTime Module Methods */
|
Chris@0
|
755
|
Chris@0
|
756 {"frame2RealTime", (PyCFunction)RealTime_frame2RealTime, METH_VARARGS,
|
Chris@0
|
757 PyDoc_STR("frame2RealTime((int64)frame, (uint32)sampleRate ) -> returns new RealTime object from frame.")},
|
Chris@0
|
758
|
Chris@0
|
759 {"realtime", (PyCFunction)RealTime_new, METH_VARARGS,
|
Chris@0
|
760 PyDoc_STR("realtime() -> returns new RealTime object")},
|
luis@7
|
761
|
Chris@0
|
762 {NULL, NULL} /* sentinel */
|
Chris@0
|
763 };
|
Chris@0
|
764
|
Chris@0
|
765 //Documentation for our new module
|
Chris@0
|
766 PyDoc_STRVAR(module_doc, "This is a template module just for instruction.");
|
Chris@0
|
767
|
Chris@0
|
768 /* Initialization function for the module (*must* be called initxx) */
|
Chris@0
|
769
|
Chris@0
|
770 //module initialization (includes extern C {...} as necessary)
|
Chris@0
|
771 PyMODINIT_FUNC
|
Chris@0
|
772 initvampyhost(void)
|
Chris@0
|
773 {
|
Chris@0
|
774 PyObject *m;
|
Chris@0
|
775
|
Chris@0
|
776 /* Finalize the type object including setting type of the new type
|
luis@7
|
777 * object; doing it here is required for portability to Windows
|
Chris@0
|
778 * without requiring C++. */
|
Chris@0
|
779
|
Chris@0
|
780 if (PyType_Ready(&RealTime_Type) < 0)
|
Chris@0
|
781 return;
|
Chris@0
|
782 // PyModule_AddObject(m, "Real_Time", (PyObject *)&RealTime_Type);
|
Chris@0
|
783
|
Chris@0
|
784 /* Create the module and add the functions */
|
Chris@0
|
785 m = Py_InitModule3("vampyhost", vampyhost_methods, module_doc);
|
Chris@0
|
786 if (m == NULL) return;
|
Chris@0
|
787
|
luis@8
|
788 // Numpy array library initialization function
|
luis@8
|
789 import_array();
|
luis@8
|
790
|
Chris@0
|
791 // PyModule_AddObject(m, "realtime", (PyObject *)&RealTime_Type);
|
Chris@0
|
792
|
Chris@0
|
793 }
|