annotate vampyhost.cpp @ 16:7987e3123909

Rationalise plugin handle management
author Chris Cannam
date Mon, 24 Nov 2014 14:39:56 +0000
parents 8b264cabbc28
children 3893b76daf80
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@0 3 //include for python extension module: must be first
Chris@0 4 #include <Python.h>
Chris@14 5
Chris@14 6 // define a unique API pointer
Chris@14 7 #define PY_ARRAY_UNIQUE_SYMBOL VAMPY_ARRAY_API
Chris@14 8 #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
Chris@14 9 #include "numpy/arrayobject.h"
Chris@14 10
Chris@0 11 #include <vampyhost.h>
Chris@12 12
Chris@12 13 #define HAVE_NUMPY 1 // Required
Chris@12 14
Chris@0 15 //includes for vamp host
Chris@1 16 #include "vamp-hostsdk/Plugin.h"
Chris@1 17 #include "vamp-hostsdk/PluginHostAdapter.h"
Chris@1 18 #include "vamp-hostsdk/PluginChannelAdapter.h"
Chris@1 19 #include "vamp-hostsdk/PluginInputDomainAdapter.h"
Chris@1 20 #include "vamp-hostsdk/PluginLoader.h"
Chris@16 21
Chris@16 22 #include "PyTypeConversions.h"
Chris@16 23 #include "PyRealTime.h"
Chris@0 24
Chris@0 25 #include <iostream>
Chris@0 26 #include <fstream>
Chris@0 27 #include <set>
Chris@0 28 #include <sndfile.h>
Chris@0 29
Chris@0 30 #include <cstring>
Chris@0 31 #include <cstdlib>
Chris@0 32 #include <string>
Chris@0 33
Chris@0 34 #include <cmath>
Chris@0 35
Chris@0 36 using namespace std;
Chris@0 37 using namespace Vamp;
Chris@0 38
Chris@0 39 using Vamp::Plugin;
Chris@0 40 using Vamp::PluginHostAdapter;
Chris@0 41 using Vamp::RealTime;
Chris@0 42 using Vamp::HostExt::PluginLoader;
Chris@0 43
Chris@0 44 #define HOST_VERSION "1.1"
Chris@0 45
Chris@16 46 // structure for holding plugin instance data
Chris@16 47 struct PyPluginData
Chris@16 48 {
Chris@16 49 PyPluginData(string k, Plugin *p, float rate) :
Chris@16 50 key(k),
Chris@16 51 plugin(p),
Chris@16 52 inputSampleRate(rate),
Chris@16 53 isInitialised(false),
Chris@16 54 channels(0),
Chris@16 55 blockSize(0),
Chris@16 56 stepSize(0) {
Chris@16 57 }
Chris@16 58
Chris@16 59 string key;
Chris@16 60 Plugin *plugin;
Chris@16 61 float inputSampleRate;
Chris@16 62 bool isInitialised;
Chris@16 63 size_t channels;
Chris@16 64 size_t blockSize;
Chris@16 65 size_t stepSize;
Chris@16 66 Vamp::Plugin::FeatureSet output;
Chris@16 67 };
Chris@0 68
Chris@0 69 /* MODULE HELPER FUNCTIONS */
Chris@2 70 PyDoc_STRVAR(xx_foo_doc, "Some description"); //!!!
Chris@0 71
Chris@16 72 //!!! nb "The CObject API is deprecated" https://docs.python.org/2/c-api/cobject.html
Chris@0 73
Chris@16 74 PyPluginData *
Chris@16 75 getPluginData(PyObject *pyPluginHandle)
Chris@16 76 {
Chris@16 77 PyPluginData *pd = 0;
Chris@16 78 if (PyCObject_Check(pyPluginHandle)) {
Chris@16 79 pd = (PyPluginData *)PyCObject_AsVoidPtr(pyPluginHandle);
Chris@16 80 }
Chris@16 81 if (!pd || !pd->plugin) {
Chris@16 82 PyErr_SetString(PyExc_AttributeError,
Chris@16 83 "Invalid or already deleted plugin handle.");
Chris@16 84 return 0;
Chris@0 85 } else {
Chris@16 86 return pd;
Chris@0 87 }
Chris@0 88 }
Chris@0 89
Chris@0 90 static PyObject *
Chris@0 91 vampyhost_enumeratePlugins(PyObject *self, PyObject *args)
Chris@0 92 {
Chris@0 93 PluginLoader *loader = PluginLoader::getInstance();
Chris@0 94 vector<PluginLoader::PluginKey> plugins = loader->listPlugins();
Chris@15 95 PyTypeConversions conv;
Chris@15 96 return conv.PyValue_From_StringVector(plugins);
Chris@0 97 }
Chris@0 98
Chris@15 99 static PyObject *
Chris@15 100 vampyhost_getPluginPath(PyObject *self, PyObject *args)
Chris@15 101 {
Chris@15 102 vector<string> path = PluginHostAdapter::getPluginPath();
Chris@15 103 PyTypeConversions conv;
Chris@15 104 return conv.PyValue_From_StringVector(path);
Chris@15 105 }
Chris@0 106
Chris@15 107 static string toPluginKey(PyObject *pyPluginKey)
Chris@0 108 {
Chris@0 109 //convert to stl string
Chris@0 110 string pluginKey(PyString_AS_STRING(pyPluginKey));
Chris@0 111
Chris@0 112 //check pluginKey Validity
Chris@0 113 string::size_type ki = pluginKey.find(':');
Chris@0 114 if (ki == string::npos) {
Chris@0 115 PyErr_SetString(PyExc_TypeError,
Chris@15 116 "Plugin key must be of the form library:identifier");
Chris@15 117 return "";
Chris@0 118 }
Chris@0 119
Chris@15 120 return pluginKey;
Chris@15 121 }
Chris@15 122
Chris@15 123 static PyObject *
Chris@15 124 vampyhost_getLibraryFor(PyObject *self, PyObject *args)
Chris@15 125 {
Chris@15 126 PyObject *pyPluginKey;
Chris@15 127
Chris@15 128 if (!PyArg_ParseTuple(args, "S", &pyPluginKey)) {
Chris@15 129 PyErr_SetString(PyExc_TypeError,
Chris@15 130 "getLibraryPathForPlugin() takes plugin key (string) argument");
Chris@16 131 return 0; }
Chris@15 132
Chris@15 133 string pluginKey = toPluginKey(pyPluginKey);
Chris@16 134 if (pluginKey == "") return 0;
Chris@15 135
Chris@0 136 PluginLoader *loader = PluginLoader::getInstance();
Chris@0 137 string path = loader->getLibraryPathForPlugin(pluginKey);
Chris@0 138 PyObject *pyPath = PyString_FromString(path.c_str());
Chris@0 139 return pyPath;
Chris@0 140 }
Chris@0 141
Chris@0 142 static PyObject *
Chris@0 143 vampyhost_getPluginCategory(PyObject *self, PyObject *args)
Chris@0 144 {
Chris@0 145 PyObject *pyPluginKey;
Chris@0 146
Chris@0 147 if (!PyArg_ParseTuple(args, "S", &pyPluginKey)) {
Chris@0 148 PyErr_SetString(PyExc_TypeError,
Chris@15 149 "getPluginCategory() takes plugin key (string) argument");
Chris@16 150 return 0; }
Chris@0 151
Chris@15 152 string pluginKey = toPluginKey(pyPluginKey);
Chris@16 153 if (pluginKey == "") return 0;
Chris@0 154
Chris@0 155 PluginLoader *loader = PluginLoader::getInstance();
luis@7 156 PluginLoader::PluginCategoryHierarchy
Chris@0 157 category = loader->getPluginCategory(pluginKey);
Chris@0 158
Chris@15 159 PyTypeConversions conv;
Chris@15 160 return conv.PyValue_From_StringVector(category);
Chris@0 161 }
Chris@0 162
Chris@0 163 static PyObject *
Chris@0 164 vampyhost_getOutputList(PyObject *self, PyObject *args)
Chris@0 165 {
Chris@16 166 PyObject *keyOrHandle;
Chris@15 167 Plugin::OutputList outputs;
Chris@0 168
Chris@16 169 if (!PyArg_ParseTuple(args, "O", &keyOrHandle)) {
Chris@0 170 PyErr_SetString(PyExc_TypeError,
Chris@15 171 "getOutputList() takes plugin handle (object) or plugin key (string) argument");
Chris@16 172 return 0;
Chris@0 173 }
Chris@0 174
Chris@16 175 if (PyString_Check(keyOrHandle) ) {
Chris@0 176
Chris@15 177 // we have a plugin key
Chris@0 178
Chris@16 179 string pluginKey = toPluginKey(keyOrHandle);
Chris@16 180 if (pluginKey == "") return 0;
Chris@15 181
Chris@15 182 PluginLoader *loader = PluginLoader::getInstance();
Chris@15 183
Chris@15 184 Plugin *plugin = loader->loadPlugin
Chris@15 185 (pluginKey, 48000, PluginLoader::ADAPT_ALL_SAFE);
Chris@15 186 if (!plugin) {
Chris@15 187 string pyerr("Failed to load plugin: "); pyerr += pluginKey;
Chris@15 188 PyErr_SetString(PyExc_TypeError,pyerr.c_str());
Chris@16 189 return 0;
Chris@15 190 }
Chris@15 191
Chris@15 192 outputs = plugin->getOutputDescriptors();
Chris@15 193
Chris@15 194 delete plugin;
Chris@15 195
Chris@0 196 } else {
luis@7 197
Chris@15 198 // we have a loaded plugin handle
Chris@15 199
Chris@16 200 PyPluginData *pd = getPluginData(keyOrHandle);
Chris@16 201 if (!pd) return 0;
Chris@0 202
Chris@16 203 outputs = pd->plugin->getOutputDescriptors();
luis@7 204 }
luis@7 205
Chris@0 206 PyObject *pyList = PyList_New(outputs.size());
Chris@0 207
Chris@0 208 for (size_t i = 0; i < outputs.size(); ++i) {
luis@7 209 PyObject *pyOutputId =
Chris@0 210 PyString_FromString(outputs[i].identifier.c_str());
Chris@15 211 PyList_SET_ITEM(pyList, i, pyOutputId);
Chris@0 212 }
Chris@0 213
Chris@0 214 return pyList;
Chris@0 215 }
Chris@0 216
Chris@0 217 static PyObject *
Chris@0 218 vampyhost_loadPlugin(PyObject *self, PyObject *args)
Chris@0 219 {
Chris@0 220 PyObject *pyPluginKey;
Chris@0 221 float inputSampleRate;
Chris@0 222
luis@7 223 if (!PyArg_ParseTuple(args, "Sf",
Chris@0 224 &pyPluginKey,
Chris@0 225 &inputSampleRate)) {
Chris@0 226 PyErr_SetString(PyExc_TypeError,
Chris@15 227 "loadPlugin() takes plugin key (string) and sample rate (number) arguments");
Chris@16 228 return 0; }
Chris@0 229
Chris@15 230 string pluginKey = toPluginKey(pyPluginKey);
Chris@16 231 if (pluginKey == "") return 0;
Chris@0 232
Chris@0 233 PluginLoader *loader = PluginLoader::getInstance();
luis@7 234
Chris@15 235 Plugin *plugin = loader->loadPlugin(pluginKey, inputSampleRate,
Chris@15 236 PluginLoader::ADAPT_ALL_SAFE);
luis@7 237 if (!plugin) {
Chris@0 238 string pyerr("Failed to load plugin: "); pyerr += pluginKey;
luis@7 239 PyErr_SetString(PyExc_TypeError,pyerr.c_str());
Chris@16 240 return 0;
luis@7 241 }
Chris@15 242
Chris@16 243 PyPluginData *pd = new PyPluginData(pluginKey, plugin, inputSampleRate);
Chris@16 244 return PyCObject_FromVoidPtr(pd, 0);
Chris@0 245 }
Chris@0 246
Chris@0 247 static PyObject *
Chris@0 248 vampyhost_unloadPlugin(PyObject *self, PyObject *args)
Chris@0 249 {
Chris@0 250 PyObject *pyPluginHandle;
Chris@0 251
Chris@0 252 if (!PyArg_ParseTuple(args, "O", &pyPluginHandle)) {
Chris@0 253 PyErr_SetString(PyExc_TypeError,
Chris@16 254 "unloadPlugin() takes plugin handle (object) argument");
Chris@16 255 return 0;
Chris@16 256 }
Chris@0 257
Chris@16 258 PyPluginData *pd = getPluginData(pyPluginHandle);
Chris@16 259 if (!pd) return 0;
Chris@0 260
Chris@16 261 /* Prevent repeated calls from causing segfault since it will fail
Chris@16 262 * type checking the 2nd time: */
Chris@16 263 PyCObject_SetVoidPtr(pyPluginHandle, 0);
Chris@0 264
Chris@16 265 delete pd->plugin;
Chris@0 266 delete pd;
Chris@0 267 return pyPluginHandle;
Chris@0 268 }
Chris@0 269
Chris@0 270
Chris@0 271 /* INITIALISE PLUGIN */
Chris@0 272
Chris@0 273 static PyObject *
Chris@0 274 vampyhost_initialise(PyObject *self, PyObject *args)
Chris@0 275 {
Chris@0 276 PyObject *pyPluginHandle;
luis@7 277 size_t channels, blockSize, stepSize;
Chris@0 278
luis@7 279 if (!PyArg_ParseTuple (args, "Onnn", &pyPluginHandle,
luis@7 280 (size_t) &channels,
luis@7 281 (size_t) &stepSize,
luis@7 282 (size_t) &blockSize))
Chris@0 283 {
Chris@0 284 PyErr_SetString(PyExc_TypeError,
Chris@0 285 "Wrong input arguments: requires a valid plugin handle,channels,stepSize,blockSize.");
Chris@16 286 return 0;
Chris@0 287 }
Chris@0 288
Chris@16 289 PyPluginData *pd = getPluginData(pyPluginHandle);
Chris@16 290 if (!pd) return 0;
Chris@0 291
Chris@16 292 pd->channels = channels;
Chris@16 293 pd->stepSize = stepSize;
Chris@16 294 pd->blockSize = blockSize;
Chris@0 295
Chris@16 296 if (!pd->plugin->initialise(channels, stepSize, blockSize)) {
Chris@6 297 std::cerr << "Failed to initialise native plugin adapter with channels = " << channels << ", stepSize = " << stepSize << ", blockSize = " << blockSize << " and ADAPT_ALL_SAFE set" << std::endl;
Chris@0 298 PyErr_SetString(PyExc_TypeError,
Chris@0 299 "Plugin initialization failed.");
Chris@16 300 return 0;
Chris@6 301 }
Chris@0 302
Chris@16 303 pd->isInitialised = true;
luis@7 304
Chris@0 305 return Py_True;
Chris@0 306 }
Chris@0 307
Chris@0 308 /* RUN PROCESS */
Chris@0 309
Chris@0 310 static PyObject *
Chris@0 311 vampyhost_process(PyObject *self, PyObject *args)
Chris@0 312 {
Chris@0 313 PyObject *pyPluginHandle;
Chris@0 314 PyObject *pyBuffer;
Chris@0 315 PyObject *pyRealTime;
Chris@0 316
luis@7 317 if (!PyArg_ParseTuple(args, "OOO",
Chris@0 318 &pyPluginHandle, // C object holding a pointer to a plugin and its descriptor
Chris@0 319 &pyBuffer, // Audio data
Chris@0 320 &pyRealTime)) { // TimeStamp
Chris@0 321 PyErr_SetString(PyExc_TypeError,
Chris@0 322 "Required: plugin handle, buffer, timestmap.");
Chris@16 323 return 0; }
Chris@0 324
Chris@0 325 if (!PyRealTime_Check(pyRealTime)) {
Chris@0 326 PyErr_SetString(PyExc_TypeError,"Valid timestamp required.");
Chris@16 327 return 0; }
Chris@0 328
Chris@16 329 PyPluginData *pd = getPluginData(pyPluginHandle);
Chris@16 330 if (!pd) return 0;
Chris@0 331
Chris@0 332 if (!pd->isInitialised) {
Chris@0 333 PyErr_SetString(PyExc_StandardError,
Chris@0 334 "Plugin has not been initialised.");
Chris@16 335 return 0;
Chris@16 336 }
Chris@0 337
Chris@12 338 int channels = pd->channels;
Chris@12 339 // int blockSize = pd->blockSize;
Chris@0 340
Chris@4 341 if (!PyList_Check(pyBuffer)) {
Chris@4 342 PyErr_SetString(PyExc_TypeError, "List of NumPy Array required for process input.");
Chris@16 343 return 0;
Chris@0 344 }
Chris@0 345
Chris@4 346 if (PyList_GET_SIZE(pyBuffer) != channels) {
Chris@6 347 std::cerr << "Wrong number of channels: got " << PyList_GET_SIZE(pyBuffer) << ", expected " << channels << std::endl;
Chris@4 348 PyErr_SetString(PyExc_TypeError, "Wrong number of channels");
Chris@16 349 return 0;
Chris@4 350 }
Chris@0 351
Chris@4 352 float **inbuf = new float *[channels];
Chris@0 353
Chris@12 354 PyTypeConversions typeConv;
Chris@12 355 typeConv.setNumpyInstalled(true);
Chris@12 356
Chris@12 357 vector<vector<float> > data;
Chris@4 358 for (int c = 0; c < channels; ++c) {
Chris@4 359 PyObject *cbuf = PyList_GET_ITEM(pyBuffer, c);
Chris@12 360 data.push_back(typeConv.PyArray_To_FloatVector(cbuf));
Chris@12 361 }
Chris@12 362
Chris@12 363 for (int c = 0; c < channels; ++c) {
Chris@12 364 inbuf[c] = &data[c][0];
Chris@4 365 }
Chris@0 366
Chris@12 367 RealTime timeStamp = *PyRealTime_AsRealTime(pyRealTime);
Chris@0 368
Chris@0 369 //Call process and store the output
Chris@16 370 pd->output = pd->plugin->process(inbuf, timeStamp);
Chris@0 371
Chris@0 372 /* TODO: DO SOMETHONG WITH THE FEATURE SET HERE */
Chris@0 373 /// convert to appropriate python objects, reuse types and conversion utilities from Vampy ...
Chris@0 374
Chris@4 375 delete[] inbuf;
Chris@0 376
Chris@16 377 return 0; //!!! Need to return actual features!
Chris@0 378
Chris@0 379 }
Chris@0 380
Chris@0 381 /* GET / SET OUTPUT */
Chris@0 382
Chris@0 383 //getOutput(plugin,outputNo)
Chris@0 384 static PyObject *
Chris@0 385 vampyhost_getOutput(PyObject *self, PyObject *args) {
Chris@0 386
Chris@0 387 PyObject *pyPluginHandle;
Chris@0 388 // PyObject *pyBuffer;
Chris@0 389 // PyObject *pyRealTime;
Chris@0 390 PyObject *pyOutput;
Chris@0 391
luis@7 392 if (!PyArg_ParseTuple(args, "OO",
Chris@0 393 &pyPluginHandle, // C object holding a pointer to a plugin and its descriptor
Chris@0 394 &pyOutput)) { // Output reference
Chris@0 395 PyErr_SetString(PyExc_TypeError,
Chris@0 396 "Required: plugin handle, buffer, timestmap.");
Chris@16 397 return 0; }
Chris@0 398
Chris@16 399 PyPluginData *pd = getPluginData(pyPluginHandle);
Chris@16 400 if (!pd) return 0;
Chris@0 401
Chris@0 402 unsigned int outputNo = (unsigned int) PyInt_AS_LONG(pyOutput);
Chris@0 403
Chris@0 404 //Get output list: but we don't need it
Chris@0 405 //Plugin::FeatureList features = pd->output[outputNo];
Chris@0 406
Chris@0 407 size_t outLength = pd->output[outputNo].size();
Chris@0 408
Chris@0 409 //New PyList for the featurelist
Chris@0 410 PyObject *pyFeatureList = PyList_New(outLength);
Chris@0 411
Chris@0 412 for (size_t i = 0; i < outLength; ++i) {
Chris@0 413 // Test:
Chris@0 414 /*
luis@7 415 XxoObject *pyFeature = PyObject_New(XxoObject, &Xxo_Type);
Chris@16 416 if (pyFeature == 0) break; //return 0;
Chris@0 417
Chris@16 418 pyFeature->x_attr = 0;
Chris@0 419 pyFeature->feature = &pd->output[outputNo][i];
Chris@0 420
luis@7 421 PyList_SET_ITEM(pyFeatureList,i,(PyObject*)pyFeature);
Chris@0 422 */
Chris@0 423 }
Chris@0 424
Chris@0 425 Py_INCREF(pyFeatureList);
Chris@0 426 return pyFeatureList;
Chris@0 427
Chris@0 428 // EXPLAIN WHAT WE NEED TO DO HERE:
Chris@0 429 // We have the block output in pd->output
luis@7 430 // FeatureSet[output] -> [Feature[x]] -> Feature.hasTimestamp = v
luis@7 431 // Vamp::Plugin::FeatureSet output; = pd->output
Chris@0 432 // typedef std::vector<Feature> FeatureList;
Chris@0 433 // typedef std::map<int, FeatureList> FeatureSet; // key is output no
Chris@0 434
luis@7 435 // THIS IS FOR OUTPUT id LOOKUP LATER
Chris@0 436 // Plugin::OutputList outputs = plugin->getOutputDescriptors();
luis@7 437 //
Chris@0 438 // if (outputs.size()<1) {
Chris@0 439 // string pyerr("Plugin has no output: "); pyerr += pluginKey;
luis@7 440 // PyErr_SetString(PyExc_TypeError,pyerr.c_str());
Chris@16 441 // return 0;
Chris@0 442 // }
luis@7 443 //
Chris@0 444 // //New list object
Chris@0 445 // PyObject *pyList = PyList_New(outputs.size());
luis@7 446 //
Chris@0 447 // for (size_t i = 0; i < outputs.size(); ++i) {
luis@7 448 // PyObject *pyOutputId =
Chris@0 449 // PyString_FromString(outputs[i].identifier.c_str());
luis@7 450 // PyList_SET_ITEM(pyList,i,pyOutputId);
Chris@0 451 // }
luis@7 452
Chris@0 453 }
Chris@0 454
Chris@0 455
Chris@0 456
Chris@0 457
Chris@0 458 /* List of functions defined in this module */
Chris@0 459 //module methods table
Chris@0 460 static PyMethodDef vampyhost_methods[] = {
Chris@0 461
Chris@15 462 {"enumeratePlugins", vampyhost_enumeratePlugins, METH_NOARGS,
Chris@0 463 xx_foo_doc},
Chris@0 464
Chris@15 465 {"getPluginPath", vampyhost_getPluginPath, METH_NOARGS,
Chris@15 466 xx_foo_doc},
Chris@15 467
Chris@15 468 {"getLibraryForPlugin", vampyhost_getLibraryFor, METH_VARARGS,
Chris@0 469 xx_foo_doc},
Chris@0 470
Chris@0 471 {"getPluginCategory", vampyhost_getPluginCategory, METH_VARARGS,
Chris@0 472 xx_foo_doc},
Chris@0 473
Chris@0 474 {"getOutputList", vampyhost_getOutputList, METH_VARARGS,
Chris@0 475 xx_foo_doc},
Chris@0 476
Chris@0 477 {"loadPlugin", vampyhost_loadPlugin, METH_VARARGS,
Chris@0 478 xx_foo_doc},
Chris@0 479
Chris@0 480 {"process", vampyhost_process, METH_VARARGS,
Chris@0 481 xx_foo_doc},
Chris@0 482
Chris@0 483 {"unloadPlugin", vampyhost_unloadPlugin, METH_VARARGS,
Chris@0 484 xx_foo_doc},
Chris@0 485
Chris@0 486 {"initialise", vampyhost_initialise, METH_VARARGS,
Chris@0 487 xx_foo_doc},
Chris@0 488
Chris@0 489 {"getOutput", vampyhost_getOutput, METH_VARARGS,
Chris@0 490 xx_foo_doc},
Chris@0 491
Chris@0 492 /* Add RealTime Module Methods */
Chris@12 493 /*
Chris@0 494 {"frame2RealTime", (PyCFunction)RealTime_frame2RealTime, METH_VARARGS,
Chris@0 495 PyDoc_STR("frame2RealTime((int64)frame, (uint32)sampleRate ) -> returns new RealTime object from frame.")},
Chris@0 496
Chris@0 497 {"realtime", (PyCFunction)RealTime_new, METH_VARARGS,
Chris@0 498 PyDoc_STR("realtime() -> returns new RealTime object")},
Chris@12 499 */
Chris@16 500 {0, 0} /* sentinel */
Chris@0 501 };
Chris@0 502
Chris@0 503 //Documentation for our new module
Chris@0 504 PyDoc_STRVAR(module_doc, "This is a template module just for instruction.");
Chris@0 505
Chris@14 506
Chris@14 507
Chris@0 508 /* Initialization function for the module (*must* be called initxx) */
Chris@0 509
Chris@0 510 //module initialization (includes extern C {...} as necessary)
Chris@0 511 PyMODINIT_FUNC
Chris@0 512 initvampyhost(void)
Chris@0 513 {
Chris@0 514 PyObject *m;
Chris@0 515
Chris@0 516 /* Finalize the type object including setting type of the new type
luis@7 517 * object; doing it here is required for portability to Windows
Chris@0 518 * without requiring C++. */
Chris@0 519
Chris@0 520 if (PyType_Ready(&RealTime_Type) < 0)
Chris@0 521 return;
Chris@0 522 // PyModule_AddObject(m, "Real_Time", (PyObject *)&RealTime_Type);
Chris@0 523
Chris@0 524 /* Create the module and add the functions */
Chris@0 525 m = Py_InitModule3("vampyhost", vampyhost_methods, module_doc);
Chris@16 526 if (!m) return;
Chris@0 527
Chris@14 528 import_array();
Chris@14 529
Chris@0 530 // PyModule_AddObject(m, "realtime", (PyObject *)&RealTime_Type);
Chris@0 531
Chris@0 532 }