1 /************************************************************************/
2 /* PyRtAudio: a python wrapper around RtAudio
3 Copyright (c) 2011 Antoine Lefebvre
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:
13 The above copyright notice and this permission notice shall be
14 included in all copies or substantial portions of the Software.
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.
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.
29 /************************************************************************/
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
45 RtAudioFormat _format;
47 unsigned int inputChannels;
48 PyObject *callback_func;
51 static PyObject *RtAudioError;
53 static int callback(void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames,
54 double streamTime, RtAudioStreamStatus status, void *data )
56 PyRtAudio* self = (PyRtAudio*) data;
58 if (status == RTAUDIO_OUTPUT_UNDERFLOW)
59 printf("underflow.\n");
61 if (self == NULL) return -1;
63 float* in = (float *) inputBuffer;
64 float* out = (float *) outputBuffer;
66 PyObject *py_callback_func = self->callback_func;
70 if (py_callback_func) {
71 PyGILState_STATE gstate = PyGILState_Ensure();
73 PyObject* iBuffer = PyBuffer_FromMemory(in, sizeof(float) * self->inputChannels * nBufferFrames);
74 PyObject* oBuffer = PyBuffer_FromReadWriteMemory(out, sizeof(float) * nBufferFrames);
75 PyObject *arglist = Py_BuildValue("(O,O)", oBuffer, iBuffer);
77 if (arglist == NULL) {
80 PyGILState_Release(gstate);
84 // Calling the callback
85 PyObject *result = PyEval_CallObject(py_callback_func, arglist);
87 if (PyErr_Occurred() != NULL) {
90 else if PyInt_Check(result) {
91 retval = PyInt_AsLong(result);
99 PyGILState_Release(gstate);
107 static void RtAudio_dealloc(PyRtAudio *self)
109 printf("RtAudio_dealloc.\n");
110 if (self == NULL) return;
113 self->dac->closeStream();
114 Py_CLEAR(self->callback_func);
118 self->ob_type->tp_free((PyObject *) self);
122 static PyObject* RtAudio_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
124 printf("RtAudio_new.\n");
128 if(!PyArg_ParseTuple(args, "|s", &api))
131 self = (PyRtAudio *) type->tp_alloc(type, 0);
133 if(self == NULL) return NULL;
136 self->callback_func = NULL;
140 self->dac = new RtAudio;
141 else if(!strcmp(api, "jack"))
142 self->dac = new RtAudio(RtAudio::UNIX_JACK);
143 else if(!strcmp(api, "alsa"))
144 self->dac = new RtAudio(RtAudio::LINUX_ALSA);
145 else if(!strcmp(api, "oss"))
146 self->dac = new RtAudio(RtAudio::LINUX_ALSA);
147 else if(!strcmp(api, "core"))
148 self->dac = new RtAudio(RtAudio::MACOSX_CORE);
149 else if(!strcmp(api, "asio"))
150 self->dac = new RtAudio(RtAudio::WINDOWS_ASIO);
151 else if(!strcmp(api, "directsound"))
152 self->dac = new RtAudio(RtAudio::WINDOWS_DS);
154 catch (RtError &error) {
155 PyErr_SetString(RtAudioError, error.getMessage().c_str());
156 Py_INCREF(RtAudioError);
160 self->dac->showWarnings(false);
163 return (PyObject *) self;
166 static int RtAudio_init(PyRtAudio *self, PyObject *args, PyObject *kwds)
168 printf("RtAudio_init.\n");
169 //if (self == NULL) return 0;
173 // This functions does not yet support all the features of the RtAudio::openStream method.
174 // Please send your patches if you improves this.
175 static PyObject* RtAudio_openStream(PyRtAudio *self, PyObject *args)
177 if (self == NULL) return NULL;
179 if (self->dac == NULL) {
180 printf("the dac is null.\n");
184 PyObject *oParamsObj;
185 PyObject *iParamsObj;
188 PyObject *pycallback;
190 if (!PyArg_ParseTuple(args, "OOiiO", &oParamsObj, &iParamsObj, &fs, &bf, &pycallback))
193 RtAudio::StreamParameters oParams;
194 oParams.deviceId = 1;
195 oParams.nChannels = 1;
196 oParams.firstChannel = 0;
198 if (PyDict_Check(oParamsObj)) {
199 if (PyDict_Contains(oParamsObj, PyString_FromString("deviceId"))) {
200 PyObject *value = PyDict_GetItem(oParamsObj, PyString_FromString("deviceId"));
201 oParams.deviceId = PyInt_AsLong(value);
203 if (PyDict_Contains(oParamsObj, PyString_FromString("nChannels"))) {
204 PyObject *value = PyDict_GetItem(oParamsObj, PyString_FromString("nChannels"));
205 oParams.nChannels = PyInt_AsLong(value);
207 if (PyDict_Contains(oParamsObj, PyString_FromString("firstChannel"))) {
208 PyObject *value = PyDict_GetItem(oParamsObj, PyString_FromString("firstChannel"));
209 oParams.firstChannel = PyInt_AsLong(value);
213 printf("First argument must be a dictionary. Default values will be used.\n");
216 RtAudio::StreamParameters iParams;
217 iParams.deviceId = 1;
218 iParams.nChannels = 2;
219 iParams.firstChannel = 0;
221 if (PyDict_Check(iParamsObj)) {
222 if (PyDict_Contains(iParamsObj, PyString_FromString("deviceId"))) {
223 PyObject *value = PyDict_GetItem(iParamsObj, PyString_FromString("deviceId"));
224 iParams.deviceId = PyInt_AsLong(value);
226 if (PyDict_Contains(iParamsObj, PyString_FromString("nChannels"))) {
227 PyObject *value = PyDict_GetItem(iParamsObj, PyString_FromString("nChannels"));
228 iParams.nChannels = PyInt_AsLong(value);
230 if (PyDict_Contains(iParamsObj, PyString_FromString("firstChannel"))) {
231 PyObject *value = PyDict_GetItem(iParamsObj, PyString_FromString("firstChannel"));
232 iParams.firstChannel = PyInt_AsLong(value);
236 printf("Second argument must be a dictionary. Default values will be used.\n");
240 if (!PyCallable_Check(pycallback)) {
241 PyErr_SetString(PyExc_TypeError, "Need a callable object!");
242 Py_XINCREF(PyExc_TypeError);
246 // sanity check the callback ?
249 Py_INCREF(pycallback); /* Add a reference to new callback */
250 self->callback_func = pycallback; /*Remember new callback */
252 // add support for other format
253 self->_format = RTAUDIO_FLOAT32;
255 // add support for other options
256 RtAudio::StreamOptions options;
257 options.flags = RTAUDIO_NONINTERLEAVED;
260 if (self->dac->isStreamOpen())
261 self->dac->closeStream();
262 self->dac->openStream(&oParams, &iParams, self->_format, fs, &bf, &callback, self, &options);
264 catch ( RtError& error ) {
265 PyErr_SetString(RtAudioError, error.getMessage().c_str());
266 Py_INCREF(RtAudioError);
270 self->inputChannels = iParams.nChannels;
275 static PyObject* RtAudio_closeStream(PyRtAudio *self, PyObject *args)
277 printf("RtAudio_closeStream.\n");
278 if (self == NULL || self->dac == NULL) return NULL;
281 self->dac->closeStream();
282 Py_CLEAR(self->callback_func);
284 catch(RtError &error) {
285 PyErr_SetString(RtAudioError, error.getMessage().c_str());
286 Py_INCREF(RtAudioError);
293 static PyObject* RtAudio_startStream(PyRtAudio *self, PyObject *args)
295 if (self == NULL || self->dac == NULL) return NULL;
298 self->dac->startStream();
300 catch(RtError &error) {
301 PyErr_SetString(RtAudioError, error.getMessage().c_str());
302 Py_INCREF(RtAudioError);
310 static PyObject* RtAudio_stopStream(PyRtAudio *self, PyObject *args)
312 printf("RtAudio_stopStream.\n");
313 if (self == NULL || self->dac == NULL) return NULL;
316 self->dac->stopStream();
318 catch(RtError &error) {
319 PyErr_SetString(RtAudioError, error.getMessage().c_str());
320 Py_INCREF(RtAudioError);
327 static PyObject* RtAudio_abortStream(PyRtAudio *self, PyObject *args)
329 printf("RtAudio_abortStream.\n");
330 if (self == NULL || self->dac == NULL) return NULL;
333 self->dac->abortStream();
335 catch(RtError &error) {
336 PyErr_SetString(RtAudioError, error.getMessage().c_str());
337 Py_INCREF(RtAudioError);
343 static PyObject* RtAudio_isStreamRunning(PyRtAudio *self, PyObject *args)
345 if (self == NULL || self->dac == NULL) return NULL;
347 if (self->dac == NULL) {
350 if (self->dac->isStreamRunning())
356 static PyObject* RtAudio_isStreamOpen(PyRtAudio *self, PyObject *args)
358 if (self == NULL || self->dac == NULL) return NULL;
360 if (self->dac == NULL) {
363 if (self->dac->isStreamOpen())
370 static PyObject* RtAudio_getDeviceCount(PyRtAudio *self, PyObject *args)
372 if (self == NULL || self->dac == NULL) return NULL;
374 return PyInt_FromLong(self->dac->getDeviceCount());
377 static PyObject* RtAudio_getDeviceInfo(PyRtAudio *self, PyObject *args)
379 if (self == NULL || self->dac == NULL) return NULL;
382 if (!PyArg_ParseTuple(args, "i", &device))
386 RtAudio::DeviceInfo info = self->dac->getDeviceInfo(device);
388 PyObject* info_dict = PyDict_New();
392 PyDict_SetItemString(info_dict, "probed", Py_True);
396 PyDict_SetItemString(info_dict, "probed", Py_False);
400 obj = PyString_FromString(info.name.c_str());
401 PyDict_SetItemString(info_dict, "name", obj);
403 obj = PyInt_FromLong(info.outputChannels);
404 PyDict_SetItemString(info_dict, "outputChannels", obj);
406 obj = PyInt_FromLong(info.inputChannels);
407 PyDict_SetItemString(info_dict, "inputChannels", obj);
409 obj = PyInt_FromLong(info.duplexChannels);
410 PyDict_SetItemString(info_dict, "duplexChannels", obj);
412 if (info.isDefaultOutput) {
414 PyDict_SetItemString(info_dict, "isDefaultOutput", Py_True);
418 PyDict_SetItemString(info_dict, "isDefaultOutput", Py_False);
421 if (info.isDefaultInput) {
423 PyDict_SetItemString(info_dict, "isDefaultInput", Py_True);
427 PyDict_SetItemString(info_dict, "isDefaultInput", Py_False);
433 catch(RtError &error) {
434 PyErr_SetString(RtAudioError, error.getMessage().c_str());
435 Py_INCREF(RtAudioError);
440 static PyObject* RtAudio_getDefaultOutputDevice(PyRtAudio *self, PyObject *args)
442 if (self == NULL || self->dac == NULL) return NULL;
443 return PyInt_FromLong(self->dac->getDefaultOutputDevice());
446 static PyObject* RtAudio_getDefaultInputDevice(PyRtAudio *self, PyObject *args)
448 if (self == NULL || self->dac == NULL) return NULL;
449 return PyInt_FromLong(self->dac->getDefaultInputDevice());
452 static PyObject* RtAudio_getStreamTime(PyRtAudio *self, PyObject *args)
454 if (self == NULL || self->dac == NULL) return NULL;
455 return PyFloat_FromDouble( self->dac->getStreamTime() );
458 static PyObject* RtAudio_getStreamLatency(PyRtAudio *self, PyObject *args)
460 if (self == NULL || self->dac == NULL) return NULL;
461 return PyInt_FromLong( self->dac->getStreamLatency() );
464 static PyObject* RtAudio_getStreamSampleRate(PyRtAudio *self, PyObject *args)
466 if (self == NULL || self->dac == NULL) return NULL;
467 return PyInt_FromLong( self->dac->getStreamSampleRate() );
470 static PyObject* RtAudio_showWarnings(PyRtAudio *self, PyObject *args)
472 if (self == NULL || self->dac == NULL) return NULL;
475 if (!PyArg_ParseTuple(args, "O", &obj))
478 if (!PyBool_Check(obj))
482 self->dac->showWarnings(true);
483 else if (obj == Py_False)
484 self->dac->showWarnings(false);
486 printf("not true nor false\n");
492 static PyMethodDef RtAudio_methods[] =
494 // TO BE DONE: getCurrentApi(void)
495 {"getDeviceCount", (PyCFunction) RtAudio_getDeviceCount, METH_NOARGS,
496 "A public function that queries for the number of audio devices available."},
497 {"getDeviceInfo", (PyCFunction) RtAudio_getDeviceInfo, METH_VARARGS,
498 "Return a dictionary with information for a specified device number."},
499 {"getDefaultOutputDevice", (PyCFunction) RtAudio_getDefaultOutputDevice, METH_NOARGS,
500 "A function that returns the index of the default output device."},
501 {"getDefaultInputDevice", (PyCFunction) RtAudio_getDefaultInputDevice, METH_NOARGS,
502 "A function that returns the index of the default input device."},
503 {"openStream", (PyCFunction) RtAudio_openStream, METH_VARARGS,
504 "A public method for opening a stream with the specified parameters."},
505 {"closeStream", (PyCFunction) RtAudio_closeStream, METH_NOARGS,
506 "A function that closes a stream and frees any associated stream memory. "},
507 {"startStream", (PyCFunction) RtAudio_startStream, METH_NOARGS,
508 "A function that starts a stream. "},
509 {"stopStream", (PyCFunction) RtAudio_stopStream, METH_NOARGS,
510 "Stop a stream, allowing any samples remaining in the output queue to be played. "},
511 {"abortStream", (PyCFunction) RtAudio_abortStream, METH_NOARGS,
512 "Stop a stream, discarding any samples remaining in the input/output queue."},
513 {"isStreamOpen", (PyCFunction) RtAudio_isStreamOpen, METH_NOARGS,
514 "Returns true if a stream is open and false if not."},
515 {"isStreamRunning", (PyCFunction) RtAudio_isStreamRunning, METH_NOARGS,
516 "Returns true if the stream is running and false if it is stopped or not open."},
517 {"getStreamTime", (PyCFunction) RtAudio_getStreamTime, METH_NOARGS,
518 "Returns the number of elapsed seconds since the stream was started."},
519 {"getStreamLatency", (PyCFunction) RtAudio_getStreamLatency, METH_NOARGS,
520 "Returns the internal stream latency in sample frames."},
521 {"getStreamSampleRate", (PyCFunction) RtAudio_getStreamSampleRate, METH_NOARGS,
522 "Returns actual sample rate in use by the stream."},
523 {"showWarnings", (PyCFunction) RtAudio_showWarnings, METH_VARARGS,
524 "Specify whether warning messages should be printed to stderr."},
525 // TO BE DONE: getCompiledApi (std::vector< RtAudio::Api > &apis) throw ()
530 static PyTypeObject RtAudio_type = {
531 PyObject_HEAD_INIT(NULL)
533 "rtaudio.RtAudio", /*tp_name*/
534 sizeof(RtAudio), /*tp_basicsize*/
536 (destructor) RtAudio_dealloc, /*tp_dealloc*/
543 0, /*tp_as_sequence*/
551 Py_TPFLAGS_DEFAULT, /*tp_flags*/
552 "Audio input device", /* tp_doc */
555 0, /* tp_richcompare */
556 0, /* tp_weaklistoffset */
559 RtAudio_methods, /* tp_methods */
564 0, /* tp_descr_get */
565 0, /* tp_descr_set */
566 0, /* tp_dictoffset */
567 (initproc)RtAudio_init, /* tp_init */
569 RtAudio_new, /* tp_new */
570 0, /* Low-level free-memory routine */
571 0, /* For PyObject_IS_GC */
572 0, // PyObject *tp_bases;
573 0, // PyObject *tp_mro; /* method resolution order */
574 0, //PyObject *tp_cache;
575 0, //PyObject *tp_subclasses;
576 0, //PyObject *tp_weaklist;
577 0, //destructor tp_del;
578 //0, /* Type attribute cache version tag. Added in version 2.6 */
583 #ifndef PyMODINIT_FUNC /* declarations for DLL import/export */
584 #define PyMODINIT_FUNC void
589 PyEval_InitThreads();
591 if (PyType_Ready(&RtAudio_type) < 0)
594 PyObject* module = Py_InitModule3("rtaudio", NULL, "RtAudio wrapper.");
598 Py_INCREF(&RtAudio_type);
599 PyModule_AddObject(module, "RtAudio", (PyObject *)&RtAudio_type);
601 RtAudioError = PyErr_NewException("rtaudio.RtError", NULL, NULL);
602 Py_INCREF(RtAudioError);
603 PyModule_AddObject(module, "RtError", RtAudioError);