@@ -86,6 +86,7 @@ static const RtAudioFormat RTAUDIO_FLOAT64 = 0x20; // Normalized between plus/mi | |||
- \e RTAUDIO_NONINTERLEAVED: Use non-interleaved buffers (default = interleaved). | |||
- \e RTAUDIO_MINIMIZE_LATENCY: Attempt to set stream parameters for lowest possible latency. | |||
- \e RTAUDIO_HOG_DEVICE: Attempt grab device for exclusive use. | |||
- \e RTAUDIO_ALSA_USE_DEFAULT: Use the "default" PCM device (ALSA only). | |||
By default, RtAudio streams pass and receive audio data from the | |||
client in an interleaved format. By passing the | |||
@@ -113,12 +114,17 @@ static const RtAudioFormat RTAUDIO_FLOAT64 = 0x20; // Normalized between plus/mi | |||
If the RTAUDIO_SCHEDULE_REALTIME flag is set, RtAudio will attempt | |||
to select realtime scheduling (round-robin) for the callback thread. | |||
If the RTAUDIO_ALSA_USE_DEFAULT flag is set, RtAudio will attempt to | |||
open the "default" PCM device when using the ALSA API. Note that this | |||
will override any specified input or output device id. | |||
*/ | |||
typedef unsigned int RtAudioStreamFlags; | |||
static const RtAudioStreamFlags RTAUDIO_NONINTERLEAVED = 0x1; // Use non-interleaved buffers (default = interleaved). | |||
static const RtAudioStreamFlags RTAUDIO_MINIMIZE_LATENCY = 0x2; // Attempt to set stream parameters for lowest possible latency. | |||
static const RtAudioStreamFlags RTAUDIO_HOG_DEVICE = 0x4; // Attempt grab device and prevent use by others. | |||
static const RtAudioStreamFlags RTAUDIO_SCHEDULE_REALTIME = 0x8; // Try to select realtime scheduling for callback thread. | |||
static const RtAudioStreamFlags RTAUDIO_ALSA_USE_DEFAULT = 0x10; // Use the "default" PCM device (ALSA only). | |||
/*! \typedef typedef unsigned long RtAudioStreamStatus; | |||
\brief RtAudio stream status (over- or underflow) flags. | |||
@@ -250,6 +256,7 @@ class RtAudio | |||
- \e RTAUDIO_MINIMIZE_LATENCY: Attempt to set stream parameters for lowest possible latency. | |||
- \e RTAUDIO_HOG_DEVICE: Attempt grab device for exclusive use. | |||
- \e RTAUDIO_SCHEDULE_REALTIME: Attempt to select realtime scheduling for callback thread. | |||
- \e RTAUDIO_ALSA_USE_DEFAULT: Use the "default" PCM device (ALSA only). | |||
By default, RtAudio streams pass and receive audio data from the | |||
client in an interleaved format. By passing the | |||
@@ -278,7 +285,11 @@ class RtAudio | |||
If the RTAUDIO_SCHEDULE_REALTIME flag is set, RtAudio will attempt | |||
to select realtime scheduling (round-robin) for the callback thread. | |||
The \c priority parameter will only be used if the RTAUDIO_SCHEDULE_REALTIME | |||
flag is set. It defines the thread's realtime priority. | |||
flag is set. It defines the thread's realtime priority. | |||
If the RTAUDIO_ALSA_USE_DEFAULT flag is set, RtAudio will attempt to | |||
open the "default" PCM device when using the ALSA API. Note that this | |||
will override any specified input or output device id. | |||
The \c numberOfBuffers parameter can be used to control stream | |||
latency in the Windows DirectSound, Linux OSS, and Linux Alsa APIs | |||
@@ -294,7 +305,7 @@ class RtAudio | |||
RtAudio with Jack, each instance must have a unique client name. | |||
*/ | |||
struct StreamOptions { | |||
RtAudioStreamFlags flags; /*!< A bit-mask of stream flags (RTAUDIO_NONINTERLEAVED, RTAUDIO_MINIMIZE_LATENCY, RTAUDIO_HOG_DEVICE). */ | |||
RtAudioStreamFlags flags; /*!< A bit-mask of stream flags (RTAUDIO_NONINTERLEAVED, RTAUDIO_MINIMIZE_LATENCY, RTAUDIO_HOG_DEVICE, RTAUDIO_ALSA_USE_DEFAULT). */ | |||
unsigned int numberOfBuffers; /*!< Number of stream buffers. */ | |||
std::string streamName; /*!< A stream name (currently used only in Jack). */ | |||
int priority; /*!< Scheduling priority of callback thread (only used with flag RTAUDIO_SCHEDULE_REALTIME). */ | |||
@@ -0,0 +1,70 @@ | |||
import rtaudio as rt | |||
from math import cos | |||
import struct | |||
class audio_generator: | |||
def __init__(self): | |||
self.idx = -1 | |||
self.freq = 440. | |||
def __call__(self): | |||
self.idx += 1 | |||
if self.idx%48000 == 0: | |||
self.freq *= 2**(1/12.) | |||
return 0.5*cos(2.*3.1416*self.freq*self.idx/48000.) | |||
class callback: | |||
def __init__(self, gen): | |||
self.gen = gen | |||
self.i = 0 | |||
def __call__(self,playback, capture): | |||
[struct.pack_into("f", playback, 4*o, self.gen()) for o in xrange(256)] | |||
self.i = self.i + 256 | |||
if self.i > 48000*10: | |||
print '.' | |||
return 1 | |||
dac = rt.RtAudio() | |||
n = dac.getDeviceCount() | |||
print 'Number of devices available: ', n | |||
for i in range(n): | |||
try: | |||
print dac.getDeviceInfo(i) | |||
except rt.RtError as e: | |||
print e | |||
print 'Default output device: ', dac.getDefaultOutputDevice() | |||
print 'Default input device: ', dac.getDefaultInputDevice() | |||
print 'is stream open: ', dac.isStreamOpen() | |||
print 'is stream running: ', dac.isStreamRunning() | |||
oParams = {'deviceId': 1, 'nChannels': 1, 'firstChannel': 0} | |||
iParams = {'deviceId': 1, 'nChannels': 1, 'firstChannel': 0} | |||
try: | |||
dac.openStream(oParams,oParams,48000,256,callback(audio_generator()) ) | |||
except rt.RtError as e: | |||
print e | |||
else: | |||
dac.startStream() | |||
import time | |||
print 'latency: ', dac.getStreamLatency() | |||
while (dac.isStreamRunning()): | |||
time.sleep(0.1) | |||
print dac.getStreamTime() | |||
dac.stopStream() | |||
dac.abortStream() | |||
dac.closeStream() | |||
@@ -0,0 +1,57 @@ | |||
PyRtAudio - a python wrapper around RtAudio that allows to perform audio i/o operations in real-time from the python language. | |||
By Antoine Lefebvre, 2011 | |||
This software is in the development stage. Do not expect compatibility | |||
with future versions. Comments, suggestions, new features, bug fixes, | |||
etc. are welcome. | |||
This distribution of PyRtAudio contains the following: | |||
- rtaudiomodule.cpp: the python wrapper code | |||
- setup.py: a setup script use to compile and install PyRtAudio | |||
- examples: a single PyRtAudioTest.py script | |||
INSTALLATION | |||
The compilation and installation of the PyRtAudio module is handled by | |||
the python Distribution Utilities ("Distutils"). Provided that your | |||
system has a C++ compiler and is properly configure, the following | |||
command should be sufficient: | |||
>> python setup.py install | |||
Please refer to the distutils documentation for installation problems: http://docs.python.org/distutils/index.html | |||
LEGAL AND ETHICAL: | |||
The PyRtAudio license is the same as the RtAudio license: | |||
PyRtAudio: a python wrapper around RtAudio | |||
Copyright (c)2011 Antoine Lefebvre | |||
Permission is hereby granted, free of charge, to any person | |||
obtaining a copy of this software and associated documentation files | |||
(the "Software"), to deal in the Software without restriction, | |||
including without limitation the rights to use, copy, modify, merge, | |||
publish, distribute, sublicense, and/or sell copies of the Software, | |||
and to permit persons to whom the Software is furnished to do so, | |||
subject to the following conditions: | |||
The above copyright notice and this permission notice shall be | |||
included in all copies or substantial portions of the Software. | |||
Any person wishing to distribute modifications to the Software is | |||
asked to send the modifications to the original developer so that | |||
they can be incorporated into the canonical version. This is, | |||
however, not a binding provision of this license. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR | |||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF | |||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | |||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |||
@@ -0,0 +1,605 @@ | |||
/************************************************************************/ | |||
/* PyRtAudio: a python wrapper around RtAudio | |||
Copyright (c) 2011 Antoine Lefebvre | |||
Permission is hereby granted, free of charge, to any person | |||
obtaining a copy of this software and associated documentation files | |||
(the "Software"), to deal in the Software without restriction, | |||
including without limitation the rights to use, copy, modify, merge, | |||
publish, distribute, sublicense, and/or sell copies of the Software, | |||
and to permit persons to whom the Software is furnished to do so, | |||
subject to the following conditions: | |||
The above copyright notice and this permission notice shall be | |||
included in all copies or substantial portions of the Software. | |||
Any person wishing to distribute modifications to the Software is | |||
asked to send the modifications to the original developer so that | |||
they can be incorporated into the canonical version. This is, | |||
however, not a binding provision of this license. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR | |||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF | |||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | |||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |||
*/ | |||
/************************************************************************/ | |||
// This software is in the development stage | |||
// Do not expect compatibility with future versions. | |||
// Comments, suggestions, new features, bug fixes, etc. are welcome | |||
#include <Python.h> | |||
#include "RtAudio.h" | |||
extern "C" { | |||
typedef struct | |||
{ | |||
PyObject_HEAD; | |||
RtAudio *dac; | |||
RtAudioFormat _format; | |||
int _bufferSize; | |||
unsigned int inputChannels; | |||
PyObject *callback_func; | |||
} PyRtAudio; | |||
static PyObject *RtAudioError; | |||
static int callback(void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames, | |||
double streamTime, RtAudioStreamStatus status, void *data ) | |||
{ | |||
PyRtAudio* self = (PyRtAudio*) data; | |||
if (status == RTAUDIO_OUTPUT_UNDERFLOW) | |||
printf("underflow.\n"); | |||
if (self == NULL) return -1; | |||
float* in = (float *) inputBuffer; | |||
float* out = (float *) outputBuffer; | |||
PyObject *py_callback_func = self->callback_func; | |||
int retval = 0; | |||
if (py_callback_func) { | |||
PyGILState_STATE gstate = PyGILState_Ensure(); | |||
PyObject* iBuffer = PyBuffer_FromMemory(in, sizeof(float) * self->inputChannels * nBufferFrames); | |||
PyObject* oBuffer = PyBuffer_FromReadWriteMemory(out, sizeof(float) * nBufferFrames); | |||
PyObject *arglist = Py_BuildValue("(O,O)", oBuffer, iBuffer); | |||
if (arglist == NULL) { | |||
printf("error.\n"); | |||
PyErr_Print(); | |||
PyGILState_Release(gstate); | |||
return 2; | |||
} | |||
// Calling the callback | |||
PyObject *result = PyEval_CallObject(py_callback_func, arglist); | |||
if (PyErr_Occurred() != NULL) { | |||
PyErr_Print(); | |||
} | |||
else if PyInt_Check(result) { | |||
retval = PyInt_AsLong(result); | |||
} | |||
Py_DECREF(arglist); | |||
Py_DECREF(oBuffer); | |||
Py_DECREF(iBuffer); | |||
Py_XDECREF(result); | |||
PyGILState_Release(gstate); | |||
} | |||
return retval; | |||
} | |||
static void RtAudio_dealloc(PyRtAudio *self) | |||
{ | |||
printf("RtAudio_dealloc.\n"); | |||
if (self == NULL) return; | |||
if (self->dac) { | |||
self->dac->closeStream(); | |||
Py_CLEAR(self->callback_func); | |||
delete self->dac; | |||
} | |||
self->ob_type->tp_free((PyObject *) self); | |||
} | |||
static PyObject* RtAudio_new(PyTypeObject *type, PyObject *args, PyObject *kwds) | |||
{ | |||
printf("RtAudio_new.\n"); | |||
PyRtAudio *self; | |||
char *api = NULL; | |||
if(!PyArg_ParseTuple(args, "|s", &api)) | |||
return NULL; | |||
self = (PyRtAudio *) type->tp_alloc(type, 0); | |||
if(self == NULL) return NULL; | |||
self->dac = NULL; | |||
self->callback_func = NULL; | |||
try { | |||
if (api == NULL) | |||
self->dac = new RtAudio; | |||
else if(!strcmp(api, "jack")) | |||
self->dac = new RtAudio(RtAudio::UNIX_JACK); | |||
else if(!strcmp(api, "alsa")) | |||
self->dac = new RtAudio(RtAudio::LINUX_ALSA); | |||
else if(!strcmp(api, "oss")) | |||
self->dac = new RtAudio(RtAudio::LINUX_ALSA); | |||
else if(!strcmp(api, "core")) | |||
self->dac = new RtAudio(RtAudio::MACOSX_CORE); | |||
else if(!strcmp(api, "asio")) | |||
self->dac = new RtAudio(RtAudio::WINDOWS_ASIO); | |||
else if(!strcmp(api, "directsound")) | |||
self->dac = new RtAudio(RtAudio::WINDOWS_DS); | |||
} | |||
catch (RtError &error) { | |||
PyErr_SetString(RtAudioError, error.getMessage().c_str()); | |||
Py_INCREF(RtAudioError); | |||
return NULL; | |||
} | |||
self->dac->showWarnings(false); | |||
//Py_XINCREF(self); | |||
return (PyObject *) self; | |||
} | |||
static int RtAudio_init(PyRtAudio *self, PyObject *args, PyObject *kwds) | |||
{ | |||
printf("RtAudio_init.\n"); | |||
//if (self == NULL) return 0; | |||
return 0; | |||
} | |||
// This functions does not yet support all the features of the RtAudio::openStream method. | |||
// Please send your patches if you improves this. | |||
static PyObject* RtAudio_openStream(PyRtAudio *self, PyObject *args) | |||
{ | |||
if (self == NULL) return NULL; | |||
if (self->dac == NULL) { | |||
printf("the dac is null.\n"); | |||
Py_RETURN_NONE; | |||
} | |||
PyObject *oParamsObj; | |||
PyObject *iParamsObj; | |||
int fs; | |||
unsigned int bf; | |||
PyObject *pycallback; | |||
if (!PyArg_ParseTuple(args, "OOiiO", &oParamsObj, &iParamsObj, &fs, &bf, &pycallback)) | |||
return NULL; | |||
RtAudio::StreamParameters oParams; | |||
oParams.deviceId = 1; | |||
oParams.nChannels = 1; | |||
oParams.firstChannel = 0; | |||
if (PyDict_Check(oParamsObj)) { | |||
if (PyDict_Contains(oParamsObj, PyString_FromString("deviceId"))) { | |||
PyObject *value = PyDict_GetItem(oParamsObj, PyString_FromString("deviceId")); | |||
oParams.deviceId = PyInt_AsLong(value); | |||
} | |||
if (PyDict_Contains(oParamsObj, PyString_FromString("nChannels"))) { | |||
PyObject *value = PyDict_GetItem(oParamsObj, PyString_FromString("nChannels")); | |||
oParams.nChannels = PyInt_AsLong(value); | |||
} | |||
if (PyDict_Contains(oParamsObj, PyString_FromString("firstChannel"))) { | |||
PyObject *value = PyDict_GetItem(oParamsObj, PyString_FromString("firstChannel")); | |||
oParams.firstChannel = PyInt_AsLong(value); | |||
} | |||
} | |||
else { | |||
printf("First argument must be a dictionary. Default values will be used.\n"); | |||
} | |||
RtAudio::StreamParameters iParams; | |||
iParams.deviceId = 1; | |||
iParams.nChannels = 2; | |||
iParams.firstChannel = 0; | |||
if (PyDict_Check(iParamsObj)) { | |||
if (PyDict_Contains(iParamsObj, PyString_FromString("deviceId"))) { | |||
PyObject *value = PyDict_GetItem(iParamsObj, PyString_FromString("deviceId")); | |||
iParams.deviceId = PyInt_AsLong(value); | |||
} | |||
if (PyDict_Contains(iParamsObj, PyString_FromString("nChannels"))) { | |||
PyObject *value = PyDict_GetItem(iParamsObj, PyString_FromString("nChannels")); | |||
iParams.nChannels = PyInt_AsLong(value); | |||
} | |||
if (PyDict_Contains(iParamsObj, PyString_FromString("firstChannel"))) { | |||
PyObject *value = PyDict_GetItem(iParamsObj, PyString_FromString("firstChannel")); | |||
iParams.firstChannel = PyInt_AsLong(value); | |||
} | |||
} | |||
else { | |||
printf("Second argument must be a dictionary. Default values will be used.\n"); | |||
} | |||
if (!PyCallable_Check(pycallback)) { | |||
PyErr_SetString(PyExc_TypeError, "Need a callable object!"); | |||
Py_XINCREF(PyExc_TypeError); | |||
return NULL; | |||
} | |||
// sanity check the callback ? | |||
Py_INCREF(pycallback); /* Add a reference to new callback */ | |||
self->callback_func = pycallback; /*Remember new callback */ | |||
// add support for other format | |||
self->_format = RTAUDIO_FLOAT32; | |||
// add support for other options | |||
RtAudio::StreamOptions options; | |||
options.flags = RTAUDIO_NONINTERLEAVED; | |||
try { | |||
if (self->dac->isStreamOpen()) | |||
self->dac->closeStream(); | |||
self->dac->openStream(&oParams, &iParams, self->_format, fs, &bf, &callback, self, &options); | |||
} | |||
catch ( RtError& error ) { | |||
PyErr_SetString(RtAudioError, error.getMessage().c_str()); | |||
Py_INCREF(RtAudioError); | |||
return NULL; | |||
} | |||
self->inputChannels = iParams.nChannels; | |||
Py_RETURN_NONE; | |||
} | |||
static PyObject* RtAudio_closeStream(PyRtAudio *self, PyObject *args) | |||
{ | |||
printf("RtAudio_closeStream.\n"); | |||
if (self == NULL || self->dac == NULL) return NULL; | |||
try { | |||
self->dac->closeStream(); | |||
Py_CLEAR(self->callback_func); | |||
} | |||
catch(RtError &error) { | |||
PyErr_SetString(RtAudioError, error.getMessage().c_str()); | |||
Py_INCREF(RtAudioError); | |||
return NULL; | |||
} | |||
Py_RETURN_NONE; | |||
} | |||
static PyObject* RtAudio_startStream(PyRtAudio *self, PyObject *args) | |||
{ | |||
if (self == NULL || self->dac == NULL) return NULL; | |||
try { | |||
self->dac->startStream(); | |||
} | |||
catch(RtError &error) { | |||
PyErr_SetString(RtAudioError, error.getMessage().c_str()); | |||
Py_INCREF(RtAudioError); | |||
return NULL; | |||
} | |||
Py_RETURN_NONE; | |||
} | |||
static PyObject* RtAudio_stopStream(PyRtAudio *self, PyObject *args) | |||
{ | |||
printf("RtAudio_stopStream.\n"); | |||
if (self == NULL || self->dac == NULL) return NULL; | |||
try { | |||
self->dac->stopStream(); | |||
} | |||
catch(RtError &error) { | |||
PyErr_SetString(RtAudioError, error.getMessage().c_str()); | |||
Py_INCREF(RtAudioError); | |||
return NULL; | |||
} | |||
Py_RETURN_NONE; | |||
} | |||
static PyObject* RtAudio_abortStream(PyRtAudio *self, PyObject *args) | |||
{ | |||
printf("RtAudio_abortStream.\n"); | |||
if (self == NULL || self->dac == NULL) return NULL; | |||
try { | |||
self->dac->abortStream(); | |||
} | |||
catch(RtError &error) { | |||
PyErr_SetString(RtAudioError, error.getMessage().c_str()); | |||
Py_INCREF(RtAudioError); | |||
return NULL; | |||
} | |||
Py_RETURN_NONE; | |||
} | |||
static PyObject* RtAudio_isStreamRunning(PyRtAudio *self, PyObject *args) | |||
{ | |||
if (self == NULL || self->dac == NULL) return NULL; | |||
if (self->dac == NULL) { | |||
Py_RETURN_FALSE; | |||
} | |||
if (self->dac->isStreamRunning()) | |||
Py_RETURN_TRUE; | |||
else | |||
Py_RETURN_FALSE; | |||
} | |||
static PyObject* RtAudio_isStreamOpen(PyRtAudio *self, PyObject *args) | |||
{ | |||
if (self == NULL || self->dac == NULL) return NULL; | |||
if (self->dac == NULL) { | |||
Py_RETURN_FALSE; | |||
} | |||
if (self->dac->isStreamOpen()) | |||
Py_RETURN_TRUE; | |||
else | |||
Py_RETURN_FALSE; | |||
} | |||
static PyObject* RtAudio_getDeviceCount(PyRtAudio *self, PyObject *args) | |||
{ | |||
if (self == NULL || self->dac == NULL) return NULL; | |||
return PyInt_FromLong(self->dac->getDeviceCount()); | |||
} | |||
static PyObject* RtAudio_getDeviceInfo(PyRtAudio *self, PyObject *args) | |||
{ | |||
if (self == NULL || self->dac == NULL) return NULL; | |||
int device; | |||
if (!PyArg_ParseTuple(args, "i", &device)) | |||
return NULL; | |||
try { | |||
RtAudio::DeviceInfo info = self->dac->getDeviceInfo(device); | |||
PyObject* info_dict = PyDict_New(); | |||
if (info.probed) { | |||
Py_INCREF(Py_True); | |||
PyDict_SetItemString(info_dict, "probed", Py_True); | |||
} | |||
else { | |||
Py_INCREF(Py_False); | |||
PyDict_SetItemString(info_dict, "probed", Py_False); | |||
} | |||
PyObject* obj; | |||
obj = PyString_FromString(info.name.c_str()); | |||
PyDict_SetItemString(info_dict, "name", obj); | |||
obj = PyInt_FromLong(info.outputChannels); | |||
PyDict_SetItemString(info_dict, "outputChannels", obj); | |||
obj = PyInt_FromLong(info.inputChannels); | |||
PyDict_SetItemString(info_dict, "inputChannels", obj); | |||
obj = PyInt_FromLong(info.duplexChannels); | |||
PyDict_SetItemString(info_dict, "duplexChannels", obj); | |||
if (info.isDefaultOutput) { | |||
Py_INCREF(Py_True); | |||
PyDict_SetItemString(info_dict, "isDefaultOutput", Py_True); | |||
} | |||
else { | |||
Py_INCREF(Py_False); | |||
PyDict_SetItemString(info_dict, "isDefaultOutput", Py_False); | |||
} | |||
if (info.isDefaultInput) { | |||
Py_INCREF(Py_True); | |||
PyDict_SetItemString(info_dict, "isDefaultInput", Py_True); | |||
} | |||
else { | |||
Py_INCREF(Py_False); | |||
PyDict_SetItemString(info_dict, "isDefaultInput", Py_False); | |||
} | |||
return info_dict; | |||
} | |||
catch(RtError &error) { | |||
PyErr_SetString(RtAudioError, error.getMessage().c_str()); | |||
Py_INCREF(RtAudioError); | |||
return NULL; | |||
} | |||
} | |||
static PyObject* RtAudio_getDefaultOutputDevice(PyRtAudio *self, PyObject *args) | |||
{ | |||
if (self == NULL || self->dac == NULL) return NULL; | |||
return PyInt_FromLong(self->dac->getDefaultOutputDevice()); | |||
} | |||
static PyObject* RtAudio_getDefaultInputDevice(PyRtAudio *self, PyObject *args) | |||
{ | |||
if (self == NULL || self->dac == NULL) return NULL; | |||
return PyInt_FromLong(self->dac->getDefaultInputDevice()); | |||
} | |||
static PyObject* RtAudio_getStreamTime(PyRtAudio *self, PyObject *args) | |||
{ | |||
if (self == NULL || self->dac == NULL) return NULL; | |||
return PyFloat_FromDouble( self->dac->getStreamTime() ); | |||
} | |||
static PyObject* RtAudio_getStreamLatency(PyRtAudio *self, PyObject *args) | |||
{ | |||
if (self == NULL || self->dac == NULL) return NULL; | |||
return PyInt_FromLong( self->dac->getStreamLatency() ); | |||
} | |||
static PyObject* RtAudio_getStreamSampleRate(PyRtAudio *self, PyObject *args) | |||
{ | |||
if (self == NULL || self->dac == NULL) return NULL; | |||
return PyInt_FromLong( self->dac->getStreamSampleRate() ); | |||
} | |||
static PyObject* RtAudio_showWarnings(PyRtAudio *self, PyObject *args) | |||
{ | |||
if (self == NULL || self->dac == NULL) return NULL; | |||
PyObject *obj; | |||
if (!PyArg_ParseTuple(args, "O", &obj)) | |||
return NULL; | |||
if (!PyBool_Check(obj)) | |||
return NULL; | |||
if (obj == Py_True) | |||
self->dac->showWarnings(true); | |||
else if (obj == Py_False) | |||
self->dac->showWarnings(false); | |||
else { | |||
printf("not true nor false\n"); | |||
} | |||
Py_RETURN_NONE; | |||
} | |||
static PyMethodDef RtAudio_methods[] = | |||
{ | |||
// TO BE DONE: getCurrentApi(void) | |||
{"getDeviceCount", (PyCFunction) RtAudio_getDeviceCount, METH_NOARGS, | |||
"A public function that queries for the number of audio devices available."}, | |||
{"getDeviceInfo", (PyCFunction) RtAudio_getDeviceInfo, METH_VARARGS, | |||
"Return a dictionary with information for a specified device number."}, | |||
{"getDefaultOutputDevice", (PyCFunction) RtAudio_getDefaultOutputDevice, METH_NOARGS, | |||
"A function that returns the index of the default output device."}, | |||
{"getDefaultInputDevice", (PyCFunction) RtAudio_getDefaultInputDevice, METH_NOARGS, | |||
"A function that returns the index of the default input device."}, | |||
{"openStream", (PyCFunction) RtAudio_openStream, METH_VARARGS, | |||
"A public method for opening a stream with the specified parameters."}, | |||
{"closeStream", (PyCFunction) RtAudio_closeStream, METH_NOARGS, | |||
"A function that closes a stream and frees any associated stream memory. "}, | |||
{"startStream", (PyCFunction) RtAudio_startStream, METH_NOARGS, | |||
"A function that starts a stream. "}, | |||
{"stopStream", (PyCFunction) RtAudio_stopStream, METH_NOARGS, | |||
"Stop a stream, allowing any samples remaining in the output queue to be played. "}, | |||
{"abortStream", (PyCFunction) RtAudio_abortStream, METH_NOARGS, | |||
"Stop a stream, discarding any samples remaining in the input/output queue."}, | |||
{"isStreamOpen", (PyCFunction) RtAudio_isStreamOpen, METH_NOARGS, | |||
"Returns true if a stream is open and false if not."}, | |||
{"isStreamRunning", (PyCFunction) RtAudio_isStreamRunning, METH_NOARGS, | |||
"Returns true if the stream is running and false if it is stopped or not open."}, | |||
{"getStreamTime", (PyCFunction) RtAudio_getStreamTime, METH_NOARGS, | |||
"Returns the number of elapsed seconds since the stream was started."}, | |||
{"getStreamLatency", (PyCFunction) RtAudio_getStreamLatency, METH_NOARGS, | |||
"Returns the internal stream latency in sample frames."}, | |||
{"getStreamSampleRate", (PyCFunction) RtAudio_getStreamSampleRate, METH_NOARGS, | |||
"Returns actual sample rate in use by the stream."}, | |||
{"showWarnings", (PyCFunction) RtAudio_showWarnings, METH_VARARGS, | |||
"Specify whether warning messages should be printed to stderr."}, | |||
// TO BE DONE: getCompiledApi (std::vector< RtAudio::Api > &apis) throw () | |||
{NULL} | |||
}; | |||
static PyTypeObject RtAudio_type = { | |||
PyObject_HEAD_INIT(NULL) | |||
0, /*ob_size*/ | |||
"rtaudio.RtAudio", /*tp_name*/ | |||
sizeof(RtAudio), /*tp_basicsize*/ | |||
0, /*tp_itemsize*/ | |||
(destructor) RtAudio_dealloc, /*tp_dealloc*/ | |||
0, /*tp_print*/ | |||
0, /*tp_getattr*/ | |||
0, /*tp_setattr*/ | |||
0, /*tp_compare*/ | |||
0, /*tp_repr*/ | |||
0, /*tp_as_number*/ | |||
0, /*tp_as_sequence*/ | |||
0, /*tp_as_mapping*/ | |||
0, /*tp_hash */ | |||
0, /*tp_call*/ | |||
0, /*tp_str*/ | |||
0, /*tp_getattro*/ | |||
0, /*tp_setattro*/ | |||
0, /*tp_as_buffer*/ | |||
Py_TPFLAGS_DEFAULT, /*tp_flags*/ | |||
"Audio input device", /* tp_doc */ | |||
0, /* tp_traverse */ | |||
0, /* tp_clear */ | |||
0, /* tp_richcompare */ | |||
0, /* tp_weaklistoffset */ | |||
0, /* tp_iter */ | |||
0, /* tp_iternext */ | |||
RtAudio_methods, /* tp_methods */ | |||
0, /* tp_members */ | |||
0, /* tp_getset */ | |||
0, /* tp_base */ | |||
0, /* tp_dict */ | |||
0, /* tp_descr_get */ | |||
0, /* tp_descr_set */ | |||
0, /* tp_dictoffset */ | |||
(initproc)RtAudio_init, /* tp_init */ | |||
0, /* tp_alloc */ | |||
RtAudio_new, /* tp_new */ | |||
0, /* Low-level free-memory routine */ | |||
0, /* For PyObject_IS_GC */ | |||
0, // PyObject *tp_bases; | |||
0, // PyObject *tp_mro; /* method resolution order */ | |||
0, //PyObject *tp_cache; | |||
0, //PyObject *tp_subclasses; | |||
0, //PyObject *tp_weaklist; | |||
0, //destructor tp_del; | |||
//0, /* Type attribute cache version tag. Added in version 2.6 */ | |||
}; | |||
#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */ | |||
#define PyMODINIT_FUNC void | |||
#endif | |||
PyMODINIT_FUNC | |||
initrtaudio(void) | |||
{ | |||
PyEval_InitThreads(); | |||
if (PyType_Ready(&RtAudio_type) < 0) | |||
return; | |||
PyObject* module = Py_InitModule3("rtaudio", NULL, "RtAudio wrapper."); | |||
if (module == NULL) | |||
return; | |||
Py_INCREF(&RtAudio_type); | |||
PyModule_AddObject(module, "RtAudio", (PyObject *)&RtAudio_type); | |||
RtAudioError = PyErr_NewException("rtaudio.RtError", NULL, NULL); | |||
Py_INCREF(RtAudioError); | |||
PyModule_AddObject(module, "RtError", RtAudioError); | |||
} | |||
} |
@@ -0,0 +1,58 @@ | |||
#!/bin/env python | |||
import os | |||
from distutils.core import setup, Extension | |||
if hasattr(os, 'uname'): | |||
OSNAME = os.uname()[0] | |||
else: | |||
OSNAME = 'Windows' | |||
define_macros = [] | |||
libraries = [] | |||
extra_link_args = [] | |||
extra_compile_args = ['-I../../../'] | |||
sources = ['rtaudiomodule.cpp', '../../../RtAudio.cpp'] | |||
if OSNAME == 'Linux': | |||
define_macros=[("__LINUX_ALSA__", ''), | |||
('__LINUX_JACK__', ''), | |||
('__LINUX_OSS__', '')] | |||
libraries = ['asound', 'jack', 'pthread'] | |||
elif OSNAME == 'Darwin': | |||
define_macros = [('__MACOSX_CORE__', '')] | |||
libraries = ['pthread', 'stdc++'] | |||
extra_link_args = ['-framework', 'CoreAudio'] | |||
elif OSNAME == 'Windows': | |||
define_macros = [('__WINDOWS_DS__', None), | |||
('__WINDOWS_ASIO__', None), | |||
('__LITTLE_ENDIAN__',None), | |||
('WIN32',None)] | |||
libraries = ['winmm', 'dsound', 'Advapi32','Ole32','User32'] | |||
sources += ['../../../include/asio.cpp', | |||
'../../../include/asiodrivers.cpp', | |||
'../../../include/asiolist.cpp', | |||
'../../../include/iasiothiscallresolver.cpp'] | |||
extra_compile_args.append('-I../../../include/') | |||
extra_compile_args.append('-EHsc') | |||
audio = Extension('rtaudio', | |||
sources=sources, | |||
libraries=libraries, | |||
define_macros=define_macros, | |||
extra_compile_args = extra_compile_args, | |||
extra_link_args = extra_link_args, | |||
) | |||
setup(name = 'rtaudio', | |||
version = '0.1', | |||
description = 'Python RtAudio interface', | |||
ext_modules = [audio]) | |||
@@ -31,7 +31,7 @@ PROJECT_NAME = RtAudio | |||
# This could be handy for archiving the generated documentation or | |||
# if some version control system is used. | |||
PROJECT_NUMBER = 4.0.7 | |||
PROJECT_NUMBER = 4.0.8 | |||
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) | |||
# base path where the generated documentation will be put. | |||
@@ -4,9 +4,12 @@ Many thanks to the following people for providing bug fixes and improvements: | |||
<UL> | |||
<LI>Anders Ervik</LI> | |||
<LI>Robin Davies (Windows DS and ASIO)</LI> | |||
<LI>Antoine Lefebvre</LI> | |||
<LI>Dominic Mazzoni</LI> | |||
<LI>Tristan Matthews</LI> | |||
<LI>Ryan Williams (Windows non-MS compiler ASIO support)</LI> | |||
<LI>Ed Wildgoose (Linux ALSA and Jack)</LI> | |||
<LI>Dominic Mazzoni</LI> | |||
</UL> | |||
The RtAudio API incorporates many of the concepts developed in the <A href="http://www.portaudio.com/">PortAudio</A> project by Phil Burk and Ross Bencina. Early development also incorporated ideas from Bill Schottstaedt's <A href="http://www-ccrma.stanford.edu/software/snd/sndlib/">sndlib</A>. The CCRMA <A href="http://www-ccrma.stanford.edu/groups/soundwire/">SoundWire group</A> provided valuable feedback during the API proposal stages. | |||
@@ -1,7 +1,7 @@ | |||
/*! \page license License | |||
RtAudio: a set of realtime audio i/o C++ classes<BR> | |||
Copyright (c) 2001-2010 Gary P. Scavone | |||
Copyright (c) 2001-2011 Gary P. Scavone | |||
Permission is hereby granted, free of charge, to any person | |||
obtaining a copy of this software and associated documentation files | |||
@@ -32,7 +32,7 @@ Devices are now re-enumerated every time the RtAudio::getDeviceCount(), RtAudio: | |||
\section download Download | |||
Latest Release (4 February 2010): <A href="http://www.music.mcgill.ca/~gary/rtaudio/release/rtaudio-4.0.7.tar.gz">Version 4.0.7</A> | |||
Latest Release (12 April 2011): <A href="http://www.music.mcgill.ca/~gary/rtaudio/release/rtaudio-4.0.8.tar.gz">Version 4.0.8</A> | |||
\section documentation Documentation Links | |||
@@ -2,9 +2,16 @@ RtAudio - a set of C++ classes that provide a common API for realtime audio inpu | |||
By Gary P. Scavone, 2001-2011. | |||
v4.0.8: (?? February 2011) | |||
- fix for MinGW4 problem enumerating and setting sample rates | |||
v4.0.8: (12 April 2011) | |||
- fix for MinGW4 problem enumerating and setting sample rates (iasiothiscallresolver, Dmitry Kostjuchenko) | |||
- fix for OS-X problem handling device names in some languages (CFString conversion, Vincent Bénony) | |||
- small change to OS-X mutex lock location to avoid lockups | |||
- correction to documentation regarding 24-bit data (should be lower 3 bytes, not upper 3 bytes) | |||
- bug fix for error handling of warnings (Antoine Lefebvre) | |||
- added option to use the ALSA "default" device (Tristan Matthews) | |||
- removed use of mutexes in Windows | |||
- fix for ASIO4ALL behavior when stopping/closing streams (Antoine Lefebvre) | |||
- included python binding in "contrib" directory (beta, Antoine Lefebvre) | |||
v4.0.7: (4 February 2010) | |||
- revised Windows DS code and device enumeration to speed up device queries | |||
@@ -1,6 +1,6 @@ | |||
RtAudio - a set of C++ classes which provide a common API for realtime audio input/output across Linux (native ALSA, JACK, and OSS), Macintosh OS X (CoreAudio and JACK), and Windows (DirectSound and ASIO) operating systems. | |||
By Gary P. Scavone, 2001-2010. | |||
By Gary P. Scavone, 2001-2011. | |||
To configure and compile (on Unix systems and MinGW): | |||
@@ -9,7 +9,9 @@ To configure and compile (on Unix systems and MinGW): | |||
./configure | |||
3. From within the "tests" directory, type "make". | |||
3. Typing "make" will compile static and shared libraries. | |||
4. From within the "tests" directory, type "make" to compile the example programs. | |||
A few options can be passed to configure, including: | |||
@@ -29,6 +31,6 @@ If you wish to use a different compiler than that selected by configure, specify | |||
For Windows Users: | |||
RtAudio compiles with the MinGW compiler, though there appears to be a problem with ASIO support using gcc 4.4 (the compile is fine but with my RME HDSP 9632 driver, the functions to set and query the supported sample rates do not work). | |||
RtAudio compiles with the MinGW compiler or MS Visual Studio. | |||
Visual C++ 6.0 project files are included for the test programs in the /tests/Windows/ directory. These projects compile API support for both ASIO and DirectSound. Version 4.0 of RtAudio was tested with the .net compiler and it will not compile in Visual C++ 6.0 because of its non-conformance to modern C++ standards. |
@@ -1,6 +1,6 @@ | |||
RtAudio - a set of C++ classes that provide a common API for realtime audio input/output across Linux (native ALSA, JACK, and OSS), Macintosh OS X (CoreAudio and JACK), and Windows (DirectSound and ASIO) operating systems. | |||
By Gary P. Scavone, 2001-2010. | |||
By Gary P. Scavone, 2001-2011. | |||
This distribution of RtAudio contains the following: | |||
@@ -34,7 +34,7 @@ LEGAL AND ETHICAL: | |||
The RtAudio license is similar to the MIT License. | |||
RtAudio: a set of realtime audio i/o C++ classes | |||
Copyright (c) 2001-2010 Gary P. Scavone | |||
Copyright (c) 2001-2011 Gary P. Scavone | |||
Permission is hereby granted, free of charge, to any person | |||
obtaining a copy of this software and associated documentation files | |||
@@ -1,7 +1,7 @@ | |||
### Do not edit -- Generated by 'configure --with-whatever' from Makefile.in | |||
### RtAudio tests Makefile - for various flavors of unix and MinGW | |||
PROGRAMS = audioprobe playsaw playraw record duplex testall | |||
PROGRAMS = audioprobe playsaw playraw record duplex testall teststops | |||
RM = /bin/rm | |||
SRC_PATH = .. | |||
INCLUDE = .. | |||
@@ -42,6 +42,9 @@ duplex : duplex.cpp $(OBJECTS) | |||
testall : testall.cpp $(OBJECTS) | |||
$(CC) $(CFLAGS) $(DEFS) -o testall testall.cpp $(OBJECT_PATH)/*.o $(LIBRARY) | |||
teststops : teststops.cpp $(OBJECTS) | |||
$(CC) $(CFLAGS) $(DEFS) -o teststops teststops.cpp $(OBJECT_PATH)/*.o $(LIBRARY) | |||
clean : | |||
$(RM) -f $(OBJECT_PATH)/*.o | |||
$(RM) -f $(PROGRAMS) | |||
@@ -75,6 +75,18 @@ Package=<4> | |||
############################################################################### | |||
Project: "teststops"=.\teststops.dsp - Package Owner=<4> | |||
Package=<5> | |||
{{{ | |||
}}} | |||
Package=<4> | |||
{{{ | |||
}}} | |||
############################################################################### | |||
Global: | |||
Package=<5> | |||
@@ -0,0 +1,162 @@ | |||
# Microsoft Developer Studio Project File - Name="teststops" - Package Owner=<4> | |||
# Microsoft Developer Studio Generated Build File, Format Version 6.00 | |||
# ** DO NOT EDIT ** | |||
# TARGTYPE "Win32 (x86) Console Application" 0x0103 | |||
CFG=teststops - Win32 Debug | |||
!MESSAGE This is not a valid makefile. To build this project using NMAKE, | |||
!MESSAGE use the Export Makefile command and run | |||
!MESSAGE | |||
!MESSAGE NMAKE /f "teststops.mak". | |||
!MESSAGE | |||
!MESSAGE You can specify a configuration when running NMAKE | |||
!MESSAGE by defining the macro CFG on the command line. For example: | |||
!MESSAGE | |||
!MESSAGE NMAKE /f "teststops.mak" CFG="teststops - Win32 Debug" | |||
!MESSAGE | |||
!MESSAGE Possible choices for configuration are: | |||
!MESSAGE | |||
!MESSAGE "teststops - Win32 Release" (based on "Win32 (x86) Console Application") | |||
!MESSAGE "teststops - Win32 Debug" (based on "Win32 (x86) Console Application") | |||
!MESSAGE | |||
# Begin Project | |||
# PROP AllowPerConfigDependencies 0 | |||
# PROP Scc_ProjName "" | |||
# PROP Scc_LocalPath "" | |||
CPP=cl.exe | |||
RSC=rc.exe | |||
!IF "$(CFG)" == "teststops - Win32 Release" | |||
# PROP BASE Use_MFC 0 | |||
# PROP BASE Use_Debug_Libraries 0 | |||
# PROP BASE Output_Dir "teststops___Win32_Release" | |||
# PROP BASE Intermediate_Dir "teststops___Win32_Release" | |||
# PROP BASE Target_Dir "" | |||
# PROP Use_MFC 0 | |||
# PROP Use_Debug_Libraries 0 | |||
# PROP Output_Dir "" | |||
# PROP Intermediate_Dir "Release" | |||
# PROP Ignore_Export_Lib 0 | |||
# PROP Target_Dir "" | |||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c | |||
# ADD CPP /nologo /MT /W3 /GX /O2 /I "../../" /I "../../include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_ASIO__" /D "__WINDOWS_DS__" /YX /FD /c | |||
# ADD BASE RSC /l 0x409 /d "NDEBUG" | |||
# ADD RSC /l 0x409 /d "NDEBUG" | |||
BSC32=bscmake.exe | |||
# ADD BASE BSC32 /nologo | |||
# ADD BSC32 /nologo | |||
LINK32=link.exe | |||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 | |||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib dsound.lib /nologo /subsystem:console /machine:I386 | |||
!ELSEIF "$(CFG)" == "teststops - Win32 Debug" | |||
# PROP BASE Use_MFC 0 | |||
# PROP BASE Use_Debug_Libraries 1 | |||
# PROP BASE Output_Dir "teststops___Win32_Debug" | |||
# PROP BASE Intermediate_Dir "teststops___Win32_Debug" | |||
# PROP BASE Target_Dir "" | |||
# PROP Use_MFC 0 | |||
# PROP Use_Debug_Libraries 1 | |||
# PROP Output_Dir "" | |||
# PROP Intermediate_Dir "Debug" | |||
# PROP Ignore_Export_Lib 0 | |||
# PROP Target_Dir "" | |||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c | |||
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../../" /I "../../include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_ASIO__" /D "__WINDOWS_DS__" /YX /FD /GZ /c | |||
# ADD BASE RSC /l 0x409 /d "_DEBUG" | |||
# ADD RSC /l 0x409 /d "_DEBUG" | |||
BSC32=bscmake.exe | |||
# ADD BASE BSC32 /nologo | |||
# ADD BSC32 /nologo | |||
LINK32=link.exe | |||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept | |||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib dsound.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept | |||
!ENDIF | |||
# Begin Target | |||
# Name "teststops - Win32 Release" | |||
# Name "teststops - Win32 Debug" | |||
# Begin Group "Source Files" | |||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" | |||
# Begin Source File | |||
SOURCE=..\..\include\asio.cpp | |||
# End Source File | |||
# Begin Source File | |||
SOURCE=..\..\include\asiodrivers.cpp | |||
# End Source File | |||
# Begin Source File | |||
SOURCE=..\..\include\asiolist.cpp | |||
# End Source File | |||
# Begin Source File | |||
SOURCE=..\..\include\iasiothiscallresolver.cpp | |||
# End Source File | |||
# Begin Source File | |||
SOURCE=..\..\RtAudio.cpp | |||
# End Source File | |||
# Begin Source File | |||
SOURCE=..\teststops.cpp | |||
# End Source File | |||
# End Group | |||
# Begin Group "Header Files" | |||
# PROP Default_Filter "h;hpp;hxx;hm;inl" | |||
# Begin Source File | |||
SOURCE=..\..\include\asio.h | |||
# End Source File | |||
# Begin Source File | |||
SOURCE=..\..\include\asiodrivers.h | |||
# End Source File | |||
# Begin Source File | |||
SOURCE=..\..\include\asiodrvr.h | |||
# End Source File | |||
# Begin Source File | |||
SOURCE=..\..\include\asiolist.h | |||
# End Source File | |||
# Begin Source File | |||
SOURCE=..\..\include\asiosys.h | |||
# End Source File | |||
# Begin Source File | |||
SOURCE=..\..\include\ginclude.h | |||
# End Source File | |||
# Begin Source File | |||
SOURCE=..\..\include\iasiodrv.h | |||
# End Source File | |||
# Begin Source File | |||
SOURCE=..\..\include\iasiothiscallresolver.h | |||
# End Source File | |||
# Begin Source File | |||
SOURCE=..\..\RtAudio.h | |||
# End Source File | |||
# Begin Source File | |||
SOURCE=..\..\RtError.h | |||
# End Source File | |||
# End Group | |||
# Begin Group "Resource Files" | |||
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" | |||
# End Group | |||
# End Target | |||
# End Project |
@@ -40,22 +40,36 @@ typedef double MY_TYPE; | |||
#define SCALE 1.0 | |||
*/ | |||
// Platform-dependent sleep routines. | |||
#if defined( __WINDOWS_ASIO__ ) || defined( __WINDOWS_DS__ ) | |||
#include <windows.h> | |||
#define SLEEP( milliseconds ) Sleep( (DWORD) milliseconds ) | |||
#else // Unix variants | |||
#include <unistd.h> | |||
#define SLEEP( milliseconds ) usleep( (unsigned long) (milliseconds * 1000.0) ) | |||
#endif | |||
#define BASE_RATE 0.005 | |||
#define TIME 1.0 | |||
void usage( void ) { | |||
// Error function in case of incorrect command-line | |||
// argument specifications | |||
std::cout << "\nuseage: playsaw N fs <device> <channelOffset>\n"; | |||
std::cout << "\nuseage: playsaw N fs <device> <channelOffset> <time>\n"; | |||
std::cout << " where N = number of channels,\n"; | |||
std::cout << " fs = the sample rate,\n"; | |||
std::cout << " device = optional device to use (default = 0),\n"; | |||
std::cout << " and channelOffset = an optional channel offset on the device (default = 0).\n\n"; | |||
std::cout << " channelOffset = an optional channel offset on the device (default = 0),\n"; | |||
std::cout << " and time = an optional time duration in seconds (default = no limit).\n\n"; | |||
exit( 0 ); | |||
} | |||
unsigned int channels; | |||
RtAudio::StreamOptions options; | |||
unsigned int frameCounter = 0; | |||
bool checkCount = false; | |||
unsigned int nFrames = 0; | |||
const unsigned int callbackReturnValue = 1; | |||
//#define USE_INTERLEAVED | |||
#if defined( USE_INTERLEAVED ) | |||
@@ -80,6 +94,8 @@ int saw( void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames, | |||
} | |||
} | |||
frameCounter += nBufferFrames; | |||
if ( checkCount && ( frameCounter >= nFrames ) ) return callbackReturnValue; | |||
return 0; | |||
} | |||
@@ -106,6 +122,8 @@ int saw( void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames, | |||
} | |||
} | |||
frameCounter += nBufferFrames; | |||
if ( checkCount && ( frameCounter >= nFrames ) ) return callbackReturnValue; | |||
return 0; | |||
} | |||
#endif | |||
@@ -115,7 +133,7 @@ int main( int argc, char *argv[] ) | |||
unsigned int bufferFrames, fs, device = 0, offset = 0; | |||
// minimal command-line checking | |||
if (argc < 3 || argc > 5 ) usage(); | |||
if (argc < 3 || argc > 6 ) usage(); | |||
RtAudio dac; | |||
if ( dac.getDeviceCount() < 1 ) { | |||
@@ -129,6 +147,9 @@ int main( int argc, char *argv[] ) | |||
device = (unsigned int) atoi( argv[3] ); | |||
if ( argc > 4 ) | |||
offset = (unsigned int) atoi( argv[4] ); | |||
if ( argc > 5 ) | |||
nFrames = (unsigned int) (fs * atof( argv[5] )); | |||
if ( nFrames > 0 ) checkCount = true; | |||
double *data = (double *) calloc( channels, sizeof( double ) ); | |||
@@ -156,17 +177,22 @@ int main( int argc, char *argv[] ) | |||
goto cleanup; | |||
} | |||
char input; | |||
//std::cout << "Stream latency = " << dac.getStreamLatency() << "\n" << std::endl; | |||
std::cout << "\nPlaying ... press <enter> to quit (buffer size = " << bufferFrames << ").\n"; | |||
std::cin.get( input ); | |||
try { | |||
// Stop the stream | |||
dac.stopStream(); | |||
if ( checkCount ) { | |||
while ( dac.isStreamRunning() == true ) SLEEP( 100 ); | |||
} | |||
catch ( RtError& e ) { | |||
e.printMessage(); | |||
else { | |||
char input; | |||
//std::cout << "Stream latency = " << dac.getStreamLatency() << "\n" << std::endl; | |||
std::cout << "\nPlaying ... press <enter> to quit (buffer size = " << bufferFrames << ").\n"; | |||
std::cin.get( input ); | |||
try { | |||
// Stop the stream | |||
dac.stopStream(); | |||
} | |||
catch ( RtError& e ) { | |||
e.printMessage(); | |||
} | |||
} | |||
cleanup: | |||
@@ -86,7 +86,7 @@ int inout( void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames, | |||
// a simple buffer copy operation here. | |||
if ( status ) std::cout << "Stream over/underflow detected." << std::endl; | |||
unsigned long *bytes = (unsigned long *) data; | |||
unsigned int *bytes = (unsigned int *) data; | |||
memcpy( outputBuffer, inputBuffer, *bytes ); | |||
return 0; | |||
} | |||
@@ -0,0 +1,266 @@ | |||
/******************************************/ | |||
/* | |||
teststop.cpp | |||
by Gary P. Scavone, 2011 | |||
This program starts and stops an RtAudio | |||
stream many times in succession and in | |||
different ways to to test its functionality. | |||
*/ | |||
/******************************************/ | |||
#include "RtAudio.h" | |||
#include <iostream> | |||
#include <cstdlib> | |||
#include <cstring> | |||
#include <cstdio> | |||
#define PULSE_RATE 0.01 // seconds | |||
#define RUNTIME 0.4 // seconds | |||
#define PAUSETIME 0.1 // seconds | |||
#define REPETITIONS 10 | |||
// Platform-dependent sleep routines. | |||
#if defined( __WINDOWS_ASIO__ ) || defined( __WINDOWS_DS__ ) | |||
#include <windows.h> | |||
#define SLEEP( milliseconds ) Sleep( (DWORD) milliseconds ) | |||
#else // Unix variants | |||
#include <unistd.h> | |||
#define SLEEP( milliseconds ) usleep( (unsigned long) (milliseconds * 1000.0) ) | |||
#endif | |||
void usage( void ) { | |||
// Error function in case of incorrect command-line | |||
// argument specifications | |||
std::cout << "\nuseage: teststops N fs <iDevice> <oDevice> <iChannelOffset> <oChannelOffset>\n"; | |||
std::cout << " where N = number of channels,\n"; | |||
std::cout << " fs = the sample rate,\n"; | |||
std::cout << " iDevice = optional input device to use (default = 0),\n"; | |||
std::cout << " oDevice = optional output device to use (default = 0),\n"; | |||
std::cout << " iChannelOffset = an optional input channel offset (default = 0),\n"; | |||
std::cout << " and oChannelOffset = optional output channel offset (default = 0).\n\n"; | |||
exit( 0 ); | |||
} | |||
struct MyData { | |||
unsigned int channels; | |||
unsigned int pulseCount; | |||
unsigned int frameCounter; | |||
unsigned int nFrames; | |||
unsigned int returnValue; | |||
}; | |||
// Interleaved buffers | |||
int pulse( void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames, | |||
double streamTime, RtAudioStreamStatus status, void *mydata ) | |||
{ | |||
// Write out a pulse signal and ignore the input buffer. | |||
unsigned int i, j; | |||
float sample; | |||
float *buffer = (float *) outputBuffer; | |||
MyData *data = (MyData *) mydata; | |||
if ( status ) std::cout << "Stream over/underflow detected!" << std::endl; | |||
for ( i=0; i<nBufferFrames; i++ ) { | |||
if ( data->frameCounter % data->pulseCount == 0 ) sample = 0.9; | |||
else sample = 0.0; | |||
for ( j=0; j<data->channels; j++ ) | |||
*buffer++ = sample; | |||
data->frameCounter++; | |||
} | |||
if ( data->frameCounter >= data->nFrames ) | |||
return data->returnValue; | |||
else | |||
return 0; | |||
} | |||
int main( int argc, char *argv[] ) | |||
{ | |||
unsigned int bufferFrames, fs, oDevice = 0, iDevice = 0, iOffset = 0, oOffset = 0; | |||
unsigned int runtime, pausetime; | |||
char input; | |||
// minimal command-line checking | |||
if (argc < 3 || argc > 7 ) usage(); | |||
RtAudio *adc = new RtAudio(); | |||
if ( adc->getDeviceCount() < 1 ) { | |||
std::cout << "\nNo audio devices found!\n"; | |||
exit( 1 ); | |||
} | |||
MyData mydata; | |||
mydata.channels = (unsigned int) atoi( argv[1] ); | |||
fs = (unsigned int) atoi( argv[2] ); | |||
if ( argc > 3 ) | |||
iDevice = (unsigned int) atoi( argv[3] ); | |||
if ( argc > 4 ) | |||
oDevice = (unsigned int) atoi(argv[4]); | |||
if ( argc > 5 ) | |||
iOffset = (unsigned int) atoi(argv[5]); | |||
if ( argc > 6 ) | |||
oOffset = (unsigned int) atoi(argv[6]); | |||
// Let RtAudio print messages to stderr. | |||
adc->showWarnings( true ); | |||
runtime = RUNTIME * 1000; | |||
pausetime = PAUSETIME * 1000; | |||
// Set our stream parameters for a duplex stream. | |||
bufferFrames = 256; | |||
RtAudio::StreamParameters oParams, iParams; | |||
oParams.deviceId = oDevice; | |||
oParams.nChannels = mydata.channels; | |||
oParams.firstChannel = oOffset; | |||
iParams.deviceId = iDevice; | |||
iParams.nChannels = mydata.channels; | |||
iParams.firstChannel = iOffset; | |||
// First, test external stopStream() calls. | |||
mydata.pulseCount = PULSE_RATE * fs; | |||
mydata.nFrames = 50 * fs; | |||
mydata.returnValue = 0; | |||
try { | |||
adc->openStream( &oParams, &iParams, RTAUDIO_SINT32, fs, &bufferFrames, &pulse, (void *)&mydata ); | |||
std::cout << "Press <enter> to start test.\n"; | |||
std::cin.get( input ); | |||
for (int i=0; i<REPETITIONS; i++ ) { | |||
mydata.frameCounter = 0; | |||
adc->startStream(); | |||
std::cout << "Stream started ... "; | |||
SLEEP( runtime ); | |||
adc->stopStream(); | |||
std::cout << "stream externally stopped.\n"; | |||
SLEEP( pausetime ); | |||
} | |||
} | |||
catch ( RtError& e ) { | |||
e.printMessage(); | |||
goto cleanup; | |||
} | |||
adc->closeStream(); | |||
// Next, test internal stopStream() calls. | |||
mydata.nFrames = (unsigned int) (RUNTIME * fs); | |||
mydata.returnValue = 1; | |||
try { | |||
adc->openStream( &oParams, &iParams, RTAUDIO_SINT32, fs, &bufferFrames, &pulse, (void *)&mydata ); | |||
std::cin.clear(); | |||
fflush(stdin); | |||
std::cout << "\nPress <enter> to continue test.\n"; | |||
std::cin.get( input ); | |||
for (int i=0; i<REPETITIONS; i++ ) { | |||
mydata.frameCounter = 0; | |||
adc->startStream(); | |||
std::cout << "Stream started ... "; | |||
while ( adc->isStreamRunning() ) SLEEP( 5 ); | |||
std::cout << "stream stopped via callback return value = 1.\n"; | |||
SLEEP( pausetime ); | |||
} | |||
} | |||
catch ( RtError& e ) { | |||
e.printMessage(); | |||
goto cleanup; | |||
} | |||
adc->closeStream(); | |||
// Test internal abortStream() calls. | |||
mydata.returnValue = 2; | |||
try { | |||
adc->openStream( &oParams, &iParams, RTAUDIO_SINT32, fs, &bufferFrames, &pulse, (void *)&mydata ); | |||
std::cin.clear(); | |||
fflush(stdin); | |||
std::cout << "\nPress <enter> to continue test.\n"; | |||
std::cin.get( input ); | |||
for (int i=0; i<REPETITIONS; i++ ) { | |||
mydata.frameCounter = 0; | |||
adc->startStream(); | |||
std::cout << "Stream started ... "; | |||
while ( adc->isStreamRunning() ) SLEEP( 5 ); | |||
std::cout << "stream aborted via callback return value = 2.\n"; | |||
SLEEP( pausetime ); | |||
} | |||
} | |||
catch ( RtError& e ) { | |||
e.printMessage(); | |||
goto cleanup; | |||
} | |||
adc->closeStream(); | |||
// Test consecutive stream re-opening. | |||
mydata.returnValue = 0; | |||
mydata.nFrames = 50 * fs; | |||
try { | |||
std::cin.clear(); | |||
fflush(stdin); | |||
std::cout << "\nPress <enter> to continue test.\n"; | |||
std::cin.get( input ); | |||
for (int i=0; i<REPETITIONS; i++ ) { | |||
adc->openStream( &oParams, &iParams, RTAUDIO_SINT32, fs, &bufferFrames, &pulse, (void *)&mydata ); | |||
mydata.frameCounter = 0; | |||
adc->startStream(); | |||
std::cout << "New stream started ... "; | |||
SLEEP( runtime ); | |||
adc->stopStream(); | |||
adc->closeStream(); | |||
std::cout << "stream stopped externally and closed.\n"; | |||
SLEEP( pausetime ); | |||
} | |||
} | |||
catch ( RtError& e ) { | |||
e.printMessage(); | |||
goto cleanup; | |||
} | |||
delete adc; | |||
adc = 0; | |||
// Test consecutive RtAudio creating and deletion. | |||
try { | |||
std::cin.clear(); | |||
fflush(stdin); | |||
std::cout << "\nPress <enter> to continue test.\n"; | |||
std::cin.get( input ); | |||
for (int i=0; i<REPETITIONS; i++ ) { | |||
adc = new RtAudio(); | |||
adc->openStream( &oParams, &iParams, RTAUDIO_SINT32, fs, &bufferFrames, &pulse, (void *)&mydata ); | |||
mydata.frameCounter = 0; | |||
adc->startStream(); | |||
std::cout << "New instance and stream started ... "; | |||
SLEEP( runtime ); | |||
adc->stopStream(); | |||
adc->closeStream(); | |||
delete adc; | |||
adc = 0; | |||
std::cout << "stream stopped and instance deleted.\n"; | |||
SLEEP( pausetime ); | |||
} | |||
} | |||
catch ( RtError& e ) { | |||
e.printMessage(); | |||
goto cleanup; | |||
} | |||
cleanup: | |||
if ( adc && adc->isStreamOpen() ) adc->closeStream(); | |||
if ( adc ) delete adc; | |||
return 0; | |||
} |