*/
/************************************************************************/
-// RtAudio: Version 4.0
+// RtAudio: Version 4.0.3
#include "RtAudio.h"
#include <iostream>
// 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;
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( RtError::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];
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,
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 ) ) {
return FAILURE;
}
- // Set the sample rate.
- result = ASIOSetSampleRate( (ASIOSampleRate) sampleRate );
+ // Get the current sample rate
+ ASIOSampleRate currentRate;
+ result = ASIOGetSampleRate( ¤tRate );
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;
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.";
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] );
#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++
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; }
};
/*
// 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 );
{
// 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();
// 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();
// 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();
{
// 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();
// 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();
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();
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();
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();
}
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();
}
// Set various stream parameters
+ DsHandle *handle = 0;
stream_.nDeviceChannels[mode] = channels + firstChannel;
stream_.nUserChannels[mode] = channels;
stream_.bufferSize = *bufferSize;
}
// Allocate our DsHandle structures for the stream.
- DsHandle *handle;
if ( stream_.apiHandle == 0 ) {
try {
handle = new DsHandle;
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];
MUTEX_LOCK( &stream_.mutex );
- HRESULT result;
+ HRESULT result = 0;
LPVOID audioPtr;
DWORD dataLen;
DsHandle *handle = (DsHandle *) stream_.apiHandle;
return s;
}
-static bool CALLBACK deviceCountCallback( LPGUID lpguid,
+static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid,
LPCTSTR description,
LPCTSTR module,
LPVOID lpContext )
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 );
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 );
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";
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
-#include "oss/soundcard.h"
+#include "soundcard.h"
#include <errno.h>
#include <math.h>
// message printing.
void RtApi :: error( RtError::Type type )
{
+ errorStream_.str(""); // clear the ostringstream
if ( type == RtError::WARNING && showWarnings_ == true )
std::cerr << '\n' << errorText_ << "\n\n";
else
throw( RtError( errorText_, type ) );
- errorStream_.str(""); // clear the ostringstream
}
void RtApi :: verifyStream()