[PATCH] dsound: Use a 2 stage mixing/normalization for sound

Maarten Lankhorst maarten at codeweavers.com
Sat Oct 13 13:15:40 CDT 2007


---
 dlls/dsound/dsound.c         |    5 +-
 dlls/dsound/dsound_private.h |    9 ++-
 dlls/dsound/mixer.c          |  109 +++++++++++++++--------------------------
 dlls/dsound/primary.c        |   21 ++++++++-
 4 files changed, 69 insertions(+), 75 deletions(-)

diff --git a/dlls/dsound/dsound.c b/dlls/dsound/dsound.c
index ed6c221..8368457 100644
--- a/dlls/dsound/dsound.c
+++ b/dlls/dsound/dsound.c
@@ -1271,8 +1271,9 @@ ULONG DirectSoundDevice_Release(DirectSoundDevice * device)
 
         DSOUND_renderer[device->drvdesc.dnDevNode] = NULL;
 
-        HeapFree(GetProcessHeap(),0,device->tmp_buffer);
-        HeapFree(GetProcessHeap(),0,device->buffer);
+        HeapFree(GetProcessHeap(), 0, device->tmp_buffer);
+        HeapFree(GetProcessHeap(), 0, device->mix_buffer);
+        HeapFree(GetProcessHeap(), 0, device->buffer);
         RtlDeleteResource(&device->buffer_list_lock);
         device->mixlock.DebugInfo->Spare[0] = 0;
         DeleteCriticalSection(&device->mixlock);
diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h
index 339877e..a5e3ddd 100644
--- a/dlls/dsound/dsound_private.h
+++ b/dlls/dsound/dsound_private.h
@@ -104,8 +104,11 @@ struct DirectSoundDevice
     PrimaryBufferImpl*          primary;
     DSBUFFERDESC                dsbd;
     DWORD                       speaker_config;
-    LPBYTE                      tmp_buffer;
-    DWORD                       tmp_buffer_len;
+    LPBYTE                      tmp_buffer, mix_buffer;
+    DWORD                       tmp_buffer_len, mix_buffer_len;
+
+    mixfunc mixfunction;
+    normfunc normfunction;
 
     /* DirectSound3DListener fields */
     IDirectSound3DListenerImpl*	listener;
@@ -441,7 +444,7 @@ HRESULT DSOUND_ReopenDevice(DirectSoundDevice *device, BOOL forcewave);
 HRESULT DSOUND_FullDuplexCreate(REFIID riid, LPDIRECTSOUNDFULLDUPLEX* ppDSFD);
 
 /* mixer.c */
-
+DWORD DSOUND_bufpos_to_mixpos(const DirectSoundDevice* device, DWORD pos);
 void DSOUND_CheckEvent(const IDirectSoundBufferImpl *dsb, DWORD playpos, int len);
 void DSOUND_RecalcVolPan(PDSVOLUMEPAN volpan);
 void DSOUND_AmpFactorToVolPan(PDSVOLUMEPAN volpan);
diff --git a/dlls/dsound/mixer.c b/dlls/dsound/mixer.c
index 975bffd..77bc6ad 100644
--- a/dlls/dsound/mixer.c
+++ b/dlls/dsound/mixer.c
@@ -90,6 +90,19 @@ void DSOUND_AmpFactorToVolPan(PDSVOLUMEPAN volpan)
     TRACE("Vol=%d Pan=%d\n", volpan->lVolume, volpan->lPan);
 }
 
+/** Convert a primary buffer position to a pointer position for device->mix_buffer
+ * device: DirectSoundDevice for which to calculate
+ * pos: Primary buffer position to converts
+ * Returns: Offset for mix_buffer
+ */
+DWORD DSOUND_bufpos_to_mixpos(const DirectSoundDevice* device, DWORD pos)
+{
+    DWORD ret = pos * 32 / device->pwfx->wBitsPerSample;
+    if (device->pwfx->wBitsPerSample == 32)
+        ret *= 2;
+    return ret;
+}
+
 /* NOTE: Not all secpos have to always be mapped to a bufpos, other way around is always the case
  * DWORD64 is used here because a single DWORD wouldn't be big enough to fit the freqAcc for big buffers
  */
@@ -466,9 +479,9 @@ static LPBYTE DSOUND_MixerVol(const IDirectSoundBufferImpl *dsb, DWORD writepos,
  */
 static DWORD DSOUND_MixInBuffer(IDirectSoundBufferImpl *dsb, DWORD writepos, DWORD fraglen)
 {
-	INT i, len = fraglen, field, todo, ilen;
+	INT len = fraglen, ilen;
 	BYTE *ibuf = (dsb->tmp_buffer ? dsb->tmp_buffer : dsb->buffer->memory) + dsb->buf_mixpos, *volbuf;
-	DWORD oldpos;
+	DWORD oldpos, mixbufpos;
 
 	TRACE("buf_mixpos=%d/%d sec_mixpos=%d/%d\n", dsb->buf_mixpos, dsb->tmp_buffer_len, dsb->sec_mixpos, dsb->buflen);
 	TRACE("(%p,%d,%d)\n",dsb,writepos,fraglen);
@@ -486,82 +499,26 @@ static DWORD DSOUND_MixInBuffer(IDirectSoundBufferImpl *dsb, DWORD writepos, DWO
 	if (volbuf)
 		ibuf = volbuf;
 
+	mixbufpos = DSOUND_bufpos_to_mixpos(dsb->device, writepos);
 	/* Now mix the temporary buffer into the devices main buffer */
-	if (dsb->device->pwfx->wBitsPerSample == 8) {
-		BYTE	*obuf = dsb->device->buffer + writepos;
-
-		if ((writepos + len) <= dsb->device->buflen)
-			todo = len;
-		else
-			todo = dsb->device->buflen - writepos;
-
-		for (i = 0; i < todo; i++) {
-			/* 8-bit WAV is unsigned */
-			field = (*ibuf++ - 128);
-			field += (*obuf - 128);
-			if (field > 127) field = 127;
-			else if (field < -128) field = -128;
-			*obuf++ = field + 128;
-		}
- 
-		if (todo < len) {
-			todo = len - todo;
-			obuf = dsb->device->buffer;
-
-			for (i = 0; i < todo; i++) {
-				/* 8-bit WAV is unsigned */
-				field = (*ibuf++ - 128);
-				field += (*obuf - 128);
-				if (field > 127) field = 127;
-				else if (field < -128) field = -128;
-				*obuf++ = field + 128;
-			}
-		}
-	} else {
-		INT16	*ibufs, *obufs;
-
-		ibufs = (INT16 *) ibuf;
-		obufs = (INT16 *)(dsb->device->buffer + writepos);
-
-		if ((writepos + len) <= dsb->device->buflen)
-			todo = len / 2;
-		else
-			todo = (dsb->device->buflen - writepos) / 2;
-
-		for (i = 0; i < todo; i++) {
-			/* 16-bit WAV is signed */
-			field = *ibufs++;
-
-			field += *obufs;
-			if (field > 32767) field = 32767;
-			else if (field < -32768) field = -32768;
-			*obufs++ = field;
-		}
-
-		if (todo < (len / 2)) {
-			todo = (len / 2) - todo;
-			obufs = (INT16 *)dsb->device->buffer;
-
-			for (i = 0; i < todo; i++) {
-				/* 16-bit WAV is signed */
-				field = *ibufs++;
-				field += *obufs;
-				if (field > 32767) field = 32767;
-				else if (field < -32768) field = -32768;
-				*obufs++ = field;
-			}
-		}
+	if ((writepos + len) <= dsb->device->buflen)
+		dsb->device->mixfunction(ibuf, dsb->device->mix_buffer + mixbufpos, len);
+	else
+	{
+		DWORD todo = dsb->device->buflen - writepos;
+		dsb->device->mixfunction(ibuf, dsb->device->mix_buffer + mixbufpos, todo);
+		dsb->device->mixfunction(ibuf + todo, dsb->device->mix_buffer, len - todo);
 	}
 
 	oldpos = dsb->sec_mixpos;
 	dsb->buf_mixpos += len;
 
 	if (dsb->buf_mixpos >= dsb->tmp_buffer_len) {
+		if (dsb->buf_mixpos > dsb->tmp_buffer_len)
+			ERR("Mixpos (%u) past buflen (%u), capping...\n", dsb->buf_mixpos, dsb->tmp_buffer_len);
 		if (dsb->playflags & DSBPLAY_LOOPING) {
 			dsb->buf_mixpos -= dsb->tmp_buffer_len;
 		} else if (dsb->buf_mixpos >= dsb->tmp_buffer_len) {
-			if (dsb->buf_mixpos > dsb->tmp_buffer_len)
-				ERR("Mixpos (%u) past buflen (%u), capping...\n", dsb->buf_mixpos, dsb->tmp_buffer_len);
 			dsb->buf_mixpos = dsb->sec_mixpos = 0;
 			dsb->state = STATE_STOPPED;
 		}
@@ -817,7 +774,7 @@ static void DSOUND_PerformMix(DirectSoundDevice *device)
 
 	if (device->priolevel != DSSCL_WRITEPRIMARY) {
 		BOOL recover = FALSE, all_stopped = FALSE;
-		DWORD playpos, writepos, writelead, maxq, frag, prebuff_max, prebuff_left, size1, size2;
+		DWORD playpos, writepos, writelead, maxq, frag, prebuff_max, prebuff_left, size1, size2, mixplaypos, mixplaypos2;
 		LPVOID buf1, buf2;
 		BOOL lock = (device->hwbuf && !(device->drvdesc.dwFlags & DSDDESC_DONTNEEDPRIMARYLOCK));
 		BOOL mustlock = FALSE;
@@ -836,12 +793,16 @@ static void DSOUND_PerformMix(DirectSoundDevice *device)
 		      playpos,writepos,device->playpos,device->mixpos,device->buflen);
 		assert(device->playpos < device->buflen);
 
+		mixplaypos = DSOUND_bufpos_to_mixpos(device, device->playpos);
+		mixplaypos2 = DSOUND_bufpos_to_mixpos(device, playpos);
 		/* wipe out just-played sound data */
 		if (playpos < device->playpos) {
 			buf1 = device->buffer + device->playpos;
 			buf2 = device->buffer;
 			size1 = device->buflen - device->playpos;
 			size2 = playpos;
+			FillMemory(device->mix_buffer + mixplaypos, device->mix_buffer_len - mixplaypos, 0);
+			FillMemory(device->mix_buffer, mixplaypos2, 0);
 			if (lock)
 				IDsDriverBuffer_Lock(device->hwbuf, &buf1, &size1, &buf2, &size2, device->playpos, size1+size2, 0);
 			FillMemory(buf1, size1, nfiller);
@@ -855,6 +816,7 @@ static void DSOUND_PerformMix(DirectSoundDevice *device)
 			buf2 = NULL;
 			size1 = playpos - device->playpos;
 			size2 = 0;
+			FillMemory(device->mix_buffer + mixplaypos, mixplaypos2 - mixplaypos, 0);
 			if (lock)
 				IDsDriverBuffer_Lock(device->hwbuf, &buf1, &size1, &buf2, &size2, device->playpos, size1+size2, 0);
 			FillMemory(buf1, size1, nfiller);
@@ -906,6 +868,15 @@ static void DSOUND_PerformMix(DirectSoundDevice *device)
 		/* do the mixing */
 		frag = DSOUND_MixToPrimary(device, writepos, maxq, mustlock, recover, &all_stopped);
 
+		if (frag + writepos > device->buflen)
+		{
+			DWORD todo = device->buflen - writepos;
+			device->normfunction(device->mix_buffer + DSOUND_bufpos_to_mixpos(device, writepos), device->buffer + writepos, todo);
+			device->normfunction(device->mix_buffer, device->buffer, frag - todo);
+		}
+		else
+			device->normfunction(device->mix_buffer + DSOUND_bufpos_to_mixpos(device, writepos), device->buffer + writepos, frag);
+
 		/* update the mix position, taking wrap-around into acount */
 		device->mixpos = writepos + frag;
 		device->mixpos %= device->buflen;
diff --git a/dlls/dsound/primary.c b/dlls/dsound/primary.c
index 57facf8..eec681c 100644
--- a/dlls/dsound/primary.c
+++ b/dlls/dsound/primary.c
@@ -188,6 +188,16 @@ static HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device)
 			device->prebuf = device->helfrags;
 	}
 
+	device->mix_buffer_len = DSOUND_bufpos_to_mixpos(device, device->buflen);
+	device->mix_buffer = HeapAlloc(GetProcessHeap(), 0, device->mix_buffer_len);
+	if (!device->mix_buffer)
+	{
+		if (device->hwbuf)
+			IDsDriverBuffer_Release(device->hwbuf);
+		device->hwbuf = NULL;
+		return DSERR_OUTOFMEMORY;
+	}
+
 	if (device->state == STATE_PLAYING) device->state = STATE_STARTING;
 	else if (device->state == STATE_STOPPING) device->state = STATE_STOPPED;
 
@@ -256,7 +266,10 @@ static HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device)
 
 		TRACE("fraglen=%d, overshot=%d\n", device->fraglen, overshot);
 	}
+	device->mixfunction = mixfunctions[device->pwfx->wBitsPerSample/8 - 1];
+	device->normfunction = normfunctions[device->pwfx->wBitsPerSample/8 - 1];
 	FillMemory(device->buffer, device->buflen, (device->pwfx->wBitsPerSample == 8) ? 128 : 0);
+	FillMemory(device->mix_buffer, device->mix_buffer_len, 0);
 	device->pwplay = device->pwqueue = device->playpos = device->mixpos = 0;
 	return err;
 }
@@ -443,7 +456,7 @@ HRESULT DSOUND_PrimarySetFormat(DirectSoundDevice *device, LPCWAVEFORMATEX wfex,
 	RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
 	EnterCriticalSection(&(device->mixlock));
 
-	if (wfex->wFormatTag == WAVE_FORMAT_PCM) {
+        if (wfex->wFormatTag == WAVE_FORMAT_PCM) {
             alloc_size = sizeof(WAVEFORMATEX);
             cp_size = sizeof(PCMWAVEFORMAT);
         } else
@@ -520,6 +533,12 @@ HRESULT DSOUND_PrimarySetFormat(DirectSoundDevice *device, LPCWAVEFORMATEX wfex,
 		}
 	}
 
+	device->mix_buffer_len = DSOUND_bufpos_to_mixpos(device, device->buflen);
+	device->mix_buffer = HeapReAlloc(GetProcessHeap(), 0, device->mix_buffer, device->mix_buffer_len);
+	FillMemory(device->mix_buffer, device->mix_buffer_len, 0);
+	device->mixfunction = mixfunctions[device->pwfx->wBitsPerSample/8 - 1];
+	device->normfunction = normfunctions[device->pwfx->wBitsPerSample/8 - 1];
+
 	if (nSamplesPerSec != device->pwfx->nSamplesPerSec || bpp != device->pwfx->wBitsPerSample || chans != device->pwfx->nChannels) {
 		IDirectSoundBufferImpl** dsb = device->buffers;
 		for (i = 0; i < device->nrofbuffers; i++, dsb++) {
-- 
1.5.2.5


--------------060204080307040402050504--



More information about the wine-patches mailing list