bool haveValueRange = false;\r
info.sampleRates.clear();\r
for ( UInt32 i=0; i<nRanges; i++ ) {\r
- if ( rangeList[i].mMinimum == rangeList[i].mMaximum )\r
- info.sampleRates.push_back( (unsigned int) rangeList[i].mMinimum );\r
- else {\r
+ if ( rangeList[i].mMinimum == rangeList[i].mMaximum ) {\r
+ unsigned int tmpSr = (unsigned int) rangeList[i].mMinimum;\r
+ info.sampleRates.push_back( tmpSr );\r
+\r
+ if ( !info.preferredSampleRate || ( tmpSr <= 48000 && tmpSr > info.preferredSampleRate ) )\r
+ info.preferredSampleRate = tmpSr;\r
+\r
+ } else {\r
haveValueRange = true;\r
if ( rangeList[i].mMinimum > minimumRate ) minimumRate = rangeList[i].mMinimum;\r
if ( rangeList[i].mMaximum < maximumRate ) maximumRate = rangeList[i].mMaximum;\r
\r
if ( haveValueRange ) {\r
for ( unsigned int k=0; k<MAX_SAMPLE_RATES; k++ ) {\r
- if ( SAMPLE_RATES[k] >= (unsigned int) minimumRate && SAMPLE_RATES[k] <= (unsigned int) maximumRate )\r
+ if ( SAMPLE_RATES[k] >= (unsigned int) minimumRate && SAMPLE_RATES[k] <= (unsigned int) maximumRate ) {\r
info.sampleRates.push_back( SAMPLE_RATES[k] );\r
+\r
+ if ( !info.preferredSampleRate || ( SAMPLE_RATES[k] <= 48000 && SAMPLE_RATES[k] > info.preferredSampleRate ) )\r
+ info.preferredSampleRate = SAMPLE_RATES[k];\r
+ }\r
}\r
}\r
\r
\r
// Get the current jack server sample rate.\r
info.sampleRates.clear();\r
- info.sampleRates.push_back( jack_get_sample_rate( client ) );\r
+\r
+ info.preferredSampleRate = jack_get_sample_rate( client );\r
+ info.sampleRates.push_back( info.preferredSampleRate );\r
\r
// Count the available ports containing the client name as device\r
// channels. Jack "input ports" equal RtAudio output channels.\r
info.sampleRates.clear();\r
for ( unsigned int i=0; i<MAX_SAMPLE_RATES; i++ ) {\r
result = ASIOCanSampleRate( (ASIOSampleRate) SAMPLE_RATES[i] );\r
- if ( result == ASE_OK )\r
+ if ( result == ASE_OK ) {\r
info.sampleRates.push_back( SAMPLE_RATES[i] );\r
+\r
+ if ( !info.preferredSampleRate || ( SAMPLE_RATES[i] <= 48000 && SAMPLE_RATES[i] > info.preferredSampleRate ) )\r
+ info.preferredSampleRate = SAMPLE_RATES[i];\r
+ }\r
}\r
\r
// Determine supported data types ... just check first channel and assume rest are the same.\r
unsigned int firstChannel, unsigned int sampleRate,\r
RtAudioFormat format, unsigned int *bufferSize,\r
RtAudio::StreamOptions *options )\r
-{\r
+{////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r
+\r
+ bool isDuplexInput = mode == INPUT && stream_.mode == OUTPUT;\r
+\r
// For ASIO, a duplex stream MUST use the same driver.\r
- if ( mode == INPUT && stream_.mode == OUTPUT && stream_.device[0] != device ) {\r
+ if ( isDuplexInput && stream_.device[0] != device ) {\r
errorText_ = "RtApiAsio::probeDeviceOpen: an ASIO duplex stream must use the same device for input and output!";\r
return FAILURE;\r
}\r
}\r
\r
// Only load the driver once for duplex stream.\r
- if ( mode != INPUT || stream_.mode != OUTPUT ) {\r
+ if ( !isDuplexInput ) {\r
// The getDeviceInfo() function will not work when a stream is open\r
// because ASIO does not allow multiple devices to run at the same\r
// time. Thus, we'll probe the system before opening a stream and\r
}\r
}\r
\r
+ // keep them before any "goto error", they are used for error cleanup + goto device boundary checks\r
+ bool buffersAllocated = false;\r
+ AsioHandle *handle = (AsioHandle *) stream_.apiHandle;\r
+ unsigned int nChannels;\r
+\r
+\r
// Check the device channel count.\r
long inputChannels, outputChannels;\r
result = ASIOGetChannels( &inputChannels, &outputChannels );\r
if ( result != ASE_OK ) {\r
- drivers.removeCurrentDriver();\r
errorStream_ << "RtApiAsio::probeDeviceOpen: error (" << getAsioErrorString( result ) << ") getting channel count (" << driverName << ").";\r
errorText_ = errorStream_.str();\r
- return FAILURE;\r
+ goto error;\r
}\r
\r
if ( ( mode == OUTPUT && (channels+firstChannel) > (unsigned int) outputChannels) ||\r
( mode == INPUT && (channels+firstChannel) > (unsigned int) inputChannels) ) {\r
- drivers.removeCurrentDriver();\r
errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") does not support requested channel count (" << channels << ") + offset (" << firstChannel << ").";\r
errorText_ = errorStream_.str();\r
- return FAILURE;\r
+ goto error;\r
}\r
stream_.nDeviceChannels[mode] = channels;\r
stream_.nUserChannels[mode] = channels;\r
// Verify the sample rate is supported.\r
result = ASIOCanSampleRate( (ASIOSampleRate) sampleRate );\r
if ( result != ASE_OK ) {\r
- drivers.removeCurrentDriver();\r
errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") does not support requested sample rate (" << sampleRate << ").";\r
errorText_ = errorStream_.str();\r
- return FAILURE;\r
+ goto error;\r
}\r
\r
// Get the current sample rate\r
ASIOSampleRate currentRate;\r
result = ASIOGetSampleRate( ¤tRate );\r
if ( result != ASE_OK ) {\r
- drivers.removeCurrentDriver();\r
errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error getting sample rate.";\r
errorText_ = errorStream_.str();\r
- return FAILURE;\r
+ goto error;\r
}\r
\r
// Set the sample rate only if necessary\r
if ( currentRate != sampleRate ) {\r
result = ASIOSetSampleRate( (ASIOSampleRate) sampleRate );\r
if ( result != ASE_OK ) {\r
- drivers.removeCurrentDriver();\r
errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error setting sample rate (" << sampleRate << ").";\r
errorText_ = errorStream_.str();\r
- return FAILURE;\r
+ goto error;\r
}\r
}\r
\r
else channelInfo.isInput = true;\r
result = ASIOGetChannelInfo( &channelInfo );\r
if ( result != ASE_OK ) {\r
- drivers.removeCurrentDriver();\r
errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") getting data format.";\r
errorText_ = errorStream_.str();\r
- return FAILURE;\r
+ goto error;\r
}\r
\r
// Assuming WINDOWS host is always little-endian.\r
}\r
\r
if ( stream_.deviceFormat[mode] == 0 ) {\r
- drivers.removeCurrentDriver();\r
errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") data format not supported by RtAudio.";\r
errorText_ = errorStream_.str();\r
- return FAILURE;\r
+ goto error;\r
}\r
\r
// Set the buffer size. For a duplex stream, this will end up\r
long minSize, maxSize, preferSize, granularity;\r
result = ASIOGetBufferSize( &minSize, &maxSize, &preferSize, &granularity );\r
if ( result != ASE_OK ) {\r
- drivers.removeCurrentDriver();\r
errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") getting buffer size.";\r
errorText_ = errorStream_.str();\r
- return FAILURE;\r
+ goto error;\r
}\r
\r
- if ( *bufferSize < (unsigned int) minSize ) *bufferSize = (unsigned int) minSize;\r
- else if ( *bufferSize > (unsigned int) maxSize ) *bufferSize = (unsigned int) maxSize;\r
- else if ( granularity == -1 ) {\r
- // Make sure bufferSize is a power of two.\r
- int log2_of_min_size = 0;\r
- int log2_of_max_size = 0;\r
+ if ( isDuplexInput ) {\r
+ // When this is the duplex input (output was opened before), then we have to use the same\r
+ // buffersize as the output, because it might use the preferred buffer size, which most\r
+ // likely wasn't passed as input to this. The buffer sizes have to be identically anyway,\r
+ // So instead of throwing an error, make them equal. The caller uses the reference\r
+ // to the "bufferSize" param as usual to set up processing buffers.\r
\r
- for ( unsigned int i = 0; i < sizeof(long) * 8; i++ ) {\r
- if ( minSize & ((long)1 << i) ) log2_of_min_size = i;\r
- if ( maxSize & ((long)1 << i) ) log2_of_max_size = i;\r
- }\r
+ *bufferSize = stream_.bufferSize;\r
\r
- long min_delta = std::abs( (long)*bufferSize - ((long)1 << log2_of_min_size) );\r
- int min_delta_num = log2_of_min_size;\r
+ } else {\r
+ if ( *bufferSize < (unsigned int) minSize ) *bufferSize = (unsigned int) minSize;\r
+ else if ( *bufferSize > (unsigned int) maxSize ) *bufferSize = (unsigned int) maxSize;\r
+ else if ( granularity == -1 ) {\r
+ // Make sure bufferSize is a power of two.\r
+ int log2_of_min_size = 0;\r
+ int log2_of_max_size = 0;\r
\r
- for (int i = log2_of_min_size + 1; i <= log2_of_max_size; i++) {\r
- long current_delta = std::abs( (long)*bufferSize - ((long)1 << i) );\r
- if (current_delta < min_delta) {\r
- min_delta = current_delta;\r
- min_delta_num = i;\r
+ for ( unsigned int i = 0; i < sizeof(long) * 8; i++ ) {\r
+ if ( minSize & ((long)1 << i) ) log2_of_min_size = i;\r
+ if ( maxSize & ((long)1 << i) ) log2_of_max_size = i;\r
}\r
- }\r
\r
- *bufferSize = ( (unsigned int)1 << min_delta_num );\r
- if ( *bufferSize < (unsigned int) minSize ) *bufferSize = (unsigned int) minSize;\r
- else if ( *bufferSize > (unsigned int) maxSize ) *bufferSize = (unsigned int) maxSize;\r
- }\r
- else if ( granularity != 0 ) {\r
- // Set to an even multiple of granularity, rounding up.\r
- *bufferSize = (*bufferSize + granularity-1) / granularity * granularity;\r
+ long min_delta = std::abs( (long)*bufferSize - ((long)1 << log2_of_min_size) );\r
+ int min_delta_num = log2_of_min_size;\r
+\r
+ for (int i = log2_of_min_size + 1; i <= log2_of_max_size; i++) {\r
+ long current_delta = std::abs( (long)*bufferSize - ((long)1 << i) );\r
+ if (current_delta < min_delta) {\r
+ min_delta = current_delta;\r
+ min_delta_num = i;\r
+ }\r
+ }\r
+\r
+ *bufferSize = ( (unsigned int)1 << min_delta_num );\r
+ if ( *bufferSize < (unsigned int) minSize ) *bufferSize = (unsigned int) minSize;\r
+ else if ( *bufferSize > (unsigned int) maxSize ) *bufferSize = (unsigned int) maxSize;\r
+ }\r
+ else if ( granularity != 0 ) {\r
+ // Set to an even multiple of granularity, rounding up.\r
+ *bufferSize = (*bufferSize + granularity-1) / granularity * granularity;\r
+ }\r
}\r
\r
- if ( mode == INPUT && stream_.mode == OUTPUT && stream_.bufferSize != *bufferSize ) {\r
- drivers.removeCurrentDriver();\r
+ /*\r
+ // we don't use it anymore, see above!\r
+ // Just left it here for the case...\r
+ if ( isDuplexInput && stream_.bufferSize != *bufferSize ) {\r
errorText_ = "RtApiAsio::probeDeviceOpen: input/output buffersize discrepancy!";\r
- return FAILURE;\r
+ goto error;\r
}\r
+ */\r
\r
stream_.bufferSize = *bufferSize;\r
stream_.nBuffers = 2;\r
stream_.deviceInterleaved[mode] = false;\r
\r
// Allocate, if necessary, our AsioHandle structure for the stream.\r
- AsioHandle *handle = (AsioHandle *) stream_.apiHandle;\r
if ( handle == 0 ) {\r
try {\r
handle = new AsioHandle;\r
}\r
catch ( std::bad_alloc& ) {\r
- //if ( handle == NULL ) { \r
- drivers.removeCurrentDriver();\r
errorText_ = "RtApiAsio::probeDeviceOpen: error allocating AsioHandle memory.";\r
- return FAILURE;\r
+ goto error;\r
}\r
handle->bufferInfos = 0;\r
\r
// Create the ASIO internal buffers. Since RtAudio sets up input\r
// and output separately, we'll have to dispose of previously\r
// created output buffers for a duplex stream.\r
- long inputLatency, outputLatency;\r
if ( mode == INPUT && stream_.mode == OUTPUT ) {\r
ASIODisposeBuffers();\r
if ( handle->bufferInfos ) free( handle->bufferInfos );\r
}\r
\r
// Allocate, initialize, and save the bufferInfos in our stream callbackInfo structure.\r
- bool buffersAllocated = false;\r
- unsigned int i, nChannels = stream_.nDeviceChannels[0] + stream_.nDeviceChannels[1];\r
+ unsigned int i;\r
+ nChannels = stream_.nDeviceChannels[0] + stream_.nDeviceChannels[1];\r
handle->bufferInfos = (ASIOBufferInfo *) malloc( nChannels * sizeof(ASIOBufferInfo) );\r
if ( handle->bufferInfos == NULL ) {\r
errorStream_ << "RtApiAsio::probeDeviceOpen: error allocating bufferInfo memory for driver (" << driverName << ").";\r
// prepare for callbacks\r
stream_.sampleRate = sampleRate;\r
stream_.device[mode] = device;\r
- if ( stream_.mode == OUTPUT && mode == INPUT )\r
- // We had already set up an output stream.\r
- stream_.mode = DUPLEX;\r
- else\r
- stream_.mode = mode;\r
+ stream_.mode = isDuplexInput ? DUPLEX : mode;\r
\r
// store this class instance before registering callbacks, that are going to use it\r
asioCallbackInfo = &stream_.callbackInfo;\r
errorText_ = errorStream_.str();\r
goto error;\r
}\r
- buffersAllocated = true;\r
+ buffersAllocated = true; \r
stream_.state = STREAM_STOPPED;\r
\r
// Set flags for buffer conversion.\r
\r
bool makeBuffer = true;\r
bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] );\r
- if ( stream_.mode == DUPLEX && stream_.deviceBuffer ) {\r
+ if ( isDuplexInput && stream_.deviceBuffer ) {\r
unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] );\r
if ( bufferBytes <= bytesOut ) makeBuffer = false;\r
}\r
}\r
\r
// Determine device latencies\r
+ long inputLatency, outputLatency;\r
result = ASIOGetLatencies( &inputLatency, &outputLatency );\r
if ( result != ASE_OK ) {\r
errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") getting latency.";\r
return SUCCESS;\r
\r
error:\r
- if ( buffersAllocated )\r
- ASIODisposeBuffers();\r
- drivers.removeCurrentDriver();\r
+ if ( !isDuplexInput ) {\r
+ // the cleanup for error in the duplex input, is done by RtApi::openStream\r
+ // So we clean up for single channel only\r
\r
- if ( handle ) {\r
- CloseHandle( handle->condition );\r
- if ( handle->bufferInfos )\r
- free( handle->bufferInfos );\r
- delete handle;\r
- stream_.apiHandle = 0;\r
- }\r
+ if ( buffersAllocated )\r
+ ASIODisposeBuffers();\r
\r
- for ( int i=0; i<2; i++ ) {\r
- if ( stream_.userBuffer[i] ) {\r
- free( stream_.userBuffer[i] );\r
- stream_.userBuffer[i] = 0;\r
+ drivers.removeCurrentDriver();\r
+\r
+ if ( handle ) {\r
+ CloseHandle( handle->condition );\r
+ if ( handle->bufferInfos )\r
+ free( handle->bufferInfos );\r
+\r
+ delete handle;\r
+ stream_.apiHandle = 0;\r
}\r
- }\r
\r
- if ( stream_.deviceBuffer ) {\r
- free( stream_.deviceBuffer );\r
- stream_.deviceBuffer = 0;\r
+\r
+ if ( stream_.userBuffer[mode] ) {\r
+ free( stream_.userBuffer[mode] );\r
+ stream_.userBuffer[mode] = 0;\r
+ }\r
+\r
+ if ( stream_.deviceBuffer ) {\r
+ free( stream_.deviceBuffer );\r
+ stream_.deviceBuffer = 0;\r
+ }\r
}\r
\r
return FAILURE;\r
-}\r
+}////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r
\r
void RtApiAsio :: closeStream()\r
{\r
for ( unsigned int i = 0; i < MAX_SAMPLE_RATES; i++ ) {\r
info.sampleRates.push_back( SAMPLE_RATES[i] );\r
}\r
+ info.preferredSampleRate = deviceFormat->nSamplesPerSec;\r
\r
// native format\r
info.nativeFormats = 0;\r
info.sampleRates.clear();\r
for ( unsigned int k=0; k<MAX_SAMPLE_RATES; k++ ) {\r
if ( SAMPLE_RATES[k] >= (unsigned int) outCaps.dwMinSecondarySampleRate &&\r
- SAMPLE_RATES[k] <= (unsigned int) outCaps.dwMaxSecondarySampleRate )\r
+ SAMPLE_RATES[k] <= (unsigned int) outCaps.dwMaxSecondarySampleRate ) {\r
info.sampleRates.push_back( SAMPLE_RATES[k] );\r
+\r
+ if ( !info.preferredSampleRate || ( SAMPLE_RATES[k] <= 48000 && SAMPLE_RATES[k] > info.preferredSampleRate ) )\r
+ info.preferredSampleRate = SAMPLE_RATES[k];\r
+ }\r
}\r
\r
// Get format information.\r
// Test our discrete set of sample rate values.\r
info.sampleRates.clear();\r
for ( unsigned int i=0; i<MAX_SAMPLE_RATES; i++ ) {\r
- if ( snd_pcm_hw_params_test_rate( phandle, params, SAMPLE_RATES[i], 0 ) == 0 )\r
+ if ( snd_pcm_hw_params_test_rate( phandle, params, SAMPLE_RATES[i], 0 ) == 0 ) {\r
info.sampleRates.push_back( SAMPLE_RATES[i] );\r
+\r
+ if ( !info.preferredSampleRate || ( SAMPLE_RATES[i] <= 48000 && SAMPLE_RATES[i] > info.preferredSampleRate ) )\r
+ info.preferredSampleRate = SAMPLE_RATES[i];\r
+ }\r
}\r
if ( info.sampleRates.size() == 0 ) {\r
snd_pcm_close( phandle );\r
for ( const unsigned int *sr = SUPPORTED_SAMPLERATES; *sr; ++sr )\r
info.sampleRates.push_back( *sr );\r
\r
+ info.preferredSampleRate = 48000;\r
info.nativeFormats = RTAUDIO_SINT16 | RTAUDIO_SINT32 | RTAUDIO_FLOAT32;\r
\r
return info;\r
for ( unsigned int k=0; k<MAX_SAMPLE_RATES; k++ ) {\r
if ( ainfo.rates[i] == SAMPLE_RATES[k] ) {\r
info.sampleRates.push_back( SAMPLE_RATES[k] );\r
+\r
+ if ( !info.preferredSampleRate || ( SAMPLE_RATES[k] <= 48000 && SAMPLE_RATES[k] > info.preferredSampleRate ) )\r
+ info.preferredSampleRate = SAMPLE_RATES[k];\r
+\r
break;\r
}\r
}\r
else {\r
// Check min and max rate values;\r
for ( unsigned int k=0; k<MAX_SAMPLE_RATES; k++ ) {\r
- if ( ainfo.min_rate <= (int) SAMPLE_RATES[k] && ainfo.max_rate >= (int) SAMPLE_RATES[k] )\r
+ if ( ainfo.min_rate <= (int) SAMPLE_RATES[k] && ainfo.max_rate >= (int) SAMPLE_RATES[k] ) {\r
info.sampleRates.push_back( SAMPLE_RATES[k] );\r
+\r
+ if ( !info.preferredSampleRate || ( SAMPLE_RATES[k] <= 48000 && SAMPLE_RATES[k] > info.preferredSampleRate ) )\r
+ info.preferredSampleRate = SAMPLE_RATES[k];\r
+ }\r
}\r
}\r
\r