dsound: Simplify mixing by removing remixing support, and fix its waveout breakage

Maarten Lankhorst m.b.lankhorst at gmail.com
Thu Jun 21 13:58:56 CDT 2007


This patch is a modified version of the original changes to dsound by
Peter Dons Tychsen.

Currently the mixer is too smart, rather then let it be smart, remove
the idea of unmixing data, rather just not write too far ahead. This
means that the mixer will require lot less cpu because it only mixes the
data once, the same idea is applied to waveout: Don't mess with mixed
data, rather queue it to waveout.
-------------- next part --------------
>From 138e65928f84bdfdc37df9c19d364d4571ac46d6 Mon Sep 17 00:00:00 2001
From: Peter Dons Tychsen and Maarten Lankhorst <m.b.lankhorst at gmail.com>
Date: Wed, 13 Jun 2007 17:05:49 +0200
Subject: [PATCH] dsound: Simplify mixing by remove remixing support and fixing waveout mixing stuff

---
 dlls/dsound/buffer.c         |  112 +++---
 dlls/dsound/dsound_main.c    |    9 +-
 dlls/dsound/dsound_private.h |   16 +-
 dlls/dsound/mixer.c          |  831 +++++++++++++++---------------------------
 dlls/dsound/primary.c        |   75 +++-
 dlls/dsound/sound3d.c        |    4 +-
 6 files changed, 412 insertions(+), 635 deletions(-)

diff --git a/dlls/dsound/buffer.c b/dlls/dsound/buffer.c
index 2437758..edc6aee 100644
--- a/dlls/dsound/buffer.c
+++ b/dlls/dsound/buffer.c
@@ -236,8 +236,7 @@ static HRESULT WINAPI IDirectSoundBufferImpl_SetVolume(
 			hres = IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan));
 	    		if (hres != DS_OK)
 		    		WARN("IDsDriverBuffer_SetVolumePan failed\n");
-		} else
-			DSOUND_ForceRemix(This);
+		}
 	}
 
 	LeaveCriticalSection(&(This->lock));
@@ -297,8 +296,6 @@ static HRESULT WINAPI IDirectSoundBufferImpl_SetFrequency(
 		This->freqAdjust = (freq << DSOUND_FREQSHIFT) / This->device->pwfx->nSamplesPerSec;
 		This->nAvgBytesPerSec = freq * This->pwfx->nBlockAlign;
 		DSOUND_RecalcFormat(This);
-		if (!This->hwbuf)
-			DSOUND_ForceRemix(This);
 	}
 
 	LeaveCriticalSection(&(This->lock));
@@ -424,29 +421,51 @@ DWORD DSOUND_CalcPlayPosition(IDirectSoundBufferImpl *This, DWORD pplay, DWORD p
 	/* we need to know how far away we are from there */
 	if (pmix < pplay) pmix += device->buflen; /* wraparound */
 	pmix -= pplay;
-	/* detect buffer underrun */
+	
+	/* detect buffer underrun (sanity) */
 	if (pwrite < pplay) pwrite += device->buflen; /* wraparound */
 	pwrite -= pplay;
 	if (pmix > (ds_snd_queue_max * device->fraglen + pwrite + device->writelead)) {
-		WARN("detected an underrun: primary queue was %d\n",pmix);
+		ERR("detected an underrun: primary queue was %d\n",pmix);
 		pmix = 0;
 	}
+
+	TRACE("primary back-samples=%d\n",pmix);
+	
 	/* divide the offset by its sample size */
 	pmix /= device->pwfx->nBlockAlign;
-	TRACE("primary back-samples=%d\n",pmix);
+	
 	/* adjust for our frequency */
 	pmix = (pmix * This->freqAdjust) >> DSOUND_FREQSHIFT;
+	
 	/* multiply by our own sample size */
 	pmix *= This->pwfx->nBlockAlign;
+	
 	TRACE("this back-offset=%d\n", pmix);
+
+	/* sanity */
+	if(pmix > This->buflen){
+		ERR("Bad length in CalcPlayPosition!\n");
+		return 0;
+	}
+
 	/* subtract from our last mixed position */
-	while (bplay < pmix) bplay += This->buflen; /* wraparound */
+	if (bplay < pmix) bplay += This->buflen; /* wraparound */
 	bplay -= pmix;
+	
+	/* check for lead-in */
 	if (This->leadin && ((bplay < This->startpos) || (bplay > This->buf_mixpos))) {
 		/* seems we haven't started playing yet */
 		TRACE("this still in lead-in phase\n");
 		bplay = This->startpos;
 	}
+
+	/* sanity */
+	if(bplay > This->buflen){
+		ERR("Bad play position in CalcPlayPosition!\n");
+		return 0;
+	}	
+
 	/* return the result */
 	return bplay;
 }
@@ -469,13 +488,13 @@ static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition(
 			*playpos = This->buf_mixpos;
 		} else if (playpos) {
 			DWORD pplay, pwrite;
-			/* let's get this exact; first, recursively call GetPosition on the primary */
+
+			/* get primary lock, before messing with primary/device data */
 			EnterCriticalSection(&(This->device->mixlock));
+			
+			/* let's get this exact; first, recursively call GetPosition on the primary */
 			if (DSOUND_PrimaryGetPosition(This->device, &pplay, &pwrite) != DS_OK)
 				WARN("DSOUND_PrimaryGetPosition failed\n");
-			/* detect HEL mode underrun */
-			if (!(This->device->hwbuf || This->device->pwqueue))
-				TRACE("detected an underrun\n");
 			if ((This->dsbd.dwFlags & DSBCAPS_GETCURRENTPOSITION2) || This->device->hwbuf) {
 				/* calculate play position using this */
 				*playpos = DSOUND_CalcPlayPosition(This, pplay, pwrite);
@@ -489,7 +508,9 @@ static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition(
 				wp = (This->device->pwplay + ds_hel_margin) * This->device->fraglen;
 				wp %= This->device->buflen;
 				*playpos = DSOUND_CalcPlayPosition(This, wp, pwrite);
+				TRACE("Using non-GETCURRENTPOSITION2\n");
 			}
+
 			LeaveCriticalSection(&(This->device->mixlock));
 		}
 		if (writepos)
@@ -504,7 +525,10 @@ static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition(
 	}
 	if (playpos)
             This->last_playpos = *playpos;
-	TRACE("playpos = %d, writepos = %d (%p, time=%d)\n", playpos?*playpos:0, writepos?*writepos:0, This, GetTickCount());
+	
+	TRACE("playpos = %d, writepos = %d, buflen=%d (%p, time=%d)\n", 
+		playpos?*playpos:0, writepos?*writepos:0, This->buflen, This, GetTickCount());
+
 	return DS_OK;
 }
 
@@ -610,19 +634,9 @@ static HRESULT WINAPI IDirectSoundBufferImpl_Lock(
 		return DSERR_INVALIDPARAM;
         }
 
+	/* **** */
 	EnterCriticalSection(&(This->lock));
 
-	if ((writebytes == This->buflen) &&
-	    ((This->state == STATE_STARTING) ||
-	     (This->state == STATE_PLAYING)))
-		/* some games, like Half-Life, try to be clever (not) and
-		 * keep one secondary buffer, and mix sounds into it itself,
-		 * locking the entire buffer every time... so we can just forget
-		 * about tracking the last-written-to-position... */
-		This->probably_valid_to = (DWORD)-1;
-	else
-		This->probably_valid_to = writecursor;
-
 	if (!(This->device->drvdesc.dwFlags & DSDDESC_DONTNEEDSECONDARYLOCK) && This->hwbuf) {
 		hres = IDsDriverBuffer_Lock(This->hwbuf,
 				     lplpaudioptr1, audiobytes1,
@@ -635,7 +649,6 @@ static HRESULT WINAPI IDirectSoundBufferImpl_Lock(
 			return hres;
 		}
 	} else {
-		BOOL remix = FALSE;
 		if (writecursor+writebytes <= This->buflen) {
 			*(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
 			*audiobytes1 = writebytes;
@@ -643,6 +656,8 @@ static HRESULT WINAPI IDirectSoundBufferImpl_Lock(
 				*(LPBYTE*)lplpaudioptr2 = NULL;
 			if (audiobytes2)
 				*audiobytes2 = 0;
+			TRACE("Locked %p(%i bytes) and %p(%i bytes) writecursor=%d\n",
+			  *(LPBYTE*)lplpaudioptr1, *audiobytes1, lplpaudioptr2 ? *(LPBYTE*)lplpaudioptr2 : NULL, audiobytes2 ? *audiobytes2: 0, writecursor);
 			TRACE("->%d.0\n",writebytes);
 		} else {
 			*(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
@@ -651,30 +666,12 @@ static HRESULT WINAPI IDirectSoundBufferImpl_Lock(
 				*(LPBYTE*)lplpaudioptr2 = This->buffer->memory;
 			if (audiobytes2)
 				*audiobytes2 = writebytes-(This->buflen-writecursor);
-			TRACE("->%d.%d\n",*audiobytes1,audiobytes2?*audiobytes2:0);
-		}
-		if (This->state == STATE_PLAYING) {
-			/* if the segment between playpos and buf_mixpos is touched,
-			 * we need to cancel some mixing */
-			/* we'll assume that the app always calls GetCurrentPosition before
-			 * locking a playing buffer, so that last_playpos is up-to-date */
-			if (This->buf_mixpos >= This->last_playpos) {
-				if (This->buf_mixpos > writecursor &&
-				    This->last_playpos < writecursor+writebytes)
-					remix = TRUE;
-			} else {
-				if (This->buf_mixpos > writecursor ||
-				    This->last_playpos < writecursor+writebytes)
-					remix = TRUE;
-			}
-			if (remix) {
-				TRACE("locking prebuffered region, ouch\n");
-				DSOUND_MixCancelAt(This, writecursor);
-			}
+			TRACE("Locked %p(%i bytes) and %p(%i bytes) writecursor=%d\n", *(LPBYTE*)lplpaudioptr1, *audiobytes1, lplpaudioptr2 ? *(LPBYTE*)lplpaudioptr2 : NULL, audiobytes2 ? *audiobytes2: 0, writecursor);
 		}
 	}
 
 	LeaveCriticalSection(&(This->lock));
+	/* **** */
 
 	return DS_OK;
 }
@@ -689,9 +686,15 @@ static HRESULT WINAPI IDirectSoundBufferImpl_SetCurrentPosition(
 	/* **** */
 	EnterCriticalSection(&(This->lock));
 
+	/* start mixing from this new location instead */
 	newpos %= This->buflen;
 	newpos -= newpos%This->pwfx->nBlockAlign;
 	This->buf_mixpos = newpos;
+
+	/* at this point, do not attempt to reset buffers, mess with primary mix position,
+           or anything like that to reduce latancy. The data already prebuffered cannot be changed */
+
+	/* position HW buffer if applicable */
 	if (This->hwbuf) {
 		hres = IDsDriverBuffer_SetPosition(This->hwbuf, This->buf_mixpos);
 		if (hres != DS_OK)
@@ -735,8 +738,7 @@ static HRESULT WINAPI IDirectSoundBufferImpl_SetPan(
 			hres = IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan));
 			if (hres != DS_OK)
 				WARN("IDsDriverBuffer_SetVolumePan failed\n");
-		} else
-			DSOUND_ForceRemix(This);
+		}	
 	}
 
 	LeaveCriticalSection(&(This->lock));
@@ -770,7 +772,6 @@ static HRESULT WINAPI IDirectSoundBufferImpl_Unlock(
 	LPDIRECTSOUNDBUFFER8 iface,LPVOID p1,DWORD x1,LPVOID p2,DWORD x2
 ) {
 	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
-	DWORD probably_valid_to;
 	HRESULT hres = DS_OK;
 
 	TRACE("(%p,%p,%d,%p,%d)\n", This,p1,x1,p2,x2);
@@ -784,22 +785,9 @@ static HRESULT WINAPI IDirectSoundBufferImpl_Unlock(
 			WARN("IDsDriverBuffer_Unlock failed\n");
 	}
 
-        if (hres == DS_OK) {
-		if (p2) probably_valid_to = (((LPBYTE)p2)-This->buffer->memory) + x2;
-		else probably_valid_to = (((LPBYTE)p1)-This->buffer->memory) + x1;
-		probably_valid_to %= This->buflen;
-		if ((probably_valid_to == 0) && ((x1+x2) == This->buflen) &&
-		    ((This->state == STATE_STARTING) ||
-		     (This->state == STATE_PLAYING)))
-			/* see IDirectSoundBufferImpl_Lock */
-			probably_valid_to = (DWORD)-1;
-		This->probably_valid_to = probably_valid_to;
-	}
-
 	LeaveCriticalSection(&(This->lock));
 	/* **** */
 
-	TRACE("probably_valid_to=%d\n", This->probably_valid_to);
 	return hres;
 }
 
@@ -1044,6 +1032,8 @@ HRESULT IDirectSoundBufferImpl_Create(
 	dsb->lpVtbl = &dsbvt;
 	dsb->iks = NULL;
 
+	dsb->remix_pos = 0;
+
 	/* size depends on version */
 	CopyMemory(&dsb->dsbd, dsbd, dsbd->dwSize);
 
diff --git a/dlls/dsound/dsound_main.c b/dlls/dsound/dsound_main.c
index 1736fe3..1f6dd26 100644
--- a/dlls/dsound/dsound_main.c
+++ b/dlls/dsound/dsound_main.c
@@ -66,8 +66,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(dsound);
 #define DS_HEL_QUEUE  5 /* HEL only: number of waveOut fragments ahead to queue to driver
 			 * (this will affect HEL sound reliability and latency) */
 
-#define DS_SND_QUEUE_MAX 28 /* max number of fragments to prebuffer */
-#define DS_SND_QUEUE_MIN 12 /* min number of fragments to prebuffer */
+#define DS_SND_QUEUE_MAX 10 /* max number of fragments to prebuffer */
 
 DirectSoundDevice*	DSOUND_renderer[MAXWAVEDRIVERS];
 GUID                    DSOUND_renderer_guids[MAXWAVEDRIVERS];
@@ -104,7 +103,6 @@ int ds_emuldriver = DS_EMULDRIVER;
 int ds_hel_margin = DS_HEL_MARGIN;
 int ds_hel_queue = DS_HEL_QUEUE;
 int ds_snd_queue_max = DS_SND_QUEUE_MAX;
-int ds_snd_queue_min = DS_SND_QUEUE_MIN;
 int ds_hw_accel = DS_HW_ACCEL_FULL;
 int ds_default_playback = 0;
 int ds_default_capture = 0;
@@ -170,9 +168,6 @@ void setup_dsound_options(void)
     if (!get_config_key( hkey, appkey, "SndQueueMax", buffer, MAX_PATH ))
         ds_snd_queue_max = atoi(buffer);
 
-    if (!get_config_key( hkey, appkey, "SndQueueMin", buffer, MAX_PATH ))
-        ds_snd_queue_min = atoi(buffer);
-
     if (!get_config_key( hkey, appkey, "HardwareAcceleration", buffer, MAX_PATH )) {
 	if (strcmp(buffer, "Full") == 0)
 	    ds_hw_accel = DS_HW_ACCEL_FULL;
@@ -207,8 +202,6 @@ void setup_dsound_options(void)
        WARN("ds_hel_queue = %d (default=%d)\n",ds_hel_queue, DS_HEL_QUEUE );
     if (ds_snd_queue_max != DS_SND_QUEUE_MAX)
        WARN("ds_snd_queue_max = %d (default=%d)\n",ds_snd_queue_max ,DS_SND_QUEUE_MAX);
-    if (ds_snd_queue_min != DS_SND_QUEUE_MIN)
-       WARN("ds_snd_queue_min = %d (default=%d)\n",ds_snd_queue_min ,DS_SND_QUEUE_MIN);
     if (ds_hw_accel != DS_HW_ACCEL_FULL)
 	WARN("ds_hw_accel = %s (default=Full)\n",
 	    ds_hw_accel==DS_HW_ACCEL_FULL ? "Full" :
diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h
index c46c945..ee2c9ec 100644
--- a/dlls/dsound/dsound_private.h
+++ b/dlls/dsound/dsound_private.h
@@ -20,10 +20,11 @@
  */
 
 /* Linux does not support better timing than 10ms */
-#define DS_TIME_RES 10  /* Resolution of multimedia timer */
+#define DS_TIME_RES 2  /* Resolution of multimedia timer */
 #define DS_TIME_DEL 10  /* Delay of multimedia timer callback, and duration of HEL fragment */
 
-#define DS_HEL_FRAGS 48 /* HEL only: number of waveOut fragments in primary buffer
+#define DS_HEL_BUFLEN 0x8000 /* HEL: The buffer length of the emulated buffer */
+#define DS_HEL_FRAGS 0x40 /* HEL only: number of waveOut fragments in primary buffer
 			 * (changing this won't help you) */
 
 /* direct sound hardware acceleration levels */
@@ -36,7 +37,6 @@ extern int ds_emuldriver;
 extern int ds_hel_margin;
 extern int ds_hel_queue;
 extern int ds_snd_queue_max;
-extern int ds_snd_queue_min;
 extern int ds_hw_accel;
 extern int ds_default_playback;
 extern int ds_default_capture;
@@ -91,7 +91,6 @@ struct DirectSoundDevice
     PIDSDRIVERBUFFER            hwbuf;
     LPBYTE                      buffer;
     DWORD                       writelead, buflen, state, playpos, mixpos;
-    BOOL                        need_remix;
     int                         nrofbuffers;
     IDirectSoundBufferImpl**    buffers;
     RTL_RWLOCK                  buffer_list_lock;
@@ -168,14 +167,12 @@ struct IDirectSoundBufferImpl
     DWORD                       playpos,startpos,writelead,buflen;
     DWORD                       nAvgBytesPerSec;
     DWORD                       freq;
-    DSVOLUMEPAN                 volpan, cvolpan;
+    DSVOLUMEPAN                 volpan;
     DSBUFFERDESC                dsbd;
     /* used for frequency conversion (PerfectPitch) */
     ULONG                       freqAdjust, freqAcc;
     /* used for intelligent (well, sort of) prebuffering */
-    DWORD                       probably_valid_to, last_playpos;
-    DWORD                       primary_mixpos, buf_mixpos;
-    BOOL                        need_remix;
+    DWORD                       primary_mixpos, buf_mixpos, last_playpos, remix_pos;
 
     /* IDirectSoundNotifyImpl fields */
     IDirectSoundNotifyImpl*     notify;
@@ -439,9 +436,6 @@ DWORD DSOUND_CalcPlayPosition(IDirectSoundBufferImpl *This, DWORD pplay, DWORD p
 /* mixer.c */
 
 void DSOUND_CheckEvent(IDirectSoundBufferImpl *dsb, int len);
-void DSOUND_ForceRemix(IDirectSoundBufferImpl *dsb);
-void DSOUND_MixCancelAt(IDirectSoundBufferImpl *dsb, DWORD buf_writepos);
-void DSOUND_WaveQueue(DirectSoundDevice *device, DWORD mixq);
 void DSOUND_RecalcVolPan(PDSVOLUMEPAN volpan);
 void DSOUND_AmpFactorToVolPan(PDSVOLUMEPAN volpan);
 void DSOUND_RecalcFormat(IDirectSoundBufferImpl *dsb);
diff --git a/dlls/dsound/mixer.c b/dlls/dsound/mixer.c
index 1388e6f..21494fb 100644
--- a/dlls/dsound/mixer.c
+++ b/dlls/dsound/mixer.c
@@ -3,6 +3,7 @@
  * Copyright 1998 Marcus Meissner
  * Copyright 1998 Rob Riggs
  * Copyright 2000-2002 TransGaming Technologies, Inc.
+ * Copyright 2007 Peter Dons Tychsen
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -285,7 +286,7 @@ static INT DSOUND_MixerNorm(IDirectSoundBufferImpl *dsb, BYTE *buf, INT len)
 	/* New PerfectPitch(tm) Technology (c) 1998 Rob Riggs */
 	/* Patent Pending :-] */
 
-	/* Patent enhancements (c) 2000 Ove Kåven,
+	/* Patent enhancements (c) 2000 Ove Kaven,
 	 * TransGaming Technologies Inc. */
 
 	/* FIXME("(%p) Adjusting frequency: %ld -> %ld (need optimization)\n",
@@ -315,11 +316,11 @@ static void DSOUND_MixerVol(IDirectSoundBufferImpl *dsb, BYTE *buf, INT len)
 	INT16	*bps = (INT16 *) buf;
 
 	TRACE("(%p,%p,%d)\n",dsb,buf,len);
-	TRACE("left = %x, right = %x\n", dsb->cvolpan.dwTotalLeftAmpFactor,
-		dsb->cvolpan.dwTotalRightAmpFactor);
+	TRACE("left = %x, right = %x\n", dsb->volpan.dwTotalLeftAmpFactor,
+		dsb->volpan.dwTotalRightAmpFactor);
 
-	if ((!(dsb->dsbd.dwFlags & DSBCAPS_CTRLPAN) || (dsb->cvolpan.lPan == 0)) &&
-	    (!(dsb->dsbd.dwFlags & DSBCAPS_CTRLVOLUME) || (dsb->cvolpan.lVolume == 0)) &&
+	if ((!(dsb->dsbd.dwFlags & DSBCAPS_CTRLPAN) || (dsb->volpan.lPan == 0)) &&
+	    (!(dsb->dsbd.dwFlags & DSBCAPS_CTRLVOLUME) || (dsb->volpan.lVolume == 0)) &&
 	    !(dsb->dsbd.dwFlags & DSBCAPS_CTRL3D))
 		return;		/* Nothing to do */
 
@@ -335,7 +336,7 @@ static void DSOUND_MixerVol(IDirectSoundBufferImpl *dsb, BYTE *buf, INT len)
 		case 1:
 			for (i = 0; i < len; i++) {
 				INT val = *bpc - 128;
-				val = (val * dsb->cvolpan.dwTotalLeftAmpFactor) >> 16;
+				val = (val * dsb->volpan.dwTotalLeftAmpFactor) >> 16;
 				*bpc = val + 128;
 				bpc++;
 			}
@@ -343,10 +344,10 @@ static void DSOUND_MixerVol(IDirectSoundBufferImpl *dsb, BYTE *buf, INT len)
 		case 2:
 			for (i = 0; i < len; i+=2) {
 				INT val = *bpc - 128;
-				val = (val * dsb->cvolpan.dwTotalLeftAmpFactor) >> 16;
+				val = (val * dsb->volpan.dwTotalLeftAmpFactor) >> 16;
 				*bpc++ = val + 128;
 				val = *bpc - 128;
-				val = (val * dsb->cvolpan.dwTotalRightAmpFactor) >> 16;
+				val = (val * dsb->volpan.dwTotalRightAmpFactor) >> 16;
 				*bpc = val + 128;
 				bpc++;
 			}
@@ -361,15 +362,15 @@ static void DSOUND_MixerVol(IDirectSoundBufferImpl *dsb, BYTE *buf, INT len)
 		switch (dsb->device->pwfx->nChannels) {
 		case 1:
 			for (i = 0; i < len; i += 2) {
-				*bps = (*bps * dsb->cvolpan.dwTotalLeftAmpFactor) >> 16;
+				*bps = (*bps * dsb->volpan.dwTotalLeftAmpFactor) >> 16;
 				bps++;
 			}
 			break;
 		case 2:
 			for (i = 0; i < len; i += 4) {
-				*bps = (*bps * dsb->cvolpan.dwTotalLeftAmpFactor) >> 16;
+				*bps = (*bps * dsb->volpan.dwTotalLeftAmpFactor) >> 16;
 				bps++;
-				*bps = (*bps * dsb->cvolpan.dwTotalRightAmpFactor) >> 16;
+				*bps = (*bps * dsb->volpan.dwTotalRightAmpFactor) >> 16;
 				bps++;
 			}
 			break;
@@ -447,9 +448,10 @@ static DWORD DSOUND_MixInBuffer(IDirectSoundBufferImpl *dsb, DWORD writepos, DWO
 	if (len % dsb->device->pwfx->nBlockAlign) {
 		INT nBlockAlign = dsb->device->pwfx->nBlockAlign;
 		ERR("length not a multiple of block size, len = %d, block size = %d\n", len, nBlockAlign);
-		len = (len / nBlockAlign) * nBlockAlign;	/* data alignment */
+		len -= len % nBlockAlign; /* data alignment */
 	}
 
+	/* Create temp buffer to hold actual resulting data */
 	if ((buf = ibuf = DSOUND_tmpbuffer(dsb->device, len)) == NULL)
 		return 0;
 
@@ -459,6 +461,8 @@ static DWORD DSOUND_MixInBuffer(IDirectSoundBufferImpl *dsb, DWORD writepos, DWO
 	   buffer, translating frequency/bits-per-sample/number-of-channels
 	   to match the device settings */
 	ilen = DSOUND_MixerNorm(dsb, ibuf, len);
+
+	/* then apply the correct volume, if necessary */
 	if ((dsb->dsbd.dwFlags & DSBCAPS_CTRLPAN) ||
 	    (dsb->dsbd.dwFlags & DSBCAPS_CTRLVOLUME) ||
 	    (dsb->dsbd.dwFlags & DSBCAPS_CTRL3D))
@@ -555,173 +559,6 @@ static DWORD DSOUND_MixInBuffer(IDirectSoundBufferImpl *dsb, DWORD writepos, DWO
 	return len;
 }
 
-static void DSOUND_PhaseCancel(IDirectSoundBufferImpl *dsb, DWORD writepos, DWORD len)
-{
-	INT     ilen, field;
-	UINT    i, todo;
-	BYTE	*buf, *ibuf;
-
-	TRACE("(%p,%d,%d)\n",dsb,writepos,len);
-
-	if (len % dsb->device->pwfx->nBlockAlign) {
-		INT nBlockAlign = dsb->device->pwfx->nBlockAlign;
-		ERR("length not a multiple of block size, len = %d, block size = %d\n", len, nBlockAlign);
-		len = (len / nBlockAlign) * nBlockAlign;	/* data alignment */
-	}
-
-	if ((buf = ibuf = DSOUND_tmpbuffer(dsb->device, len)) == NULL)
-		return;
-
-	TRACE("PhaseCancel (%p) len = %d, dest = %d\n", dsb, len, writepos);
-
-	ilen = DSOUND_MixerNorm(dsb, ibuf, len);
-	if ((dsb->dsbd.dwFlags & DSBCAPS_CTRLPAN) ||
-	    (dsb->dsbd.dwFlags & DSBCAPS_CTRLVOLUME) ||
-	    (dsb->dsbd.dwFlags & DSBCAPS_CTRL3D))
-		DSOUND_MixerVol(dsb, ibuf, len);
-
-	/* subtract instead of add, to phase out premixed data */
-	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 = (*obuf - 128);
-			field -= (*ibuf++ - 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 = (*obuf - 128);
-				field -= (*ibuf++ - 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 = *obufs;
-			field -= *ibufs++;
-			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 = *obufs;
-				field -= *ibufs++;
-				if (field > 32767) field = 32767;
-				else if (field < -32768) field = -32768;
-				*obufs++ = field;
-			}
-		}
-        }
-}
-
-static void DSOUND_MixCancel(IDirectSoundBufferImpl *dsb, DWORD writepos, BOOL cancel)
-{
-	DWORD   size, flen, len, npos, nlen;
-	INT	iAdvance = dsb->pwfx->nBlockAlign;
-	INT	oAdvance = dsb->device->pwfx->nBlockAlign;
-	/* determine amount of premixed data to cancel */
-	DWORD primary_done =
-		((dsb->primary_mixpos < writepos) ? dsb->device->buflen : 0) +
-		dsb->primary_mixpos - writepos;
-
-	TRACE("(%p, %d), buf_mixpos=%d\n", dsb, writepos, dsb->buf_mixpos);
-
-	/* backtrack the mix position */
-	size = primary_done / oAdvance;
-	flen = size * dsb->freqAdjust;
-	len = (flen >> DSOUND_FREQSHIFT) * iAdvance;
-	flen &= (1<<DSOUND_FREQSHIFT)-1;
-	while (dsb->freqAcc < flen) {
-		len += iAdvance;
-		dsb->freqAcc += 1<<DSOUND_FREQSHIFT;
-	}
-	len %= dsb->buflen;
-	npos = ((dsb->buf_mixpos < len) ? dsb->buflen : 0) +
-		dsb->buf_mixpos - len;
-	if (dsb->leadin && (dsb->startpos > npos) && (dsb->startpos <= npos + len)) {
-		/* stop backtracking at startpos */
-		npos = dsb->startpos;
-		len = ((dsb->buf_mixpos < npos) ? dsb->buflen : 0) +
-			dsb->buf_mixpos - npos;
-		flen = dsb->freqAcc;
-		nlen = len / dsb->pwfx->nBlockAlign;
-		nlen = ((nlen << DSOUND_FREQSHIFT) + flen) / dsb->freqAdjust;
-		nlen *= dsb->device->pwfx->nBlockAlign;
-		writepos =
-			((dsb->primary_mixpos < nlen) ? dsb->device->buflen : 0) +
-			dsb->primary_mixpos - nlen;
-	}
-
-	dsb->freqAcc -= flen;
-	dsb->buf_mixpos = npos;
-	dsb->primary_mixpos = writepos;
-
-	TRACE("new buf_mixpos=%d, primary_mixpos=%d (len=%d)\n",
-	      dsb->buf_mixpos, dsb->primary_mixpos, len);
-
-	if (cancel) DSOUND_PhaseCancel(dsb, writepos, len);
-}
-
-void DSOUND_MixCancelAt(IDirectSoundBufferImpl *dsb, DWORD buf_writepos)
-{
-#if 0
-	DWORD   i, size, flen, len, npos, nlen;
-	INT	iAdvance = dsb->pwfx->nBlockAlign;
-	INT	oAdvance = dsb->device->pwfx->nBlockAlign;
-	/* determine amount of premixed data to cancel */
-	DWORD buf_done =
-		((dsb->buf_mixpos < buf_writepos) ? dsb->buflen : 0) +
-		dsb->buf_mixpos - buf_writepos;
-#endif
-
-	WARN("(%p, %d), buf_mixpos=%d\n", dsb, buf_writepos, dsb->buf_mixpos);
-	/* since this is not implemented yet, just cancel *ALL* prebuffering for now
-	 * (which is faster anyway when there's only a single secondary buffer) */
-	dsb->device->need_remix = TRUE;
-}
-
-void DSOUND_ForceRemix(IDirectSoundBufferImpl *dsb)
-{
-	TRACE("(%p)\n",dsb);
-	EnterCriticalSection(&dsb->lock);
-	if (dsb->state == STATE_PLAYING)
-		dsb->device->need_remix = TRUE;
-	LeaveCriticalSection(&dsb->lock);
-}
-
 /**
  * Calculate the distance between two buffer offsets, taking wraparound
  * into account.
@@ -751,149 +588,70 @@ static DWORD DSOUND_MixOne(IDirectSoundBufferImpl *dsb, DWORD playpos, DWORD wri
 {
 	/* The buffer's primary_mixpos may be before or after the the device
 	 * buffer's mixpos, but both must be ahead of writepos. */
-
-	DWORD len, slen;
-	/* determine this buffer's write position */
-	DWORD buf_writepos = DSOUND_CalcPlayPosition(dsb, writepos, writepos);
-	/* determine how much already-mixed data exists */
-	DWORD buf_done = DSOUND_BufPtrDiff(dsb->buflen, dsb->buf_mixpos, buf_writepos);
-	DWORD primary_done = DSOUND_BufPtrDiff(dsb->device->buflen, dsb->primary_mixpos, writepos);
-	DWORD adv_done = DSOUND_BufPtrDiff(dsb->device->buflen, dsb->device->mixpos, writepos);
-	DWORD played = DSOUND_BufPtrDiff(dsb->buflen, buf_writepos, dsb->playpos);
-	DWORD buf_left = dsb->buflen - buf_writepos;
-	int still_behind;
-
+	DWORD primary_done;
+	
 	TRACE("(%p,%d,%d,%d)\n",dsb,playpos,writepos,mixlen);
-	TRACE("buf_writepos=%d, primary_writepos=%d\n", buf_writepos, writepos);
-	TRACE("buf_done=%d, primary_done=%d\n", buf_done, primary_done);
-	TRACE("buf_mixpos=%d, primary_mixpos=%d, mixlen=%d\n", dsb->buf_mixpos, dsb->primary_mixpos,
-	      mixlen);
-	TRACE("looping=%d, startpos=%d, leadin=%d\n", dsb->playflags, dsb->startpos, dsb->leadin);
+	TRACE("writepos=%d, buf_mixpos=%d, primary_mixpos=%d, mixlen=%d\n", writepos, dsb->buf_mixpos, dsb->primary_mixpos, mixlen);
+	TRACE("looping=%d, startpos=%d, leadin=%d, buflen=%d\n", dsb->playflags, dsb->startpos, dsb->leadin, dsb->buflen);
 
 	/* check for notification positions */
 	if (dsb->dsbd.dwFlags & DSBCAPS_CTRLPOSITIONNOTIFY &&
 	    dsb->state != STATE_STARTING) {
-		DSOUND_CheckEvent(dsb, played);
+		DSOUND_CheckEvent(dsb, mixlen);
 	}
 
 	/* save write position for non-GETCURRENTPOSITION2... */
-	dsb->playpos = buf_writepos;
-
-	/* check whether CalcPlayPosition detected a mixing underrun */
-	if ((buf_done == 0) && (dsb->primary_mixpos != writepos)) {
-		/* it did, but did we have more to play? */
-		if ((dsb->playflags & DSBPLAY_LOOPING) ||
-		    (dsb->buf_mixpos < dsb->buflen)) {
-			/* yes, have to recover */
-			ERR("underrun on sound buffer %p\n", dsb);
-			TRACE("recovering from underrun: primary_mixpos=%d\n", writepos);
-		}
-		dsb->primary_mixpos = writepos;
-		primary_done = 0;
-	}
-	/* determine how far ahead we should mix */
-	if (((dsb->playflags & DSBPLAY_LOOPING) ||
-	     (dsb->leadin && (dsb->probably_valid_to != 0))) &&
-	    !(dsb->dsbd.dwFlags & DSBCAPS_STATIC)) {
-		/* if this is a streaming buffer, it typically means that
-		 * we should defer mixing past probably_valid_to as long
-		 * as we can, to avoid unnecessary remixing */
-		/* the heavy-looking calculations shouldn't be that bad,
-		 * as any game isn't likely to be have more than 1 or 2
-		 * streaming buffers in use at any time anyway... */
-		DWORD probably_valid_left =
-			(dsb->probably_valid_to == (DWORD)-1) ? dsb->buflen :
-			((dsb->probably_valid_to < buf_writepos) ? dsb->buflen : 0) +
-			dsb->probably_valid_to - buf_writepos;
-		/* check for leadin condition */
-		if ((probably_valid_left == 0) &&
-		    (dsb->probably_valid_to == dsb->startpos) &&
-		    dsb->leadin)
-			probably_valid_left = dsb->buflen;
-		TRACE("streaming buffer probably_valid_to=%d, probably_valid_left=%d\n",
-		      dsb->probably_valid_to, probably_valid_left);
-		/* check whether the app's time is already up */
-		if (probably_valid_left < dsb->writelead) {
-			WARN("probably_valid_to now within writelead, possible streaming underrun\n");
-			/* once we pass the point of no return,
-			 * no reason to hold back anymore */
-			dsb->probably_valid_to = (DWORD)-1;
-			/* we just have to go ahead and mix what we have,
-			 * there's no telling what the app is thinking anyway */
-		} else {
-			/* adjust for our frequency and our sample size */
-			probably_valid_left = MulDiv(probably_valid_left,
-						     1 << DSOUND_FREQSHIFT,
-						     dsb->pwfx->nBlockAlign * dsb->freqAdjust) *
-				              dsb->device->pwfx->nBlockAlign;
-			/* check whether to clip mix_len */
-			if (probably_valid_left < mixlen) {
-				TRACE("clipping to probably_valid_left=%d\n", probably_valid_left);
-				mixlen = probably_valid_left;
-			}
-		}
-	}
-	/* cut mixlen with what's already been mixed */
-	if (mixlen < primary_done) {
-		/* huh? and still CalcPlayPosition didn't
-		 * detect an underrun? */
-		FIXME("problem with underrun detection (mixlen=%d < primary_done=%d)\n", mixlen, primary_done);
+	dsb->playpos = writepos;
+
+	/* calculate how much pre-buffering has already been done for this buffer */
+	primary_done = DSOUND_BufPtrDiff(dsb->device->buflen, dsb->primary_mixpos, writepos);
+
+	/* sanity */
+	if(mixlen < primary_done)
+	{
+		/* Should *NEVER* happen */
+		ERR("Fatal error. Under/Overflow? primary_done=%d, mixpos=%d, primary_mixpos=%d, writepos=%d, playpos=%d\n", primary_done,dsb->buf_mixpos,dsb->primary_mixpos, writepos, playpos);
 		return 0;
 	}
-	len = mixlen - primary_done;
-	TRACE("remaining mixlen=%d\n", len);
-
-	if (len < dsb->device->fraglen) {
-		/* smaller than a fragment, wait until it gets larger
-		 * before we take the mixing overhead */
-		TRACE("mixlen not worth it, deferring mixing\n");
-		still_behind = 1;
-		goto post_mix;
-	}
 
-	/* ok, we know how much to mix, let's go */
-	still_behind = (adv_done > primary_done);
-	while (len) {
-		slen = dsb->device->buflen - dsb->primary_mixpos;
-		if (slen > len) slen = len;
-		slen = DSOUND_MixInBuffer(dsb, dsb->primary_mixpos, slen);
+	/* take into acount already mixed data */
+	mixlen = mixlen - primary_done;
+	
+	TRACE("mixlen (primary) = %i\n", mixlen);
 
-		if ((dsb->primary_mixpos < dsb->device->mixpos) &&
-		    (dsb->primary_mixpos + slen >= dsb->device->mixpos))
-			still_behind = FALSE;
+	/* clip to valid length */
+	mixlen = (dsb->buflen < mixlen) ? dsb->buflen : mixlen;
 
-		dsb->primary_mixpos += slen; len -= slen;
-		dsb->primary_mixpos %= dsb->device->buflen;
+	TRACE("primary_done=%d, mixlen (buffer)=%d\n", primary_done, mixlen);
 
-		if ((dsb->state == STATE_STOPPED) || !slen) break;
-	}
-	TRACE("new primary_mixpos=%d, primary_advbase=%d\n", dsb->primary_mixpos, dsb->device->mixpos);
-	TRACE("mixed data len=%d, still_behind=%d\n", mixlen-len, still_behind);
+	/* mix more data */
+	mixlen = DSOUND_MixInBuffer(dsb, dsb->primary_mixpos, mixlen);
+
+	/* increase mix position */
+	dsb->primary_mixpos += mixlen;
+	dsb->primary_mixpos %= dsb->device->buflen;
+
+	TRACE("new primary_mixpos=%d, mixed data len=%d, buffer left = %d\n", 
+		dsb->primary_mixpos, mixlen, (dsb->buflen - dsb->buf_mixpos));
+	
+	/* re-calculate the primary done */
+	primary_done = DSOUND_BufPtrDiff(dsb->device->buflen, dsb->primary_mixpos, writepos);
 
-post_mix:
 	/* check if buffer should be considered complete */
-	if (buf_left < dsb->writelead &&
+	if (((dsb->buflen - dsb->buf_mixpos) < dsb->writelead) &&
 	    !(dsb->playflags & DSBPLAY_LOOPING)) {
+	
+		TRACE("Buffer reached end. Stopped\n");
+
 		dsb->state = STATE_STOPPED;
 		dsb->playpos = 0;
-		dsb->last_playpos = 0;
 		dsb->buf_mixpos = 0;
 		dsb->leadin = FALSE;
-		dsb->need_remix = FALSE;
-		DSOUND_CheckEvent(dsb, buf_left);
-	}
-
-	/* return how far we think the primary buffer can
-	 * advance its underrun detector...*/
-	if (still_behind) return 0;
-	if ((mixlen - len) < primary_done) return 0;
-	slen = DSOUND_BufPtrDiff(dsb->device->buflen, dsb->primary_mixpos, dsb->device->mixpos);
-	if (slen > mixlen) {
-		/* the primary_done and still_behind checks above should have worked */
-		FIXME("problem with advancement calculation (advlen=%d > mixlen=%d)\n", slen, mixlen);
-		slen = 0;
+		DSOUND_CheckEvent(dsb, mixlen);
 	}
-	return slen;
+	
+	/* Report back the total prebuffered amount for this buffer */
+	return primary_done;
 }
 
 /**
@@ -906,127 +664,130 @@ post_mix:
  *          (beyond the current writepos)
  * recover = true if the sound device may have been reset and the write
  *           position in the device buffer changed
+ * all_stopped = reports back if all buffers have stopped
  *
  * Returns:  the length beyond the writepos that was mixed to.
  */
+
 static DWORD DSOUND_MixToPrimary(const DirectSoundDevice *device, DWORD playpos, DWORD writepos,
-                                 DWORD mixlen, BOOL recover)
+                                 DWORD mixlen, BOOL recover, BOOL *all_stopped)
 {
-	INT			i, len, maxlen = 0;
+	INT i, len;
+	DWORD minlen = 0;
 	IDirectSoundBufferImpl	*dsb;
+ 
+	/* unless we find a running buffer, all have stopped */
+	*all_stopped = TRUE;
 
 	TRACE("(%d,%d,%d,%d)\n", playpos, writepos, mixlen, recover);
 	for (i = 0; i < device->nrofbuffers; i++) {
 		dsb = device->buffers[i];
+ 
+		TRACE("MixToPrimary for %p, state=%d\n", dsb, dsb->state);
 
 		if (dsb->buflen && dsb->state && !dsb->hwbuf) {
 			TRACE("Checking %p, mixlen=%d\n", dsb, mixlen);
 			EnterCriticalSection(&(dsb->lock));
+	
+			/* if buffer is stopping it is stopped now */
 			if (dsb->state == STATE_STOPPING) {
-				DSOUND_MixCancel(dsb, writepos, TRUE);
 				dsb->state = STATE_STOPPED;
 				DSOUND_CheckEvent(dsb, 0);
 			} else {
+
+				/* if recovering, reset the mix position */
 				if ((dsb->state == STATE_STARTING) || recover) {
 					dsb->primary_mixpos = writepos;
-					dsb->cvolpan = dsb->volpan;
-					dsb->need_remix = FALSE;
-				}
-				else if (dsb->need_remix) {
-					DSOUND_MixCancel(dsb, writepos, TRUE);
-					dsb->cvolpan = dsb->volpan;
-					dsb->need_remix = FALSE;
 				}
+
+				/* mix next buffer into the main buffer */
 				len = DSOUND_MixOne(dsb, playpos, writepos, mixlen);
+				
+				/* if the buffer was starting, it must be playing now */
 				if (dsb->state == STATE_STARTING)
 					dsb->state = STATE_PLAYING;
-				maxlen = (len > maxlen) ? len : maxlen;
-			}
-			LeaveCriticalSection(&(dsb->lock));
-		}
-	}
-
-	return maxlen;
-}
-
-static void DSOUND_MixReset(DirectSoundDevice *device, DWORD writepos)
-{
-	INT			i;
-	IDirectSoundBufferImpl	*dsb;
-	int nfiller;
+				
+				/* check if min-len should be initialized */
+				if(minlen == 0) minlen = len;
 
-	TRACE("(%p,%d)\n", device, writepos);
-
-	/* the sound of silence */
-	nfiller = device->pwfx->wBitsPerSample == 8 ? 128 : 0;
-
-	/* reset all buffer mix positions */
-	for (i = 0; i < device->nrofbuffers; i++) {
-		dsb = device->buffers[i];
-
-		if (dsb->buflen && dsb->state && !dsb->hwbuf) {
-			TRACE("Resetting %p\n", dsb);
-			EnterCriticalSection(&(dsb->lock));
-			if (dsb->state == STATE_STOPPING) {
-				dsb->state = STATE_STOPPED;
+			        /* record the minimum length mixed from all buffers */	
+				/* we only want to return the length which *all* buffers have mixed */
+			        if(len != 0) minlen = (len < minlen) ? len : minlen;
 			}
-			else if (dsb->state == STATE_STARTING) {
-				/* nothing */
-			} else {
-				DSOUND_MixCancel(dsb, writepos, FALSE);
-				dsb->cvolpan = dsb->volpan;
-				dsb->need_remix = FALSE;
+
+			if(dsb->state != STATE_STOPPED){
+				*all_stopped = FALSE;
 			}
+
 			LeaveCriticalSection(&(dsb->lock));
 		}
 	}
-
-	/* wipe out premixed data */
-	if (device->mixpos < writepos) {
-		FillMemory(device->buffer + writepos, device->buflen - writepos, nfiller);
-		FillMemory(device->buffer, device->mixpos, nfiller);
-	} else {
-		FillMemory(device->buffer + writepos, device->mixpos - writepos, nfiller);
-	}
-
-	/* reset primary mix position */
-	device->mixpos = writepos;
+ 
+	TRACE("Mixed at least %d from all buffers\n", minlen);
+ 
+	return minlen;
 }
 
-static void DSOUND_CheckReset(DirectSoundDevice *device, DWORD writepos)
+/**
+ * Add buffers to the emulated wave device system.
+ *
+ * device = The current dsound playback device
+ * force = If TRUE, the function will buffer up as many frags as possible,
+ *         even though and will ignore the actual state of the primary buffer.
+ *
+ * Returns:  None
+ */
+
+static void DSOUND_WaveQueue(DirectSoundDevice *device, BOOL force)
 {
-	TRACE("(%p,%d)\n",device,writepos);
-	if (device->need_remix) {
-		DSOUND_MixReset(device, writepos);
-		device->need_remix = FALSE;
-		/* maximize Half-Life performance */
-		device->prebuf = ds_snd_queue_min;
-		device->precount = 0;
-	} else {
-		device->precount++;
-		if (device->precount >= 4) {
-			if (device->prebuf < ds_snd_queue_max)
-				device->prebuf++;
-			device->precount = 0;
-		}
+	DWORD prebuf_frags, wave_writepos, wave_fragpos, i;
+	TRACE("(%p)\n", device);
+	
+	/* calculate the current wave frag position */
+	wave_fragpos = (device->pwplay + device->pwqueue) % DS_HEL_FRAGS;
+		
+	/* calculte the current wave write position */
+	wave_writepos = wave_fragpos * device->fraglen;
+
+	TRACE("wave_fragpos = %i, wave_writepos = %i, pwqueue = %i, ds_hel_queue= %i\n", 
+		wave_fragpos, wave_writepos, device->pwqueue, ds_hel_queue); 
+
+	if(force == FALSE){
+		/* check remaining prebuffered frags */
+		prebuf_frags = DSOUND_BufPtrDiff(device->buflen, device->mixpos, wave_writepos);
+		prebuf_frags = prebuf_frags / device->fraglen;
+	}
+	else{
+		/* buffer the maximum amount of frags */
+		prebuf_frags = device->prebuf;
 	}
-	TRACE("premix adjust: %d\n", device->prebuf);
-}
 
-void DSOUND_WaveQueue(DirectSoundDevice *device, DWORD mixq)
-{
-	TRACE("(%p,%d)\n", device, mixq);
-	if (mixq + device->pwqueue > ds_hel_queue) mixq = ds_hel_queue - device->pwqueue;
-	TRACE("queueing %d buffers, starting at %d\n", mixq, device->pwwrite);
-	for (; mixq; mixq--) {
-		waveOutWrite(device->hwo, device->pwave[device->pwwrite], sizeof(WAVEHDR));
-		device->pwwrite++;
-		if (device->pwwrite >= DS_HEL_FRAGS) device->pwwrite = 0;
-		device->pwqueue++;
+	/* limit to the queue we have left */
+	if((prebuf_frags + device->pwqueue) > device->prebuf)
+		prebuf_frags = device->prebuf - device->pwqueue;
+ 
+	TRACE("prebuf_frags = %i\n", prebuf_frags);
+
+	/* adjust queue */
+	device->pwqueue += prebuf_frags;
+
+	/* get out of CS when calling the wave system */	
+	LeaveCriticalSection(&(device->mixlock));
+	/* **** */
+	
+	/* queue up the new buffers */
+	for(i=0; i<prebuf_frags; i++){
+		TRACE("queueing wave buffer %i\n", wave_fragpos);
+		waveOutWrite(device->hwo, device->pwave[wave_fragpos], sizeof(WAVEHDR));
+		wave_fragpos++;
+		wave_fragpos %= DS_HEL_FRAGS; 
 	}
-}
 
-/* #define SYNC_CALLBACK */
+	/* **** */
+	EnterCriticalSection(&(device->mixlock));
+
+	TRACE("queue now = %i\n", device->pwqueue);
+}
 
 /**
  * Perform mixing for a Direct Sound device. That is, go through all the
@@ -1035,151 +796,164 @@ void DSOUND_WaveQueue(DirectSoundDevice *device, DWORD mixq)
  */
 static void DSOUND_PerformMix(DirectSoundDevice *device)
 {
-	int nfiller;
-	BOOL forced;
-	HRESULT hres;
 
 	TRACE("(%p)\n", device);
 
-	/* the sound of silence */
-	nfiller = device->pwfx->wBitsPerSample == 8 ? 128 : 0;
-
-	/* whether the primary is forced to play even without secondary buffers */
-	forced = ((device->state == STATE_PLAYING) || (device->state == STATE_STARTING));
+	/* **** */
+	EnterCriticalSection(&(device->mixlock));
 
 	if (device->priolevel != DSSCL_WRITEPRIMARY) {
-		BOOL paused = ((device->state == STATE_STOPPED) || (device->state == STATE_STARTING));
-		/* FIXME: document variables */
- 		DWORD playpos, writepos, inq, maxq, frag;
- 		if (device->hwbuf) {
-			hres = IDsDriverBuffer_GetPosition(device->hwbuf, &playpos, &writepos);
-			if (hres) {
-			    WARN("IDsDriverBuffer_GetPosition failed\n");
-			    return;
-			}
-			/* Well, we *could* do Just-In-Time mixing using the writepos,
-			 * but that's a little bit ambitious and unnecessary... */
-			/* rather add our safety margin to the writepos, if we're playing */
-			if (!paused) {
-				writepos += device->writelead;
-				writepos %= device->buflen;
-			} else writepos = playpos;
-		} else {
- 			playpos = device->pwplay * device->fraglen;
- 			writepos = playpos;
- 			if (!paused) {
-	 			writepos += ds_hel_margin * device->fraglen;
- 				writepos %= device->buflen;
-	 		}
+		BOOL recover = FALSE, all_stopped = FALSE;
+		DWORD playpos, writepos, writelead, maxq, frag, prebuff_max, prebuff_left, size1, size2;
+		LPVOID buf1, buf2;
+		BOOL lock = (device->hwbuf && !(device->drvdesc.dwFlags & DSDDESC_DONTNEEDPRIMARYLOCK));
+		int nfiller;
+
+		/* the sound of silence */
+		nfiller = device->pwfx->wBitsPerSample == 8 ? 128 : 0;
+ 
+		/* get the position in the primary buffer */
+		if (DSOUND_PrimaryGetPosition(device, &playpos, &writepos) != 0){
+			LeaveCriticalSection(&(device->mixlock));
+			return;
 		}
+
 		TRACE("primary playpos=%d, writepos=%d, clrpos=%d, mixpos=%d, buflen=%d\n",
 		      playpos,writepos,device->playpos,device->mixpos,device->buflen);
 		assert(device->playpos < device->buflen);
+
 		/* wipe out just-played sound data */
 		if (playpos < device->playpos) {
-			FillMemory(device->buffer + device->playpos, device->buflen - device->playpos, nfiller);
-			FillMemory(device->buffer, playpos, nfiller);
+			buf1 = device->buffer + device->playpos;
+			buf2 = device->buffer;
+			size1 = device->buflen - device->playpos;
+			size2 = playpos;
+			if (lock)
+				IDsDriverBuffer_Lock(device->hwbuf, &buf1, &size1, &buf2, &size2, device->playpos, size1+size2, 0);
+			FillMemory(buf1, size1, nfiller);
+			if (playpos && (!buf2 || !size2))
+				FIXME("%d: (%d, %d)=>(%d, %d) There should be an additional buffer here!!\n", __LINE__, device->playpos, device->mixpos, playpos, writepos);
+			FillMemory(buf2, size2, nfiller);
+			if (lock)
+				IDsDriverBuffer_Unlock(device->hwbuf, buf1, size1, buf2, size2);
 		} else {
-			FillMemory(device->buffer + device->playpos, playpos - device->playpos, nfiller);
+			buf1 = device->buffer + device->playpos;
+			buf2 = NULL;
+			size1 = playpos - device->playpos;
+			size2 = 0;
+			if (lock)
+				IDsDriverBuffer_Lock(device->hwbuf, &buf1, &size1, &buf2, &size2, device->playpos, size1+size2, 0);
+			FillMemory(buf1, size1, nfiller);
+			if (buf2 && size2)
+			{
+				FIXME("%d: There should be no additional buffer here!!\n", __LINE__);
+				FillMemory(buf2, size2, nfiller);
+			}
+			if (lock)
+				IDsDriverBuffer_Unlock(device->hwbuf, buf1, size1, buf2, size2);
 		}
 		device->playpos = playpos;
 
-		EnterCriticalSection(&(device->mixlock));
-
-		/* reset mixing if necessary */
-		DSOUND_CheckReset(device, writepos);
-
-		/* check how much prebuffering is left */
-		inq = DSOUND_BufPtrDiff(device->buflen, device->mixpos, writepos);
-
-		/* find the maximum we can prebuffer */
-		if (!paused)
-			maxq = DSOUND_BufPtrDiff(device->buflen, playpos, writepos);
-		/* If we get the whole buffer, difference is 0, so we need to set whole buffer then */
-		if (paused || !maxq)
-			maxq = device->buflen;
-
-		/* clip maxq to device->prebuf */
-		frag = device->prebuf * device->fraglen;
-		if (maxq > frag)
-			maxq = frag;
-
-		/* check for consistency */
-		if (inq > maxq) {
-			/* the playback position must have passed our last
-			 * mixed position, i.e. it's an underrun, or we have
-			 * nothing more to play */
-			TRACE("reached end of mixed data (inq=%d, maxq=%d)\n", inq, maxq);
-			inq = 0;
-			/* stop the playback now, to allow buffers to refill */
-			if (device->state == STATE_PLAYING) {
-				device->state = STATE_STARTING;
-			}
-			else if (device->state == STATE_STOPPING) {
-				device->state = STATE_STOPPED;
-			}
-			else {
-				/* how can we have an underrun if we aren't playing? */
-				WARN("unexpected primary state (%d)\n", device->state);
-			}
-#ifdef SYNC_CALLBACK
-			/* DSOUND_callback may need this lock */
-			LeaveCriticalSection(&(device->mixlock));
-#endif
-			if (DSOUND_PrimaryStop(device) != DS_OK)
-				WARN("DSOUND_PrimaryStop failed\n");
-#ifdef SYNC_CALLBACK
-			EnterCriticalSection(&(device->mixlock));
-#endif
-			if (device->hwbuf) {
-				/* the Stop is supposed to reset play position to beginning of buffer */
-				/* unfortunately, OSS is not able to do so, so get current pointer */
-				hres = IDsDriverBuffer_GetPosition(device->hwbuf, &playpos, NULL);
-				if (hres) {
-					LeaveCriticalSection(&(device->mixlock));
-					WARN("IDsDriverBuffer_GetPosition failed\n");
-					return;
-				}
-			} else {
-	 			playpos = device->pwplay * device->fraglen;
-			}
-			writepos = playpos;
-			device->playpos = playpos;
+		/* calc maximum prebuff */
+		prebuff_max = (device->prebuf * device->fraglen);
+
+		/* check how close we are to an underrun. It occurs when the writepos overtakes the mixpos */
+		prebuff_left = DSOUND_BufPtrDiff(device->buflen, device->mixpos, playpos);
+
+		writelead = DSOUND_BufPtrDiff(device->buflen, writepos, playpos);
+
+		/* find the maximum we can prebuffer from current write position */
+		maxq = prebuff_max - prebuff_left;
+		maxq = (writelead < prebuff_max) ? (prebuff_max - writelead) : 0;
+	
+		TRACE("prebuff_left = %d, prebuff_max = %dx%d=%d, writelead=%d\n", 
+			prebuff_left, device->prebuf, device->fraglen, prebuff_max, writelead);
+		
+		/* check for underrun. underrun occurs when the write position passes the mix position */
+		if((prebuff_left > prebuff_max) || (device->state == STATE_STOPPED) || (device->state == STATE_STARTING)){
+			TRACE("Buffer starting or buffer underrun\n");
+
+			/* recover mixing for all buffers */
+			recover = TRUE;
+	
+			/* reset mix position to write position */
 			device->mixpos = writepos;
-			inq = 0;
-			maxq = device->buflen;
-			if (maxq > frag) maxq = frag;
-			FillMemory(device->buffer, device->buflen, nfiller);
-			paused = TRUE;
 		}
 
+		if (lock)
+			IDsDriverBuffer_Lock(device->hwbuf, &buf1, &size1, &buf2, &size2, device->mixpos, maxq, 0);
+
 		/* do the mixing */
-		frag = DSOUND_MixToPrimary(device, playpos, writepos, maxq, paused);
-		if (forced) frag = maxq - inq;
-		device->mixpos += frag;
+		frag = DSOUND_MixToPrimary(device, playpos, writepos, maxq, recover, &all_stopped);
+
+		/* update the mix position, taking wrap-around into acount */
+		device->mixpos = writepos + frag;
 		device->mixpos %= device->buflen;
 
-		if (frag) {
-			/* buffers have been filled, restart playback */
-			if (device->state == STATE_STARTING) {
-				device->state = STATE_PLAYING;
+		if (lock)
+		{
+			DWORD frag2 = (frag > size1 ? frag - size1 : 0);
+			frag -= frag2;
+			if (frag2 > size2)
+			{
+				FIXME("Buffering too much! (%d, %d, %d, %d)\n", maxq, frag, size2, frag2 - size2);
+				frag2 = size2;
 			}
-			else if (device->state == STATE_STOPPED) {
-				/* the dsound is supposed to play if there's something to play
-				 * even if it is reported as stopped, so don't let this confuse you */
-				device->state = STATE_STOPPING;
+			IDsDriverBuffer_Unlock(device->hwbuf, buf1, frag, buf2, frag2);
+		}
+
+		/* update prebuff left */
+		prebuff_left = DSOUND_BufPtrDiff(device->buflen, device->mixpos, playpos);
+
+		/* check if have a whole fragment */
+		if (prebuff_left >= device->fraglen){
+			
+			/* update the wave queue if using wave system */
+			if(device->hwbuf == NULL){
+				DSOUND_WaveQueue(device,TRUE);
 			}
-			LeaveCriticalSection(&(device->mixlock));
-			if (paused) {
-				if (DSOUND_PrimaryPlay(device) != DS_OK)
+
+			/* buffers are full. start playing if applicable */
+			if(device->state == STATE_STARTING){
+				TRACE("started primary buffer\n");
+				if(DSOUND_PrimaryPlay(device) != DS_OK){
 					WARN("DSOUND_PrimaryPlay failed\n");
-				else
-					TRACE("starting playback\n");
+				}
+				else{
+					/* we are playing now */
+					device->state = STATE_PLAYING;
+				}
+			}
+		
+			/* buffers are full. start stopping if applicable */	
+			if(device->state == STATE_STOPPED){
+				TRACE("restarting primary buffer");
+				if(DSOUND_PrimaryPlay(device) != DS_OK){
+					WARN("DSOUND_PrimaryPlay failed\n");
+				}
+				else{
+					/* start stopping again. as soon as there is no more data, it will stop */ 
+					device->state = STATE_STOPPING;
+				}
 			}
 		}
-		else
-			LeaveCriticalSection(&(device->mixlock));
+		
+		/* if device was stopping, its for sure stopped when all buffers have stopped */
+		else if((all_stopped == TRUE) && (device->state == STATE_STOPPING)){
+			TRACE("All buffers have stopped. Stopping primary buffer\n");
+			device->state = STATE_STOPPED;
+
+			/* stop the primary buffer now */	
+			DSOUND_PrimaryStop(device);	
+		}
+
 	} else {
+		
+		/* update the wave queue if using wave system */
+		if(device->hwbuf == NULL){
+			DSOUND_WaveQueue(device, TRUE);
+		}
+
 		/* in the DSSCL_WRITEPRIMARY mode, the app is totally in charge... */
 		if (device->state == STATE_STARTING) {
 			if (DSOUND_PrimaryPlay(device) != DS_OK)
@@ -1194,6 +968,9 @@ static void DSOUND_PerformMix(DirectSoundDevice *device)
 				device->state = STATE_STOPPED;
 		}
 	}
+
+	LeaveCriticalSection(&(device->mixlock));
+	/* **** */
 }
 
 void CALLBACK DSOUND_timer(UINT timerID, UINT msg, DWORD_PTR dwUser,
@@ -1230,39 +1007,29 @@ void CALLBACK DSOUND_callback(HWAVEOUT hwo, UINT msg, DWORD dwUser, DWORD dw1, D
 	TRACE("entering at %d, msg=%08x(%s)\n", GetTickCount(), msg,
 		msg==MM_WOM_DONE ? "MM_WOM_DONE" : msg==MM_WOM_CLOSE ? "MM_WOM_CLOSE" : 
 		msg==MM_WOM_OPEN ? "MM_WOM_OPEN" : "UNKNOWN");
+
+	/* check if packet completed from wave driver */
 	if (msg == MM_WOM_DONE) {
-		DWORD inq, mixq, fraglen, buflen, pwplay, playpos, mixpos;
-		if (device->pwqueue == (DWORD)-1) {
-			TRACE("completed due to reset\n");
-			return;
+		
+		/* **** */
+		EnterCriticalSection(&(device->mixlock));	
+
+		TRACE("done playing primary pos=%d\n", device->pwplay * device->fraglen);
+	
+		/* update playpos */
+		device->pwplay++;
+		device->pwplay %= DS_HEL_FRAGS;
+
+		/* sanity */
+		if(device->pwqueue == 0){
+			ERR("Wave queue corrupted!\n");
 		}
-/* it could be a bad idea to enter critical section here... if there's lock contention,
- * the resulting scheduling delays might obstruct the winmm player thread */
-#ifdef SYNC_CALLBACK
-		EnterCriticalSection(&(device->mixlock));
-#endif
-		/* retrieve current values */
-		fraglen = device->fraglen;
-		buflen = device->buflen;
-		pwplay = device->pwplay;
-		playpos = pwplay * fraglen;
-		mixpos = device->mixpos;
-		/* check remaining mixed data */
-		inq = DSOUND_BufPtrDiff(buflen, mixpos, playpos);
-		mixq = inq / fraglen;
-		if ((inq - (mixq * fraglen)) > 0) mixq++;
-		/* complete the playing buffer */
-		TRACE("done playing primary pos=%d\n", playpos);
-		pwplay++;
-		if (pwplay >= DS_HEL_FRAGS) pwplay = 0;
-		/* write new values */
-		device->pwplay = pwplay;
+
+		/* update queue */
 		device->pwqueue--;
-		/* queue new buffer if we have data for it */
-		if (inq>1) DSOUND_WaveQueue(device, inq-1);
-#ifdef SYNC_CALLBACK
-		LeaveCriticalSection(&(device->mixlock));
-#endif
+	
+		LeaveCriticalSection(&(device->mixlock));	
+		/* **** */
 	}
 	TRACE("completed\n");
 }
diff --git a/dlls/dsound/primary.c b/dlls/dsound/primary.c
index 3e3fce4..7449ac3 100644
--- a/dlls/dsound/primary.c
+++ b/dlls/dsound/primary.c
@@ -82,12 +82,14 @@ static HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device)
 		waveOutPause(device->hwo);
 		if (device->state == STATE_PLAYING) device->state = STATE_STARTING;
 		else if (device->state == STATE_STOPPING) device->state = STATE_STOPPED;
-		/* use fragments of 10ms (1/100s) each (which should get us within
-		 * the documented write cursor lead of 10-15ms) */
-		buflen = ((device->pwfx->nSamplesPerSec / 100) * device->pwfx->nBlockAlign) * DS_HEL_FRAGS;
+		
+		/* on original windows, the buffer it set to a fixed size, no matter what the settings are.
+		   on windows this size is always fixed (tested on win-xp) */ 
+		buflen = DS_HEL_BUFLEN;
+		
 		TRACE("desired buflen=%d, old buffer=%p\n", buflen, device->buffer);
+		
 		/* reallocate emulated primary buffer */
-
 		if (device->buffer)
 			newbuf = HeapReAlloc(GetProcessHeap(),0,device->buffer,buflen);
 		else
@@ -106,6 +108,11 @@ static HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device)
 
 			device->fraglen = device->buflen / DS_HEL_FRAGS;
 
+			/* sanity */
+			if(device->buflen % DS_HEL_FRAGS){
+				ERR("Bad DS_HEL_FRAGS resolution\n");
+			}
+
 			/* prepare fragment headers */
 			for (c=0; c<DS_HEL_FRAGS; c++) {
 				device->pwave[c]->lpData = (char*)device->buffer + c*device->fraglen;
@@ -128,7 +135,6 @@ static HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device)
 			device->mixpos = 0;
 			FillMemory(device->buffer, device->buflen, (device->pwfx->wBitsPerSample == 8) ? 128 : 0);
 			TRACE("fraglen=%d\n", device->fraglen);
-			DSOUND_WaveQueue(device, (DWORD)-1);
 		}
 		if ((err == DS_OK) && (merr != DS_OK))
 			err = merr;
@@ -160,11 +166,18 @@ static void DSOUND_PrimaryClose(DirectSoundDevice *device)
 	/* are we using waveOut stuff? */
 	if (!device->hwbuf) {
 		unsigned c;
-
+		
+		/* get out of CS when calling the wave system */	
+		LeaveCriticalSection(&(device->mixlock));
+		/* **** */
 		device->pwqueue = (DWORD)-1; /* resetting queues */
 		waveOutReset(device->hwo);
 		for (c=0; c<DS_HEL_FRAGS; c++)
 			waveOutUnprepareHeader(device->hwo, device->pwave[c], sizeof(WAVEHDR));
+		/* **** */
+		EnterCriticalSection(&(device->mixlock));
+
+		/* clear the queue */
 		device->pwqueue = 0;
 	} else {
 		if (IDsDriverBuffer_Release(device->hwbuf) == 0)
@@ -224,8 +237,9 @@ HRESULT DSOUND_PrimaryDestroy(DirectSoundDevice *device)
 {
 	TRACE("(%p)\n", device);
 
-        EnterCriticalSection(&(device->mixlock));
-
+	/* **** */
+	EnterCriticalSection(&(device->mixlock));
+	
 	DSOUND_PrimaryClose(device);
 	if (device->driver) {
 		if (device->hwbuf) {
@@ -240,7 +254,10 @@ HRESULT DSOUND_PrimaryDestroy(DirectSoundDevice *device)
 	}
         HeapFree(GetProcessHeap(),0,device->pwfx);
         device->pwfx=NULL;
-        LeaveCriticalSection(&(device->mixlock));
+
+	LeaveCriticalSection(&(device->mixlock));
+	/* **** */
+
 	return DS_OK;
 }
 
@@ -267,7 +284,6 @@ HRESULT DSOUND_PrimaryStop(DirectSoundDevice *device)
 	HRESULT err = DS_OK;
 	TRACE("(%p)\n", device);
 
-	EnterCriticalSection(&(device->mixlock));
 	if (device->hwbuf) {
 		err = IDsDriverBuffer_Stop(device->hwbuf);
 		if (err == DSERR_BUFFERLOST) {
@@ -296,11 +312,20 @@ HRESULT DSOUND_PrimaryStop(DirectSoundDevice *device)
 			WARN("IDsDriverBuffer_Stop failed\n");
 		}
 	} else {
+	
+		/* dont call the wave system with the lock set */	
+		LeaveCriticalSection(&(device->mixlock));
+		/* **** */
+
 		err = mmErr(waveOutPause(device->hwo));
+
+		/* **** */
+		EnterCriticalSection(&(device->mixlock));
+
 		if (err != DS_OK)
 			WARN("waveOutPause failed\n");
 	}
-	LeaveCriticalSection(&(device->mixlock));
+	
 	return err;
 }
 
@@ -315,19 +340,20 @@ HRESULT DSOUND_PrimaryGetPosition(DirectSoundDevice *device, LPDWORD playpos, LP
 			return err;
 		}
 	} else {
+
+		/* check if playpos was requested */
 		if (playpos) {
-			MMTIME mtime;
-			mtime.wType = TIME_BYTES;
-			waveOutGetPosition(device->hwo, &mtime, sizeof(mtime));
-			mtime.u.cb = mtime.u.cb % device->buflen;
-			*playpos = mtime.u.cb;
+			/* use the cached play position */
+			*playpos = device->pwplay * device->fraglen;
 		}
+
+		/* check if writepos was requested */
 		if (writepos) {
-			/* the writepos should only be used by apps with WRITEPRIMARY priority,
-			 * in which case our software mixer is disabled anyway */
-			*writepos = (device->pwplay + ds_hel_margin) * device->fraglen;
-			while (*writepos >= device->buflen)
-				*writepos -= device->buflen;
+			TRACE("pwplay=%i, pwqueue=%i\n", device->pwplay, device->pwqueue);
+
+			/* the writepos is the first non-queued position */
+			*writepos = (device->pwplay + device->pwqueue) * device->fraglen;
+			*writepos %= device->buflen;
 		}
 	}
 	TRACE("playpos = %d, writepos = %d (%p, time=%d)\n", playpos?*playpos:0, writepos?*writepos:0, device, GetTickCount());
@@ -607,6 +633,9 @@ static HRESULT WINAPI PrimaryBufferImpl_GetCurrentPosition(
         DirectSoundDevice *device = ((PrimaryBufferImpl *)iface)->device;
 	TRACE("(%p,%p,%p)\n", iface, playpos, writepos);
 
+	/* **** */
+	EnterCriticalSection(&(device->mixlock));
+
 	hres = DSOUND_PrimaryGetPosition(device, playpos, writepos);
 	if (hres != DS_OK) {
 		WARN("DSOUND_PrimaryGetPosition failed\n");
@@ -618,6 +647,10 @@ static HRESULT WINAPI PrimaryBufferImpl_GetCurrentPosition(
 			*writepos += device->writelead;
 		while (*writepos >= device->buflen) *writepos -= device->buflen;
 	}
+
+	LeaveCriticalSection(&(device->mixlock));
+	/* **** */
+
 	TRACE("playpos = %d, writepos = %d (%p, time=%d)\n", playpos?*playpos:0, writepos?*writepos:0, device, GetTickCount());
 	return DS_OK;
 }
diff --git a/dlls/dsound/sound3d.c b/dlls/dsound/sound3d.c
index 2ee050d..f6ae455 100644
--- a/dlls/dsound/sound3d.c
+++ b/dlls/dsound/sound3d.c
@@ -192,7 +192,6 @@ void DSOUND_Calc3DBuffer(IDirectSoundBufferImpl *dsb)
 			TRACE("3D processing disabled\n");
 			/* this one is here only to eliminate annoying warning message */
 			DSOUND_RecalcVolPan (&dsb->volpan);
-			DSOUND_ForceRemix (dsb);
 			break;
 		case DS3DMODE_NORMAL:
 			TRACE("Normal 3D processing mode\n");
@@ -319,7 +318,6 @@ static void DSOUND_Mix3DBuffer(IDirectSoundBufferImpl *dsb)
 	TRACE("(%p)\n",dsb);
 
 	DSOUND_Calc3DBuffer(dsb);
-	DSOUND_ForceRemix(dsb);			
 }
 
 static void DSOUND_ChangeListener(IDirectSound3DListenerImpl *ds3dl)
@@ -332,6 +330,8 @@ static void DSOUND_ChangeListener(IDirectSound3DListenerImpl *ds3dl)
 		crash without the following line) */
 		if (ds3dl->device->buffers[i]->ds3db == NULL)
 			continue;
+
+		/* check if this buffer is waiting for recalculation */
 		if (ds3dl->device->buffers[i]->ds3db_need_recalc)
 		{
 			DSOUND_Mix3DBuffer(ds3dl->device->buffers[i]);
-- 
1.4.4.2



More information about the wine-patches mailing list