diff options
| author | Stephen Sinclair <sinclair@music.mcgill.ca> | 2013-10-11 02:06:06 +0200 |
|---|---|---|
| committer | Stephen Sinclair <sinclair@music.mcgill.ca> | 2013-10-11 02:06:06 +0200 |
| commit | 948a7eda7a295de0ac6d677822cd702029705f7a (patch) | |
| tree | ff7209dc976454025bdfe054f34e4a059979c9dd | |
| parent | fa0759941de32b91fd328c7ec412d2dd3255aa1e (diff) | |
| parent | d6fd1442b2fe1bb366c5539354eeb841fc6943a1 (diff) | |
Merge 4.0.12 into releases
| -rw-r--r-- | Makefile.in | 9 | ||||
| -rw-r--r-- | RtAudio.cpp | 500 | ||||
| -rw-r--r-- | RtAudio.h | 112 | ||||
| -rwxr-xr-x | config/config.sub | 10 | ||||
| -rw-r--r-- | configure.ac | 23 | ||||
| -rw-r--r-- | doc/doxygen/Doxyfile | 2 | ||||
| -rw-r--r-- | doc/doxygen/compiling.txt | 2 | ||||
| -rw-r--r-- | doc/doxygen/footer.html | 2 | ||||
| -rw-r--r-- | doc/doxygen/tutorial.txt | 27 | ||||
| -rw-r--r-- | doc/release.txt | 13 | ||||
| -rw-r--r-- | include/asiolist.cpp | 576 | ||||
| -rw-r--r-- | install | 12 | ||||
| -rw-r--r-- | librtaudio.pc.in | 12 | ||||
| -rw-r--r-- | readme | 6 | ||||
| -rw-r--r-- | tests/audioprobe.cpp | 3 | ||||
| -rw-r--r-- | tests/duplex.cpp | 16 | ||||
| -rw-r--r-- | tests/playraw.cpp | 4 | ||||
| -rw-r--r-- | tests/playsaw.cpp | 24 | ||||
| -rw-r--r-- | tests/record.cpp | 12 |
19 files changed, 840 insertions, 525 deletions
diff --git a/Makefile.in b/Makefile.in index c2cdcb1..41685e5 100644 --- a/Makefile.in +++ b/Makefile.in @@ -8,7 +8,7 @@ OBJECTS = RtAudio.o @objects@ STATIC = librtaudio.a SHARED = @sharedlib@ -RELEASE = 4.0.11 +RELEASE = 4.0.12 MAJOR = 4 LIBRARIES = $(STATIC) $(SHARED) @@ -28,9 +28,8 @@ $(LIBRARIES): $(OBJECTS) $(AR) ruv $(STATIC) $(OBJECTS) ranlib $(STATIC) $(CC) -fPIC @libflags@ $(OBJECTS) @LIBS@ - $(LN) -s @sharedname@ $(SHARED) - -# $(CC) -shared $(OBJECTS) -o $(SHARED) @LIBS@ + $(LN) -sf @sharedname@ $(SHARED) + $(LN) -sf @sharedname@ $(SHARED).$(MAJOR) %.o : %.cpp $(CC) $(CFLAGS) $(DEFS) -c $(<) -o $@ @@ -48,7 +47,7 @@ distclean: $(RM) -f $(LIBRARIES) @sharedname@ $(SHARED)* $(RM) -f $(OBJECTS) $(RM) -f *~ - $(RM) -rf config.log config.status autom4te.cache Makefile rtaudio-config + $(RM) -rf config.log config.status autom4te.cache Makefile rtaudio-config librtaudio.pc cd tests && $(MAKE) distclean strip : diff --git a/RtAudio.cpp b/RtAudio.cpp index 823faaf..4b600bd 100644 --- a/RtAudio.cpp +++ b/RtAudio.cpp @@ -10,7 +10,7 @@ RtAudio WWW site: http://www.music.mcgill.ca/~gary/rtaudio/
RtAudio: realtime audio i/o C++ classes
- Copyright (c) 2001-2012 Gary P. Scavone
+ Copyright (c) 2001-2013 Gary P. Scavone
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files
@@ -38,7 +38,7 @@ */
/************************************************************************/
-// RtAudio: Version 4.0.11
+// RtAudio: Version 4.0.12
#include "RtAudio.h"
#include <iostream>
@@ -189,11 +189,12 @@ void RtAudio :: openStream( RtAudio::StreamParameters *outputParameters, RtAudioFormat format, unsigned int sampleRate,
unsigned int *bufferFrames,
RtAudioCallback callback, void *userData,
- RtAudio::StreamOptions *options )
+ RtAudio::StreamOptions *options,
+ RtAudioErrorCallback errorCallback )
{
return rtapi_->openStream( outputParameters, inputParameters, format,
sampleRate, bufferFrames, callback,
- userData, options );
+ userData, options, errorCallback );
}
// *************************************************** //
@@ -224,31 +225,37 @@ void RtApi :: openStream( RtAudio::StreamParameters *oParams, RtAudioFormat format, unsigned int sampleRate,
unsigned int *bufferFrames,
RtAudioCallback callback, void *userData,
- RtAudio::StreamOptions *options )
+ RtAudio::StreamOptions *options,
+ RtAudioErrorCallback errorCallback )
{
if ( stream_.state != STREAM_CLOSED ) {
errorText_ = "RtApi::openStream: a stream is already open!";
error( RtError::INVALID_USE );
+ return;
}
if ( oParams && oParams->nChannels < 1 ) {
errorText_ = "RtApi::openStream: a non-NULL output StreamParameters structure cannot have an nChannels value less than one.";
error( RtError::INVALID_USE );
+ return;
}
if ( iParams && iParams->nChannels < 1 ) {
errorText_ = "RtApi::openStream: a non-NULL input StreamParameters structure cannot have an nChannels value less than one.";
error( RtError::INVALID_USE );
+ return;
}
if ( oParams == NULL && iParams == NULL ) {
errorText_ = "RtApi::openStream: input and output StreamParameters structures are both NULL!";
error( RtError::INVALID_USE );
+ return;
}
if ( formatBytes(format) == 0 ) {
errorText_ = "RtApi::openStream: 'format' parameter value is undefined.";
error( RtError::INVALID_USE );
+ return;
}
unsigned int nDevices = getDeviceCount();
@@ -258,6 +265,7 @@ void RtApi :: openStream( RtAudio::StreamParameters *oParams, if ( oParams->deviceId >= nDevices ) {
errorText_ = "RtApi::openStream: output device parameter value is invalid.";
error( RtError::INVALID_USE );
+ return;
}
}
@@ -267,6 +275,7 @@ void RtApi :: openStream( RtAudio::StreamParameters *oParams, if ( iParams->deviceId >= nDevices ) {
errorText_ = "RtApi::openStream: input device parameter value is invalid.";
error( RtError::INVALID_USE );
+ return;
}
}
@@ -277,7 +286,10 @@ void RtApi :: openStream( RtAudio::StreamParameters *oParams, result = probeDeviceOpen( oParams->deviceId, OUTPUT, oChannels, oParams->firstChannel,
sampleRate, format, bufferFrames, options );
- if ( result == false ) error( RtError::SYSTEM_ERROR );
+ if ( result == false ) {
+ error( RtError::SYSTEM_ERROR );
+ return;
+ }
}
if ( iChannels > 0 ) {
@@ -287,11 +299,13 @@ void RtApi :: openStream( RtAudio::StreamParameters *oParams, if ( result == false ) {
if ( oChannels > 0 ) closeStream();
error( RtError::SYSTEM_ERROR );
+ return;
}
}
stream_.callbackInfo.callback = (void *) callback;
stream_.callbackInfo.userData = userData;
+ stream_.callbackInfo.errorCallback = (void *) errorCallback;
if ( options ) options->numberOfBuffers = stream_.nBuffers;
stream_.state = STREAM_STOPPED;
@@ -315,10 +329,10 @@ void RtApi :: closeStream( void ) return;
}
-bool RtApi :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
- unsigned int firstChannel, unsigned int sampleRate,
- RtAudioFormat format, unsigned int *bufferSize,
- RtAudio::StreamOptions *options )
+bool RtApi :: probeDeviceOpen( unsigned int /*device*/, StreamMode /*mode*/, unsigned int /*channels*/,
+ unsigned int /*firstChannel*/, unsigned int /*sampleRate*/,
+ RtAudioFormat /*format*/, unsigned int * /*bufferSize*/,
+ RtAudio::StreamOptions * /*options*/ )
{
// MUST be implemented in subclasses!
return FAILURE;
@@ -423,8 +437,6 @@ struct CoreHandle { :deviceBuffer(0), drainCounter(0), internalDrain(false) { nStreams[0] = 1; nStreams[1] = 1; id[0] = 0; id[1] = 0; xrun[0] = false; xrun[1] = false; }
};
-ThreadHandle threadId;
-
RtApiCore:: RtApiCore()
{
#if defined( AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER )
@@ -543,11 +555,13 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device ) if ( nDevices == 0 ) {
errorText_ = "RtApiCore::getDeviceInfo: no devices found!";
error( RtError::INVALID_USE );
+ return info;
}
if ( device >= nDevices ) {
errorText_ = "RtApiCore::getDeviceInfo: device ID is invalid!";
error( RtError::INVALID_USE );
+ return info;
}
AudioDeviceID deviceList[ nDevices ];
@@ -736,13 +750,13 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device ) return info;
}
-OSStatus callbackHandler( AudioDeviceID inDevice,
- const AudioTimeStamp* inNow,
- const AudioBufferList* inInputData,
- const AudioTimeStamp* inInputTime,
- AudioBufferList* outOutputData,
- const AudioTimeStamp* inOutputTime,
- void* infoPointer )
+static OSStatus callbackHandler( AudioDeviceID inDevice,
+ const AudioTimeStamp* /*inNow*/,
+ const AudioBufferList* inInputData,
+ const AudioTimeStamp* /*inInputTime*/,
+ AudioBufferList* outOutputData,
+ const AudioTimeStamp* /*inOutputTime*/,
+ void* infoPointer )
{
CallbackInfo *info = (CallbackInfo *) infoPointer;
@@ -753,10 +767,10 @@ OSStatus callbackHandler( AudioDeviceID inDevice, return kAudioHardwareNoError;
}
-OSStatus xrunListener( AudioObjectID inDevice,
- UInt32 nAddresses,
- const AudioObjectPropertyAddress properties[],
- void* handlePointer )
+static OSStatus xrunListener( AudioObjectID /*inDevice*/,
+ UInt32 nAddresses,
+ const AudioObjectPropertyAddress properties[],
+ void* handlePointer )
{
CoreHandle *handle = (CoreHandle *) handlePointer;
for ( UInt32 i=0; i<nAddresses; i++ ) {
@@ -771,10 +785,10 @@ OSStatus xrunListener( AudioObjectID inDevice, return kAudioHardwareNoError;
}
-OSStatus rateListener( AudioObjectID inDevice,
- UInt32 nAddresses,
- const AudioObjectPropertyAddress properties[],
- void* ratePointer )
+static OSStatus rateListener( AudioObjectID inDevice,
+ UInt32 /*nAddresses*/,
+ const AudioObjectPropertyAddress /*properties*/[],
+ void* ratePointer )
{
Float64 *rate = (Float64 *) ratePointer;
@@ -1300,6 +1314,7 @@ bool RtApiCore :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne stream_.deviceBuffer = 0;
}
+ stream_.state = STREAM_CLOSED;
return FAILURE;
}
@@ -1459,7 +1474,7 @@ void RtApiCore :: abortStream( void ) // aborted. It is better to handle it this way because the
// callbackEvent() function probably should return before the AudioDeviceStop()
// function is called.
-extern "C" void *coreStopStream( void *ptr )
+static void *coreStopStream( void *ptr )
{
CallbackInfo *info = (CallbackInfo *) ptr;
RtApiCore *object = (RtApiCore *) info->object;
@@ -1484,6 +1499,7 @@ bool RtApiCore :: callbackEvent( AudioDeviceID deviceId, // Check if we were draining the stream and signal is finished.
if ( handle->drainCounter > 3 ) {
+ ThreadHandle threadId;
stream_.state = STREAM_STOPPING;
if ( handle->internalDrain == true )
@@ -1821,8 +1837,7 @@ struct JackHandle { :client(0), drainCounter(0), internalDrain(false) { ports[0] = 0; ports[1] = 0; xrun[0] = false; xrun[1] = false; }
};
-ThreadHandle threadId;
-void jackSilentError( const char * ) {};
+static void jackSilentError( const char * ) {};
RtApiJack :: RtApiJack()
{
@@ -1911,6 +1926,7 @@ RtAudio::DeviceInfo RtApiJack :: getDeviceInfo( unsigned int device ) jack_client_close( client );
errorText_ = "RtApiJack::getDeviceInfo: device ID is invalid!";
error( RtError::INVALID_USE );
+ return info;
}
// Get the current jack server sample rate.
@@ -1961,7 +1977,7 @@ RtAudio::DeviceInfo RtApiJack :: getDeviceInfo( unsigned int device ) return info;
}
-int jackCallbackHandler( jack_nframes_t nframes, void *infoPointer )
+static int jackCallbackHandler( jack_nframes_t nframes, void *infoPointer )
{
CallbackInfo *info = (CallbackInfo *) infoPointer;
@@ -1975,7 +1991,7 @@ int jackCallbackHandler( jack_nframes_t nframes, void *infoPointer ) // server signals that it is shutting down. It is necessary to handle
// it this way because the jackShutdown() function must return before
// the jack_deactivate() function (in closeStream()) will return.
-extern "C" void *jackCloseStream( void *ptr )
+static void *jackCloseStream( void *ptr )
{
CallbackInfo *info = (CallbackInfo *) ptr;
RtApiJack *object = (RtApiJack *) info->object;
@@ -1984,7 +2000,7 @@ extern "C" void *jackCloseStream( void *ptr ) pthread_exit( NULL );
}
-void jackShutdown( void *infoPointer )
+static void jackShutdown( void *infoPointer )
{
CallbackInfo *info = (CallbackInfo *) infoPointer;
RtApiJack *object = (RtApiJack *) info->object;
@@ -1996,11 +2012,12 @@ void jackShutdown( void *infoPointer ) // other problem occurred and we should close the stream.
if ( object->isStreamRunning() == false ) return;
+ ThreadHandle threadId;
pthread_create( &threadId, NULL, jackCloseStream, info );
std::cerr << "\nRtApiJack: the Jack server is shutting down this client ... stream stopped and closed!!\n" << std::endl;
}
-int jackXrun( void *infoPointer )
+static int jackXrun( void *infoPointer )
{
JackHandle *handle = (JackHandle *) infoPointer;
@@ -2094,8 +2111,17 @@ bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne // Get the latency of the JACK port.
ports = jack_get_ports( client, deviceName.c_str(), NULL, flag );
- if ( ports[ firstChannel ] )
- stream_.latency[mode] = jack_port_get_latency( jack_port_by_name( client, ports[ firstChannel ] ) );
+ if ( ports[ firstChannel ] ) {
+ // Added by Ge Wang
+ jack_latency_callback_mode_t cbmode = (mode == INPUT ? JackCaptureLatency : JackPlaybackLatency);
+ // the range (usually the min and max are equal)
+ jack_latency_range_t latrange; latrange.min = latrange.max = 0;
+ // get the latency range
+ jack_port_get_latency_range( jack_port_by_name( client, ports[firstChannel] ), cbmode, &latrange );
+ // be optimistic, use the min!
+ stream_.latency[mode] = latrange.min;
+ //stream_.latency[mode] = jack_port_get_latency( jack_port_by_name( client, ports[ firstChannel ] ) );
+ }
free( ports );
// The jack server always uses 32-bit floating-point data.
@@ -2409,7 +2435,7 @@ void RtApiJack :: abortStream( void ) // 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 )
+static void *jackStopStream( void *ptr )
{
CallbackInfo *info = (CallbackInfo *) ptr;
RtApiJack *object = (RtApiJack *) info->object;
@@ -2437,6 +2463,7 @@ bool RtApiJack :: callbackEvent( unsigned long nframes ) // Check if we were draining the stream and signal is finished.
if ( handle->drainCounter > 3 ) {
+ ThreadHandle threadId;
stream_.state = STREAM_STOPPING;
if ( handle->internalDrain == true )
@@ -2556,11 +2583,11 @@ bool RtApiJack :: callbackEvent( unsigned long nframes ) #include "asiodrivers.h"
#include <cmath>
-AsioDrivers drivers;
-ASIOCallbacks asioCallbacks;
-ASIODriverInfo driverInfo;
-CallbackInfo *asioCallbackInfo;
-bool asioXRun;
+static AsioDrivers drivers;
+static ASIOCallbacks asioCallbacks;
+static ASIODriverInfo driverInfo;
+static CallbackInfo *asioCallbackInfo;
+static bool asioXRun;
struct AsioHandle {
int drainCounter; // Tracks callback counts when draining
@@ -2574,8 +2601,8 @@ struct AsioHandle { // Function declarations (definitions at end of section)
static const char* getAsioErrorString( ASIOError result );
-void sampleRateChanged( ASIOSampleRate sRate );
-long asioMessages( long selector, long value, void* message, double* opt );
+static void sampleRateChanged( ASIOSampleRate sRate );
+static long asioMessages( long selector, long value, void* message, double* opt );
RtApiAsio :: RtApiAsio()
{
@@ -2618,11 +2645,13 @@ RtAudio::DeviceInfo RtApiAsio :: getDeviceInfo( unsigned int device ) if ( nDevices == 0 ) {
errorText_ = "RtApiAsio::getDeviceInfo: no devices found!";
error( RtError::INVALID_USE );
+ return info;
}
if ( device >= nDevices ) {
errorText_ = "RtApiAsio::getDeviceInfo: device ID is invalid!";
error( RtError::INVALID_USE );
+ return info;
}
// If a stream is already open, we cannot probe other devices. Thus, use the saved results.
@@ -2708,6 +2737,8 @@ RtAudio::DeviceInfo RtApiAsio :: getDeviceInfo( unsigned int device ) info.nativeFormats |= RTAUDIO_FLOAT32;
else if ( channelInfo.type == ASIOSTFloat64MSB || channelInfo.type == ASIOSTFloat64LSB )
info.nativeFormats |= RTAUDIO_FLOAT64;
+ else if ( channelInfo.type == ASIOSTInt24MSB || channelInfo.type == ASIOSTInt24LSB )
+ info.nativeFormats |= RTAUDIO_SINT24;
if ( info.outputChannels > 0 )
if ( getDefaultOutputDevice() == device ) info.isDefaultOutput = true;
@@ -2719,7 +2750,7 @@ RtAudio::DeviceInfo RtApiAsio :: getDeviceInfo( unsigned int device ) return info;
}
-void bufferSwitch( long index, ASIOBool processNow )
+static void bufferSwitch( long index, ASIOBool processNow )
{
RtApiAsio *object = (RtApiAsio *) asioCallbackInfo->object;
object->callbackEvent( index );
@@ -2860,6 +2891,10 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne stream_.deviceFormat[mode] = RTAUDIO_FLOAT64;
if ( channelInfo.type == ASIOSTFloat64MSB ) stream_.doByteSwap[mode] = true;
}
+ else if ( channelInfo.type == ASIOSTInt24MSB || channelInfo.type == ASIOSTInt24LSB ) {
+ stream_.deviceFormat[mode] = RTAUDIO_SINT24;
+ if ( channelInfo.type == ASIOSTInt24MSB ) stream_.doByteSwap[mode] = true;
+ }
if ( stream_.deviceFormat[mode] == 0 ) {
drivers.removeCurrentDriver();
@@ -3215,7 +3250,7 @@ void RtApiAsio :: abortStream() // aborted. It is necessary to handle it this way because the
// callbackEvent() function must return before the ASIOStop()
// function will return.
-extern "C" unsigned __stdcall asioStopStream( void *ptr )
+static unsigned __stdcall asioStopStream( void *ptr )
{
CallbackInfo *info = (CallbackInfo *) ptr;
RtApiAsio *object = (RtApiAsio *) info->object;
@@ -3378,7 +3413,7 @@ bool RtApiAsio :: callbackEvent( long bufferIndex ) return SUCCESS;
}
-void sampleRateChanged( ASIOSampleRate sRate )
+static void sampleRateChanged( ASIOSampleRate sRate )
{
// The ASIO documentation says that this usually only happens during
// external sync. Audio processing is not stopped by the driver,
@@ -3398,7 +3433,7 @@ void sampleRateChanged( ASIOSampleRate sRate ) std::cerr << "\nRtApiAsio: driver reports sample rate changed to " << sRate << " ... stream stopped!!!\n" << std::endl;
}
-long asioMessages( long selector, long value, void* message, double* opt )
+static long asioMessages( long selector, long value, void* message, double* opt )
{
long ret = 0;
@@ -3476,7 +3511,7 @@ static const char* getAsioErrorString( ASIOError result ) const char*message;
};
- static Messages m[] =
+ static const Messages m[] =
{
{ ASE_NotPresent, "Hardware input or output is not present or available." },
{ ASE_HWMalfunction, "Hardware is malfunctioning." },
@@ -3557,7 +3592,7 @@ static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid, static const char* getErrorString( int code );
-extern "C" unsigned __stdcall callbackHandler( void *ptr );
+static unsigned __stdcall callbackHandler( void *ptr );
struct DsDevice {
LPGUID id[2];
@@ -3569,7 +3604,10 @@ struct DsDevice { : found(false) { validId[0] = false; validId[1] = false; }
};
-std::vector< DsDevice > dsDevices;
+struct DsProbeData {
+ bool isInput;
+ std::vector<struct DsDevice>* dsDevices;
+};
RtApiDs :: RtApiDs()
{
@@ -3607,8 +3645,10 @@ unsigned int RtApiDs :: getDeviceCount( void ) dsDevices[i].found = false;
// Query DirectSound devices.
- bool isInput = false;
- HRESULT result = DirectSoundEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &isInput );
+ struct DsProbeData probeInfo;
+ probeInfo.isInput = false;
+ probeInfo.dsDevices = &dsDevices;
+ HRESULT result = DirectSoundEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &probeInfo );
if ( FAILED( result ) ) {
errorStream_ << "RtApiDs::getDeviceCount: error (" << getErrorString( result ) << ") enumerating output devices!";
errorText_ = errorStream_.str();
@@ -3616,8 +3656,8 @@ unsigned int RtApiDs :: getDeviceCount( void ) }
// Query DirectSoundCapture devices.
- isInput = true;
- result = DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &isInput );
+ probeInfo.isInput = true;
+ result = DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &probeInfo );
if ( FAILED( result ) ) {
errorStream_ << "RtApiDs::getDeviceCount: error (" << getErrorString( result ) << ") enumerating input devices!";
errorText_ = errorStream_.str();
@@ -3646,12 +3686,14 @@ RtAudio::DeviceInfo RtApiDs :: getDeviceInfo( unsigned int device ) if ( dsDevices.size() == 0 ) {
errorText_ = "RtApiDs::getDeviceInfo: no devices found!";
error( RtError::INVALID_USE );
+ return info;
}
}
if ( device >= dsDevices.size() ) {
errorText_ = "RtApiDs::getDeviceInfo: device ID is invalid!";
error( RtError::INVALID_USE );
+ return info;
}
HRESULT result;
@@ -3879,7 +3921,7 @@ bool RtApiDs :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned // Determine the device buffer size. By default, we'll use the value
// defined above (32K), but we will grow it to make allowances for
// very large software buffer sizes.
- DWORD dsBufferSize = MINIMUM_DEVICE_BUFFER_SIZE;;
+ DWORD dsBufferSize = MINIMUM_DEVICE_BUFFER_SIZE;
DWORD dsPointerLeadTime = 0;
void *ohandle = 0, *bhandle = 0;
@@ -4306,6 +4348,7 @@ bool RtApiDs :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned stream_.deviceBuffer = 0;
}
+ stream_.state = STREAM_CLOSED;
return FAILURE;
}
@@ -4627,12 +4670,14 @@ void RtApiDs :: callbackEvent() errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";
errorText_ = errorStream_.str();
error( RtError::SYSTEM_ERROR );
+ return;
}
result = dsCaptureBuffer->GetCurrentPosition( NULL, &startSafeReadPointer );
if ( FAILED( result ) ) {
errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";
errorText_ = errorStream_.str();
error( RtError::SYSTEM_ERROR );
+ return;
}
while ( true ) {
result = dsWriteBuffer->GetCurrentPosition( NULL, &safeWritePointer );
@@ -4640,12 +4685,14 @@ void RtApiDs :: callbackEvent() errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";
errorText_ = errorStream_.str();
error( RtError::SYSTEM_ERROR );
+ return;
}
result = dsCaptureBuffer->GetCurrentPosition( NULL, &safeReadPointer );
if ( FAILED( result ) ) {
errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";
errorText_ = errorStream_.str();
error( RtError::SYSTEM_ERROR );
+ return;
}
if ( safeWritePointer != startSafeWritePointer && safeReadPointer != startSafeReadPointer ) break;
Sleep( 1 );
@@ -4666,6 +4713,7 @@ void RtApiDs :: callbackEvent() errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";
errorText_ = errorStream_.str();
error( RtError::SYSTEM_ERROR );
+ return;
}
handle->bufferPointer[0] = safeWritePointer + handle->dsPointerLeadTime[0];
if ( handle->bufferPointer[0] >= handle->dsBufferSize[0] ) handle->bufferPointer[0] -= handle->dsBufferSize[0];
@@ -4716,6 +4764,7 @@ void RtApiDs :: callbackEvent() errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";
errorText_ = errorStream_.str();
error( RtError::SYSTEM_ERROR );
+ return;
}
// We will copy our output buffer into the region between
@@ -4756,6 +4805,7 @@ void RtApiDs :: callbackEvent() errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") locking buffer during playback!";
errorText_ = errorStream_.str();
error( RtError::SYSTEM_ERROR );
+ return;
}
// Copy our buffer into the DS buffer
@@ -4768,6 +4818,7 @@ void RtApiDs :: callbackEvent() errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") unlocking buffer during playback!";
errorText_ = errorStream_.str();
error( RtError::SYSTEM_ERROR );
+ return;
}
nextWritePointer = ( nextWritePointer + bufferSize1 + bufferSize2 ) % dsBufferSize;
handle->bufferPointer[0] = nextWritePointer;
@@ -4802,6 +4853,7 @@ void RtApiDs :: callbackEvent() errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";
errorText_ = errorStream_.str();
error( RtError::SYSTEM_ERROR );
+ return;
}
if ( safeReadPointer < (DWORD)nextReadPointer ) safeReadPointer += dsBufferSize; // unwrap offset
@@ -4862,6 +4914,7 @@ void RtApiDs :: callbackEvent() errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";
errorText_ = errorStream_.str();
error( RtError::SYSTEM_ERROR );
+ return;
}
if ( safeReadPointer < (DWORD)nextReadPointer ) safeReadPointer += dsBufferSize; // unwrap offset
@@ -4875,6 +4928,7 @@ void RtApiDs :: callbackEvent() errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") locking capture buffer!";
errorText_ = errorStream_.str();
error( RtError::SYSTEM_ERROR );
+ return;
}
if ( duplexPrerollBytes <= 0 ) {
@@ -4895,6 +4949,7 @@ void RtApiDs :: callbackEvent() errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") unlocking capture buffer!";
errorText_ = errorStream_.str();
error( RtError::SYSTEM_ERROR );
+ return;
}
handle->bufferPointer[1] = nextReadPointer;
@@ -4916,7 +4971,7 @@ void RtApiDs :: callbackEvent() // Definitions for utility functions and callbacks
// specific to the DirectSound implementation.
-extern "C" unsigned __stdcall callbackHandler( void *ptr )
+static unsigned __stdcall callbackHandler( void *ptr )
{
CallbackInfo *info = (CallbackInfo *) ptr;
RtApiDs *object = (RtApiDs *) info->object;
@@ -4932,12 +4987,12 @@ extern "C" unsigned __stdcall callbackHandler( void *ptr ) #include "tchar.h"
-std::string convertTChar( LPCTSTR name )
+static std::string convertTChar( LPCTSTR name )
{
#if defined( UNICODE ) || defined( _UNICODE )
int length = WideCharToMultiByte(CP_UTF8, 0, name, -1, NULL, 0, NULL, NULL);
- std::string s( length, 0 );
- length = WideCharToMultiByte(CP_UTF8, 0, name, wcslen(name), &s[0], length, NULL, NULL);
+ std::string s( length-1, '\0' );
+ WideCharToMultiByte(CP_UTF8, 0, name, -1, &s[0], length, NULL, NULL);
#else
std::string s( name );
#endif
@@ -4950,11 +5005,12 @@ static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid, LPCTSTR module,
LPVOID lpContext )
{
- bool *isInput = (bool *) lpContext;
+ struct DsProbeData& probeInfo = *(struct DsProbeData*) lpContext;
+ std::vector<struct DsDevice>& dsDevices = *probeInfo.dsDevices;
HRESULT hr;
bool validDevice = false;
- if ( *isInput == true ) {
+ if ( probeInfo.isInput == true ) {
DSCCAPS caps;
LPDIRECTSOUNDCAPTURE object;
@@ -4986,13 +5042,14 @@ static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid, // If good device, then save its name and guid.
std::string name = convertTChar( description );
- if ( name == "Primary Sound Driver" || name == "Primary Sound Capture Driver" )
+ //if ( name == "Primary Sound Driver" || name == "Primary Sound Capture Driver" )
+ if ( lpguid == NULL )
name = "Default Device";
if ( validDevice ) {
for ( unsigned int i=0; i<dsDevices.size(); i++ ) {
if ( dsDevices[i].name == name ) {
dsDevices[i].found = true;
- if ( *isInput ) {
+ if ( probeInfo.isInput ) {
dsDevices[i].id[1] = lpguid;
dsDevices[i].validId[1] = true;
}
@@ -5007,7 +5064,7 @@ static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid, DsDevice device;
device.name = name;
device.found = true;
- if ( *isInput ) {
+ if ( probeInfo.isInput ) {
device.id[1] = lpguid;
device.validId[1] = true;
}
@@ -5096,7 +5153,7 @@ struct AlsaHandle { :synchronized(false), runnable(false) { xrun[0] = false; xrun[1] = false; }
};
-extern "C" void *alsaCallbackHandler( void * ptr );
+static void *alsaCallbackHandler( void * ptr );
RtApiAlsa :: RtApiAlsa()
{
@@ -5145,6 +5202,12 @@ unsigned int RtApiAlsa :: getDeviceCount( void ) snd_card_next( &card );
}
+ result = snd_ctl_open( &handle, "default", 0 );
+ if (result == 0) {
+ nDevices++;
+ snd_ctl_close( handle );
+ }
+
return nDevices;
}
@@ -5191,14 +5254,25 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device ) snd_card_next( &card );
}
+ result = snd_ctl_open( &chandle, "default", SND_CTL_NONBLOCK );
+ if ( result == 0 ) {
+ if ( nDevices == device ) {
+ strcpy( name, "default" );
+ goto foundDevice;
+ }
+ nDevices++;
+ }
+
if ( nDevices == 0 ) {
errorText_ = "RtApiAlsa::getDeviceInfo: no devices found!";
error( RtError::INVALID_USE );
+ return info;
}
if ( device >= nDevices ) {
errorText_ = "RtApiAlsa::getDeviceInfo: device ID is invalid!";
error( RtError::INVALID_USE );
+ return info;
}
foundDevice:
@@ -5224,16 +5298,18 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device ) snd_pcm_hw_params_t *params;
snd_pcm_hw_params_alloca( ¶ms );
- // First try for playback
+ // First try for playback unless default device (which has subdev -1)
stream = SND_PCM_STREAM_PLAYBACK;
- snd_pcm_info_set_device( pcminfo, subdevice );
- snd_pcm_info_set_subdevice( pcminfo, 0 );
snd_pcm_info_set_stream( pcminfo, stream );
+ if ( subdevice != -1 ) {
+ snd_pcm_info_set_device( pcminfo, subdevice );
+ snd_pcm_info_set_subdevice( pcminfo, 0 );
- result = snd_ctl_pcm_info( chandle, pcminfo );
- if ( result < 0 ) {
- // Device probably doesn't support playback.
- goto captureProbe;
+ result = snd_ctl_pcm_info( chandle, pcminfo );
+ if ( result < 0 ) {
+ // Device probably doesn't support playback.
+ goto captureProbe;
+ }
}
result = snd_pcm_open( &phandle, name, stream, openMode | SND_PCM_NONBLOCK );
@@ -5268,16 +5344,18 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device ) snd_pcm_close( phandle );
captureProbe:
- // Now try for capture
stream = SND_PCM_STREAM_CAPTURE;
snd_pcm_info_set_stream( pcminfo, stream );
- result = snd_ctl_pcm_info( chandle, pcminfo );
- snd_ctl_close( chandle );
- if ( result < 0 ) {
- // Device probably doesn't support capture.
- if ( info.outputChannels == 0 ) return info;
- goto probeParameters;
+ // Now try for capture unless default device (with subdev = -1)
+ if ( subdevice != -1 ) {
+ result = snd_ctl_pcm_info( chandle, pcminfo );
+ snd_ctl_close( chandle );
+ if ( result < 0 ) {
+ // Device probably doesn't support capture.
+ if ( info.outputChannels == 0 ) return info;
+ goto probeParameters;
+ }
}
result = snd_pcm_open( &phandle, name, stream, openMode | SND_PCM_NONBLOCK);
@@ -5468,6 +5546,15 @@ bool RtApiAlsa :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne snd_card_next( &card );
}
+ result = snd_ctl_open( &chandle, "default", SND_CTL_NONBLOCK );
+ if ( result == 0 ) {
+ if ( nDevices == device ) {
+ strcpy( name, "default" );
+ goto foundDevice;
+ }
+ nDevices++;
+ }
+
if ( nDevices == 0 ) {
// This should not happen because a check is made before this function is called.
errorText_ = "RtApiAlsa::probeDeviceOpen: no devices found!";
@@ -5866,22 +5953,21 @@ bool RtApiAlsa :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne 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)
if ( options && options->flags & RTAUDIO_SCHEDULE_REALTIME ) {
- struct sched_param param;
+ // We previously attempted to increase the audio callback priority
+ // to SCHED_RR here via the attributes. However, while no errors
+ // were reported in doing so, it did not work. So, now this is
+ // done in the alsaCallbackHandler function.
+ stream_.callbackInfo.doRealtime = true;
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, ¶m );
- pthread_attr_setschedpolicy( &attr, SCHED_RR );
+ stream_.callbackInfo.priority = priority;
}
- else
- pthread_attr_setschedpolicy( &attr, SCHED_OTHER );
-#else
- pthread_attr_setschedpolicy( &attr, SCHED_OTHER );
#endif
stream_.callbackInfo.isRunning = true;
@@ -5919,6 +6005,7 @@ bool RtApiAlsa :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne stream_.deviceBuffer = 0;
}
+ stream_.state = STREAM_CLOSED;
return FAILURE;
}
@@ -6293,12 +6380,20 @@ void RtApiAlsa :: callbackEvent() if ( doStopStream == 1 ) this->stopStream();
}
-extern "C" void *alsaCallbackHandler( void *ptr )
+static void *alsaCallbackHandler( void *ptr )
{
CallbackInfo *info = (CallbackInfo *) ptr;
RtApiAlsa *object = (RtApiAlsa *) info->object;
bool *isRunning = &info->isRunning;
+#ifdef SCHED_RR // Undefined with some OSes (eg: NetBSD 1.6.x with GNU Pthread)
+ if ( &info->doRealtime ) {
+ pthread_t tID = pthread_self(); // ID of this thread
+ sched_param prio = { info->priority }; // scheduling priority of thread
+ pthread_setschedparam( tID, SCHED_RR, &prio );
+ }
+#endif
+
while ( *isRunning == true ) {
pthread_testcancel();
object->callbackEvent();
@@ -6319,9 +6414,8 @@ extern "C" void *alsaCallbackHandler( void *ptr ) #include <pulse/simple.h>
#include <cstdio>
-namespace {
-const unsigned int SUPPORTED_SAMPLERATES[] = { 8000, 16000, 22050, 32000,
- 44100, 48000, 96000, 0}; }
+static const unsigned int SUPPORTED_SAMPLERATES[] = { 8000, 16000, 22050, 32000,
+ 44100, 48000, 96000, 0};
struct rtaudio_pa_format_mapping_t {
RtAudioFormat rtaudio_format;
@@ -6373,7 +6467,7 @@ RtAudio::DeviceInfo RtApiPulse::getDeviceInfo( unsigned int device ) return info;
}
-extern "C" void *pulseaudio_callback( void * user )
+static void *pulseaudio_callback( void * user )
{
CallbackInfo *cbi = static_cast<CallbackInfo *>( user );
RtApiPulse *context = static_cast<RtApiPulse *>( cbi->object );
@@ -6452,7 +6546,7 @@ void RtApiPulse::callbackEvent( void ) RtAudioCallback callback = (RtAudioCallback) stream_.callbackInfo.callback;
double streamTime = getStreamTime();
RtAudioStreamStatus status = 0;
- int doStopStream = callback( stream_.userBuffer[0], stream_.userBuffer[1],
+ int doStopStream = callback( stream_.userBuffer[OUTPUT], stream_.userBuffer[INPUT],
stream_.bufferSize, streamTime, status,
stream_.callbackInfo.userData );
@@ -6462,50 +6556,52 @@ void RtApiPulse::callbackEvent( void ) }
MUTEX_LOCK( &stream_.mutex );
+ void *pulse_in = stream_.doConvertBuffer[INPUT] ? stream_.deviceBuffer : stream_.userBuffer[INPUT];
+ void *pulse_out = stream_.doConvertBuffer[OUTPUT] ? stream_.deviceBuffer : stream_.userBuffer[OUTPUT];
if ( stream_.state != STREAM_RUNNING )
goto unlock;
int pa_error;
size_t bytes;
- switch ( stream_.mode ) {
- case INPUT:
- bytes = stream_.nUserChannels[1] * stream_.bufferSize * formatBytes( stream_.userFormat );
- if ( pa_simple_read( pah->s_rec, stream_.userBuffer[1], bytes, &pa_error ) < 0 ) {
- errorStream_ << "RtApiPulse::callbackEvent: audio read error, " <<
- pa_strerror( pa_error ) << ".";
- errorText_ = errorStream_.str();
- error( RtError::WARNING );
- }
- break;
- case OUTPUT:
- bytes = stream_.nUserChannels[0] * stream_.bufferSize * formatBytes( stream_.userFormat );
- if ( pa_simple_write( pah->s_play, stream_.userBuffer[0], bytes, &pa_error ) < 0 ) {
+ if (stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
+ if ( stream_.doConvertBuffer[OUTPUT] ) {
+ convertBuffer( stream_.deviceBuffer,
+ stream_.userBuffer[OUTPUT],
+ stream_.convertInfo[OUTPUT] );
+ bytes = stream_.nDeviceChannels[OUTPUT] * stream_.bufferSize *
+ formatBytes( stream_.deviceFormat[OUTPUT] );
+ } else
+ bytes = stream_.nUserChannels[OUTPUT] * stream_.bufferSize *
+ formatBytes( stream_.userFormat );
+
+ if ( pa_simple_write( pah->s_play, pulse_out, bytes, &pa_error ) < 0 ) {
errorStream_ << "RtApiPulse::callbackEvent: audio write error, " <<
pa_strerror( pa_error ) << ".";
errorText_ = errorStream_.str();
error( RtError::WARNING );
}
- break;
- case DUPLEX:
- bytes = stream_.nUserChannels[1] * stream_.bufferSize * formatBytes( stream_.userFormat );
- if ( pa_simple_read( pah->s_rec, stream_.userBuffer[1], bytes, &pa_error ) < 0 ) {
+ }
+
+ if ( stream_.mode == INPUT || stream_.mode == DUPLEX) {
+ if ( stream_.doConvertBuffer[INPUT] )
+ bytes = stream_.nDeviceChannels[INPUT] * stream_.bufferSize *
+ formatBytes( stream_.deviceFormat[INPUT] );
+ else
+ bytes = stream_.nUserChannels[INPUT] * stream_.bufferSize *
+ formatBytes( stream_.userFormat );
+
+ if ( pa_simple_read( pah->s_rec, pulse_in, bytes, &pa_error ) < 0 ) {
errorStream_ << "RtApiPulse::callbackEvent: audio read error, " <<
pa_strerror( pa_error ) << ".";
errorText_ = errorStream_.str();
error( RtError::WARNING );
}
- bytes = stream_.nUserChannels[0] * stream_.bufferSize * formatBytes( stream_.userFormat );
- if ( pa_simple_write( pah->s_play, stream_.userBuffer[0], bytes, &pa_error ) < 0) {
- errorStream_ << "RtApiPulse::callbackEvent: audio write error, " <<
- pa_strerror( pa_error ) << ".";
- errorText_ = errorStream_.str();
- error( RtError::WARNING );
+ if ( stream_.doConvertBuffer[INPUT] ) {
+ convertBuffer( stream_.userBuffer[INPUT],
+ stream_.deviceBuffer,
+ stream_.convertInfo[INPUT] );
}
- break;
- default:
- // ERROR
- break;
}
unlock:
@@ -6566,6 +6662,7 @@ void RtApiPulse::stopStream( void ) errorText_ = errorStream_.str();
MUTEX_UNLOCK( &stream_.mutex );
error( RtError::SYSTEM_ERROR );
+ return;
}
}
@@ -6599,6 +6696,7 @@ void RtApiPulse::abortStream( void ) errorText_ = errorStream_.str();
MUTEX_UNLOCK( &stream_.mutex );
error( RtError::SYSTEM_ERROR );
+ return;
}
}
@@ -6654,20 +6752,16 @@ bool RtApiPulse::probeDeviceOpen( unsigned int device, StreamMode mode, return false;
}
- if ( options && ( options->flags & RTAUDIO_NONINTERLEAVED ) ) {
- errorText_ = "RtApiPulse::probeDeviceOpen: only interleaved audio data supported.";
- return false;
- }
-
- stream_.userInterleaved = true;
- stream_.nBuffers = 1;
-
+ // Set interleaving parameters.
+ if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) stream_.userInterleaved = false;
+ else stream_.userInterleaved = true;
stream_.deviceInterleaved[mode] = true;
+ stream_.nBuffers = 1;
stream_.doByteSwap[mode] = false;
- stream_.doConvertBuffer[mode] = false;
+ stream_.doConvertBuffer[mode] = channels > 1 && !stream_.userInterleaved;
stream_.deviceFormat[mode] = stream_.userFormat;
stream_.nUserChannels[mode] = channels;
- stream_.nDeviceChannels[mode] = channels;
+ stream_.nDeviceChannels[mode] = channels + firstChannel;
stream_.channelOffset[mode] = 0;
// Allocate necessary internal buffers.
@@ -6679,6 +6773,33 @@ bool RtApiPulse::probeDeviceOpen( unsigned int device, StreamMode mode, }
stream_.bufferSize = *bufferSize;
+ if ( stream_.doConvertBuffer[mode] ) {
+
+ bool makeBuffer = true;
+ bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] );
+ if ( mode == INPUT ) {
+ if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {
+ unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] );
+ if ( bufferBytes <= bytesOut ) makeBuffer = false;
+ }
+ }
+
+ if ( makeBuffer ) {
+ bufferBytes *= *bufferSize;
+ if ( stream_.deviceBuffer ) free( stream_.deviceBuffer );
+ stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 );
+ if ( stream_.deviceBuffer == NULL ) {
+ errorText_ = "RtApiPulse::probeDeviceOpen: error allocating device buffer memory.";
+ goto error;
+ }
+ }
+ }
+
+ stream_.device[mode] = device;
+
+ // Setup the buffer conversion information structure.
+ if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, firstChannel );
+
if ( !stream_.apiHandle ) {
PulseAudioHandle *pah = new PulseAudioHandle;
if ( !pah ) {
@@ -6721,8 +6842,6 @@ bool RtApiPulse::probeDeviceOpen( unsigned int device, StreamMode mode, else
stream_.mode = DUPLEX;
- stream_.state = STREAM_STOPPED;
-
if ( !stream_.callbackInfo.isRunning ) {
stream_.callbackInfo.object = this;
stream_.callbackInfo.isRunning = true;
@@ -6731,11 +6850,30 @@ bool RtApiPulse::probeDeviceOpen( unsigned int device, StreamMode mode, goto error;
}
}
+
+ stream_.state = STREAM_STOPPED;
return true;
error:
- closeStream();
- return false;
+ if ( pah && stream_.callbackInfo.isRunning ) {
+ pthread_cond_destroy( &pah->runnable_cv );
+ delete pah;
+ stream_.apiHandle = 0;
+ }
+
+ for ( int i=0; i<2; i++ ) {
+ if ( stream_.userBuffer[i] ) {
+ free( stream_.userBuffer[i] );
+ stream_.userBuffer[i] = 0;
+ }
+ }
+
+ if ( stream_.deviceBuffer ) {
+ free( stream_.deviceBuffer );
+ stream_.deviceBuffer = 0;
+ }
+
+ return FAILURE;
}
//******************** End of __LINUX_PULSE__ *********************//
@@ -6751,7 +6889,7 @@ bool RtApiPulse::probeDeviceOpen( unsigned int device, StreamMode mode, #include <errno.h>
#include <math.h>
-extern "C" void *ossCallbackHandler(void * ptr);
+static void *ossCallbackHandler(void * ptr);
// A structure to hold various information related to the OSS API
// implementation.
@@ -6822,12 +6960,14 @@ RtAudio::DeviceInfo RtApiOss :: getDeviceInfo( unsigned int device ) close( mixerfd );
errorText_ = "RtApiOss::getDeviceInfo: no devices found!";
error( RtError::INVALID_USE );
+ return info;
}
if ( device >= nDevices ) {
close( mixerfd );
errorText_ = "RtApiOss::getDeviceInfo: device ID is invalid!";
error( RtError::INVALID_USE );
+ return info;
}
oss_audioinfo ainfo;
@@ -7658,7 +7798,7 @@ void RtApiOss :: callbackEvent() if ( doStopStream == 1 ) this->stopStream();
}
-extern "C" void *ossCallbackHandler( void *ptr )
+static void *ossCallbackHandler( void *ptr )
{
CallbackInfo *info = (CallbackInfo *) ptr;
RtApiOss *object = (RtApiOss *) info->object;
@@ -7687,6 +7827,28 @@ extern "C" void *ossCallbackHandler( void *ptr ) void RtApi :: error( RtError::Type type )
{
errorStream_.str(""); // clear the ostringstream
+
+ RtAudioErrorCallback errorCallback = (RtAudioErrorCallback) stream_.callbackInfo.errorCallback;
+ if ( errorCallback ) {
+ // abortStream() can generate new error messages. Ignore them. Just keep original one.
+ static bool firstErrorOccured = false;
+
+ if ( firstErrorOccured )
+ return;
+
+ firstErrorOccured = true;
+ const std::string errorMessage = errorText_;
+
+ if ( type != RtError::WARNING && stream_.state != STREAM_STOPPED) {
+ stream_.callbackInfo.isRunning = false; // exit from the thread
+ abortStream();
+ }
+
+ errorCallback( type, errorMessage );
+ firstErrorOccured = false;
+ return;
+ }
+
if ( type == RtError::WARNING && showWarnings_ == true )
std::cerr << '\n' << errorText_ << "\n\n";
else if ( type != RtError::WARNING )
@@ -7716,6 +7878,7 @@ void RtApi :: clearStreamInfo() stream_.callbackInfo.callback = 0;
stream_.callbackInfo.userData = 0;
stream_.callbackInfo.isRunning = false;
+ stream_.callbackInfo.errorCallback = 0;
for ( int i=0; i<2; i++ ) {
stream_.device[i] = 11111;
stream_.doConvertBuffer[i] = false;
@@ -7741,11 +7904,12 @@ unsigned int RtApi :: formatBytes( RtAudioFormat format ) {
if ( format == RTAUDIO_SINT16 )
return 2;
- else if ( format == RTAUDIO_SINT24 || format == RTAUDIO_SINT32 ||
- format == RTAUDIO_FLOAT32 )
+ else if ( format == RTAUDIO_SINT32 || format == RTAUDIO_FLOAT32 )
return 4;
else if ( format == RTAUDIO_FLOAT64 )
return 8;
+ else if ( format == RTAUDIO_SINT24 )
+ return 3;
else if ( format == RTAUDIO_SINT8 )
return 1;
@@ -7878,11 +8042,11 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info }
}
else if (info.inFormat == RTAUDIO_SINT24) {
- Int32 *in = (Int32 *)inBuffer;
+ Int24 *in = (Int24 *)inBuffer;
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]] = (Float64) (in[info.inOffset[j]].asInt());
out[info.outOffset[j]] += 0.5;
out[info.outOffset[j]] *= scale;
}
@@ -7956,11 +8120,11 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info }
}
else if (info.inFormat == RTAUDIO_SINT24) {
- Int32 *in = (Int32 *)inBuffer;
+ Int24 *in = (Int24 *)inBuffer;
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]] = (Float32) (in[info.inOffset[j]].asInt());
out[info.outOffset[j]] += 0.5;
out[info.outOffset[j]] *= scale;
}
@@ -8027,11 +8191,11 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info out += info.outJump;
}
}
- else if (info.inFormat == RTAUDIO_SINT24) { // Hmmm ... we could just leave it in the lower 3 bytes
- Int32 *in = (Int32 *)inBuffer;
+ else if (info.inFormat == RTAUDIO_SINT24) {
+ Int24 *in = (Int24 *)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]];
+ out[info.outOffset[j]] = (Int32) in[info.inOffset[j]].asInt();
out[info.outOffset[j]] <<= 8;
}
in += info.inJump;
@@ -8071,13 +8235,13 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info }
}
else if (info.outFormat == RTAUDIO_SINT24) {
- Int32 *out = (Int32 *)outBuffer;
+ Int24 *out = (Int24 *)outBuffer;
if (info.inFormat == RTAUDIO_SINT8) {
signed char *in = (signed char *)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]];
- out[info.outOffset[j]] <<= 16;
+ out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] << 16);
+ //out[info.outOffset[j]] <<= 16;
}
in += info.inJump;
out += info.outJump;
@@ -8087,8 +8251,8 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info Int16 *in = (Int16 *)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]];
- out[info.outOffset[j]] <<= 8;
+ out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] << 8);
+ //out[info.outOffset[j]] <<= 8;
}
in += info.inJump;
out += info.outJump;
@@ -8096,7 +8260,7 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info }
else if (info.inFormat == RTAUDIO_SINT24) {
// Channel compensation and/or (de)interleaving only.
- Int32 *in = (Int32 *)inBuffer;
+ Int24 *in = (Int24 *)inBuffer;
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
out[info.outOffset[j]] = in[info.inOffset[j]];
@@ -8109,8 +8273,8 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info Int32 *in = (Int32 *)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]];
- out[info.outOffset[j]] >>= 8;
+ out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] >> 8);
+ //out[info.outOffset[j]] >>= 8;
}
in += info.inJump;
out += info.outJump;
@@ -8162,10 +8326,10 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info }
}
else if (info.inFormat == RTAUDIO_SINT24) {
- Int32 *in = (Int32 *)inBuffer;
+ Int24 *in = (Int24 *)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]] >> 8) & 0x0000ffff);
+ out[info.outOffset[j]] = (Int16) (in[info.inOffset[j]].asInt() >> 8);
}
in += info.inJump;
out += info.outJump;
@@ -8226,10 +8390,10 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info }
}
else if (info.inFormat == RTAUDIO_SINT24) {
- Int32 *in = (Int32 *)inBuffer;
+ Int24 *in = (Int24 *)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]] >> 16) & 0x000000ff);
+ out[info.outOffset[j]] = (signed char) (in[info.inOffset[j]].asInt() >> 16);
}
in += info.inJump;
out += info.outJump;
@@ -8268,9 +8432,9 @@ 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)); }
+//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 )
{
@@ -8289,8 +8453,7 @@ void RtApi :: byteSwapBuffer( char *buffer, unsigned int samples, RtAudioFormat ptr += 2;
}
}
- else if ( format == RTAUDIO_SINT24 ||
- format == RTAUDIO_SINT32 ||
+ else if ( format == RTAUDIO_SINT32 ||
format == RTAUDIO_FLOAT32 ) {
for ( unsigned int i=0; i<samples; i++ ) {
// Swap 1st and 4th bytes.
@@ -8308,6 +8471,17 @@ void RtApi :: byteSwapBuffer( char *buffer, unsigned int samples, RtAudioFormat ptr += 3;
}
}
+ else if ( format == RTAUDIO_SINT24 ) {
+ for ( unsigned int i=0; i<samples; i++ ) {
+ // Swap 1st and 3rd bytes.
+ val = *(ptr);
+ *(ptr) = *(ptr+2);
+ *(ptr+2) = val;
+
+ // Increment 2 more bytes.
+ ptr += 2;
+ }
+ }
else if ( format == RTAUDIO_FLOAT64 ) {
for ( unsigned int i=0; i<samples; i++ ) {
// Swap 1st and 8th bytes
@@ -10,7 +10,7 @@ RtAudio WWW site: http://www.music.mcgill.ca/~gary/rtaudio/ RtAudio: realtime audio i/o C++ classes - Copyright (c) 2001-2012 Gary P. Scavone + Copyright (c) 2001-2013 Gary P. Scavone Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files @@ -42,8 +42,6 @@ \file RtAudio.h */ -// RtAudio: Version 4.0.11 - #ifndef __RTAUDIO_H #define __RTAUDIO_H @@ -51,6 +49,9 @@ #include <vector> #include "RtError.h" +// RtAudio version +static const std::string VERSION( "4.0.12" ); + /*! \typedef typedef unsigned long RtAudioFormat; \brief RtAudio data format type. @@ -59,12 +60,10 @@ internal routines will automatically take care of any necessary byte-swapping between the host format and the soundcard. Thus, endian-ness is not a concern in the following format definitions. - Note that 24-bit data is expected to be encapsulated in a 32-bit - format. - \e RTAUDIO_SINT8: 8-bit signed integer. - \e RTAUDIO_SINT16: 16-bit signed integer. - - \e RTAUDIO_SINT24: Lower 3 bytes of 32-bit signed integer. + - \e RTAUDIO_SINT24: 24-bit signed integer. - \e RTAUDIO_SINT32: 32-bit signed integer. - \e RTAUDIO_FLOAT32: Normalized between plus/minus 1.0. - \e RTAUDIO_FLOAT64: Normalized between plus/minus 1.0. @@ -72,7 +71,7 @@ typedef unsigned long RtAudioFormat; static const RtAudioFormat RTAUDIO_SINT8 = 0x1; // 8-bit signed integer. static const RtAudioFormat RTAUDIO_SINT16 = 0x2; // 16-bit signed integer. -static const RtAudioFormat RTAUDIO_SINT24 = 0x4; // Lower 3 bytes of 32-bit signed integer. +static const RtAudioFormat RTAUDIO_SINT24 = 0x4; // 24-bit signed integer. static const RtAudioFormat RTAUDIO_SINT32 = 0x8; // 32-bit signed integer. static const RtAudioFormat RTAUDIO_FLOAT32 = 0x10; // Normalized between plus/minus 1.0. static const RtAudioFormat RTAUDIO_FLOAT64 = 0x20; // Normalized between plus/minus 1.0. @@ -186,6 +185,12 @@ typedef int (*RtAudioCallback)( void *outputBuffer, void *inputBuffer, RtAudioStreamStatus status, void *userData ); +//! RtAudio error callback function prototype. +/*! + \param type Type of error. + \param errorText Error description. + */ +typedef void (*RtAudioErrorCallback)( RtError::Type type, const std::string &errorText ); // **************************************************************** // // @@ -316,6 +321,9 @@ class RtAudio : flags(0), numberOfBuffers(0), priority(0) {} }; + //! A static function to determine the current RtAudio version. + static std::string getVersion( void ) { return VERSION; } + //! A static function to determine the available compiled audio APIs. /*! The values returned in the std::vector can be compared against @@ -423,12 +431,14 @@ class RtAudio chosen. If the RTAUDIO_MINIMIZE_LATENCY flag bit is set, the lowest allowable value is used. The actual value used is returned via the structure argument. The parameter is API dependent. + \param errorCallback A client-defined function that will be invoked + when an error has occured. */ void openStream( RtAudio::StreamParameters *outputParameters, RtAudio::StreamParameters *inputParameters, RtAudioFormat format, unsigned int sampleRate, unsigned int *bufferFrames, RtAudioCallback callback, - void *userData = NULL, RtAudio::StreamOptions *options = NULL ); + void *userData = NULL, RtAudio::StreamOptions *options = NULL, RtAudioErrorCallback errorCallback = NULL ); //! A function that closes a stream and frees any associated stream memory. /*! @@ -535,12 +545,15 @@ struct CallbackInfo { ThreadHandle thread; void *callback; void *userData; + void *errorCallback; void *apiInfo; // void pointer for API specific callback information bool isRunning; + bool doRealtime; + int priority; // Default constructor. CallbackInfo() - :object(0), callback(0), userData(0), apiInfo(0), isRunning(false) {} + :object(0), callback(0), userData(0), errorCallback(0), apiInfo(0), isRunning(false), doRealtime(false) {} }; // **************************************************************** // @@ -557,6 +570,36 @@ struct CallbackInfo { // // **************************************************************** // +#pragma pack(push, 1) +class S24 { + + protected: + unsigned char c3[3]; + + public: + S24() {} + + S24& operator = ( const int& i ) { + c3[0] = (i & 0x000000ff); + c3[1] = (i & 0x0000ff00) >> 8; + c3[2] = (i & 0x00ff0000) >> 16; + return *this; + } + + S24( const S24& v ) { *this = v; } + S24( const double& d ) { *this = (int) d; } + S24( const float& f ) { *this = (int) f; } + S24( const signed short& s ) { *this = (int) s; } + S24( const char& c ) { *this = (int) c; } + + int asInt() { + int i = c3[0] | (c3[1] << 8) | (c3[2] << 16); + if (i & 0x800000) i |= ~0xffffff; + return i; + } +}; +#pragma pack(pop) + #if defined( HAVE_GETTIMEOFDAY ) #include <sys/time.h> #endif @@ -578,7 +621,8 @@ public: RtAudio::StreamParameters *inputParameters, RtAudioFormat format, unsigned int sampleRate, unsigned int *bufferFrames, RtAudioCallback callback, - void *userData, RtAudio::StreamOptions *options ); + void *userData, RtAudio::StreamOptions *options, + RtAudioErrorCallback errorCallback ); virtual void closeStream( void ); virtual void startStream( void ) = 0; virtual void stopStream( void ) = 0; @@ -586,9 +630,9 @@ public: long getStreamLatency( void ); unsigned int getStreamSampleRate( void ); virtual double getStreamTime( void ); - bool isStreamOpen( void ) const { return stream_.state != STREAM_CLOSED; }; - bool isStreamRunning( void ) const { return stream_.state == STREAM_RUNNING; }; - void showWarnings( bool value ) { showWarnings_ = value; }; + bool isStreamOpen( void ) const { return stream_.state != STREAM_CLOSED; } + bool isStreamRunning( void ) const { return stream_.state == STREAM_RUNNING; } + void showWarnings( bool value ) { showWarnings_ = value; } protected: @@ -655,6 +699,7 @@ protected: :apiHandle(0), deviceBuffer(0) { device[0] = 11111; device[1] = 11111; } }; + typedef S24 Int24; typedef signed short Int16; typedef signed int Int32; typedef float Float32; @@ -726,7 +771,7 @@ inline void RtAudio :: abortStream( void ) { return rtapi_->abortStream(); } 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 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 ); } @@ -742,7 +787,7 @@ public: RtApiCore(); ~RtApiCore(); - RtAudio::Api getCurrentApi( void ) { return RtAudio::MACOSX_CORE; }; + RtAudio::Api getCurrentApi( void ) { return RtAudio::MACOSX_CORE; } unsigned int getDeviceCount( void ); RtAudio::DeviceInfo getDeviceInfo( unsigned int device ); unsigned int getDefaultOutputDevice( void ); @@ -780,7 +825,7 @@ public: RtApiJack(); ~RtApiJack(); - RtAudio::Api getCurrentApi( void ) { return RtAudio::UNIX_JACK; }; + RtAudio::Api getCurrentApi( void ) { return RtAudio::UNIX_JACK; } unsigned int getDeviceCount( void ); RtAudio::DeviceInfo getDeviceInfo( unsigned int device ); void closeStream( void ); @@ -813,7 +858,7 @@ public: RtApiAsio(); ~RtApiAsio(); - RtAudio::Api getCurrentApi( void ) { return RtAudio::WINDOWS_ASIO; }; + RtAudio::Api getCurrentApi( void ) { return RtAudio::WINDOWS_ASIO; } unsigned int getDeviceCount( void ); RtAudio::DeviceInfo getDeviceInfo( unsigned int device ); void closeStream( void ); @@ -849,7 +894,7 @@ public: RtApiDs(); ~RtApiDs(); - RtAudio::Api getCurrentApi( void ) { return RtAudio::WINDOWS_DS; }; + RtAudio::Api getCurrentApi( void ) { return RtAudio::WINDOWS_DS; } unsigned int getDeviceCount( void ); unsigned int getDefaultOutputDevice( void ); unsigned int getDefaultInputDevice( void ); @@ -871,6 +916,7 @@ public: bool coInitialized_; bool buffersRolling; long duplexPrerollBytes; + std::vector<struct DsDevice> dsDevices; bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, unsigned int firstChannel, unsigned int sampleRate, RtAudioFormat format, unsigned int *bufferSize, @@ -887,7 +933,7 @@ public: RtApiAlsa(); ~RtApiAlsa(); - RtAudio::Api getCurrentApi() { return RtAudio::LINUX_ALSA; }; + RtAudio::Api getCurrentApi() { return RtAudio::LINUX_ALSA; } unsigned int getDeviceCount( void ); RtAudio::DeviceInfo getDeviceInfo( unsigned int device ); void closeStream( void ); @@ -919,7 +965,7 @@ class RtApiPulse: public RtApi { public: ~RtApiPulse(); - RtAudio::Api getCurrentApi() { return RtAudio::LINUX_PULSE; }; + RtAudio::Api getCurrentApi() { return RtAudio::LINUX_PULSE; } unsigned int getDeviceCount( void ); RtAudio::DeviceInfo getDeviceInfo( unsigned int device ); void closeStream( void ); @@ -953,7 +999,7 @@ public: RtApiOss(); ~RtApiOss(); - RtAudio::Api getCurrentApi() { return RtAudio::LINUX_OSS; }; + RtAudio::Api getCurrentApi() { return RtAudio::LINUX_OSS; } unsigned int getDeviceCount( void ); RtAudio::DeviceInfo getDeviceInfo( unsigned int device ); void closeStream( void ); @@ -983,21 +1029,21 @@ class RtApiDummy: public RtApi { public: - RtApiDummy() { errorText_ = "RtApiDummy: This class provides no functionality."; error( RtError::WARNING ); }; - RtAudio::Api getCurrentApi( void ) { return RtAudio::RTAUDIO_DUMMY; }; - unsigned int getDeviceCount( void ) { return 0; }; - RtAudio::DeviceInfo getDeviceInfo( unsigned int device ) { RtAudio::DeviceInfo info; return info; }; - void closeStream( void ) {}; - void startStream( void ) {}; - void stopStream( void ) {}; - void abortStream( void ) {}; + RtApiDummy() { errorText_ = "RtApiDummy: This class provides no functionality."; error( RtError::WARNING ); } + RtAudio::Api getCurrentApi( void ) { return RtAudio::RTAUDIO_DUMMY; } + unsigned int getDeviceCount( void ) { return 0; } + RtAudio::DeviceInfo getDeviceInfo( unsigned int /*device*/ ) { RtAudio::DeviceInfo info; return info; } + void closeStream( void ) {} + void startStream( void ) {} + void stopStream( void ) {} + void abortStream( void ) {} private: - bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, - unsigned int firstChannel, unsigned int sampleRate, - RtAudioFormat format, unsigned int *bufferSize, - RtAudio::StreamOptions *options ) { return false; }; + bool probeDeviceOpen( unsigned int /*device*/, StreamMode /*mode*/, unsigned int /*channels*/, + unsigned int /*firstChannel*/, unsigned int /*sampleRate*/, + RtAudioFormat /*format*/, unsigned int * /*bufferSize*/, + RtAudio::StreamOptions * /*options*/ ) { return false; } }; #endif diff --git a/config/config.sub b/config/config.sub index 7d3f49f..9a7d59a 100755 --- a/config/config.sub +++ b/config/config.sub @@ -3,7 +3,7 @@ # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 # Free Software Foundation, Inc. -timestamp='2004-02-26' +timestamp='2012-11-19' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software @@ -225,7 +225,7 @@ case $basic_machine in | alpha | alphaev[4-8] | alphaev56 | alphapca5[67] \ | alphaev6[78] \ | we32k | ns16k | clipper | i370 | sh | sh[34] \ - | powerpc | powerpcle \ + | powerpc | powerpc64 | powerpcle \ | 1750a | dsp16xx | pdp10 | pdp11 \ | mips16 | mips64 | mipsel | mips64el \ | mips64orion | mips64orionel | mipstx39 | mipstx39el \ @@ -271,7 +271,7 @@ case $basic_machine in | alphaev6[78]-* \ | we32k-* | cydra-* | ns16k-* | pn-* | np1-* | xps100-* \ | clipper-* | orion-* \ - | sparclite-* | pdp10-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \ + | sparclite-* | pdp10-* | pdp11-* | sh-* | powerpc-* | powerpc64-* | powerpcle-* \ | sparc64-* | sparcv9-* | sparcv9b-* | sparc86x-* \ | mips16-* | mips64-* | mipsel-* \ | mips64el-* | mips64orion-* | mips64orionel-* \ @@ -721,6 +721,10 @@ case $basic_machine in ;; ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; diff --git a/configure.ac b/configure.ac index 69250e8..6586116 100644 --- a/configure.ac +++ b/configure.ac @@ -2,11 +2,25 @@ 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]) +AC_CONFIG_FILES([rtaudio-config librtaudio.pc Makefile tests/Makefile]) # Fill GXX with something before test. AC_SUBST( GXX, ["no"] ) +dnl Check for pkg-config program, used for configuring some libraries. +m4_define_default([PKG_PROG_PKG_CONFIG], +[AC_MSG_CHECKING([pkg-config]) +AC_MSG_RESULT([no])]) + +PKG_PROG_PKG_CONFIG + +dnl If the pkg-config autoconf support isn't installed, define its +dnl autoconf macro to disable any packages depending on it. +m4_define_default([PKG_CHECK_MODULES], +[AC_MSG_CHECKING([$1]) +AC_MSG_RESULT([no]) +$4]) + # Checks for programs. AC_PROG_CXX(g++ CC c++ cxx) AC_PROG_RANLIB @@ -58,6 +72,7 @@ esac # Checks for package options and external software AC_SUBST( api, [""] ) +AC_SUBST( req, [""] ) AC_MSG_CHECKING(for audio API) case $host in *-*-netbsd*) @@ -77,14 +92,17 @@ case $host in # Look for ALSA flag AC_ARG_WITH(alsa, [ --with-alsa = choose native ALSA API support (linux only)], [ api="$api -D__LINUX_ALSA__" + req="$req alsa" AC_MSG_RESULT(using ALSA) AC_CHECK_LIB(asound, snd_pcm_open, , AC_MSG_ERROR(ALSA support requires the asound library!))], ) # Look for PULSE flag AC_ARG_WITH(pulse, [ --with-pulse = choose PulseAudio API support (linux only)], [ api="$api -D__LINUX_PULSE__" + req="$req libpulse-simple" AC_MSG_RESULT(using PulseAudio) - AC_CHECK_LIB(pulse-simple, pa_simple_new, , AC_MSG_ERROR(PulseAudio support requires the pulse-simple library!))], ) + PKG_CHECK_MODULES([PULSE], [libpulse-simple], , AC_MSG_ERROR(PulseAudio support requires the pulse-simple library!)) + LIBS="$LIBS `pkg-config --libs libpulse-simple`" ], ) # Look for OSS flag AC_ARG_WITH(oss, [ --with-oss = choose OSS API support (linux only)], [ @@ -95,6 +113,7 @@ case $host in if [test "$api" == "";] then AC_MSG_RESULT(using ALSA) AC_SUBST( api, [-D__LINUX_ALSA__] ) + req="$req alsa" AC_CHECK_LIB(asound, snd_pcm_open, , AC_MSG_ERROR(ALSA support requires the asound library!)) fi diff --git a/doc/doxygen/Doxyfile b/doc/doxygen/Doxyfile index 2c13b09..eb094df 100644 --- a/doc/doxygen/Doxyfile +++ b/doc/doxygen/Doxyfile @@ -31,7 +31,7 @@ PROJECT_NAME = RtAudio # This could be handy for archiving the generated documentation or # if some version control system is used. -PROJECT_NUMBER = 4.0.11 +PROJECT_NUMBER = 4.0.12 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. diff --git a/doc/doxygen/compiling.txt b/doc/doxygen/compiling.txt index d9884d0..c1f83e4 100644 --- a/doc/doxygen/compiling.txt +++ b/doc/doxygen/compiling.txt @@ -32,7 +32,7 @@ In order to compile RtAudio for a specific OS and audio API, it is necessary to <TD>RtApiPulse</TD> <TD>__LINUX_PULSE__</TD> <TD><TT>pthread</TT></TD> - <TD><TT>g++ -Wall -D__LINUX_PULSE__ -o audioprobe audioprobe.cpp RtAudio.cpp -lpthread</TT></TD> + <TD><TT>g++ -Wall -D__LINUX_PULSE__ -o audioprobe audioprobe.cpp RtAudio.cpp -lpthread -lpulse-simple -lpulse</TT></TD> </TR> <TR> <TD>Linux</TD> diff --git a/doc/doxygen/footer.html b/doc/doxygen/footer.html index 18df8f2..4f5b71c 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>©2001-2012 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>©2001-2013 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/tutorial.txt b/doc/doxygen/tutorial.txt index 19ed170..6581774 100644 --- a/doc/doxygen/tutorial.txt +++ b/doc/doxygen/tutorial.txt @@ -15,24 +15,21 @@ RtAudio is a set of C++ classes that provide a common API (Application Programmi RtAudio incorporates the concept of audio streams, which represent audio output (playback) and/or input (recording). Available audio devices and their capabilities can be enumerated and then specified when opening a stream. Where applicable, multiple API support can be compiled and a particular API specified when creating an RtAudio instance. See the \ref apinotes section for information specific to each of the supported audio APIs. -\section whatsnew What's New (Version 4.0) - -RtAudio V4 represents a significant rewrite of the code and includes a number of API and functionality changes from previous versions. A partial list of the changes includes: -- new support for non-interleaved user data -- additional input/output parameter specifications, including channel offset -- new support for dynamic connection of devices -- new support for stream time -- revised callback arguments, including separate input and output buffer arguments -- revised C++ exception handling -- updated support for OSS version 4.0 -- discontinued support of blocking functionality -- discontinued support of SGI - -Devices are now re-enumerated every time the RtAudio::getDeviceCount(), RtAudio::getDeviceInfo(), and RtAudio::openStream() functions are called. This allows for the proper identification of hot-pluggable (USB, Firewire, ...) devices that are connected after an RtAudio instance is created. +\section whatsnew Latest Updates (Version 4.0.12) + +- new functionality to allow error reporting via a client-supplied function (thanks to Pavel Mogilevskiy) +- new function to return the version number +- updated RtAudio.cpp and ASIO files for UNICODE support (thanks to Renaud Schoonbroodt) +- updates to PulseAudio API support (thanks to Peter Meerwald and Tristan Matthews) +- updates for pkg-config support in configure script +- 24-bit format changed to true 24-bit format, not sub-bytes of 32-bits (thanks to Marc Britton) +- bug fixes to make sure stream status is closed if error during probeDeviceOpen +- updates / fixes to SCHED_RR code in ALSA (thanks to Marc Lindahl) +- various changes to avoid global variables (thanks to Martin Koegler) \section download Download -Latest Release (14 June 2012): <A href="http://www.music.mcgill.ca/~gary/rtaudio/release/rtaudio-4.0.11.tar.gz">Version 4.0.11</A> +Latest Release (16 April 2013): <A href="http://www.music.mcgill.ca/~gary/rtaudio/release/rtaudio-4.0.12.tar.gz">Version 4.0.12</A> \section documentation Documentation Links diff --git a/doc/release.txt b/doc/release.txt index a29a36c..b9ba915 100644 --- a/doc/release.txt +++ b/doc/release.txt @@ -1,6 +1,17 @@ RtAudio - a set of C++ classes that provide a common API for realtime audio input/output across Linux (native ALSA, JACK, PulseAudio, and OSS), Macintosh OS X (CoreAudio and JACK), and Windows (DirectSound and ASIO) operating systems. -By Gary P. Scavone, 2001-2012. +By Gary P. Scavone, 2001-2013. + +v4.0.12: (16 April 2013) +- new functionality to allow error reporting via a client-supplied function (thanks to Pavel Mogilevskiy) +- new function to return the version number +- updated RtAudio.cpp and ASIO files for UNICODE support (thanks to Renaud Schoonbroodt) +- updates to PulseAudio API support (thanks to Peter Meerwald and Tristan Matthews) +- updates for pkg-config support in configure script +- 24-bit format changed to true 24-bit format, not sub-bytes of 32-bits (thanks to Marc Britton) +- bug fixes to make sure stream status is closed if error during probeDeviceOpen +- updates / fixes to SCHED_RR code in ALSA (thanks to Marc Lindahl) +- various changes to avoid global variables (thanks to Martin Koegler) v4.0.11: (14 June 2012) - fixes for memory leaks in ALSA (thanks to Martin Koegler) diff --git a/include/asiolist.cpp b/include/asiolist.cpp index 5a62f5b..e4c73c2 100644 --- a/include/asiolist.cpp +++ b/include/asiolist.cpp @@ -1,268 +1,308 @@ -#include <windows.h>
-#include "iasiodrv.h"
-#include "asiolist.h"
-
-#define ASIODRV_DESC "description"
-#define INPROC_SERVER "InprocServer32"
-#define ASIO_PATH "software\\asio"
-#define COM_CLSID "clsid"
-
-// ******************************************************************
-// Local Functions
-// ******************************************************************
-static LONG findDrvPath (char *clsidstr,char *dllpath,int dllpathsize)
-{
- HKEY hkEnum,hksub,hkpath;
- char databuf[512];
- LONG cr,rc = -1;
- DWORD datatype,datasize;
- DWORD index;
- OFSTRUCT ofs;
- HFILE hfile;
- BOOL found = FALSE;
-
- CharLowerBuff(clsidstr,strlen(clsidstr));
- if ((cr = RegOpenKey(HKEY_CLASSES_ROOT,COM_CLSID,&hkEnum)) == ERROR_SUCCESS) {
-
- index = 0;
- while (cr == ERROR_SUCCESS && !found) {
- cr = RegEnumKey(hkEnum,index++,(LPTSTR)databuf,512);
- if (cr == ERROR_SUCCESS) {
- CharLowerBuff(databuf,strlen(databuf));
- if (!(strcmp(databuf,clsidstr))) {
- if ((cr = RegOpenKeyEx(hkEnum,(LPCTSTR)databuf,0,KEY_READ,&hksub)) == ERROR_SUCCESS) {
- if ((cr = RegOpenKeyEx(hksub,(LPCTSTR)INPROC_SERVER,0,KEY_READ,&hkpath)) == ERROR_SUCCESS) {
- datatype = REG_SZ; datasize = (DWORD)dllpathsize;
- cr = RegQueryValueEx(hkpath,0,0,&datatype,(LPBYTE)dllpath,&datasize);
- if (cr == ERROR_SUCCESS) {
- memset(&ofs,0,sizeof(OFSTRUCT));
- ofs.cBytes = sizeof(OFSTRUCT);
- hfile = OpenFile(dllpath,&ofs,OF_EXIST);
- if (hfile) rc = 0;
- }
- RegCloseKey(hkpath);
- }
- RegCloseKey(hksub);
- }
- found = TRUE; // break out
- }
- }
- }
- RegCloseKey(hkEnum);
- }
- return rc;
-}
-
-
-static LPASIODRVSTRUCT newDrvStruct (HKEY hkey,char *keyname,int drvID,LPASIODRVSTRUCT lpdrv)
-{
- HKEY hksub;
- char databuf[256];
- char dllpath[MAXPATHLEN];
- WORD wData[100];
- CLSID clsid;
- DWORD datatype,datasize;
- LONG cr,rc;
-
- if (!lpdrv) {
- if ((cr = RegOpenKeyEx(hkey,(LPCTSTR)keyname,0,KEY_READ,&hksub)) == ERROR_SUCCESS) {
-
- datatype = REG_SZ; datasize = 256;
- cr = RegQueryValueEx(hksub,COM_CLSID,0,&datatype,(LPBYTE)databuf,&datasize);
- if (cr == ERROR_SUCCESS) {
- rc = findDrvPath (databuf,dllpath,MAXPATHLEN);
- if (rc == 0) {
- lpdrv = new ASIODRVSTRUCT[1];
- if (lpdrv) {
- memset(lpdrv,0,sizeof(ASIODRVSTRUCT));
- lpdrv->drvID = drvID;
- MultiByteToWideChar(CP_ACP,0,(LPCSTR)databuf,-1,(LPWSTR)wData,100);
- if ((cr = CLSIDFromString((LPOLESTR)wData,(LPCLSID)&clsid)) == S_OK) {
- memcpy(&lpdrv->clsid,&clsid,sizeof(CLSID));
- }
-
- datatype = REG_SZ; datasize = 256;
- cr = RegQueryValueEx(hksub,ASIODRV_DESC,0,&datatype,(LPBYTE)databuf,&datasize);
- if (cr == ERROR_SUCCESS) {
- strcpy(lpdrv->drvname,databuf);
- }
- else strcpy(lpdrv->drvname,keyname);
- }
- }
- }
- RegCloseKey(hksub);
- }
- }
- else lpdrv->next = newDrvStruct(hkey,keyname,drvID+1,lpdrv->next);
-
- return lpdrv;
-}
-
-static void deleteDrvStruct (LPASIODRVSTRUCT lpdrv)
-{
- IASIO *iasio;
-
- if (lpdrv != 0) {
- deleteDrvStruct(lpdrv->next);
- if (lpdrv->asiodrv) {
- iasio = (IASIO *)lpdrv->asiodrv;
- iasio->Release();
- }
- delete lpdrv;
- }
-}
-
-
-static LPASIODRVSTRUCT getDrvStruct (int drvID,LPASIODRVSTRUCT lpdrv)
-{
- while (lpdrv) {
- if (lpdrv->drvID == drvID) return lpdrv;
- lpdrv = lpdrv->next;
- }
- return 0;
-}
-// ******************************************************************
-
-
-// ******************************************************************
-// AsioDriverList
-// ******************************************************************
-AsioDriverList::AsioDriverList ()
-{
- HKEY hkEnum = 0;
- char keyname[MAXDRVNAMELEN];
- LPASIODRVSTRUCT pdl;
- LONG cr;
- DWORD index = 0;
- BOOL fin = FALSE;
-
- numdrv = 0;
- lpdrvlist = 0;
-
- cr = RegOpenKey(HKEY_LOCAL_MACHINE,ASIO_PATH,&hkEnum);
- while (cr == ERROR_SUCCESS) {
- if ((cr = RegEnumKey(hkEnum,index++,(LPTSTR)keyname,MAXDRVNAMELEN))== ERROR_SUCCESS) {
- lpdrvlist = newDrvStruct (hkEnum,keyname,0,lpdrvlist);
- }
- else fin = TRUE;
- }
- if (hkEnum) RegCloseKey(hkEnum);
-
- pdl = lpdrvlist;
- while (pdl) {
- numdrv++;
- pdl = pdl->next;
- }
-
- if (numdrv) CoInitialize(0); // initialize COM
-}
-
-AsioDriverList::~AsioDriverList ()
-{
- if (numdrv) {
- deleteDrvStruct(lpdrvlist);
- CoUninitialize();
- }
-}
-
-
-LONG AsioDriverList::asioGetNumDev (VOID)
-{
- return (LONG)numdrv;
-}
-
-
-LONG AsioDriverList::asioOpenDriver (int drvID,LPVOID *asiodrv)
-{
- LPASIODRVSTRUCT lpdrv = 0;
- long rc;
-
- if (!asiodrv) return DRVERR_INVALID_PARAM;
-
- if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) {
- if (!lpdrv->asiodrv) {
- rc = CoCreateInstance(lpdrv->clsid,0,CLSCTX_INPROC_SERVER,lpdrv->clsid,asiodrv);
- if (rc == S_OK) {
- lpdrv->asiodrv = *asiodrv;
- return 0;
- }
- // else if (rc == REGDB_E_CLASSNOTREG)
- // strcpy (info->messageText, "Driver not registered in the Registration Database!");
- }
- else rc = DRVERR_DEVICE_ALREADY_OPEN;
- }
- else rc = DRVERR_DEVICE_NOT_FOUND;
-
- return rc;
-}
-
-
-LONG AsioDriverList::asioCloseDriver (int drvID)
-{
- LPASIODRVSTRUCT lpdrv = 0;
- IASIO *iasio;
-
- if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) {
- if (lpdrv->asiodrv) {
- iasio = (IASIO *)lpdrv->asiodrv;
- iasio->Release();
- lpdrv->asiodrv = 0;
- }
- }
-
- return 0;
-}
-
-LONG AsioDriverList::asioGetDriverName (int drvID,char *drvname,int drvnamesize)
-{
- LPASIODRVSTRUCT lpdrv = 0;
-
- if (!drvname) return DRVERR_INVALID_PARAM;
-
- if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) {
- if (strlen(lpdrv->drvname) < (unsigned int)drvnamesize) {
- strcpy(drvname,lpdrv->drvname);
- }
- else {
- memcpy(drvname,lpdrv->drvname,drvnamesize-4);
- drvname[drvnamesize-4] = '.';
- drvname[drvnamesize-3] = '.';
- drvname[drvnamesize-2] = '.';
- drvname[drvnamesize-1] = 0;
- }
- return 0;
- }
- return DRVERR_DEVICE_NOT_FOUND;
-}
-
-LONG AsioDriverList::asioGetDriverPath (int drvID,char *dllpath,int dllpathsize)
-{
- LPASIODRVSTRUCT lpdrv = 0;
-
- if (!dllpath) return DRVERR_INVALID_PARAM;
-
- if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) {
- if (strlen(lpdrv->dllpath) < (unsigned int)dllpathsize) {
- strcpy(dllpath,lpdrv->dllpath);
- return 0;
- }
- dllpath[0] = 0;
- return DRVERR_INVALID_PARAM;
- }
- return DRVERR_DEVICE_NOT_FOUND;
-}
-
-LONG AsioDriverList::asioGetDriverCLSID (int drvID,CLSID *clsid)
-{
- LPASIODRVSTRUCT lpdrv = 0;
-
- if (!clsid) return DRVERR_INVALID_PARAM;
-
- if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) {
- memcpy(clsid,&lpdrv->clsid,sizeof(CLSID));
- return 0;
- }
- return DRVERR_DEVICE_NOT_FOUND;
-}
-
-
+#include <windows.h> +#include "iasiodrv.h" +#include "asiolist.h" + +#define ASIODRV_DESC "description" +#define INPROC_SERVER "InprocServer32" +#define ASIO_PATH "software\\asio" +#define COM_CLSID "clsid" + +// ****************************************************************** +// Local Functions +// ****************************************************************** +static LONG findDrvPath (char *clsidstr,char *dllpath,int dllpathsize) +{ + HKEY hkEnum,hksub,hkpath; + char databuf[512]; + LONG cr,rc = -1; + DWORD datatype,datasize; + DWORD index; + OFSTRUCT ofs; + HFILE hfile; + BOOL found = FALSE; + +#ifdef UNICODE + CharLowerBuffA(clsidstr,strlen(clsidstr)); + if ((cr = RegOpenKeyA(HKEY_CLASSES_ROOT,COM_CLSID,&hkEnum)) == ERROR_SUCCESS) { + + index = 0; + while (cr == ERROR_SUCCESS && !found) { + cr = RegEnumKeyA(hkEnum,index++,databuf,512); + if (cr == ERROR_SUCCESS) { + CharLowerBuffA(databuf,strlen(databuf)); + if (!(strcmp(databuf,clsidstr))) { + if ((cr = RegOpenKeyExA(hkEnum,databuf,0,KEY_READ,&hksub)) == ERROR_SUCCESS) { + if ((cr = RegOpenKeyExA(hksub,INPROC_SERVER,0,KEY_READ,&hkpath)) == ERROR_SUCCESS) { + datatype = REG_SZ; datasize = (DWORD)dllpathsize; + cr = RegQueryValueEx(hkpath,0,0,&datatype,(LPBYTE)dllpath,&datasize); + if (cr == ERROR_SUCCESS) { + memset(&ofs,0,sizeof(OFSTRUCT)); + ofs.cBytes = sizeof(OFSTRUCT); + hfile = OpenFile(dllpath,&ofs,OF_EXIST); + if (hfile) rc = 0; + } + RegCloseKey(hkpath); + } + RegCloseKey(hksub); + } + found = TRUE; // break out + } + } + } + RegCloseKey(hkEnum); + } +#else + CharLowerBuff(clsidstr,strlen(clsidstr)); + if ((cr = RegOpenKey(HKEY_CLASSES_ROOT,COM_CLSID,&hkEnum)) == ERROR_SUCCESS) { + + index = 0; + while (cr == ERROR_SUCCESS && !found) { + cr = RegEnumKey(hkEnum,index++,databuf,512); + if (cr == ERROR_SUCCESS) { + CharLowerBuff(databuf,strlen(databuf)); + if (!(strcmp(databuf,clsidstr))) { + if ((cr = RegOpenKeyEx(hkEnum,databuf,0,KEY_READ,&hksub)) == ERROR_SUCCESS) { + if ((cr = RegOpenKeyEx(hksub,INPROC_SERVER,0,KEY_READ,&hkpath)) == ERROR_SUCCESS) { + datatype = REG_SZ; datasize = (DWORD)dllpathsize; + cr = RegQueryValueEx(hkpath,0,0,&datatype,(LPBYTE)dllpath,&datasize); + if (cr == ERROR_SUCCESS) { + memset(&ofs,0,sizeof(OFSTRUCT)); + ofs.cBytes = sizeof(OFSTRUCT); + hfile = OpenFile(dllpath,&ofs,OF_EXIST); + if (hfile) rc = 0; + } + RegCloseKey(hkpath); + } + RegCloseKey(hksub); + } + found = TRUE; // break out + } + } + } + RegCloseKey(hkEnum); + } +#endif + return rc; +} + + +static LPASIODRVSTRUCT newDrvStruct (HKEY hkey,char *keyname,int drvID,LPASIODRVSTRUCT lpdrv) +{ + HKEY hksub; + char databuf[256]; + char dllpath[MAXPATHLEN]; + WORD wData[100]; + CLSID clsid; + DWORD datatype,datasize; + LONG cr,rc; + + if (!lpdrv) { + if ((cr = RegOpenKeyExA(hkey,keyname,0,KEY_READ,&hksub)) == ERROR_SUCCESS) { + + datatype = REG_SZ; datasize = 256; + cr = RegQueryValueExA(hksub,COM_CLSID,0,&datatype,(LPBYTE)databuf,&datasize); + if (cr == ERROR_SUCCESS) { + rc = findDrvPath (databuf,dllpath,MAXPATHLEN); + if (rc == 0) { + lpdrv = new ASIODRVSTRUCT[1]; + if (lpdrv) { + memset(lpdrv,0,sizeof(ASIODRVSTRUCT)); + lpdrv->drvID = drvID; + MultiByteToWideChar(CP_ACP,0,(LPCSTR)databuf,-1,(LPWSTR)wData,100); + if ((cr = CLSIDFromString((LPOLESTR)wData,(LPCLSID)&clsid)) == S_OK) { + memcpy(&lpdrv->clsid,&clsid,sizeof(CLSID)); + } + + datatype = REG_SZ; datasize = 256; + cr = RegQueryValueExA(hksub,ASIODRV_DESC,0,&datatype,(LPBYTE)databuf,&datasize); + if (cr == ERROR_SUCCESS) { + strcpy(lpdrv->drvname,databuf); + } + else strcpy(lpdrv->drvname,keyname); + } + } + } + RegCloseKey(hksub); + } + } + else lpdrv->next = newDrvStruct(hkey,keyname,drvID+1,lpdrv->next); + + return lpdrv; +} + +static void deleteDrvStruct (LPASIODRVSTRUCT lpdrv) +{ + IASIO *iasio; + + if (lpdrv != 0) { + deleteDrvStruct(lpdrv->next); + if (lpdrv->asiodrv) { + iasio = (IASIO *)lpdrv->asiodrv; + iasio->Release(); + } + delete lpdrv; + } +} + + +static LPASIODRVSTRUCT getDrvStruct (int drvID,LPASIODRVSTRUCT lpdrv) +{ + while (lpdrv) { + if (lpdrv->drvID == drvID) return lpdrv; + lpdrv = lpdrv->next; + } + return 0; +} +// ****************************************************************** + + +// ****************************************************************** +// AsioDriverList +// ****************************************************************** +AsioDriverList::AsioDriverList () +{ + HKEY hkEnum = 0; + char keyname[MAXDRVNAMELEN]; + LPASIODRVSTRUCT pdl; + LONG cr; + DWORD index = 0; + BOOL fin = FALSE; + + numdrv = 0; + lpdrvlist = 0; + +#ifdef UNICODE + cr = RegOpenKeyA(HKEY_LOCAL_MACHINE,ASIO_PATH,&hkEnum); +#else + cr = RegOpenKey(HKEY_LOCAL_MACHINE,ASIO_PATH,&hkEnum); +#endif + while (cr == ERROR_SUCCESS) { +#ifdef UNICODE + if ((cr = RegEnumKeyA(hkEnum,index++,keyname,MAXDRVNAMELEN))== ERROR_SUCCESS) { +#else + if ((cr = RegEnumKey(hkEnum,index++,keyname,MAXDRVNAMELEN))== ERROR_SUCCESS) { +#endif + lpdrvlist = newDrvStruct (hkEnum,keyname,0,lpdrvlist); + } + else fin = TRUE; + } + if (hkEnum) RegCloseKey(hkEnum); + + pdl = lpdrvlist; + while (pdl) { + numdrv++; + pdl = pdl->next; + } + + if (numdrv) CoInitialize(0); // initialize COM +} + +AsioDriverList::~AsioDriverList () +{ + if (numdrv) { + deleteDrvStruct(lpdrvlist); + CoUninitialize(); + } +} + + +LONG AsioDriverList::asioGetNumDev (VOID) +{ + return (LONG)numdrv; +} + + +LONG AsioDriverList::asioOpenDriver (int drvID,LPVOID *asiodrv) +{ + LPASIODRVSTRUCT lpdrv = 0; + long rc; + + if (!asiodrv) return DRVERR_INVALID_PARAM; + + if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) { + if (!lpdrv->asiodrv) { + rc = CoCreateInstance(lpdrv->clsid,0,CLSCTX_INPROC_SERVER,lpdrv->clsid,asiodrv); + if (rc == S_OK) { + lpdrv->asiodrv = *asiodrv; + return 0; + } + // else if (rc == REGDB_E_CLASSNOTREG) + // strcpy (info->messageText, "Driver not registered in the Registration Database!"); + } + else rc = DRVERR_DEVICE_ALREADY_OPEN; + } + else rc = DRVERR_DEVICE_NOT_FOUND; + + return rc; +} + + +LONG AsioDriverList::asioCloseDriver (int drvID) +{ + LPASIODRVSTRUCT lpdrv = 0; + IASIO *iasio; + + if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) { + if (lpdrv->asiodrv) { + iasio = (IASIO *)lpdrv->asiodrv; + iasio->Release(); + lpdrv->asiodrv = 0; + } + } + + return 0; +} + +LONG AsioDriverList::asioGetDriverName (int drvID,char *drvname,int drvnamesize) +{ + LPASIODRVSTRUCT lpdrv = 0; + + if (!drvname) return DRVERR_INVALID_PARAM; + + if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) { + if (strlen(lpdrv->drvname) < (unsigned int)drvnamesize) { + strcpy(drvname,lpdrv->drvname); + } + else { + memcpy(drvname,lpdrv->drvname,drvnamesize-4); + drvname[drvnamesize-4] = '.'; + drvname[drvnamesize-3] = '.'; + drvname[drvnamesize-2] = '.'; + drvname[drvnamesize-1] = 0; + } + return 0; + } + return DRVERR_DEVICE_NOT_FOUND; +} + +LONG AsioDriverList::asioGetDriverPath (int drvID,char *dllpath,int dllpathsize) +{ + LPASIODRVSTRUCT lpdrv = 0; + + if (!dllpath) return DRVERR_INVALID_PARAM; + + if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) { + if (strlen(lpdrv->dllpath) < (unsigned int)dllpathsize) { + strcpy(dllpath,lpdrv->dllpath); + return 0; + } + dllpath[0] = 0; + return DRVERR_INVALID_PARAM; + } + return DRVERR_DEVICE_NOT_FOUND; +} + +LONG AsioDriverList::asioGetDriverCLSID (int drvID,CLSID *clsid) +{ + LPASIODRVSTRUCT lpdrv = 0; + + if (!clsid) return DRVERR_INVALID_PARAM; + + if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) { + memcpy(clsid,&lpdrv->clsid,sizeof(CLSID)); + return 0; + } + return DRVERR_DEVICE_NOT_FOUND; +} + + @@ -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, PulseAudio, and OSS), Macintosh OS X (CoreAudio and JACK), and Windows (DirectSound and ASIO) operating systems. -By Gary P. Scavone, 2001-2012. +By Gary P. Scavone, 2001-2013. To configure and compile (on Unix systems and MinGW): @@ -30,8 +30,14 @@ If you wish to use a different compiler than that selected by configure, specify ./configure CXX=CC -For Windows Users: + +WINDOWS USERS: RtAudio compiles with the MinGW compiler or MS Visual Studio. -Visual C++ 6.0 project files are included for the test programs in the /tests/Windows/ directory. These projects compile API support for both ASIO and DirectSound. Version 4.0 of RtAudio was tested with the .net compiler and it will not compile in Visual C++ 6.0 because of its non-conformance to modern C++ standards. +Visual C++ 6.0 project files (very old) are included for the test programs in the /tests/Windows/ directory. These projects compile API support for both ASIO and DirectSound. + + +LINUX OSS: + +The OSS API support in RtAudio has not been tested for many years. I'm not even sure there are OSS drivers supporting recent linux kernels. In all likelihood, the OSS API code in RtAudio will disappear within the next year or two (if you don't want this to happen, let me know). diff --git a/librtaudio.pc.in b/librtaudio.pc.in new file mode 100644 index 0000000..d7591a7 --- /dev/null +++ b/librtaudio.pc.in @@ -0,0 +1,12 @@ +prefix=/usr/local +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: librtaudio +Description: RtAudio - a set of C++ classes that provide a common API for realtime audio input/output +Version: 4.0.12 +Requires: @req@ +Libs: -L${libdir} -lrtaudio +Libs.private: -lpthread +Cflags: -pthread -I${includedir} @CPPFLAGS@
\ No newline at end of file @@ -1,12 +1,12 @@ RtAudio - a set of C++ classes that provide a common API for realtime audio input/output across Linux (native ALSA, JACK, PulseAudio and OSS), Macintosh OS X (CoreAudio and JACK), and Windows (DirectSound and ASIO) operating systems. -By Gary P. Scavone, 2001-2012. +By Gary P. Scavone, 2001-2013. This distribution of RtAudio contains the following: doc: RtAudio documentation (see doc/html/index.html) tests: example RtAudio programs -asio: header and source files necessary for ASIO compilation +include: header and source files necessary for ASIO, DS & OSS compilation tests/Windows: Visual C++ .net test program workspace and projects OVERVIEW: @@ -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-2012 Gary P. Scavone + Copyright (c) 2001-2013 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/tests/audioprobe.cpp b/tests/audioprobe.cpp index f7246fb..a69437f 100644 --- a/tests/audioprobe.cpp +++ b/tests/audioprobe.cpp @@ -20,12 +20,15 @@ int main() apiMap[RtAudio::WINDOWS_DS] = "Windows Direct Sound"; apiMap[RtAudio::UNIX_JACK] = "Jack Client"; apiMap[RtAudio::LINUX_ALSA] = "Linux ALSA"; + apiMap[RtAudio::LINUX_PULSE] = "Linux PulseAudio"; apiMap[RtAudio::LINUX_OSS] = "Linux OSS"; apiMap[RtAudio::RTAUDIO_DUMMY] = "RtAudio Dummy"; std::vector< RtAudio::Api > apis; RtAudio :: getCompiledApi( apis ); + std::cout << "\nRtAudio Version " << RtAudio::getVersion() << std::endl; + std::cout << "\nCompiled APIs:\n"; for ( unsigned int i=0; i<apis.size(); i++ ) std::cout << " " << apiMap[ apis[i] ] << std::endl; diff --git a/tests/duplex.cpp b/tests/duplex.cpp index 9991dcf..2c60aad 100644 --- a/tests/duplex.cpp +++ b/tests/duplex.cpp @@ -14,24 +14,24 @@ #include <cstring> /* -typedef signed long MY_TYPE; -#define FORMAT RTAUDIO_SINT24 - -typedef char MY_TYPE; +typedef char MY_TYPE; #define FORMAT RTAUDIO_SINT8 */ -typedef signed short MY_TYPE; +typedef signed short MY_TYPE; #define FORMAT RTAUDIO_SINT16 /* -typedef signed long MY_TYPE; +typedef S24 MY_TYPE; +#define FORMAT RTAUDIO_SINT24 + +typedef signed long MY_TYPE; #define FORMAT RTAUDIO_SINT32 -typedef float MY_TYPE; +typedef float MY_TYPE; #define FORMAT RTAUDIO_FLOAT32 -typedef double MY_TYPE; +typedef double MY_TYPE; #define FORMAT RTAUDIO_FLOAT64 */ diff --git a/tests/playraw.cpp b/tests/playraw.cpp index 3b7be76..f57c0b0 100644 --- a/tests/playraw.cpp +++ b/tests/playraw.cpp @@ -26,6 +26,10 @@ typedef signed short MY_TYPE; #define SCALE 32767.0 /* +typedef S24 MY_TYPE; +#define FORMAT RTAUDIO_SINT24 +#define SCALE 8388607.0 + typedef signed int MY_TYPE; #define FORMAT RTAUDIO_SINT32 #define SCALE 2147483647.0 diff --git a/tests/playsaw.cpp b/tests/playsaw.cpp index 2117b54..100d8d9 100644 --- a/tests/playsaw.cpp +++ b/tests/playsaw.cpp @@ -13,29 +13,29 @@ #include <cstdlib> /* -typedef signed long MY_TYPE; -#define FORMAT RTAUDIO_SINT24 -#define SCALE 2147483647.0 - -typedef char MY_TYPE; +typedef char MY_TYPE; #define FORMAT RTAUDIO_SINT8 #define SCALE 127.0 */ -typedef signed short MY_TYPE; +typedef signed short MY_TYPE; #define FORMAT RTAUDIO_SINT16 #define SCALE 32767.0 /* -typedef signed long MY_TYPE; +typedef S24 MY_TYPE; +#define FORMAT RTAUDIO_SINT24 +#define SCALE 8388607.0 + +typedef signed long MY_TYPE; #define FORMAT RTAUDIO_SINT32 #define SCALE 2147483647.0 -typedef float MY_TYPE; +typedef float MY_TYPE; #define FORMAT RTAUDIO_FLOAT32 #define SCALE 1.0 -typedef double MY_TYPE; +typedef double MY_TYPE; #define FORMAT RTAUDIO_FLOAT64 #define SCALE 1.0 */ @@ -88,7 +88,7 @@ int saw( void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames, for ( i=0; i<nBufferFrames; i++ ) { for ( j=0; j<channels; j++ ) { - *buffer++ = (MY_TYPE) (lastValues[j] * SCALE); + *buffer++ = (MY_TYPE) (lastValues[j] * SCALE * 0.5); lastValues[j] += BASE_RATE * (j+1+(j*0.1)); if ( lastValues[j] >= 1.0 ) lastValues[j] -= 2.0; } @@ -116,7 +116,7 @@ int saw( void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames, for ( j=0; j<channels; j++ ) { increment = BASE_RATE * (j+1+(j*0.1)); for ( i=0; i<nBufferFrames; i++ ) { - *buffer++ = (MY_TYPE) (lastValues[j] * SCALE); + *buffer++ = (MY_TYPE) (lastValues[j] * SCALE * 0.5); lastValues[j] += increment; if ( lastValues[j] >= 1.0 ) lastValues[j] -= 2.0; } @@ -163,7 +163,7 @@ int main( int argc, char *argv[] ) oParams.nChannels = channels; oParams.firstChannel = offset; - options.flags |= RTAUDIO_HOG_DEVICE; + options.flags = RTAUDIO_HOG_DEVICE; options.flags |= RTAUDIO_SCHEDULE_REALTIME; #if !defined( USE_INTERLEAVED ) options.flags |= RTAUDIO_NONINTERLEAVED; diff --git a/tests/record.cpp b/tests/record.cpp index e4c7b12..5aa0ef3 100644 --- a/tests/record.cpp +++ b/tests/record.cpp @@ -16,24 +16,24 @@ #include <stdio.h> /* -typedef char MY_TYPE; +typedef char MY_TYPE; #define FORMAT RTAUDIO_SINT8 */ -typedef signed short MY_TYPE; +typedef signed short MY_TYPE; #define FORMAT RTAUDIO_SINT16 /* -typedef signed long MY_TYPE; +typedef S24 MY_TYPE; #define FORMAT RTAUDIO_SINT24 -typedef signed long MY_TYPE; +typedef signed long MY_TYPE; #define FORMAT RTAUDIO_SINT32 -typedef float MY_TYPE; +typedef float MY_TYPE; #define FORMAT RTAUDIO_FLOAT32 -typedef double MY_TYPE; +typedef double MY_TYPE; #define FORMAT RTAUDIO_FLOAT64 */ |
