// - Introduces support for the Windows WASAPI API\r
// - Aims to deliver bit streams to and from hardware at the lowest possible latency, via the absolute minimum buffer sizes required\r
// - Provides flexible stream configuration to an otherwise strict and inflexible WASAPI interface\r
-// - Includes automatic internal conversion of sample rate, buffer size and channel count\r
+// - Includes automatic internal conversion of sample rate and buffer size between hardware and the user\r
\r
#ifndef INITGUID\r
#define INITGUID\r
\r
//-----------------------------------------------------------------------------\r
\r
-// In order to satisfy WASAPI's buffer requirements, we need a means of converting sample rate and\r
-// channel counts between HW and the user. The convertBufferWasapi function is used to perform\r
-// these conversions between HwIn->UserIn and UserOut->HwOut during the stream callback loop.\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
void convertBufferWasapi( char* outBuffer,\r
const char* inBuffer,\r
- const unsigned int& inChannelCount,\r
- const unsigned int& outChannelCount,\r
+ const unsigned int& channelCount,\r
const unsigned int& inSampleRate,\r
const unsigned int& outSampleRate,\r
const unsigned int& inSampleCount,\r
float sampleRatio = ( float ) outSampleRate / inSampleRate;\r
float sampleStep = 1.0f / sampleRatio;\r
float inSampleFraction = 0.0f;\r
- unsigned int commonChannelCount = std::min( inChannelCount, outChannelCount );\r
\r
outSampleCount = ( unsigned int ) ( inSampleCount * sampleRatio );\r
\r
switch ( format )\r
{\r
case RTAUDIO_SINT8:\r
- memcpy( &( ( char* ) outBuffer )[ outSample * outChannelCount ], &( ( char* ) inBuffer )[ inSample * inChannelCount ], commonChannelCount * sizeof( char ) );\r
+ memcpy( &( ( char* ) outBuffer )[ outSample * channelCount ], &( ( char* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( char ) );\r
break;\r
case RTAUDIO_SINT16:\r
- memcpy( &( ( short* ) outBuffer )[ outSample * outChannelCount ], &( ( short* ) inBuffer )[ inSample * inChannelCount ], commonChannelCount * sizeof( short ) );\r
+ memcpy( &( ( short* ) outBuffer )[ outSample * channelCount ], &( ( short* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( short ) );\r
break;\r
case RTAUDIO_SINT24:\r
- memcpy( &( ( S24* ) outBuffer )[ outSample * outChannelCount ], &( ( S24* ) inBuffer )[ inSample * inChannelCount ], commonChannelCount * sizeof( S24 ) );\r
+ memcpy( &( ( S24* ) outBuffer )[ outSample * channelCount ], &( ( S24* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( S24 ) );\r
break;\r
case RTAUDIO_SINT32:\r
- memcpy( &( ( int* ) outBuffer )[ outSample * outChannelCount ], &( ( int* ) inBuffer )[ inSample * inChannelCount ], commonChannelCount * sizeof( int ) );\r
+ memcpy( &( ( int* ) outBuffer )[ outSample * channelCount ], &( ( int* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( int ) );\r
break;\r
case RTAUDIO_FLOAT32:\r
- memcpy( &( ( float* ) outBuffer )[ outSample * outChannelCount ], &( ( float* ) inBuffer )[ inSample * inChannelCount ], commonChannelCount * sizeof( float ) );\r
+ memcpy( &( ( float* ) outBuffer )[ outSample * channelCount ], &( ( float* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( float ) );\r
break;\r
case RTAUDIO_FLOAT64:\r
- memcpy( &( ( double* ) outBuffer )[ outSample * outChannelCount ], &( ( double* ) inBuffer )[ inSample * inChannelCount ], commonChannelCount * sizeof( double ) );\r
+ memcpy( &( ( double* ) outBuffer )[ outSample * channelCount ], &( ( double* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( double ) );\r
break;\r
}\r
\r
\r
// Set flags for buffer conversion.\r
stream_.doConvertBuffer[mode] = false;\r
- if ( stream_.userFormat != stream_.deviceFormat[mode] )\r
+ if ( stream_.userFormat != stream_.deviceFormat[mode] ||\r
+ stream_.nUserChannels != stream_.nDeviceChannels )\r
stream_.doConvertBuffer[mode] = true;\r
- if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] &&\r
- stream_.nUserChannels[mode] > 1 )\r
+ else if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] &&\r
+ stream_.nUserChannels[mode] > 1 )\r
stream_.doConvertBuffer[mode] = true;\r
\r
if ( stream_.doConvertBuffer[mode] )\r
stream_.deviceFormat[INPUT] );\r
\r
if ( callbackPulled ) {\r
- // Convert callback buffer to user sample rate and channel count\r
+ // Convert callback buffer to user sample rate\r
convertBufferWasapi( stream_.deviceBuffer,\r
convBuffer,\r
stream_.nDeviceChannels[INPUT],\r
- stream_.nUserChannels[INPUT],\r
captureFormat->nSamplesPerSec,\r
stream_.sampleRate,\r
( unsigned int ) ( stream_.bufferSize * captureSrRatio ),\r
stream_.convertInfo[INPUT] );\r
}\r
else {\r
- // no conversion, simple copy deviceBuffer to userBuffer\r
+ // no further conversion, simple copy deviceBuffer to userBuffer\r
memcpy( stream_.userBuffer[INPUT],\r
stream_.deviceBuffer,\r
stream_.bufferSize * stream_.nUserChannels[INPUT] * formatBytes( stream_.userFormat ) );\r
stream_.userBuffer[OUTPUT],\r
stream_.convertInfo[OUTPUT] );\r
\r
- // Convert callback buffer to stream sample rate and channel count\r
- convertBufferWasapi( convBuffer,\r
- stream_.deviceBuffer,\r
- stream_.nUserChannels[OUTPUT],\r
- stream_.nDeviceChannels[OUTPUT],\r
- stream_.sampleRate,\r
- renderFormat->nSamplesPerSec,\r
- stream_.bufferSize,\r
- convBufferSize,\r
- stream_.deviceFormat[OUTPUT] );\r
- }\r
- else {\r
- // Convert callback buffer to stream sample rate and channel count\r
- convertBufferWasapi( convBuffer,\r
- stream_.userBuffer[OUTPUT],\r
- stream_.nUserChannels[OUTPUT],\r
- stream_.nDeviceChannels[OUTPUT],\r
- stream_.sampleRate,\r
- renderFormat->nSamplesPerSec,\r
- stream_.bufferSize,\r
- convBufferSize,\r
- stream_.deviceFormat[OUTPUT] );\r
}\r
\r
+ // Convert callback buffer to stream sample rate\r
+ convertBufferWasapi( convBuffer,\r
+ stream_.deviceBuffer,\r
+ stream_.nDeviceChannels[OUTPUT],\r
+ stream_.sampleRate,\r
+ renderFormat->nSamplesPerSec,\r
+ stream_.bufferSize,\r
+ convBufferSize,\r
+ stream_.deviceFormat[OUTPUT] );\r
+\r
// Push callback buffer into outputBuffer\r
callbackPushed = renderBuffer.pushBuffer( convBuffer,\r
convBufferSize * stream_.nDeviceChannels[OUTPUT],\r
if ( bufferFrameCount != 0 ) {\r
// Push capture buffer into inputBuffer\r
if ( captureBuffer.pushBuffer( ( char* ) streamBuffer,\r
- bufferFrameCount * stream_.nDeviceChannels[INPUT],\r
- stream_.deviceFormat[INPUT] ) )\r
+ bufferFrameCount * stream_.nDeviceChannels[INPUT],\r
+ stream_.deviceFormat[INPUT] ) )\r
{\r
// Release capture buffer\r
hr = captureClient->ReleaseBuffer( bufferFrameCount );\r
// Pull next buffer from outputBuffer\r
// Fill render buffer with next buffer\r
if ( renderBuffer.pullBuffer( ( char* ) streamBuffer,\r
- bufferFrameCount * stream_.nDeviceChannels[OUTPUT],\r
- stream_.deviceFormat[OUTPUT] ) )\r
+ bufferFrameCount * stream_.nDeviceChannels[OUTPUT],\r
+ stream_.deviceFormat[OUTPUT] ) )\r
{\r
// Release render buffer\r
hr = renderClient->ReleaseBuffer( bufferFrameCount, 0 );\r