Skip to content

Commit

Permalink
dsound: don't restrict the host buffer to 16-bit
Browse files Browse the repository at this point in the history
Currently, the DirectSound Host API code only creates 16-bit integer
DirectSound buffers. All audio data provided by the user is therefore
converted by PortAudio to and from 16-bit, regardless of the user buffer
format.

This basically makes it impossible to pass 24-bit audio through the
DirectSound Host API.

If the user buffer format is not 16-bit, this also causes pointless
conversions to take place, *even if the hardware is running at 16-bit*,
because modern Windows versions (Vista+) convert the data to floating
point behind the scenes before it is handed off to the hardware. This
can lead to silly situations where 32-bit float samples from the user
are (lossily) converted to 16-bit by PortAudio, then ended off to
Windows via DirectSound, only to be converted back to 32-bit float
again, before finally being converted to the format the hardware device
is configured to use. This can easily lead to two layers of
16-bit dithering (one from PortAudio, and one from Windows) being piled
on top of each other, resulting in an elevated noise floor.

This commit fixes this problem by configuring the DirectSound buffers to
use the same format as the user buffer. This should stop PortAudio from
converting samples in all cases except paInt8, which is not supported by
WAVEFORMATEX (only paUInt8 is).

The new code assumes that DirectSound will accept whatever format we
throw at it. I feel confident that this is always true on Vista+
regardless of hardware, because starting from Vista DirectSound does not
access hardware directly - it always goes through the Windows Audio
Engine which supports all formats in both directions (I verified this
using paloopback).

The consequences of this change on pre-Vista Windows are less clear,
although [1] suggests that this might just work even on 2000/XP as
KMixer should be able to handle these conversions as well.

[1]: https://microsoft.public.win32.programmer.directx.audio.narkive.com/elgNlPIn/

Fixes PortAudio#54
  • Loading branch information
dechamps committed Feb 25, 2023
1 parent d07842c commit 00fd54a
Showing 1 changed file with 4 additions and 10 deletions.
14 changes: 4 additions & 10 deletions src/hostapi/dsound/pa_win_ds.c
Original file line number Diff line number Diff line change
Expand Up @@ -2045,15 +2045,13 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,

PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );

/* These are all the formats that can be represented in WAVEFORMATEX */
const PaSampleFormat nativeFormats = paUInt8 | paInt16 | paInt24 | paInt32 | paFloat32;

if( inputParameters )
{
/* IMPLEMENT ME - establish which host formats are available */
PaSampleFormat nativeInputFormats = paInt16;
/* PaSampleFormat nativeFormats = paUInt8 | paInt16 | paInt24 | paInt32 | paFloat32; */

hostInputSampleFormat =
PaUtil_SelectClosestAvailableFormat( nativeInputFormats, inputParameters->sampleFormat );
PaUtil_SelectClosestAvailableFormat( nativeFormats, inputParameters->sampleFormat );
}
else
{
Expand All @@ -2062,12 +2060,8 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,

if( outputParameters )
{
/* IMPLEMENT ME - establish which host formats are available */
PaSampleFormat nativeOutputFormats = paInt16;
/* PaSampleFormat nativeOutputFormats = paUInt8 | paInt16 | paInt24 | paInt32 | paFloat32; */

hostOutputSampleFormat =
PaUtil_SelectClosestAvailableFormat( nativeOutputFormats, outputParameters->sampleFormat );
PaUtil_SelectClosestAvailableFormat( nativeFormats, outputParameters->sampleFormat );
}
else
{
Expand Down

0 comments on commit 00fd54a

Please sign in to comment.