[PATCH 4/4] dsound: Clean up channels

Alexander E. Patrakov patrakov at gmail.com
Tue May 1 10:46:11 CDT 2012


The infrastructure set up in the "Replace convert() functions with
get() and put()" also allows to convert the number of channels more
elegantly. See how much deeply-nested code and complex conditions was
removed from cp_fields() :)

The old code supported (secondary -> primary):
n -> n
6 -> 2
2 -> 8 (hack, first 2 only)
2 -> 6 (hack, first 2 only)
2 -> 1
1 -> 2
silence (catchall)

While the new code supports:
n -> n
1 -> 2
n -> 1
n -> m (catchall, hack, first 2 only)

-- 
Alexander E. Patrakov

-------------- next part --------------
>From b421c12f35a1374b13275cec53be0467e52515e1 Mon Sep 17 00:00:00 2001
From: "Alexander E. Patrakov" <patrakov at gmail.com>
Date: Mon, 12 Dec 2011 14:07:49 -0600
Subject: [PATCH 4/7] dsound: Clean up channels

---
 dlls/dsound/dsound_convert.c |   18 ++++++++++
 dlls/dsound/dsound_private.h |    8 +++-
 dlls/dsound/mixer.c          |   77 +++++++++++++++++++-----------------------
 3 files changed, 59 insertions(+), 44 deletions(-)

diff --git a/dlls/dsound/dsound_convert.c b/dlls/dsound/dsound_convert.c
index b670c04..63f1eb0 100644
--- a/dlls/dsound/dsound_convert.c
+++ b/dlls/dsound/dsound_convert.c
@@ -104,6 +104,18 @@ static float getieee32(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD chann
 
 const bitsgetfunc getbpp[5] = {get8, get16, get24, get32, getieee32};
 
+float get_mono(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel)
+{
+    DWORD channels = dsb->pwfx->nChannels;
+    DWORD c;
+    float val = 0;
+    /* XXX: does Windows include LFE into the mix? */
+    for (c = 0; c < channels; c++)
+        val += dsb->get_aux(dsb, pos, c);
+    val /= channels;
+    return val;
+}
+
 static void put8(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value)
 {
     BYTE* buf = dsb->device->tmp_buffer;
@@ -158,6 +170,12 @@ static void put32(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, f
 
 const bitsputfunc putbpp[4] = {put8, put16, put24, put32};
 
+void put_mono2stereo(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value)
+{
+    dsb->put_aux(dsb, pos, 0, value);
+    dsb->put_aux(dsb, pos, 1, value);
+}
+
 static void mix8(signed char *src, INT *dst, unsigned len)
 {
     TRACE("%p - %p %d\n", src, dst, len);
diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h
index 9f30bff..5d1d62a 100644
--- a/dlls/dsound/dsound_private.h
+++ b/dlls/dsound/dsound_private.h
@@ -193,12 +193,16 @@ struct IDirectSoundBufferImpl
     LONG                        ds3db_lVolume;
     BOOL                        ds3db_need_recalc;
     /* Used for bit depth conversion */
-    bitsgetfunc get;
-    bitsputfunc put;
+    int                         mix_channels;
+    bitsgetfunc get, get_aux;
+    bitsputfunc put, put_aux;
 
     struct list entry;
 };
 
+float get_mono(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel) DECLSPEC_HIDDEN;
+void put_mono2stereo(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value) DECLSPEC_HIDDEN;
+
 HRESULT IDirectSoundBufferImpl_Create(
     DirectSoundDevice *device,
     IDirectSoundBufferImpl **ppdsb,
diff --git a/dlls/dsound/mixer.c b/dlls/dsound/mixer.c
index 4f73831..5fa15b2 100644
--- a/dlls/dsound/mixer.c
+++ b/dlls/dsound/mixer.c
@@ -178,6 +178,8 @@ static void DSOUND_RecalcFreqAcc(IDirectSoundBufferImpl *dsb)
  */
 void DSOUND_RecalcFormat(IDirectSoundBufferImpl *dsb)
 {
+	DWORD ichannels = dsb->pwfx->nChannels;
+	DWORD ochannels = dsb->device->pwfx->nChannels;
 	BOOL needremix = TRUE, needresample = (dsb->freq != dsb->device->pwfx->nSamplesPerSec);
 	DWORD bAlign = dsb->pwfx->nBlockAlign, pAlign = dsb->device->pwfx->nBlockAlign;
 	WAVEFORMATEXTENSIBLE *pwfxe;
@@ -200,8 +202,36 @@ void DSOUND_RecalcFormat(IDirectSoundBufferImpl *dsb)
 	dsb->freqAcc = dsb->freqAccNext = 0;
 	dsb->freqneeded = needresample;
 
-	dsb->get = ieee ? getbpp[4] : getbpp[dsb->pwfx->wBitsPerSample/8 - 1];
-	dsb->put = putbpp[dsb->device->pwfx->wBitsPerSample/8 - 1];
+	dsb->get_aux = ieee ? getbpp[4] : getbpp[dsb->pwfx->wBitsPerSample/8 - 1];
+	dsb->put_aux = putbpp[dsb->device->pwfx->wBitsPerSample/8 - 1];
+
+	dsb->get = dsb->get_aux;
+	dsb->put = dsb->put_aux;
+
+	if (ichannels == ochannels)
+	{
+		dsb->mix_channels = ichannels;
+		if (ichannels > 32) {
+			FIXME("Copying %u channels is unsupported, limiting to first 32\n", ichannels);
+			dsb->mix_channels = 32;
+		}
+	}
+	else if (ichannels == 1)
+	{
+		dsb->mix_channels = 1;
+		dsb->put = put_mono2stereo;
+	}
+	else if (ochannels == 1)
+	{
+		dsb->mix_channels = 1;
+		dsb->get = get_mono;
+	}
+	else
+	{
+		if (ichannels > 2)
+			FIXME("Conversion from %u to %u channels is not implemented, falling back to stereo\n", ichannels, ochannels);
+		dsb->mix_channels = 2;
+	}
 
 	if (needremix)
 	{
@@ -278,38 +308,13 @@ static inline void cp_fields(const IDirectSoundBufferImpl *dsb,
     DWORD ipos = dsb->sec_mixpos;
     UINT istride = dsb->pwfx->nBlockAlign;
     UINT adj = dsb->freqAdjust;
-    DirectSoundDevice *device = dsb->device;
-    float value;
     ULONG adv;
     DWORD opos = 0;
 
     while (count-- > 0) {
-        if (device->pwfx->nChannels == dsb->pwfx->nChannels ||
-                (device->pwfx->nChannels == 2 && dsb->pwfx->nChannels == 6) ||
-                (device->pwfx->nChannels == 8 && dsb->pwfx->nChannels == 2) ||
-                (device->pwfx->nChannels == 6 && dsb->pwfx->nChannels == 2)) {
-            value = dsb->get(dsb, ipos, 0);
-            dsb->put(dsb, opos, 0, value);
-            if (device->pwfx->nChannels == 2 || dsb->pwfx->nChannels == 2) {
-                value = dsb->get(dsb, ipos, 1);
-                dsb->put(dsb, opos, 1, value);
-            }
-        }
-
-        if (device->pwfx->nChannels == 1 && dsb->pwfx->nChannels == 2)
-        {
-            float val = (dsb->get(dsb, ipos, 0) + dsb->get(dsb, ipos, 1)) / 2.;
-
-            dsb->put(dsb, opos, 0, val);
-        }
-
-        if (device->pwfx->nChannels == 2 && dsb->pwfx->nChannels == 1)
-        {
-            value = dsb->get(dsb, ipos, 0);
-            dsb->put(dsb, opos, 0, value);
-            dsb->put(dsb, opos, 1, value);
-        }
-
+        DWORD channel;
+        for (channel = 0; channel < dsb->mix_channels; channel++)
+            dsb->put(dsb, opos, channel, dsb->get(dsb, ipos, channel));
         freqAcc += adj;
         adv = (freqAcc >> DSOUND_FREQSHIFT);
         freqAcc &= (1 << DSOUND_FREQSHIFT) - 1;
@@ -361,18 +366,6 @@ static void DSOUND_MixToTemporary(const IDirectSoundBufferImpl *dsb, DWORD tmp_l
 			dsb->device->tmp_buffer = HeapAlloc(GetProcessHeap(), 0, tmp_len);
 	}
 
-	/* Check for same sample rate */
-	if (dsb->freq == dsb->device->pwfx->nSamplesPerSec) {
-		TRACE("(%p) Same sample rate %d = primary %d\n", dsb,
-			dsb->freq, dsb->device->pwfx->nSamplesPerSec);
-
-		cp_fields(dsb, oAdvance, size, 0);
-		return;
-	}
-
-	/* Mix in different sample rates */
-	TRACE("(%p) Adjusting frequency: %d -> %d\n", dsb, dsb->freq, dsb->device->pwfx->nSamplesPerSec);
-
 	DSOUND_secpos_to_bufpos(dsb, dsb->sec_mixpos, dsb->sec_mixpos, &freqAcc);
 
 	/* FIXME: Small problem here when we're overwriting buf_mixpos, it then STILL uses old freqAcc, not sure if it matters or not */
-- 
1.7.8.6



More information about the wine-patches mailing list