summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Sinclair <sinclair@music.mcgill.ca>2013-10-11 01:56:29 +0200
committerStephen Sinclair <sinclair@music.mcgill.ca>2013-10-11 01:56:29 +0200
commitacd5fefddbc6629095bcfae56edb87af8d40e4db (patch)
treed09a573bce0a46e95c2da8c4336ecbfb6e6f67fa
parent504ebe4ba69765df5ca0da115690c29e52a44c6d (diff)
parent1022a7876a6ef1980ad5518340df177814783c7f (diff)
Merge 4.0.5 into releases
-rw-r--r--Makefile.in6
-rw-r--r--RtAudio.cpp959
-rw-r--r--RtAudio.h47
-rw-r--r--config/config.guess (renamed from config.guess)0
-rwxr-xr-xconfig/config.sub (renamed from config.sub)0
-rwxr-xr-xconfig/install.sh (renamed from install.sh)0
-rw-r--r--configure.ac119
-rw-r--r--doc/doxygen/Doxyfile942
-rw-r--r--doc/doxygen/compiling.txt2
-rw-r--r--doc/doxygen/duplex.txt2
-rw-r--r--doc/doxygen/footer.html2
-rw-r--r--doc/doxygen/license.txt2
-rw-r--r--doc/doxygen/playback.txt1
-rw-r--r--doc/doxygen/recording.txt2
-rw-r--r--doc/doxygen/tutorial.txt2
-rw-r--r--doc/release.txt17
-rw-r--r--install2
-rw-r--r--readme6
-rw-r--r--rtaudio-config.in13
-rw-r--r--tests/Makefile.in13
-rw-r--r--tests/duplex.cpp2
-rw-r--r--tests/playraw.cpp6
-rw-r--r--tests/playsaw.cpp8
-rw-r--r--tests/record.cpp6
-rw-r--r--tests/testall.cpp32
25 files changed, 873 insertions, 1318 deletions
diff --git a/Makefile.in b/Makefile.in
index 23a444f..3230002 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -11,10 +11,8 @@ CC = @CXX@
AR = @AR@
RANLIB = @RANLIB@
-DEFS = @debug@
-DEFS += @audio_apis@
-CFLAGS = @CFLAGS@ -Iinclude
-CFLAGS += @warn@
+DEFS = @CPPFLAGS@
+CFLAGS = @CXXFLAGS@ -Iinclude
all : $(LIBRARY)
diff --git a/RtAudio.cpp b/RtAudio.cpp
index 8d15a34..cd427f3 100644
--- a/RtAudio.cpp
+++ b/RtAudio.cpp
@@ -4,13 +4,13 @@
RtAudio provides a common API (Application Programming Interface)
for realtime audio input/output across Linux (native ALSA, Jack,
- and OSS), SGI, Macintosh OS X (CoreAudio and Jack), and Windows
+ and OSS), Macintosh OS X (CoreAudio and Jack), and Windows
(DirectSound and ASIO) operating systems.
RtAudio WWW site: http://www.music.mcgill.ca/~gary/rtaudio/
RtAudio: realtime audio i/o C++ classes
- Copyright (c) 2001-2008 Gary P. Scavone
+ Copyright (c) 2001-2009 Gary P. Scavone
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files
@@ -38,10 +38,13 @@
*/
/************************************************************************/
-// RtAudio: Version 4.0.4
+// RtAudio: Version 4.0.5
#include "RtAudio.h"
#include <iostream>
+#include <cstdlib>
+#include <cstring>
+#include <limits.h>
// Static variable definitions.
const unsigned int RtApi::MAX_SAMPLE_RATES = 14;
@@ -359,6 +362,13 @@ double RtApi :: getStreamTime( void )
#endif
}
+unsigned int RtApi :: getStreamSampleRate( void )
+{
+ verifyStream();
+
+ return stream_.sampleRate;
+}
+
// *************************************************** //
//
@@ -393,7 +403,9 @@ double RtApi :: getStreamTime( void )
// implementation.
struct CoreHandle {
AudioDeviceID id[2]; // device ids
- UInt32 iStream[2]; // device stream index (first for mono mode)
+ AudioDeviceIOProcID procId[2];
+ UInt32 iStream[2]; // device stream index (or first if using multiple)
+ UInt32 nStreams[2]; // number of streams to use
bool xrun[2];
char *deviceBuffer;
pthread_cond_t condition;
@@ -401,7 +413,7 @@ struct CoreHandle {
bool internalDrain; // Indicates if stop is initiated from callback or not.
CoreHandle()
- :deviceBuffer(0), drainCounter(0), internalDrain(false) { id[0] = 0; id[1] = 0; xrun[0] = false; xrun[1] = false; }
+ :deviceBuffer(0), drainCounter(0), internalDrain(false) { nStreams[0] = 1; nStreams[1] = 1; id[0] = 0; id[1] = 0; xrun[0] = false; xrun[1] = false; }
};
RtApiCore :: RtApiCore()
@@ -805,70 +817,72 @@ bool RtApiCore :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
return FAILURE;
}
- // Search for a stream that contains the desired number of
+ // Search for one or more streams that contain the desired number of
// channels. CoreAudio devices can have an arbitrary number of
// streams and each stream can have an arbitrary number of channels.
// For each stream, a single buffer of interleaved samples is
- // provided. RtAudio currently only supports the use of one stream
- // of interleaved data or multiple consecutive single-channel
- // streams. Thus, our search below is limited to these two
- // contexts.
- unsigned int streamChannels = 0, nStreams = 0;
- UInt32 iChannel = 0, iStream = 0;
- unsigned int offsetCounter = firstChannel;
- stream_.deviceInterleaved[mode] = true;
- nStreams = bufferList->mNumberBuffers;
+ // provided. RtAudio prefers the use of one stream of interleaved
+ // data or multiple consecutive single-channel streams. However, we
+ // now support multiple consecutive multi-channel streams of
+ // interleaved data as well.
+ UInt32 iStream, offsetCounter = firstChannel;
+ UInt32 nStreams = bufferList->mNumberBuffers;
+ bool monoMode = false;
bool foundStream = false;
+ // First check that the device supports the requested number of
+ // channels.
+ UInt32 deviceChannels = 0;
+ for ( iStream=0; iStream<nStreams; iStream++ )
+ deviceChannels += bufferList->mBuffers[iStream].mNumberChannels;
+
+ if ( deviceChannels < ( channels + firstChannel ) ) {
+ free( bufferList );
+ errorStream_ << "RtApiCore::probeDeviceOpen: the device (" << device << ") does not support the requested channel count.";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ // Look for a single stream meeting our needs.
+ UInt32 firstStream, streamCount = 1, streamChannels = 0, channelOffset = 0;
for ( iStream=0; iStream<nStreams; iStream++ ) {
streamChannels = bufferList->mBuffers[iStream].mNumberChannels;
if ( streamChannels >= channels + offsetCounter ) {
- iChannel += offsetCounter;
+ firstStream = iStream;
+ channelOffset = offsetCounter;
foundStream = true;
break;
}
if ( streamChannels > offsetCounter ) break;
offsetCounter -= streamChannels;
- iChannel += streamChannels;
}
- // If we didn't find a single stream above, see if we can meet
- // the channel specification in mono mode (i.e. using separate
- // non-interleaved buffers). This can only work if there are N
- // consecutive one-channel streams, where N is the number of
- // desired channels (+ channel offset).
+ // If we didn't find a single stream above, then we should be able
+ // to meet the channel specification with multiple streams.
if ( foundStream == false ) {
- unsigned int counter = 0;
+ monoMode = true;
offsetCounter = firstChannel;
- iChannel = 0;
for ( iStream=0; iStream<nStreams; iStream++ ) {
streamChannels = bufferList->mBuffers[iStream].mNumberChannels;
- if ( offsetCounter ) {
- if ( streamChannels > offsetCounter ) break;
- offsetCounter -= streamChannels;
- }
- else if ( streamChannels == 1 )
- counter++;
- else
- counter = 0;
- if ( counter == channels ) {
- iStream -= channels - 1;
- iChannel -= channels - 1;
- stream_.deviceInterleaved[mode] = false;
- foundStream = true;
- break;
- }
- iChannel += streamChannels;
+ if ( streamChannels > offsetCounter ) break;
+ offsetCounter -= streamChannels;
}
- }
- free( bufferList );
- if ( foundStream == false ) {
- errorStream_ << "RtApiCore::probeDeviceOpen: unable to find OS-X stream on device (" << device << ") for requested channels.";
- errorText_ = errorStream_.str();
- return FAILURE;
+ firstStream = iStream;
+ channelOffset = offsetCounter;
+ Int32 channelCounter = channels + offsetCounter - streamChannels;
+
+ if ( streamChannels > 1 ) monoMode = false;
+ while ( channelCounter > 0 ) {
+ streamChannels = bufferList->mBuffers[++iStream].mNumberChannels;
+ if ( streamChannels > 1 ) monoMode = false;
+ channelCounter -= streamChannels;
+ streamCount++;
+ }
}
+ free( bufferList );
+
// Determine the buffer size.
AudioValueRange bufferRange;
dataSize = sizeof( AudioValueRange );
@@ -885,8 +899,8 @@ bool RtApiCore :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
else if ( bufferRange.mMaximum < *bufferSize ) *bufferSize = (unsigned long) bufferRange.mMaximum;
if ( options && options->flags & RTAUDIO_MINIMIZE_LATENCY ) *bufferSize = (unsigned long) bufferRange.mMinimum;
- // Set the buffer size. For mono mode, I'm assuming we only need to
- // make this setting for the master channel.
+ // Set the buffer size. For multiple streams, I'm assuming we only
+ // need to make this setting for the master channel.
UInt32 theSize = (UInt32) *bufferSize;
dataSize = sizeof( UInt32 );
result = AudioDeviceSetProperty( id, NULL, 0, isInput,
@@ -911,8 +925,8 @@ bool RtApiCore :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
stream_.bufferSize = *bufferSize;
stream_.nBuffers = 1;
- // Get the stream ID(s) so we can set the stream format. In mono
- // mode, we'll have to do this for each stream (channel).
+ // Get the stream ID(s) so we can set the stream format. We'll have
+ // to do this for each stream.
AudioStreamID streamIDs[ nStreams ];
dataSize = nStreams * sizeof( AudioStreamID );
result = AudioDeviceGetProperty( id, 0, isInput,
@@ -928,13 +942,11 @@ bool RtApiCore :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
// device and change that if necessary.
AudioStreamBasicDescription description;
dataSize = sizeof( AudioStreamBasicDescription );
- if ( stream_.deviceInterleaved[mode] ) nStreams = 1;
- else nStreams = channels;
bool updateFormat;
- for ( unsigned int i=0; i<nStreams; i++ ) {
+ for ( UInt32 i=0; i<streamCount; i++ ) {
- result = AudioStreamGetProperty( streamIDs[iStream+i], 0,
+ result = AudioStreamGetProperty( streamIDs[firstStream+i], 0,
kAudioStreamPropertyVirtualFormat,
&dataSize, &description );
@@ -959,7 +971,7 @@ bool RtApiCore :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
}
if ( updateFormat ) {
- result = AudioStreamSetProperty( streamIDs[iStream+i], NULL, 0,
+ result = AudioStreamSetProperty( streamIDs[firstStream+i], NULL, 0,
kAudioStreamPropertyVirtualFormat,
dataSize, &description );
if ( result != noErr ) {
@@ -970,7 +982,7 @@ bool RtApiCore :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
}
// Now check the physical format.
- result = AudioStreamGetProperty( streamIDs[iStream+i], 0,
+ result = AudioStreamGetProperty( streamIDs[firstStream+i], 0,
kAudioStreamPropertyPhysicalFormat,
&dataSize, &description );
if ( result != noErr ) {
@@ -988,32 +1000,32 @@ bool RtApiCore :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
testDescription.mBitsPerChannel = 32;
formatFlags = description.mFormatFlags | kLinearPCMFormatFlagIsFloat & ~kLinearPCMFormatFlagIsSignedInteger;
testDescription.mFormatFlags = formatFlags;
- result = AudioStreamSetProperty( streamIDs[iStream+i], NULL, 0, kAudioStreamPropertyPhysicalFormat, dataSize, &testDescription );
+ result = AudioStreamSetProperty( streamIDs[firstStream+i], NULL, 0, kAudioStreamPropertyPhysicalFormat, dataSize, &testDescription );
if ( result == noErr ) continue;
testDescription = description;
testDescription.mBitsPerChannel = 32;
formatFlags = (description.mFormatFlags | kLinearPCMFormatFlagIsSignedInteger) & ~kLinearPCMFormatFlagIsFloat;
testDescription.mFormatFlags = formatFlags;
- result = AudioStreamSetProperty( streamIDs[iStream+i], NULL, 0, kAudioStreamPropertyPhysicalFormat, dataSize, &testDescription );
+ result = AudioStreamSetProperty( streamIDs[firstStream+i], NULL, 0, kAudioStreamPropertyPhysicalFormat, dataSize, &testDescription );
if ( result == noErr ) continue;
testDescription = description;
testDescription.mBitsPerChannel = 24;
testDescription.mFormatFlags = formatFlags;
- result = AudioStreamSetProperty( streamIDs[iStream+i], NULL, 0, kAudioStreamPropertyPhysicalFormat, dataSize, &testDescription );
+ result = AudioStreamSetProperty( streamIDs[firstStream+i], NULL, 0, kAudioStreamPropertyPhysicalFormat, dataSize, &testDescription );
if ( result == noErr ) continue;
testDescription = description;
testDescription.mBitsPerChannel = 16;
testDescription.mFormatFlags = formatFlags;
- result = AudioStreamSetProperty( streamIDs[iStream+i], NULL, 0, kAudioStreamPropertyPhysicalFormat, dataSize, &testDescription );
+ result = AudioStreamSetProperty( streamIDs[firstStream+i], NULL, 0, kAudioStreamPropertyPhysicalFormat, dataSize, &testDescription );
if ( result == noErr ) continue;
testDescription = description;
testDescription.mBitsPerChannel = 8;
testDescription.mFormatFlags = formatFlags;
- result = AudioStreamSetProperty( streamIDs[iStream+i], NULL, 0, kAudioStreamPropertyPhysicalFormat, dataSize, &testDescription );
+ result = AudioStreamSetProperty( streamIDs[firstStream+i], NULL, 0, kAudioStreamPropertyPhysicalFormat, dataSize, &testDescription );
if ( result != noErr ) {
errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting physical data format for device (" << device << ").";
errorText_ = errorStream_.str();
@@ -1026,14 +1038,12 @@ bool RtApiCore :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
// and the stream. First, attempt to get the device latency on the
// master channel or the first open channel. Errors that might
// occur here are not deemed critical.
+
+ // ***** CHECK THIS ***** //
UInt32 latency, channel = 0;
dataSize = sizeof( UInt32 );
AudioDevicePropertyID property = kAudioDevicePropertyLatency;
- for ( int i=0; i<2; i++ ) {
- if ( hasProperty( id, channel, isInput, property ) == true ) break;
- channel = iChannel + 1 + i;
- }
- if ( channel <= iChannel + 1 ) {
+ if ( hasProperty( id, channel, isInput, property ) == true ) {
result = AudioDeviceGetProperty( id, channel, isInput, property, &dataSize, &latency );
if ( result == kAudioHardwareNoError ) stream_.latency[ mode ] = latency;
else {
@@ -1043,9 +1053,9 @@ bool RtApiCore :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
}
}
- // Now try to get the stream latency. For "mono" mode, I assume the
- // latency is equal for all single-channel streams.
- result = AudioStreamGetProperty( streamIDs[iStream], 0, property, &dataSize, &latency );
+ // Now try to get the stream latency. For multiple streams, I assume the
+ // latency is equal for each.
+ result = AudioStreamGetProperty( streamIDs[firstStream], 0, property, &dataSize, &latency );
if ( result == kAudioHardwareNoError ) stream_.latency[ mode ] += latency;
else {
errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting stream latency for device (" << device << ").";
@@ -1063,14 +1073,16 @@ bool RtApiCore :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
stream_.userFormat = format;
stream_.deviceFormat[mode] = RTAUDIO_FLOAT32;
- if ( stream_.deviceInterleaved[mode] )
+ if ( streamCount == 1 )
stream_.nDeviceChannels[mode] = description.mChannelsPerFrame;
- else // mono mode
+ else // multiple streams
stream_.nDeviceChannels[mode] = channels;
stream_.nUserChannels[mode] = channels;
- stream_.channelOffset[mode] = iChannel; // offset within a CoreAudio stream
+ stream_.channelOffset[mode] = channelOffset; // offset within a CoreAudio stream
if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) stream_.userInterleaved = false;
else stream_.userInterleaved = true;
+ stream_.deviceInterleaved[mode] = true;
+ if ( monoMode == true ) stream_.deviceInterleaved[mode] = false;
// Set flags for buffer conversion.
stream_.doConvertBuffer[mode] = false;
@@ -1078,8 +1090,12 @@ bool RtApiCore :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
stream_.doConvertBuffer[mode] = true;
if ( stream_.nUserChannels[mode] < stream_.nDeviceChannels[mode] )
stream_.doConvertBuffer[mode] = true;
- if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] &&
- stream_.nUserChannels[mode] > 1 )
+ if ( streamCount == 1 ) {
+ if ( stream_.nUserChannels[mode] > 1 &&
+ stream_.userInterleaved != stream_.deviceInterleaved[mode] )
+ stream_.doConvertBuffer[mode] = true;
+ }
+ else if ( monoMode && stream_.userInterleaved )
stream_.doConvertBuffer[mode] = true;
// Allocate our CoreHandle structure for the stream.
@@ -1101,11 +1117,13 @@ bool RtApiCore :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
}
else
handle = (CoreHandle *) stream_.apiHandle;
- handle->iStream[mode] = iStream;
+ handle->iStream[mode] = firstStream;
+ handle->nStreams[mode] = streamCount;
handle->id[mode] = id;
// Allocate necessary internal buffers.
- unsigned long bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat );
+ unsigned long bufferBytes;
+ bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat );
stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 );
if ( stream_.userBuffer[mode] == NULL ) {
errorText_ = "RtApiCore::probeDeviceOpen: error allocating user buffer memory.";
@@ -1113,9 +1131,9 @@ bool RtApiCore :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
}
// If possible, we will make use of the CoreAudio stream buffers as
- // "device buffers". However, we can't do this if the device
- // buffers are non-interleaved ("mono" mode).
- if ( !stream_.deviceInterleaved[mode] && stream_.doConvertBuffer[mode] ) {
+ // "device buffers". However, we can't do this if using multiple
+ // streams.
+ if ( stream_.doConvertBuffer[mode] && handle->nStreams[mode] > 1 ) {
bool makeBuffer = true;
bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] );
@@ -1134,13 +1152,6 @@ bool RtApiCore :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
errorText_ = "RtApiCore::probeDeviceOpen: error allocating device buffer memory.";
goto error;
}
-
- // Save a pointer to our own device buffer in the CoreHandle
- // structure because we may need to use the stream_.deviceBuffer
- // variable to point to the CoreAudio buffer before buffer
- // conversion (if we have a duplex stream with two different
- // conversion schemes).
- handle->deviceBuffer = stream_.deviceBuffer;
}
}
@@ -1149,30 +1160,22 @@ bool RtApiCore :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
stream_.state = STREAM_STOPPED;
stream_.callbackInfo.object = (void *) this;
- // Setup the buffer conversion information structure. We override
- // the channel offset value and perform our own setting for that
- // here.
+ // Setup the buffer conversion information structure.
if ( stream_.doConvertBuffer[mode] ) {
- setConvertInfo( mode, 0 );
-
- // Add channel offset for interleaved channels.
- if ( firstChannel > 0 && stream_.deviceInterleaved[mode] ) {
- if ( mode == OUTPUT ) {
- for ( int k=0; k<stream_.convertInfo[mode].channels; k++ )
- stream_.convertInfo[mode].outOffset[k] += firstChannel;
- }
- else {
- for ( int k=0; k<stream_.convertInfo[mode].channels; k++ )
- stream_.convertInfo[mode].inOffset[k] += firstChannel;
- }
- }
+ if ( streamCount > 1 ) setConvertInfo( mode, 0 );
+ else setConvertInfo( mode, channelOffset );
}
if ( mode == INPUT && stream_.mode == OUTPUT && stream_.device[0] == device )
// Only one callback procedure per device.
stream_.mode = DUPLEX;
else {
+#if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 )
+ result = AudioDeviceCreateIOProcID( id, callbackHandler, (void *) &stream_.callbackInfo, &handle->procId[mode] );
+#else
+ // deprecated in favor of AudioDeviceCreateIOProcID()
result = AudioDeviceAddIOProc( id, callbackHandler, (void *) &stream_.callbackInfo );
+#endif
if ( result != noErr ) {
errorStream_ << "RtApiCore::probeDeviceOpen: system error setting callback for device (" << device << ").";
errorText_ = errorStream_.str();
@@ -1225,13 +1228,23 @@ void RtApiCore :: closeStream( void )
if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
if ( stream_.state == STREAM_RUNNING )
AudioDeviceStop( handle->id[0], callbackHandler );
+#if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 )
+ AudioDeviceDestroyIOProcID( handle->id[0], handle->procId[0] );
+#else
+ // deprecated in favor of AudioDeviceDestroyIOProcID()
AudioDeviceRemoveIOProc( handle->id[0], callbackHandler );
+#endif
}
if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && stream_.device[0] != stream_.device[1] ) ) {
if ( stream_.state == STREAM_RUNNING )
AudioDeviceStop( handle->id[1], callbackHandler );
+#if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 )
+ AudioDeviceDestroyIOProcID( handle->id[1], handle->procId[1] );
+#else
+ // deprecated in favor of AudioDeviceDestroyIOProcID()
AudioDeviceRemoveIOProc( handle->id[1], callbackHandler );
+#endif
}
for ( int i=0; i<2; i++ ) {
@@ -1241,8 +1254,8 @@ void RtApiCore :: closeStream( void )
}
}
- if ( handle->deviceBuffer ) {
- free( handle->deviceBuffer );
+ if ( stream_.deviceBuffer ) {
+ free( stream_.deviceBuffer );
stream_.deviceBuffer = 0;
}
@@ -1311,6 +1324,11 @@ void RtApiCore :: stopStream( void )
MUTEX_LOCK( &stream_.mutex );
+ if ( stream_.state == STREAM_STOPPED ) {
+ MUTEX_UNLOCK( &stream_.mutex );
+ return;
+ }
+
OSStatus result = noErr;
CoreHandle *handle = (CoreHandle *) stream_.apiHandle;
if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
@@ -1338,10 +1356,11 @@ void RtApiCore :: stopStream( void )
}
}
+ stream_.state = STREAM_STOPPED;
+
unlock:
MUTEX_UNLOCK( &stream_.mutex );
- stream_.state = STREAM_STOPPED;
if ( result == noErr ) return;
error( RtError::SYSTEM_ERROR );
}
@@ -1386,6 +1405,12 @@ bool RtApiCore :: callbackEvent( AudioDeviceID deviceId,
MUTEX_LOCK( &stream_.mutex );
+ // The state might change while waiting on a mutex.
+ if ( stream_.state == STREAM_STOPPED ) {
+ MUTEX_UNLOCK( &stream_.mutex );
+ return SUCCESS;
+ }
+
AudioDeviceID outputDevice = handle->id[0];
// Invoke user callback to get fresh output data UNLESS we are
@@ -1418,48 +1443,96 @@ bool RtApiCore :: callbackEvent( AudioDeviceID deviceId,
if ( handle->drainCounter > 1 ) { // write zeros to the output stream
- if ( stream_.deviceInterleaved[0] ) {
+ if ( handle->nStreams[0] == 1 ) {
memset( outBufferList->mBuffers[handle->iStream[0]].mData,
0,
outBufferList->mBuffers[handle->iStream[0]].mDataByteSize );
}
- else {
- for ( unsigned int i=0; i<stream_.nDeviceChannels[0]; i++ ) {
+ else { // fill multiple streams with zeros
+ for ( unsigned int i=0; i<handle->nStreams[0]; i++ ) {
memset( outBufferList->mBuffers[handle->iStream[0]+i].mData,
0,
outBufferList->mBuffers[handle->iStream[0]+i].mDataByteSize );
}
}
}
- else if ( stream_.doConvertBuffer[0] ) {
-
- if ( stream_.deviceInterleaved[0] )
- stream_.deviceBuffer = (char *) outBufferList->mBuffers[handle->iStream[0]].mData;
- else
- stream_.deviceBuffer = handle->deviceBuffer;
-
- convertBuffer( stream_.deviceBuffer, stream_.userBuffer[0], stream_.convertInfo[0] );
-
- if ( !stream_.deviceInterleaved[0] ) {
- UInt32 bufferBytes = outBufferList->mBuffers[handle->iStream[0]].mDataByteSize;
- for ( unsigned int i=0; i<stream_.nDeviceChannels[0]; i++ ) {
- memcpy( outBufferList->mBuffers[handle->iStream[0]+i].mData,
- &stream_.deviceBuffer[i*bufferBytes], bufferBytes );
- }
+ else if ( handle->nStreams[0] == 1 ) {
+ if ( stream_.doConvertBuffer[0] ) { // convert directly to CoreAudio stream buffer
+ convertBuffer( (char *) outBufferList->mBuffers[handle->iStream[0]].mData,
+ stream_.userBuffer[0], stream_.convertInfo[0] );
}
-
- }
- else {
- if ( stream_.deviceInterleaved[0] ) {
+ else { // copy from user buffer
memcpy( outBufferList->mBuffers[handle->iStream[0]].mData,
stream_.userBuffer[0],
outBufferList->mBuffers[handle->iStream[0]].mDataByteSize );
}
- else {
+ }
+ else { // fill multiple streams
+ Float32 *inBuffer = (Float32 *) stream_.userBuffer[0];
+ if ( stream_.doConvertBuffer[0] ) {
+ convertBuffer( stream_.deviceBuffer, stream_.userBuffer[0], stream_.convertInfo[0] );
+ inBuffer = (Float32 *) stream_.deviceBuffer;
+ }
+
+ if ( stream_.deviceInterleaved[0] == false ) { // mono mode
UInt32 bufferBytes = outBufferList->mBuffers[handle->iStream[0]].mDataByteSize;
- for ( unsigned int i=0; i<stream_.nDeviceChannels[0]; i++ ) {
+ for ( unsigned int i=0; i<stream_.nUserChannels[0]; i++ ) {
memcpy( outBufferList->mBuffers[handle->iStream[0]+i].mData,
- &stream_.userBuffer[0][i*bufferBytes], bufferBytes );
+ (void *)&inBuffer[i*stream_.bufferSize], bufferBytes );
+ }
+ }
+ else { // fill multiple multi-channel streams with interleaved data
+ UInt32 streamChannels, channelsLeft, inJump, outJump, inOffset;
+ Float32 *out, *in;
+
+ bool inInterleaved = ( stream_.userInterleaved ) ? true : false;
+ UInt32 inChannels = stream_.nUserChannels[0];
+ if ( stream_.doConvertBuffer[0] ) {
+ inInterleaved = true; // device buffer will always be interleaved for nStreams > 1 and not mono mode
+ inChannels = stream_.nDeviceChannels[0];
+ }
+
+ if ( inInterleaved ) inOffset = 1;
+ else inOffset = stream_.bufferSize;
+
+ channelsLeft = inChannels;
+ for ( unsigned int i=0; i<handle->nStreams[0]; i++ ) {
+ in = inBuffer;
+ out = (Float32 *) outBufferList->mBuffers[handle->iStream[0]+i].mData;
+ streamChannels = outBufferList->mBuffers[handle->iStream[0]+i].mNumberChannels;
+
+ outJump = 0;
+ // Account for possible channel offset in first stream
+ if ( i == 0 && stream_.channelOffset[0] > 0 ) {
+ streamChannels -= stream_.channelOffset[0];
+ outJump = stream_.channelOffset[0];
+ out += outJump;
+ }
+
+ // Account for possible unfilled channels at end of the last stream
+ if ( streamChannels > channelsLeft ) {
+ outJump = streamChannels - channelsLeft;
+ streamChannels = channelsLeft;
+ }
+
+ // Determine input buffer offsets and skips
+ if ( inInterleaved ) {
+ inJump = inChannels;
+ in += inChannels - channelsLeft;
+ }
+ else {
+ inJump = 1;
+ in += (inChannels - channelsLeft) * inOffset;
+ }
+
+ for ( unsigned int i=0; i<stream_.bufferSize; i++ ) {
+ for ( unsigned int j=0; j<streamChannels; j++ ) {
+ *out++ = in[j*inOffset];
+ }
+ out += outJump;
+ in += inJump;
+ }
+ channelsLeft -= streamChannels;
}
}
}
@@ -1470,29 +1543,93 @@ bool RtApiCore :: callbackEvent( AudioDeviceID deviceId,
}
}
- AudioDeviceID inputDevice = handle->id[1];
+ AudioDeviceID inputDevice;
+ inputDevice = handle->id[1];
if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && deviceId == inputDevice ) ) {
- if ( stream_.doConvertBuffer[1] ) {
+ if ( handle->nStreams[1] == 1 ) {
+ if ( stream_.doConvertBuffer[1] ) { // convert directly from CoreAudio stream buffer
+ convertBuffer( stream_.userBuffer[1],
+ (char *) inBufferList->mBuffers[handle->iStream[1]].mData,
+ stream_.convertInfo[1] );
+ }
+ else { // copy to user buffer
+ memcpy( stream_.userBuffer[1],
+ inBufferList->mBuffers[handle->iStream[1]].mData,
+ inBufferList->mBuffers[handle->iStream[1]].mDataByteSize );
+ }
+ }
+ else { // read from multiple streams
+ Float32 *outBuffer = (Float32 *) stream_.userBuffer[1];
+ if ( stream_.doConvertBuffer[1] ) outBuffer = (Float32 *) stream_.deviceBuffer;
- if ( stream_.deviceInterleaved[1] )
- stream_.deviceBuffer = (char *) inBufferList->mBuffers[handle->iStream[1]].mData;
- else {
- stream_.deviceBuffer = (char *) handle->deviceBuffer;
+ if ( stream_.deviceInterleaved[1] == false ) { // mono mode
UInt32 bufferBytes = inBufferList->mBuffers[handle->iStream[1]].mDataByteSize;
- for ( unsigned int i=0; i<stream_.nDeviceChannels[1]; i++ ) {
- memcpy( &stream_.deviceBuffer[i*bufferBytes],
+ for ( unsigned int i=0; i<stream_.nUserChannels[1]; i++ ) {
+ memcpy( (void *)&outBuffer[i*stream_.bufferSize],
inBufferList->mBuffers[handle->iStream[1]+i].mData, bufferBytes );
}
}
+ else { // read from multiple multi-channel streams
+ UInt32 streamChannels, channelsLeft, inJump, outJump, outOffset;
+ Float32 *out, *in;
+
+ bool outInterleaved = ( stream_.userInterleaved ) ? true : false;
+ UInt32 outChannels = stream_.nUserChannels[1];
+ if ( stream_.doConvertBuffer[1] ) {
+ outInterleaved = true; // device buffer will always be interleaved for nStreams > 1 and not mono mode
+ outChannels = stream_.nDeviceChannels[1];
+ }
- convertBuffer( stream_.userBuffer[1], stream_.deviceBuffer, stream_.convertInfo[1] );
+ if ( outInterleaved ) outOffset = 1;
+ else outOffset = stream_.bufferSize;
+
+ channelsLeft = outChannels;
+ for ( unsigned int i=0; i<handle->nStreams[1]; i++ ) {
+ out = outBuffer;
+ in = (Float32 *) inBufferList->mBuffers[handle->iStream[1]+i].mData;
+ streamChannels = inBufferList->mBuffers[handle->iStream[1]+i].mNumberChannels;
+
+ inJump = 0;
+ // Account for possible channel offset in first stream
+ if ( i == 0 && stream_.channelOffset[1] > 0 ) {
+ streamChannels -= stream_.channelOffset[1];
+ inJump = stream_.channelOffset[1];
+ in += inJump;
+ }
- }
- else {
- memcpy( stream_.userBuffer[1],
- inBufferList->mBuffers[handle->iStream[1]].mData,
- inBufferList->mBuffers[handle->iStream[1]].mDataByteSize );
+ // Account for possible unread channels at end of the last stream
+ if ( streamChannels > channelsLeft ) {
+ inJump = streamChannels - channelsLeft;
+ streamChannels = channelsLeft;
+ }
+
+ // Determine output buffer offsets and skips
+ if ( outInterleaved ) {
+ outJump = outChannels;
+ out += outChannels - channelsLeft;
+ }
+ else {
+ outJump = 1;
+ out += (outChannels - channelsLeft) * outOffset;
+ }
+
+ for ( unsigned int i=0; i<stream_.bufferSize; i++ ) {
+ for ( unsigned int j=0; j<streamChannels; j++ ) {
+ out[j*outOffset] = *in++;
+ }
+ out += outJump;
+ in += inJump;
+ }
+ channelsLeft -= streamChannels;
+ }
+ }
+
+ if ( stream_.doConvertBuffer[1] ) { // convert from our internal "device" buffer
+ convertBuffer( stream_.userBuffer[1],
+ stream_.deviceBuffer,
+ stream_.convertInfo[1] );
+ }
}
}
@@ -1505,7 +1642,7 @@ bool RtApiCore :: callbackEvent( AudioDeviceID deviceId,
const char* RtApiCore :: getErrorCode( OSStatus code )
{
- switch( code ) {
+ switch( code ) {
case kAudioHardwareNotRunningError:
return "kAudioHardwareNotRunningError";
@@ -1542,10 +1679,10 @@ const char* RtApiCore :: getErrorCode( OSStatus code )
default:
return "CoreAudio unknown error";
- }
+ }
}
-//******************** End of __MACOSX_CORE__ *********************//
+ //******************** End of __MACOSX_CORE__ *********************//
#endif
#if defined(__UNIX_JACK__)
@@ -1597,9 +1734,15 @@ struct JackHandle {
:client(0), drainCounter(0), internalDrain(false) { ports[0] = 0; ports[1] = 0; xrun[0] = false; xrun[1] = false; }
};
+void jackSilentError( const char * ) {};
+
RtApiJack :: RtApiJack()
{
// Nothing to do here.
+#if !defined(__RTAUDIO_DEBUG__)
+ // Turn off Jack's internal error reporting.
+ jack_set_error_function( &jackSilentError );
+#endif
}
RtApiJack :: ~RtApiJack()
@@ -1610,7 +1753,9 @@ RtApiJack :: ~RtApiJack()
unsigned int RtApiJack :: getDeviceCount( void )
{
// See if we can become a jack client.
- jack_client_t *client = jack_client_new( "RtApiJackCount" );
+ jack_options_t options = (jack_options_t) ( JackNoStartServer | JackUseExactName ); //JackNullOption;
+ jack_status_t *status = NULL;
+ jack_client_t *client = jack_client_open( "RtApiJackCount", options, status );
if ( client == 0 ) return 0;
const char **ports;
@@ -1619,7 +1764,7 @@ unsigned int RtApiJack :: getDeviceCount( void )
ports = jack_get_ports( client, NULL, NULL, 0 );
if ( ports ) {
// Parse the port names up to the first colon (:).
- unsigned int iColon = 0;
+ size_t iColon = 0;
do {
port = (char *) ports[ nChannels ];
iColon = port.find(":");
@@ -1643,7 +1788,9 @@ RtAudio::DeviceInfo RtApiJack :: getDeviceInfo( unsigned int device )
RtAudio::DeviceInfo info;
info.probed = false;
- jack_client_t *client = jack_client_new( "RtApiJackInfo" );
+ jack_options_t options = (jack_options_t) ( JackNoStartServer | JackUseExactName ); //JackNullOption
+ jack_status_t *status = NULL;
+ jack_client_t *client = jack_client_open( "RtApiJackInfo", options, status );
if ( client == 0 ) {
errorText_ = "RtApiJack::getDeviceInfo: Jack server not found or connection error!";
error( RtError::WARNING );
@@ -1656,7 +1803,7 @@ RtAudio::DeviceInfo RtApiJack :: getDeviceInfo( unsigned int device )
ports = jack_get_ports( client, NULL, NULL, 0 );
if ( ports ) {
// Parse the port names up to the first colon (:).
- unsigned int iColon = 0;
+ size_t iColon = 0;
do {
port = (char *) ports[ nPorts ];
iColon = port.find(":");
@@ -1771,10 +1918,12 @@ bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
// Look for jack server and try to become a client (only do once per stream).
jack_client_t *client = 0;
if ( mode == OUTPUT || ( mode == INPUT && stream_.mode != OUTPUT ) ) {
+ jack_options_t jackoptions = (jack_options_t) ( JackNoStartServer | JackUseExactName ); //JackNullOption;
+ jack_status_t *status = NULL;
if ( options && !options->streamName.empty() )
- client = jack_client_new( options->streamName.c_str() );
+ client = jack_client_open( options->streamName.c_str(), jackoptions, status );
else
- client = jack_client_new( "RtApiJack" );
+ client = jack_client_open( "RtApiJack", jackoptions, status );
if ( client == 0 ) {
errorText_ = "RtApiJack::probeDeviceOpen: Jack server not found or connection error!";
error( RtError::WARNING );
@@ -1792,7 +1941,7 @@ bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
ports = jack_get_ports( client, NULL, NULL, 0 );
if ( ports ) {
// Parse the port names up to the first colon (:).
- unsigned int iColon = 0;
+ size_t iColon = 0;
do {
port = (char *) ports[ nPorts ];
iColon = port.find(":");
@@ -2131,6 +2280,11 @@ void RtApiJack :: stopStream( void )
MUTEX_LOCK( &stream_.mutex );
+ if ( stream_.state == STREAM_STOPPED ) {
+ MUTEX_UNLOCK( &stream_.mutex );
+ return;
+ }
+
JackHandle *handle = (JackHandle *) stream_.apiHandle;
if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
@@ -2161,6 +2315,21 @@ void RtApiJack :: abortStream( void )
stopStream();
}
+// This function will be called by a spawned thread when the user
+// callback function signals that the stream should be stopped or
+// aborted. It is necessary to handle it this way because the
+// callbackEvent() function must return before the jack_deactivate()
+// function will return.
+extern "C" void *jackStopStream( void *ptr )
+{
+ CallbackInfo *info = (CallbackInfo *) ptr;
+ RtApiJack *object = (RtApiJack *) info->object;
+
+ object->stopStream();
+
+ pthread_exit( NULL );
+}
+
bool RtApiJack :: callbackEvent( unsigned long nframes )
{
if ( stream_.state == STREAM_STOPPED ) return SUCCESS;
@@ -2180,15 +2349,23 @@ bool RtApiJack :: callbackEvent( unsigned long nframes )
// Check if we were draining the stream and signal is finished.
if ( handle->drainCounter > 3 ) {
- if ( handle->internalDrain == false )
- pthread_cond_signal( &handle->condition );
+ if ( handle->internalDrain == true ) {
+ ThreadHandle id;
+ pthread_create( &id, NULL, jackStopStream, info );
+ }
else
- stopStream();
+ pthread_cond_signal( &handle->condition );
return SUCCESS;
}
MUTEX_LOCK( &stream_.mutex );
+ // The state might change while waiting on a mutex.
+ if ( stream_.state == STREAM_STOPPED ) {
+ MUTEX_UNLOCK( &stream_.mutex );
+ return SUCCESS;
+ }
+
// Invoke user callback first, to get fresh output data.
if ( handle->drainCounter == 0 ) {
RtAudioCallback callback = (RtAudioCallback) info->callback;
@@ -2206,7 +2383,8 @@ bool RtApiJack :: callbackEvent( unsigned long nframes )
stream_.bufferSize, streamTime, status, info->userData );
if ( handle->drainCounter == 2 ) {
MUTEX_UNLOCK( &stream_.mutex );
- abortStream();
+ ThreadHandle id;
+ pthread_create( &id, NULL, jackStopStream, info );
return SUCCESS;
}
else if ( handle->drainCounter == 1 )
@@ -2270,7 +2448,7 @@ bool RtApiJack :: callbackEvent( unsigned long nframes )
RtApi::tickStreamTime();
return SUCCESS;
}
-//******************** End of __UNIX_JACK__ *********************//
+ //******************** End of __UNIX_JACK__ *********************//
#endif
#if defined(__WINDOWS_ASIO__) // ASIO API on Windows
@@ -2625,11 +2803,28 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
else if ( *bufferSize > (unsigned int) maxSize ) *bufferSize = (unsigned int) maxSize;
else if ( granularity == -1 ) {
// Make sure bufferSize is a power of two.
- double power = std::log10( (double) *bufferSize ) / log10( 2.0 );
- *bufferSize = (int) pow( 2.0, floor(power+0.5) );
+ int log2_of_min_size = 0;
+ int log2_of_max_size = 0;
+
+ for ( unsigned int i = 0; i < sizeof(long) * 8; i++ ) {
+ if ( minSize & ((long)1 << i) ) log2_of_min_size = i;
+ if ( maxSize & ((long)1 << i) ) log2_of_max_size = i;
+ }
+
+ long min_delta = std::abs( (long)*bufferSize - ((long)1 << log2_of_min_size) );
+ int min_delta_num = log2_of_min_size;
+
+ for (int i = log2_of_min_size + 1; i <= log2_of_max_size; i++) {
+ long current_delta = std::abs( (long)*bufferSize - ((long)1 << i) );
+ if (current_delta < min_delta) {
+ min_delta = current_delta;
+ min_delta_num = i;
+ }
+ }
+
+ *bufferSize = ( (unsigned int)1 << min_delta_num );
if ( *bufferSize < (unsigned int) minSize ) *bufferSize = (unsigned int) minSize;
else if ( *bufferSize > (unsigned int) maxSize ) *bufferSize = (unsigned int) maxSize;
- else *bufferSize = preferSize;
}
else if ( granularity != 0 ) {
// Set to an even multiple of granularity, rounding up.
@@ -2897,6 +3092,11 @@ void RtApiAsio :: stopStream()
MUTEX_LOCK( &stream_.mutex );
+ if ( stream_.state == STREAM_STOPPED ) {
+ MUTEX_UNLOCK( &stream_.mutex );
+ return;
+ }
+
AsioHandle *handle = (AsioHandle *) stream_.apiHandle;
if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
if ( handle->drainCounter == 0 ) {
@@ -2932,10 +3132,10 @@ void RtApiAsio :: abortStream()
// The following lines were commented-out because some behavior was
// noted where the device buffers need to be zeroed to avoid
- // continuing sound, even when the device buffers are completed
+ // continuing sound, even when the device buffers are completely
// disposed. So now, calling abort is the same as calling stop.
- //AsioHandle *handle = (AsioHandle *) stream_.apiHandle;
- //handle->drainCounter = 1;
+ // AsioHandle *handle = (AsioHandle *) stream_.apiHandle;
+ // handle->drainCounter = 1;
stopStream();
}
@@ -3188,15 +3388,15 @@ static const char* getAsioErrorString( ASIOError result )
};
static Messages m[] =
- {
- { ASE_NotPresent, "Hardware input or output is not present or available." },
- { ASE_HWMalfunction, "Hardware is malfunctioning." },
- { ASE_InvalidParameter, "Invalid input parameter." },
- { ASE_InvalidMode, "Invalid mode." },
- { ASE_SPNotAdvancing, "Sample position not advancing." },
- { ASE_NoClock, "Sample clock or rate cannot be determined or is not present." },
- { ASE_NoMemory, "Not enough memory to complete the request." }
- };
+ {
+ { ASE_NotPresent, "Hardware input or output is not present or available." },
+ { ASE_HWMalfunction, "Hardware is malfunctioning." },
+ { ASE_InvalidParameter, "Invalid input parameter." },
+ { ASE_InvalidMode, "Invalid mode." },
+ { ASE_SPNotAdvancing, "Sample position not advancing." },
+ { ASE_NoClock, "Sample clock or rate cannot be determined or is not present." },
+ { ASE_NoMemory, "Not enough memory to complete the request." }
+ };
for ( unsigned int i = 0; i < sizeof(m)/sizeof(m[0]); ++i )
if ( m[i].value == result ) return m[i].message;
@@ -3220,7 +3420,7 @@ static const char* getAsioErrorString( ASIOError result )
#include <assert.h>
#if defined(__MINGW32__)
-// missing from latest mingw winapi
+ // missing from latest mingw winapi
#define WAVE_FORMAT_96M08 0x00010000 /* 96 kHz, Mono, 8-bit */
#define WAVE_FORMAT_96S08 0x00020000 /* 96 kHz, Stereo, 8-bit */
#define WAVE_FORMAT_96M16 0x00040000 /* 96 kHz, Mono, 16-bit */
@@ -3235,7 +3435,7 @@ static const char* getAsioErrorString( ASIOError result )
static inline DWORD dsPointerDifference( DWORD laterPointer, DWORD earlierPointer, DWORD bufferSize )
{
- if (laterPointer > earlierPointer)
+ if ( laterPointer > earlierPointer )
return laterPointer - earlierPointer;
else
return laterPointer - earlierPointer + bufferSize;
@@ -3684,7 +3884,7 @@ bool RtApiDs :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned
bufferBytes *= 2;
// Set cooperative level to DSSCL_EXCLUSIVE ... sound stops when window focus changes.
- //result = output->SetCooperativeLevel( hWnd, DSSCL_EXCLUSIVE );
+ // result = output->SetCooperativeLevel( hWnd, DSSCL_EXCLUSIVE );
// Set cooperative level to DSSCL_PRIORITY ... sound remains when window focus changes.
result = output->SetCooperativeLevel( hWnd, DSSCL_PRIORITY );
if ( FAILED( result ) ) {
@@ -3850,6 +4050,11 @@ bool RtApiDs :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned
// Update wave format structure and buffer information.
waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8;
waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
+ dsPointerLeadTime = nBuffers * (*bufferSize) * (waveFormat.wBitsPerSample / 8) * channels;
+
+ // If the user wants an even bigger buffer, increase the device buffer size accordingly.
+ while ( dsPointerLeadTime * 2U > (DWORD) bufferBytes )
+ bufferBytes *= 2;
// Setup the secondary DS buffer description.
dsBufferSize = bufferBytes;
@@ -3871,6 +4076,20 @@ bool RtApiDs :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned
return FAILURE;
}
+ // Get the buffer size ... might be different from what we specified.
+ DSCBCAPS dscbcaps;
+ dscbcaps.dwSize = sizeof( DSCBCAPS );
+ result = buffer->GetCaps( &dscbcaps );
+ if ( FAILED( result ) ) {
+ input->Release();
+ buffer->Release();
+ errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") getting buffer settings (" << dsinfo.name << ")!";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ bufferBytes = dscbcaps.dwBufferBytes;
+
// Lock the capture buffer
LPVOID audioPtr;
DWORD dataLen;
@@ -4111,9 +4330,9 @@ void RtApiDs :: startStream()
timeBeginPeriod( 1 );
/*
- memset( &statistics, 0, sizeof( statistics ) );
- statistics.sampleRate = stream_.sampleRate;
- statistics.writeDeviceBufferLeadBytes = handle->dsPointerLeadTime[0];
+ memset( &statistics, 0, sizeof( statistics ) );
+ statistics.sampleRate = stream_.sampleRate;
+ statistics.writeDeviceBufferLeadBytes = handle->dsPointerLeadTime[0];
*/
buffersRolling = false;
@@ -4170,6 +4389,11 @@ void RtApiDs :: stopStream()
MUTEX_LOCK( &stream_.mutex );
+ if ( stream_.state == STREAM_STOPPED ) {
+ MUTEX_UNLOCK( &stream_.mutex );
+ return;
+ }
+
HRESULT result = 0;
LPVOID audioPtr;
DWORD dataLen;
@@ -4187,7 +4411,7 @@ void RtApiDs :: stopStream()
LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];
result = buffer->Stop();
if ( FAILED( result ) ) {
- errorStream_ << "RtApiDs::abortStream: error (" << getErrorString( result ) << ") stopping output buffer!";
+ errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") stopping output buffer!";
errorText_ = errorStream_.str();
goto unlock;
}
@@ -4196,7 +4420,7 @@ void RtApiDs :: stopStream()
// we won't have old data playing.
result = buffer->Lock( 0, handle->dsBufferSize[0], &audioPtr, &dataLen, NULL, NULL, 0 );
if ( FAILED( result ) ) {
- errorStream_ << "RtApiDs::abortStream: error (" << getErrorString( result ) << ") locking output buffer!";
+ errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") locking output buffer!";
errorText_ = errorStream_.str();
goto unlock;
}
@@ -4207,7 +4431,7 @@ void RtApiDs :: stopStream()
// Unlock the DS buffer
result = buffer->Unlock( audioPtr, dataLen, NULL, 0 );
if ( FAILED( result ) ) {
- errorStream_ << "RtApiDs::abortStream: error (" << getErrorString( result ) << ") unlocking output buffer!";
+ errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") unlocking output buffer!";
errorText_ = errorStream_.str();
goto unlock;
}
@@ -4223,7 +4447,7 @@ void RtApiDs :: stopStream()
result = buffer->Stop();
if ( FAILED( result ) ) {
- errorStream_ << "RtApiDs::abortStream: error (" << getErrorString( result ) << ") stopping input buffer!";
+ errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") stopping input buffer!";
errorText_ = errorStream_.str();
goto unlock;
}
@@ -4232,7 +4456,7 @@ void RtApiDs :: stopStream()
// we won't have old data playing.
result = buffer->Lock( 0, handle->dsBufferSize[1], &audioPtr, &dataLen, NULL, NULL, 0 );
if ( FAILED( result ) ) {
- errorStream_ << "RtApiDs::abortStream: error (" << getErrorString( result ) << ") locking input buffer!";
+ errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") locking input buffer!";
errorText_ = errorStream_.str();
goto unlock;
}
@@ -4243,7 +4467,7 @@ void RtApiDs :: stopStream()
// Unlock the DS buffer
result = buffer->Unlock( audioPtr, dataLen, NULL, 0 );
if ( FAILED( result ) ) {
- errorStream_ << "RtApiDs::abortStream: error (" << getErrorString( result ) << ") unlocking input buffer!";
+ errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") unlocking input buffer!";
errorText_ = errorStream_.str();
goto unlock;
}
@@ -4256,6 +4480,7 @@ void RtApiDs :: stopStream()
timeEndPeriod( 1 ); // revert to normal scheduler frequency on lesser windows.
stream_.state = STREAM_STOPPED;
MUTEX_UNLOCK( &stream_.mutex );
+
if ( FAILED( result ) ) error( RtError::SYSTEM_ERROR );
}
@@ -4301,6 +4526,12 @@ void RtApiDs :: callbackEvent()
MUTEX_LOCK( &stream_.mutex );
+ // The state might change while waiting on a mutex.
+ if ( stream_.state == STREAM_STOPPED ) {
+ MUTEX_UNLOCK( &stream_.mutex );
+ return;
+ }
+
// Invoke user callback to get fresh output data UNLESS we are
// draining stream.
if ( handle->drainCounter == 0 ) {
@@ -4345,7 +4576,7 @@ void RtApiDs :: callbackEvent()
long bufferBytes;
if ( stream_.mode == DUPLEX && !buffersRolling ) {
- assert( handle->dsBufferSize[0] == handle->dsBufferSize[1] );
+ //assert( handle->dsBufferSize[0] == handle->dsBufferSize[1] );
// It takes a while for the devices to get rolling. As a result,
// there's no guarantee that the capture and write device pointers
@@ -4396,7 +4627,7 @@ void RtApiDs :: callbackEvent()
Sleep( 1 );
}
- assert( handle->dsBufferSize[0] == handle->dsBufferSize[1] );
+ //assert( handle->dsBufferSize[0] == handle->dsBufferSize[1] );
buffersRolling = true;
handle->bufferPointer[0] = ( safeWritePos + handle->dsPointerLeadTime[0] );
@@ -4656,17 +4887,17 @@ void RtApiDs :: callbackEvent()
}
#ifdef GENERATE_DEBUG_LOG
if ( currentDebugLogEntry < debugLog.size() )
- {
- TTickRecord &r = debugLog[currentDebugLogEntry++];
- r.currentReadPointer = currentReadPos;
- r.safeReadPointer = safeReadPos;
- r.currentWritePointer = currentWritePos;
- r.safeWritePointer = safeWritePos;
- r.readTime = readTime;
- r.writeTime = writeTime;
- r.nextReadPointer = handles[1].bufferPointer;
- r.nextWritePointer = handles[0].bufferPointer;
- }
+ {
+ TTickRecord &r = debugLog[currentDebugLogEntry++];
+ r.currentReadPointer = currentReadPos;
+ r.safeReadPointer = safeReadPos;
+ r.currentWritePointer = currentWritePos;
+ r.safeWritePointer = safeWritePos;
+ r.readTime = readTime;
+ r.writeTime = writeTime;
+ r.nextReadPointer = handles[1].bufferPointer;
+ r.nextWritePointer = handles[0].bufferPointer;
+ }
#endif
unlock:
@@ -4762,7 +4993,7 @@ static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid,
static char* getErrorString( int code )
{
- switch ( code ) {
+ switch ( code ) {
case DSERR_ALLOCATED:
return "Already allocated";
@@ -4811,7 +5042,7 @@ static char* getErrorString( int code )
default:
return "DirectSound unknown error";
- }
+ }
}
//******************** End of __WINDOWS_DS__ *********************//
#endif
@@ -4822,12 +5053,13 @@ static char* getErrorString( int code )
#include <alsa/asoundlib.h>
#include <unistd.h>
-// A structure to hold various information related to the ALSA API
-// implementation.
+ // A structure to hold various information related to the ALSA API
+ // implementation.
struct AlsaHandle {
snd_pcm_t *handles[2];
bool synchronized;
bool xrun[2];
+ pthread_cond_t runnable;
AlsaHandle()
:synchronized(false) { xrun[0] = false; xrun[1] = false; }
@@ -4863,17 +5095,17 @@ unsigned int RtApiAlsa :: getDeviceCount( void )
errorText_ = errorStream_.str();
error( RtError::WARNING );
goto nextcard;
- }
- subdevice = -1;
- while( 1 ) {
+ }
+ subdevice = -1;
+ while( 1 ) {
result = snd_ctl_pcm_next_device( handle, &subdevice );
- if ( result < 0 ) {
+ if ( result < 0 ) {
errorStream_ << "RtApiAlsa::getDeviceCount: control next device, card = " << card << ", " << snd_strerror( result ) << ".";
errorText_ = errorStream_.str();
error( RtError::WARNING );
break;
}
- if ( subdevice < 0 )
+ if ( subdevice < 0 )
break;
nDevices++;
}
@@ -4906,17 +5138,17 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
errorText_ = errorStream_.str();
error( RtError::WARNING );
goto nextcard;
- }
- subdevice = -1;
- while( 1 ) {
+ }
+ subdevice = -1;
+ while( 1 ) {
result = snd_ctl_pcm_next_device( chandle, &subdevice );
- if ( result < 0 ) {
+ if ( result < 0 ) {
errorStream_ << "RtApiAlsa::getDeviceInfo: control next device, card = " << card << ", " << snd_strerror( result ) << ".";
errorText_ = errorStream_.str();
error( RtError::WARNING );
break;
}
- if ( subdevice < 0 ) break;
+ if ( subdevice < 0 ) break;
if ( nDevices == device ) {
sprintf( name, "hw:%d,%d", card, subdevice );
goto foundDevice;
@@ -4954,8 +5186,8 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
int openMode = SND_PCM_ASYNC;
snd_pcm_stream_t stream;
- snd_pcm_info_t *pcminfo;
- snd_pcm_info_alloca( &pcminfo );
+ snd_pcm_info_t *pcminfo;
+ snd_pcm_info_alloca( &pcminfo );
snd_pcm_t *phandle;
snd_pcm_hw_params_t *params;
snd_pcm_hw_params_alloca( &params );
@@ -5184,12 +5416,12 @@ bool RtApiAlsa :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
errorStream_ << "RtApiAlsa::probeDeviceOpen: control open, card = " << card << ", " << snd_strerror( result ) << ".";
errorText_ = errorStream_.str();
return FAILURE;
- }
- subdevice = -1;
- while( 1 ) {
+ }
+ subdevice = -1;
+ while( 1 ) {
result = snd_ctl_pcm_next_device( chandle, &subdevice );
- if ( result < 0 ) break;
- if ( subdevice < 0 ) break;
+ if ( result < 0 ) break;
+ if ( subdevice < 0 ) break;
if ( nDevices == device ) {
sprintf( name, "hw:%d,%d", card, subdevice );
snd_ctl_close( chandle );
@@ -5414,19 +5646,10 @@ bool RtApiAlsa :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
}
// Set the buffer number, which in ALSA is referred to as the "period".
- int dir;
+ int totalSize, dir;
unsigned int periods = 0;
if ( options ) periods = options->numberOfBuffers;
- if ( options && options->flags & RTAUDIO_MINIMIZE_LATENCY ) periods = 2;
- // Even though the hardware might allow 1 buffer, it won't work reliably.
- if ( periods < 2 ) periods = 2;
- result = snd_pcm_hw_params_set_periods_near( phandle, hw_params, &periods, &dir );
- if ( result < 0 ) {
- snd_pcm_close( phandle );
- errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting periods for device (" << name << "), " << snd_strerror( result ) << ".";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
+ totalSize = *bufferSize * periods;
// Set the buffer (or period) size.
snd_pcm_uframes_t periodSize = *bufferSize;
@@ -5439,6 +5662,18 @@ bool RtApiAlsa :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
}
*bufferSize = periodSize;
+ if ( options && options->flags & RTAUDIO_MINIMIZE_LATENCY ) periods = 2;
+ else periods = totalSize / *bufferSize;
+ // Even though the hardware might allow 1 buffer, it won't work reliably.
+ if ( periods < 2 ) periods = 2;
+ result = snd_pcm_hw_params_set_periods_near( phandle, hw_params, &periods, &dir );
+ if ( result < 0 ) {
+ snd_pcm_close( phandle );
+ errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting periods for device (" << name << "), " << snd_strerror( result ) << ".";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
// If attempting to setup a duplex stream, the bufferSize parameter
// MUST be the same in both directions!
if ( stream_.mode == OUTPUT && mode == INPUT && *bufferSize != stream_.bufferSize ) {
@@ -5468,9 +5703,19 @@ bool RtApiAlsa :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
snd_pcm_sw_params_alloca( &sw_params );
snd_pcm_sw_params_current( phandle, sw_params );
snd_pcm_sw_params_set_start_threshold( phandle, sw_params, *bufferSize );
- snd_pcm_sw_params_set_stop_threshold( phandle, sw_params, 0x7fffffff );
+ snd_pcm_sw_params_set_stop_threshold( phandle, sw_params, ULONG_MAX );
snd_pcm_sw_params_set_silence_threshold( phandle, sw_params, 0 );
- snd_pcm_sw_params_set_silence_size( phandle, sw_params, INT_MAX );
+
+ // The following two settings were suggested by Theo Veenker
+ //snd_pcm_sw_params_set_avail_min( phandle, sw_params, *bufferSize );
+ //snd_pcm_sw_params_set_xfer_align( phandle, sw_params, 1 );
+
+ // here are two options for a fix
+ //snd_pcm_sw_params_set_silence_size( phandle, sw_params, ULONG_MAX );
+ snd_pcm_uframes_t val;
+ snd_pcm_sw_params_get_boundary( sw_params, &val );
+ snd_pcm_sw_params_set_silence_size( phandle, sw_params, val );
+
result = snd_pcm_sw_params( phandle, sw_params );
if ( result < 0 ) {
snd_pcm_close( phandle );
@@ -5504,6 +5749,12 @@ bool RtApiAlsa :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
errorText_ = "RtApiAlsa::probeDeviceOpen: error allocating AlsaHandle memory.";
goto error;
}
+
+ if ( pthread_cond_init( &apiInfo->runnable, NULL ) ) {
+ errorText_ = "RtApiAlsa::probeDeviceOpen: error initializing pthread condition variable.";
+ goto error;
+ }
+
stream_.apiHandle = (void *) apiInfo;
apiInfo->handles[0] = 0;
apiInfo->handles[1] = 0;
@@ -5572,13 +5823,28 @@ bool RtApiAlsa :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
stream_.callbackInfo.object = (void *) this;
// Set the thread attributes for joinable and realtime scheduling
- // priority. The higher priority will only take affect if the
- // program is run as root or suid.
+ // priority (optional). The higher priority will only take affect
+ // if the program is run as root or suid. Note, under Linux
+ // processes with CAP_SYS_NICE privilege, a user can change
+ // scheduling policy and priority (thus need not be root). See
+ // POSIX "capabilities".
pthread_attr_t attr;
pthread_attr_init( &attr );
pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE );
#ifdef SCHED_RR // Undefined with some OSes (eg: NetBSD 1.6.x with GNU Pthread)
- pthread_attr_setschedpolicy( &attr, SCHED_RR );
+ if ( options && options->flags & RTAUDIO_SCHEDULE_REALTIME ) {
+ struct sched_param param;
+ int priority = options->priority;
+ int min = sched_get_priority_min( SCHED_RR );
+ int max = sched_get_priority_max( SCHED_RR );
+ if ( priority < min ) priority = min;
+ else if ( priority > max ) priority = max;
+ param.sched_priority = priority;
+ pthread_attr_setschedparam( &attr, &param );
+ pthread_attr_setschedpolicy( &attr, SCHED_RR );
+ }
+ else
+ pthread_attr_setschedpolicy( &attr, SCHED_OTHER );
#else
pthread_attr_setschedpolicy( &attr, SCHED_OTHER );
#endif
@@ -5597,6 +5863,7 @@ bool RtApiAlsa :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
error:
if ( apiInfo ) {
+ pthread_cond_destroy( &apiInfo->runnable );
if ( apiInfo->handles[0] ) snd_pcm_close( apiInfo->handles[0] );
if ( apiInfo->handles[1] ) snd_pcm_close( apiInfo->handles[1] );
delete apiInfo;
@@ -5626,10 +5893,14 @@ void RtApiAlsa :: closeStream()
return;
}
+ AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;
stream_.callbackInfo.isRunning = false;
+ MUTEX_LOCK( &stream_.mutex );
+ if ( stream_.state == STREAM_STOPPED )
+ pthread_cond_signal( &apiInfo->runnable );
+ MUTEX_UNLOCK( &stream_.mutex );
pthread_join( stream_.callbackInfo.thread, NULL );
- AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;
if ( stream_.state == STREAM_RUNNING ) {
stream_.state = STREAM_STOPPED;
if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX )
@@ -5639,6 +5910,7 @@ void RtApiAlsa :: closeStream()
}
if ( apiInfo ) {
+ pthread_cond_destroy( &apiInfo->runnable );
if ( apiInfo->handles[0] ) snd_pcm_close( apiInfo->handles[0] );
if ( apiInfo->handles[1] ) snd_pcm_close( apiInfo->handles[1] );
delete apiInfo;
@@ -5707,6 +5979,8 @@ void RtApiAlsa :: startStream()
unlock:
MUTEX_UNLOCK( &stream_.mutex );
+ pthread_cond_signal( &apiInfo->runnable );
+
if ( result >= 0 ) return;
error( RtError::SYSTEM_ERROR );
}
@@ -5720,11 +5994,13 @@ void RtApiAlsa :: stopStream()
return;
}
- // Change the state before the lock to improve shutdown response
- // when using a callback.
- stream_.state = STREAM_STOPPED;
MUTEX_LOCK( &stream_.mutex );
+ if ( stream_.state == STREAM_STOPPED ) {
+ MUTEX_UNLOCK( &stream_.mutex );
+ return;
+ }
+
int result = 0;
AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;
snd_pcm_t **handle = (snd_pcm_t **) apiInfo->handles;
@@ -5750,6 +6026,7 @@ void RtApiAlsa :: stopStream()
}
unlock:
+ stream_.state = STREAM_STOPPED;
MUTEX_UNLOCK( &stream_.mutex );
if ( result >= 0 ) return;
@@ -5765,11 +6042,13 @@ void RtApiAlsa :: abortStream()
return;
}
- // Change the state before the lock to improve shutdown response
- // when using a callback.
- stream_.state = STREAM_STOPPED;
MUTEX_LOCK( &stream_.mutex );
+ if ( stream_.state == STREAM_STOPPED ) {
+ MUTEX_UNLOCK( &stream_.mutex );
+ return;
+ }
+
int result = 0;
AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;
snd_pcm_t **handle = (snd_pcm_t **) apiInfo->handles;
@@ -5792,18 +6071,24 @@ void RtApiAlsa :: abortStream()
}
unlock:
+ stream_.state = STREAM_STOPPED;
MUTEX_UNLOCK( &stream_.mutex );
- stream_.state = STREAM_STOPPED;
if ( result >= 0 ) return;
error( RtError::SYSTEM_ERROR );
}
void RtApiAlsa :: callbackEvent()
{
+ AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;
if ( stream_.state == STREAM_STOPPED ) {
- if ( stream_.callbackInfo.isRunning ) usleep( 50000 ); // sleep 50 milliseconds
- return;
+ MUTEX_LOCK( &stream_.mutex );
+ pthread_cond_wait( &apiInfo->runnable, &stream_.mutex );
+ if ( stream_.state != STREAM_RUNNING ) {
+ MUTEX_UNLOCK( &stream_.mutex );
+ return;
+ }
+ MUTEX_UNLOCK( &stream_.mutex );
}
if ( stream_.state == STREAM_CLOSED ) {
@@ -5813,7 +6098,6 @@ void RtApiAlsa :: callbackEvent()
}
int doStopStream = 0;
- AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;
RtAudioCallback callback = (RtAudioCallback) stream_.callbackInfo.callback;
double streamTime = getStreamTime();
RtAudioStreamStatus status = 0;
@@ -5826,7 +6110,12 @@ void RtApiAlsa :: callbackEvent()
apiInfo->xrun[1] = false;
}
doStopStream = callback( stream_.userBuffer[0], stream_.userBuffer[1],
- stream_.bufferSize, streamTime, status, stream_.callbackInfo.userData );
+ stream_.bufferSize, streamTime, status, stream_.callbackInfo.userData );
+
+ if ( doStopStream == 2 ) {
+ abortStream();
+ return;
+ }
MUTEX_LOCK( &stream_.mutex );
@@ -5867,7 +6156,7 @@ void RtApiAlsa :: callbackEvent()
}
if ( result < (int) stream_.bufferSize ) {
- // Either an error or underrun occured.
+ // Either an error or overrun occured.
if ( result == -EPIPE ) {
snd_pcm_state_t state = snd_pcm_state( handle[1] );
if ( state == SND_PCM_STATE_XRUN ) {
@@ -5888,7 +6177,7 @@ void RtApiAlsa :: callbackEvent()
errorText_ = errorStream_.str();
}
error( RtError::WARNING );
- goto unlock;
+ goto tryOutput;
}
// Do byte swapping if necessary.
@@ -5904,6 +6193,8 @@ void RtApiAlsa :: callbackEvent()
if ( result == 0 && frames > 0 ) stream_.latency[1] = frames;
}
+ tryOutput:
+
if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
// Setup parameters and do buffer conversion if necessary.
@@ -5969,7 +6260,6 @@ void RtApiAlsa :: callbackEvent()
RtApi::tickStreamTime();
if ( doStopStream == 1 ) this->stopStream();
- else if ( doStopStream == 2 ) this->abortStream();
}
extern "C" void *alsaCallbackHandler( void *ptr )
@@ -5978,15 +6268,6 @@ extern "C" void *alsaCallbackHandler( void *ptr )
RtApiAlsa *object = (RtApiAlsa *) info->object;
bool *isRunning = &info->isRunning;
-#ifdef SCHED_RR
- // Set a higher scheduler priority (P.J. Leonard)
- struct sched_param param;
- int min = sched_get_priority_min( SCHED_RR );
- int max = sched_get_priority_max( SCHED_RR );
- param.sched_priority = min + ( max - min ) / 2; // Is this the best number?
- sched_setscheduler( 0, SCHED_RR, &param );
-#endif
-
while ( *isRunning == true ) {
pthread_testcancel();
object->callbackEvent();
@@ -6017,6 +6298,7 @@ struct OssHandle {
int id[2]; // device ids
bool xrun[2];
bool triggered;
+ pthread_cond_t runnable;
OssHandle()
:triggered(false) { id[0] = 0; id[1] = 0; xrun[0] = false; xrun[1] = false; }
@@ -6162,7 +6444,7 @@ RtAudio::DeviceInfo RtApiOss :: getDeviceInfo( unsigned int device )
bool RtApiOss :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
- unsigned int firstChannel, unsigned int sampleRate,
+ unsigned int firstChannel, unsigned int sampleRate,
RtAudioFormat format, unsigned int *bufferSize,
RtAudio::StreamOptions *options )
{
@@ -6259,14 +6541,14 @@ bool RtApiOss :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned
// For duplex operation, specifically set this mode (this doesn't seem to work).
/*
- if ( flags | O_RDWR ) {
+ if ( flags | O_RDWR ) {
result = ioctl( fd, SNDCTL_DSP_SETDUPLEX, NULL );
if ( result == -1) {
- errorStream_ << "RtApiOss::probeDeviceOpen: error setting duplex mode for device (" << ainfo.name << ").";
- errorText_ = errorStream_.str();
- return FAILURE;
+ errorStream_ << "RtApiOss::probeDeviceOpen: error setting duplex mode for device (" << ainfo.name << ").";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
}
- }
*/
// Check the device channel support.
@@ -6474,6 +6756,11 @@ bool RtApiOss :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned
goto error;
}
+ if ( pthread_cond_init( &handle->runnable, NULL ) ) {
+ errorText_ = "RtApiOss::probeDeviceOpen: error initializing pthread condition variable.";
+ goto error;
+ }
+
stream_.apiHandle = (void *) handle;
}
else {
@@ -6537,7 +6824,19 @@ bool RtApiOss :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned
pthread_attr_init( &attr );
pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE );
#ifdef SCHED_RR // Undefined with some OSes (eg: NetBSD 1.6.x with GNU Pthread)
- pthread_attr_setschedpolicy( &attr, SCHED_RR );
+ if ( options && options->flags & RTAUDIO_SCHEDULE_REALTIME ) {
+ struct sched_param param;
+ int priority = options->priority;
+ int min = sched_get_priority_min( SCHED_RR );
+ int max = sched_get_priority_max( SCHED_RR );
+ if ( priority < min ) priority = min;
+ else if ( priority > max ) priority = max;
+ param.sched_priority = priority;
+ pthread_attr_setschedparam( &attr, &param );
+ pthread_attr_setschedpolicy( &attr, SCHED_RR );
+ }
+ else
+ pthread_attr_setschedpolicy( &attr, SCHED_OTHER );
#else
pthread_attr_setschedpolicy( &attr, SCHED_OTHER );
#endif
@@ -6556,6 +6855,7 @@ bool RtApiOss :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned
error:
if ( handle ) {
+ pthread_cond_destroy( &handle->runnable );
if ( handle->id[0] ) close( handle->id[0] );
if ( handle->id[1] ) close( handle->id[1] );
delete handle;
@@ -6585,10 +6885,14 @@ void RtApiOss :: closeStream()
return;
}
+ OssHandle *handle = (OssHandle *) stream_.apiHandle;
stream_.callbackInfo.isRunning = false;
+ MUTEX_LOCK( &stream_.mutex );
+ if ( stream_.state == STREAM_STOPPED )
+ pthread_cond_signal( &handle->runnable );
+ MUTEX_UNLOCK( &stream_.mutex );
pthread_join( stream_.callbackInfo.thread, NULL );
- OssHandle *handle = (OssHandle *) stream_.apiHandle;
if ( stream_.state == STREAM_RUNNING ) {
if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX )
ioctl( handle->id[0], SNDCTL_DSP_HALT, 0 );
@@ -6598,6 +6902,7 @@ void RtApiOss :: closeStream()
}
if ( handle ) {
+ pthread_cond_destroy( &handle->runnable );
if ( handle->id[0] ) close( handle->id[0] );
if ( handle->id[1] ) close( handle->id[1] );
delete handle;
@@ -6637,6 +6942,9 @@ void RtApiOss :: startStream()
// when fed samples.
MUTEX_UNLOCK( &stream_.mutex );
+
+ OssHandle *handle = (OssHandle *) stream_.apiHandle;
+ pthread_cond_signal( &handle->runnable );
}
void RtApiOss :: stopStream()
@@ -6648,11 +6956,14 @@ void RtApiOss :: stopStream()
return;
}
- // Change the state before the lock to improve shutdown response
- // when using a callback.
- stream_.state = STREAM_STOPPED;
MUTEX_LOCK( &stream_.mutex );
+ // The state might change while waiting on a mutex.
+ if ( stream_.state == STREAM_STOPPED ) {
+ MUTEX_UNLOCK( &stream_.mutex );
+ return;
+ }
+
int result = 0;
OssHandle *handle = (OssHandle *) stream_.apiHandle;
if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
@@ -6701,9 +7012,9 @@ void RtApiOss :: stopStream()
}
unlock:
+ stream_.state = STREAM_STOPPED;
MUTEX_UNLOCK( &stream_.mutex );
- stream_.state = STREAM_STOPPED;
if ( result != -1 ) return;
error( RtError::SYSTEM_ERROR );
}
@@ -6717,11 +7028,14 @@ void RtApiOss :: abortStream()
return;
}
- // Change the state before the lock to improve shutdown response
- // when using a callback.
- stream_.state = STREAM_STOPPED;
MUTEX_LOCK( &stream_.mutex );
+ // The state might change while waiting on a mutex.
+ if ( stream_.state == STREAM_STOPPED ) {
+ MUTEX_UNLOCK( &stream_.mutex );
+ return;
+ }
+
int result = 0;
OssHandle *handle = (OssHandle *) stream_.apiHandle;
if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
@@ -6744,18 +7058,24 @@ void RtApiOss :: abortStream()
}
unlock:
+ stream_.state = STREAM_STOPPED;
MUTEX_UNLOCK( &stream_.mutex );
- stream_.state = STREAM_STOPPED;
if ( result != -1 ) return;
error( RtError::SYSTEM_ERROR );
}
void RtApiOss :: callbackEvent()
{
+ OssHandle *handle = (OssHandle *) stream_.apiHandle;
if ( stream_.state == STREAM_STOPPED ) {
- if ( stream_.callbackInfo.isRunning ) usleep( 50000 ); // sleep 50 milliseconds
- return;
+ MUTEX_LOCK( &stream_.mutex );
+ pthread_cond_wait( &handle->runnable, &stream_.mutex );
+ if ( stream_.state != STREAM_RUNNING ) {
+ MUTEX_UNLOCK( &stream_.mutex );
+ return;
+ }
+ MUTEX_UNLOCK( &stream_.mutex );
}
if ( stream_.state == STREAM_CLOSED ) {
@@ -6769,7 +7089,6 @@ void RtApiOss :: callbackEvent()
RtAudioCallback callback = (RtAudioCallback) stream_.callbackInfo.callback;
double streamTime = getStreamTime();
RtAudioStreamStatus status = 0;
- OssHandle *handle = (OssHandle *) stream_.apiHandle;
if ( stream_.mode != INPUT && handle->xrun[0] == true ) {
status |= RTAUDIO_OUTPUT_UNDERFLOW;
handle->xrun[0] = false;
@@ -6780,6 +7099,10 @@ void RtApiOss :: callbackEvent()
}
doStopStream = callback( stream_.userBuffer[0], stream_.userBuffer[1],
stream_.bufferSize, streamTime, status, stream_.callbackInfo.userData );
+ if ( doStopStream == 2 ) {
+ this->abortStream();
+ return;
+ }
MUTEX_LOCK( &stream_.mutex );
@@ -6828,7 +7151,7 @@ void RtApiOss :: callbackEvent()
handle->xrun[0] = true;
errorText_ = "RtApiOss::callbackEvent: audio write error.";
error( RtError::WARNING );
- goto unlock;
+ // Continue on to input section.
}
}
@@ -6872,7 +7195,6 @@ void RtApiOss :: callbackEvent()
RtApi::tickStreamTime();
if ( doStopStream == 1 ) this->stopStream();
- else if ( doStopStream == 2 ) this->abortStream();
}
extern "C" void *ossCallbackHandler( void *ptr )
@@ -6881,13 +7203,6 @@ extern "C" void *ossCallbackHandler( void *ptr )
RtApiOss *object = (RtApiOss *) info->object;
bool *isRunning = &info->isRunning;
-#ifdef SCHED_RR
- // Set a higher scheduler priority (P.J. Leonard)
- struct sched_param param;
- param.sched_priority = 39; // Is this the best number?
- sched_setscheduler( 0, SCHED_RR, &param );
-#endif
-
while ( *isRunning == true ) {
pthread_testcancel();
object->callbackEvent();
@@ -7077,10 +7392,11 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info
if (info.inFormat == RTAUDIO_SINT8) {
signed char *in = (signed char *)inBuffer;
- scale = 1.0 / 128.0;
+ scale = 1.0 / 127.5;
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
out[info.outOffset[j]] = (Float64) in[info.inOffset[j]];
+ out[info.outOffset[j]] += 0.5;
out[info.outOffset[j]] *= scale;
}
in += info.inJump;
@@ -7089,10 +7405,11 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info
}
else if (info.inFormat == RTAUDIO_SINT16) {
Int16 *in = (Int16 *)inBuffer;
- scale = 1.0 / 32768.0;
+ scale = 1.0 / 32767.5;
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
out[info.outOffset[j]] = (Float64) in[info.inOffset[j]];
+ out[info.outOffset[j]] += 0.5;
out[info.outOffset[j]] *= scale;
}
in += info.inJump;
@@ -7101,10 +7418,11 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info
}
else if (info.inFormat == RTAUDIO_SINT24) {
Int32 *in = (Int32 *)inBuffer;
- scale = 1.0 / 8388608.0;
+ scale = 1.0 / 8388607.5;
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
out[info.outOffset[j]] = (Float64) (in[info.inOffset[j]] & 0x00ffffff);
+ out[info.outOffset[j]] += 0.5;
out[info.outOffset[j]] *= scale;
}
in += info.inJump;
@@ -7113,10 +7431,11 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info
}
else if (info.inFormat == RTAUDIO_SINT32) {
Int32 *in = (Int32 *)inBuffer;
- scale = 1.0 / 2147483648.0;
+ scale = 1.0 / 2147483647.5;
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
out[info.outOffset[j]] = (Float64) in[info.inOffset[j]];
+ out[info.outOffset[j]] += 0.5;
out[info.outOffset[j]] *= scale;
}
in += info.inJump;
@@ -7151,10 +7470,11 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info
if (info.inFormat == RTAUDIO_SINT8) {
signed char *in = (signed char *)inBuffer;
- scale = 1.0 / 128.0;
+ scale = (Float32) ( 1.0 / 127.5 );
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
out[info.outOffset[j]] = (Float32) in[info.inOffset[j]];
+ out[info.outOffset[j]] += 0.5;
out[info.outOffset[j]] *= scale;
}
in += info.inJump;
@@ -7163,10 +7483,11 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info
}
else if (info.inFormat == RTAUDIO_SINT16) {
Int16 *in = (Int16 *)inBuffer;
- scale = 1.0 / 32768.0;
+ scale = (Float32) ( 1.0 / 32767.5 );
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
out[info.outOffset[j]] = (Float32) in[info.inOffset[j]];
+ out[info.outOffset[j]] += 0.5;
out[info.outOffset[j]] *= scale;
}
in += info.inJump;
@@ -7175,10 +7496,11 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info
}
else if (info.inFormat == RTAUDIO_SINT24) {
Int32 *in = (Int32 *)inBuffer;
- scale = 1.0 / 8388608.0;
+ scale = (Float32) ( 1.0 / 8388607.5 );
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
out[info.outOffset[j]] = (Float32) (in[info.inOffset[j]] & 0x00ffffff);
+ out[info.outOffset[j]] += 0.5;
out[info.outOffset[j]] *= scale;
}
in += info.inJump;
@@ -7187,10 +7509,11 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info
}
else if (info.inFormat == RTAUDIO_SINT32) {
Int32 *in = (Int32 *)inBuffer;
- scale = 1.0 / 2147483648.0;
+ scale = (Float32) ( 1.0 / 2147483647.5 );
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
out[info.outOffset[j]] = (Float32) in[info.inOffset[j]];
+ out[info.outOffset[j]] += 0.5;
out[info.outOffset[j]] *= scale;
}
in += info.inJump;
@@ -7269,7 +7592,7 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info
Float32 *in = (Float32 *)inBuffer;
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 2147483647.0);
+ out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 2147483647.5 - 0.5);
}
in += info.inJump;
out += info.outJump;
@@ -7279,7 +7602,7 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info
Float64 *in = (Float64 *)inBuffer;
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 2147483647.0);
+ out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 2147483647.5 - 0.5);
}
in += info.inJump;
out += info.outJump;
@@ -7336,7 +7659,7 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info
Float32 *in = (Float32 *)inBuffer;
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 8388608.0);
+ out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 8388607.5 - 0.5);
}
in += info.inJump;
out += info.outJump;
@@ -7346,7 +7669,7 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info
Float64 *in = (Float64 *)inBuffer;
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 2147483647.0);
+ out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 8388607.5 - 0.5);
}
in += info.inJump;
out += info.outJump;
@@ -7401,7 +7724,7 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info
Float32 *in = (Float32 *)inBuffer;
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (Int16) (in[info.inOffset[j]] * 32767.0);
+ out[info.outOffset[j]] = (Int16) (in[info.inOffset[j]] * 32767.5 - 0.5);
}
in += info.inJump;
out += info.outJump;
@@ -7411,7 +7734,7 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info
Float64 *in = (Float64 *)inBuffer;
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (Int16) (in[info.inOffset[j]] * 32767.0);
+ out[info.outOffset[j]] = (Int16) (in[info.inOffset[j]] * 32767.5 - 0.5);
}
in += info.inJump;
out += info.outJump;
@@ -7465,7 +7788,7 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info
Float32 *in = (Float32 *)inBuffer;
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (signed char) (in[info.inOffset[j]] * 127.0);
+ out[info.outOffset[j]] = (signed char) (in[info.inOffset[j]] * 127.5 - 0.5);
}
in += info.inJump;
out += info.outJump;
@@ -7475,7 +7798,7 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info
Float64 *in = (Float64 *)inBuffer;
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (signed char) (in[info.inOffset[j]] * 127.0);
+ out[info.outOffset[j]] = (signed char) (in[info.inOffset[j]] * 127.5 - 0.5);
}
in += info.inJump;
out += info.outJump;
@@ -7484,6 +7807,10 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info
}
}
+ //static inline uint16_t bswap_16(uint16_t x) { return (x>>8) | (x<<8); }
+ //static inline uint32_t bswap_32(uint32_t x) { return (bswap_16(x&0xffff)<<16) | (bswap_16(x>>16)); }
+ //static inline uint64_t bswap_64(uint64_t x) { return (((unsigned long long)bswap_32(x&0xffffffffull))<<32) | (bswap_32(x>>32)); }
+
void RtApi :: byteSwapBuffer( char *buffer, unsigned int samples, RtAudioFormat format )
{
register char val;
@@ -7516,8 +7843,8 @@ void RtApi :: byteSwapBuffer( char *buffer, unsigned int samples, RtAudioFormat
*(ptr) = *(ptr+1);
*(ptr+1) = val;
- // Increment 4 bytes.
- ptr += 4;
+ // Increment 3 more bytes.
+ ptr += 3;
}
}
else if ( format == RTAUDIO_FLOAT64 ) {
@@ -7545,18 +7872,18 @@ void RtApi :: byteSwapBuffer( char *buffer, unsigned int samples, RtAudioFormat
*(ptr) = *(ptr+1);
*(ptr+1) = val;
- // Increment 8 bytes.
- ptr += 8;
+ // Increment 5 more bytes.
+ ptr += 5;
}
}
}
-// Indentation settings for Vim and Emacs
-//
-// Local Variables:
-// c-basic-offset: 2
-// indent-tabs-mode: nil
-// End:
-//
-// vim: et sts=2 sw=2
+ // Indentation settings for Vim and Emacs
+ //
+ // Local Variables:
+ // c-basic-offset: 2
+ // indent-tabs-mode: nil
+ // End:
+ //
+ // vim: et sts=2 sw=2
diff --git a/RtAudio.h b/RtAudio.h
index 8696262..5c5fd6f 100644
--- a/RtAudio.h
+++ b/RtAudio.h
@@ -4,13 +4,13 @@
RtAudio provides a common API (Application Programming Interface)
for realtime audio input/output across Linux (native ALSA, Jack,
- and OSS), SGI, Macintosh OS X (CoreAudio and Jack), and Windows
+ and OSS), Macintosh OS X (CoreAudio and Jack), and Windows
(DirectSound and ASIO) operating systems.
RtAudio WWW site: http://www.music.mcgill.ca/~gary/rtaudio/
RtAudio: realtime audio i/o C++ classes
- Copyright (c) 2001-2008 Gary P. Scavone
+ Copyright (c) 2001-2009 Gary P. Scavone
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files
@@ -42,7 +42,7 @@
\file RtAudio.h
*/
-// RtAudio: Version 4.0.4
+// RtAudio: Version 4.0.5
#ifndef __RTAUDIO_H
#define __RTAUDIO_H
@@ -108,11 +108,15 @@ static const RtAudioFormat RTAUDIO_FLOAT64 = 0x20; // Normalized between plus/mi
If the RTAUDIO_HOG_DEVICE flag is set, RtAudio will attempt to
open the input and/or output stream device(s) for exclusive use.
Note that this is not possible with all supported audio APIs.
+
+ If the RTAUDIO_SCHEDULE_REALTIME flag is set, RtAudio will attempt
+ to select realtime scheduling (round-robin) for the callback thread.
*/
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.
/*! \typedef typedef unsigned long RtAudioStreamStatus;
\brief RtAudio stream status (over- or underflow) flags.
@@ -240,9 +244,10 @@ class RtAudio
The following flags can be OR'ed together to allow a client to
make changes to the default stream behavior:
- - \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_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_SCHEDULE_REALTIME: Attempt to select realtime scheduling for callback thread.
By default, RtAudio streams pass and receive audio data from the
client in an interleaved format. By passing the
@@ -268,6 +273,11 @@ class RtAudio
open the input and/or output stream device(s) for exclusive use.
Note that this is not possible with all supported audio APIs.
+ 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.
+
The \c numberOfBuffers parameter can be used to control stream
latency in the Windows DirectSound, Linux OSS, and Linux Alsa APIs
only. A value of two is usually the smallest allowed. Larger
@@ -285,10 +295,11 @@ class RtAudio
RtAudioStreamFlags flags; /*!< A bit-mask of stream flags (RTAUDIO_NONINTERLEAVED, RTAUDIO_MINIMIZE_LATENCY, RTAUDIO_HOG_DEVICE). */
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). */
// Default constructor.
StreamOptions()
- : flags(0), numberOfBuffers(0) {}
+ : flags(0), numberOfBuffers(0), priority(0) {}
};
//! A static function to determine the available compiled audio APIs.
@@ -440,10 +451,10 @@ class RtAudio
void abortStream( void );
//! Returns true if a stream is open and false if not.
- bool isStreamOpen( void ) throw();
+ bool isStreamOpen( void ) const throw();
//! Returns true if the stream is running and false if it is stopped or not open.
- bool isStreamRunning( void ) throw();
+ bool isStreamRunning( void ) const throw();
//! Returns the number of elapsed seconds since the stream was started.
/*!
@@ -462,6 +473,14 @@ class RtAudio
*/
long getStreamLatency( void );
+ //! Returns actual sample rate in use by the stream.
+ /*!
+ On some systems, the sample rate used may be slightly different
+ than that specified in the stream parameters. If a stream is not
+ open, an RtError (type = INVALID_USE) will be thrown.
+ */
+ unsigned int getStreamSampleRate( void );
+
//! Specify whether warning messages should be printed to stderr.
void showWarnings( bool value = true ) throw();
@@ -551,9 +570,10 @@ public:
virtual void stopStream( void ) = 0;
virtual void abortStream( void ) = 0;
long getStreamLatency( void );
+ unsigned int getStreamSampleRate( void );
virtual double getStreamTime( void );
- bool isStreamOpen( void ) { return stream_.state != STREAM_CLOSED; };
- bool isStreamRunning( void ) { return stream_.state == STREAM_RUNNING; };
+ bool isStreamOpen( void ) const { return stream_.state != STREAM_CLOSED; };
+ bool isStreamRunning( void ) const { return stream_.state == STREAM_RUNNING; };
void showWarnings( bool value ) { showWarnings_ = value; };
@@ -688,9 +708,10 @@ inline void RtAudio :: closeStream( void ) throw() { return rtapi_->closeStream(
inline void RtAudio :: startStream( void ) { return rtapi_->startStream(); }
inline void RtAudio :: stopStream( void ) { return rtapi_->stopStream(); }
inline void RtAudio :: abortStream( void ) { return rtapi_->abortStream(); }
-inline bool RtAudio :: isStreamOpen( void ) throw() { return rtapi_->isStreamOpen(); }
-inline bool RtAudio :: isStreamRunning( void ) throw() { return rtapi_->isStreamRunning(); }
+inline bool RtAudio :: isStreamOpen( void ) const throw() { return rtapi_->isStreamOpen(); }
+inline bool RtAudio :: isStreamRunning( void ) const throw() { return rtapi_->isStreamRunning(); }
inline long RtAudio :: getStreamLatency( void ) { return rtapi_->getStreamLatency(); }
+inline unsigned int RtAudio :: getStreamSampleRate( void ) { return rtapi_->getStreamSampleRate(); };
inline double RtAudio :: getStreamTime( void ) { return rtapi_->getStreamTime(); }
inline void RtAudio :: showWarnings( bool value ) throw() { rtapi_->showWarnings( value ); }
diff --git a/config.guess b/config/config.guess
index 313be34..313be34 100644
--- a/config.guess
+++ b/config/config.guess
diff --git a/config.sub b/config/config.sub
index 7d3f49f..7d3f49f 100755
--- a/config.sub
+++ b/config/config.sub
diff --git a/install.sh b/config/install.sh
index e69de29..e69de29 100755
--- a/install.sh
+++ b/config/install.sh
diff --git a/configure.ac b/configure.ac
index 027dae0..97989d2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,6 @@
# Process this file with autoconf to produce a configure script.
AC_INIT(RtAudio, 4.0, gary@music.mcgill.ca, rtaudio)
+AC_CONFIG_AUX_DIR(config)
AC_CONFIG_SRCDIR(RtAudio.cpp)
AC_CONFIG_FILES([rtaudio-config Makefile tests/Makefile])
@@ -7,8 +8,7 @@ AC_CONFIG_FILES([rtaudio-config Makefile tests/Makefile])
AC_SUBST( GXX, ["no"] )
# Checks for programs.
-AC_PROG_CC
-AC_PROG_CXX(g++ CC c++ cxx)
+AC_PROG_CXX
AC_PROG_RANLIB
AC_PATH_PROG(AR, ar, no)
if [[ $AR = "no" ]] ; then
@@ -19,66 +19,65 @@ fi
AC_HEADER_STDC
AC_CHECK_HEADERS(sys/ioctl.h unistd.h)
-# Checks for typedefs, structures, and compiler characteristics.
-AC_C_CONST
-
# Check for debug
AC_MSG_CHECKING(whether to compile debug version)
AC_ARG_ENABLE(debug,
[ --enable-debug = enable various debug output],
- [AC_SUBST( debug, [-D__RTAUDIO_DEBUG__] ) AC_SUBST( cflags, [-g] ) AC_SUBST( object_path, [Debug] ) AC_MSG_RESULT(yes)],
- [AC_SUBST( debug, [] ) AC_SUBST( cflags, [-O2] ) AC_SUBST( object_path, [Release] ) AC_MSG_RESULT(no)])
+ [AC_SUBST( cppflag, [-D__RTAUDIO_DEBUG__] ) AC_SUBST( cxxflag, [-g] ) AC_SUBST( object_path, [Debug] ) AC_MSG_RESULT(yes)],
+ [AC_SUBST( cppflag, [] ) AC_SUBST( cxxflag, [-O2] ) AC_SUBST( object_path, [Release] ) AC_MSG_RESULT(no)])
+
# Checks for functions
-AC_CHECK_FUNC(gettimeofday, [CFLAGS=$CFLAGS" -DHAVE_GETTIMEOFDAY"], )
+AC_CHECK_FUNC(gettimeofday, [cppflag="$cppflag -DHAVE_GETTIMEOFDAY"], )
+
+# For -I and -D flags
+CPPFLAGS="$CPPFLAGS $cppflag"
+
+# For debugging and optimization ... overwrite default because it has both -g and -O2
+#CXXFLAGS="$CXXFLAGS $cxxflag"
+CXXFLAGS="$cxxflag"
# Check compiler and use -Wall if gnu.
if [test $GXX = "yes" ;] then
- AC_SUBST( warn, [-Wall] )
+ AC_SUBST( cxxflag, [-Wall] )
fi
-CFLAGS="$CFLAGS $cflags"
+CXXFLAGS="$CXXFLAGS $cxxflag"
# Checks for package options and external software
+AC_SUBST( api, [""] )
AC_CANONICAL_HOST
AC_MSG_CHECKING(for audio API)
case $host in
*-*-netbsd*)
- AC_SUBST( sound_api, [-D__LINUX_OSS__] )
AC_MSG_RESULT(using OSS)
- AC_SUBST( audio_apis, [-D__LINUX_OSS__] )
- CFLAGS=$CFLAGS" -lossaudio"
+ api="$api -D__LINUX_OSS__"
+ LIBS="$LIBS -lossaudio"
AC_CHECK_LIB(pthread, pthread_create, , AC_MSG_ERROR(RtAudio requires the pthread library!))
;;
*-*-linux*)
- AC_SUBST( sound_api, [_NO_API_] )
- AC_ARG_WITH(jack, [ --with-jack = choose JACK server support (mac and linux only)], [AC_SUBST( sound_api, [-D__UNIX_JACK__] ) AC_MSG_RESULT(using JACK)], )
- if [test $sound_api = -D__UNIX_JACK__;] then
- TEMP_LIBS=$LIBS
- AC_CHECK_LIB(jack, jack_client_new, , AC_MSG_ERROR(JACK support requires the jack library!))
- AC_CHECK_LIB(asound, snd_pcm_open, , AC_MSG_ERROR(Jack support also requires the asound library!))
- LIBS="`pkg-config --CFLAGS --libs jack` $TEMP_LIBS -lasound"
- audio_apis="-D__UNIX_JACK__"
- fi
+ AC_ARG_WITH(jack, [ --with-jack = choose JACK server support (mac and linux only)], [
+ api="$api -D__UNIX_JACK__"
+ AC_MSG_RESULT(using JACK)
+ AC_CHECK_LIB(jack, jack_client_open, , AC_MSG_ERROR(JACK support requires the jack library!))
+ AC_CHECK_LIB(asound, snd_pcm_open, , AC_MSG_ERROR(Jack support also requires the asound library!))], )
# Look for ALSA flag
- AC_ARG_WITH(alsa, [ --with-alsa = choose native ALSA API support (linux only)], [AC_SUBST( sound_api, [-D__LINUX_ALSA__] ) AC_MSG_RESULT(using ALSA)], )
- if [test $sound_api = -D__LINUX_ALSA__;] then
- AC_CHECK_LIB(asound, snd_pcm_open, , AC_MSG_ERROR(ALSA support requires the asound library!))
- audio_apis="-D__LINUX_ALSA__ $audio_apis"
- fi
+ AC_ARG_WITH(alsa, [ --with-alsa = choose native ALSA API support (linux only)], [
+ api="$api -D__LINUX_ALSA__"
+ AC_MSG_RESULT(using ALSA)
+ AC_CHECK_LIB(asound, snd_pcm_open, , AC_MSG_ERROR(ALSA support requires the asound library!))], )
# Look for OSS flag
- AC_ARG_WITH(oss, [ --with-oss = choose OSS API support (linux only)], [AC_SUBST( sound_api, [-D__LINUX_OSS__] ) AC_MSG_RESULT(using OSS)], )
- if test $sound_api = -D__LINUX_OSS__; then
- audio_apis="-D__LINUX_OSS__ $audio_apis"
- fi
+ AC_ARG_WITH(oss, [ --with-oss = choose OSS API support (linux only)], [
+ api="$api -D__LINUX_OSS__"
+ AC_MSG_RESULT(using OSS)], )
# If no audio api flags specified, use ALSA
- if [test $sound_api = _NO_API_;] then
+ if [test "$api" == "";] then
AC_MSG_RESULT(using ALSA)
- AC_SUBST( audio_apis, [-D__LINUX_ALSA__] )
+ AC_SUBST( api, [-D__LINUX_ALSA__] )
AC_CHECK_LIB(asound, snd_pcm_open, , AC_MSG_ERROR(ALSA support requires the asound library!))
fi
@@ -86,54 +85,47 @@ case $host in
;;
*-apple*)
- AC_SUBST( sound_api, [_NO_API_] )
- AC_ARG_WITH(jack, [ --with-jack = choose JACK server support (unix only)], [AC_SUBST( sound_api, [-D__UNIX_JACK__] ) AC_MSG_RESULT(using JACK)], )
- if [test $sound_api = -D__UNIX_JACK__;] then
- AC_CHECK_LIB(jack, jack_client_new, , AC_MSG_ERROR(JACK support requires the jack library!))
- audio_apis="-D__UNIX_JACK__"
- fi
+ AC_ARG_WITH(jack, [ --with-jack = choose JACK server support (unix only)], [
+ api="$api -D__UNIX_JACK__"
+ AC_MSG_RESULT(using JACK)
+ AC_CHECK_LIB(jack, jack_client_new, , AC_MSG_ERROR(JACK support requires the jack library!))], )
# Look for Core flag
- AC_ARG_WITH(core, [ --with-core = choose CoreAudio API support (mac only)], [AC_SUBST( sound_api, [-D__MACOSX_CORE__] ) AC_MSG_RESULT(using CoreAudio)], )
- if test $sound_api = -D__MACOSX_CORE__; then
+ AC_ARG_WITH(core, [ --with-core = choose CoreAudio API support (mac only)], [
+ api="$api -D__MACOSX_CORE__"
+ AC_MSG_RESULT(using CoreAudio)
AC_CHECK_HEADER(CoreAudio/CoreAudio.h, [], [AC_MSG_ERROR(CoreAudio header files not found!)] )
- AC_SUBST( frameworks, ["-framework CoreAudio -framework CoreFoundation"] )
- audio_apis="-D__MACOSX_CORE__ $audio_apis"
- fi
+ LIBS="$LIBS -framework CoreAudio -framework CoreFoundation" ], )
# If no audio api flags specified, use CoreAudio
- if [test $sound_api = _NO_API_;] then
- AC_SUBST( sound_api, [-D__MACOSX_CORE__] )
+ if [test "$api" == ""; ] then
+ AC_SUBST( api, [-D__MACOSX_CORE__] )
AC_MSG_RESULT(using CoreAudio)
AC_CHECK_HEADER(CoreAudio/CoreAudio.h,
- [AC_SUBST( audio_apis, [-D__MACOSX_CORE__] )],
+ [],
[AC_MSG_ERROR(CoreAudio header files not found!)] )
- AC_SUBST( frameworks, ["-framework CoreAudio -framework CoreFoundation"] )
+ AC_SUBST( LIBS, ["-framework CoreAudio -framework CoreFoundation"] )
fi
AC_CHECK_LIB(pthread, pthread_create, , AC_MSG_ERROR(RtAudio requires the pthread library!))
;;
*-mingw32*)
- AC_SUBST( sound_api, [_NO_API_] )
- AC_ARG_WITH(asio, [ --with-asio = choose ASIO API support (windoze only)], [AC_SUBST( sound_api, [-D__WINDOWS_ASIO__] ) AC_MSG_RESULT(using ASIO)], )
- if [test $sound_api = -D__WINDOWS_ASIO__;] then
- audio_apis="-D__WINDOWS_ASIO__"
- AC_SUBST( objects, ["asio.o asiodrivers.o asiolist.o iasiothiscallresolver.o"] )
- fi
+ AC_ARG_WITH(asio, [ --with-asio = choose ASIO API support (windoze only)], [
+ api="$api -D__WINDOWS_ASIO__"
+ AC_MSG_RESULT(using ASIO)
+ AC_SUBST( objects, ["asio.o asiodrivers.o asiolist.o iasiothiscallresolver.o"] ) ], )
# Look for DirectSound flag
- AC_ARG_WITH(ds, [ --with-ds = choose DirectSound API support (windoze only)], [AC_SUBST( sound_api, [-D__WINDOWS_DS__] ) AC_MSG_RESULT(using DirectSound)], )
- if test $sound_api = -D__WINDOWS_DS__; then
- audio_apis="-D__WINDOWS_DS__ $audio_apis"
- LIBS="-ldsound -lwinmm $LIBS"
- fi
+ AC_ARG_WITH(ds, [ --with-ds = choose DirectSound API support (windoze only)], [
+ api="$api -D__WINDOWS_DS__"
+ AC_MSG_RESULT(using DirectSound)
+ LIBS="-ldsound -lwinmm $LIBS" ], )
# If no audio api flags specified, use DirectSound
- if [test $sound_api = _NO_API_;] then
- AC_SUBST( sound_api, [-D__WINDOWS_DS__] )
+ if [test "$api" == "";] then
+ AC_SUBST( api, [-D__WINDOWS_DS__] )
AC_MSG_RESULT(using DirectSound)
- audio_apis="-D__WINDOWS_DS__"
LIBS="-ldsound -lwinmm $LIBS"
fi
@@ -146,8 +138,7 @@ case $host in
;;
esac
-# Checks for library functions.
-AC_PROG_GCC_TRADITIONAL
+CPPFLAGS="$CPPFLAGS $api"
AC_OUTPUT
diff --git a/doc/doxygen/Doxyfile b/doc/doxygen/Doxyfile
index be6e89c..74ae894 100644
--- a/doc/doxygen/Doxyfile
+++ b/doc/doxygen/Doxyfile
@@ -1,1080 +1,258 @@
-# Doxyfile 1.3.4
-
-# This file describes the settings to be used by the documentation system
-# doxygen (www.doxygen.org) for a project
-#
-# All text after a hash (#) is considered a comment and will be ignored
-# The format is:
-# TAG = value [value, ...]
-# For lists items can also be appended using:
-# TAG += value [value, ...]
-# Values that contain spaces should be placed between quotes (" ")
+# Doxyfile 1.5.6
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
-
-# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
-# by quotes) that should identify the project.
-
+DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = RtAudio
-
-# The PROJECT_NUMBER tag can be used to enter a project or revision number.
-# This could be handy for archiving the generated documentation or
-# if some version control system is used.
-
-PROJECT_NUMBER = 4.0.4
-
-# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
-# base path where the generated documentation will be put.
-# If a relative path is entered, it will be relative to the location
-# where doxygen was started. If left blank the current directory will be used.
-
+PROJECT_NUMBER = 4.0.5
OUTPUT_DIRECTORY = .
-
-# The OUTPUT_LANGUAGE tag is used to specify the language in which all
-# documentation generated by doxygen is written. Doxygen will use this
-# information to generate all constant output in the proper language.
-# The default language is English, other supported languages are:
-# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch,
-# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en
-# (Japanese with English messages), Korean, Norwegian, Polish, Portuguese,
-# Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian.
-
+CREATE_SUBDIRS = NO
OUTPUT_LANGUAGE = English
-
-# This tag can be used to specify the encoding used in the generated output.
-# The encoding is not always determined by the language that is chosen,
-# but also whether or not the output is meant for Windows or non-Windows users.
-# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES
-# forces the Windows encoding (this is the default for the Windows binary),
-# whereas setting the tag to NO uses a Unix-style encoding (the default for
-# all platforms other than Windows).
-
-USE_WINDOWS_ENCODING = NO
-
-# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
-# include brief member descriptions after the members that are listed in
-# the file and class documentation (similar to JavaDoc).
-# Set to NO to disable this.
-
BRIEF_MEMBER_DESC = YES
-
-# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
-# the brief description of a member or function before the detailed description.
-# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
-# brief descriptions will be completely suppressed.
-
REPEAT_BRIEF = YES
-
-# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
-# Doxygen will generate a detailed section even if there is only a brief
-# description.
-
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
ALWAYS_DETAILED_SEC = NO
-
-# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited
-# members of a class in the documentation of that class as if those members were
-# ordinary class members. Constructors, destructors and assignment operators of
-# the base classes will not be shown.
-
INLINE_INHERITED_MEMB = NO
-
-# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
-# path before files name in the file list and in the header files. If set
-# to NO the shortest path that makes the file name unique will be used.
-
FULL_PATH_NAMES = NO
-
-# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
-# can be used to strip a user-defined part of the path. Stripping is
-# only done if one of the specified strings matches the left-hand part of
-# the path. It is allowed to use relative paths in the argument list.
-
STRIP_FROM_PATH =
-
-# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
-# (but less readable) file names. This can be useful is your file systems
-# doesn't support long names like on DOS, Mac, or CD-ROM.
-
+STRIP_FROM_INC_PATH =
SHORT_NAMES = NO
-
-# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
-# will interpret the first line (until the first dot) of a JavaDoc-style
-# comment as the brief description. If set to NO, the JavaDoc
-# comments will behave just like the Qt-style comments (thus requiring an
-# explict @brief command for a brief description.
-
JAVADOC_AUTOBRIEF = NO
-
-# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
-# treat a multi-line C++ special comment block (i.e. a block of //! or ///
-# comments) as a brief description. This used to be the default behaviour.
-# The new default is to treat a multi-line C++ comment block as a detailed
-# description. Set this tag to YES if you prefer the old behaviour instead.
-
+QT_AUTOBRIEF = NO
MULTILINE_CPP_IS_BRIEF = NO
-
-# If the DETAILS_AT_TOP tag is set to YES then Doxygen
-# will output the detailed description near the top, like JavaDoc.
-# If set to NO, the detailed description appears after the member
-# documentation.
-
DETAILS_AT_TOP = NO
-
-# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
-# member inherits the documentation from any documented member that it
-# reimplements.
-
INHERIT_DOCS = YES
-
-# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
-# tag is set to YES, then doxygen will reuse the documentation of the first
-# member in the group (if any) for the other members of the group. By default
-# all members of a group must be documented explicitly.
-
-DISTRIBUTE_GROUP_DOC = NO
-
-# The TAB_SIZE tag can be used to set the number of spaces in a tab.
-# Doxygen uses this value to replace tabs by spaces in code fragments.
-
+SEPARATE_MEMBER_PAGES = NO
TAB_SIZE = 8
-
-# This tag can be used to specify a number of aliases that acts
-# as commands in the documentation. An alias has the form "name=value".
-# For example adding "sideeffect=\par Side Effects:\n" will allow you to
-# put the command \sideeffect (or @sideeffect) in the documentation, which
-# will result in a user-defined paragraph with heading "Side Effects:".
-# You can put \n's in the value part of an alias to insert newlines.
-
ALIASES =
-
-# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
-# only. Doxygen will then generate output that is more tailored for C.
-# For instance, some of the names that are used will be different. The list
-# of all members will be omitted, etc.
-
OPTIMIZE_OUTPUT_FOR_C = NO
-
-# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources
-# only. Doxygen will then generate output that is more tailored for Java.
-# For instance, namespaces will be presented as packages, qualified scopes
-# will look different, etc.
-
OPTIMIZE_OUTPUT_JAVA = NO
-
-# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
-# the same type (for instance a group of public functions) to be put as a
-# subgroup of that type (e.g. under the Public Functions section). Set it to
-# NO to prevent subgrouping. Alternatively, this can be done per class using
-# the \nosubgrouping command.
-
+OPTIMIZE_FOR_FORTRAN = NO
+OPTIMIZE_OUTPUT_VHDL = NO
+BUILTIN_STL_SUPPORT = NO
+CPP_CLI_SUPPORT = NO
+SIP_SUPPORT = NO
+IDL_PROPERTY_SUPPORT = YES
+DISTRIBUTE_GROUP_DOC = NO
SUBGROUPING = YES
-
+TYPEDEF_HIDES_STRUCT = NO
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
-
-# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
-# documentation are documented, even if no documentation was available.
-# Private class members and static file members will be hidden unless
-# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
-
EXTRACT_ALL = NO
-
-# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
-# will be included in the documentation.
-
EXTRACT_PRIVATE = NO
-
-# If the EXTRACT_STATIC tag is set to YES all static members of a file
-# will be included in the documentation.
-
EXTRACT_STATIC = NO
-
-# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
-# defined locally in source files will be included in the documentation.
-# If set to NO only classes defined in header files are included.
-
EXTRACT_LOCAL_CLASSES = YES
-
-# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
-# undocumented members of documented classes, files or namespaces.
-# If set to NO (the default) these members will be included in the
-# various overviews, but no documentation section is generated.
-# This option has no effect if EXTRACT_ALL is enabled.
-
+EXTRACT_LOCAL_METHODS = NO
+EXTRACT_ANON_NSPACES = NO
HIDE_UNDOC_MEMBERS = YES
-
-# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
-# undocumented classes that are normally visible in the class hierarchy.
-# If set to NO (the default) these classes will be included in the various
-# overviews. This option has no effect if EXTRACT_ALL is enabled.
-
HIDE_UNDOC_CLASSES = YES
-
-# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
-# friend (class|struct|union) declarations.
-# If set to NO (the default) these declarations will be included in the
-# documentation.
-
HIDE_FRIEND_COMPOUNDS = NO
-
-# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
-# documentation blocks found inside the body of a function.
-# If set to NO (the default) these blocks will be appended to the
-# function's detailed documentation block.
-
HIDE_IN_BODY_DOCS = NO
-
-# The INTERNAL_DOCS tag determines if documentation
-# that is typed after a \internal command is included. If the tag is set
-# to NO (the default) then the documentation will be excluded.
-# Set it to YES to include the internal documentation.
-
INTERNAL_DOCS = NO
-
-# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
-# file names in lower-case letters. If set to YES upper-case letters are also
-# allowed. This is useful if you have classes or files whose names only differ
-# in case and if your file system supports case sensitive file names. Windows
-# users are advised to set this option to NO.
-
CASE_SENSE_NAMES = YES
-
-# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
-# will show members with their full class and namespace scopes in the
-# documentation. If set to YES the scope will be hidden.
-
HIDE_SCOPE_NAMES = NO
-
-# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
-# will put a list of the files that are included by a file in the documentation
-# of that file.
-
SHOW_INCLUDE_FILES = YES
-
-# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
-# is inserted in the documentation for inline members.
-
INLINE_INFO = YES
-
-# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
-# will sort the (detailed) documentation of file and class members
-# alphabetically by member name. If set to NO the members will appear in
-# declaration order.
-
SORT_MEMBER_DOCS = NO
-
-# The GENERATE_TODOLIST tag can be used to enable (YES) or
-# disable (NO) the todo list. This list is created by putting \todo
-# commands in the documentation.
-
+SORT_BRIEF_DOCS = NO
+SORT_GROUP_NAMES = NO
+SORT_BY_SCOPE_NAME = NO
GENERATE_TODOLIST = YES
-
-# The GENERATE_TESTLIST tag can be used to enable (YES) or
-# disable (NO) the test list. This list is created by putting \test
-# commands in the documentation.
-
GENERATE_TESTLIST = YES
-
-# The GENERATE_BUGLIST tag can be used to enable (YES) or
-# disable (NO) the bug list. This list is created by putting \bug
-# commands in the documentation.
-
GENERATE_BUGLIST = YES
-
-# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
-# disable (NO) the deprecated list. This list is created by putting
-# \deprecated commands in the documentation.
-
GENERATE_DEPRECATEDLIST= YES
-
-# The ENABLED_SECTIONS tag can be used to enable conditional
-# documentation sections, marked by \if sectionname ... \endif.
-
ENABLED_SECTIONS =
-
-# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
-# the initial value of a variable or define consists of for it to appear in
-# the documentation. If the initializer consists of more lines than specified
-# here it will be hidden. Use a value of 0 to hide initializers completely.
-# The appearance of the initializer of individual variables and defines in the
-# documentation can be controlled using \showinitializer or \hideinitializer
-# command in the documentation regardless of this setting.
-
MAX_INITIALIZER_LINES = 30
-
-# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
-# at the bottom of the documentation of classes and structs. If set to YES the
-# list will mention the files that were used to generate the documentation.
-
SHOW_USED_FILES = YES
-
+SHOW_DIRECTORIES = NO
+SHOW_FILES = YES
+SHOW_NAMESPACES = YES
+FILE_VERSION_FILTER =
#---------------------------------------------------------------------------
# configuration options related to warning and progress messages
#---------------------------------------------------------------------------
-
-# The QUIET tag can be used to turn on/off the messages that are generated
-# by doxygen. Possible values are YES and NO. If left blank NO is used.
-
QUIET = NO
-
-# The WARNINGS tag can be used to turn on/off the warning messages that are
-# generated by doxygen. Possible values are YES and NO. If left blank
-# NO is used.
-
WARNINGS = YES
-
-# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
-# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
-# automatically be disabled.
-
WARN_IF_UNDOCUMENTED = YES
-
-# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
-# potential errors in the documentation, such as not documenting some
-# parameters in a documented function, or documenting parameters that
-# don't exist or using markup commands wrongly.
-
WARN_IF_DOC_ERROR = YES
-
-# The WARN_FORMAT tag determines the format of the warning messages that
-# doxygen can produce. The string should contain the $file, $line, and $text
-# tags, which will be replaced by the file and line number from which the
-# warning originated and the warning text.
-
+WARN_NO_PARAMDOC = NO
WARN_FORMAT = "$file:$line: $text"
-
-# The WARN_LOGFILE tag can be used to specify a file to which warning
-# and error messages should be written. If left blank the output is written
-# to stderr.
-
WARN_LOGFILE =
-
#---------------------------------------------------------------------------
# configuration options related to the input files
#---------------------------------------------------------------------------
-
-# The INPUT tag can be used to specify the files and/or directories that contain
-# documented source files. You may enter file names like "myfile.cpp" or
-# directories like "/usr/src/myproject". Separate the files or directories
-# with spaces.
-
INPUT = . \
../../RtAudio.h \
../../RtError.h
-
-# If the value of the INPUT tag contains directories, you can use the
-# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
-# and *.h) to filter out the source-files in the directories. If left
-# blank the following patterns are tested:
-# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp
-# *.h++ *.idl *.odl *.cs *.php *.php3 *.inc
-
+INPUT_ENCODING = UTF-8
FILE_PATTERNS = *.txt
-
-# The RECURSIVE tag can be used to turn specify whether or not subdirectories
-# should be searched for input files as well. Possible values are YES and NO.
-# If left blank NO is used.
-
RECURSIVE = NO
-
-# The EXCLUDE tag can be used to specify files and/or directories that should
-# excluded from the INPUT source files. This way you can easily exclude a
-# subdirectory from a directory tree whose root is specified with the INPUT tag.
-
EXCLUDE =
-
-# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories
-# that are symbolic links (a Unix filesystem feature) are excluded from the input.
-
EXCLUDE_SYMLINKS = NO
-
-# If the value of the INPUT tag contains directories, you can use the
-# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
-# certain files from those directories.
-
EXCLUDE_PATTERNS =
-
-# The EXAMPLE_PATH tag can be used to specify one or more files or
-# directories that contain example code fragments that are included (see
-# the \include command).
-
+EXCLUDE_SYMBOLS =
EXAMPLE_PATH = ../../tests/
-
-# If the value of the EXAMPLE_PATH tag contains directories, you can use the
-# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
-# and *.h) to filter out the source-files in the directories. If left
-# blank all files are included.
-
EXAMPLE_PATTERNS =
-
-# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
-# searched for input files to be used with the \include or \dontinclude
-# commands irrespective of the value of the RECURSIVE tag.
-# Possible values are YES and NO. If left blank NO is used.
-
EXAMPLE_RECURSIVE = NO
-
-# The IMAGE_PATH tag can be used to specify one or more files or
-# directories that contain image that are included in the documentation (see
-# the \image command).
-
IMAGE_PATH =
-
-# The INPUT_FILTER tag can be used to specify a program that doxygen should
-# invoke to filter for each input file. Doxygen will invoke the filter program
-# by executing (via popen()) the command <filter> <input-file>, where <filter>
-# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
-# input file. Doxygen will then use the output that the filter program writes
-# to standard output.
-
INPUT_FILTER =
-
-# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
-# INPUT_FILTER) will be used to filter the input files when producing source
-# files to browse (i.e. when SOURCE_BROWSER is set to YES).
-
+FILTER_PATTERNS =
FILTER_SOURCE_FILES = NO
-
#---------------------------------------------------------------------------
# configuration options related to source browsing
#---------------------------------------------------------------------------
-
-# If the SOURCE_BROWSER tag is set to YES then a list of source files will
-# be generated. Documented entities will be cross-referenced with these sources.
-
SOURCE_BROWSER = NO
-
-# Setting the INLINE_SOURCES tag to YES will include the body
-# of functions and classes directly in the documentation.
-
INLINE_SOURCES = NO
-
-# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
-# doxygen to hide any special comment blocks from generated source code
-# fragments. Normal C and C++ comments will always remain visible.
-
STRIP_CODE_COMMENTS = YES
-
-# If the REFERENCED_BY_RELATION tag is set to YES (the default)
-# then for each documented function all documented
-# functions referencing it will be listed.
-
REFERENCED_BY_RELATION = YES
-
-# If the REFERENCES_RELATION tag is set to YES (the default)
-# then for each documented function all documented entities
-# called/used by that function will be listed.
-
REFERENCES_RELATION = YES
-
-# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
-# will generate a verbatim copy of the header file for each class for
-# which an include is specified. Set to NO to disable this.
-
+REFERENCES_LINK_SOURCE = YES
+USE_HTAGS = NO
VERBATIM_HEADERS = YES
-
#---------------------------------------------------------------------------
# configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
-
-# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
-# of all compounds will be generated. Enable this if the project
-# contains a lot of classes, structs, unions or interfaces.
-
ALPHABETICAL_INDEX = NO
-
-# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
-# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
-# in which this list will be split (can be a number in the range [1..20])
-
COLS_IN_ALPHA_INDEX = 5
-
-# In case all classes in a project start with a common prefix, all
-# classes will be put under the same header in the alphabetical index.
-# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
-# should be ignored while generating the index headers.
-
IGNORE_PREFIX =
-
#---------------------------------------------------------------------------
# configuration options related to the HTML output
#---------------------------------------------------------------------------
-
-# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
-# generate HTML output.
-
GENERATE_HTML = YES
-
-# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `html' will be used as the default path.
-
HTML_OUTPUT = ../html
-
-# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
-# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
-# doxygen will generate files with .html extension.
-
HTML_FILE_EXTENSION = .html
-
-# The HTML_HEADER tag can be used to specify a personal HTML header for
-# each generated HTML page. If it is left blank doxygen will generate a
-# standard header.
-
HTML_HEADER = header.html
-
-# The HTML_FOOTER tag can be used to specify a personal HTML footer for
-# each generated HTML page. If it is left blank doxygen will generate a
-# standard footer.
-
HTML_FOOTER = footer.html
-
-# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
-# style sheet that is used by each HTML page. It can be used to
-# fine-tune the look of the HTML output. If the tag is left blank doxygen
-# will generate a default style sheet
-
HTML_STYLESHEET =
-
-# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
-# files or namespaces will be aligned in HTML using tables. If set to
-# NO a bullet list will be used.
-
HTML_ALIGN_MEMBERS = YES
-
-# If the GENERATE_HTMLHELP tag is set to YES, additional index files
-# will be generated that can be used as input for tools like the
-# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
-# of the generated HTML documentation.
-
GENERATE_HTMLHELP = NO
-
-# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
-# be used to specify the file name of the resulting .chm file. You
-# can add a path in front of the file if the result should not be
-# written to the html output dir.
-
+GENERATE_DOCSET = NO
+DOCSET_FEEDNAME = "Doxygen generated docs"
+DOCSET_BUNDLE_ID = org.doxygen.Project
+HTML_DYNAMIC_SECTIONS = NO
CHM_FILE =
-
-# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
-# be used to specify the location (absolute path including file name) of
-# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
-# the HTML help compiler on the generated index.hhp.
-
HHC_LOCATION =
-
-# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
-# controls if a separate .chi index file is generated (YES) or that
-# it should be included in the master .chm file (NO).
-
GENERATE_CHI = NO
-
-# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
-# controls whether a binary table of contents is generated (YES) or a
-# normal table of contents (NO) in the .chm file.
-
+CHM_INDEX_ENCODING =
BINARY_TOC = NO
-
-# The TOC_EXPAND flag can be set to YES to add extra items for group members
-# to the contents of the HTML help documentation and to the tree view.
-
TOC_EXPAND = NO
-
-# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
-# top of each HTML page. The value NO (the default) enables the index and
-# the value YES disables it.
-
DISABLE_INDEX = YES
-
-# This tag can be used to set the number of enum values (range [1..20])
-# that doxygen will group on one line in the generated HTML documentation.
-
ENUM_VALUES_PER_LINE = 4
-
-# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
-# generated containing a tree-like index structure (just like the one that
-# is generated for HTML Help). For this to work a browser that supports
-# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
-# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
-# probably better off using the HTML help feature.
-
GENERATE_TREEVIEW = NO
-
-# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
-# used to set the initial width (in pixels) of the frame in which the tree
-# is shown.
-
TREEVIEW_WIDTH = 250
-
+FORMULA_FONTSIZE = 10
#---------------------------------------------------------------------------
# configuration options related to the LaTeX output
#---------------------------------------------------------------------------
-
-# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
-# generate Latex output.
-
GENERATE_LATEX = NO
-
-# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `latex' will be used as the default path.
-
LATEX_OUTPUT = latex
-
-# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
-# invoked. If left blank `latex' will be used as the default command name.
-
LATEX_CMD_NAME = latex
-
-# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
-# generate index for LaTeX. If left blank `makeindex' will be used as the
-# default command name.
-
MAKEINDEX_CMD_NAME = makeindex
-
-# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
-# LaTeX documents. This may be useful for small projects and may help to
-# save some trees in general.
-
COMPACT_LATEX = NO
-
-# The PAPER_TYPE tag can be used to set the paper type that is used
-# by the printer. Possible values are: a4, a4wide, letter, legal and
-# executive. If left blank a4wide will be used.
-
PAPER_TYPE = letter
-
-# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
-# packages that should be included in the LaTeX output.
-
EXTRA_PACKAGES =
-
-# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
-# the generated latex document. The header should contain everything until
-# the first chapter. If it is left blank doxygen will generate a
-# standard header. Notice: only use this tag if you know what you are doing!
-
LATEX_HEADER =
-
-# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
-# is prepared for conversion to pdf (using ps2pdf). The pdf file will
-# contain links (just like the HTML output) instead of page references
-# This makes the output suitable for online browsing using a pdf viewer.
-
PDF_HYPERLINKS = NO
-
-# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
-# plain latex in the generated Makefile. Set this option to YES to get a
-# higher quality PDF documentation.
-
USE_PDFLATEX = YES
-
-# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
-# command to the generated LaTeX files. This will instruct LaTeX to keep
-# running if errors occur, instead of asking the user for help.
-# This option is also used when generating formulas in HTML.
-
LATEX_BATCHMODE = NO
-
-# If LATEX_HIDE_INDICES is set to YES then doxygen will not
-# include the index chapters (such as File Index, Compound Index, etc.)
-# in the output.
-
LATEX_HIDE_INDICES = NO
-
#---------------------------------------------------------------------------
# configuration options related to the RTF output
#---------------------------------------------------------------------------
-
-# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
-# The RTF output is optimised for Word 97 and may not look very pretty with
-# other RTF readers or editors.
-
GENERATE_RTF = NO
-
-# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `rtf' will be used as the default path.
-
RTF_OUTPUT = rtf
-
-# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
-# RTF documents. This may be useful for small projects and may help to
-# save some trees in general.
-
COMPACT_RTF = NO
-
-# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
-# will contain hyperlink fields. The RTF file will
-# contain links (just like the HTML output) instead of page references.
-# This makes the output suitable for online browsing using WORD or other
-# programs which support those fields.
-# Note: wordpad (write) and others do not support links.
-
RTF_HYPERLINKS = NO
-
-# Load stylesheet definitions from file. Syntax is similar to doxygen's
-# config file, i.e. a series of assigments. You only have to provide
-# replacements, missing definitions are set to their default value.
-
RTF_STYLESHEET_FILE =
-
-# Set optional variables used in the generation of an rtf document.
-# Syntax is similar to doxygen's config file.
-
RTF_EXTENSIONS_FILE =
-
#---------------------------------------------------------------------------
# configuration options related to the man page output
#---------------------------------------------------------------------------
-
-# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
-# generate man pages
-
GENERATE_MAN = NO
-
-# The MAN_OUTPUT tag is used to specify where the man pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `man' will be used as the default path.
-
MAN_OUTPUT = man
-
-# The MAN_EXTENSION tag determines the extension that is added to
-# the generated man pages (default is the subroutine's section .3)
-
MAN_EXTENSION = .3
-
-# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
-# then it will generate one additional man file for each entity
-# documented in the real man page(s). These additional files
-# only source the real man page, but without them the man command
-# would be unable to find the correct page. The default is NO.
-
MAN_LINKS = NO
-
#---------------------------------------------------------------------------
# configuration options related to the XML output
#---------------------------------------------------------------------------
-
-# If the GENERATE_XML tag is set to YES Doxygen will
-# generate an XML file that captures the structure of
-# the code including all documentation. Note that this
-# feature is still experimental and incomplete at the
-# moment.
-
GENERATE_XML = NO
-
-# The XML_OUTPUT tag is used to specify where the XML pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `xml' will be used as the default path.
-
XML_OUTPUT = xml
-
-# The XML_SCHEMA tag can be used to specify an XML schema,
-# which can be used by a validating XML parser to check the
-# syntax of the XML files.
-
XML_SCHEMA =
-
-# The XML_DTD tag can be used to specify an XML DTD,
-# which can be used by a validating XML parser to check the
-# syntax of the XML files.
-
XML_DTD =
-
+XML_PROGRAMLISTING = YES
#---------------------------------------------------------------------------
# configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
-
-# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
-# generate an AutoGen Definitions (see autogen.sf.net) file
-# that captures the structure of the code including all
-# documentation. Note that this feature is still experimental
-# and incomplete at the moment.
-
GENERATE_AUTOGEN_DEF = NO
-
#---------------------------------------------------------------------------
# configuration options related to the Perl module output
#---------------------------------------------------------------------------
-
-# If the GENERATE_PERLMOD tag is set to YES Doxygen will
-# generate a Perl module file that captures the structure of
-# the code including all documentation. Note that this
-# feature is still experimental and incomplete at the
-# moment.
-
GENERATE_PERLMOD = NO
-
-# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
-# the necessary Makefile rules, Perl scripts and LaTeX code to be able
-# to generate PDF and DVI output from the Perl module output.
-
PERLMOD_LATEX = NO
-
-# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
-# nicely formatted so it can be parsed by a human reader. This is useful
-# if you want to understand what is going on. On the other hand, if this
-# tag is set to NO the size of the Perl module output will be much smaller
-# and Perl will parse it just the same.
-
PERLMOD_PRETTY = YES
-
-# The names of the make variables in the generated doxyrules.make file
-# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
-# This is useful so different doxyrules.make files included by the same
-# Makefile don't overwrite each other's variables.
-
PERLMOD_MAKEVAR_PREFIX =
-
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
-
-# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
-# evaluate all C-preprocessor directives found in the sources and include
-# files.
-
ENABLE_PREPROCESSING = YES
-
-# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
-# names in the source code. If set to NO (the default) only conditional
-# compilation will be performed. Macro expansion can be done in a controlled
-# way by setting EXPAND_ONLY_PREDEF to YES.
-
MACRO_EXPANSION = NO
-
-# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
-# then the macro expansion is limited to the macros specified with the
-# PREDEFINED and EXPAND_AS_PREDEFINED tags.
-
EXPAND_ONLY_PREDEF = NO
-
-# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
-# in the INCLUDE_PATH (see below) will be search if a #include is found.
-
SEARCH_INCLUDES = YES
-
-# The INCLUDE_PATH tag can be used to specify one or more directories that
-# contain include files that are not input files but should be processed by
-# the preprocessor.
-
INCLUDE_PATH =
-
-# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
-# patterns (like *.h and *.hpp) to filter out the header-files in the
-# directories. If left blank, the patterns specified with FILE_PATTERNS will
-# be used.
-
INCLUDE_FILE_PATTERNS =
-
-# The PREDEFINED tag can be used to specify one or more macro names that
-# are defined before the preprocessor is started (similar to the -D option of
-# gcc). The argument of the tag is a list of macros of the form: name
-# or name=definition (no spaces). If the definition and the = are
-# omitted =1 is assumed.
-
PREDEFINED =
-
-# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
-# this tag can be used to specify a list of macro names that should be expanded.
-# The macro definition that is found in the sources will be used.
-# Use the PREDEFINED tag if you want to use a different macro definition.
-
EXPAND_AS_DEFINED =
-
-# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
-# doxygen's preprocessor will remove all function-like macros that are alone
-# on a line, have an all uppercase name, and do not end with a semicolon. Such
-# function macros are typically used for boiler-plate code, and will confuse the
-# parser if not removed.
-
SKIP_FUNCTION_MACROS = YES
-
#---------------------------------------------------------------------------
-# Configuration::addtions related to external references
+# Configuration::additions related to external references
#---------------------------------------------------------------------------
-
-# The TAGFILES option can be used to specify one or more tagfiles.
-# Optionally an initial location of the external documentation
-# can be added for each tagfile. The format of a tag file without
-# this location is as follows:
-# TAGFILES = file1 file2 ...
-# Adding location for the tag files is done as follows:
-# TAGFILES = file1=loc1 "file2 = loc2" ...
-# where "loc1" and "loc2" can be relative or absolute paths or
-# URLs. If a location is present for each tag, the installdox tool
-# does not have to be run to correct the links.
-# Note that each tag file must have a unique name
-# (where the name does NOT include the path)
-# If a tag file is not located in the directory in which doxygen
-# is run, you must also specify the path to the tagfile here.
-
TAGFILES =
-
-# When a file name is specified after GENERATE_TAGFILE, doxygen will create
-# a tag file that is based on the input files it reads.
-
GENERATE_TAGFILE =
-
-# If the ALLEXTERNALS tag is set to YES all external classes will be listed
-# in the class index. If set to NO only the inherited external classes
-# will be listed.
-
ALLEXTERNALS = NO
-
-# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
-# in the modules index. If set to NO, only the current project's groups will
-# be listed.
-
EXTERNAL_GROUPS = YES
-
-# The PERL_PATH should be the absolute path and name of the perl script
-# interpreter (i.e. the result of `which perl').
-
PERL_PATH = /usr/bin/perl
-
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
-
-# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
-# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base or
-# super classes. Setting the tag to NO turns the diagrams off. Note that this
-# option is superceded by the HAVE_DOT option below. This is only a fallback. It is
-# recommended to install and use dot, since it yields more powerful graphs.
-
CLASS_DIAGRAMS = YES
-
-# If set to YES, the inheritance and collaboration graphs will hide
-# inheritance and usage relations if the target is undocumented
-# or is not a class.
-
+MSCGEN_PATH = /Applications/Doxygen.app/Contents/Resources/
HIDE_UNDOC_RELATIONS = YES
-
-# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
-# available from the path. This tool is part of Graphviz, a graph visualization
-# toolkit from AT&T and Lucent Bell Labs. The other options in this section
-# have no effect if this option is set to NO (the default)
-
HAVE_DOT = NO
-
-# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for each documented class showing the direct and
-# indirect inheritance relations. Setting this tag to YES will force the
-# the CLASS_DIAGRAMS tag to NO.
-
+DOT_FONTNAME = FreeSans
+DOT_FONTPATH =
CLASS_GRAPH = YES
-
-# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for each documented class showing the direct and
-# indirect implementation dependencies (inheritance, containment, and
-# class references variables) of the class with other documented classes.
-
COLLABORATION_GRAPH = YES
-
-# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
-# collaboration diagrams in a style similiar to the OMG's Unified Modeling
-# Language.
-
+GROUP_GRAPHS = YES
UML_LOOK = NO
-
-# If set to YES, the inheritance and collaboration graphs will show the
-# relations between templates and their instances.
-
TEMPLATE_RELATIONS = NO
-
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
-# tags are set to YES then doxygen will generate a graph for each documented
-# file showing the direct and indirect include dependencies of the file with
-# other documented files.
-
INCLUDE_GRAPH = YES
-
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
-# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
-# documented header file showing the documented files that directly or
-# indirectly include this file.
-
INCLUDED_BY_GRAPH = YES
-
-# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will
-# generate a call dependency graph for every global function or class method.
-# Note that enabling this option will significantly increase the time of a run.
-# So in most cases it will be better to enable call graphs for selected
-# functions only using the \callgraph command.
-
CALL_GRAPH = NO
-
-# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
-# will graphical hierarchy of all classes instead of a textual one.
-
+CALLER_GRAPH = NO
GRAPHICAL_HIERARCHY = YES
-
-# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
-# generated by dot. Possible values are png, jpg, or gif
-# If left blank png will be used.
-
+DIRECTORY_GRAPH = YES
DOT_IMAGE_FORMAT = png
-
-# The tag DOT_PATH can be used to specify the path where the dot tool can be
-# found. If left blank, it is assumed the dot tool can be found on the path.
-
-DOT_PATH =
-
-# The DOTFILE_DIRS tag can be used to specify one or more directories that
-# contain dot files that are included in the documentation (see the
-# \dotfile command).
-
+DOT_PATH = /Applications/Doxygen.app/Contents/Resources/
DOTFILE_DIRS =
-
-# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
-# (in pixels) of the graphs generated by dot. If a graph becomes larger than
-# this value, doxygen will try to truncate the graph, so that it fits within
-# the specified constraint. Beware that most browsers cannot cope with very
-# large images.
-
-MAX_DOT_GRAPH_WIDTH = 1024
-
-# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height
-# (in pixels) of the graphs generated by dot. If a graph becomes larger than
-# this value, doxygen will try to truncate the graph, so that it fits within
-# the specified constraint. Beware that most browsers cannot cope with very
-# large images.
-
-MAX_DOT_GRAPH_HEIGHT = 1024
-
-# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
-# graphs generated by dot. A depth value of 3 means that only nodes reachable
-# from the root by following a path via at most 3 edges will be shown. Nodes that
-# lay further from the root node will be omitted. Note that setting this option to
-# 1 or 2 may greatly reduce the computation time needed for large code bases. Also
-# note that a graph may be further truncated if the graph's image dimensions are
-# not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH and MAX_DOT_GRAPH_HEIGHT).
-# If 0 is used for the depth value (the default), the graph is not depth-constrained.
-
+DOT_GRAPH_MAX_NODES = 50
MAX_DOT_GRAPH_DEPTH = 0
-
-# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
-# generate a legend page explaining the meaning of the various boxes and
-# arrows in the dot generated graphs.
-
+DOT_TRANSPARENT = YES
+DOT_MULTI_TARGETS = NO
GENERATE_LEGEND = YES
-
-# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
-# remove the intermediate dot files that are used to generate
-# the various graphs.
-
DOT_CLEANUP = YES
-
#---------------------------------------------------------------------------
-# Configuration::addtions related to the search engine
+# Configuration::additions related to the search engine
#---------------------------------------------------------------------------
-
-# The SEARCHENGINE tag specifies whether or not a search engine should be
-# used. If set to NO the values of all tags below this one will be ignored.
-
SEARCHENGINE = NO
diff --git a/doc/doxygen/compiling.txt b/doc/doxygen/compiling.txt
index d7b9a29..79cb314 100644
--- a/doc/doxygen/compiling.txt
+++ b/doc/doxygen/compiling.txt
@@ -2,7 +2,7 @@
\section debug Debugging
-If you are having problems getting RtAudio to run on your system, make sure to pass a value of \e true to the RtAudio::showWarnings() function (this is the default setting). A variety of warning messages will be displayed which may help in determining the problem. Also, try using the programs included in the <tt>tests</tt> directory. The program <tt>audioprobe</tt> displays the queried capabilities of all hardware devices found for all APIs compiled. When using the ALSA API, further information can be displayed by defining the preprocessor definition __RTAUDIO_DEBUG__.
+If you are having problems getting RtAudio to run on your system, make sure to pass a value of \e true to the RtAudio::showWarnings() function (this is the default setting). A variety of warning messages will be displayed which may help in determining the problem. Also, try using the programs included in the <tt>tests</tt> directory. The program <tt>audioprobe</tt> displays the queried capabilities of all hardware devices found for all APIs compiled. When using the ALSA and JACK APIs, further information can be displayed by defining the preprocessor definition __RTAUDIO_DEBUG__.
\section compile Compiling
diff --git a/doc/doxygen/duplex.txt b/doc/doxygen/duplex.txt
index f060602..c76ae73 100644
--- a/doc/doxygen/duplex.txt
+++ b/doc/doxygen/duplex.txt
@@ -5,6 +5,8 @@ Finally, it is easy to use RtAudio for simultaneous audio input/output, or duple
\code
#include "RtAudio.h"
#include <iostream>
+#include <cstdlib>
+#include <cstring>
// Pass-through function.
int inout( void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames,
diff --git a/doc/doxygen/footer.html b/doc/doxygen/footer.html
index 6d2718d..fd6004b 100644
--- a/doc/doxygen/footer.html
+++ b/doc/doxygen/footer.html
@@ -1,7 +1,7 @@
<HR>
<table><tr><td><img src="../images/mcgill.gif" width=165></td>
- <td>&copy;2001-2008 Gary P. Scavone, McGill University. All Rights Reserved.<br>Maintained by <a href="http://www.music.mcgill.ca/~gary/">Gary P. Scavone</a>.</td></tr>
+ <td>&copy;2001-2009 Gary P. Scavone, McGill University. All Rights Reserved.<br>Maintained by <a href="http://www.music.mcgill.ca/~gary/">Gary P. Scavone</a>.</td></tr>
</table>
</BODY>
diff --git a/doc/doxygen/license.txt b/doc/doxygen/license.txt
index abcdc26..f7a2f89 100644
--- a/doc/doxygen/license.txt
+++ b/doc/doxygen/license.txt
@@ -1,7 +1,7 @@
/*! \page license License
RtAudio: a set of realtime audio i/o C++ classes<BR>
- Copyright (c) 2001-2007 Gary P. Scavone
+ Copyright (c) 2001-2009 Gary P. Scavone
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files
diff --git a/doc/doxygen/playback.txt b/doc/doxygen/playback.txt
index 4d5a793..c291f5a 100644
--- a/doc/doxygen/playback.txt
+++ b/doc/doxygen/playback.txt
@@ -5,6 +5,7 @@ In this example, we provide a complete program that demonstrates the use of RtAu
\code
#include "RtAudio.h"
#include <iostream>
+#include <cstdlib>
// Two-channel sawtooth wave generator.
int saw( void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames,
diff --git a/doc/doxygen/recording.txt b/doc/doxygen/recording.txt
index 6316a5c..9b62438 100644
--- a/doc/doxygen/recording.txt
+++ b/doc/doxygen/recording.txt
@@ -6,6 +6,8 @@ Using RtAudio for audio input is almost identical to the way it is used for play
\code
#include "RtAudio.h"
#include <iostream>
+#include <cstdlib>
+#include <cstring>
int record( void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames,
double streamTime, RtAudioStreamStatus status, void *userData )
diff --git a/doc/doxygen/tutorial.txt b/doc/doxygen/tutorial.txt
index 906afe3..7f7d5ae 100644
--- a/doc/doxygen/tutorial.txt
+++ b/doc/doxygen/tutorial.txt
@@ -32,7 +32,7 @@ Devices are now re-enumerated every time the RtAudio::getDeviceCount(), RtAudio:
\section download Download
-Latest Release (24 January 2008): <A href="http://music.mcgill.ca/~gary/rtaudio/release/rtaudio-4.0.4.tar.gz">Version 4.0.4</A>
+Latest Release (2 February 2009): <A href="http://www.music.mcgill.ca/~gary/rtaudio/release/rtaudio-4.0.5.tar.gz">Version 4.0.5</A>
\section documentation Documentation Links
diff --git a/doc/release.txt b/doc/release.txt
index 4bccff8..d42b768 100644
--- a/doc/release.txt
+++ b/doc/release.txt
@@ -1,6 +1,21 @@
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-2008.
+By Gary P. Scavone, 2001-2009.
+
+v4.0.5: (2 February 2009)
+- added support in CoreAudio for arbitrary stream channel configurations
+- added getStreamSampleRate() function because the actual sample rate can sometimes vary slightly from the specified one (thanks to Theo Veenker)
+- added new StreamOptions flag "RTAUDIO_SCHEDULE_REALTIME" and attribute "priority" to StreamOptions (thanks to Theo Veenker)
+- replaced usleep(50000) in callbackEvent() by a wait on condition variable which gets signaled in startStream() (thanks to Theo Veenker)
+- fix for Jack API when user callback function signals stop or abort calls
+- fix to way stream state is changed to avoid infinite loop problem
+- fix to int<->float conversion in convertBuffer() (thanks to Theo Veenker)
+- bug fix in byteSwapBuffer() (thanks to Stefan Muller Arisona and Theo Veenker)
+- fixed a few gcc 4.4 errors in OS-X
+- fixed bug in rtaudio-config script
+- revised configure script and Makefile structures
+- 64-bit fixes in ALSA API (thanks to Stefan Muller Arisona)
+- fixed ASIO sample rate selection bug (thanks to Sasha Zheligovsky)
v4.0.4: (24 January 2008)
- added functionality to allow getDeviceInfo() to work in ALSA for an open device (like ASIO)
diff --git a/install b/install
index 8bdd0ca..70c795f 100644
--- a/install
+++ b/install
@@ -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-2008.
+By Gary P. Scavone, 2001-2009.
To configure and compile (on Unix systems and MinGW):
diff --git a/readme b/readme
index 8228cd3..d73ff91 100644
--- a/readme
+++ b/readme
@@ -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-2008.
+By Gary P. Scavone, 2001-2009.
This distribution of RtAudio contains the following:
@@ -11,7 +11,7 @@ tests/Windows: Visual C++ .net test program workspace and projects
OVERVIEW:
-RtAudio is a set of C++ classes that provide a common API (Application Programming Interface) for realtime audio input/output across Linux (native ALSA, JACK, and OSS), Macintosh OS X, SGI, and Windows (DirectSound and ASIO) operating systems. RtAudio significantly simplifies the process of interacting with computer audio hardware. It was designed with the following objectives:
+RtAudio is a set of C++ classes that provides a common API (Application Programming Interface) for realtime audio input/output across Linux (native ALSA, JACK, and OSS), Macintosh OS X, SGI, and Windows (DirectSound and ASIO) operating systems. RtAudio significantly simplifies the process of interacting with computer audio hardware. It was designed with the following objectives:
- object-oriented C++ design
- simple, common API across all supported platforms
@@ -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-2008 Gary P. Scavone
+ Copyright (c) 2001-2009 Gary P. Scavone
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files
diff --git a/rtaudio-config.in b/rtaudio-config.in
index c689a98..2422b60 100644
--- a/rtaudio-config.in
+++ b/rtaudio-config.in
@@ -1,16 +1,19 @@
#! /bin/sh
if (test "x$#" != "x1") ; then
- echo "Usage: $0 [--libs | --cxxflags]"
+ echo "Usage: $0 [--libs | --cxxflags | --cppflags]"
exit;
fi
-LIBRARY="@LIBS@ @frameworks@"
-CFLAGS="@audio_apis@"
+LIBRARY="@LIBS@"
+CXXFLAGS="@CXXFLAGS@"
+CPPFLAGS="@CPPFLAGS@"
if (test "x$1" == "x--libs") ; then
echo "$LIBRARY"
-elif (test "x$1" == "x--CFLAGS") ; then
- echo "$CFLAGS"
+elif (test "x$1" == "x--cxxflags") ; then
+ echo "$CXXFLAGS"
+elif (test "x$1" == "x--cppflags") ; then
+ echo "$CPPFLAGS"
else
echo "Unknown option: $1"
fi
diff --git a/tests/Makefile.in b/tests/Makefile.in
index 059b5ce..4e93823 100644
--- a/tests/Makefile.in
+++ b/tests/Makefile.in
@@ -11,12 +11,10 @@ vpath %.o $(OBJECT_PATH)
OBJECTS = RtAudio.o @objects@
CC = @CXX@
-DEFS = @debug@
-DEFS += @audio_apis@
-CFLAGS = @CFLAGS@
-CFLAGS += @warn@ -I$(INCLUDE) -I../include
+DEFS = @CPPFLAGS@
+CFLAGS = @CXXFLAGS@
+CFLAGS += -I$(INCLUDE) -I../include
LIBRARY = @LIBS@
-LIBRARY += @frameworks@
%.o : $(SRC_PATH)/%.cpp
$(CC) $(CFLAGS) $(DEFS) -c $(<) -o $(OBJECT_PATH)/$@
@@ -44,11 +42,14 @@ duplex : duplex.cpp $(OBJECTS)
testall : testall.cpp $(OBJECTS)
$(CC) $(CFLAGS) $(DEFS) -o testall testall.cpp $(OBJECT_PATH)/*.o $(LIBRARY)
-
clean :
-rm $(OBJECT_PATH)/*.o
-rm $(PROGRAMS)
-rm -f *.raw *~ *.exe
+ -rm -fR *.dSYM
+
+distclean: clean
+ -rm Makefile
strip :
strip $(PROGRAMS)
diff --git a/tests/duplex.cpp b/tests/duplex.cpp
index f416bad..125b56e 100644
--- a/tests/duplex.cpp
+++ b/tests/duplex.cpp
@@ -10,6 +10,8 @@
#include "RtAudio.h"
#include <iostream>
+#include <cstdlib>
+#include <cstring>
/*
typedef signed long MY_TYPE;
diff --git a/tests/playraw.cpp b/tests/playraw.cpp
index a9e4db1..1ab1600 100644
--- a/tests/playraw.cpp
+++ b/tests/playraw.cpp
@@ -11,16 +11,20 @@
#include "RtAudio.h"
#include <iostream>
+#include <cstdlib>
+#include <cstring>
/*
typedef char MY_TYPE;
#define FORMAT RTAUDIO_SINT8
#define SCALE 127.0
+*/
typedef signed short MY_TYPE;
#define FORMAT RTAUDIO_SINT16
#define SCALE 32767.0
+/*
typedef signed long MY_TYPE;
#define FORMAT RTAUDIO_SINT24
#define SCALE 8388607.0
@@ -28,13 +32,11 @@ typedef signed long MY_TYPE;
typedef signed long MY_TYPE;
#define FORMAT RTAUDIO_SINT32
#define SCALE 2147483647.0
-*/
typedef float MY_TYPE;
#define FORMAT RTAUDIO_FLOAT32
#define SCALE 1.0;
-/*
typedef double MY_TYPE;
#define FORMAT RTAUDIO_FLOAT64
#define SCALE 1.0;
diff --git a/tests/playsaw.cpp b/tests/playsaw.cpp
index c39bcb4..b89d5f9 100644
--- a/tests/playsaw.cpp
+++ b/tests/playsaw.cpp
@@ -10,6 +10,7 @@
#include "RtAudio.h"
#include <iostream>
+#include <cstdlib>
/*
typedef signed long MY_TYPE;
@@ -19,21 +20,21 @@ typedef signed long MY_TYPE;
typedef char MY_TYPE;
#define FORMAT RTAUDIO_SINT8
#define SCALE 127.0
+*/
typedef signed short MY_TYPE;
#define FORMAT RTAUDIO_SINT16
#define SCALE 32767.0
+/*
typedef signed long MY_TYPE;
#define FORMAT RTAUDIO_SINT32
#define SCALE 2147483647.0
-*/
typedef float MY_TYPE;
#define FORMAT RTAUDIO_FLOAT32
#define SCALE 1.0
-/*
typedef double MY_TYPE;
#define FORMAT RTAUDIO_FLOAT64
#define SCALE 1.0
@@ -142,6 +143,7 @@ int main( int argc, char *argv[] )
oParams.firstChannel = offset;
options.flags |= RTAUDIO_HOG_DEVICE;
+ options.flags |= RTAUDIO_SCHEDULE_REALTIME;
#if !defined( USE_INTERLEAVED )
options.flags |= RTAUDIO_NONINTERLEAVED;
#endif
@@ -155,12 +157,12 @@ int main( int argc, char *argv[] )
}
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
- std::cout << "Stream latency = " << dac.getStreamLatency() << "\n" << std::endl;
dac.stopStream();
}
catch ( RtError& e ) {
diff --git a/tests/record.cpp b/tests/record.cpp
index 7fb1317..a56f351 100644
--- a/tests/record.cpp
+++ b/tests/record.cpp
@@ -11,25 +11,27 @@
#include "RtAudio.h"
#include <iostream>
+#include <cstdlib>
+#include <cstring>
/*
typedef char MY_TYPE;
#define FORMAT RTAUDIO_SINT8
+*/
typedef signed short MY_TYPE;
#define FORMAT RTAUDIO_SINT16
+/*
typedef signed long MY_TYPE;
#define FORMAT RTAUDIO_SINT24
typedef signed long MY_TYPE;
#define FORMAT RTAUDIO_SINT32
-*/
typedef float MY_TYPE;
#define FORMAT RTAUDIO_FLOAT32
-/*
typedef double MY_TYPE;
#define FORMAT RTAUDIO_FLOAT64
*/
diff --git a/tests/testall.cpp b/tests/testall.cpp
index 2eeb330..bd9ca74 100644
--- a/tests/testall.cpp
+++ b/tests/testall.cpp
@@ -1,7 +1,7 @@
/******************************************/
/*
testall.cpp
- by Gary P. Scavone, 2007
+ by Gary P. Scavone, 2007-2008
This program will make a variety of calls
to extensively test RtAudio functionality.
@@ -10,6 +10,8 @@
#include "RtAudio.h"
#include <iostream>
+#include <cstdlib>
+#include <cstring>
#define BASE_RATE 0.005
#define TIME 1.0
@@ -17,11 +19,13 @@
void usage( void ) {
// Error function in case of incorrect command-line
// argument specifications
- std::cout << "\nuseage: testall N fs <device> <channelOffset>\n";
+ std::cout << "\nuseage: testall N fs <iDevice> <oDevice> <iChannelOffset> <oChannelOffset>\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 << " 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 );
}
@@ -89,11 +93,11 @@ int inout( void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames,
int main( int argc, char *argv[] )
{
- unsigned int bufferFrames, fs, device = 0, offset = 0;
+ unsigned int bufferFrames, fs, oDevice = 0, iDevice = 0, iOffset = 0, oOffset = 0;
char input;
// minimal command-line checking
- if (argc < 3 || argc > 5 ) usage();
+ if (argc < 3 || argc > 7 ) usage();
RtAudio dac;
if ( dac.getDeviceCount() < 1 ) {
@@ -104,9 +108,13 @@ int main( int argc, char *argv[] )
channels = (unsigned int) atoi( argv[1] );
fs = (unsigned int) atoi( argv[2] );
if ( argc > 3 )
- device = (unsigned int) atoi( argv[3] );
+ iDevice = (unsigned int) atoi( argv[3] );
if ( argc > 4 )
- offset = (unsigned int) atoi( argv[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]);
double *data = (double *) calloc( channels, sizeof( double ) );
@@ -116,9 +124,9 @@ int main( int argc, char *argv[] )
// Set our stream parameters for output only.
bufferFrames = 256;
RtAudio::StreamParameters oParams, iParams;
- oParams.deviceId = device;
+ oParams.deviceId = oDevice;
oParams.nChannels = channels;
- oParams.firstChannel = offset;
+ oParams.firstChannel = oOffset;
RtAudio::StreamOptions options;
options.flags = RTAUDIO_HOG_DEVICE;
@@ -181,9 +189,9 @@ int main( int argc, char *argv[] )
// Now open a duplex stream.
unsigned int bufferBytes;
- iParams.deviceId = device;
+ iParams.deviceId = iDevice;
iParams.nChannels = channels;
- iParams.firstChannel = offset;
+ iParams.firstChannel = iOffset;
options.flags = RTAUDIO_NONINTERLEAVED;
try {
dac.openStream( &oParams, &iParams, RTAUDIO_SINT32, fs, &bufferFrames, &inout, (void *)&bufferBytes, &options );