| @@ -3585,7 +3585,7 @@ static const char* getAsioErrorString( ASIOError result ) | |||||
| // - Introduces support for the Windows WASAPI API | // - Introduces support for the Windows WASAPI API | ||||
| // - Aims to deliver bit streams to and from hardware at the lowest possible latency, via the absolute minimum buffer sizes required | // - Aims to deliver bit streams to and from hardware at the lowest possible latency, via the absolute minimum buffer sizes required | ||||
| // - Provides flexible stream configuration to an otherwise strict and inflexible WASAPI interface | // - Provides flexible stream configuration to an otherwise strict and inflexible WASAPI interface | ||||
| // - Includes automatic internal conversion of sample rate, buffer size and channel count | |||||
| // - Includes automatic internal conversion of sample rate and buffer size between hardware and the user | |||||
| #ifndef INITGUID | #ifndef INITGUID | ||||
| #define INITGUID | #define INITGUID | ||||
| @@ -3767,15 +3767,14 @@ private: | |||||
| //----------------------------------------------------------------------------- | //----------------------------------------------------------------------------- | ||||
| // In order to satisfy WASAPI's buffer requirements, we need a means of converting sample rate and | |||||
| // channel counts between HW and the user. The convertBufferWasapi function is used to perform | |||||
| // these conversions between HwIn->UserIn and UserOut->HwOut during the stream callback loop. | |||||
| // 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 | // This sample rate converter favors speed over quality, and works best with conversions between | ||||
| // one rate and its multiple. | // one rate and its multiple. | ||||
| void convertBufferWasapi( char* outBuffer, | void convertBufferWasapi( char* outBuffer, | ||||
| const char* inBuffer, | const char* inBuffer, | ||||
| const unsigned int& inChannelCount, | |||||
| const unsigned int& outChannelCount, | |||||
| const unsigned int& channelCount, | |||||
| const unsigned int& inSampleRate, | const unsigned int& inSampleRate, | ||||
| const unsigned int& outSampleRate, | const unsigned int& outSampleRate, | ||||
| const unsigned int& inSampleCount, | const unsigned int& inSampleCount, | ||||
| @@ -3786,7 +3785,6 @@ void convertBufferWasapi( char* outBuffer, | |||||
| float sampleRatio = ( float ) outSampleRate / inSampleRate; | float sampleRatio = ( float ) outSampleRate / inSampleRate; | ||||
| float sampleStep = 1.0f / sampleRatio; | float sampleStep = 1.0f / sampleRatio; | ||||
| float inSampleFraction = 0.0f; | float inSampleFraction = 0.0f; | ||||
| unsigned int commonChannelCount = std::min( inChannelCount, outChannelCount ); | |||||
| outSampleCount = ( unsigned int ) ( inSampleCount * sampleRatio ); | outSampleCount = ( unsigned int ) ( inSampleCount * sampleRatio ); | ||||
| @@ -3798,22 +3796,22 @@ void convertBufferWasapi( char* outBuffer, | |||||
| switch ( format ) | switch ( format ) | ||||
| { | { | ||||
| case RTAUDIO_SINT8: | case RTAUDIO_SINT8: | ||||
| memcpy( &( ( char* ) outBuffer )[ outSample * outChannelCount ], &( ( char* ) inBuffer )[ inSample * inChannelCount ], commonChannelCount * sizeof( char ) ); | |||||
| memcpy( &( ( char* ) outBuffer )[ outSample * channelCount ], &( ( char* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( char ) ); | |||||
| break; | break; | ||||
| case RTAUDIO_SINT16: | case RTAUDIO_SINT16: | ||||
| memcpy( &( ( short* ) outBuffer )[ outSample * outChannelCount ], &( ( short* ) inBuffer )[ inSample * inChannelCount ], commonChannelCount * sizeof( short ) ); | |||||
| memcpy( &( ( short* ) outBuffer )[ outSample * channelCount ], &( ( short* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( short ) ); | |||||
| break; | break; | ||||
| case RTAUDIO_SINT24: | case RTAUDIO_SINT24: | ||||
| memcpy( &( ( S24* ) outBuffer )[ outSample * outChannelCount ], &( ( S24* ) inBuffer )[ inSample * inChannelCount ], commonChannelCount * sizeof( S24 ) ); | |||||
| memcpy( &( ( S24* ) outBuffer )[ outSample * channelCount ], &( ( S24* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( S24 ) ); | |||||
| break; | break; | ||||
| case RTAUDIO_SINT32: | case RTAUDIO_SINT32: | ||||
| memcpy( &( ( int* ) outBuffer )[ outSample * outChannelCount ], &( ( int* ) inBuffer )[ inSample * inChannelCount ], commonChannelCount * sizeof( int ) ); | |||||
| memcpy( &( ( int* ) outBuffer )[ outSample * channelCount ], &( ( int* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( int ) ); | |||||
| break; | break; | ||||
| case RTAUDIO_FLOAT32: | case RTAUDIO_FLOAT32: | ||||
| memcpy( &( ( float* ) outBuffer )[ outSample * outChannelCount ], &( ( float* ) inBuffer )[ inSample * inChannelCount ], commonChannelCount * sizeof( float ) ); | |||||
| memcpy( &( ( float* ) outBuffer )[ outSample * channelCount ], &( ( float* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( float ) ); | |||||
| break; | break; | ||||
| case RTAUDIO_FLOAT64: | case RTAUDIO_FLOAT64: | ||||
| memcpy( &( ( double* ) outBuffer )[ outSample * outChannelCount ], &( ( double* ) inBuffer )[ inSample * inChannelCount ], commonChannelCount * sizeof( double ) ); | |||||
| memcpy( &( ( double* ) outBuffer )[ outSample * channelCount ], &( ( double* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( double ) ); | |||||
| break; | break; | ||||
| } | } | ||||
| @@ -4508,10 +4506,11 @@ bool RtApiWasapi::probeDeviceOpen( unsigned int device, StreamMode mode, unsigne | |||||
| // Set flags for buffer conversion. | // Set flags for buffer conversion. | ||||
| stream_.doConvertBuffer[mode] = false; | stream_.doConvertBuffer[mode] = false; | ||||
| if ( stream_.userFormat != stream_.deviceFormat[mode] ) | |||||
| if ( stream_.userFormat != stream_.deviceFormat[mode] || | |||||
| stream_.nUserChannels != stream_.nDeviceChannels ) | |||||
| stream_.doConvertBuffer[mode] = true; | stream_.doConvertBuffer[mode] = true; | ||||
| if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] && | |||||
| stream_.nUserChannels[mode] > 1 ) | |||||
| else if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] && | |||||
| stream_.nUserChannels[mode] > 1 ) | |||||
| stream_.doConvertBuffer[mode] = true; | stream_.doConvertBuffer[mode] = true; | ||||
| if ( stream_.doConvertBuffer[mode] ) | if ( stream_.doConvertBuffer[mode] ) | ||||
| @@ -4830,11 +4829,10 @@ void RtApiWasapi::wasapiThread() | |||||
| stream_.deviceFormat[INPUT] ); | stream_.deviceFormat[INPUT] ); | ||||
| if ( callbackPulled ) { | if ( callbackPulled ) { | ||||
| // Convert callback buffer to user sample rate and channel count | |||||
| // Convert callback buffer to user sample rate | |||||
| convertBufferWasapi( stream_.deviceBuffer, | convertBufferWasapi( stream_.deviceBuffer, | ||||
| convBuffer, | convBuffer, | ||||
| stream_.nDeviceChannels[INPUT], | stream_.nDeviceChannels[INPUT], | ||||
| stream_.nUserChannels[INPUT], | |||||
| captureFormat->nSamplesPerSec, | captureFormat->nSamplesPerSec, | ||||
| stream_.sampleRate, | stream_.sampleRate, | ||||
| ( unsigned int ) ( stream_.bufferSize * captureSrRatio ), | ( unsigned int ) ( stream_.bufferSize * captureSrRatio ), | ||||
| @@ -4848,7 +4846,7 @@ void RtApiWasapi::wasapiThread() | |||||
| stream_.convertInfo[INPUT] ); | stream_.convertInfo[INPUT] ); | ||||
| } | } | ||||
| else { | else { | ||||
| // no conversion, simple copy deviceBuffer to userBuffer | |||||
| // no further conversion, simple copy deviceBuffer to userBuffer | |||||
| memcpy( stream_.userBuffer[INPUT], | memcpy( stream_.userBuffer[INPUT], | ||||
| stream_.deviceBuffer, | stream_.deviceBuffer, | ||||
| stream_.bufferSize * stream_.nUserChannels[INPUT] * formatBytes( stream_.userFormat ) ); | stream_.bufferSize * stream_.nUserChannels[INPUT] * formatBytes( stream_.userFormat ) ); | ||||
| @@ -4924,35 +4922,27 @@ void RtApiWasapi::wasapiThread() | |||||
| stream_.userBuffer[OUTPUT], | stream_.userBuffer[OUTPUT], | ||||
| stream_.convertInfo[OUTPUT] ); | stream_.convertInfo[OUTPUT] ); | ||||
| // Convert callback buffer to stream sample rate and channel count | |||||
| convertBufferWasapi( convBuffer, | |||||
| stream_.deviceBuffer, | |||||
| stream_.nUserChannels[OUTPUT], | |||||
| stream_.nDeviceChannels[OUTPUT], | |||||
| stream_.sampleRate, | |||||
| renderFormat->nSamplesPerSec, | |||||
| stream_.bufferSize, | |||||
| convBufferSize, | |||||
| stream_.deviceFormat[OUTPUT] ); | |||||
| } | |||||
| else { | |||||
| // Convert callback buffer to stream sample rate and channel count | |||||
| convertBufferWasapi( convBuffer, | |||||
| stream_.userBuffer[OUTPUT], | |||||
| stream_.nUserChannels[OUTPUT], | |||||
| stream_.nDeviceChannels[OUTPUT], | |||||
| stream_.sampleRate, | |||||
| renderFormat->nSamplesPerSec, | |||||
| stream_.bufferSize, | |||||
| convBufferSize, | |||||
| stream_.deviceFormat[OUTPUT] ); | |||||
| } | } | ||||
| // Convert callback buffer to stream sample rate | |||||
| convertBufferWasapi( convBuffer, | |||||
| stream_.deviceBuffer, | |||||
| stream_.nDeviceChannels[OUTPUT], | |||||
| stream_.sampleRate, | |||||
| renderFormat->nSamplesPerSec, | |||||
| stream_.bufferSize, | |||||
| convBufferSize, | |||||
| stream_.deviceFormat[OUTPUT] ); | |||||
| // Push callback buffer into outputBuffer | // Push callback buffer into outputBuffer | ||||
| callbackPushed = renderBuffer.pushBuffer( convBuffer, | callbackPushed = renderBuffer.pushBuffer( convBuffer, | ||||
| convBufferSize * stream_.nDeviceChannels[OUTPUT], | convBufferSize * stream_.nDeviceChannels[OUTPUT], | ||||
| stream_.deviceFormat[OUTPUT] ); | stream_.deviceFormat[OUTPUT] ); | ||||
| } | } | ||||
| else { | |||||
| // if there is no render stream, set callbackPushed flag | |||||
| callbackPushed = true; | |||||
| } | |||||
| // Stream Capture | // Stream Capture | ||||
| // ============== | // ============== | ||||
| @@ -4978,8 +4968,8 @@ void RtApiWasapi::wasapiThread() | |||||
| if ( bufferFrameCount != 0 ) { | if ( bufferFrameCount != 0 ) { | ||||
| // Push capture buffer into inputBuffer | // Push capture buffer into inputBuffer | ||||
| if ( captureBuffer.pushBuffer( ( char* ) streamBuffer, | if ( captureBuffer.pushBuffer( ( char* ) streamBuffer, | ||||
| bufferFrameCount * stream_.nDeviceChannels[INPUT], | |||||
| stream_.deviceFormat[INPUT] ) ) | |||||
| bufferFrameCount * stream_.nDeviceChannels[INPUT], | |||||
| stream_.deviceFormat[INPUT] ) ) | |||||
| { | { | ||||
| // Release capture buffer | // Release capture buffer | ||||
| hr = captureClient->ReleaseBuffer( bufferFrameCount ); | hr = captureClient->ReleaseBuffer( bufferFrameCount ); | ||||
| @@ -5047,8 +5037,8 @@ void RtApiWasapi::wasapiThread() | |||||
| // Pull next buffer from outputBuffer | // Pull next buffer from outputBuffer | ||||
| // Fill render buffer with next buffer | // Fill render buffer with next buffer | ||||
| if ( renderBuffer.pullBuffer( ( char* ) streamBuffer, | if ( renderBuffer.pullBuffer( ( char* ) streamBuffer, | ||||
| bufferFrameCount * stream_.nDeviceChannels[OUTPUT], | |||||
| stream_.deviceFormat[OUTPUT] ) ) | |||||
| bufferFrameCount * stream_.nDeviceChannels[OUTPUT], | |||||
| stream_.deviceFormat[OUTPUT] ) ) | |||||
| { | { | ||||
| // Release render buffer | // Release render buffer | ||||
| hr = renderClient->ReleaseBuffer( bufferFrameCount, 0 ); | hr = renderClient->ReleaseBuffer( bufferFrameCount, 0 ); | ||||