Browse Source

Updates for release 4.0.8, including new python binding, new teststops.cpp program, ALSA "default" flag, and various changes to stopping behavior (GS).

tags/4.0.8
Gary Scavone Stephen Sinclair 14 years ago
parent
commit
6faf4336eb
19 changed files with 9271 additions and 7944 deletions
  1. +7960
    -7915
      RtAudio.cpp
  2. +13
    -2
      RtAudio.h
  3. +70
    -0
      contrib/python/pyrtaudio/PyRtAudioTest.py
  4. +57
    -0
      contrib/python/pyrtaudio/readme
  5. +605
    -0
      contrib/python/pyrtaudio/rtaudiomodule.cpp
  6. +58
    -0
      contrib/python/pyrtaudio/setup.py
  7. +1
    -1
      doc/doxygen/Doxyfile
  8. +4
    -1
      doc/doxygen/acknowledge.txt
  9. +1
    -1
      doc/doxygen/license.txt
  10. +1
    -1
      doc/doxygen/tutorial.txt
  11. +10
    -3
      doc/release.txt
  12. +5
    -3
      install
  13. +2
    -2
      readme
  14. +4
    -1
      tests/Makefile.in
  15. +12
    -0
      tests/Windows/rtaudio.dsw
  16. +162
    -0
      tests/Windows/teststops.dsp
  17. +39
    -13
      tests/playsaw.cpp
  18. +1
    -1
      tests/testall.cpp
  19. +266
    -0
      tests/teststops.cpp

+ 7960
- 7915
RtAudio.cpp
File diff suppressed because it is too large
View File


+ 13
- 2
RtAudio.h View File

@@ -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). */


+ 70
- 0
contrib/python/pyrtaudio/PyRtAudioTest.py View File

@@ -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()

+ 57
- 0
contrib/python/pyrtaudio/readme View File

@@ -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.

+ 605
- 0
contrib/python/pyrtaudio/rtaudiomodule.cpp View File

@@ -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);
}
}

+ 58
- 0
contrib/python/pyrtaudio/setup.py View File

@@ -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])


+ 1
- 1
doc/doxygen/Doxyfile View File

@@ -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
- 1
doc/doxygen/acknowledge.txt View File

@@ -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
- 1
doc/doxygen/license.txt View File

@@ -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


+ 1
- 1
doc/doxygen/tutorial.txt View File

@@ -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



+ 10
- 3
doc/release.txt View File

@@ -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


+ 5
- 3
install View File

@@ -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.

+ 2
- 2
readme View File

@@ -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


+ 4
- 1
tests/Makefile.in View File

@@ -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)


+ 12
- 0
tests/Windows/rtaudio.dsw View File

@@ -75,6 +75,18 @@ Package=<4>
###############################################################################
Project: "teststops"=.\teststops.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Global:
Package=<5>


+ 162
- 0
tests/Windows/teststops.dsp View File

@@ -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

+ 39
- 13
tests/playsaw.cpp View File

@@ -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:


+ 1
- 1
tests/testall.cpp View File

@@ -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;
}


+ 266
- 0
tests/teststops.cpp View File

@@ -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;
}

Loading…
Cancel
Save