RtAudio WWW site: http://www.music.mcgill.ca/~gary/rtaudio/
RtAudio: realtime audio i/o C++ classes
- Copyright (c) 2001-2007 Gary P. Scavone
+ Copyright (c) 2001-2008 Gary P. Scavone
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files
*/
/************************************************************************/
-// RtAudio: Version 4.0
+// RtAudio: Version 4.0.4
#include "RtAudio.h"
#include <iostream>
#endif
}
+unsigned int RtApi :: getStreamSampleRate( void )
+{
+ verifyStream();
+
+ return stream_.sampleRate;
+}
+
// *************************************************** //
//
// implementation.
struct CoreHandle {
AudioDeviceID id[2]; // device ids
+ AudioDeviceIOProcID procId[2];
UInt32 iStream[2]; // device stream index (first for mono mode)
bool xrun[2];
char *deviceBuffer;
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;
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;
handle->id[mode] = id;
// Allocate necessary internal buffers.
- unsigned long bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat );
+ unsigned long bufferBytes;
+ bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat );
stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 );
if ( stream_.userBuffer[mode] == NULL ) {
errorText_ = "RtApiCore::probeDeviceOpen: error allocating user buffer memory.";
// Only one callback procedure per device.
stream_.mode = DUPLEX;
else {
+#if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 )
+ result = AudioDeviceCreateIOProcID( id, callbackHandler, (void *) &stream_.callbackInfo, &handle->procId[mode] );
+#else
+ // deprecated in favor of AudioDeviceCreateIOProcID()
result = AudioDeviceAddIOProc( id, callbackHandler, (void *) &stream_.callbackInfo );
+#endif
if ( result != noErr ) {
errorStream_ << "RtApiCore::probeDeviceOpen: system error setting callback for device (" << device << ").";
errorText_ = errorStream_.str();
if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
if ( stream_.state == STREAM_RUNNING )
AudioDeviceStop( handle->id[0], callbackHandler );
+#if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 )
+ AudioDeviceDestroyIOProcID( handle->id[0], handle->procId[0] );
+#else
+ // deprecated in favor of AudioDeviceDestroyIOProcID()
AudioDeviceRemoveIOProc( handle->id[0], callbackHandler );
+#endif
}
if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && stream_.device[0] != stream_.device[1] ) ) {
if ( stream_.state == STREAM_RUNNING )
AudioDeviceStop( handle->id[1], callbackHandler );
+#if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 )
+ AudioDeviceDestroyIOProcID( handle->id[1], handle->procId[1] );
+#else
+ // deprecated in favor of AudioDeviceDestroyIOProcID()
AudioDeviceRemoveIOProc( handle->id[1], callbackHandler );
+#endif
}
for ( int i=0; i<2; i++ ) {
}
}
- AudioDeviceID inputDevice = handle->id[1];
+ AudioDeviceID inputDevice;
+ inputDevice = handle->id[1];
if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && deviceId == inputDevice ) ) {
if ( stream_.doConvertBuffer[1] ) {
unsigned int RtApiJack :: getDeviceCount( void )
{
// See if we can become a jack client.
- jack_client_t *client = jack_client_new( "RtApiJackCount" );
+ jack_options_t options = (jack_options_t) ( JackNoStartServer | JackUseExactName ); //JackNullOption;
+ jack_status_t *status = NULL;
+ jack_client_t *client = jack_client_open( "RtApiJackCount", options, status );
if ( client == 0 ) return 0;
const char **ports;
ports = jack_get_ports( client, NULL, NULL, 0 );
if ( ports ) {
// Parse the port names up to the first colon (:).
- unsigned int iColon = 0;
+ size_t iColon = 0;
do {
port = (char *) ports[ nChannels ];
iColon = port.find(":");
RtAudio::DeviceInfo info;
info.probed = false;
- jack_client_t *client = jack_client_new( "RtApiJackInfo" );
+ jack_options_t options = (jack_options_t) ( JackNoStartServer | JackUseExactName ); //JackNullOption
+ jack_status_t *status = NULL;
+ jack_client_t *client = jack_client_open( "RtApiJackInfo", options, status );
if ( client == 0 ) {
errorText_ = "RtApiJack::getDeviceInfo: Jack server not found or connection error!";
error( RtError::WARNING );
ports = jack_get_ports( client, NULL, NULL, 0 );
if ( ports ) {
// Parse the port names up to the first colon (:).
- unsigned int iColon = 0;
+ size_t iColon = 0;
do {
port = (char *) ports[ nPorts ];
iColon = port.find(":");
// Look for jack server and try to become a client (only do once per stream).
jack_client_t *client = 0;
if ( mode == OUTPUT || ( mode == INPUT && stream_.mode != OUTPUT ) ) {
+ jack_options_t jackoptions = (jack_options_t) ( JackNoStartServer | JackUseExactName ); //JackNullOption;
+ jack_status_t *status = NULL;
if ( options && !options->streamName.empty() )
- client = jack_client_new( options->streamName.c_str() );
+ client = jack_client_open( options->streamName.c_str(), jackoptions, status );
else
- client = jack_client_new( "RtApiJack" );
+ client = jack_client_open( "RtApiJack", jackoptions, status );
if ( client == 0 ) {
errorText_ = "RtApiJack::probeDeviceOpen: Jack server not found or connection error!";
error( RtError::WARNING );
ports = jack_get_ports( client, NULL, NULL, 0 );
if ( ports ) {
// Parse the port names up to the first colon (:).
- unsigned int iColon = 0;
+ size_t iColon = 0;
do {
port = (char *) ports[ nPorts ];
iColon = port.find(":");
// Count the available ports containing the client name as device
// channels. Jack "input ports" equal RtAudio output channels.
unsigned int nChannels = 0;
- unsigned long flag = JackPortIsOutput;
- if ( mode == INPUT ) flag = JackPortIsInput;
+ unsigned long flag = JackPortIsInput;
+ if ( mode == INPUT ) flag = JackPortIsOutput;
ports = jack_get_ports( client, deviceName.c_str(), NULL, flag );
if ( ports ) {
while ( ports[ nChannels ] ) nChannels++;
// 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;
else if ( *bufferSize > (unsigned int) maxSize ) *bufferSize = (unsigned int) maxSize;
else if ( granularity == -1 ) {
// Make sure bufferSize is a power of two.
- double power = std::log10( (double) *bufferSize ) / log10( 2.0 );
- *bufferSize = (int) pow( 2.0, floor(power+0.5) );
- if ( *bufferSize < (unsigned int) minSize ) *bufferSize = (unsigned int) minSize;
- else if ( *bufferSize > (unsigned int) maxSize ) *bufferSize = (unsigned int) maxSize;
- else *bufferSize = preferSize;
+ int log2_of_min_size = 0;
+ int log2_of_max_size = 0;
+
+ for ( unsigned int i = 0; i < sizeof(long) * 8; i++ ) {
+ if ( minSize & ((long)1 << i) ) log2_of_min_size = i;
+ if ( maxSize & ((long)1 << i) ) log2_of_max_size = i;
+ }
+
+ long min_delta = std::abs( (long)*bufferSize - ((long)1 << log2_of_min_size) );
+ int min_delta_num = log2_of_min_size;
+
+ for (int i = log2_of_min_size + 1; i <= log2_of_max_size; i++) {
+ long current_delta = std::abs( (long)*bufferSize - ((long)1 << i) );
+ if (current_delta < min_delta) {
+ min_delta = current_delta;
+ min_delta_num = i;
+ }
+ }
+
+ *bufferSize = ( (unsigned int)1 << min_delta_num );
+ if ( *bufferSize < (unsigned int) minSize ) *bufferSize = (unsigned int) minSize;
+ else if ( *bufferSize > (unsigned int) maxSize ) *bufferSize = (unsigned int) maxSize;
}
else if ( granularity != 0 ) {
// Set to an even multiple of granularity, rounding up.
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++
static inline DWORD dsPointerDifference( DWORD laterPointer, DWORD earlierPointer, DWORD bufferSize )
{
- if (laterPointer > earlierPointer)
+ if ( laterPointer > earlierPointer )
return laterPointer - earlierPointer;
else
return laterPointer - earlierPointer + bufferSize;
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();
while ( dsPointerLeadTime * 2U > (DWORD) bufferBytes )
bufferBytes *= 2;
- // Set cooperative level to DSSCL_EXCLUSIVE
- result = output->SetCooperativeLevel( hWnd, DSSCL_EXCLUSIVE );
+ // Set cooperative level to DSSCL_EXCLUSIVE ... sound stops when window focus changes.
+ //result = output->SetCooperativeLevel( hWnd, DSSCL_EXCLUSIVE );
+ // Set cooperative level to DSSCL_PRIORITY ... sound remains when window focus changes.
+ result = output->SetCooperativeLevel( hWnd, DSSCL_PRIORITY );
if ( FAILED( result ) ) {
output->Release();
errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") setting cooperative level (" << dsinfo.name << ")!";
ZeroMemory( &bufferDescription, sizeof( DSBUFFERDESC ) );
bufferDescription.dwSize = sizeof( DSBUFFERDESC );
bufferDescription.dwFlags = ( DSBCAPS_STICKYFOCUS |
+ DSBCAPS_GLOBALFOCUS |
DSBCAPS_GETCURRENTPOSITION2 |
DSBCAPS_LOCHARDWARE ); // Force hardware mixing
bufferDescription.dwBufferBytes = bufferBytes;
result = output->CreateSoundBuffer( &bufferDescription, &buffer, NULL );
if ( FAILED( result ) ) {
bufferDescription.dwFlags = ( DSBCAPS_STICKYFOCUS |
+ DSBCAPS_GLOBALFOCUS |
DSBCAPS_GETCURRENTPOSITION2 |
DSBCAPS_LOCSOFTWARE ); // Force software mixing
result = output->CreateSoundBuffer( &bufferDescription, &buffer, NULL );
}
// 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;
goto error;
}
+ // Boost DS thread priority
+ SetThreadPriority( (HANDLE) stream_.callbackInfo.thread, THREAD_PRIORITY_HIGHEST );
return SUCCESS;
error:
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";
snd_pcm_t *handles[2];
bool synchronized;
bool xrun[2];
+ pthread_cond_t runnable;
AlsaHandle()
:synchronized(false) { xrun[0] = false; xrun[1] = false; }
foundDevice:
+ // If a stream is already open, we cannot probe the stream devices.
+ // Thus, use the saved results.
+ if ( stream_.state != STREAM_CLOSED &&
+ ( stream_.device[0] == device || stream_.device[1] == device ) ) {
+ if ( device >= devices_.size() ) {
+ errorText_ = "RtApiAlsa::getDeviceInfo: device ID was not present before stream was opened.";
+ error( RtError::WARNING );
+ return info;
+ }
+ return devices_[ device ];
+ }
+
int openMode = SND_PCM_ASYNC;
snd_pcm_stream_t stream;
snd_pcm_info_t *pcminfo;
return info;
}
+void RtApiAlsa :: saveDeviceInfo( void )
+{
+ devices_.clear();
+
+ unsigned int nDevices = getDeviceCount();
+ devices_.resize( nDevices );
+ for ( unsigned int i=0; i<nDevices; i++ )
+ devices_[i] = getDeviceInfo( i );
+}
+
bool RtApiAlsa :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
unsigned int firstChannel, unsigned int sampleRate,
RtAudioFormat format, unsigned int *bufferSize,
if ( subdevice < 0 ) break;
if ( nDevices == device ) {
sprintf( name, "hw:%d,%d", card, subdevice );
+ snd_ctl_close( chandle );
goto foundDevice;
}
nDevices++;
foundDevice:
+ // The getDeviceInfo() function will not work for a device that is
+ // already open. Thus, we'll probe the system before opening a
+ // stream and save the results for use by getDeviceInfo().
+ if ( mode == OUTPUT || ( mode == INPUT && stream_.mode != OUTPUT ) ) // only do once
+ this->saveDeviceInfo();
+
snd_pcm_stream_t stream;
if ( mode == OUTPUT )
stream = SND_PCM_STREAM_PLAYBACK;
}
// Set the buffer number, which in ALSA is referred to as the "period".
- int dir;
+ int totalSize, dir;
unsigned int periods = 0;
if ( options ) periods = options->numberOfBuffers;
- if ( options && options->flags & RTAUDIO_MINIMIZE_LATENCY ) periods = 2;
- // Even though the hardware might allow 1 buffer, it won't work reliably.
- if ( periods < 2 ) periods = 2;
- result = snd_pcm_hw_params_set_periods_near( phandle, hw_params, &periods, &dir );
- if ( result < 0 ) {
- snd_pcm_close( phandle );
- errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting periods for device (" << name << "), " << snd_strerror( result ) << ".";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
+ totalSize = *bufferSize * periods;
// Set the buffer (or period) size.
snd_pcm_uframes_t periodSize = *bufferSize;
}
*bufferSize = periodSize;
+ if ( options && options->flags & RTAUDIO_MINIMIZE_LATENCY ) periods = 2;
+ else periods = totalSize / *bufferSize;
+ // Even though the hardware might allow 1 buffer, it won't work reliably.
+ if ( periods < 2 ) periods = 2;
+ result = snd_pcm_hw_params_set_periods_near( phandle, hw_params, &periods, &dir );
+ if ( result < 0 ) {
+ snd_pcm_close( phandle );
+ errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting periods for device (" << name << "), " << snd_strerror( result ) << ".";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
// If attempting to setup a duplex stream, the bufferSize parameter
// MUST be the same in both directions!
if ( stream_.mode == OUTPUT && mode == INPUT && *bufferSize != stream_.bufferSize ) {
snd_pcm_sw_params_alloca( &sw_params );
snd_pcm_sw_params_current( phandle, sw_params );
snd_pcm_sw_params_set_start_threshold( phandle, sw_params, *bufferSize );
- snd_pcm_sw_params_set_stop_threshold( phandle, sw_params, 0x7fffffff );
+ snd_pcm_sw_params_set_stop_threshold( phandle, sw_params, ULONG_MAX );
snd_pcm_sw_params_set_silence_threshold( phandle, sw_params, 0 );
- snd_pcm_sw_params_set_silence_size( phandle, sw_params, INT_MAX );
+
+ // The following two settings were suggested by Theo Veenker
+ //snd_pcm_sw_params_set_avail_min( phandle, sw_params, *bufferSize );
+ //snd_pcm_sw_params_set_xfer_align( phandle, sw_params, 1 );
+
+ // here are two options for a fix
+ //snd_pcm_sw_params_set_silence_size( phandle, sw_params, ULONG_MAX );
+ snd_pcm_uframes_t val;
+ snd_pcm_sw_params_get_boundary( sw_params, &val );
+ snd_pcm_sw_params_set_silence_size( phandle, sw_params, val );
+
result = snd_pcm_sw_params( phandle, sw_params );
if ( result < 0 ) {
snd_pcm_close( phandle );
errorText_ = "RtApiAlsa::probeDeviceOpen: error allocating AlsaHandle memory.";
goto error;
}
+
+ if ( pthread_cond_init( &apiInfo->runnable, NULL ) ) {
+ errorText_ = "RtApiAlsa::probeDeviceOpen: error initializing pthread condition variable.";
+ goto error;
+ }
+
stream_.apiHandle = (void *) apiInfo;
apiInfo->handles[0] = 0;
apiInfo->handles[1] = 0;
stream_.callbackInfo.object = (void *) this;
// Set the thread attributes for joinable and realtime scheduling
- // priority. The higher priority will only take affect if the
- // program is run as root or suid.
+ // priority (optional). The higher priority will only take affect
+ // if the program is run as root or suid. Note, under Linux
+ // processes with CAP_SYS_NICE privilege, a user can change
+ // scheduling policy and priority (thus need not be root). See
+ // POSIX "capabilities".
pthread_attr_t attr;
pthread_attr_init( &attr );
pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE );
#ifdef SCHED_RR // Undefined with some OSes (eg: NetBSD 1.6.x with GNU Pthread)
- pthread_attr_setschedpolicy( &attr, SCHED_RR );
+ if ( options && options->flags & RTAUDIO_SCHEDULE_REALTIME ) {
+ struct sched_param param;
+ int priority = options->priority;
+ int min = sched_get_priority_min( SCHED_RR );
+ int max = sched_get_priority_max( SCHED_RR );
+ if ( priority < min ) priority = min;
+ else if ( priority > max ) priority = max;
+ param.sched_priority = priority;
+ pthread_attr_setschedparam( &attr, ¶m );
+ pthread_attr_setschedpolicy( &attr, SCHED_RR );
+ }
+ else
+ pthread_attr_setschedpolicy( &attr, SCHED_OTHER );
#else
pthread_attr_setschedpolicy( &attr, SCHED_OTHER );
#endif
error:
if ( apiInfo ) {
+ pthread_cond_destroy( &apiInfo->runnable );
if ( apiInfo->handles[0] ) snd_pcm_close( apiInfo->handles[0] );
if ( apiInfo->handles[1] ) snd_pcm_close( apiInfo->handles[1] );
delete apiInfo;
return;
}
+ AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;
stream_.callbackInfo.isRunning = false;
+ MUTEX_LOCK( &stream_.mutex );
+ if ( stream_.state == STREAM_STOPPED )
+ pthread_cond_signal( &apiInfo->runnable );
+ MUTEX_UNLOCK( &stream_.mutex );
pthread_join( stream_.callbackInfo.thread, NULL );
- AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;
if ( stream_.state == STREAM_RUNNING ) {
stream_.state = STREAM_STOPPED;
if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX )
}
if ( apiInfo ) {
+ pthread_cond_destroy( &apiInfo->runnable );
if ( apiInfo->handles[0] ) snd_pcm_close( apiInfo->handles[0] );
if ( apiInfo->handles[1] ) snd_pcm_close( apiInfo->handles[1] );
delete apiInfo;
unlock:
MUTEX_UNLOCK( &stream_.mutex );
+ pthread_cond_signal( &apiInfo->runnable );
+
if ( result >= 0 ) return;
error( RtError::SYSTEM_ERROR );
}
return;
}
- // Change the state before the lock to improve shutdown response
- // when using a callback.
+ // Change the state before the lock to improve shutdown response.
stream_.state = STREAM_STOPPED;
MUTEX_LOCK( &stream_.mutex );
return;
}
- // Change the state before the lock to improve shutdown response
- // when using a callback.
+ // Change the state before the lock to improve shutdown response.
stream_.state = STREAM_STOPPED;
MUTEX_LOCK( &stream_.mutex );
unlock:
MUTEX_UNLOCK( &stream_.mutex );
- stream_.state = STREAM_STOPPED;
if ( result >= 0 ) return;
error( RtError::SYSTEM_ERROR );
}
void RtApiAlsa :: callbackEvent()
{
+ AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;
if ( stream_.state == STREAM_STOPPED ) {
- if ( stream_.callbackInfo.isRunning ) usleep( 50000 ); // sleep 50 milliseconds
- return;
+ MUTEX_LOCK( &stream_.mutex );
+ pthread_cond_wait( &apiInfo->runnable, &stream_.mutex );
+ if ( stream_.state != STREAM_RUNNING ) {
+ MUTEX_UNLOCK( &stream_.mutex );
+ return;
+ }
+ MUTEX_UNLOCK( &stream_.mutex );
}
if ( stream_.state == STREAM_CLOSED ) {
}
int doStopStream = 0;
- AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;
RtAudioCallback callback = (RtAudioCallback) stream_.callbackInfo.callback;
double streamTime = getStreamTime();
RtAudioStreamStatus status = 0;
doStopStream = callback( stream_.userBuffer[0], stream_.userBuffer[1],
stream_.bufferSize, streamTime, status, stream_.callbackInfo.userData );
+ if ( doStopStream == 2 ) {
+ abortStream();
+ return;
+ }
+
MUTEX_LOCK( &stream_.mutex );
// The state might change while waiting on a mutex.
}
if ( result < (int) stream_.bufferSize ) {
- // Either an error or underrun occured.
+ // Either an error or overrun occured.
if ( result == -EPIPE ) {
snd_pcm_state_t state = snd_pcm_state( handle[1] );
if ( state == SND_PCM_STATE_XRUN ) {
errorText_ = errorStream_.str();
}
error( RtError::WARNING );
- goto unlock;
+ goto tryOutput;
}
// Do byte swapping if necessary.
if ( result == 0 && frames > 0 ) stream_.latency[1] = frames;
}
+ tryOutput:
+
if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
// Setup parameters and do buffer conversion if necessary.
RtApi::tickStreamTime();
if ( doStopStream == 1 ) this->stopStream();
- else if ( doStopStream == 2 ) this->abortStream();
}
extern "C" void *alsaCallbackHandler( void *ptr )
RtApiAlsa *object = (RtApiAlsa *) info->object;
bool *isRunning = &info->isRunning;
-#ifdef SCHED_RR
- // Set a higher scheduler priority (P.J. Leonard)
- struct sched_param param;
- param.sched_priority = 39; // Is this the best number?
- sched_setscheduler( 0, SCHED_RR, ¶m );
-#endif
-
while ( *isRunning == true ) {
pthread_testcancel();
object->callbackEvent();
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
-#include "oss/soundcard.h"
+#include "soundcard.h"
#include <errno.h>
#include <math.h>
int id[2]; // device ids
bool xrun[2];
bool triggered;
+ pthread_cond_t runnable;
OssHandle()
:triggered(false) { id[0] = 0; id[1] = 0; xrun[0] = false; xrun[1] = false; }
return 0;
}
+ close( mixerfd );
return sysinfo.numaudios;
}
goto error;
}
+ if ( pthread_cond_init( &handle->runnable, NULL ) ) {
+ errorText_ = "RtApiOss::probeDeviceOpen: error initializing pthread condition variable.";
+ goto error;
+ }
+
stream_.apiHandle = (void *) handle;
}
else {
pthread_attr_init( &attr );
pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE );
#ifdef SCHED_RR // Undefined with some OSes (eg: NetBSD 1.6.x with GNU Pthread)
- pthread_attr_setschedpolicy( &attr, SCHED_RR );
+ if ( options && options->flags & RTAUDIO_SCHEDULE_REALTIME ) {
+ struct sched_param param;
+ int priority = options->priority;
+ int min = sched_get_priority_min( SCHED_RR );
+ int max = sched_get_priority_max( SCHED_RR );
+ if ( priority < min ) priority = min;
+ else if ( priority > max ) priority = max;
+ param.sched_priority = priority;
+ pthread_attr_setschedparam( &attr, ¶m );
+ pthread_attr_setschedpolicy( &attr, SCHED_RR );
+ }
+ else
+ pthread_attr_setschedpolicy( &attr, SCHED_OTHER );
#else
pthread_attr_setschedpolicy( &attr, SCHED_OTHER );
#endif
error:
if ( handle ) {
+ pthread_cond_destroy( &handle->runnable );
if ( handle->id[0] ) close( handle->id[0] );
if ( handle->id[1] ) close( handle->id[1] );
delete handle;
return;
}
+ OssHandle *handle = (OssHandle *) stream_.apiHandle;
stream_.callbackInfo.isRunning = false;
+ MUTEX_LOCK( &stream_.mutex );
+ if ( stream_.state == STREAM_STOPPED )
+ pthread_cond_signal( &handle->runnable );
+ MUTEX_UNLOCK( &stream_.mutex );
pthread_join( stream_.callbackInfo.thread, NULL );
- OssHandle *handle = (OssHandle *) stream_.apiHandle;
if ( stream_.state == STREAM_RUNNING ) {
if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX )
ioctl( handle->id[0], SNDCTL_DSP_HALT, 0 );
}
if ( handle ) {
+ pthread_cond_destroy( &handle->runnable );
if ( handle->id[0] ) close( handle->id[0] );
if ( handle->id[1] ) close( handle->id[1] );
delete handle;
// when fed samples.
MUTEX_UNLOCK( &stream_.mutex );
+
+ OssHandle *handle = (OssHandle *) stream_.apiHandle;
+ pthread_cond_signal( &handle->runnable );
}
void RtApiOss :: stopStream()
void RtApiOss :: callbackEvent()
{
+ OssHandle *handle = (OssHandle *) stream_.apiHandle;
if ( stream_.state == STREAM_STOPPED ) {
- if ( stream_.callbackInfo.isRunning ) usleep( 50000 ); // sleep 50 milliseconds
- return;
+ MUTEX_LOCK( &stream_.mutex );
+ pthread_cond_wait( &handle->runnable, &stream_.mutex );
+ if ( stream_.state != STREAM_RUNNING ) {
+ MUTEX_UNLOCK( &stream_.mutex );
+ return;
+ }
+ MUTEX_UNLOCK( &stream_.mutex );
}
if ( stream_.state == STREAM_CLOSED ) {
RtAudioCallback callback = (RtAudioCallback) stream_.callbackInfo.callback;
double streamTime = getStreamTime();
RtAudioStreamStatus status = 0;
- OssHandle *handle = (OssHandle *) stream_.apiHandle;
if ( stream_.mode != INPUT && handle->xrun[0] == true ) {
status |= RTAUDIO_OUTPUT_UNDERFLOW;
handle->xrun[0] = false;
}
doStopStream = callback( stream_.userBuffer[0], stream_.userBuffer[1],
stream_.bufferSize, streamTime, status, stream_.callbackInfo.userData );
+ if ( doStopStream == 2 ) {
+ this->abortStream();
+ return;
+ }
MUTEX_LOCK( &stream_.mutex );
handle->xrun[0] = true;
errorText_ = "RtApiOss::callbackEvent: audio write error.";
error( RtError::WARNING );
- goto unlock;
+ // Continue on to input section.
}
}
RtApi::tickStreamTime();
if ( doStopStream == 1 ) this->stopStream();
- else if ( doStopStream == 2 ) this->abortStream();
}
extern "C" void *ossCallbackHandler( void *ptr )
RtApiOss *object = (RtApiOss *) info->object;
bool *isRunning = &info->isRunning;
-#ifdef SCHED_RR
- // Set a higher scheduler priority (P.J. Leonard)
- struct sched_param param;
- param.sched_priority = 39; // Is this the best number?
- sched_setscheduler( 0, SCHED_RR, ¶m );
-#endif
-
while ( *isRunning == true ) {
pthread_testcancel();
object->callbackEvent();
// message printing.
void RtApi :: error( RtError::Type type )
{
- if ( type == RtError::RtError::WARNING && showWarnings_ == true )
+ 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()
stream_.callbackInfo.userData = 0;
stream_.callbackInfo.isRunning = false;
for ( int i=0; i<2; i++ ) {
- stream_.device[i] = 0;
+ stream_.device[i] = 11111;
stream_.doConvertBuffer[i] = false;
stream_.deviceInterleaved[i] = true;
stream_.doByteSwap[i] = false;
if (info.inFormat == RTAUDIO_SINT8) {
signed char *in = (signed char *)inBuffer;
- scale = 1.0 / 128.0;
+ scale = 1.0 / 127.5;
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
out[info.outOffset[j]] = (Float64) in[info.inOffset[j]];
+ out[info.outOffset[j]] += 0.5;
out[info.outOffset[j]] *= scale;
}
in += info.inJump;
}
else if (info.inFormat == RTAUDIO_SINT16) {
Int16 *in = (Int16 *)inBuffer;
- scale = 1.0 / 32768.0;
+ scale = 1.0 / 32767.5;
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
out[info.outOffset[j]] = (Float64) in[info.inOffset[j]];
+ out[info.outOffset[j]] += 0.5;
out[info.outOffset[j]] *= scale;
}
in += info.inJump;
}
else if (info.inFormat == RTAUDIO_SINT24) {
Int32 *in = (Int32 *)inBuffer;
- scale = 1.0 / 8388608.0;
+ scale = 1.0 / 8388607.5;
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
out[info.outOffset[j]] = (Float64) (in[info.inOffset[j]] & 0x00ffffff);
+ out[info.outOffset[j]] += 0.5;
out[info.outOffset[j]] *= scale;
}
in += info.inJump;
}
else if (info.inFormat == RTAUDIO_SINT32) {
Int32 *in = (Int32 *)inBuffer;
- scale = 1.0 / 2147483648.0;
+ scale = 1.0 / 2147483647.5;
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
out[info.outOffset[j]] = (Float64) in[info.inOffset[j]];
+ out[info.outOffset[j]] += 0.5;
out[info.outOffset[j]] *= scale;
}
in += info.inJump;
if (info.inFormat == RTAUDIO_SINT8) {
signed char *in = (signed char *)inBuffer;
- scale = 1.0 / 128.0;
+ scale = (Float32) ( 1.0 / 127.5 );
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
out[info.outOffset[j]] = (Float32) in[info.inOffset[j]];
+ out[info.outOffset[j]] += 0.5;
out[info.outOffset[j]] *= scale;
}
in += info.inJump;
}
else if (info.inFormat == RTAUDIO_SINT16) {
Int16 *in = (Int16 *)inBuffer;
- scale = 1.0 / 32768.0;
+ scale = (Float32) ( 1.0 / 32767.5 );
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
out[info.outOffset[j]] = (Float32) in[info.inOffset[j]];
+ out[info.outOffset[j]] += 0.5;
out[info.outOffset[j]] *= scale;
}
in += info.inJump;
}
else if (info.inFormat == RTAUDIO_SINT24) {
Int32 *in = (Int32 *)inBuffer;
- scale = 1.0 / 8388608.0;
+ scale = (Float32) ( 1.0 / 8388607.5 );
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
out[info.outOffset[j]] = (Float32) (in[info.inOffset[j]] & 0x00ffffff);
+ out[info.outOffset[j]] += 0.5;
out[info.outOffset[j]] *= scale;
}
in += info.inJump;
}
else if (info.inFormat == RTAUDIO_SINT32) {
Int32 *in = (Int32 *)inBuffer;
- scale = 1.0 / 2147483648.0;
+ scale = (Float32) ( 1.0 / 2147483647.5 );
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
out[info.outOffset[j]] = (Float32) in[info.inOffset[j]];
+ out[info.outOffset[j]] += 0.5;
out[info.outOffset[j]] *= scale;
}
in += info.inJump;
Float32 *in = (Float32 *)inBuffer;
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 2147483647.0);
+ out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 2147483647.5 - 0.5);
}
in += info.inJump;
out += info.outJump;
Float64 *in = (Float64 *)inBuffer;
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 2147483647.0);
+ out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 2147483647.5 - 0.5);
}
in += info.inJump;
out += info.outJump;
Float32 *in = (Float32 *)inBuffer;
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 8388608.0);
+ out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 8388607.5 - 0.5);
}
in += info.inJump;
out += info.outJump;
Float64 *in = (Float64 *)inBuffer;
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 2147483647.0);
+ out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 8388607.5 - 0.5);
}
in += info.inJump;
out += info.outJump;
Float32 *in = (Float32 *)inBuffer;
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (Int16) (in[info.inOffset[j]] * 32767.0);
+ out[info.outOffset[j]] = (Int16) (in[info.inOffset[j]] * 32767.5 - 0.5);
}
in += info.inJump;
out += info.outJump;
Float64 *in = (Float64 *)inBuffer;
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (Int16) (in[info.inOffset[j]] * 32767.0);
+ out[info.outOffset[j]] = (Int16) (in[info.inOffset[j]] * 32767.5 - 0.5);
}
in += info.inJump;
out += info.outJump;
Float32 *in = (Float32 *)inBuffer;
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (signed char) (in[info.inOffset[j]] * 127.0);
+ out[info.outOffset[j]] = (signed char) (in[info.inOffset[j]] * 127.5 - 0.5);
}
in += info.inJump;
out += info.outJump;
Float64 *in = (Float64 *)inBuffer;
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (signed char) (in[info.inOffset[j]] * 127.0);
+ out[info.outOffset[j]] = (signed char) (in[info.inOffset[j]] * 127.5 - 0.5);
}
in += info.inJump;
out += info.outJump;
}
}
+//static inline uint16_t bswap_16(uint16_t x) { return (x>>8) | (x<<8); }
+//static inline uint32_t bswap_32(uint32_t x) { return (bswap_16(x&0xffff)<<16) | (bswap_16(x>>16)); }
+//static inline uint64_t bswap_64(uint64_t x) { return (((unsigned long long)bswap_32(x&0xffffffffull))<<32) | (bswap_32(x>>32)); }
+
void RtApi :: byteSwapBuffer( char *buffer, unsigned int samples, RtAudioFormat format )
{
register char val;
*(ptr) = *(ptr+1);
*(ptr+1) = val;
- // Increment 4 bytes.
- ptr += 4;
+ // Increment 3 more bytes.
+ ptr += 3;
}
}
else if ( format == RTAUDIO_FLOAT64 ) {
*(ptr) = *(ptr+1);
*(ptr+1) = val;
- // Increment 8 bytes.
- ptr += 8;
+ // Increment 5 more bytes.
+ ptr += 5;
}
}
}