annotate vampyhost.cpp @ 31:f565f4b5cbaa

Pull out plugin object implementation into separate source file
author Chris Cannam
date Wed, 26 Nov 2014 11:12:00 +0000
parents 7e7f2f7d9542
children 20a9fcbc2f5f
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@0 38 //include for python extension module: must be first
Chris@0 39 #include <Python.h>
Chris@14 40
Chris@14 41 // define a unique API pointer
Chris@27 42 #define PY_ARRAY_UNIQUE_SYMBOL VAMPYHOST_ARRAY_API
Chris@14 43 #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
Chris@14 44 #include "numpy/arrayobject.h"
Chris@14 45
Chris@31 46 #include "PyRealTime.h"
Chris@31 47 #include "PyPluginObject.h"
Chris@12 48
Chris@1 49 #include "vamp-hostsdk/PluginHostAdapter.h"
Chris@1 50 #include "vamp-hostsdk/PluginChannelAdapter.h"
Chris@1 51 #include "vamp-hostsdk/PluginInputDomainAdapter.h"
Chris@1 52 #include "vamp-hostsdk/PluginLoader.h"
Chris@16 53
Chris@29 54 #include "VectorConversion.h"
Chris@16 55 #include "PyRealTime.h"
Chris@0 56
Chris@0 57 #include <iostream>
Chris@0 58 #include <string>
Chris@0 59
Chris@0 60 #include <cmath>
Chris@0 61
Chris@0 62 using namespace std;
Chris@0 63 using namespace Vamp;
Chris@31 64 using namespace Vamp::HostExt;
Chris@21 65
Chris@2 66 PyDoc_STRVAR(xx_foo_doc, "Some description"); //!!!
Chris@0 67
Chris@28 68 //!!! todo: conv errors
Chris@28 69
Chris@0 70 static PyObject *
Chris@23 71 vampyhost_enumeratePlugins(PyObject *self, PyObject *)
Chris@0 72 {
Chris@21 73 cerr << "vampyhost_enumeratePlugins" << endl;
Chris@21 74
Chris@0 75 PluginLoader *loader = PluginLoader::getInstance();
Chris@0 76 vector<PluginLoader::PluginKey> plugins = loader->listPlugins();
Chris@29 77 VectorConversion conv;
Chris@15 78 return conv.PyValue_From_StringVector(plugins);
Chris@0 79 }
Chris@0 80
Chris@15 81 static PyObject *
Chris@23 82 vampyhost_getPluginPath(PyObject *self, PyObject *)
Chris@15 83 {
Chris@21 84 cerr << "vampyhost_getPluginPath" << endl;
Chris@21 85
Chris@15 86 vector<string> path = PluginHostAdapter::getPluginPath();
Chris@29 87 VectorConversion conv;
Chris@15 88 return conv.PyValue_From_StringVector(path);
Chris@15 89 }
Chris@0 90
Chris@15 91 static string toPluginKey(PyObject *pyPluginKey)
Chris@0 92 {
Chris@21 93 cerr << "toPluginKey" << endl;
Chris@21 94
Chris@0 95 //convert to stl string
Chris@0 96 string pluginKey(PyString_AS_STRING(pyPluginKey));
Chris@0 97
Chris@0 98 //check pluginKey Validity
Chris@0 99 string::size_type ki = pluginKey.find(':');
Chris@0 100 if (ki == string::npos) {
Chris@0 101 PyErr_SetString(PyExc_TypeError,
Chris@15 102 "Plugin key must be of the form library:identifier");
Chris@15 103 return "";
Chris@0 104 }
Chris@0 105
Chris@15 106 return pluginKey;
Chris@15 107 }
Chris@15 108
Chris@15 109 static PyObject *
Chris@15 110 vampyhost_getLibraryFor(PyObject *self, PyObject *args)
Chris@15 111 {
Chris@21 112 cerr << "vampyhost_getLibraryFor" << endl;
Chris@21 113
Chris@15 114 PyObject *pyPluginKey;
Chris@15 115
Chris@15 116 if (!PyArg_ParseTuple(args, "S", &pyPluginKey)) {
Chris@15 117 PyErr_SetString(PyExc_TypeError,
Chris@15 118 "getLibraryPathForPlugin() takes plugin key (string) argument");
Chris@16 119 return 0; }
Chris@15 120
Chris@15 121 string pluginKey = toPluginKey(pyPluginKey);
Chris@16 122 if (pluginKey == "") return 0;
Chris@15 123
Chris@0 124 PluginLoader *loader = PluginLoader::getInstance();
Chris@0 125 string path = loader->getLibraryPathForPlugin(pluginKey);
Chris@0 126 PyObject *pyPath = PyString_FromString(path.c_str());
Chris@0 127 return pyPath;
Chris@0 128 }
Chris@0 129
Chris@0 130 static PyObject *
Chris@0 131 vampyhost_getPluginCategory(PyObject *self, PyObject *args)
Chris@0 132 {
Chris@21 133 cerr << "vampyhost_getPluginCategory" << endl;
Chris@21 134
Chris@0 135 PyObject *pyPluginKey;
Chris@0 136
Chris@0 137 if (!PyArg_ParseTuple(args, "S", &pyPluginKey)) {
Chris@0 138 PyErr_SetString(PyExc_TypeError,
Chris@15 139 "getPluginCategory() takes plugin key (string) argument");
Chris@16 140 return 0; }
Chris@0 141
Chris@15 142 string pluginKey = toPluginKey(pyPluginKey);
Chris@16 143 if (pluginKey == "") return 0;
Chris@0 144
Chris@0 145 PluginLoader *loader = PluginLoader::getInstance();
luis@7 146 PluginLoader::PluginCategoryHierarchy
Chris@0 147 category = loader->getPluginCategory(pluginKey);
Chris@0 148
Chris@29 149 VectorConversion conv;
Chris@15 150 return conv.PyValue_From_StringVector(category);
Chris@0 151 }
Chris@0 152
Chris@0 153 static PyObject *
Chris@0 154 vampyhost_getOutputList(PyObject *self, PyObject *args)
Chris@0 155 {
Chris@21 156 cerr << "vampyhost_getOutputList" << endl;
Chris@21 157
Chris@31 158 PyObject *pyPluginKey;
Chris@31 159
Chris@31 160 if (!PyArg_ParseTuple(args, "S", &pyPluginKey)) {
Chris@31 161 PyErr_SetString(PyExc_TypeError,
Chris@31 162 "getOutputList() takes plugin key (string) argument");
Chris@31 163 return 0; }
Chris@31 164
Chris@15 165 Plugin::OutputList outputs;
Chris@0 166
Chris@31 167 string pluginKey = toPluginKey(pyPluginKey);
Chris@31 168 if (pluginKey == "") return 0;
Chris@31 169
Chris@31 170 PluginLoader *loader = PluginLoader::getInstance();
Chris@31 171
Chris@31 172 Plugin *plugin = loader->loadPlugin
Chris@31 173 (pluginKey, 48000, PluginLoader::ADAPT_ALL_SAFE);
Chris@31 174 if (!plugin) {
Chris@31 175 string pyerr("Failed to load plugin: "); pyerr += pluginKey;
Chris@31 176 PyErr_SetString(PyExc_TypeError,pyerr.c_str());
Chris@31 177 return 0;
Chris@0 178 }
Chris@0 179
Chris@31 180 outputs = plugin->getOutputDescriptors();
luis@7 181
Chris@0 182 PyObject *pyList = PyList_New(outputs.size());
Chris@0 183
Chris@0 184 for (size_t i = 0; i < outputs.size(); ++i) {
luis@7 185 PyObject *pyOutputId =
Chris@0 186 PyString_FromString(outputs[i].identifier.c_str());
Chris@15 187 PyList_SET_ITEM(pyList, i, pyOutputId);
Chris@0 188 }
Chris@0 189
Chris@0 190 return pyList;
Chris@0 191 }
Chris@0 192
Chris@0 193 static PyObject *
Chris@0 194 vampyhost_loadPlugin(PyObject *self, PyObject *args)
Chris@0 195 {
Chris@21 196 cerr << "vampyhost_loadPlugin" << endl;
Chris@21 197
Chris@0 198 PyObject *pyPluginKey;
Chris@0 199 float inputSampleRate;
Chris@0 200
luis@7 201 if (!PyArg_ParseTuple(args, "Sf",
Chris@0 202 &pyPluginKey,
Chris@0 203 &inputSampleRate)) {
Chris@0 204 PyErr_SetString(PyExc_TypeError,
Chris@20 205 "loadPlugin() takes plugin key (string) and sample rate (float) arguments");
Chris@16 206 return 0; }
Chris@0 207
Chris@15 208 string pluginKey = toPluginKey(pyPluginKey);
Chris@16 209 if (pluginKey == "") return 0;
Chris@0 210
Chris@0 211 PluginLoader *loader = PluginLoader::getInstance();
luis@7 212
Chris@15 213 Plugin *plugin = loader->loadPlugin(pluginKey, inputSampleRate,
Chris@15 214 PluginLoader::ADAPT_ALL_SAFE);
luis@7 215 if (!plugin) {
Chris@0 216 string pyerr("Failed to load plugin: "); pyerr += pluginKey;
luis@7 217 PyErr_SetString(PyExc_TypeError,pyerr.c_str());
Chris@16 218 return 0;
luis@7 219 }
Chris@15 220
Chris@31 221 return PyPluginObject_From_Plugin(plugin);
Chris@0 222 }
Chris@0 223
Chris@18 224 // module methods table
Chris@0 225 static PyMethodDef vampyhost_methods[] = {
Chris@0 226
Chris@18 227 {"listPlugins", vampyhost_enumeratePlugins, METH_NOARGS,
Chris@0 228 xx_foo_doc},
Chris@0 229
Chris@15 230 {"getPluginPath", vampyhost_getPluginPath, METH_NOARGS,
Chris@15 231 xx_foo_doc},
Chris@15 232
Chris@18 233 {"getCategoryOf", vampyhost_getPluginCategory, METH_VARARGS,
Chris@0 234 xx_foo_doc},
Chris@0 235
Chris@18 236 {"getLibraryFor", vampyhost_getLibraryFor, METH_VARARGS,
Chris@0 237 xx_foo_doc},
Chris@0 238
Chris@18 239 {"getOutputsOf", vampyhost_getOutputList, METH_VARARGS,
Chris@0 240 xx_foo_doc},
Chris@0 241
Chris@0 242 {"loadPlugin", vampyhost_loadPlugin, METH_VARARGS,
Chris@0 243 xx_foo_doc},
Chris@0 244
Chris@16 245 {0, 0} /* sentinel */
Chris@0 246 };
Chris@0 247
Chris@0 248 //Documentation for our new module
Chris@0 249 PyDoc_STRVAR(module_doc, "This is a template module just for instruction.");
Chris@0 250
Chris@25 251 static int
Chris@25 252 setint(PyObject *d, const char *name, int value)
Chris@25 253 {
Chris@25 254 PyObject *v;
Chris@25 255 int err;
Chris@25 256 v = PyInt_FromLong((long)value);
Chris@25 257 err = PyDict_SetItemString(d, name, v);
Chris@25 258 Py_XDECREF(v);
Chris@25 259 return err;
Chris@25 260 }
Chris@14 261
Chris@0 262 /* Initialization function for the module (*must* be called initxx) */
Chris@0 263
Chris@25 264 // module initialization (includes extern C {...} as necessary)
Chris@0 265 PyMODINIT_FUNC
Chris@0 266 initvampyhost(void)
Chris@0 267 {
Chris@0 268 PyObject *m;
Chris@0 269
Chris@25 270 if (PyType_Ready(&RealTime_Type) < 0) return;
Chris@25 271 if (PyType_Ready(&Plugin_Type) < 0) return;
Chris@0 272
Chris@0 273 m = Py_InitModule3("vampyhost", vampyhost_methods, module_doc);
Chris@25 274 if (!m) {
Chris@25 275 cerr << "ERROR: initvampyhost: Failed to initialise module" << endl;
Chris@25 276 return;
Chris@25 277 }
Chris@0 278
Chris@14 279 import_array();
Chris@14 280
Chris@17 281 PyModule_AddObject(m, "RealTime", (PyObject *)&RealTime_Type);
Chris@25 282 PyModule_AddObject(m, "Plugin", (PyObject *)&Plugin_Type);
Chris@25 283
Chris@25 284 // Some enum types
Chris@25 285 PyObject *dict = PyModule_GetDict(m);
Chris@25 286 if (!dict) {
Chris@25 287 cerr << "ERROR: initvampyhost: Failed to obtain module dictionary" << endl;
Chris@25 288 return;
Chris@25 289 }
Chris@25 290
Chris@25 291 if (setint(dict, "OneSamplePerStep",
Chris@25 292 Plugin::OutputDescriptor::OneSamplePerStep) < 0 ||
Chris@25 293 setint(dict, "FixedSampleRate",
Chris@25 294 Plugin::OutputDescriptor::FixedSampleRate) < 0 ||
Chris@25 295 setint(dict, "VariableSampleRate",
Chris@25 296 Plugin::OutputDescriptor::VariableSampleRate) < 0 ||
Chris@25 297 setint(dict, "TimeDomain",
Chris@25 298 Plugin::TimeDomain) < 0 ||
Chris@25 299 setint(dict, "FrequencyDomain",
Chris@25 300 Plugin::FrequencyDomain) < 0) {
Chris@25 301 cerr << "ERROR: initvampyhost: Failed to add enums to module dictionary" << endl;
Chris@25 302 return;
Chris@25 303 }
Chris@0 304 }