[PATCH 0/2] MR11154: dsound: Add conversions to 7.1 audio.
Found with Portal 2. In settings you can set it to 2 speakers, 4 speakers or 5.1 audio. 7.1 setups are popular with home cinema and soundbars. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11154
From: Lakulish Antani <lakulisha@valvesoftware.com> If the system's PulseAudio sink is (say) 7.1, and the game has configured the DirectSound buffer to be (say) 5.1, then the format conversion code just copies the first 2 channels of the game's buffer to the first 2 channels of the PulseAudio buffer, leaving the remaining 6 channels of the PulseAudio buffer untouched. This can result in garbage/noise in the output. This change adds explicit handling for quad -> 7.1 and 5.1 -> 7.1 conversion. --- dlls/dsound/dsound_convert.c | 38 ++++++++++++++++++++++++++++++++++++ dlls/dsound/dsound_private.h | 2 ++ dlls/dsound/mixer.c | 10 ++++++++++ 3 files changed, 50 insertions(+) diff --git a/dlls/dsound/dsound_convert.c b/dlls/dsound/dsound_convert.c index bdd62c8e51f..4cd21f628e9 100644 --- a/dlls/dsound/dsound_convert.c +++ b/dlls/dsound/dsound_convert.c @@ -210,6 +210,44 @@ void put_stereo2surround51(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD c } } +void put_quad2surround71(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value) +{ + if (channel == 0) { /* Front left */ + dsb->put_aux(dsb, pos, 0, value); /* Front left */ + + dsb->put_aux(dsb, pos, 2, 0.0f); /* Mute front center */ + dsb->put_aux(dsb, pos, 3, 0.0f); /* Mute LFE */ + dsb->put_aux(dsb, pos, 6, 0.0f); /* Mute side left */ + dsb->put_aux(dsb, pos, 7, 0.0f); /* Mute side right */ + } else if (channel == 1) { /* Front right */ + dsb->put_aux(dsb, pos, 1, value); /* Front right */ + } else if (channel == 2) { /* Rear left */ + dsb->put_aux(dsb, pos, 4, value); /* Rear left */ + } else if (channel == 3) { /* Rear right */ + dsb->put_aux(dsb, pos, 5, value); /* Rear right */ + } +} + +void put_surround512surround71(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value) +{ + if (channel == 0) { /* Front left */ + dsb->put_aux(dsb, pos, 0, value); /* Front left */ + + dsb->put_aux(dsb, pos, 6, 0.0f); /* Mute side left */ + dsb->put_aux(dsb, pos, 7, 0.0f); /* Mute side right */ + } else if (channel == 1) { /* Front right */ + dsb->put_aux(dsb, pos, 1, value); /* Front right */ + } else if (channel == 2) { /* Front center */ + dsb->put_aux(dsb, pos, 2, value); /* Front center */ + } else if (channel == 3) { /* LFE */ + dsb->put_aux(dsb, pos, 3, value); /* LFE */ + } else if (channel == 4) { /* Rear left */ + dsb->put_aux(dsb, pos, 4, value); /* Rear left */ + } else if (channel == 5) { /* Rear right */ + dsb->put_aux(dsb, pos, 5, value); /* Rear right */ + } +} + void put_surround512stereo(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value) { /* based on analyzing a recording of a dsound downmix */ diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h index 7e6768a21a8..2b3aa9a9d25 100644 --- a/dlls/dsound/dsound_private.h +++ b/dlls/dsound/dsound_private.h @@ -182,6 +182,8 @@ void put_stereo2surround51(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD c void put_surround512stereo(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value); void put_surround712stereo(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value); void put_quad2stereo(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value); +void put_quad2surround71(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value); +void put_surround512surround71(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value); HRESULT secondarybuffer_create(DirectSoundDevice *device, const DSBUFFERDESC *dsbd, IDirectSoundBuffer **buffer); diff --git a/dlls/dsound/mixer.c b/dlls/dsound/mixer.c index 3b7715e0c69..c37011752b0 100644 --- a/dlls/dsound/mixer.c +++ b/dlls/dsound/mixer.c @@ -195,6 +195,16 @@ void DSOUND_RecalcFormat(IDirectSoundBufferImpl *dsb) dsb->put = put_quad2stereo; dsb->put_aux = putieee32_sum; } + else if (ichannels == 4 && ochannels == 8) + { + dsb->mix_channels = 4; + dsb->put = put_quad2surround71; + } + else if (ichannels == 6 && ochannels == 8) + { + dsb->mix_channels = 6; + dsb->put = put_surround512surround71; + } else { if (ichannels > 2) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11154
From: Arkadiusz Hiler <ahiler@codeweavers.com> --- dlls/dsound/dsound_convert.c | 28 ++++++++++++++++++++++++++++ dlls/dsound/dsound_private.h | 2 ++ dlls/dsound/mixer.c | 10 ++++++++++ 3 files changed, 40 insertions(+) diff --git a/dlls/dsound/dsound_convert.c b/dlls/dsound/dsound_convert.c index 4cd21f628e9..d494afc4441 100644 --- a/dlls/dsound/dsound_convert.c +++ b/dlls/dsound/dsound_convert.c @@ -210,6 +210,34 @@ void put_stereo2surround51(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD c } } +void put_mono2surround71(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value) +{ + dsb->put_aux(dsb, pos, 0, value); + dsb->put_aux(dsb, pos, 1, value); + dsb->put_aux(dsb, pos, 2, value); + dsb->put_aux(dsb, pos, 3, value); + dsb->put_aux(dsb, pos, 4, value); + dsb->put_aux(dsb, pos, 5, value); + dsb->put_aux(dsb, pos, 6, value); + dsb->put_aux(dsb, pos, 7, value); +} + +void put_stereo2surround71(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value) +{ + if (channel == 0) { /* Left */ + dsb->put_aux(dsb, pos, 0, value); /* Front left */ + dsb->put_aux(dsb, pos, 4, value); /* Back left */ + dsb->put_aux(dsb, pos, 6, value); /* Side left */ + + dsb->put_aux(dsb, pos, 2, 0.0f); /* Mute front centre */ + dsb->put_aux(dsb, pos, 3, 0.0f); /* Mute LFE */ + } else if (channel == 1) { /* Right */ + dsb->put_aux(dsb, pos, 1, value); /* Front right */ + dsb->put_aux(dsb, pos, 5, value); /* Back right */ + dsb->put_aux(dsb, pos, 7, value); /* Side right */ + } +} + void put_quad2surround71(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value) { if (channel == 0) { /* Front left */ diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h index 2b3aa9a9d25..3b4806a487b 100644 --- a/dlls/dsound/dsound_private.h +++ b/dlls/dsound/dsound_private.h @@ -182,6 +182,8 @@ void put_stereo2surround51(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD c void put_surround512stereo(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value); void put_surround712stereo(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value); void put_quad2stereo(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value); +void put_stereo2surround71(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value); +void put_mono2surround71(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value); void put_quad2surround71(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value); void put_surround512surround71(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value); diff --git a/dlls/dsound/mixer.c b/dlls/dsound/mixer.c index c37011752b0..2ab7a88233f 100644 --- a/dlls/dsound/mixer.c +++ b/dlls/dsound/mixer.c @@ -195,6 +195,16 @@ void DSOUND_RecalcFormat(IDirectSoundBufferImpl *dsb) dsb->put = put_quad2stereo; dsb->put_aux = putieee32_sum; } + else if (ichannels == 1 && ochannels == 8) + { + dsb->mix_channels = 1; + dsb->put = put_mono2surround71; + } + else if (ichannels == 2 && ochannels == 8) + { + dsb->mix_channels = 2; + dsb->put = put_stereo2surround71; + } else if (ichannels == 4 && ochannels == 8) { dsb->mix_channels = 4; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11154
This merge request was approved by Arek Hiler. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11154
Matteo Bruni (@Mystral) commented about dlls/dsound/dsound_convert.c:
} }
+void put_quad2surround71(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value) +{ + if (channel == 0) { /* Front left */ + dsb->put_aux(dsb, pos, 0, value); /* Front left */ + + dsb->put_aux(dsb, pos, 2, 0.0f); /* Mute front center */ + dsb->put_aux(dsb, pos, 3, 0.0f); /* Mute LFE */ + dsb->put_aux(dsb, pos, 6, 0.0f); /* Mute side left */ + dsb->put_aux(dsb, pos, 7, 0.0f); /* Mute side right */
This and the next conversion mute the side speakers, while the two in the next patch replicate the front speakers into them. I think we should be consistent one way or another unless there is a good reason not to. Ideally this should be checked on Windows, or at least it should replicate what pipewire / pulseaudio / ffmpeg / some other commonly used sound demuxer does. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11154#note_143221
Matteo Bruni (@Mystral) commented about dlls/dsound/dsound_convert.c:
} }
+void put_mono2surround71(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value) +{ + dsb->put_aux(dsb, pos, 0, value); + dsb->put_aux(dsb, pos, 1, value); + dsb->put_aux(dsb, pos, 2, value); + dsb->put_aux(dsb, pos, 3, value);
Should this keep the LFE muted? I realize the existing "mono2*" conversions do the same, but it seems suspicious nonetheless. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11154#note_143222
On Tue Jun 16 10:38:58 2026 +0000, Matteo Bruni wrote:
This and the next conversion mute the side speakers, while the two in the next patch replicate the front speakers into them. I think we should be consistent one way or another unless there is a good reason not to. Ideally this should be checked on Windows, or at least it should replicate what pipewire / pulseaudio / ffmpeg / some other commonly used sound demuxer does. The difference between this and the other patch is that here you have actual front and rear speakers. Using any of them for the side channels would require a blend at best, so keeping them muted just downgrades you to a quad or 5.1 setup.
The next patch uses front speakers as you only have a single channel to replicate across the left and right sides. Everything remains stereo or mono. I'll check what dsound produces on Windows and if my intuition here is correct. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11154#note_143225
On Tue Jun 16 10:38:38 2026 +0000, Matteo Bruni wrote:
Should this keep the LFE muted? I realize the existing "mono2*" conversions do the same, but it seems suspicious nonetheless. Hah, I remember thinking about it at some point and then just forgot and went with what the existing code was doing.
I'll check things and possibly fix it including the existing conversions. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11154#note_143226
participants (4)
-
Arek Hiler (@ivyl) -
Arkadiusz Hiler -
Lakulish Antani -
Matteo Bruni (@Mystral)