|
|
@@ -3585,7 +3585,7 @@ static const char* getAsioErrorString( ASIOError result ) |
|
|
|
// - 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
|
|
|
|
// - 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
|
|
|
|
#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
|
|
|
|
// one rate and its multiple.
|
|
|
|
void convertBufferWasapi( char* outBuffer,
|
|
|
|
const char* inBuffer,
|
|
|
|
const unsigned int& inChannelCount,
|
|
|
|
const unsigned int& outChannelCount,
|
|
|
|
const unsigned int& channelCount,
|
|
|
|
const unsigned int& inSampleRate,
|
|
|
|
const unsigned int& outSampleRate,
|
|
|
|
const unsigned int& inSampleCount,
|
|
|
@@ -3786,7 +3785,6 @@ void convertBufferWasapi( char* outBuffer, |
|
|
|
float sampleRatio = ( float ) outSampleRate / inSampleRate;
|
|
|
|
float sampleStep = 1.0f / sampleRatio;
|
|
|
|
float inSampleFraction = 0.0f;
|
|
|
|
unsigned int commonChannelCount = std::min( inChannelCount, outChannelCount );
|
|
|
|
|
|
|
|
outSampleCount = ( unsigned int ) ( inSampleCount * sampleRatio );
|
|
|
|
|
|
|
@@ -3798,22 +3796,22 @@ void convertBufferWasapi( char* outBuffer, |
|
|
|
switch ( format )
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
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;
|
|
|
|
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;
|
|
|
|
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;
|
|
|
|
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;
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
@@ -4508,10 +4506,11 @@ bool RtApiWasapi::probeDeviceOpen( unsigned int device, StreamMode mode, unsigne |
|
|
|
|
|
|
|
// Set flags for buffer conversion.
|
|
|
|
stream_.doConvertBuffer[mode] = false;
|
|
|
|
if ( stream_.userFormat != stream_.deviceFormat[mode] )
|
|
|
|
if ( stream_.userFormat != stream_.deviceFormat[mode] ||
|
|
|
|
stream_.nUserChannels != stream_.nDeviceChannels )
|
|
|
|
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;
|
|
|
|
|
|
|
|
if ( stream_.doConvertBuffer[mode] )
|
|
|
@@ -4830,11 +4829,10 @@ void RtApiWasapi::wasapiThread() |
|
|
|
stream_.deviceFormat[INPUT] );
|
|
|
|
|
|
|
|
if ( callbackPulled ) {
|
|
|
|
// Convert callback buffer to user sample rate and channel count
|
|
|
|
// Convert callback buffer to user sample rate
|
|
|
|
convertBufferWasapi( stream_.deviceBuffer,
|
|
|
|
convBuffer,
|
|
|
|
stream_.nDeviceChannels[INPUT],
|
|
|
|
stream_.nUserChannels[INPUT],
|
|
|
|
captureFormat->nSamplesPerSec,
|
|
|
|
stream_.sampleRate,
|
|
|
|
( unsigned int ) ( stream_.bufferSize * captureSrRatio ),
|
|
|
@@ -4848,7 +4846,7 @@ void RtApiWasapi::wasapiThread() |
|
|
|
stream_.convertInfo[INPUT] );
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// no conversion, simple copy deviceBuffer to userBuffer
|
|
|
|
// no further conversion, simple copy deviceBuffer to userBuffer
|
|
|
|
memcpy( stream_.userBuffer[INPUT],
|
|
|
|
stream_.deviceBuffer,
|
|
|
|
stream_.bufferSize * stream_.nUserChannels[INPUT] * formatBytes( stream_.userFormat ) );
|
|
|
@@ -4924,35 +4922,27 @@ void RtApiWasapi::wasapiThread() |
|
|
|
stream_.userBuffer[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
|
|
|
|
callbackPushed = renderBuffer.pushBuffer( convBuffer,
|
|
|
|
convBufferSize * stream_.nDeviceChannels[OUTPUT],
|
|
|
|
stream_.deviceFormat[OUTPUT] );
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// if there is no render stream, set callbackPushed flag
|
|
|
|
callbackPushed = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stream Capture
|
|
|
|
// ==============
|
|
|
@@ -4978,8 +4968,8 @@ void RtApiWasapi::wasapiThread() |
|
|
|
if ( bufferFrameCount != 0 ) {
|
|
|
|
// Push capture buffer into inputBuffer
|
|
|
|
if ( captureBuffer.pushBuffer( ( char* ) streamBuffer,
|
|
|
|
bufferFrameCount * stream_.nDeviceChannels[INPUT],
|
|
|
|
stream_.deviceFormat[INPUT] ) )
|
|
|
|
bufferFrameCount * stream_.nDeviceChannels[INPUT],
|
|
|
|
stream_.deviceFormat[INPUT] ) )
|
|
|
|
{
|
|
|
|
// Release capture buffer
|
|
|
|
hr = captureClient->ReleaseBuffer( bufferFrameCount );
|
|
|
@@ -5047,8 +5037,8 @@ void RtApiWasapi::wasapiThread() |
|
|
|
// Pull next buffer from outputBuffer
|
|
|
|
// Fill render buffer with next buffer
|
|
|
|
if ( renderBuffer.pullBuffer( ( char* ) streamBuffer,
|
|
|
|
bufferFrameCount * stream_.nDeviceChannels[OUTPUT],
|
|
|
|
stream_.deviceFormat[OUTPUT] ) )
|
|
|
|
bufferFrameCount * stream_.nDeviceChannels[OUTPUT],
|
|
|
|
stream_.deviceFormat[OUTPUT] ) )
|
|
|
|
{
|
|
|
|
// Release render buffer
|
|
|
|
hr = renderClient->ReleaseBuffer( bufferFrameCount, 0 );
|
|
|
|