More updates for 4.0.3 release.
[rtaudio.git] / RtAudio.cpp
index 71be207b5ecb339c47925bbd7245e28d8f8b51d3..cdefda421c9aeacf0254947f05a795af2dd06a97 100644 (file)
@@ -38,7 +38,7 @@
 */
 /************************************************************************/
 
-// RtAudio: Version 4.0
+// RtAudio: Version 4.0.3
 
 #include "RtAudio.h"
 #include <iostream>
@@ -214,27 +214,27 @@ void RtApi :: openStream( RtAudio::StreamParameters *oParams,
 {
   if ( stream_.state != STREAM_CLOSED ) {
     errorText_ = "RtApi::openStream: a stream is already open!";
-    error( INVALID_CALL );
+    error( RtError::INVALID_USE );
   }
 
   if ( oParams && oParams->nChannels < 1 ) {
     errorText_ = "RtApi::openStream: a non-NULL output StreamParameters structure cannot have an nChannels value less than one.";
-    error( INVALID_CALL );
+    error( RtError::INVALID_USE );
   }
 
   if ( iParams && iParams->nChannels < 1 ) {
     errorText_ = "RtApi::openStream: a non-NULL input StreamParameters structure cannot have an nChannels value less than one.";
-    error( INVALID_CALL );
+    error( RtError::INVALID_USE );
   }
 
   if ( oParams == NULL && iParams == NULL ) {
     errorText_ = "RtApi::openStream: input and output StreamParameters structures are both NULL!";
-    error( INVALID_CALL );
+    error( RtError::INVALID_USE );
   }
 
   if ( formatBytes(format) == 0 ) {
     errorText_ = "RtApi::openStream: 'format' parameter value is undefined.";
-    error( INVALID_CALL );
+    error( RtError::INVALID_USE );
   }
 
   unsigned int nDevices = getDeviceCount();
@@ -243,7 +243,7 @@ void RtApi :: openStream( RtAudio::StreamParameters *oParams,
     oChannels = oParams->nChannels;
     if ( oParams->deviceId >= nDevices ) {
       errorText_ = "RtApi::openStream: output device parameter value is invalid.";
-      error( INVALID_CALL );
+      error( RtError::INVALID_USE );
     }
   }
 
@@ -252,7 +252,7 @@ void RtApi :: openStream( RtAudio::StreamParameters *oParams,
     iChannels = iParams->nChannels;
     if ( iParams->deviceId >= nDevices ) {
       errorText_ = "RtApi::openStream: input device parameter value is invalid.";
-      error( INVALID_CALL );
+      error( RtError::INVALID_USE );
     }
   }
 
@@ -263,7 +263,7 @@ void RtApi :: openStream( RtAudio::StreamParameters *oParams,
 
     result = probeDeviceOpen( oParams->deviceId, OUTPUT, oChannels, oParams->firstChannel,
                               sampleRate, format, bufferFrames, options );
-    if ( result == false ) error( SYSTEM );
+    if ( result == false ) error( RtError::SYSTEM_ERROR );
   }
 
   if ( iChannels > 0 ) {
@@ -272,7 +272,7 @@ void RtApi :: openStream( RtAudio::StreamParameters *oParams,
                               sampleRate, format, bufferFrames, options );
     if ( result == false ) {
       if ( oChannels > 0 ) closeStream();
-      error( SYSTEM );
+      error( RtError::SYSTEM_ERROR );
     }
   }
 
@@ -424,7 +424,7 @@ unsigned int RtApiCore :: getDeviceCount( void )
   OSStatus result = AudioHardwareGetPropertyInfo( kAudioHardwarePropertyDevices, &dataSize, NULL );
   if ( result != noErr ) {
     errorText_ = "RtApiCore::getDeviceCount: OS-X error getting device info!";
-    error( WARNING );
+    error( RtError::WARNING );
     return 0;
   }
 
@@ -443,7 +443,7 @@ unsigned int RtApiCore :: getDefaultInputDevice( void )
 
   if ( result != noErr ) {
     errorText_ = "RtApiCore::getDefaultInputDevice: OS-X system error getting device.";
-    error( WARNING );
+    error( RtError::WARNING );
     return 0;
   }
 
@@ -452,7 +452,7 @@ unsigned int RtApiCore :: getDefaultInputDevice( void )
   result = AudioHardwareGetProperty( kAudioHardwarePropertyDevices, &dataSize, (void *) &deviceList );
   if ( result != noErr ) {
     errorText_ = "RtApiCore::getDefaultInputDevice: OS-X system error getting device IDs.";
-    error( WARNING );
+    error( RtError::WARNING );
     return 0;
   }
 
@@ -460,7 +460,7 @@ unsigned int RtApiCore :: getDefaultInputDevice( void )
     if ( id == deviceList[i] ) return i;
 
   errorText_ = "RtApiCore::getDefaultInputDevice: No default device found!";
-  error( WARNING );
+  error( RtError::WARNING );
   return 0;
 }
 
@@ -476,7 +476,7 @@ unsigned int RtApiCore :: getDefaultOutputDevice( void )
 
   if ( result != noErr ) {
     errorText_ = "RtApiCore::getDefaultOutputDevice: OS-X system error getting device.";
-    error( WARNING );
+    error( RtError::WARNING );
     return 0;
   }
 
@@ -485,7 +485,7 @@ unsigned int RtApiCore :: getDefaultOutputDevice( void )
   result = AudioHardwareGetProperty( kAudioHardwarePropertyDevices, &dataSize, (void *) &deviceList );
   if ( result != noErr ) {
     errorText_ = "RtApiCore::getDefaultOutputDevice: OS-X system error getting device IDs.";
-    error( WARNING );
+    error( RtError::WARNING );
     return 0;
   }
 
@@ -493,7 +493,7 @@ unsigned int RtApiCore :: getDefaultOutputDevice( void )
     if ( id == deviceList[i] ) return i;
 
   errorText_ = "RtApiCore::getDefaultOutputDevice: No default device found!";
-  error( WARNING );
+  error( RtError::WARNING );
   return 0;
 }
 
@@ -506,12 +506,12 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )
   unsigned int nDevices = getDeviceCount();
   if ( nDevices == 0 ) {
     errorText_ = "RtApiCore::getDeviceInfo: no devices found!";
-    error( INVALID_CALL );
+    error( RtError::INVALID_USE );
   }
 
   if ( device >= nDevices ) {
     errorText_ = "RtApiCore::getDeviceInfo: device ID is invalid!";
-    error( INVALID_CALL );
+    error( RtError::INVALID_USE );
   }
 
   AudioDeviceID deviceList[ nDevices ];
@@ -519,7 +519,7 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )
   OSStatus result = AudioHardwareGetProperty( kAudioHardwarePropertyDevices, &dataSize, (void *) &deviceList );
   if ( result != noErr ) {
     errorText_ = "RtApiCore::getDeviceInfo: OS-X system error getting device IDs.";
-    error( WARNING );
+    error( RtError::WARNING );
     return info;
   }
 
@@ -536,10 +536,10 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )
   if ( result != noErr ) {
     errorStream_ << "RtApiCore::probeDeviceInfo: system error (" << getErrorCode( result ) << ") getting device manufacturer.";
     errorText_ = errorStream_.str();
-    error( WARNING );
+    error( RtError::WARNING );
     return info;
   }
-  info.name.append( (const char *)name, strlen(name) + 1 );
+  info.name.append( (const char *)name, strlen(name) );
   info.name.append( ": " );
 
   dataSize = 256;
@@ -549,10 +549,10 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )
   if ( result != noErr ) {
     errorStream_ << "RtApiCore::probeDeviceInfo: system error (" << getErrorCode( result ) << ") getting device name.";
     errorText_ = errorStream_.str();
-    error( WARNING );
+    error( RtError::WARNING );
     return info;
   }
-  info.name.append( (const char *)name, strlen(name) + 1 );
+  info.name.append( (const char *)name, strlen(name) );
 
   // Get the output stream "configuration".
   AudioBufferList      *bufferList = nil;
@@ -562,7 +562,7 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )
   if (result != noErr || dataSize == 0) {
     errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting output stream configuration info for device (" << device << ").";
     errorText_ = errorStream_.str();
-    error( WARNING );
+    error( RtError::WARNING );
     return info;
   }
 
@@ -570,7 +570,7 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )
   bufferList = (AudioBufferList *) malloc( dataSize );
   if ( bufferList == NULL ) {
     errorText_ = "RtApiCore::getDeviceInfo: memory error allocating output AudioBufferList.";
-    error( WARNING );
+    error( RtError::WARNING );
     return info;
   }
 
@@ -581,7 +581,7 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )
     free( bufferList );
     errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting output stream configuration for device (" << device << ").";
     errorText_ = errorStream_.str();
-    error( WARNING );
+    error( RtError::WARNING );
     return info;
   }
 
@@ -598,7 +598,7 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )
   if (result != noErr || dataSize == 0) {
     errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting input stream configuration info for device (" << device << ").";
     errorText_ = errorStream_.str();
-    error( WARNING );
+    error( RtError::WARNING );
     return info;
   }
 
@@ -606,7 +606,7 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )
   bufferList = (AudioBufferList *) malloc( dataSize );
   if ( bufferList == NULL ) {
     errorText_ = "RtApiCore::getDeviceInfo: memory error allocating input AudioBufferList.";
-    error( WARNING );
+    error( RtError::WARNING );
     return info;
   }
 
@@ -617,7 +617,7 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )
     free( bufferList );
     errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting input stream configuration for device (" << device << ").";
     errorText_ = errorStream_.str();
-    error( WARNING );
+    error( RtError::WARNING );
     return info;
   }
 
@@ -643,7 +643,7 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )
   if ( result != kAudioHardwareNoError || dataSize == 0 ) {
     errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting sample rate info.";
     errorText_ = errorStream_.str();
-    error( WARNING );
+    error( RtError::WARNING );
     return info;
   }
 
@@ -656,7 +656,7 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )
   if ( result != kAudioHardwareNoError ) {
     errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting sample rates.";
     errorText_ = errorStream_.str();
-    error( WARNING );
+    error( RtError::WARNING );
     return info;
   }
 
@@ -675,7 +675,7 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )
   if ( info.sampleRates.size() == 0 ) {
     errorStream_ << "RtApiCore::probeDeviceInfo: No supported sample rates found for device (" << device << ").";
     errorText_ = errorStream_.str();
-    error( WARNING );
+    error( RtError::WARNING );
     return info;
   }
 
@@ -1039,7 +1039,7 @@ bool RtApiCore :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
     else {
       errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting device latency for device (" << device << ").";
       errorText_ = errorStream_.str();
-      error( WARNING );
+      error( RtError::WARNING );
     }
   }
 
@@ -1050,7 +1050,7 @@ bool RtApiCore :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
   else {
     errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting stream latency for device (" << device << ").";
     errorText_ = errorStream_.str();
-    error( WARNING );
+    error( RtError::WARNING );
   }
 
   // Byte-swapping: According to AudioHardware.h, the stream data will
@@ -1217,7 +1217,7 @@ void RtApiCore :: closeStream( void )
 {
   if ( stream_.state == STREAM_CLOSED ) {
     errorText_ = "RtApiCore::closeStream(): no open stream to close!";
-    error( WARNING );
+    error( RtError::WARNING );
     return;
   }
 
@@ -1260,7 +1260,7 @@ void RtApiCore :: startStream( void )
   verifyStream();
   if ( stream_.state == STREAM_RUNNING ) {
     errorText_ = "RtApiCore::startStream(): the stream is already running!";
-    error( WARNING );
+    error( RtError::WARNING );
     return;
   }
 
@@ -1297,7 +1297,7 @@ void RtApiCore :: startStream( void )
   MUTEX_UNLOCK( &stream_.mutex );
 
   if ( result == noErr ) return;
-  error( SYSTEM );
+  error( RtError::SYSTEM_ERROR );
 }
 
 void RtApiCore :: stopStream( void )
@@ -1305,7 +1305,7 @@ void RtApiCore :: stopStream( void )
   verifyStream();
   if ( stream_.state == STREAM_STOPPED ) {
     errorText_ = "RtApiCore::stopStream(): the stream is already stopped!";
-    error( WARNING );
+    error( RtError::WARNING );
     return;
   }
 
@@ -1343,7 +1343,7 @@ void RtApiCore :: stopStream( void )
 
   stream_.state = STREAM_STOPPED;
   if ( result == noErr ) return;
-  error( SYSTEM );
+  error( RtError::SYSTEM_ERROR );
 }
 
 void RtApiCore :: abortStream( void )
@@ -1351,7 +1351,7 @@ void RtApiCore :: abortStream( void )
   verifyStream();
   if ( stream_.state == STREAM_STOPPED ) {
     errorText_ = "RtApiCore::abortStream(): the stream is already stopped!";
-    error( WARNING );
+    error( RtError::WARNING );
     return;
   }
 
@@ -1368,7 +1368,7 @@ bool RtApiCore :: callbackEvent( AudioDeviceID deviceId,
   if ( stream_.state == STREAM_STOPPED ) return SUCCESS;
   if ( stream_.state == STREAM_CLOSED ) {
     errorText_ = "RtApiCore::callbackEvent(): the stream is closed ... this shouldn't happen!";
-    error( WARNING );
+    error( RtError::WARNING );
     return FAILURE;
   }
 
@@ -1646,7 +1646,7 @@ RtAudio::DeviceInfo RtApiJack :: getDeviceInfo( unsigned int device )
   jack_client_t *client = jack_client_new( "RtApiJackInfo" );
   if ( client == 0 ) {
     errorText_ = "RtApiJack::getDeviceInfo: Jack server not found or connection error!";
-    error( WARNING );
+    error( RtError::WARNING );
     return info;
   }
 
@@ -1674,7 +1674,7 @@ RtAudio::DeviceInfo RtApiJack :: getDeviceInfo( unsigned int device )
 
   if ( device >= nDevices ) {
     errorText_ = "RtApiJack::getDeviceInfo: device ID is invalid!";
-    error( INVALID_CALL );
+    error( RtError::INVALID_USE );
   }
 
   // Get the current jack server sample rate.
@@ -1703,7 +1703,7 @@ RtAudio::DeviceInfo RtApiJack :: getDeviceInfo( unsigned int device )
   if ( info.outputChannels == 0 && info.inputChannels == 0 ) {
     jack_client_close(client);
     errorText_ = "RtApiJack::getDeviceInfo: error determining Jack input/output channels!";
-    error( WARNING );
+    error( RtError::WARNING );
     return info;
   }
 
@@ -1777,7 +1777,7 @@ bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
       client = jack_client_new( "RtApiJack" );
     if ( client == 0 ) {
       errorText_ = "RtApiJack::probeDeviceOpen: Jack server not found or connection error!";
-      error( WARNING );
+      error( RtError::WARNING );
       return FAILURE;
     }
   }
@@ -2005,7 +2005,7 @@ void RtApiJack :: closeStream( void )
 {
   if ( stream_.state == STREAM_CLOSED ) {
     errorText_ = "RtApiJack::closeStream(): no open stream to close!";
-    error( WARNING );
+    error( RtError::WARNING );
     return;
   }
 
@@ -2047,7 +2047,7 @@ void RtApiJack :: startStream( void )
   verifyStream();
   if ( stream_.state == STREAM_RUNNING ) {
     errorText_ = "RtApiJack::startStream(): the stream is already running!";
-    error( WARNING );
+    error( RtError::WARNING );
     return;
   }
 
@@ -2117,7 +2117,7 @@ void RtApiJack :: startStream( void )
   MUTEX_UNLOCK(&stream_.mutex);
 
   if ( result == 0 ) return;
-  error( SYSTEM );
+  error( RtError::SYSTEM_ERROR );
 }
 
 void RtApiJack :: stopStream( void )
@@ -2125,7 +2125,7 @@ void RtApiJack :: stopStream( void )
   verifyStream();
   if ( stream_.state == STREAM_STOPPED ) {
     errorText_ = "RtApiJack::stopStream(): the stream is already stopped!";
-    error( WARNING );
+    error( RtError::WARNING );
     return;
   }
 
@@ -2151,7 +2151,7 @@ void RtApiJack :: abortStream( void )
   verifyStream();
   if ( stream_.state == STREAM_STOPPED ) {
     errorText_ = "RtApiJack::abortStream(): the stream is already stopped!";
-    error( WARNING );
+    error( RtError::WARNING );
     return;
   }
 
@@ -2166,12 +2166,12 @@ bool RtApiJack :: callbackEvent( unsigned long nframes )
   if ( stream_.state == STREAM_STOPPED ) return SUCCESS;
   if ( stream_.state == STREAM_CLOSED ) {
     errorText_ = "RtApiCore::callbackEvent(): the stream is closed ... this shouldn't happen!";
-    error( WARNING );
+    error( RtError::WARNING );
     return FAILURE;
   }
   if ( stream_.bufferSize != nframes ) {
     errorText_ = "RtApiCore::callbackEvent(): the JACK buffer size has changed ... cannot process!";
-    error( WARNING );
+    error( RtError::WARNING );
     return FAILURE;
   }
 
@@ -2291,10 +2291,10 @@ bool RtApiJack :: callbackEvent( unsigned long nframes )
 // on information found in
 // http://www.cs.wustl.edu/~schmidt/win32-cv-1.html.
 
-#include "asio/asiosys.h"
-#include "asio/asio.h"
-#include "asio/iasiothiscallresolver.h"
-#include "asio/asiodrivers.h"
+#include "asiosys.h"
+#include "asio.h"
+#include "iasiothiscallresolver.h"
+#include "asiodrivers.h"
 #include <cmath>
 
 AsioDrivers drivers;
@@ -2327,7 +2327,7 @@ RtApiAsio :: RtApiAsio()
   HRESULT hr = CoInitialize( NULL ); 
   if ( FAILED(hr) ) {
     errorText_ = "RtApiAsio::ASIO requires a single-threaded appartment. Call CoInitializeEx(0,COINIT_APARTMENTTHREADED)";
-    error( WARNING );
+    error( RtError::WARNING );
   }
   coInitialized_ = true;
 
@@ -2358,19 +2358,22 @@ RtAudio::DeviceInfo RtApiAsio :: getDeviceInfo( unsigned int device )
   unsigned int nDevices = getDeviceCount();
   if ( nDevices == 0 ) {
     errorText_ = "RtApiAsio::getDeviceInfo: no devices found!";
-    error( INVALID_CALL );
+    error( RtError::INVALID_USE );
   }
 
   if ( device >= nDevices ) {
     errorText_ = "RtApiAsio::getDeviceInfo: device ID is invalid!";
-    error( INVALID_CALL );
+    error( RtError::INVALID_USE );
   }
 
-  // Don't probe if a stream is already open.
+  // If a stream is already open, we cannot probe other devices.  Thus, use the saved results.
   if ( stream_.state != STREAM_CLOSED ) {
-    errorText_ = "RtApiAsio::getDeviceInfo: unable to probe driver while a stream is open.";
-    error( WARNING );
-    return info;
+    if ( device >= devices_.size() ) {
+      errorText_ = "RtApiAsio::getDeviceInfo: device ID was not present before stream was opened.";
+      error( RtError::WARNING );
+      return info;
+    }
+    return devices_[ device ];
   }
 
   char driverName[32];
@@ -2378,7 +2381,7 @@ RtAudio::DeviceInfo RtApiAsio :: getDeviceInfo( unsigned int device )
   if ( result != ASE_OK ) {
     errorStream_ << "RtApiAsio::getDeviceInfo: unable to get driver name (" << getAsioErrorString( result ) << ").";
     errorText_ = errorStream_.str();
-    error( WARNING );
+    error( RtError::WARNING );
     return info;
   }
 
@@ -2387,7 +2390,7 @@ RtAudio::DeviceInfo RtApiAsio :: getDeviceInfo( unsigned int device )
   if ( !drivers.loadDriver( driverName ) ) {
     errorStream_ << "RtApiAsio::getDeviceInfo: unable to load driver (" << driverName << ").";
     errorText_ = errorStream_.str();
-    error( WARNING );
+    error( RtError::WARNING );
     return info;
   }
 
@@ -2395,7 +2398,7 @@ RtAudio::DeviceInfo RtApiAsio :: getDeviceInfo( unsigned int device )
   if ( result != ASE_OK ) {
     errorStream_ << "RtApiAsio::getDeviceInfo: error (" << getAsioErrorString( result ) << ") initializing driver (" << driverName << ").";
     errorText_ = errorStream_.str();
-    error( WARNING );
+    error( RtError::WARNING );
     return info;
   }
 
@@ -2406,7 +2409,7 @@ RtAudio::DeviceInfo RtApiAsio :: getDeviceInfo( unsigned int device )
     drivers.removeCurrentDriver();
     errorStream_ << "RtApiAsio::getDeviceInfo: error (" << getAsioErrorString( result ) << ") getting channel count (" << driverName << ").";
     errorText_ = errorStream_.str();
-    error( WARNING );
+    error( RtError::WARNING );
     return info;
   }
 
@@ -2433,7 +2436,7 @@ RtAudio::DeviceInfo RtApiAsio :: getDeviceInfo( unsigned int device )
     drivers.removeCurrentDriver();
     errorStream_ << "RtApiAsio::getDeviceInfo: error (" << getAsioErrorString( result ) << ") getting driver channel info (" << driverName << ").";
     errorText_ = errorStream_.str();
-    error( WARNING );
+    error( RtError::WARNING );
     return info;
   }
 
@@ -2463,6 +2466,16 @@ void bufferSwitch( long index, ASIOBool processNow )
   object->callbackEvent( index );
 }
 
+void RtApiAsio :: saveDeviceInfo( void )
+{
+  devices_.clear();
+
+  unsigned int nDevices = getDeviceCount();
+  devices_.resize( nDevices );
+  for ( unsigned int i=0; i<nDevices; i++ )
+    devices_[i] = getDeviceInfo( i );
+}
+
 bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
                                    unsigned int firstChannel, unsigned int sampleRate,
                                    RtAudioFormat format, unsigned int *bufferSize,
@@ -2482,6 +2495,12 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
     return FAILURE;
   }
 
+  // The getDeviceInfo() function will not work when a stream is open
+  // because ASIO does not allow multiple devices to run at the same
+  // time.  Thus, we'll probe the system before opening a stream and
+  // save the results for use by getDeviceInfo().
+  this->saveDeviceInfo();
+
   // Only load the driver once for duplex stream.
   if ( mode != INPUT || stream_.mode != OUTPUT ) {
     if ( !drivers.loadDriver( driverName ) ) {
@@ -2528,15 +2547,27 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
     return FAILURE;
   }
 
-  // Set the sample rate.
-  result = ASIOSetSampleRate( (ASIOSampleRate) sampleRate );
+  // Get the current sample rate
+  ASIOSampleRate currentRate;
+  result = ASIOGetSampleRate( &currentRate );
   if ( result != ASE_OK ) {
     drivers.removeCurrentDriver();
-    errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error setting sample rate (" << sampleRate << ").";
+    errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error getting sample rate.";
     errorText_ = errorStream_.str();
     return FAILURE;
   }
 
+  // Set the sample rate only if necessary
+  if ( currentRate != sampleRate ) {
+    result = ASIOSetSampleRate( (ASIOSampleRate) sampleRate );
+    if ( result != ASE_OK ) {
+      drivers.removeCurrentDriver();
+      errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error setting sample rate (" << sampleRate << ").";
+      errorText_ = errorStream_.str();
+      return FAILURE;
+    }
+  }
+
   // Determine the driver data type.
   ASIOChannelInfo channelInfo;
   channelInfo.channel = 0;
@@ -2696,7 +2727,8 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
     stream_.doConvertBuffer[mode] = true;
 
   // 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_ = "RtApiAsio::probeDeviceOpen: error allocating user buffer memory.";
@@ -2741,7 +2773,7 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
   if ( result != ASE_OK ) {
     errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") getting latency.";
     errorText_ = errorStream_.str();
-    error( WARNING); // warn but don't fail
+    error( RtError::WARNING); // warn but don't fail
   }
   else {
     stream_.latency[0] = outputLatency;
@@ -2787,7 +2819,7 @@ void RtApiAsio :: closeStream()
 {
   if ( stream_.state == STREAM_CLOSED ) {
     errorText_ = "RtApiAsio::closeStream(): no open stream to close!";
-    error( WARNING );
+    error( RtError::WARNING );
     return;
   }
 
@@ -2828,7 +2860,7 @@ void RtApiAsio :: startStream()
   verifyStream();
   if ( stream_.state == STREAM_RUNNING ) {
     errorText_ = "RtApiAsio::startStream(): the stream is already running!";
-    error( WARNING );
+    error( RtError::WARNING );
     return;
   }
 
@@ -2851,7 +2883,7 @@ void RtApiAsio :: startStream()
   MUTEX_UNLOCK( &stream_.mutex );
 
   if ( result == ASE_OK ) return;
-  error( SYSTEM );
+  error( RtError::SYSTEM_ERROR );
 }
 
 void RtApiAsio :: stopStream()
@@ -2859,7 +2891,7 @@ void RtApiAsio :: stopStream()
   verifyStream();
   if ( stream_.state == STREAM_STOPPED ) {
     errorText_ = "RtApiAsio::stopStream(): the stream is already stopped!";
-    error( WARNING );
+    error( RtError::WARNING );
     return;
   }
 
@@ -2886,7 +2918,7 @@ void RtApiAsio :: stopStream()
   MUTEX_UNLOCK( &stream_.mutex );
 
   if ( result == ASE_OK ) return;
-  error( SYSTEM );
+  error( RtError::SYSTEM_ERROR );
 }
 
 void RtApiAsio :: abortStream()
@@ -2894,7 +2926,7 @@ void RtApiAsio :: abortStream()
   verifyStream();
   if ( stream_.state == STREAM_STOPPED ) {
     errorText_ = "RtApiAsio::abortStream(): the stream is already stopped!";
-    error( WARNING );
+    error( RtError::WARNING );
     return;
   }
 
@@ -2912,7 +2944,7 @@ bool RtApiAsio :: callbackEvent( long bufferIndex )
   if ( stream_.state == STREAM_STOPPED ) return SUCCESS;
   if ( stream_.state == STREAM_CLOSED ) {
     errorText_ = "RtApiAsio::callbackEvent(): the stream is closed ... this shouldn't happen!";
-    error( WARNING );
+    error( RtError::WARNING );
     return FAILURE;
   }
 
@@ -2958,8 +2990,8 @@ bool RtApiAsio :: callbackEvent( long bufferIndex )
       handle->internalDrain = true;
   }
 
-  unsigned int bufferBytes, i, j;
-  unsigned int nChannels = stream_.nDeviceChannels[0] + stream_.nDeviceChannels[1];
+  unsigned int nChannels, bufferBytes, i, j;
+  nChannels = stream_.nDeviceChannels[0] + stream_.nDeviceChannels[1];
   if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
 
     bufferBytes = stream_.bufferSize * formatBytes( stream_.deviceFormat[0] );
@@ -3187,6 +3219,14 @@ static const char* getAsioErrorString( ASIOError result )
 #include <dsound.h>
 #include <assert.h>
 
+#if defined(__MINGW32__)
+// 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 */
+#define WAVE_FORMAT_96S16 0x00080000 /* 96 kHz, Stereo, 16-bit */
+#endif
+
 #define MINIMUM_DEVICE_BUFFER_SIZE 32768
 
 #ifdef _MSC_VER // if Microsoft Visual C++
@@ -3223,7 +3263,7 @@ struct DsHandle {
   HANDLE condition;
 
   DsHandle()
-    :drainCounter(0), internalDrain(false) { id[0] = 0, id[1] = 0; xrun[0] = false; xrun[1] = false; bufferPointer[0] = 0; bufferPointer[1] = 0; }
+    :drainCounter(0), internalDrain(false) { id[0] = 0; id[1] = 0; buffer[0] = 0; buffer[1] = 0; xrun[0] = false; xrun[1] = false; bufferPointer[0] = 0; bufferPointer[1] = 0; }
 };
 
 /*
@@ -3247,7 +3287,7 @@ RtApiDs::RtDsStatistics RtApiDs::getDsStatistics()
 
 // Declarations for utility functions, callbacks, and structures
 // specific to the DirectSound implementation.
-static bool CALLBACK deviceCountCallback( LPGUID lpguid,
+static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid,
                                           LPCTSTR description,
                                           LPCTSTR module,
                                           LPVOID lpContext );
@@ -3288,22 +3328,22 @@ unsigned int RtApiDs :: getDefaultInputDevice( void )
 {
   // Count output devices.
   EnumInfo info;
-  HRESULT result = DirectSoundEnumerate( (LPDSENUMCALLBACK) deviceCountCallback, &info );
+  HRESULT result = DirectSoundEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &info );
   if ( FAILED( result ) ) {
     errorStream_ << "RtApiDs::getDefaultOutputDevice: error (" << getErrorString( result ) << ") counting output devices!";
     errorText_ = errorStream_.str();
-    error( WARNING );
+    error( RtError::WARNING );
     return 0;
   }
 
   // Now enumerate input devices until we find the id = NULL.
   info.isInput = true;
   info.getDefault = true;
-  result = DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK) deviceCountCallback, &info );
+  result = DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &info );
   if ( FAILED( result ) ) {
     errorStream_ << "RtApiDs::getDefaultInputDevice: error (" << getErrorString( result ) << ") enumerating input devices!";
     errorText_ = errorStream_.str();
-    error( WARNING );
+    error( RtError::WARNING );
     return 0;
   }
 
@@ -3316,11 +3356,11 @@ unsigned int RtApiDs :: getDefaultOutputDevice( void )
   // Enumerate output devices until we find the id = NULL.
   EnumInfo info;
   info.getDefault = true;
-  HRESULT result = DirectSoundEnumerate( (LPDSENUMCALLBACK) deviceCountCallback, &info );
+  HRESULT result = DirectSoundEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &info );
   if ( FAILED( result ) ) {
     errorStream_ << "RtApiDs::getDefaultOutputDevice: error (" << getErrorString( result ) << ") enumerating output devices!";
     errorText_ = errorStream_.str();
-    error( WARNING );
+    error( RtError::WARNING );
     return 0;
   }
 
@@ -3332,20 +3372,20 @@ unsigned int RtApiDs :: getDeviceCount( void )
 {
   // Count DirectSound devices.
   EnumInfo info;
-  HRESULT result = DirectSoundEnumerate( (LPDSENUMCALLBACK) deviceCountCallback, &info );
+  HRESULT result = DirectSoundEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &info );
   if ( FAILED( result ) ) {
     errorStream_ << "RtApiDs::getDeviceCount: error (" << getErrorString( result ) << ") enumerating output devices!";
     errorText_ = errorStream_.str();
-    error( WARNING );
+    error( RtError::WARNING );
   }
 
   // Count DirectSoundCapture devices.
   info.isInput = true;
-  result = DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK) deviceCountCallback, &info );
+  result = DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &info );
   if ( FAILED( result ) ) {
     errorStream_ << "RtApiDs::getDeviceCount: error (" << getErrorString( result ) << ") enumerating input devices!";
     errorText_ = errorStream_.str();
-    error( WARNING );
+    error( RtError::WARNING );
   }
 
   return info.counter;
@@ -3366,11 +3406,11 @@ RtAudio::DeviceInfo RtApiDs :: getDeviceInfo( unsigned int device )
   EnumInfo dsinfo;
   dsinfo.findIndex = true;
   dsinfo.index = device;
-  HRESULT result = DirectSoundEnumerate( (LPDSENUMCALLBACK) deviceCountCallback, &dsinfo );
+  HRESULT result = DirectSoundEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &dsinfo );
   if ( FAILED( result ) ) {
     errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") enumerating output devices!";
     errorText_ = errorStream_.str();
-    error( WARNING );
+    error( RtError::WARNING );
   }
 
   if ( dsinfo.name.empty() ) goto probeInput;
@@ -3381,7 +3421,7 @@ RtAudio::DeviceInfo RtApiDs :: getDeviceInfo( unsigned int device )
   if ( FAILED( result ) ) {
     errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") opening output device (" << dsinfo.name << ")!";
     errorText_ = errorStream_.str();
-    error( WARNING );
+    error( RtError::WARNING );
     return info;
   }
 
@@ -3391,7 +3431,7 @@ RtAudio::DeviceInfo RtApiDs :: getDeviceInfo( unsigned int device )
     output->Release();
     errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") getting capabilities!";
     errorText_ = errorStream_.str();
-    error( WARNING );
+    error( RtError::WARNING );
     return info;
   }
 
@@ -3424,11 +3464,11 @@ RtAudio::DeviceInfo RtApiDs :: getDeviceInfo( unsigned int device )
  probeInput:
 
   dsinfo.isInput = true;
-  result = DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK) deviceCountCallback, &dsinfo );
+  result = DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &dsinfo );
   if ( FAILED( result ) ) {
     errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") enumerating input devices!";
     errorText_ = errorStream_.str();
-    error( WARNING );
+    error( RtError::WARNING );
   }
 
   if ( dsinfo.name.empty() ) return info;
@@ -3438,7 +3478,7 @@ RtAudio::DeviceInfo RtApiDs :: getDeviceInfo( unsigned int device )
   if ( FAILED( result ) ) {
     errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") opening input device (" << dsinfo.name << ")!";
     errorText_ = errorStream_.str();
-    error( WARNING );
+    error( RtError::WARNING );
     return info;
   }
 
@@ -3449,7 +3489,7 @@ RtAudio::DeviceInfo RtApiDs :: getDeviceInfo( unsigned int device )
     input->Release();
     errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") getting object capabilities (" << dsinfo.name << ")!";
     errorText_ = errorStream_.str();
-    error( WARNING );
+    error( RtError::WARNING );
     return info;
   }
 
@@ -3534,7 +3574,7 @@ bool RtApiDs :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned
   EnumInfo dsinfo;
   dsinfo.findIndex = true;
   dsinfo.index = device;
-  HRESULT result = DirectSoundEnumerate( (LPDSENUMCALLBACK) deviceCountCallback, &dsinfo );
+  HRESULT result = DirectSoundEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &dsinfo );
   if ( FAILED( result ) ) {
     errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") enumerating output devices!";
     errorText_ = errorStream_.str();
@@ -3550,7 +3590,7 @@ bool RtApiDs :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned
   }
   else { // mode == INPUT
     dsinfo.isInput = true;
-    HRESULT result = DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK) deviceCountCallback, &dsinfo );
+    HRESULT result = DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &dsinfo );
     if ( FAILED( result ) ) {
       errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") enumerating input devices!";
       errorText_ = errorStream_.str();
@@ -3858,6 +3898,7 @@ bool RtApiDs :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned
   }
 
   // Set various stream parameters
+  DsHandle *handle = 0;
   stream_.nDeviceChannels[mode] = channels + firstChannel;
   stream_.nUserChannels[mode] = channels;
   stream_.bufferSize = *bufferSize;
@@ -3907,7 +3948,6 @@ bool RtApiDs :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned
   }
 
   // Allocate our DsHandle structures for the stream.
-  DsHandle *handle;
   if ( stream_.apiHandle == 0 ) {
     try {
       handle = new DsHandle;
@@ -3995,7 +4035,7 @@ void RtApiDs :: closeStream()
 {
   if ( stream_.state == STREAM_CLOSED ) {
     errorText_ = "RtApiDs::closeStream(): no open stream to close!";
-    error( WARNING );
+    error( RtError::WARNING );
     return;
   }
 
@@ -4050,7 +4090,7 @@ void RtApiDs :: startStream()
   verifyStream();
   if ( stream_.state == STREAM_RUNNING ) {
     errorText_ = "RtApiDs::startStream(): the stream is already running!";
-    error( WARNING );
+    error( RtError::WARNING );
     return;
   }
 
@@ -4078,7 +4118,7 @@ void RtApiDs :: startStream()
     duplexPrerollBytes = (int) ( 0.5 * stream_.sampleRate * formatBytes( stream_.deviceFormat[1] ) * stream_.nDeviceChannels[1] );
   }
 
-  HRESULT result;
+  HRESULT result = 0;
   if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
     //statistics.outputFrameSize = formatBytes( stream_.deviceFormat[0] ) * stream_.nDeviceChannels[0];
 
@@ -4110,7 +4150,7 @@ void RtApiDs :: startStream()
  unlock:
   MUTEX_UNLOCK( &stream_.mutex );
 
-  if ( FAILED( result ) ) error( SYSTEM );
+  if ( FAILED( result ) ) error( RtError::SYSTEM_ERROR );
 }
 
 void RtApiDs :: stopStream()
@@ -4118,13 +4158,13 @@ void RtApiDs :: stopStream()
   verifyStream();
   if ( stream_.state == STREAM_STOPPED ) {
     errorText_ = "RtApiDs::stopStream(): the stream is already stopped!";
-    error( WARNING );
+    error( RtError::WARNING );
     return;
   }
 
   MUTEX_LOCK( &stream_.mutex );
 
-  HRESULT result;
+  HRESULT result = 0;
   LPVOID audioPtr;
   DWORD dataLen;
   DsHandle *handle = (DsHandle *) stream_.apiHandle;
@@ -4210,7 +4250,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( SYSTEM );
+  if ( FAILED( result ) ) error( RtError::SYSTEM_ERROR );
 }
 
 void RtApiDs :: abortStream()
@@ -4218,7 +4258,7 @@ void RtApiDs :: abortStream()
   verifyStream();
   if ( stream_.state == STREAM_STOPPED ) {
     errorText_ = "RtApiDs::abortStream(): the stream is already stopped!";
-    error( WARNING );
+    error( RtError::WARNING );
     return;
   }
 
@@ -4237,7 +4277,7 @@ void RtApiDs :: callbackEvent()
 
   if ( stream_.state == STREAM_CLOSED ) {
     errorText_ = "RtApiDs::callbackEvent(): the stream is closed ... this shouldn't happen!";
-    error( WARNING );
+    error( RtError::WARNING );
     return;
   }
 
@@ -4325,26 +4365,26 @@ void RtApiDs :: callbackEvent()
     if ( FAILED( result ) ) {
       errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";
       errorText_ = errorStream_.str();
-      error( SYSTEM );
+      error( RtError::SYSTEM_ERROR );
     }
     result = dsCaptureBuffer->GetCurrentPosition( &initialReadPos, &initialSafeReadPos );
     if ( FAILED( result ) ) {
       errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";
       errorText_ = errorStream_.str();
-      error( SYSTEM );
+      error( RtError::SYSTEM_ERROR );
     }
     while ( true ) {
       result = dsWriteBuffer->GetCurrentPosition( &currentWritePos, &safeWritePos );
       if ( FAILED( result ) ) {
         errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";
         errorText_ = errorStream_.str();
-        error( SYSTEM );
+        error( RtError::SYSTEM_ERROR );
       }
       result = dsCaptureBuffer->GetCurrentPosition( &currentReadPos, &safeReadPos );
       if ( FAILED( result ) ) {
         errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";
         errorText_ = errorStream_.str();
-        error( SYSTEM );
+        error( RtError::SYSTEM_ERROR );
       }
       if ( safeWritePos != initialSafeWritePos && safeReadPos != initialSafeReadPos ) break;
       Sleep( 1 );
@@ -4398,7 +4438,7 @@ void RtApiDs :: callbackEvent()
       if ( FAILED( result ) ) {
         errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";
         errorText_ = errorStream_.str();
-        error( SYSTEM );
+        error( RtError::SYSTEM_ERROR );
       }
 
       leadPos = safeWritePos + handle->dsPointerLeadTime[0];
@@ -4449,7 +4489,7 @@ void RtApiDs :: callbackEvent()
     if ( FAILED( result ) ) {
       errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") locking buffer during playback!";
       errorText_ = errorStream_.str();
-      error( SYSTEM );
+      error( RtError::SYSTEM_ERROR );
     }
 
     // Copy our buffer into the DS buffer
@@ -4461,7 +4501,7 @@ void RtApiDs :: callbackEvent()
     if ( FAILED( result ) ) {
       errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") unlocking buffer during playback!";
       errorText_ = errorStream_.str();
-      error( SYSTEM );
+      error( RtError::SYSTEM_ERROR );
     }
     nextWritePos = ( nextWritePos + bufferSize1 + bufferSize2 ) % dsBufferSize;
     handle->bufferPointer[0] = nextWritePos;
@@ -4495,7 +4535,7 @@ void RtApiDs :: callbackEvent()
     if ( FAILED( result ) ) {
       errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";
       errorText_ = errorStream_.str();
-      error( SYSTEM );
+      error( RtError::SYSTEM_ERROR );
     }
 
     if ( safeReadPos < (DWORD)nextReadPos ) safeReadPos += dsBufferSize; // unwrap offset
@@ -4558,7 +4598,7 @@ void RtApiDs :: callbackEvent()
         if ( FAILED( result ) ) {
           errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";
           errorText_ = errorStream_.str();
-          error( SYSTEM );
+          error( RtError::SYSTEM_ERROR );
         }
       
         if ( safeReadPos < (DWORD)nextReadPos ) safeReadPos += dsBufferSize; // unwrap offset
@@ -4574,7 +4614,7 @@ void RtApiDs :: callbackEvent()
     if ( FAILED( result ) ) {
       errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") locking capture buffer!";
       errorText_ = errorStream_.str();
-      error( SYSTEM );
+      error( RtError::SYSTEM_ERROR );
     }
 
     if ( duplexPrerollBytes <= 0 ) {
@@ -4594,7 +4634,7 @@ void RtApiDs :: callbackEvent()
     if ( FAILED( result ) ) {
       errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") unlocking capture buffer!";
       errorText_ = errorStream_.str();
-      error( SYSTEM );
+      error( RtError::SYSTEM_ERROR );
     }
     handle->bufferPointer[1] = nextReadPos;
 
@@ -4665,7 +4705,7 @@ std::string convertTChar( LPCTSTR name )
   return s;
 }
 
-static bool CALLBACK deviceCountCallback( LPGUID lpguid,
+static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid,
                                           LPCTSTR description,
                                           LPCTSTR module,
                                           LPVOID lpContext )
@@ -4678,7 +4718,7 @@ static bool CALLBACK deviceCountCallback( LPGUID lpguid,
     LPDIRECTSOUNDCAPTURE object;
 
     hr = DirectSoundCaptureCreate(  lpguid, &object,   NULL );
-    if ( hr != DS_OK ) return true;
+    if ( hr != DS_OK ) return TRUE;
 
     caps.dwSize = sizeof(caps);
     hr = object->GetCaps( &caps );
@@ -4692,7 +4732,7 @@ static bool CALLBACK deviceCountCallback( LPGUID lpguid,
     DSCAPS caps;
     LPDIRECTSOUND object;
     hr = DirectSoundCreate(  lpguid, &object,   NULL );
-    if ( hr != DS_OK ) return true;
+    if ( hr != DS_OK ) return TRUE;
 
     caps.dwSize = sizeof(caps);
     hr = object->GetCaps( &caps );
@@ -4703,20 +4743,20 @@ static bool CALLBACK deviceCountCallback( LPGUID lpguid,
     object->Release();
   }
 
-  if ( info->getDefault && lpguid == NULL ) return false;
+  if ( info->getDefault && lpguid == NULL ) return FALSE;
 
   if ( info->findIndex && info->counter > info->index ) {
     info->id = lpguid;
     info->name = convertTChar( description );
-    return false;
+    return FALSE;
   }
 
-  return true;
+  return TRUE;
 }
 
 static char* getErrorString( int code )
 {
-       switch (code) {
+       switch ( code ) {
 
   case DSERR_ALLOCATED:
     return "Already allocated";
@@ -4815,7 +4855,7 @@ unsigned int RtApiAlsa :: getDeviceCount( void )
     if ( result < 0 ) {
       errorStream_ << "RtApiAlsa::getDeviceCount: control open, card = " << card << ", " << snd_strerror( result ) << ".";
       errorText_ = errorStream_.str();
-      error( WARNING );
+      error( RtError::WARNING );
       goto nextcard;
                }
                subdevice = -1;
@@ -4824,7 +4864,7 @@ unsigned int RtApiAlsa :: getDeviceCount( void )
                        if ( result < 0 ) {
         errorStream_ << "RtApiAlsa::getDeviceCount: control next device, card = " << card << ", " << snd_strerror( result ) << ".";
         errorText_ = errorStream_.str();
-        error( WARNING );
+        error( RtError::WARNING );
         break;
       }
                        if ( subdevice < 0 )
@@ -4858,7 +4898,7 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
     if ( result < 0 ) {
       errorStream_ << "RtApiAlsa::getDeviceInfo: control open, card = " << card << ", " << snd_strerror( result ) << ".";
       errorText_ = errorStream_.str();
-      error( WARNING );
+      error( RtError::WARNING );
       goto nextcard;
                }
                subdevice = -1;
@@ -4867,7 +4907,7 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
                        if ( result < 0 ) {
         errorStream_ << "RtApiAlsa::getDeviceInfo: control next device, card = " << card << ", " << snd_strerror( result ) << ".";
         errorText_ = errorStream_.str();
-        error( WARNING );
+        error( RtError::WARNING );
         break;
       }
                        if ( subdevice < 0 ) break;
@@ -4884,12 +4924,12 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
 
   if ( nDevices == 0 ) {
     errorText_ = "RtApiAlsa::getDeviceInfo: no devices found!";
-    error( INVALID_CALL );
+    error( RtError::INVALID_USE );
   }
 
   if ( device >= nDevices ) {
     errorText_ = "RtApiAlsa::getDeviceInfo: device ID is invalid!";
-    error( INVALID_CALL );
+    error( RtError::INVALID_USE );
   }
 
  foundDevice:
@@ -4918,7 +4958,7 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
   if ( result < 0 ) {
     errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_open error for device (" << name << "), " << snd_strerror( result ) << ".";
     errorText_ = errorStream_.str();
-    error( WARNING );
+    error( RtError::WARNING );
     goto captureProbe;
   }
 
@@ -4928,7 +4968,7 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
     snd_pcm_close( phandle );
     errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_hw_params error for device (" << name << "), " << snd_strerror( result ) << ".";
     errorText_ = errorStream_.str();
-    error( WARNING );
+    error( RtError::WARNING );
     goto captureProbe;
   }
 
@@ -4939,7 +4979,7 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
     snd_pcm_close( phandle );
     errorStream_ << "RtApiAlsa::getDeviceInfo: error getting device (" << name << ") output channels, " << snd_strerror( result ) << ".";
     errorText_ = errorStream_.str();
-    error( WARNING );
+    error( RtError::WARNING );
     goto captureProbe;
   }
   info.outputChannels = value;
@@ -4962,7 +5002,7 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
   if ( result < 0 ) {
     errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_open error for device (" << name << "), " << snd_strerror( result ) << ".";
     errorText_ = errorStream_.str();
-    error( WARNING );
+    error( RtError::WARNING );
     if ( info.outputChannels == 0 ) return info;
     goto probeParameters;
   }
@@ -4973,7 +5013,7 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
     snd_pcm_close( phandle );
     errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_hw_params error for device (" << name << "), " << snd_strerror( result ) << ".";
     errorText_ = errorStream_.str();
-    error( WARNING );
+    error( RtError::WARNING );
     if ( info.outputChannels == 0 ) return info;
     goto probeParameters;
   }
@@ -4983,7 +5023,7 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
     snd_pcm_close( phandle );
     errorStream_ << "RtApiAlsa::getDeviceInfo: error getting device (" << name << ") input channels, " << snd_strerror( result ) << ".";
     errorText_ = errorStream_.str();
-    error( WARNING );
+    error( RtError::WARNING );
     if ( info.outputChannels == 0 ) return info;
     goto probeParameters;
   }
@@ -5017,7 +5057,7 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
   if ( result < 0 ) {
     errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_open error for device (" << name << "), " << snd_strerror( result ) << ".";
     errorText_ = errorStream_.str();
-    error( WARNING );
+    error( RtError::WARNING );
     return info;
   }
 
@@ -5027,7 +5067,7 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
     snd_pcm_close( phandle );
     errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_hw_params error for device (" << name << "), " << snd_strerror( result ) << ".";
     errorText_ = errorStream_.str();
-    error( WARNING );
+    error( RtError::WARNING );
     return info;
   }
 
@@ -5041,7 +5081,7 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
     snd_pcm_close( phandle );
     errorStream_ << "RtApiAlsa::getDeviceInfo: no supported sample rates found for device (" << name << ").";
     errorText_ = errorStream_.str();
-    error( WARNING );
+    error( RtError::WARNING );
     return info;
   }
 
@@ -5071,7 +5111,7 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
   if ( info.nativeFormats == 0 ) {
     errorStream_ << "RtApiAlsa::getDeviceInfo: pcm device (" << name << ") data format not supported by RtAudio.";
     errorText_ = errorStream_.str();
-    error( WARNING );
+    error( RtError::WARNING );
     return info;
   }
 
@@ -5487,7 +5527,7 @@ bool RtApiAlsa :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
       apiInfo->synchronized = true;
     else {
       errorText_ = "RtApiAlsa::probeDeviceOpen: unable to synchronize input and output devices.";
-      error( WARNING );
+      error( RtError::WARNING );
     }
   }
   else {
@@ -5547,7 +5587,7 @@ void RtApiAlsa :: closeStream()
 {
   if ( stream_.state == STREAM_CLOSED ) {
     errorText_ = "RtApiAlsa::closeStream(): no open stream to close!";
-    error( WARNING );
+    error( RtError::WARNING );
     return;
   }
 
@@ -5593,7 +5633,7 @@ void RtApiAlsa :: startStream()
   verifyStream();
   if ( stream_.state == STREAM_RUNNING ) {
     errorText_ = "RtApiAlsa::startStream(): the stream is already running!";
-    error( WARNING );
+    error( RtError::WARNING );
     return;
   }
 
@@ -5633,7 +5673,7 @@ void RtApiAlsa :: startStream()
   MUTEX_UNLOCK( &stream_.mutex );
 
   if ( result >= 0 ) return;
-  error( SYSTEM );
+  error( RtError::SYSTEM_ERROR );
 }
 
 void RtApiAlsa :: stopStream()
@@ -5641,7 +5681,7 @@ void RtApiAlsa :: stopStream()
   verifyStream();
   if ( stream_.state == STREAM_STOPPED ) {
     errorText_ = "RtApiAlsa::stopStream(): the stream is already stopped!";
-    error( WARNING );
+    error( RtError::WARNING );
     return;
   }
 
@@ -5678,7 +5718,7 @@ void RtApiAlsa :: stopStream()
   MUTEX_UNLOCK( &stream_.mutex );
 
   if ( result >= 0 ) return;
-  error( SYSTEM );
+  error( RtError::SYSTEM_ERROR );
 }
 
 void RtApiAlsa :: abortStream()
@@ -5686,7 +5726,7 @@ void RtApiAlsa :: abortStream()
   verifyStream();
   if ( stream_.state == STREAM_STOPPED ) {
     errorText_ = "RtApiAlsa::abortStream(): the stream is already stopped!";
-    error( WARNING );
+    error( RtError::WARNING );
     return;
   }
 
@@ -5721,7 +5761,7 @@ void RtApiAlsa :: abortStream()
 
   stream_.state = STREAM_STOPPED;
   if ( result >= 0 ) return;
-  error( SYSTEM );
+  error( RtError::SYSTEM_ERROR );
 }
 
 void RtApiAlsa :: callbackEvent()
@@ -5733,7 +5773,7 @@ void RtApiAlsa :: callbackEvent()
 
   if ( stream_.state == STREAM_CLOSED ) {
     errorText_ = "RtApiAlsa::callbackEvent(): the stream is closed ... this shouldn't happen!";
-    error( WARNING );
+    error( RtError::WARNING );
     return;
   }
 
@@ -5812,7 +5852,7 @@ void RtApiAlsa :: callbackEvent()
         errorStream_ << "RtApiAlsa::callbackEvent: audio read error, " << snd_strerror( result ) << ".";
         errorText_ = errorStream_.str();
       }
-      error( WARNING );
+      error( RtError::WARNING );
       goto unlock;
     }
 
@@ -5880,7 +5920,7 @@ void RtApiAlsa :: callbackEvent()
         errorStream_ << "RtApiAlsa::callbackEvent: audio write error, " << snd_strerror( result ) << ".";
         errorText_ = errorStream_.str();
       }
-      error( WARNING );
+      error( RtError::WARNING );
       goto unlock;
     }
 
@@ -5906,7 +5946,9 @@ extern "C" void *alsaCallbackHandler( void *ptr )
 #ifdef SCHED_RR
   // Set a higher scheduler priority (P.J. Leonard)
   struct sched_param param;
-  param.sched_priority = 39;   // Is this the best number?
+  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
 
@@ -5928,7 +5970,7 @@ extern "C" void *alsaCallbackHandler( void *ptr )
 #include <sys/ioctl.h>
 #include <unistd.h>
 #include <fcntl.h>
-#include "oss/soundcard.h"
+#include "soundcard.h"
 #include <errno.h>
 #include <math.h>
 
@@ -5960,7 +6002,7 @@ unsigned int RtApiOss :: getDeviceCount( void )
   int mixerfd = open( "/dev/mixer", O_RDWR, 0 );
   if ( mixerfd == -1 ) {
     errorText_ = "RtApiOss::getDeviceCount: error opening '/dev/mixer'.";
-    error( WARNING );
+    error( RtError::WARNING );
     return 0;
   }
 
@@ -5968,7 +6010,7 @@ unsigned int RtApiOss :: getDeviceCount( void )
   if ( ioctl( mixerfd, SNDCTL_SYSINFO, &sysinfo ) == -1 ) {
     close( mixerfd );
     errorText_ = "RtApiOss::getDeviceCount: error getting sysinfo, OSS version >= 4.0 is required.";
-    error( WARNING );
+    error( RtError::WARNING );
     return 0;
   }
 
@@ -5983,7 +6025,7 @@ RtAudio::DeviceInfo RtApiOss :: getDeviceInfo( unsigned int device )
   int mixerfd = open( "/dev/mixer", O_RDWR, 0 );
   if ( mixerfd == -1 ) {
     errorText_ = "RtApiOss::getDeviceInfo: error opening '/dev/mixer'.";
-    error( WARNING );
+    error( RtError::WARNING );
     return info;
   }
 
@@ -5992,7 +6034,7 @@ RtAudio::DeviceInfo RtApiOss :: getDeviceInfo( unsigned int device )
   if ( result == -1 ) {
     close( mixerfd );
     errorText_ = "RtApiOss::getDeviceInfo: error getting sysinfo, OSS version >= 4.0 is required.";
-    error( WARNING );
+    error( RtError::WARNING );
     return info;
   }
 
@@ -6000,13 +6042,13 @@ RtAudio::DeviceInfo RtApiOss :: getDeviceInfo( unsigned int device )
   if ( nDevices == 0 ) {
     close( mixerfd );
     errorText_ = "RtApiOss::getDeviceInfo: no devices found!";
-    error( INVALID_CALL );
+    error( RtError::INVALID_USE );
   }
 
   if ( device >= nDevices ) {
     close( mixerfd );
     errorText_ = "RtApiOss::getDeviceInfo: device ID is invalid!";
-    error( INVALID_CALL );
+    error( RtError::INVALID_USE );
   }
 
   oss_audioinfo ainfo;
@@ -6016,7 +6058,7 @@ RtAudio::DeviceInfo RtApiOss :: getDeviceInfo( unsigned int device )
   if ( result == -1 ) {
     errorStream_ << "RtApiOss::getDeviceInfo: error getting device (" << ainfo.name << ") info.";
     errorText_ = errorStream_.str();
-    error( WARNING );
+    error( RtError::WARNING );
     return info;
   }
 
@@ -6045,7 +6087,7 @@ RtAudio::DeviceInfo RtApiOss :: getDeviceInfo( unsigned int device )
   if ( info.nativeFormats == 0 ) {
     errorStream_ << "RtApiOss::getDeviceInfo: device (" << ainfo.name << ") data format not supported by RtAudio.";
     errorText_ = errorStream_.str();
-    error( WARNING );
+    error( RtError::WARNING );
     return info;
   }
 
@@ -6072,7 +6114,7 @@ RtAudio::DeviceInfo RtApiOss :: getDeviceInfo( unsigned int device )
   if ( info.sampleRates.size() == 0 ) {
     errorStream_ << "RtApiOss::getDeviceInfo: no supported sample rates found for device (" << ainfo.name << ").";
     errorText_ = errorStream_.str();
-    error( WARNING );
+    error( RtError::WARNING );
   }
   else {
     info.probed = true;
@@ -6503,7 +6545,7 @@ void RtApiOss :: closeStream()
 {
   if ( stream_.state == STREAM_CLOSED ) {
     errorText_ = "RtApiOss::closeStream(): no open stream to close!";
-    error( WARNING );
+    error( RtError::WARNING );
     return;
   }
 
@@ -6547,7 +6589,7 @@ void RtApiOss :: startStream()
   verifyStream();
   if ( stream_.state == STREAM_RUNNING ) {
     errorText_ = "RtApiOss::startStream(): the stream is already running!";
-    error( WARNING );
+    error( RtError::WARNING );
     return;
   }
 
@@ -6566,7 +6608,7 @@ void RtApiOss :: stopStream()
   verifyStream();
   if ( stream_.state == STREAM_STOPPED ) {
     errorText_ = "RtApiOss::stopStream(): the stream is already stopped!";
-    error( WARNING );
+    error( RtError::WARNING );
     return;
   }
 
@@ -6600,7 +6642,7 @@ void RtApiOss :: stopStream()
       result = write( handle->id[0], buffer, samples * formatBytes(format) );
       if ( result == -1 ) {
         errorText_ = "RtApiOss::stopStream: audio write error.";
-        error( WARNING );
+        error( RtError::WARNING );
       }
     }
 
@@ -6627,7 +6669,7 @@ void RtApiOss :: stopStream()
 
   stream_.state = STREAM_STOPPED;
   if ( result != -1 ) return;
-  error( SYSTEM );
+  error( RtError::SYSTEM_ERROR );
 }
 
 void RtApiOss :: abortStream()
@@ -6635,7 +6677,7 @@ void RtApiOss :: abortStream()
   verifyStream();
   if ( stream_.state == STREAM_STOPPED ) {
     errorText_ = "RtApiOss::abortStream(): the stream is already stopped!";
-    error( WARNING );
+    error( RtError::WARNING );
     return;
   }
 
@@ -6670,7 +6712,7 @@ void RtApiOss :: abortStream()
 
   stream_.state = STREAM_STOPPED;
   if ( result != -1 ) return;
-  error( SYSTEM );
+  error( RtError::SYSTEM_ERROR );
 }
 
 void RtApiOss :: callbackEvent()
@@ -6682,7 +6724,7 @@ void RtApiOss :: callbackEvent()
 
   if ( stream_.state == STREAM_CLOSED ) {
     errorText_ = "RtApiOss::callbackEvent(): the stream is closed ... this shouldn't happen!";
-    error( WARNING );
+    error( RtError::WARNING );
     return;
   }
 
@@ -6749,7 +6791,7 @@ void RtApiOss :: callbackEvent()
       // specific means for determining that.
       handle->xrun[0] = true;
       errorText_ = "RtApiOss::callbackEvent: audio write error.";
-      error( WARNING );
+      error( RtError::WARNING );
       goto unlock;
     }
   }
@@ -6776,7 +6818,7 @@ void RtApiOss :: callbackEvent()
       // specific means for determining that.
       handle->xrun[1] = true;
       errorText_ = "RtApiOss::callbackEvent: audio read error.";
-      error( WARNING );
+      error( RtError::WARNING );
       goto unlock;
     }
 
@@ -6830,14 +6872,12 @@ extern "C" void *ossCallbackHandler( void *ptr )
 
 // This method can be modified to control the behavior of error
 // message printing.
-void RtApi :: error( ErrorType type )
+void RtApi :: error( RtError::Type type )
 {
-  if ( type == WARNING && showWarnings_ == true )
+  if ( type == RtError::WARNING && showWarnings_ == true )
     std::cerr << '\n' << errorText_ << "\n\n";
-  else if ( type == INVALID_CALL )
-    throw( RtError( errorText_, RtError::INVALID_USE ) );
-  else if ( type == SYSTEM )
-    throw( RtError( errorText_, RtError::SYSTEM_ERROR ) );
+  else
+    throw( RtError( errorText_, type ) );
   errorStream_.str(""); // clear the ostringstream
 }
 
@@ -6845,7 +6885,7 @@ void RtApi :: verifyStream()
 {
   if ( stream_.state == STREAM_CLOSED ) {
     errorText_ = "RtApi:: a stream is not open!";
-    error( INVALID_CALL );
+    error( RtError::INVALID_USE );
   }
 }
 
@@ -6898,7 +6938,7 @@ unsigned int RtApi :: formatBytes( RtAudioFormat format )
     return 1;
 
   errorText_ = "RtApi::formatBytes: undefined format.";
-  error( WARNING );
+  error( RtError::WARNING );
 
   return 0;
 }