TYPE * __restrict end = to + count;\\r
while (to != end)\\r
{\\r
- *to ++ = (TYPE)((float)(from[0] + from[1]) * 0.5f);\\r
+ *to ++ = (TYPE)((float)(from[0] + from[1]) * 0.70710678118654752440084436210485f/*1/sqrt(2)*/);\\r
from += 2;\\r
}\r
\r
switch (dir)\r
{\r
case MIX_DIR__1TO2:\r
- switch (format)\r
+ switch (format & ~paNonInterleaved)\r
{\r
case paUInt8: return _MixMonoToStereo_1TO2_8;\r
case paInt16: return _MixMonoToStereo_1TO2_16;\r
break;\r
\r
case MIX_DIR__2TO1:\r
- switch (format)\r
+ switch (format & ~paNonInterleaved)\r
{\r
case paUInt8: return _MixMonoToStereo_2TO1_8;\r
case paInt16: return _MixMonoToStereo_2TO1_16;\r
}\r
\r
// ------------------------------------------------------------------------------------------\r
-static PaSampleFormat waveformatToPaFormat(const WAVEFORMATEXTENSIBLE *in)\r
+static PaSampleFormat WaveToPaFormat(const WAVEFORMATEXTENSIBLE *in)\r
{\r
const WAVEFORMATEX *old = (WAVEFORMATEX *)in;\r
\r
}\r
else\r
{\r
-#define FORMATTESTS 3\r
-static const int BestToWorst[FORMATTESTS] = { paFloat32, paInt24, paInt16 };\r
-\r
- // try selecting suitable sample type\r
+ static const int BestToWorst[] = { paFloat32, paInt24, paInt16 };\r
int i;\r
- for (i = 0; i < FORMATTESTS; ++i)\r
+\r
+ // Try combination stereo and we will use built-in mono-stereo mixer then\r
+ if (params.channelCount == 1)\r
{\r
- WAVEFORMATEXTENSIBLE ext = { 0 };\r
- wasapiFillWFEXT(&ext, BestToWorst[i], sampleRate, params.channelCount);\r
+ WAVEFORMATEXTENSIBLE stereo = { 0 };\r
+\r
+ PaStreamParameters stereo_params = params;\r
+ stereo_params.channelCount = 2;\r
+\r
+ MakeWaveFormatFromParams(&stereo, &stereo_params, sampleRate);\r
\r
- hr = IAudioClient_IsFormatSupported(myClient, shareMode, &ext.Format, (shareMode == AUDCLNT_SHAREMODE_SHARED ? &sharedClosestMatch : NULL));\r
+ hr = IAudioClient_IsFormatSupported(myClient, shareMode, &stereo.Format, (shareMode == AUDCLNT_SHAREMODE_SHARED ? &sharedClosestMatch : NULL));\r
if (hr == S_OK)\r
{\r
- memcpy(outWavex, &ext, sizeof(WAVEFORMATEXTENSIBLE));\r
- answer = paFormatIsSupported;\r
- break;\r
+ memcpy(outWavex, &stereo, sizeof(WAVEFORMATEXTENSIBLE));\r
+ CoTaskMemFree(sharedClosestMatch);\r
+ return (answer = paFormatIsSupported);\r
}\r
- }\r
\r
- if (answer != paFormatIsSupported)\r
- {\r
- // If mono, then driver does not support 1 channel, we use internal workaround\r
- // of tiny software mixing functionality, e.g. we provide to user buffer 1 channel\r
- // but then mix into 2 for device buffer\r
- if (params.channelCount == 1)\r
+ // Try selecting suitable sample type\r
+ for (i = 0; i < STATIC_ARRAY_SIZE(BestToWorst); ++i)\r
{\r
- WAVEFORMATEXTENSIBLE stereo = { 0 };\r
- wasapiFillWFEXT(&stereo, params.sampleFormat, sampleRate, 2);\r
+ WAVEFORMATEXTENSIBLE sample = { 0 };\r
\r
- hr = IAudioClient_IsFormatSupported(myClient, shareMode, &stereo.Format, (shareMode == AUDCLNT_SHAREMODE_SHARED ? &sharedClosestMatch : NULL));\r
+ PaStreamParameters sample_params = stereo_params;\r
+ sample_params.sampleFormat = BestToWorst[i];\r
+\r
+ MakeWaveFormatFromParams(&sample, &sample_params, sampleRate);\r
+\r
+ hr = IAudioClient_IsFormatSupported(myClient, shareMode, &sample.Format, (shareMode == AUDCLNT_SHAREMODE_SHARED ? &sharedClosestMatch : NULL));\r
if (hr == S_OK)\r
{\r
- memcpy(outWavex, &stereo, sizeof(WAVEFORMATEXTENSIBLE));\r
- answer = paFormatIsSupported;\r
+ memcpy(outWavex, &sample, sizeof(WAVEFORMATEXTENSIBLE));\r
+ CoTaskMemFree(sharedClosestMatch);\r
+ return (answer = paFormatIsSupported);\r
}\r
}\r
}\r
\r
+ // Try selecting suitable sample type\r
+ for (i = 0; i < STATIC_ARRAY_SIZE(BestToWorst); ++i)\r
+ {\r
+ WAVEFORMATEXTENSIBLE spfmt = { 0 };\r
+\r
+ PaStreamParameters spfmt_params = params;\r
+ spfmt_params.sampleFormat = BestToWorst[i];\r
+\r
+ MakeWaveFormatFromParams(&spfmt, &spfmt_params, sampleRate);\r
+\r
+ hr = IAudioClient_IsFormatSupported(myClient, shareMode, &spfmt.Format, (shareMode == AUDCLNT_SHAREMODE_SHARED ? &sharedClosestMatch : NULL));\r
+ if (hr == S_OK)\r
+ {\r
+ memcpy(outWavex, &spfmt, sizeof(WAVEFORMATEXTENSIBLE));\r
+ CoTaskMemFree(sharedClosestMatch);\r
+ answer = paFormatIsSupported;\r
+ break;\r
+ }\r
+ }\r
+\r
+ // Nothing helped\r
LogHostError(hr);\r
}\r
\r
}\r
\r
// ------------------------------------------------------------------------------------------\r
-static HRESULT CreateAudioClient(PaWasapiSubStream *pSub, PaWasapiDeviceInfo *pInfo,\r
- const PaStreamParameters *params, UINT32 framesPerLatency, double sampleRate,\r
- BOOL blocking, BOOL output, BOOL fullDuplex, PaError *pa_error)\r
+static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSub, \r
+ PaWasapiDeviceInfo *pInfo, const PaStreamParameters *params, UINT32 framesPerLatency, \r
+ double sampleRate, BOOL blocking, BOOL output, BOOL fullDuplex, PaError *pa_error)\r
{\r
PaError error;\r
HRESULT hr;\r
goto done; // fail, format not supported\r
}\r
\r
- // Check for Mono >> Stereo workaround\r
+ // Check for Mono <<>> Stereo workaround\r
if ((params->channelCount == 1) && (pSub->wavex.Format.nChannels == 2))\r
{\r
if (blocking)\r
}\r
\r
// select mixer\r
- pSub->monoMixer = _GetMonoToStereoMixer(params->sampleFormat, (pInfo->flow == eRender ? MIX_DIR__1TO2 : MIX_DIR__2TO1));\r
+ pSub->monoMixer = _GetMonoToStereoMixer(WaveToPaFormat(&pSub->wavex), (pInfo->flow == eRender ? MIX_DIR__1TO2 : MIX_DIR__2TO1));\r
if (pSub->monoMixer == NULL)\r
{\r
LogHostError(hr = AUDCLNT_E_UNSUPPORTED_FORMAT);\r
framesPerLatency = MakeFramesFromHns(pInfo->DefaultDevicePeriod, pSub->wavex.Format.nSamplesPerSec);\r
\r
// Calculate aligned period\r
- _CalculateAlignedPeriod(pSub, &framesPerLatency, ALIGN_FWD);\r
+ _CalculateAlignedPeriod(pSub, &framesPerLatency, ALIGN_BWD);\r
\r
/*! Enforce min/max period for device in Shared mode to avoid bad audio quality.\r
Avoid doing so for Exclusive mode as alignment will suffer.\r
}\r
\r
// Select mixer\r
- pSub->monoMixer = _GetMonoToStereoMixer(params->sampleFormat, (pInfo->flow == eRender ? MIX_DIR__1TO2 : MIX_DIR__2TO1));\r
+ pSub->monoMixer = _GetMonoToStereoMixer(WaveToPaFormat(&pSub->wavex), (pInfo->flow == eRender ? MIX_DIR__1TO2 : MIX_DIR__2TO1));\r
if (pSub->monoMixer == NULL)\r
{\r
LogHostError(hr = AUDCLNT_E_UNSUPPORTED_FORMAT);\r
stream->in.streamFlags = 0; // polling interface is implemented for full-duplex mode also\r
\r
// Create Audio client\r
- hr = CreateAudioClient(&stream->in, info, inputParameters, framesPerBuffer/*framesPerLatency*/,\r
+ hr = CreateAudioClient(stream, &stream->in, info, inputParameters, framesPerBuffer/*framesPerLatency*/,\r
sampleRate, (streamCallback == NULL), FALSE, fullDuplex, &result);\r
if (hr != S_OK)\r
{\r
- LogHostError(hr);\r
- if (hr != AUDCLNT_E_UNSUPPORTED_FORMAT)\r
- result = paInvalidDevice;\r
-\r
- LogPaError(result);\r
+ LogPaError(result = paInvalidDevice);\r
goto error;\r
}\r
LogWAVEFORMATEXTENSIBLE(&stream->in.wavex);\r
\r
// Get closest format\r
- hostInputSampleFormat = PaUtil_SelectClosestAvailableFormat( waveformatToPaFormat(&stream->in.wavex), inputSampleFormat );\r
+ hostInputSampleFormat = PaUtil_SelectClosestAvailableFormat( WaveToPaFormat(&stream->in.wavex), inputSampleFormat );\r
\r
// Create volume mgr\r
stream->inVol = NULL;\r
stream->out.streamFlags = 0; // polling interface is implemented for full-duplex mode also\r
\r
// Create Audio client\r
- hr = CreateAudioClient(&stream->out, info, outputParameters, framesPerBuffer/*framesPerLatency*/,\r
+ hr = CreateAudioClient(stream, &stream->out, info, outputParameters, framesPerBuffer/*framesPerLatency*/,\r
sampleRate, (streamCallback == NULL), TRUE, fullDuplex, &result);\r
if (hr != S_OK)\r
{\r
- LogHostError(hr);\r
- if (hr != AUDCLNT_E_UNSUPPORTED_FORMAT)\r
- result = paInvalidDevice;\r
-\r
- LogPaError(result);\r
+ LogPaError(result = paInvalidDevice);\r
goto error;\r
}\r
LogWAVEFORMATEXTENSIBLE(&stream->out.wavex);\r
\r
// Get closest format\r
- hostOutputSampleFormat = PaUtil_SelectClosestAvailableFormat( waveformatToPaFormat(&stream->out.wavex), outputSampleFormat );\r
+ hostOutputSampleFormat = PaUtil_SelectClosestAvailableFormat( WaveToPaFormat(&stream->out.wavex), outputSampleFormat );\r
\r
// Activate volume\r
stream->outVol = NULL;\r
if (stream->in.period != stream->out.period)\r
{\r
PRINT(("WASAPI: OpenStream: period discrepancy\n"));\r
+ LogPaError(result = paBadIODeviceCombination);\r
goto error;\r
}\r
\r
while (WaitForSingleObject(stream->hCloseRequest, sleep_ms) == WAIT_TIMEOUT)\r
{\r
UINT32 i_frames = 0, i_processed = 0;\r
- BYTE *i_data = NULL, *o_data = NULL;\r
+ BYTE *i_data = NULL, *o_data = NULL, *o_data_host = NULL;\r
DWORD i_flags = 0;\r
UINT32 o_frames = 0;\r
\r
{\r
// processed amount of i_frames\r
i_processed = i_frames;\r
+ o_data_host = o_data;\r
\r
// convert output mono\r
if (stream->out.monoMixer)\r
#undef __DIV_8\r
// expand buffer (one way only for better performance due to no calls to realloc)\r
if (mono_frames_size > stream->out.monoBufferSize)\r
+ {\r
stream->out.monoBuffer = realloc(stream->out.monoBuffer, (stream->out.monoBufferSize = mono_frames_size));\r
+ if (stream->out.monoBuffer == NULL)\r
+ {\r
+ LogPaError(paInsufficientMemory);\r
+ break;\r
+ }\r
+ }\r
+\r
+ // replace buffer pointer\r
+ o_data = (BYTE *)stream->out.monoBuffer;\r
}\r
\r
// convert input mono\r
#undef __DIV_8\r
// expand buffer (one way only for better performance due to no calls to realloc)\r
if (mono_frames_size > stream->in.monoBufferSize)\r
+ {\r
stream->in.monoBuffer = realloc(stream->in.monoBuffer, (stream->in.monoBufferSize = mono_frames_size));\r
+ if (stream->in.monoBuffer == NULL)\r
+ {\r
+ LogPaError(paInsufficientMemory);\r
+ break;\r
+ }\r
+ }\r
\r
// mix 2 to 1 input channels\r
stream->in.monoMixer(stream->in.monoBuffer, i_data, i_processed);\r
\r
// mix 1 to 2 output channels\r
if (stream->out.monoBuffer)\r
- stream->out.monoMixer(o_data, stream->out.monoBuffer, o_processed);\r
+ stream->out.monoMixer(o_data_host, stream->out.monoBuffer, o_processed);\r
\r
// release host output buffer\r
if ((hr = IAudioRenderClient_ReleaseBuffer(stream->rclient, o_processed, 0)) != S_OK)\r