annotate vampyhost.cpp @ 17:3893b76daf80

Type checking for process call, start on some tests
author Chris Cannam
date Mon, 24 Nov 2014 16:22:54 +0000
parents 7987e3123909
children 4b9adb4b532f
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 };
Chris@0 67
Chris@0 68 /* MODULE HELPER FUNCTIONS */
Chris@2 69 PyDoc_STRVAR(xx_foo_doc, "Some description"); //!!!
Chris@0 70
Chris@16 71 //!!! nb "The CObject API is deprecated" https://docs.python.org/2/c-api/cobject.html
Chris@0 72
Chris@16 73 PyPluginData *
Chris@16 74 getPluginData(PyObject *pyPluginHandle)
Chris@16 75 {
Chris@16 76 PyPluginData *pd = 0;
Chris@16 77 if (PyCObject_Check(pyPluginHandle)) {
Chris@16 78 pd = (PyPluginData *)PyCObject_AsVoidPtr(pyPluginHandle);
Chris@16 79 }
Chris@16 80 if (!pd || !pd->plugin) {
Chris@16 81 PyErr_SetString(PyExc_AttributeError,
Chris@16 82 "Invalid or already deleted plugin handle.");
Chris@16 83 return 0;
Chris@0 84 } else {
Chris@16 85 return pd;
Chris@0 86 }
Chris@0 87 }
Chris@0 88
Chris@0 89 static PyObject *
Chris@0 90 vampyhost_enumeratePlugins(PyObject *self, PyObject *args)
Chris@0 91 {
Chris@0 92 PluginLoader *loader = PluginLoader::getInstance();
Chris@0 93 vector<PluginLoader::PluginKey> plugins = loader->listPlugins();
Chris@15 94 PyTypeConversions conv;
Chris@15 95 return conv.PyValue_From_StringVector(plugins);
Chris@0 96 }
Chris@0 97
Chris@15 98 static PyObject *
Chris@15 99 vampyhost_getPluginPath(PyObject *self, PyObject *args)
Chris@15 100 {
Chris@15 101 vector<string> path = PluginHostAdapter::getPluginPath();
Chris@15 102 PyTypeConversions conv;
Chris@15 103 return conv.PyValue_From_StringVector(path);
Chris@15 104 }
Chris@0 105
Chris@15 106 static string toPluginKey(PyObject *pyPluginKey)
Chris@0 107 {
Chris@0 108 //convert to stl string
Chris@0 109 string pluginKey(PyString_AS_STRING(pyPluginKey));
Chris@0 110
Chris@0 111 //check pluginKey Validity
Chris@0 112 string::size_type ki = pluginKey.find(':');
Chris@0 113 if (ki == string::npos) {
Chris@0 114 PyErr_SetString(PyExc_TypeError,
Chris@15 115 "Plugin key must be of the form library:identifier");
Chris@15 116 return "";
Chris@0 117 }
Chris@0 118
Chris@15 119 return pluginKey;
Chris@15 120 }
Chris@15 121
Chris@15 122 static PyObject *
Chris@15 123 vampyhost_getLibraryFor(PyObject *self, PyObject *args)
Chris@15 124 {
Chris@15 125 PyObject *pyPluginKey;
Chris@15 126
Chris@15 127 if (!PyArg_ParseTuple(args, "S", &pyPluginKey)) {
Chris@15 128 PyErr_SetString(PyExc_TypeError,
Chris@15 129 "getLibraryPathForPlugin() takes plugin key (string) argument");
Chris@16 130 return 0; }
Chris@15 131
Chris@15 132 string pluginKey = toPluginKey(pyPluginKey);
Chris@16 133 if (pluginKey == "") return 0;
Chris@15 134
Chris@0 135 PluginLoader *loader = PluginLoader::getInstance();
Chris@0 136 string path = loader->getLibraryPathForPlugin(pluginKey);
Chris@0 137 PyObject *pyPath = PyString_FromString(path.c_str());
Chris@0 138 return pyPath;
Chris@0 139 }
Chris@0 140
Chris@0 141 static PyObject *
Chris@0 142 vampyhost_getPluginCategory(PyObject *self, PyObject *args)
Chris@0 143 {
Chris@0 144 PyObject *pyPluginKey;
Chris@0 145
Chris@0 146 if (!PyArg_ParseTuple(args, "S", &pyPluginKey)) {
Chris@0 147 PyErr_SetString(PyExc_TypeError,
Chris@15 148 "getPluginCategory() takes plugin key (string) argument");
Chris@16 149 return 0; }
Chris@0 150
Chris@15 151 string pluginKey = toPluginKey(pyPluginKey);
Chris@16 152 if (pluginKey == "") return 0;
Chris@0 153
Chris@0 154 PluginLoader *loader = PluginLoader::getInstance();
luis@7 155 PluginLoader::PluginCategoryHierarchy
Chris@0 156 category = loader->getPluginCategory(pluginKey);
Chris@0 157
Chris@15 158 PyTypeConversions conv;
Chris@15 159 return conv.PyValue_From_StringVector(category);
Chris@0 160 }
Chris@0 161
Chris@0 162 static PyObject *
Chris@0 163 vampyhost_getOutputList(PyObject *self, PyObject *args)
Chris@0 164 {
Chris@16 165 PyObject *keyOrHandle;
Chris@15 166 Plugin::OutputList outputs;
Chris@0 167
Chris@16 168 if (!PyArg_ParseTuple(args, "O", &keyOrHandle)) {
Chris@0 169 PyErr_SetString(PyExc_TypeError,
Chris@15 170 "getOutputList() takes plugin handle (object) or plugin key (string) argument");
Chris@16 171 return 0;
Chris@0 172 }
Chris@0 173
Chris@16 174 if (PyString_Check(keyOrHandle) ) {
Chris@0 175
Chris@15 176 // we have a plugin key
Chris@0 177
Chris@16 178 string pluginKey = toPluginKey(keyOrHandle);
Chris@16 179 if (pluginKey == "") return 0;
Chris@15 180
Chris@15 181 PluginLoader *loader = PluginLoader::getInstance();
Chris@15 182
Chris@15 183 Plugin *plugin = loader->loadPlugin
Chris@15 184 (pluginKey, 48000, PluginLoader::ADAPT_ALL_SAFE);
Chris@15 185 if (!plugin) {
Chris@15 186 string pyerr("Failed to load plugin: "); pyerr += pluginKey;
Chris@15 187 PyErr_SetString(PyExc_TypeError,pyerr.c_str());
Chris@16 188 return 0;
Chris@15 189 }
Chris@15 190
Chris@15 191 outputs = plugin->getOutputDescriptors();
Chris@15 192
Chris@15 193 delete plugin;
Chris@15 194
Chris@0 195 } else {
luis@7 196
Chris@15 197 // we have a loaded plugin handle
Chris@15 198
Chris@16 199 PyPluginData *pd = getPluginData(keyOrHandle);
Chris@16 200 if (!pd) return 0;
Chris@0 201
Chris@16 202 outputs = pd->plugin->getOutputDescriptors();
luis@7 203 }
luis@7 204
Chris@0 205 PyObject *pyList = PyList_New(outputs.size());
Chris@0 206
Chris@0 207 for (size_t i = 0; i < outputs.size(); ++i) {
luis@7 208 PyObject *pyOutputId =
Chris@0 209 PyString_FromString(outputs[i].identifier.c_str());
Chris@15 210 PyList_SET_ITEM(pyList, i, pyOutputId);
Chris@0 211 }
Chris@0 212
Chris@0 213 return pyList;
Chris@0 214 }
Chris@0 215
Chris@0 216 static PyObject *
Chris@0 217 vampyhost_loadPlugin(PyObject *self, PyObject *args)
Chris@0 218 {
Chris@0 219 PyObject *pyPluginKey;
Chris@0 220 float inputSampleRate;
Chris@0 221
luis@7 222 if (!PyArg_ParseTuple(args, "Sf",
Chris@0 223 &pyPluginKey,
Chris@0 224 &inputSampleRate)) {
Chris@0 225 PyErr_SetString(PyExc_TypeError,
Chris@15 226 "loadPlugin() takes plugin key (string) and sample rate (number) arguments");
Chris@16 227 return 0; }
Chris@0 228
Chris@15 229 string pluginKey = toPluginKey(pyPluginKey);
Chris@16 230 if (pluginKey == "") return 0;
Chris@0 231
Chris@0 232 PluginLoader *loader = PluginLoader::getInstance();
luis@7 233
Chris@15 234 Plugin *plugin = loader->loadPlugin(pluginKey, inputSampleRate,
Chris@15 235 PluginLoader::ADAPT_ALL_SAFE);
luis@7 236 if (!plugin) {
Chris@0 237 string pyerr("Failed to load plugin: "); pyerr += pluginKey;
luis@7 238 PyErr_SetString(PyExc_TypeError,pyerr.c_str());
Chris@16 239 return 0;
luis@7 240 }
Chris@15 241
Chris@16 242 PyPluginData *pd = new PyPluginData(pluginKey, plugin, inputSampleRate);
Chris@16 243 return PyCObject_FromVoidPtr(pd, 0);
Chris@0 244 }
Chris@0 245
Chris@0 246 static PyObject *
Chris@0 247 vampyhost_unloadPlugin(PyObject *self, PyObject *args)
Chris@0 248 {
Chris@0 249 PyObject *pyPluginHandle;
Chris@0 250
Chris@0 251 if (!PyArg_ParseTuple(args, "O", &pyPluginHandle)) {
Chris@0 252 PyErr_SetString(PyExc_TypeError,
Chris@16 253 "unloadPlugin() takes plugin handle (object) argument");
Chris@16 254 return 0;
Chris@16 255 }
Chris@0 256
Chris@16 257 PyPluginData *pd = getPluginData(pyPluginHandle);
Chris@16 258 if (!pd) return 0;
Chris@0 259
Chris@16 260 /* Prevent repeated calls from causing segfault since it will fail
Chris@16 261 * type checking the 2nd time: */
Chris@16 262 PyCObject_SetVoidPtr(pyPluginHandle, 0);
Chris@0 263
Chris@16 264 delete pd->plugin;
Chris@0 265 delete pd;
Chris@0 266 return pyPluginHandle;
Chris@0 267 }
Chris@0 268
Chris@0 269 static PyObject *
Chris@0 270 vampyhost_initialise(PyObject *self, PyObject *args)
Chris@0 271 {
Chris@0 272 PyObject *pyPluginHandle;
luis@7 273 size_t channels, blockSize, stepSize;
Chris@0 274
luis@7 275 if (!PyArg_ParseTuple (args, "Onnn", &pyPluginHandle,
luis@7 276 (size_t) &channels,
luis@7 277 (size_t) &stepSize,
luis@7 278 (size_t) &blockSize))
Chris@0 279 {
Chris@0 280 PyErr_SetString(PyExc_TypeError,
Chris@17 281 "initialise() takes plugin handle (object), channel count, step size, and block size arguments");
Chris@16 282 return 0;
Chris@0 283 }
Chris@0 284
Chris@16 285 PyPluginData *pd = getPluginData(pyPluginHandle);
Chris@16 286 if (!pd) return 0;
Chris@0 287
Chris@16 288 pd->channels = channels;
Chris@16 289 pd->stepSize = stepSize;
Chris@16 290 pd->blockSize = blockSize;
Chris@0 291
Chris@16 292 if (!pd->plugin->initialise(channels, stepSize, blockSize)) {
Chris@17 293 cerr << "Failed to initialise native plugin adapter with channels = " << channels << ", stepSize = " << stepSize << ", blockSize = " << blockSize << " and ADAPT_ALL_SAFE set" << endl;
Chris@0 294 PyErr_SetString(PyExc_TypeError,
Chris@17 295 "Plugin initialization failed");
Chris@16 296 return 0;
Chris@6 297 }
Chris@0 298
Chris@16 299 pd->isInitialised = true;
luis@7 300
Chris@0 301 return Py_True;
Chris@0 302 }
Chris@0 303
Chris@0 304 static PyObject *
Chris@0 305 vampyhost_process(PyObject *self, PyObject *args)
Chris@0 306 {
Chris@0 307 PyObject *pyPluginHandle;
Chris@0 308 PyObject *pyBuffer;
Chris@0 309 PyObject *pyRealTime;
Chris@0 310
luis@7 311 if (!PyArg_ParseTuple(args, "OOO",
Chris@0 312 &pyPluginHandle, // C object holding a pointer to a plugin and its descriptor
Chris@0 313 &pyBuffer, // Audio data
Chris@0 314 &pyRealTime)) { // TimeStamp
Chris@0 315 PyErr_SetString(PyExc_TypeError,
Chris@17 316 "process() takes plugin handle (object), buffer (2D array of channels * samples floats) and timestamp (RealTime) arguments");
Chris@16 317 return 0; }
Chris@0 318
Chris@0 319 if (!PyRealTime_Check(pyRealTime)) {
Chris@0 320 PyErr_SetString(PyExc_TypeError,"Valid timestamp required.");
Chris@16 321 return 0; }
Chris@0 322
Chris@17 323 if (!PyList_Check(pyBuffer)) {
Chris@17 324 PyErr_SetString(PyExc_TypeError, "List of NumPy Array required for process input.");
Chris@17 325 return 0;
Chris@17 326 }
Chris@17 327
Chris@16 328 PyPluginData *pd = getPluginData(pyPluginHandle);
Chris@16 329 if (!pd) return 0;
Chris@0 330
Chris@0 331 if (!pd->isInitialised) {
Chris@0 332 PyErr_SetString(PyExc_StandardError,
Chris@0 333 "Plugin has not been initialised.");
Chris@16 334 return 0;
Chris@16 335 }
Chris@0 336
Chris@12 337 int channels = pd->channels;
Chris@0 338
Chris@4 339 if (PyList_GET_SIZE(pyBuffer) != channels) {
Chris@17 340 cerr << "Wrong number of channels: got " << PyList_GET_SIZE(pyBuffer) << ", expected " << channels << endl;
Chris@4 341 PyErr_SetString(PyExc_TypeError, "Wrong number of channels");
Chris@16 342 return 0;
Chris@4 343 }
Chris@0 344
Chris@4 345 float **inbuf = new float *[channels];
Chris@0 346
Chris@12 347 PyTypeConversions typeConv;
Chris@12 348 typeConv.setNumpyInstalled(true);
Chris@17 349
Chris@17 350 cerr << "here!" << endl;
Chris@12 351
Chris@12 352 vector<vector<float> > data;
Chris@4 353 for (int c = 0; c < channels; ++c) {
Chris@4 354 PyObject *cbuf = PyList_GET_ITEM(pyBuffer, c);
Chris@17 355 data.push_back(typeConv.PyValue_To_FloatVector(cbuf));
Chris@12 356 }
Chris@12 357
Chris@12 358 for (int c = 0; c < channels; ++c) {
Chris@17 359 if (data[c].size() != pd->blockSize) {
Chris@17 360 cerr << "Wrong number of samples on channel " << c << ": expected " << pd->blockSize << " (plugin's block size), got " << data[c].size() << endl;
Chris@17 361 PyErr_SetString(PyExc_TypeError, "Wrong number of samples");
Chris@17 362 return 0;
Chris@17 363 }
Chris@12 364 inbuf[c] = &data[c][0];
Chris@4 365 }
Chris@0 366
Chris@17 367 cerr << "no, here!" << endl;
Chris@17 368
Chris@12 369 RealTime timeStamp = *PyRealTime_AsRealTime(pyRealTime);
Chris@0 370
Chris@17 371 // Call process and store the output
Chris@17 372 (void) pd->plugin->process(inbuf, timeStamp); //!!! return the output!
Chris@0 373
Chris@0 374 /* TODO: DO SOMETHONG WITH THE FEATURE SET HERE */
Chris@0 375 /// convert to appropriate python objects, reuse types and conversion utilities from Vampy ...
Chris@0 376
Chris@4 377 delete[] inbuf;
Chris@0 378
Chris@16 379 return 0; //!!! Need to return actual features!
Chris@0 380
Chris@0 381 }
Chris@0 382
Chris@17 383 #ifdef NOPE
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@17 432 // typedef vector<Feature> FeatureList;
Chris@17 433 // typedef 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@17 454 #endif
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@17 489 // {"getOutput", vampyhost_getOutput, METH_VARARGS,
Chris@17 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
Chris@0 523 /* Create the module and add the functions */
Chris@0 524 m = Py_InitModule3("vampyhost", vampyhost_methods, module_doc);
Chris@16 525 if (!m) return;
Chris@0 526
Chris@14 527 import_array();
Chris@14 528
Chris@17 529 PyModule_AddObject(m, "RealTime", (PyObject *)&RealTime_Type);
Chris@0 530 }