1 /************************************************************************/ 2 /* PyRtAudio: a python wrapper around RtAudio 3 Copyright (c) 2011 Antoine Lefebvre 4 5 Permission is hereby granted, free of charge, to any person 6 obtaining a copy of this software and associated documentation files 7 (the "Software"), to deal in the Software without restriction, 8 including without limitation the rights to use, copy, modify, merge, 9 publish, distribute, sublicense, and/or sell copies of the Software, 10 and to permit persons to whom the Software is furnished to do so, 11 subject to the following conditions: 12 13 The above copyright notice and this permission notice shall be 14 included in all copies or substantial portions of the Software. 15 16 Any person wishing to distribute modifications to the Software is 17 asked to send the modifications to the original developer so that 18 they can be incorporated into the canonical version. This is, 19 however, not a binding provision of this license. 20 21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 24 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 25 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 26 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 27 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 */ 29 /************************************************************************/ 30 31 // This software is in the development stage 32 // Do not expect compatibility with future versions. 33 // Comments, suggestions, new features, bug fixes, etc. are welcome 34 35 #include <Python.h> 36 37 #include "RtAudio.h" 38 39 extern "C" { 40 41 typedef struct 42 { 43 PyObject_HEAD 44 #if PY_MAJOR_VERSION < 3 45 void *padding; // python 2.7 seems to set dac to bad value 46 // after print_function, causing a crash, no 47 // idea why, but this fixes it. 48 #endif 49 RtAudio *dac; 50 RtAudioFormat _format; 51 int _bufferSize; 52 unsigned int inputChannels; 53 PyObject *callback_func; 54 } PyRtAudio; 55 56 static PyObject *RtAudioErrorException; 57 callback(void * outputBuffer,void * inputBuffer,unsigned int nBufferFrames,double streamTime,RtAudioStreamStatus status,void * data)58 static int callback(void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames, 59 double streamTime, RtAudioStreamStatus status, void *data ) 60 { 61 PyRtAudio* self = (PyRtAudio*) data; 62 63 if (status == RTAUDIO_OUTPUT_UNDERFLOW) 64 printf("underflow.\n"); 65 66 if (self == NULL) return -1; 67 68 float* in = (float *) inputBuffer; 69 float* out = (float *) outputBuffer; 70 71 PyObject *py_callback_func = self->callback_func; 72 73 int retval = 0; 74 75 if (py_callback_func) { 76 PyGILState_STATE gstate = PyGILState_Ensure(); 77 78 #if PY_MAJOR_VERSION >= 3 79 PyObject* iBuffer = PyMemoryView_FromMemory((char*)in, sizeof(float) * self->inputChannels * nBufferFrames, PyBUF_READ); 80 PyObject* oBuffer = PyMemoryView_FromMemory((char*)out, sizeof(float) * nBufferFrames, PyBUF_WRITE); 81 #else 82 PyObject* iBuffer = PyBuffer_FromMemory(in, sizeof(float) * self->inputChannels * nBufferFrames); 83 PyObject* oBuffer = PyBuffer_FromReadWriteMemory(out, sizeof(float) * nBufferFrames); 84 #endif 85 PyObject *arglist = Py_BuildValue("(O,O)", oBuffer, iBuffer); 86 87 if (arglist == NULL) { 88 printf("error.\n"); 89 PyErr_Print(); 90 PyGILState_Release(gstate); 91 return 2; 92 } 93 94 // Calling the callback 95 PyObject *result = PyEval_CallObject(py_callback_func, arglist); 96 97 if (PyErr_Occurred() != NULL) { 98 PyErr_Print(); 99 } 100 #if PY_MAJOR_VERSION >= 3 101 else if (result == NULL) 102 retval = 0; 103 else if (PyLong_Check(result)) { 104 retval = PyLong_AsLong(result); 105 } 106 #else 107 else if (PyInt_Check(result)) { 108 retval = PyInt_AsLong(result); 109 } 110 #endif 111 112 Py_DECREF(arglist); 113 Py_DECREF(oBuffer); 114 Py_DECREF(iBuffer); 115 Py_XDECREF(result); 116 117 PyGILState_Release(gstate); 118 } 119 120 return retval; 121 } 122 123 124 RtAudio_dealloc(PyRtAudio * self)125 static void RtAudio_dealloc(PyRtAudio *self) 126 { 127 printf("RtAudio_dealloc.\n"); 128 if (self == NULL) return; 129 130 if (self->dac) { 131 self->dac->closeStream(); 132 Py_CLEAR(self->callback_func); 133 delete self->dac; 134 } 135 136 Py_TYPE(self)->tp_free((PyObject *) self); 137 } 138 139 RtAudio_new(PyTypeObject * type,PyObject * args,PyObject * kwds)140 static PyObject* RtAudio_new(PyTypeObject *type, PyObject *args, PyObject *kwds) 141 { 142 printf("RtAudio_new.\n"); 143 PyRtAudio *self; 144 char *api = NULL; 145 146 if(!PyArg_ParseTuple(args, "|s", &api)) 147 return NULL; 148 149 self = (PyRtAudio *) type->tp_alloc(type, 0); 150 151 if(self == NULL) return NULL; 152 153 self->dac = NULL; 154 self->callback_func = NULL; 155 156 try { 157 if (api == NULL) 158 self->dac = new RtAudio; 159 else if(!strcmp(api, "jack")) 160 self->dac = new RtAudio(RtAudio::UNIX_JACK); 161 else if(!strcmp(api, "alsa")) 162 self->dac = new RtAudio(RtAudio::LINUX_ALSA); 163 else if(!strcmp(api, "oss")) 164 self->dac = new RtAudio(RtAudio::LINUX_ALSA); 165 else if(!strcmp(api, "core")) 166 self->dac = new RtAudio(RtAudio::MACOSX_CORE); 167 else if(!strcmp(api, "asio")) 168 self->dac = new RtAudio(RtAudio::WINDOWS_ASIO); 169 else if(!strcmp(api, "directsound")) 170 self->dac = new RtAudio(RtAudio::WINDOWS_DS); 171 } 172 catch (RtAudioError &error) { 173 PyErr_SetString(RtAudioErrorException, error.getMessage().c_str()); 174 Py_INCREF(RtAudioErrorException); 175 return NULL; 176 } 177 178 self->dac->showWarnings(false); 179 180 //Py_XINCREF(self); 181 return (PyObject *) self; 182 } 183 RtAudio_init(PyRtAudio * self,PyObject * args,PyObject * kwds)184 static int RtAudio_init(PyRtAudio *self, PyObject *args, PyObject *kwds) 185 { 186 printf("RtAudio_init.\n"); 187 //if (self == NULL) return 0; 188 return 0; 189 } 190 191 // This functions does not yet support all the features of the RtAudio::openStream method. 192 // Please send your patches if you improves this. RtAudio_openStream(PyRtAudio * self,PyObject * args)193 static PyObject* RtAudio_openStream(PyRtAudio *self, PyObject *args) 194 { 195 if (self == NULL) return NULL; 196 197 if (self->dac == NULL) { 198 printf("the dac is null.\n"); 199 Py_RETURN_NONE; 200 } 201 202 PyObject *oParamsObj; 203 PyObject *iParamsObj; 204 int fs; 205 unsigned int bf; 206 PyObject *pycallback; 207 208 if (!PyArg_ParseTuple(args, "OOiiO", &oParamsObj, &iParamsObj, &fs, &bf, &pycallback)) 209 return NULL; 210 211 RtAudio::StreamParameters oParams; 212 oParams.deviceId = 1; 213 oParams.nChannels = 1; 214 oParams.firstChannel = 0; 215 216 if (PyDict_Check(oParamsObj)) { 217 #if PY_MAJOR_VERSION >= 3 218 if (PyDict_Contains(oParamsObj, PyUnicode_FromString("deviceId"))) { 219 PyObject *value = PyDict_GetItem(oParamsObj, PyUnicode_FromString("deviceId")); 220 oParams.deviceId = PyLong_AsLong(value); 221 } 222 if (PyDict_Contains(oParamsObj, PyUnicode_FromString("nChannels"))) { 223 PyObject *value = PyDict_GetItem(oParamsObj, PyUnicode_FromString("nChannels")); 224 oParams.nChannels = PyLong_AsLong(value); 225 } 226 if (PyDict_Contains(oParamsObj, PyUnicode_FromString("firstChannel"))) { 227 PyObject *value = PyDict_GetItem(oParamsObj, PyUnicode_FromString("firstChannel")); 228 oParams.firstChannel = PyLong_AsLong(value); 229 } 230 #else 231 if (PyDict_Contains(oParamsObj, PyString_FromString("deviceId"))) { 232 PyObject *value = PyDict_GetItem(oParamsObj, PyString_FromString("deviceId")); 233 oParams.deviceId = PyInt_AsLong(value); 234 } 235 if (PyDict_Contains(oParamsObj, PyString_FromString("nChannels"))) { 236 PyObject *value = PyDict_GetItem(oParamsObj, PyString_FromString("nChannels")); 237 oParams.nChannels = PyInt_AsLong(value); 238 } 239 if (PyDict_Contains(oParamsObj, PyString_FromString("firstChannel"))) { 240 PyObject *value = PyDict_GetItem(oParamsObj, PyString_FromString("firstChannel")); 241 oParams.firstChannel = PyInt_AsLong(value); 242 } 243 #endif 244 } 245 else { 246 printf("First argument must be a dictionary. Default values will be used.\n"); 247 } 248 249 RtAudio::StreamParameters iParams; 250 iParams.deviceId = 1; 251 iParams.nChannels = 2; 252 iParams.firstChannel = 0; 253 254 if (PyDict_Check(iParamsObj)) { 255 #if PY_MAJOR_VERSION >= 3 256 if (PyDict_Contains(iParamsObj, PyUnicode_FromString("deviceId"))) { 257 PyObject *value = PyDict_GetItem(iParamsObj, PyUnicode_FromString("deviceId")); 258 iParams.deviceId = PyLong_AsLong(value); 259 } 260 if (PyDict_Contains(iParamsObj, PyUnicode_FromString("nChannels"))) { 261 PyObject *value = PyDict_GetItem(iParamsObj, PyUnicode_FromString("nChannels")); 262 iParams.nChannels = PyLong_AsLong(value); 263 } 264 if (PyDict_Contains(iParamsObj, PyUnicode_FromString("firstChannel"))) { 265 PyObject *value = PyDict_GetItem(iParamsObj, PyUnicode_FromString("firstChannel")); 266 iParams.firstChannel = PyLong_AsLong(value); 267 } 268 #else 269 if (PyDict_Contains(iParamsObj, PyString_FromString("deviceId"))) { 270 PyObject *value = PyDict_GetItem(iParamsObj, PyString_FromString("deviceId")); 271 iParams.deviceId = PyInt_AsLong(value); 272 } 273 if (PyDict_Contains(iParamsObj, PyString_FromString("nChannels"))) { 274 PyObject *value = PyDict_GetItem(iParamsObj, PyString_FromString("nChannels")); 275 iParams.nChannels = PyInt_AsLong(value); 276 } 277 if (PyDict_Contains(iParamsObj, PyString_FromString("firstChannel"))) { 278 PyObject *value = PyDict_GetItem(iParamsObj, PyString_FromString("firstChannel")); 279 iParams.firstChannel = PyInt_AsLong(value); 280 } 281 #endif 282 } 283 else { 284 printf("Second argument must be a dictionary. Default values will be used.\n"); 285 } 286 287 288 if (!PyCallable_Check(pycallback)) { 289 PyErr_SetString(PyExc_TypeError, "Need a callable object!"); 290 Py_XINCREF(PyExc_TypeError); 291 return NULL; 292 } 293 294 // sanity check the callback ? 295 296 297 Py_INCREF(pycallback); /* Add a reference to new callback */ 298 self->callback_func = pycallback; /*Remember new callback */ 299 300 // add support for other format 301 self->_format = RTAUDIO_FLOAT32; 302 303 // add support for other options 304 RtAudio::StreamOptions options; 305 options.flags = RTAUDIO_NONINTERLEAVED; 306 307 try { 308 if (self->dac->isStreamOpen()) 309 self->dac->closeStream(); 310 self->dac->openStream(&oParams, &iParams, self->_format, fs, &bf, &callback, self, &options); 311 } 312 catch ( RtAudioError& error ) { 313 PyErr_SetString(RtAudioErrorException, error.getMessage().c_str()); 314 Py_INCREF(RtAudioErrorException); 315 return NULL; 316 } 317 318 self->inputChannels = iParams.nChannels; 319 320 Py_RETURN_NONE; 321 } 322 RtAudio_closeStream(PyRtAudio * self,PyObject * args)323 static PyObject* RtAudio_closeStream(PyRtAudio *self, PyObject *args) 324 { 325 printf("RtAudio_closeStream.\n"); 326 if (self == NULL || self->dac == NULL) return NULL; 327 328 try { 329 self->dac->closeStream(); 330 Py_CLEAR(self->callback_func); 331 } 332 catch(RtAudioError &error) { 333 PyErr_SetString(RtAudioErrorException, error.getMessage().c_str()); 334 Py_INCREF(RtAudioErrorException); 335 return NULL; 336 } 337 338 Py_RETURN_NONE; 339 } 340 RtAudio_startStream(PyRtAudio * self,PyObject * args)341 static PyObject* RtAudio_startStream(PyRtAudio *self, PyObject *args) 342 { 343 if (self == NULL || self->dac == NULL) return NULL; 344 345 try { 346 self->dac->startStream(); 347 } 348 catch(RtAudioError &error) { 349 PyErr_SetString(RtAudioErrorException, error.getMessage().c_str()); 350 Py_INCREF(RtAudioErrorException); 351 return NULL; 352 } 353 354 Py_RETURN_NONE; 355 } 356 357 RtAudio_stopStream(PyRtAudio * self,PyObject * args)358 static PyObject* RtAudio_stopStream(PyRtAudio *self, PyObject *args) 359 { 360 printf("RtAudio_stopStream.\n"); 361 if (self == NULL || self->dac == NULL) return NULL; 362 363 try { 364 self->dac->stopStream(); 365 } 366 catch(RtAudioError &error) { 367 PyErr_SetString(RtAudioErrorException, error.getMessage().c_str()); 368 Py_INCREF(RtAudioErrorException); 369 return NULL; 370 } 371 372 Py_RETURN_NONE; 373 } 374 RtAudio_abortStream(PyRtAudio * self,PyObject * args)375 static PyObject* RtAudio_abortStream(PyRtAudio *self, PyObject *args) 376 { 377 printf("RtAudio_abortStream.\n"); 378 if (self == NULL || self->dac == NULL) return NULL; 379 380 try { 381 self->dac->abortStream(); 382 } 383 catch(RtAudioError &error) { 384 PyErr_SetString(RtAudioErrorException, error.getMessage().c_str()); 385 Py_INCREF(RtAudioErrorException); 386 return NULL; 387 } 388 Py_RETURN_NONE; 389 } 390 RtAudio_isStreamRunning(PyRtAudio * self,PyObject * args)391 static PyObject* RtAudio_isStreamRunning(PyRtAudio *self, PyObject *args) 392 { 393 if (self == NULL || self->dac == NULL) return NULL; 394 395 if (self->dac == NULL) { 396 Py_RETURN_FALSE; 397 } 398 if (self->dac->isStreamRunning()) 399 Py_RETURN_TRUE; 400 else 401 Py_RETURN_FALSE; 402 } 403 RtAudio_isStreamOpen(PyRtAudio * self,PyObject * args)404 static PyObject* RtAudio_isStreamOpen(PyRtAudio *self, PyObject *args) 405 { 406 if (self == NULL || self->dac == NULL) return NULL; 407 408 if (self->dac == NULL) { 409 Py_RETURN_FALSE; 410 } 411 if (self->dac->isStreamOpen()) 412 Py_RETURN_TRUE; 413 else 414 Py_RETURN_FALSE; 415 416 } 417 RtAudio_getDeviceCount(PyRtAudio * self,PyObject * args)418 static PyObject* RtAudio_getDeviceCount(PyRtAudio *self, PyObject *args) 419 { 420 if (self == NULL || self->dac == NULL) return NULL; 421 422 #if PY_MAJOR_VERSION >= 3 423 return PyLong_FromLong(self->dac->getDeviceCount()); 424 #else 425 return PyInt_FromLong(self->dac->getDeviceCount()); 426 #endif 427 } 428 RtAudio_getDeviceInfo(PyRtAudio * self,PyObject * args)429 static PyObject* RtAudio_getDeviceInfo(PyRtAudio *self, PyObject *args) 430 { 431 if (self == NULL || self->dac == NULL) return NULL; 432 433 int device; 434 if (!PyArg_ParseTuple(args, "i", &device)) 435 return NULL; 436 437 try { 438 RtAudio::DeviceInfo info = self->dac->getDeviceInfo(device); 439 440 PyObject* info_dict = PyDict_New(); 441 442 if (info.probed) { 443 Py_INCREF(Py_True); 444 PyDict_SetItemString(info_dict, "probed", Py_True); 445 } 446 else { 447 Py_INCREF(Py_False); 448 PyDict_SetItemString(info_dict, "probed", Py_False); 449 } 450 PyObject* obj; 451 452 #if PY_MAJOR_VERSION >= 3 453 obj = PyUnicode_FromString(info.name.c_str()); 454 PyDict_SetItemString(info_dict, "name", obj); 455 456 obj = PyLong_FromLong(info.outputChannels); 457 PyDict_SetItemString(info_dict, "outputChannels", obj); 458 459 obj = PyLong_FromLong(info.inputChannels); 460 PyDict_SetItemString(info_dict, "inputChannels", obj); 461 462 obj = PyLong_FromLong(info.duplexChannels); 463 PyDict_SetItemString(info_dict, "duplexChannels", obj); 464 #else 465 obj = PyString_FromString(info.name.c_str()); 466 PyDict_SetItemString(info_dict, "name", obj); 467 468 obj = PyInt_FromLong(info.outputChannels); 469 PyDict_SetItemString(info_dict, "outputChannels", obj); 470 471 obj = PyInt_FromLong(info.inputChannels); 472 PyDict_SetItemString(info_dict, "inputChannels", obj); 473 474 obj = PyInt_FromLong(info.duplexChannels); 475 PyDict_SetItemString(info_dict, "duplexChannels", obj); 476 #endif 477 478 if (info.isDefaultOutput) { 479 Py_INCREF(Py_True); 480 PyDict_SetItemString(info_dict, "isDefaultOutput", Py_True); 481 } 482 else { 483 Py_INCREF(Py_False); 484 PyDict_SetItemString(info_dict, "isDefaultOutput", Py_False); 485 } 486 487 if (info.isDefaultInput) { 488 Py_INCREF(Py_True); 489 PyDict_SetItemString(info_dict, "isDefaultInput", Py_True); 490 } 491 else { 492 Py_INCREF(Py_False); 493 PyDict_SetItemString(info_dict, "isDefaultInput", Py_False); 494 } 495 496 return info_dict; 497 498 } 499 catch(RtAudioError &error) { 500 PyErr_SetString(RtAudioErrorException, error.getMessage().c_str()); 501 Py_INCREF(RtAudioErrorException); 502 return NULL; 503 } 504 } 505 RtAudio_getDefaultOutputDevice(PyRtAudio * self,PyObject * args)506 static PyObject* RtAudio_getDefaultOutputDevice(PyRtAudio *self, PyObject *args) 507 { 508 if (self == NULL || self->dac == NULL) return NULL; 509 #if PY_MAJOR_VERSION >= 3 510 return PyLong_FromLong(self->dac->getDefaultOutputDevice()); 511 #else 512 return PyInt_FromLong(self->dac->getDefaultOutputDevice()); 513 #endif 514 } 515 RtAudio_getDefaultInputDevice(PyRtAudio * self,PyObject * args)516 static PyObject* RtAudio_getDefaultInputDevice(PyRtAudio *self, PyObject *args) 517 { 518 if (self == NULL || self->dac == NULL) return NULL; 519 #if PY_MAJOR_VERSION >= 3 520 return PyLong_FromLong(self->dac->getDefaultInputDevice()); 521 #else 522 return PyInt_FromLong(self->dac->getDefaultInputDevice()); 523 #endif 524 } 525 RtAudio_getStreamTime(PyRtAudio * self,PyObject * args)526 static PyObject* RtAudio_getStreamTime(PyRtAudio *self, PyObject *args) 527 { 528 if (self == NULL || self->dac == NULL) return NULL; 529 return PyFloat_FromDouble( self->dac->getStreamTime() ); 530 } 531 RtAudio_getStreamLatency(PyRtAudio * self,PyObject * args)532 static PyObject* RtAudio_getStreamLatency(PyRtAudio *self, PyObject *args) 533 { 534 if (self == NULL || self->dac == NULL) return NULL; 535 #if PY_MAJOR_VERSION >= 3 536 return PyLong_FromLong( self->dac->getStreamLatency() ); 537 #else 538 return PyInt_FromLong( self->dac->getStreamLatency() ); 539 #endif 540 } 541 RtAudio_getStreamSampleRate(PyRtAudio * self,PyObject * args)542 static PyObject* RtAudio_getStreamSampleRate(PyRtAudio *self, PyObject *args) 543 { 544 if (self == NULL || self->dac == NULL) return NULL; 545 #if PY_MAJOR_VERSION >= 3 546 return PyLong_FromLong( self->dac->getStreamSampleRate() ); 547 #else 548 return PyInt_FromLong( self->dac->getStreamSampleRate() ); 549 #endif 550 } 551 RtAudio_showWarnings(PyRtAudio * self,PyObject * args)552 static PyObject* RtAudio_showWarnings(PyRtAudio *self, PyObject *args) 553 { 554 if (self == NULL || self->dac == NULL) return NULL; 555 556 PyObject *obj; 557 if (!PyArg_ParseTuple(args, "O", &obj)) 558 return NULL; 559 560 if (!PyBool_Check(obj)) 561 return NULL; 562 563 if (obj == Py_True) 564 self->dac->showWarnings(true); 565 else if (obj == Py_False) 566 self->dac->showWarnings(false); 567 else { 568 printf("not true nor false\n"); 569 } 570 Py_RETURN_NONE; 571 } 572 573 574 static PyMethodDef RtAudio_methods[] = 575 { 576 // TO BE DONE: getCurrentApi(void) 577 {"getDeviceCount", (PyCFunction) RtAudio_getDeviceCount, METH_NOARGS, 578 "A public function that queries for the number of audio devices available."}, 579 {"getDeviceInfo", (PyCFunction) RtAudio_getDeviceInfo, METH_VARARGS, 580 "Return a dictionary with information for a specified device number."}, 581 {"getDefaultOutputDevice", (PyCFunction) RtAudio_getDefaultOutputDevice, METH_NOARGS, 582 "A function that returns the index of the default output device."}, 583 {"getDefaultInputDevice", (PyCFunction) RtAudio_getDefaultInputDevice, METH_NOARGS, 584 "A function that returns the index of the default input device."}, 585 {"openStream", (PyCFunction) RtAudio_openStream, METH_VARARGS, 586 "A public method for opening a stream with the specified parameters."}, 587 {"closeStream", (PyCFunction) RtAudio_closeStream, METH_NOARGS, 588 "A function that closes a stream and frees any associated stream memory. "}, 589 {"startStream", (PyCFunction) RtAudio_startStream, METH_NOARGS, 590 "A function that starts a stream. "}, 591 {"stopStream", (PyCFunction) RtAudio_stopStream, METH_NOARGS, 592 "Stop a stream, allowing any samples remaining in the output queue to be played. "}, 593 {"abortStream", (PyCFunction) RtAudio_abortStream, METH_NOARGS, 594 "Stop a stream, discarding any samples remaining in the input/output queue."}, 595 {"isStreamOpen", (PyCFunction) RtAudio_isStreamOpen, METH_NOARGS, 596 "Returns true if a stream is open and false if not."}, 597 {"isStreamRunning", (PyCFunction) RtAudio_isStreamRunning, METH_NOARGS, 598 "Returns true if the stream is running and false if it is stopped or not open."}, 599 {"getStreamTime", (PyCFunction) RtAudio_getStreamTime, METH_NOARGS, 600 "Returns the number of elapsed seconds since the stream was started."}, 601 {"getStreamLatency", (PyCFunction) RtAudio_getStreamLatency, METH_NOARGS, 602 "Returns the internal stream latency in sample frames."}, 603 {"getStreamSampleRate", (PyCFunction) RtAudio_getStreamSampleRate, METH_NOARGS, 604 "Returns actual sample rate in use by the stream."}, 605 {"showWarnings", (PyCFunction) RtAudio_showWarnings, METH_VARARGS, 606 "Specify whether warning messages should be printed to stderr."}, 607 // TO BE DONE: getCompiledApi (std::vector< RtAudio::Api > &apis) throw () 608 {NULL} 609 }; 610 611 static PyTypeObject RtAudio_type = { 612 PyVarObject_HEAD_INIT(NULL, 0) 613 "rtaudio.RtAudio", /*tp_name*/ 614 sizeof(RtAudio), /*tp_basicsize*/ 615 0, /*tp_itemsize*/ 616 (destructor) RtAudio_dealloc, /*tp_dealloc*/ 617 0, /*tp_print*/ 618 0, /*tp_getattr*/ 619 0, /*tp_setattr*/ 620 0, /*tp_compare*/ 621 0, /*tp_repr*/ 622 0, /*tp_as_number*/ 623 0, /*tp_as_sequence*/ 624 0, /*tp_as_mapping*/ 625 0, /*tp_hash */ 626 0, /*tp_call*/ 627 0, /*tp_str*/ 628 0, /*tp_getattro*/ 629 0, /*tp_setattro*/ 630 0, /*tp_as_buffer*/ 631 Py_TPFLAGS_DEFAULT, /*tp_flags*/ 632 "Audio input device", /* tp_doc */ 633 0, /* tp_traverse */ 634 0, /* tp_clear */ 635 0, /* tp_richcompare */ 636 0, /* tp_weaklistoffset */ 637 0, /* tp_iter */ 638 0, /* tp_iternext */ 639 RtAudio_methods, /* tp_methods */ 640 0, /* tp_members */ 641 0, /* tp_getset */ 642 0, /* tp_base */ 643 0, /* tp_dict */ 644 0, /* tp_descr_get */ 645 0, /* tp_descr_set */ 646 0, /* tp_dictoffset */ 647 (initproc)RtAudio_init, /* tp_init */ 648 0, /* tp_alloc */ 649 RtAudio_new, /* tp_new */ 650 0, /* Low-level free-memory routine */ 651 0, /* For PyObject_IS_GC */ 652 0, // PyObject *tp_bases; 653 0, // PyObject *tp_mro; /* method resolution order */ 654 0, //PyObject *tp_cache; 655 0, //PyObject *tp_subclasses; 656 0, //PyObject *tp_weaklist; 657 0, //destructor tp_del; 658 //0, /* Type attribute cache version tag. Added in version 2.6 */ 659 }; 660 661 #if PY_MAJOR_VERSION >= 3 662 static PyModuleDef RtAudio_module = { 663 PyModuleDef_HEAD_INIT, 664 "RtAudio", 665 "RtAudio wrapper.", 666 }; 667 #endif 668 669 #ifndef PyMODINIT_FUNC /* declarations for DLL import/export */ 670 #define PyMODINIT_FUNC void 671 #endif 672 PyMODINIT_FUNC 673 #if PY_MAJOR_VERSION >= 3 PyInit_rtaudio(void)674 PyInit_rtaudio(void) 675 #else 676 initrtaudio(void) 677 #endif 678 { 679 if (!PyEval_ThreadsInitialized()) 680 PyEval_InitThreads(); 681 682 if (PyType_Ready(&RtAudio_type) < 0) 683 #if PY_MAJOR_VERSION >= 3 684 return NULL; 685 #else 686 return; 687 #endif 688 689 #if PY_MAJOR_VERSION >= 3 690 PyObject* module = PyModule_Create(&RtAudio_module); 691 if (module == NULL) 692 return NULL; 693 #else 694 PyObject* module = Py_InitModule3("rtaudio", NULL, "RtAudio wrapper."); 695 if (module == NULL) 696 return; 697 #endif 698 699 Py_INCREF(&RtAudio_type); 700 PyModule_AddObject(module, "RtAudio", (PyObject *)&RtAudio_type); 701 702 RtAudioErrorException = PyErr_NewException("rtaudio.RtError", NULL, NULL); 703 Py_INCREF(RtAudioErrorException); 704 PyModule_AddObject(module, "RtError", RtAudioErrorException); 705 #if PY_MAJOR_VERSION >= 3 706 return module; 707 #else 708 return; 709 #endif 710 } 711 } 712