annotate vampyhost.cpp @ 29:7e7f2f7d9542

PyTypeConversions -> VectorConversion
author Chris Cannam
date Wed, 26 Nov 2014 10:56:23 +0000
parents 1175e814954e
children f565f4b5cbaa
rev   line source
Chris@0 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@26 3 /*
Chris@26 4 VampyHost
Chris@26 5
Chris@26 6 Use Vamp audio analysis plugins in Python
Chris@26 7
Chris@26 8 Gyorgy Fazekas and Chris Cannam
Chris@26 9 Centre for Digital Music, Queen Mary, University of London
Chris@26 10 Copyright 2008-2014 Queen Mary, University of London
Chris@26 11
Chris@26 12 Permission is hereby granted, free of charge, to any person
Chris@26 13 obtaining a copy of this software and associated documentation
Chris@26 14 files (the "Software"), to deal in the Software without
Chris@26 15 restriction, including without limitation the rights to use, copy,
Chris@26 16 modify, merge, publish, distribute, sublicense, and/or sell copies
Chris@26 17 of the Software, and to permit persons to whom the Software is
Chris@26 18 furnished to do so, subject to the following conditions:
Chris@26 19
Chris@26 20 The above copyright notice and this permission notice shall be
Chris@26 21 included in all copies or substantial portions of the Software.
Chris@26 22
Chris@26 23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Chris@26 24 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Chris@26 25 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
Chris@26 26 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
Chris@26 27 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
Chris@26 28 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
Chris@26 29 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Chris@26 30
Chris@26 31 Except as contained in this notice, the names of the Centre for
Chris@26 32 Digital Music; Queen Mary, University of London; and the authors
Chris@26 33 shall not be used in advertising or otherwise to promote the sale,
Chris@26 34 use or other dealings in this Software without prior written
Chris@26 35 authorization.
Chris@26 36 */
Chris@26 37
Chris@26 38 #include "PyRealTime.h"
Chris@26 39
Chris@0 40 //include for python extension module: must be first
Chris@0 41 #include <Python.h>
Chris@14 42
Chris@14 43 // define a unique API pointer
Chris@27 44 #define PY_ARRAY_UNIQUE_SYMBOL VAMPYHOST_ARRAY_API
Chris@14 45 #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
Chris@14 46 #include "numpy/arrayobject.h"
Chris@14 47
Chris@0 48 #include <vampyhost.h>
Chris@12 49
Chris@12 50 #define HAVE_NUMPY 1 // Required
Chris@12 51
Chris@0 52 //includes for vamp host
Chris@1 53 #include "vamp-hostsdk/Plugin.h"
Chris@1 54 #include "vamp-hostsdk/PluginHostAdapter.h"
Chris@1 55 #include "vamp-hostsdk/PluginChannelAdapter.h"
Chris@1 56 #include "vamp-hostsdk/PluginInputDomainAdapter.h"
Chris@1 57 #include "vamp-hostsdk/PluginLoader.h"
Chris@16 58
Chris@29 59 #include "VectorConversion.h"
Chris@16 60 #include "PyRealTime.h"
Chris@0 61
Chris@0 62 #include <iostream>
Chris@0 63 #include <fstream>
Chris@0 64 #include <set>
Chris@0 65 #include <sndfile.h>
Chris@0 66
Chris@0 67 #include <cstring>
Chris@0 68 #include <cstdlib>
Chris@0 69 #include <string>
Chris@0 70
Chris@0 71 #include <cmath>
Chris@0 72
Chris@0 73 using namespace std;
Chris@0 74 using namespace Vamp;
Chris@0 75
Chris@0 76 using Vamp::Plugin;
Chris@0 77 using Vamp::PluginHostAdapter;
Chris@0 78 using Vamp::RealTime;
Chris@0 79 using Vamp::HostExt::PluginLoader;
Chris@0 80
Chris@0 81 #define HOST_VERSION "1.1"
Chris@0 82
Chris@16 83 // structure for holding plugin instance data
Chris@21 84 struct PyPluginObject
Chris@16 85 {
Chris@21 86 PyObject_HEAD
Chris@21 87 string *key;
Chris@16 88 Plugin *plugin;
Chris@16 89 float inputSampleRate;
Chris@16 90 bool isInitialised;
Chris@16 91 size_t channels;
Chris@16 92 size_t blockSize;
Chris@16 93 size_t stepSize;
Chris@21 94 static PyPluginObject *create_internal();
Chris@16 95 };
Chris@0 96
Chris@21 97 PyAPI_DATA(PyTypeObject) Plugin_Type;
Chris@21 98 #define PyPlugin_Check(v) PyObject_TypeCheck(v, &Plugin_Type)
Chris@21 99
Chris@21 100 static void
Chris@21 101 PyPluginObject_dealloc(PyPluginObject *self)
Chris@21 102 {
Chris@21 103 cerr << "PyPluginObject_dealloc" << endl;
Chris@21 104 delete self->key;
Chris@21 105 delete self->plugin;
Chris@21 106 PyObject_Del(self);
Chris@21 107 }
Chris@21 108
Chris@2 109 PyDoc_STRVAR(xx_foo_doc, "Some description"); //!!!
Chris@0 110
Chris@28 111 //!!! todo: conv errors
Chris@28 112
Chris@21 113 PyPluginObject *
Chris@21 114 getPluginObject(PyObject *pyPluginHandle)
Chris@21 115 {
Chris@21 116 cerr << "getPluginObject" << endl;
Chris@0 117
Chris@21 118 PyPluginObject *pd = 0;
Chris@21 119 if (PyPlugin_Check(pyPluginHandle)) {
Chris@21 120 pd = (PyPluginObject *)pyPluginHandle;
Chris@16 121 }
Chris@16 122 if (!pd || !pd->plugin) {
Chris@16 123 PyErr_SetString(PyExc_AttributeError,
Chris@16 124 "Invalid or already deleted plugin handle.");
Chris@16 125 return 0;
Chris@0 126 } else {
Chris@16 127 return pd;
Chris@0 128 }
Chris@0 129 }
Chris@0 130
Chris@0 131 static PyObject *
Chris@23 132 vampyhost_enumeratePlugins(PyObject *self, PyObject *)
Chris@0 133 {
Chris@21 134 cerr << "vampyhost_enumeratePlugins" << endl;
Chris@21 135
Chris@0 136 PluginLoader *loader = PluginLoader::getInstance();
Chris@0 137 vector<PluginLoader::PluginKey> plugins = loader->listPlugins();
Chris@29 138 VectorConversion conv;
Chris@15 139 return conv.PyValue_From_StringVector(plugins);
Chris@0 140 }
Chris@0 141
Chris@15 142 static PyObject *
Chris@23 143 vampyhost_getPluginPath(PyObject *self, PyObject *)
Chris@15 144 {
Chris@21 145 cerr << "vampyhost_getPluginPath" << endl;
Chris@21 146
Chris@15 147 vector<string> path = PluginHostAdapter::getPluginPath();
Chris@29 148 VectorConversion conv;
Chris@15 149 return conv.PyValue_From_StringVector(path);
Chris@15 150 }
Chris@0 151
Chris@15 152 static string toPluginKey(PyObject *pyPluginKey)
Chris@0 153 {
Chris@21 154 cerr << "toPluginKey" << endl;
Chris@21 155
Chris@0 156 //convert to stl string
Chris@0 157 string pluginKey(PyString_AS_STRING(pyPluginKey));
Chris@0 158
Chris@0 159 //check pluginKey Validity
Chris@0 160 string::size_type ki = pluginKey.find(':');
Chris@0 161 if (ki == string::npos) {
Chris@0 162 PyErr_SetString(PyExc_TypeError,
Chris@15 163 "Plugin key must be of the form library:identifier");
Chris@15 164 return "";
Chris@0 165 }
Chris@0 166
Chris@15 167 return pluginKey;
Chris@15 168 }
Chris@15 169
Chris@15 170 static PyObject *
Chris@15 171 vampyhost_getLibraryFor(PyObject *self, PyObject *args)
Chris@15 172 {
Chris@21 173 cerr << "vampyhost_getLibraryFor" << endl;
Chris@21 174
Chris@15 175 PyObject *pyPluginKey;
Chris@15 176
Chris@15 177 if (!PyArg_ParseTuple(args, "S", &pyPluginKey)) {
Chris@15 178 PyErr_SetString(PyExc_TypeError,
Chris@15 179 "getLibraryPathForPlugin() takes plugin key (string) argument");
Chris@16 180 return 0; }
Chris@15 181
Chris@15 182 string pluginKey = toPluginKey(pyPluginKey);
Chris@16 183 if (pluginKey == "") return 0;
Chris@15 184
Chris@0 185 PluginLoader *loader = PluginLoader::getInstance();
Chris@0 186 string path = loader->getLibraryPathForPlugin(pluginKey);
Chris@0 187 PyObject *pyPath = PyString_FromString(path.c_str());
Chris@0 188 return pyPath;
Chris@0 189 }
Chris@0 190
Chris@0 191 static PyObject *
Chris@0 192 vampyhost_getPluginCategory(PyObject *self, PyObject *args)
Chris@0 193 {
Chris@21 194 cerr << "vampyhost_getPluginCategory" << endl;
Chris@21 195
Chris@0 196 PyObject *pyPluginKey;
Chris@0 197
Chris@0 198 if (!PyArg_ParseTuple(args, "S", &pyPluginKey)) {
Chris@0 199 PyErr_SetString(PyExc_TypeError,
Chris@15 200 "getPluginCategory() takes plugin key (string) argument");
Chris@16 201 return 0; }
Chris@0 202
Chris@15 203 string pluginKey = toPluginKey(pyPluginKey);
Chris@16 204 if (pluginKey == "") return 0;
Chris@0 205
Chris@0 206 PluginLoader *loader = PluginLoader::getInstance();
luis@7 207 PluginLoader::PluginCategoryHierarchy
Chris@0 208 category = loader->getPluginCategory(pluginKey);
Chris@0 209
Chris@29 210 VectorConversion conv;
Chris@15 211 return conv.PyValue_From_StringVector(category);
Chris@0 212 }
Chris@0 213
Chris@0 214 static PyObject *
Chris@0 215 vampyhost_getOutputList(PyObject *self, PyObject *args)
Chris@0 216 {
Chris@21 217 cerr << "vampyhost_getOutputList" << endl;
Chris@21 218
Chris@16 219 PyObject *keyOrHandle;
Chris@15 220 Plugin::OutputList outputs;
Chris@0 221
Chris@16 222 if (!PyArg_ParseTuple(args, "O", &keyOrHandle)) {
Chris@0 223 PyErr_SetString(PyExc_TypeError,
Chris@15 224 "getOutputList() takes plugin handle (object) or plugin key (string) argument");
Chris@16 225 return 0;
Chris@0 226 }
Chris@0 227
Chris@16 228 if (PyString_Check(keyOrHandle) ) {
Chris@0 229
Chris@15 230 // we have a plugin key
Chris@0 231
Chris@16 232 string pluginKey = toPluginKey(keyOrHandle);
Chris@16 233 if (pluginKey == "") return 0;
Chris@15 234
Chris@15 235 PluginLoader *loader = PluginLoader::getInstance();
Chris@15 236
Chris@15 237 Plugin *plugin = loader->loadPlugin
Chris@15 238 (pluginKey, 48000, PluginLoader::ADAPT_ALL_SAFE);
Chris@15 239 if (!plugin) {
Chris@15 240 string pyerr("Failed to load plugin: "); pyerr += pluginKey;
Chris@15 241 PyErr_SetString(PyExc_TypeError,pyerr.c_str());
Chris@16 242 return 0;
Chris@15 243 }
Chris@15 244
Chris@15 245 outputs = plugin->getOutputDescriptors();
Chris@15 246
Chris@15 247 delete plugin;
Chris@15 248
Chris@0 249 } else {
luis@7 250
Chris@15 251 // we have a loaded plugin handle
Chris@15 252
Chris@21 253 PyPluginObject *pd = getPluginObject(keyOrHandle);
Chris@16 254 if (!pd) return 0;
Chris@0 255
Chris@16 256 outputs = pd->plugin->getOutputDescriptors();
luis@7 257 }
luis@7 258
Chris@0 259 PyObject *pyList = PyList_New(outputs.size());
Chris@0 260
Chris@0 261 for (size_t i = 0; i < outputs.size(); ++i) {
luis@7 262 PyObject *pyOutputId =
Chris@0 263 PyString_FromString(outputs[i].identifier.c_str());
Chris@15 264 PyList_SET_ITEM(pyList, i, pyOutputId);
Chris@0 265 }
Chris@0 266
Chris@0 267 return pyList;
Chris@0 268 }
Chris@0 269
Chris@0 270 static PyObject *
Chris@0 271 vampyhost_loadPlugin(PyObject *self, PyObject *args)
Chris@0 272 {
Chris@21 273 cerr << "vampyhost_loadPlugin" << endl;
Chris@21 274
Chris@0 275 PyObject *pyPluginKey;
Chris@0 276 float inputSampleRate;
Chris@0 277
luis@7 278 if (!PyArg_ParseTuple(args, "Sf",
Chris@0 279 &pyPluginKey,
Chris@0 280 &inputSampleRate)) {
Chris@0 281 PyErr_SetString(PyExc_TypeError,
Chris@20 282 "loadPlugin() takes plugin key (string) and sample rate (float) arguments");
Chris@16 283 return 0; }
Chris@0 284
Chris@15 285 string pluginKey = toPluginKey(pyPluginKey);
Chris@16 286 if (pluginKey == "") return 0;
Chris@0 287
Chris@0 288 PluginLoader *loader = PluginLoader::getInstance();
luis@7 289
Chris@15 290 Plugin *plugin = loader->loadPlugin(pluginKey, inputSampleRate,
Chris@15 291 PluginLoader::ADAPT_ALL_SAFE);
luis@7 292 if (!plugin) {
Chris@0 293 string pyerr("Failed to load plugin: "); pyerr += pluginKey;
luis@7 294 PyErr_SetString(PyExc_TypeError,pyerr.c_str());
Chris@16 295 return 0;
luis@7 296 }
Chris@15 297
Chris@21 298 PyPluginObject *pd = PyPluginObject::create_internal();
Chris@21 299 pd->key = new string(pluginKey);
Chris@21 300 pd->plugin = plugin;
Chris@21 301 pd->inputSampleRate = inputSampleRate;
Chris@21 302 pd->isInitialised = false;
Chris@21 303 pd->channels = 0;
Chris@21 304 pd->blockSize = 0;
Chris@21 305 pd->stepSize = 0;
Chris@21 306 return (PyObject *)pd;
Chris@0 307 }
Chris@0 308
Chris@0 309 static PyObject *
Chris@0 310 vampyhost_initialise(PyObject *self, PyObject *args)
Chris@0 311 {
Chris@21 312 cerr << "vampyhost_initialise" << endl;
Chris@21 313
luis@7 314 size_t channels, blockSize, stepSize;
Chris@0 315
Chris@23 316 if (!PyArg_ParseTuple (args, "nnn",
luis@7 317 (size_t) &channels,
luis@7 318 (size_t) &stepSize,
Chris@23 319 (size_t) &blockSize)) {
Chris@0 320 PyErr_SetString(PyExc_TypeError,
Chris@23 321 "initialise() takes channel count, step size, and block size arguments");
Chris@16 322 return 0;
Chris@0 323 }
Chris@0 324
Chris@23 325 PyPluginObject *pd = getPluginObject(self);
Chris@16 326 if (!pd) return 0;
Chris@0 327
Chris@16 328 pd->channels = channels;
Chris@16 329 pd->stepSize = stepSize;
Chris@16 330 pd->blockSize = blockSize;
Chris@0 331
Chris@16 332 if (!pd->plugin->initialise(channels, stepSize, blockSize)) {
Chris@17 333 cerr << "Failed to initialise native plugin adapter with channels = " << channels << ", stepSize = " << stepSize << ", blockSize = " << blockSize << " and ADAPT_ALL_SAFE set" << endl;
Chris@0 334 PyErr_SetString(PyExc_TypeError,
Chris@17 335 "Plugin initialization failed");
Chris@16 336 return 0;
Chris@6 337 }
Chris@0 338
Chris@16 339 pd->isInitialised = true;
luis@7 340
Chris@0 341 return Py_True;
Chris@0 342 }
Chris@0 343
Chris@0 344 static PyObject *
Chris@23 345 vampyhost_reset(PyObject *self, PyObject *)
Chris@18 346 {
Chris@21 347 cerr << "vampyhost_reset" << endl;
Chris@21 348
Chris@23 349 PyPluginObject *pd = getPluginObject(self);
Chris@18 350 if (!pd) return 0;
Chris@18 351
Chris@18 352 if (!pd->isInitialised) {
Chris@18 353 PyErr_SetString(PyExc_StandardError,
Chris@18 354 "Plugin has not been initialised");
Chris@18 355 return 0;
Chris@18 356 }
Chris@18 357
Chris@18 358 pd->plugin->reset();
Chris@18 359 return Py_True;
Chris@18 360 }
Chris@18 361
Chris@18 362 static PyObject *
Chris@20 363 vampyhost_getParameter(PyObject *self, PyObject *args)
Chris@20 364 {
Chris@21 365 cerr << "vampyhost_getParameter" << endl;
Chris@21 366
Chris@20 367 PyObject *pyParam;
Chris@20 368
Chris@23 369 if (!PyArg_ParseTuple(args, "S", &pyParam)) {
Chris@20 370 PyErr_SetString(PyExc_TypeError,
Chris@23 371 "getParameter() takes parameter id (string) argument");
Chris@20 372 return 0; }
Chris@20 373
Chris@23 374 PyPluginObject *pd = getPluginObject(self);
Chris@20 375 if (!pd) return 0;
Chris@20 376
Chris@20 377 float value = pd->plugin->getParameter(PyString_AS_STRING(pyParam));
Chris@20 378 return PyFloat_FromDouble(double(value));
Chris@20 379 }
Chris@20 380
Chris@20 381 static PyObject *
Chris@20 382 vampyhost_setParameter(PyObject *self, PyObject *args)
Chris@20 383 {
Chris@21 384 cerr << "vampyhost_setParameter" << endl;
Chris@21 385
Chris@20 386 PyObject *pyParam;
Chris@20 387 float value;
Chris@20 388
Chris@23 389 if (!PyArg_ParseTuple(args, "Sf", &pyParam, &value)) {
Chris@20 390 PyErr_SetString(PyExc_TypeError,
Chris@23 391 "setParameter() takes parameter id (string), and value (float) arguments");
Chris@20 392 return 0; }
Chris@20 393
Chris@23 394 PyPluginObject *pd = getPluginObject(self);
Chris@20 395 if (!pd) return 0;
Chris@20 396
Chris@20 397 pd->plugin->setParameter(PyString_AS_STRING(pyParam), value);
Chris@20 398 return Py_True;
Chris@20 399 }
Chris@20 400
Chris@20 401 static PyObject *
Chris@0 402 vampyhost_process(PyObject *self, PyObject *args)
Chris@0 403 {
Chris@21 404 cerr << "vampyhost_process" << endl;
Chris@21 405
Chris@0 406 PyObject *pyBuffer;
Chris@0 407 PyObject *pyRealTime;
Chris@0 408
Chris@23 409 if (!PyArg_ParseTuple(args, "OO",
Chris@0 410 &pyBuffer, // Audio data
Chris@0 411 &pyRealTime)) { // TimeStamp
Chris@0 412 PyErr_SetString(PyExc_TypeError,
Chris@17 413 "process() takes plugin handle (object), buffer (2D array of channels * samples floats) and timestamp (RealTime) arguments");
Chris@16 414 return 0; }
Chris@0 415
Chris@0 416 if (!PyRealTime_Check(pyRealTime)) {
Chris@0 417 PyErr_SetString(PyExc_TypeError,"Valid timestamp required.");
Chris@16 418 return 0; }
Chris@0 419
Chris@17 420 if (!PyList_Check(pyBuffer)) {
Chris@17 421 PyErr_SetString(PyExc_TypeError, "List of NumPy Array required for process input.");
Chris@17 422 return 0;
Chris@17 423 }
Chris@17 424
Chris@23 425 PyPluginObject *pd = getPluginObject(self);
Chris@16 426 if (!pd) return 0;
Chris@0 427
Chris@0 428 if (!pd->isInitialised) {
Chris@0 429 PyErr_SetString(PyExc_StandardError,
Chris@0 430 "Plugin has not been initialised.");
Chris@16 431 return 0;
Chris@16 432 }
Chris@0 433
Chris@12 434 int channels = pd->channels;
Chris@0 435
Chris@4 436 if (PyList_GET_SIZE(pyBuffer) != channels) {
Chris@17 437 cerr << "Wrong number of channels: got " << PyList_GET_SIZE(pyBuffer) << ", expected " << channels << endl;
Chris@4 438 PyErr_SetString(PyExc_TypeError, "Wrong number of channels");
Chris@16 439 return 0;
Chris@4 440 }
Chris@0 441
Chris@4 442 float **inbuf = new float *[channels];
Chris@0 443
Chris@29 444 VectorConversion typeConv;
Chris@17 445
Chris@17 446 cerr << "here!" << endl;
Chris@12 447
Chris@12 448 vector<vector<float> > data;
Chris@4 449 for (int c = 0; c < channels; ++c) {
Chris@4 450 PyObject *cbuf = PyList_GET_ITEM(pyBuffer, c);
Chris@17 451 data.push_back(typeConv.PyValue_To_FloatVector(cbuf));
Chris@12 452 }
Chris@12 453
Chris@12 454 for (int c = 0; c < channels; ++c) {
Chris@17 455 if (data[c].size() != pd->blockSize) {
Chris@17 456 cerr << "Wrong number of samples on channel " << c << ": expected " << pd->blockSize << " (plugin's block size), got " << data[c].size() << endl;
Chris@17 457 PyErr_SetString(PyExc_TypeError, "Wrong number of samples");
Chris@17 458 return 0;
Chris@17 459 }
Chris@12 460 inbuf[c] = &data[c][0];
Chris@4 461 }
Chris@0 462
Chris@17 463 cerr << "no, here!" << endl;
Chris@17 464
Chris@12 465 RealTime timeStamp = *PyRealTime_AsRealTime(pyRealTime);
Chris@0 466
Chris@18 467 cerr << "no no, here!" << endl;
Chris@0 468
Chris@18 469 Plugin::FeatureSet fs = pd->plugin->process(inbuf, timeStamp);
Chris@0 470
Chris@4 471 delete[] inbuf;
Chris@0 472
Chris@18 473 cerr << "no no no, here!" << endl;
Chris@18 474
Chris@29 475 VectorConversion conv;
Chris@18 476
Chris@18 477 PyObject *pyFs = PyDict_New();
Chris@0 478
Chris@18 479 for (Plugin::FeatureSet::const_iterator fsi = fs.begin();
Chris@18 480 fsi != fs.end(); ++fsi) {
Chris@18 481
Chris@18 482 int fno = fsi->first;
Chris@18 483 const Plugin::FeatureList &fl = fsi->second;
Chris@18 484
Chris@18 485 if (!fl.empty()) {
Chris@18 486
Chris@18 487 PyObject *pyFl = PyList_New(fl.size());
Chris@18 488
Chris@18 489 for (int fli = 0; fli < (int)fl.size(); ++fli) {
Chris@18 490
Chris@18 491 const Plugin::Feature &f = fl[fli];
Chris@18 492 PyObject *pyF = PyDict_New();
Chris@18 493
Chris@18 494 if (f.hasTimestamp) {
Chris@18 495 PyDict_SetItemString
Chris@18 496 (pyF, "timestamp", PyRealTime_FromRealTime(f.timestamp));
Chris@18 497 }
Chris@18 498 if (f.hasDuration) {
Chris@18 499 PyDict_SetItemString
Chris@18 500 (pyF, "duration", PyRealTime_FromRealTime(f.duration));
Chris@18 501 }
Chris@18 502
Chris@18 503 PyDict_SetItemString
Chris@18 504 (pyF, "label", PyString_FromString(f.label.c_str()));
Chris@18 505
Chris@18 506 if (!f.values.empty()) {
Chris@18 507 PyDict_SetItemString
Chris@28 508 (pyF, "values", conv.PyArray_From_FloatVector(f.values));
Chris@18 509 }
Chris@18 510
Chris@18 511 PyList_SET_ITEM(pyFl, fli, pyF);
Chris@18 512 }
Chris@18 513
Chris@18 514 PyObject *pyN = PyInt_FromLong(fno);
Chris@18 515 PyDict_SetItem(pyFs, pyN, pyFl);
Chris@18 516 }
Chris@18 517 }
Chris@18 518
Chris@18 519 cerr << "no you fool, here!" << endl;
Chris@18 520
Chris@18 521 return pyFs;
Chris@0 522 }
Chris@0 523
Chris@23 524 static PyObject *
Chris@23 525 vampyhost_unload(PyObject *self, PyObject *)
Chris@23 526 {
Chris@23 527 cerr << "vampyhost_unloadPlugin" << endl;
Chris@23 528
Chris@23 529 PyPluginObject *pd = getPluginObject(self);
Chris@23 530 if (!pd) return 0;
Chris@23 531
Chris@23 532 delete pd->plugin;
Chris@23 533 pd->plugin = 0; // This is checked by getPluginObject, so we
Chris@23 534 // attempt to avoid repeated calls from blowing up
Chris@23 535
Chris@23 536 return Py_True;
Chris@23 537 }
Chris@23 538
Chris@21 539 static PyMethodDef PyPluginObject_methods[] =
Chris@21 540 {
Chris@23 541 {"getParameter", vampyhost_getParameter, METH_VARARGS,
Chris@23 542 xx_foo_doc}, //!!! fix all these!
Chris@23 543
Chris@23 544 {"setParameter", vampyhost_setParameter, METH_VARARGS,
Chris@23 545 xx_foo_doc},
Chris@23 546
Chris@23 547 {"initialise", vampyhost_initialise, METH_VARARGS,
Chris@23 548 xx_foo_doc},
Chris@23 549
Chris@23 550 {"reset", vampyhost_reset, METH_NOARGS,
Chris@23 551 xx_foo_doc},
Chris@23 552
Chris@23 553 {"process", vampyhost_process, METH_VARARGS,
Chris@23 554 xx_foo_doc},
Chris@23 555
Chris@23 556 {"unload", vampyhost_unload, METH_NOARGS,
Chris@23 557 xx_foo_doc},
Chris@23 558
Chris@21 559 {0, 0}
Chris@21 560 };
Chris@21 561
Chris@23 562 static int
Chris@23 563 PyPluginObject_setattr(PyPluginObject *self, char *name, PyObject *value)
Chris@23 564 {
Chris@23 565 return -1;
Chris@23 566 }
Chris@23 567
Chris@23 568 static PyObject *
Chris@23 569 PyPluginObject_getattr(PyPluginObject *self, char *name)
Chris@23 570 {
Chris@23 571 return Py_FindMethod(PyPluginObject_methods, (PyObject *)self, name);
Chris@23 572 }
Chris@23 573
Chris@21 574 /* Doc:: 10.3 Type Objects */ /* static */
Chris@21 575 PyTypeObject Plugin_Type =
Chris@21 576 {
Chris@21 577 PyObject_HEAD_INIT(NULL)
Chris@21 578 0, /*ob_size*/
Chris@21 579 "vampyhost.Plugin", /*tp_name*/
Chris@21 580 sizeof(PyPluginObject), /*tp_basicsize*/
Chris@21 581 0, /*tp_itemsize*/
Chris@21 582 (destructor)PyPluginObject_dealloc, /*tp_dealloc*/
Chris@21 583 0, /*tp_print*/
Chris@23 584 (getattrfunc)PyPluginObject_getattr, /*tp_getattr*/
Chris@23 585 (setattrfunc)PyPluginObject_setattr, /*tp_setattr*/
Chris@21 586 0, /*tp_compare*/
Chris@21 587 0, /*tp_repr*/
Chris@21 588 0, /*tp_as_number*/
Chris@21 589 0, /*tp_as_sequence*/
Chris@21 590 0, /*tp_as_mapping*/
Chris@21 591 0, /*tp_hash*/
Chris@21 592 0, /*tp_call*/
Chris@21 593 0, /*tp_str*/
Chris@21 594 0, /*tp_getattro*/
Chris@21 595 0, /*tp_setattro*/
Chris@21 596 0, /*tp_as_buffer*/
Chris@21 597 Py_TPFLAGS_DEFAULT, /*tp_flags*/
Chris@21 598 "Plugin Object", /*tp_doc*/
Chris@21 599 0, /*tp_traverse*/
Chris@21 600 0, /*tp_clear*/
Chris@21 601 0, /*tp_richcompare*/
Chris@21 602 0, /*tp_weaklistoffset*/
Chris@21 603 0, /*tp_iter*/
Chris@21 604 0, /*tp_iternext*/
Chris@21 605 PyPluginObject_methods, /*tp_methods*/
Chris@21 606 0, /*tp_members*/
Chris@21 607 0, /*tp_getset*/
Chris@21 608 0, /*tp_base*/
Chris@21 609 0, /*tp_dict*/
Chris@21 610 0, /*tp_descr_get*/
Chris@21 611 0, /*tp_descr_set*/
Chris@21 612 0, /*tp_dictoffset*/
Chris@21 613 0, /*tp_init*/
Chris@21 614 PyType_GenericAlloc, /*tp_alloc*/
Chris@21 615 0, /*tp_new*/
Chris@21 616 PyObject_Del, /*tp_free*/
Chris@21 617 0, /*tp_is_gc*/
Chris@21 618 };
Chris@0 619
Chris@18 620 // module methods table
Chris@0 621 static PyMethodDef vampyhost_methods[] = {
Chris@0 622
Chris@18 623 {"listPlugins", vampyhost_enumeratePlugins, METH_NOARGS,
Chris@0 624 xx_foo_doc},
Chris@0 625
Chris@15 626 {"getPluginPath", vampyhost_getPluginPath, METH_NOARGS,
Chris@15 627 xx_foo_doc},
Chris@15 628
Chris@18 629 {"getCategoryOf", vampyhost_getPluginCategory, METH_VARARGS,
Chris@0 630 xx_foo_doc},
Chris@0 631
Chris@18 632 {"getLibraryFor", vampyhost_getLibraryFor, METH_VARARGS,
Chris@0 633 xx_foo_doc},
Chris@0 634
Chris@18 635 {"getOutputsOf", vampyhost_getOutputList, METH_VARARGS,
Chris@0 636 xx_foo_doc},
Chris@0 637
Chris@0 638 {"loadPlugin", vampyhost_loadPlugin, METH_VARARGS,
Chris@0 639 xx_foo_doc},
Chris@0 640
Chris@16 641 {0, 0} /* sentinel */
Chris@0 642 };
Chris@0 643
Chris@21 644 PyPluginObject *
Chris@21 645 PyPluginObject::create_internal()
Chris@21 646 {
Chris@21 647 return (PyPluginObject *)PyType_GenericAlloc(&Plugin_Type, 0);
Chris@21 648 }
Chris@21 649
Chris@0 650 //Documentation for our new module
Chris@0 651 PyDoc_STRVAR(module_doc, "This is a template module just for instruction.");
Chris@0 652
Chris@25 653 static int
Chris@25 654 setint(PyObject *d, const char *name, int value)
Chris@25 655 {
Chris@25 656 PyObject *v;
Chris@25 657 int err;
Chris@25 658 v = PyInt_FromLong((long)value);
Chris@25 659 err = PyDict_SetItemString(d, name, v);
Chris@25 660 Py_XDECREF(v);
Chris@25 661 return err;
Chris@25 662 }
Chris@14 663
Chris@0 664 /* Initialization function for the module (*must* be called initxx) */
Chris@0 665
Chris@25 666 // module initialization (includes extern C {...} as necessary)
Chris@0 667 PyMODINIT_FUNC
Chris@0 668 initvampyhost(void)
Chris@0 669 {
Chris@0 670 PyObject *m;
Chris@0 671
Chris@25 672 if (PyType_Ready(&RealTime_Type) < 0) return;
Chris@25 673 if (PyType_Ready(&Plugin_Type) < 0) return;
Chris@0 674
Chris@0 675 m = Py_InitModule3("vampyhost", vampyhost_methods, module_doc);
Chris@25 676 if (!m) {
Chris@25 677 cerr << "ERROR: initvampyhost: Failed to initialise module" << endl;
Chris@25 678 return;
Chris@25 679 }
Chris@0 680
Chris@14 681 import_array();
Chris@14 682
Chris@17 683 PyModule_AddObject(m, "RealTime", (PyObject *)&RealTime_Type);
Chris@25 684 PyModule_AddObject(m, "Plugin", (PyObject *)&Plugin_Type);
Chris@25 685
Chris@25 686 // Some enum types
Chris@25 687 PyObject *dict = PyModule_GetDict(m);
Chris@25 688 if (!dict) {
Chris@25 689 cerr << "ERROR: initvampyhost: Failed to obtain module dictionary" << endl;
Chris@25 690 return;
Chris@25 691 }
Chris@25 692
Chris@25 693 if (setint(dict, "OneSamplePerStep",
Chris@25 694 Plugin::OutputDescriptor::OneSamplePerStep) < 0 ||
Chris@25 695 setint(dict, "FixedSampleRate",
Chris@25 696 Plugin::OutputDescriptor::FixedSampleRate) < 0 ||
Chris@25 697 setint(dict, "VariableSampleRate",
Chris@25 698 Plugin::OutputDescriptor::VariableSampleRate) < 0 ||
Chris@25 699 setint(dict, "TimeDomain",
Chris@25 700 Plugin::TimeDomain) < 0 ||
Chris@25 701 setint(dict, "FrequencyDomain",
Chris@25 702 Plugin::FrequencyDomain) < 0) {
Chris@25 703 cerr << "ERROR: initvampyhost: Failed to add enums to module dictionary" << endl;
Chris@25 704 return;
Chris@25 705 }
Chris@0 706 }