dsound: Add support for adjusting volume of more than 2 channels

Donny Yang xiao.tai.lang.de.email at gmail.com
Fri Jul 13 02:59:03 CDT 2012


This was tested under wine 1.5.8 with Ubuntu 12.04 using both winealsa
and winepulse with 7.1 output channels and 1.0, 2.0, 5.1 and 7.1 file
input channels using foobar2000.
-------------- next part --------------
From 7c4bfbc6da0bdb7f2ced78b7b9bdd5796e8a0a4e Mon Sep 17 00:00:00 2001
From: Donny Yang <xiao.tai.lang.de.email at gmail.com>
Date: Fri, 13 Jul 2012 17:14:38 +1000
Subject: dsound: Add support for adjusting volume of more than 2 channels

---
 dlls/dsound/mixer.c |   41 +++++++++++++++++++++++++++++++++++------
 1 file changed, 35 insertions(+), 6 deletions(-)

diff --git a/dlls/dsound/mixer.c b/dlls/dsound/mixer.c
index 547c666..7d0dfa7 100644
--- a/dlls/dsound/mixer.c
+++ b/dlls/dsound/mixer.c
@@ -42,6 +42,11 @@
 #include "dsound_private.h"
 #include "fir.h"
 
+#define SPEAKERS_LEFT_MASK (SPEAKER_FRONT_LEFT | SPEAKER_BACK_LEFT | SPEAKER_FRONT_LEFT_OF_CENTER | \
+	SPEAKER_SIDE_LEFT | SPEAKER_TOP_FRONT_LEFT | SPEAKER_TOP_BACK_LEFT)
+#define SPEAKERS_RIGHT_MASK (SPEAKER_FRONT_RIGHT | SPEAKER_BACK_RIGHT | SPEAKER_FRONT_RIGHT_OF_CENTER | \
+	SPEAKER_SIDE_RIGHT | SPEAKER_TOP_FRONT_RIGHT | SPEAKER_TOP_BACK_RIGHT)
+
 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
 
 void DSOUND_RecalcVolPan(PDSVOLUMEPAN volpan)
@@ -379,11 +384,26 @@ static void DSOUND_MixToTemporary(IDirectSoundBufferImpl *dsb, DWORD frames)
 	cp_fields(dsb, frames, &dsb->freqAcc);
 }
 
+static DWORD channel_number_to_speaker_position(DWORD channel, DWORD channelMask)
+{
+	DWORD result = 1;
+	while(channel > 0 && channelMask != 0){
+		channelMask >>= 1;
+		result <<= 1;
+		if(channelMask & 1)
+			--channel;
+	}
+	if (channelMask == 0 && channel != 0)
+		return 0;
+	return result;
+}
+
 static void DSOUND_MixerVol(const IDirectSoundBufferImpl *dsb, INT frames)
 {
 	INT	i;
-	float vLeft, vRight;
+	float vLeft, vRight, vCenter;
 	UINT channels = dsb->device->pwfx->nChannels, chan;
+	DWORD channelMask, speaker;
 
 	TRACE("(%p,%d)\n",dsb,frames);
 	TRACE("left = %x, right = %x\n", dsb->volpan.dwTotalLeftAmpFactor,
@@ -394,20 +414,29 @@ static void DSOUND_MixerVol(const IDirectSoundBufferImpl *dsb, INT frames)
 	     !(dsb->dsbd.dwFlags & DSBCAPS_CTRL3D))
 		return; /* Nothing to do */
 
-	if (channels != 1 && channels != 2)
-	{
-		FIXME("There is no support for %u channels\n", channels);
+	if (dsb->device->pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
+		channelMask = ((WAVEFORMATEXTENSIBLE*)dsb->device->pwfx)->dwChannelMask;
+	else if (channels == 1)
+		channelMask = SPEAKER_FRONT_CENTER;
+	else if (channels == 2)
+		channelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
+	else {
+		FIXME("There is no support for %u channels without an extensible wave format\n", channels);
 		return;
 	}
 
 	vLeft = dsb->volpan.dwTotalLeftAmpFactor / ((float)0xFFFF);
 	vRight = dsb->volpan.dwTotalRightAmpFactor / ((float)0xFFFF);
+	vCenter = (vLeft + vRight) / 2.0;
 	for(i = 0; i < frames; ++i){
 		for(chan = 0; chan < channels; ++chan){
-			if(chan == 0)
+			speaker = channel_number_to_speaker_position(chan, channelMask);
+			if(speaker & SPEAKERS_LEFT_MASK)
 				dsb->device->tmp_buffer[i * channels + chan] *= vLeft;
-			else
+			else if(speaker & SPEAKERS_RIGHT_MASK)
 				dsb->device->tmp_buffer[i * channels + chan] *= vRight;
+			else
+				dsb->device->tmp_buffer[i * channels + chan] *= vCenter;
 		}
 	}
 }
-- 
1.7.9.5


More information about the wine-patches mailing list