-/************************************************************************/\r
+/************************************************************************/\r
/*! \class RtAudio\r
\brief Realtime audio i/o C++ classes.\r
\r
RtAudio WWW site: http://www.music.mcgill.ca/~gary/rtaudio/\r
\r
RtAudio: realtime audio i/o C++ classes\r
- Copyright (c) 2001-2014 Gary P. Scavone\r
+ Copyright (c) 2001-2016 Gary P. Scavone\r
\r
Permission is hereby granted, free of charge, to any person\r
obtaining a copy of this software and associated documentation files\r
*/\r
/************************************************************************/\r
\r
-// RtAudio: Version 4.1.1\r
+// RtAudio: Version 4.1.2\r
\r
#include "RtAudio.h"\r
#include <iostream>\r
#include <cstdlib>\r
#include <cstring>\r
#include <climits>\r
+#include <cmath>\r
#include <algorithm>\r
\r
// Static variable definitions.\r
//\r
// *************************************************** //\r
\r
-std::string RtAudio :: getVersion( void ) throw()\r
+std::string RtAudio :: getVersion( void )\r
{\r
return RTAUDIO_VERSION;\r
}\r
\r
-void RtAudio :: getCompiledApi( std::vector<RtAudio::Api> &apis ) throw()\r
+void RtAudio :: getCompiledApi( std::vector<RtAudio::Api> &apis )\r
{\r
apis.clear();\r
\r
throw( RtAudioError( errorText, RtAudioError::UNSPECIFIED ) );\r
}\r
\r
-RtAudio :: ~RtAudio() throw()\r
+RtAudio :: ~RtAudio()\r
{\r
if ( rtapi_ )\r
delete rtapi_;\r
\r
if ( time >= 0.0 )\r
stream_.streamTime = time;\r
+#if defined( HAVE_GETTIMEOFDAY )\r
+ gettimeofday( &stream_.lastTickTimestamp, NULL );\r
+#endif\r
}\r
\r
unsigned int RtApi :: getStreamSampleRate( void )\r
// In order to satisfy WASAPI's buffer requirements, we need a means of converting sample rate\r
// between HW and the user. The convertBufferWasapi function is used to perform this conversion\r
// between HwIn->UserIn and UserOut->HwOut during the stream callback loop.\r
-// This sample rate converter favors speed over quality, and works best with conversions between\r
-// one rate and its multiple.\r
+// This sample rate converter works best with conversions between one rate and its multiple.\r
void convertBufferWasapi( char* outBuffer,\r
const char* inBuffer,\r
const unsigned int& channelCount,\r
{\r
// calculate the new outSampleCount and relative sampleStep\r
float sampleRatio = ( float ) outSampleRate / inSampleRate;\r
+ float sampleRatioInv = ( float ) 1 / sampleRatio;\r
float sampleStep = 1.0f / sampleRatio;\r
float inSampleFraction = 0.0f;\r
\r
- outSampleCount = ( unsigned int ) roundf( inSampleCount * sampleRatio );\r
+ outSampleCount = ( unsigned int ) std::roundf( inSampleCount * sampleRatio );\r
\r
- // frame-by-frame, copy each relative input sample into it's corresponding output sample\r
- for ( unsigned int outSample = 0; outSample < outSampleCount; outSample++ )\r
+ // if inSampleRate is a multiple of outSampleRate (or vice versa) there's no need to interpolate\r
+ if ( floor( sampleRatio ) == sampleRatio || floor( sampleRatioInv ) == sampleRatioInv )\r
{\r
- unsigned int inSample = ( unsigned int ) inSampleFraction;\r
-\r
- switch ( format )\r
+ // frame-by-frame, copy each relative input sample into it's corresponding output sample\r
+ for ( unsigned int outSample = 0; outSample < outSampleCount; outSample++ )\r
{\r
- case RTAUDIO_SINT8:\r
- memcpy( &( ( char* ) outBuffer )[ outSample * channelCount ], &( ( char* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( char ) );\r
- break;\r
- case RTAUDIO_SINT16:\r
- memcpy( &( ( short* ) outBuffer )[ outSample * channelCount ], &( ( short* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( short ) );\r
- break;\r
- case RTAUDIO_SINT24:\r
- memcpy( &( ( S24* ) outBuffer )[ outSample * channelCount ], &( ( S24* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( S24 ) );\r
- break;\r
- case RTAUDIO_SINT32:\r
- memcpy( &( ( int* ) outBuffer )[ outSample * channelCount ], &( ( int* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( int ) );\r
- break;\r
- case RTAUDIO_FLOAT32:\r
- memcpy( &( ( float* ) outBuffer )[ outSample * channelCount ], &( ( float* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( float ) );\r
- break;\r
- case RTAUDIO_FLOAT64:\r
- memcpy( &( ( double* ) outBuffer )[ outSample * channelCount ], &( ( double* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( double ) );\r
- break;\r
+ unsigned int inSample = ( unsigned int ) inSampleFraction;\r
+\r
+ switch ( format )\r
+ {\r
+ case RTAUDIO_SINT8:\r
+ memcpy( &( ( char* ) outBuffer )[ outSample * channelCount ], &( ( char* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( char ) );\r
+ break;\r
+ case RTAUDIO_SINT16:\r
+ memcpy( &( ( short* ) outBuffer )[ outSample * channelCount ], &( ( short* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( short ) );\r
+ break;\r
+ case RTAUDIO_SINT24:\r
+ memcpy( &( ( S24* ) outBuffer )[ outSample * channelCount ], &( ( S24* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( S24 ) );\r
+ break;\r
+ case RTAUDIO_SINT32:\r
+ memcpy( &( ( int* ) outBuffer )[ outSample * channelCount ], &( ( int* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( int ) );\r
+ break;\r
+ case RTAUDIO_FLOAT32:\r
+ memcpy( &( ( float* ) outBuffer )[ outSample * channelCount ], &( ( float* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( float ) );\r
+ break;\r
+ case RTAUDIO_FLOAT64:\r
+ memcpy( &( ( double* ) outBuffer )[ outSample * channelCount ], &( ( double* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( double ) );\r
+ break;\r
+ }\r
+\r
+ // jump to next in sample\r
+ inSampleFraction += sampleStep;\r
}\r
+ }\r
+ else // else interpolate\r
+ {\r
+ // frame-by-frame, copy each relative input sample into it's corresponding output sample\r
+ for ( unsigned int outSample = 0; outSample < outSampleCount; outSample++ )\r
+ {\r
+ unsigned int inSample = ( unsigned int ) inSampleFraction;\r
+ float inSampleDec = inSampleFraction - inSample;\r
+ unsigned int frameInSample = inSample * channelCount;\r
+ unsigned int frameOutSample = outSample * channelCount;\r
\r
- // jump to next in sample\r
- inSampleFraction += sampleStep;\r
+ switch ( format )\r
+ {\r
+ case RTAUDIO_SINT8:\r
+ {\r
+ for ( unsigned int channel = 0; channel < channelCount; channel++ )\r
+ {\r
+ char fromSample = ( ( char* ) inBuffer )[ frameInSample + channel ];\r
+ char toSample = ( ( char* ) inBuffer )[ frameInSample + channelCount + channel ];\r
+ char sampleDiff = ( char ) ( ( toSample - fromSample ) * inSampleDec );\r
+ ( ( char* ) outBuffer )[ frameOutSample + channel ] = fromSample + sampleDiff;\r
+ }\r
+ break;\r
+ }\r
+ case RTAUDIO_SINT16:\r
+ {\r
+ for ( unsigned int channel = 0; channel < channelCount; channel++ )\r
+ {\r
+ short fromSample = ( ( short* ) inBuffer )[ frameInSample + channel ];\r
+ short toSample = ( ( short* ) inBuffer )[ frameInSample + channelCount + channel ];\r
+ short sampleDiff = ( short ) ( ( toSample - fromSample ) * inSampleDec );\r
+ ( ( short* ) outBuffer )[ frameOutSample + channel ] = fromSample + sampleDiff;\r
+ }\r
+ break;\r
+ }\r
+ case RTAUDIO_SINT24:\r
+ {\r
+ for ( unsigned int channel = 0; channel < channelCount; channel++ )\r
+ {\r
+ int fromSample = ( ( S24* ) inBuffer )[ frameInSample + channel ].asInt();\r
+ int toSample = ( ( S24* ) inBuffer )[ frameInSample + channelCount + channel ].asInt();\r
+ int sampleDiff = ( int ) ( ( toSample - fromSample ) * inSampleDec );\r
+ ( ( S24* ) outBuffer )[ frameOutSample + channel ] = fromSample + sampleDiff;\r
+ }\r
+ break;\r
+ }\r
+ case RTAUDIO_SINT32:\r
+ {\r
+ for ( unsigned int channel = 0; channel < channelCount; channel++ )\r
+ {\r
+ int fromSample = ( ( int* ) inBuffer )[ frameInSample + channel ];\r
+ int toSample = ( ( int* ) inBuffer )[ frameInSample + channelCount + channel ];\r
+ int sampleDiff = ( int ) ( ( toSample - fromSample ) * inSampleDec );\r
+ ( ( int* ) outBuffer )[ frameOutSample + channel ] = fromSample + sampleDiff;\r
+ }\r
+ break;\r
+ }\r
+ case RTAUDIO_FLOAT32:\r
+ {\r
+ for ( unsigned int channel = 0; channel < channelCount; channel++ )\r
+ {\r
+ float fromSample = ( ( float* ) inBuffer )[ frameInSample + channel ];\r
+ float toSample = ( ( float* ) inBuffer )[ frameInSample + channelCount + channel ];\r
+ float sampleDiff = ( toSample - fromSample ) * inSampleDec;\r
+ ( ( float* ) outBuffer )[ frameOutSample + channel ] = fromSample + sampleDiff;\r
+ }\r
+ break;\r
+ }\r
+ case RTAUDIO_FLOAT64:\r
+ {\r
+ for ( unsigned int channel = 0; channel < channelCount; channel++ )\r
+ {\r
+ double fromSample = ( ( double* ) inBuffer )[ frameInSample + channel ];\r
+ double toSample = ( ( double* ) inBuffer )[ frameInSample + channelCount + channel ];\r
+ double sampleDiff = ( toSample - fromSample ) * inSampleDec;\r
+ ( ( double* ) outBuffer )[ frameOutSample + channel ] = fromSample + sampleDiff;\r
+ }\r
+ break;\r
+ }\r
+ }\r
+\r
+ // jump to next in sample\r
+ inSampleFraction += sampleStep;\r
+ }\r
}\r
}\r
\r
// if the callback buffer was pushed renderBuffer reset callbackPulled flag\r
if ( callbackPushed ) {\r
callbackPulled = false;\r
+ // tick stream time\r
+ RtApi::tickStreamTime();\r
}\r
\r
- // tick stream time\r
- RtApi::tickStreamTime();\r
}\r
\r
Exit:\r
\r
RtApiDs :: ~RtApiDs()\r
{\r
- if ( coInitialized_ ) CoUninitialize(); // balanced call.\r
if ( stream_.state != STREAM_CLOSED ) closeStream();\r
+ if ( coInitialized_ ) CoUninitialize(); // balanced call.\r
}\r
\r
// The DirectSound default output is always the first device.\r
if ( FAILED( result ) ) {\r
errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";\r
errorText_ = errorStream_.str();\r
+ MUTEX_UNLOCK( &stream_.mutex );\r
error( RtAudioError::SYSTEM_ERROR );\r
return;\r
}\r
bool *isRunning = &info->isRunning;\r
\r
#ifdef SCHED_RR // Undefined with some OSes (eg: NetBSD 1.6.x with GNU Pthread)\r
- if ( &info->doRealtime ) {\r
+ if ( info->doRealtime ) {\r
pthread_t tID = pthread_self(); // ID of this thread\r
sched_param prio = { info->priority }; // scheduling priority of thread\r
pthread_setschedparam( tID, SCHED_RR, &prio );\r
}\r
break;\r
case OUTPUT:\r
- pah->s_play = pa_simple_new( NULL, "RtAudio", PA_STREAM_PLAYBACK, NULL, "Playback", &ss, NULL, NULL, &error );\r
+ pah->s_play = pa_simple_new( NULL, streamName.c_str(), PA_STREAM_PLAYBACK, NULL, "Playback", &ss, NULL, NULL, &error );\r
if ( !pah->s_play ) {\r
errorText_ = "RtApiPulse::probeDeviceOpen: error connecting output to PulseAudio server.";\r
goto error;\r
info.nativeFormats |= RTAUDIO_SINT8;\r
if ( mask & AFMT_S32_LE || mask & AFMT_S32_BE )\r
info.nativeFormats |= RTAUDIO_SINT32;\r
+#ifdef AFMT_FLOAT\r
if ( mask & AFMT_FLOAT )\r
info.nativeFormats |= RTAUDIO_FLOAT32;\r
+#endif\r
if ( mask & AFMT_S24_LE || mask & AFMT_S24_BE )\r
info.nativeFormats |= RTAUDIO_SINT24;\r
\r
}\r
\r
// Verify the sample rate setup worked.\r
- if ( abs( srate - sampleRate ) > 100 ) {\r
+ if ( abs( srate - (int)sampleRate ) > 100 ) {\r
close( fd );\r
errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") does not support sample rate (" << sampleRate << ").";\r
errorText_ = errorStream_.str();\r
\r
void RtApi :: byteSwapBuffer( char *buffer, unsigned int samples, RtAudioFormat format )\r
{\r
- register char val;\r
- register char *ptr;\r
+ char val;\r
+ char *ptr;\r
\r
ptr = buffer;\r
if ( format == RTAUDIO_SINT16 ) {\r