From dc20fccbbec601cca84adb248d0c9550471990fc Mon Sep 17 00:00:00 2001 From: Marcus Tomlinson Date: Sat, 22 Apr 2017 19:12:22 +0200 Subject: [PATCH] =?UTF-8?q?=C2=96Added=20interpolation=20to=20WASAPI's=20s?= =?UTF-8?q?ample=20rate=20converter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- RtAudio.cpp | 147 +++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 116 insertions(+), 31 deletions(-) diff --git a/RtAudio.cpp b/RtAudio.cpp index 882fa0e..cdb98d7 100644 --- a/RtAudio.cpp +++ b/RtAudio.cpp @@ -1,4 +1,4 @@ -/************************************************************************/ +/************************************************************************/ /*! \class RtAudio \brief Realtime audio i/o C++ classes. @@ -3859,8 +3859,7 @@ private: // In order to satisfy WASAPI's buffer requirements, we need a means of converting sample rate // between HW and the user. The convertBufferWasapi function is used to perform this conversion // between HwIn->UserIn and UserOut->HwOut during the stream callback loop. -// This sample rate converter favors speed over quality, and works best with conversions between -// one rate and its multiple. +// This sample rate converter works best with conversions between one rate and its multiple. void convertBufferWasapi( char* outBuffer, const char* inBuffer, const unsigned int& channelCount, @@ -3872,40 +3871,126 @@ void convertBufferWasapi( char* outBuffer, { // calculate the new outSampleCount and relative sampleStep float sampleRatio = ( float ) outSampleRate / inSampleRate; + float sampleRatioInv = ( float ) 1 / sampleRatio; float sampleStep = 1.0f / sampleRatio; float inSampleFraction = 0.0f; outSampleCount = ( unsigned int ) roundf( inSampleCount * sampleRatio ); - // frame-by-frame, copy each relative input sample into it's corresponding output sample - for ( unsigned int outSample = 0; outSample < outSampleCount; outSample++ ) + // if inSampleRate is a multiple of outSampleRate (or vice versa) there's no need to interpolate + if (floor(sampleRatio) == sampleRatio || floor(sampleRatioInv) == sampleRatioInv) { - unsigned int inSample = ( unsigned int ) inSampleFraction; - - switch ( format ) - { - case RTAUDIO_SINT8: - memcpy( &( ( char* ) outBuffer )[ outSample * channelCount ], &( ( char* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( char ) ); - break; - case RTAUDIO_SINT16: - memcpy( &( ( short* ) outBuffer )[ outSample * channelCount ], &( ( short* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( short ) ); - break; - case RTAUDIO_SINT24: - memcpy( &( ( S24* ) outBuffer )[ outSample * channelCount ], &( ( S24* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( S24 ) ); - break; - case RTAUDIO_SINT32: - memcpy( &( ( int* ) outBuffer )[ outSample * channelCount ], &( ( int* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( int ) ); - break; - case RTAUDIO_FLOAT32: - memcpy( &( ( float* ) outBuffer )[ outSample * channelCount ], &( ( float* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( float ) ); - break; - case RTAUDIO_FLOAT64: - memcpy( &( ( double* ) outBuffer )[ outSample * channelCount ], &( ( double* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( double ) ); - break; - } - - // jump to next in sample - inSampleFraction += sampleStep; + // frame-by-frame, copy each relative input sample into it's corresponding output sample + for (unsigned int outSample = 0; outSample < outSampleCount; outSample++) + { + unsigned int inSample = (unsigned int)inSampleFraction; + + switch (format) + { + case RTAUDIO_SINT8: + memcpy(&((char*)outBuffer)[outSample * channelCount], &((char*)inBuffer)[inSample * channelCount], channelCount * sizeof(char)); + break; + case RTAUDIO_SINT16: + memcpy(&((short*)outBuffer)[outSample * channelCount], &((short*)inBuffer)[inSample * channelCount], channelCount * sizeof(short)); + break; + case RTAUDIO_SINT24: + memcpy(&((S24*)outBuffer)[outSample * channelCount], &((S24*)inBuffer)[inSample * channelCount], channelCount * sizeof(S24)); + break; + case RTAUDIO_SINT32: + memcpy(&((int*)outBuffer)[outSample * channelCount], &((int*)inBuffer)[inSample * channelCount], channelCount * sizeof(int)); + break; + case RTAUDIO_FLOAT32: + memcpy(&((float*)outBuffer)[outSample * channelCount], &((float*)inBuffer)[inSample * channelCount], channelCount * sizeof(float)); + break; + case RTAUDIO_FLOAT64: + memcpy(&((double*)outBuffer)[outSample * channelCount], &((double*)inBuffer)[inSample * channelCount], channelCount * sizeof(double)); + break; + } + + // jump to next in sample + inSampleFraction += sampleStep; + } + } + else // else interpolate + { + // frame-by-frame, copy each relative input sample into it's corresponding output sample + for (unsigned int outSample = 0; outSample < outSampleCount; outSample++) + { + unsigned int inSample = (unsigned int)inSampleFraction; + + switch (format) + { + case RTAUDIO_SINT8: + { + for (unsigned int channel = 0; channel < channelCount; channel++) + { + char fromSample = ((char*)inBuffer)[(inSample * channelCount) + channel]; + char toSample = ((char*)inBuffer)[((inSample + 1) * channelCount) + channel]; + float sampleDiff = (toSample - fromSample) * (inSampleFraction - floor(inSampleFraction)); + ((char*)outBuffer)[(outSample * channelCount) + channel] = fromSample + (char)sampleDiff; + } + break; + } + case RTAUDIO_SINT16: + { + for (unsigned int channel = 0; channel < channelCount; channel++) + { + short fromSample = ((short*)inBuffer)[(inSample * channelCount) + channel]; + short toSample = ((short*)inBuffer)[((inSample + 1) * channelCount) + channel]; + float sampleDiff = (toSample - fromSample) * (inSampleFraction - floor(inSampleFraction)); + ((short*)outBuffer)[(outSample * channelCount) + channel] = fromSample + (short)sampleDiff; + } + break; + } + case RTAUDIO_SINT24: + { + for (unsigned int channel = 0; channel < channelCount; channel++) + { + int fromSample = ((S24*)inBuffer)[(inSample * channelCount) + channel].asInt(); + int toSample = ((S24*)inBuffer)[((inSample + 1) * channelCount) + channel].asInt(); + float sampleDiff = (toSample - fromSample) * (inSampleFraction - floor(inSampleFraction)); + ((S24*)outBuffer)[(outSample * channelCount) + channel] = fromSample + (int)sampleDiff; + } + break; + } + case RTAUDIO_SINT32: + { + for (unsigned int channel = 0; channel < channelCount; channel++) + { + int fromSample = ((int*)inBuffer)[(inSample * channelCount) + channel]; + int toSample = ((int*)inBuffer)[((inSample + 1) * channelCount) + channel]; + float sampleDiff = (toSample - fromSample) * (inSampleFraction - floor(inSampleFraction)); + ((int*)outBuffer)[(outSample * channelCount) + channel] = fromSample + (int)sampleDiff; + } + break; + } + case RTAUDIO_FLOAT32: + { + for (unsigned int channel = 0; channel < channelCount; channel++) + { + float fromSample = ((float*)inBuffer)[(inSample * channelCount) + channel]; + float toSample = ((float*)inBuffer)[((inSample + 1) * channelCount) + channel]; + float sampleDiff = (toSample - fromSample) * (inSampleFraction - floor(inSampleFraction)); + ((float*)outBuffer)[(outSample * channelCount) + channel] = fromSample + sampleDiff; + } + break; + } + case RTAUDIO_FLOAT64: + { + for (unsigned int channel = 0; channel < channelCount; channel++) + { + double fromSample = ((double*)inBuffer)[(inSample * channelCount) + channel]; + double toSample = ((double*)inBuffer)[((inSample + 1) * channelCount) + channel]; + double sampleDiff = (toSample - fromSample) * (inSampleFraction - floor(inSampleFraction)); + ((double*)outBuffer)[(outSample * channelCount) + channel] = fromSample + sampleDiff; + } + break; + } + } + + // jump to next in sample + inSampleFraction += sampleStep; + } } }