\96Added interpolation to WASAPI's sample rate converter
authorMarcus Tomlinson <themarcustomlinson@gmail.com>
Sat, 22 Apr 2017 17:12:22 +0000 (19:12 +0200)
committerMarcus Tomlinson <themarcustomlinson@gmail.com>
Sat, 22 Apr 2017 17:12:22 +0000 (19:12 +0200)
RtAudio.cpp

index 882fa0e2830202407c2f17814c8a4e372947993d..cdb98d760b91bfd00480d6d08d6f82c8d4d679c1 100644 (file)
@@ -1,4 +1,4 @@
-/************************************************************************/\r
+/************************************************************************/\r
 /*! \class RtAudio\r
     \brief Realtime audio i/o C++ classes.\r
 \r
@@ -3859,8 +3859,7 @@ private:
 // 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
@@ -3872,40 +3871,126 @@ void convertBufferWasapi( char* outBuffer,
 {\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
 \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
-    {\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
+         // 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
+\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
+\r
+                 switch (format)\r
+                 {\r
+                 case RTAUDIO_SINT8:\r
+                 {\r
+                         for (unsigned int channel = 0; channel < channelCount; channel++)\r
+                         {\r
+                                 char fromSample = ((char*)inBuffer)[(inSample * channelCount) + channel];\r
+                                 char toSample = ((char*)inBuffer)[((inSample + 1) * channelCount) + channel];\r
+                                 float sampleDiff = (toSample - fromSample) * (inSampleFraction - floor(inSampleFraction));\r
+                                 ((char*)outBuffer)[(outSample * channelCount) + channel] = fromSample + (char)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)[(inSample * channelCount) + channel];\r
+                                 short toSample = ((short*)inBuffer)[((inSample + 1) * channelCount) + channel];\r
+                                 float sampleDiff = (toSample - fromSample) * (inSampleFraction - floor(inSampleFraction));\r
+                                 ((short*)outBuffer)[(outSample * channelCount) + channel] = fromSample + (short)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)[(inSample * channelCount) + channel].asInt();\r
+                                 int toSample = ((S24*)inBuffer)[((inSample + 1) * channelCount) + channel].asInt();\r
+                                 float sampleDiff = (toSample - fromSample) * (inSampleFraction - floor(inSampleFraction));\r
+                                 ((S24*)outBuffer)[(outSample * channelCount) + channel] = fromSample + (int)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)[(inSample * channelCount) + channel];\r
+                                 int toSample = ((int*)inBuffer)[((inSample + 1) * channelCount) + channel];\r
+                                 float sampleDiff = (toSample - fromSample) * (inSampleFraction - floor(inSampleFraction));\r
+                                 ((int*)outBuffer)[(outSample * channelCount) + channel] = fromSample + (int)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)[(inSample * channelCount) + channel];\r
+                                 float toSample = ((float*)inBuffer)[((inSample + 1) * channelCount) + channel];\r
+                                 float sampleDiff = (toSample - fromSample) * (inSampleFraction - floor(inSampleFraction));\r
+                                 ((float*)outBuffer)[(outSample * channelCount) + 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)[(inSample * channelCount) + channel];\r
+                                 double toSample = ((double*)inBuffer)[((inSample + 1) * channelCount) + channel];\r
+                                 double sampleDiff = (toSample - fromSample) * (inSampleFraction - floor(inSampleFraction));\r
+                                 ((double*)outBuffer)[(outSample * channelCount) + channel] = fromSample + sampleDiff;\r
+                         }\r
+                         break;\r
+                 }\r
+                 }\r
+\r
+                 // jump to next in sample\r
+                 inSampleFraction += sampleStep;\r
+         }\r
   }\r
 }\r
 \r