Dsound from win 2004 month 12 or month 11. It is working in windows 2000 in software emulation mode. Tested with quake2 and some other apps. Not tested in ReactOS
Added: trunk/reactos/lib/dsound/buffer.c
Added: trunk/reactos/lib/dsound/capture.c
Modified: trunk/reactos/lib/dsound/dsound.c
Deleted: trunk/reactos/lib/dsound/dsound.def
Added: trunk/reactos/lib/dsound/dsound.spec
Modified: trunk/reactos/lib/dsound/dsound.xml
Added: trunk/reactos/lib/dsound/dsound_main.c
Added: trunk/reactos/lib/dsound/dsound_private.h
Added: trunk/reactos/lib/dsound/dxroslayer/
Added: trunk/reactos/lib/dsound/dxroslayer/dxros_layer.h
Added: trunk/reactos/lib/dsound/dxroslayer/dxrosdrv_querydsounddesc.c
Added: trunk/reactos/lib/dsound/dxroslayer/dxrosdrv_querydsoundiface.c
Added: trunk/reactos/lib/dsound/dxroslayer/dxroslayer.c
Added: trunk/reactos/lib/dsound/dxroslayer/getguidfromstring.c
Added: trunk/reactos/lib/dsound/mixer.c
Added: trunk/reactos/lib/dsound/primary.c
Added: trunk/reactos/lib/dsound/propset.c
Added: trunk/reactos/lib/dsound/regsvr.c
Added: trunk/reactos/lib/dsound/sound3d.c
Added: trunk/reactos/lib/dsound/tests/
Added: trunk/reactos/lib/dsound/tests/.cvsignore
Added: trunk/reactos/lib/dsound/tests/Makefile.in
Added: trunk/reactos/lib/dsound/tests/capture.c
Added: trunk/reactos/lib/dsound/tests/ds3d.c
Added: trunk/reactos/lib/dsound/tests/ds3d8.c
Added: trunk/reactos/lib/dsound/tests/dsound.c
Added: trunk/reactos/lib/dsound/tests/dsound8.c
Added: trunk/reactos/lib/dsound/tests/dsound_test.h
Added: trunk/reactos/lib/dsound/tests/propset.c
Added: trunk/reactos/lib/dsound/version.rc

Added: trunk/reactos/lib/dsound/buffer.c
--- trunk/reactos/lib/dsound/buffer.c	2005-10-08 16:26:04 UTC (rev 18338)
+++ trunk/reactos/lib/dsound/buffer.c	2005-10-08 16:38:07 UTC (rev 18339)
@@ -0,0 +1,1562 @@
+/*  			DirectSound
+ *
+ * Copyright 1998 Marcus Meissner
+ * Copyright 1998 Rob Riggs
+ * Copyright 2000-2002 TransGaming Technologies, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "config.h"
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/fcntl.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#define NONAMELESSSTRUCT
+#define NONAMELESSUNION
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "winerror.h"
+#include "mmsystem.h"
+#include "winreg.h"
+#include "winternl.h"
+#include "mmddk.h"
+#include "wine/windef16.h"
+#include "wine/debug.h"
+#include "dsound.h"
+#include "dsdriver.h"
+#include "dsound_private.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(dsound);
+
+/*******************************************************************************
+ *		IDirectSoundNotify
+ */
+static HRESULT WINAPI IDirectSoundNotifyImpl_QueryInterface(
+	LPDIRECTSOUNDNOTIFY iface,REFIID riid,LPVOID *ppobj
+) {
+	IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface;
+	TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
+
+	if (This->dsb == NULL) {
+		WARN("invalid parameter\n");
+		return E_INVALIDARG;
+	}
+
+	return IDirectSoundBuffer_QueryInterface((LPDIRECTSOUNDBUFFER)This->dsb, riid, ppobj);
+}
+
+static ULONG WINAPI IDirectSoundNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface)
+{
+	IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface;
+	TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
+	return InterlockedIncrement(&(This->ref));
+}
+
+static ULONG WINAPI IDirectSoundNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface) {
+	IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface;
+	ULONG ref;
+
+	TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
+
+	ref = InterlockedDecrement(&(This->ref));
+	if (ref == 0) {
+		IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)This->dsb);
+		This->dsb->notify = NULL;
+		HeapFree(GetProcessHeap(),0,This);
+		TRACE("(%p) released\n",This);
+	}
+	return ref;
+}
+
+static HRESULT WINAPI IDirectSoundNotifyImpl_SetNotificationPositions(
+	LPDIRECTSOUNDNOTIFY iface,DWORD howmuch,LPCDSBPOSITIONNOTIFY notify
+) {
+	IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface;
+	TRACE("(%p,0x%08lx,%p)\n",This,howmuch,notify);
+
+        if (howmuch > 0 && notify == NULL) {
+	    WARN("invalid parameter: notify == NULL\n");
+	    return DSERR_INVALIDPARAM;
+	}
+
+	if (TRACE_ON(dsound)) {
+	    unsigned int	i;
+	    for (i=0;i<howmuch;i++)
+		TRACE("notify at %ld to 0x%08lx\n",
+		    notify[i].dwOffset,(DWORD)notify[i].hEventNotify);
+	}
+
+	if (This->dsb->hwnotify) {
+	    HRESULT hres;
+	    hres = IDsDriverNotify_SetNotificationPositions(This->dsb->hwnotify, howmuch, notify);
+	    if (hres != DS_OK)
+		    WARN("IDsDriverNotify_SetNotificationPositions failed\n");
+	    return hres;
+        } else if (howmuch > 0) {
+	    /* Make an internal copy of the caller-supplied array.
+	     * Replace the existing copy if one is already present. */
+	    if (This->dsb->notifies)
+		    This->dsb->notifies = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+			This->dsb->notifies, howmuch * sizeof(DSBPOSITIONNOTIFY));
+	    else
+		    This->dsb->notifies = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+			howmuch * sizeof(DSBPOSITIONNOTIFY));
+
+	    if (This->dsb->notifies == NULL) {
+		    WARN("out of memory\n");
+		    return DSERR_OUTOFMEMORY;
+	    }
+	    memcpy(This->dsb->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY));
+	    This->dsb->nrofnotifies = howmuch;
+        } else {
+           if (This->dsb->notifies) {
+               HeapFree(GetProcessHeap(), 0, This->dsb->notifies);
+               This->dsb->notifies = NULL;
+           }
+           This->dsb->nrofnotifies = 0;
+        }
+
+	return S_OK;
+}
+
+IDirectSoundNotifyVtbl dsnvt =
+{
+    IDirectSoundNotifyImpl_QueryInterface,
+    IDirectSoundNotifyImpl_AddRef,
+    IDirectSoundNotifyImpl_Release,
+    IDirectSoundNotifyImpl_SetNotificationPositions,
+};
+
+HRESULT WINAPI IDirectSoundNotifyImpl_Create(
+    IDirectSoundBufferImpl * dsb,
+    IDirectSoundNotifyImpl **pdsn)
+{
+    IDirectSoundNotifyImpl * dsn;
+    TRACE("(%p,%p)\n",dsb,pdsn);
+
+    dsn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(dsn));
+
+    if (dsn == NULL) {
+        WARN("out of memory\n");
+        return DSERR_OUTOFMEMORY;
+    }
+
+    dsn->ref = 0;
+    dsn->lpVtbl = &dsnvt;
+    dsn->dsb = dsb;
+    dsb->notify = dsn;
+    IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)dsb);
+
+    *pdsn = dsn;
+    return DS_OK;
+}
+
+HRESULT WINAPI IDirectSoundNotifyImpl_Destroy(
+    IDirectSoundNotifyImpl *pdsn)
+{
+    TRACE("(%p)\n",pdsn);
+
+    while (IDirectSoundNotifyImpl_Release((LPDIRECTSOUNDNOTIFY)pdsn) > 0);
+
+    return DS_OK;
+}
+
+/*******************************************************************************
+ *		IDirectSoundBuffer
+ */
+
+static HRESULT WINAPI IDirectSoundBufferImpl_SetFormat(
+	LPDIRECTSOUNDBUFFER8 iface,LPCWAVEFORMATEX wfex
+) {
+	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
+
+	TRACE("(%p,%p)\n",This,wfex);
+	/* This method is not available on secondary buffers */
+	WARN("invalid call\n");
+	return DSERR_INVALIDCALL;
+}
+
+static HRESULT WINAPI IDirectSoundBufferImpl_SetVolume(
+	LPDIRECTSOUNDBUFFER8 iface,LONG vol
+) {
+	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
+	LONG oldVol;
+	HRESULT hres = DS_OK;
+
+	TRACE("(%p,%ld)\n",This,vol);
+
+	if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) {
+		WARN("control unavailable: This->dsbd.dwFlags = 0x%08lx\n", This->dsbd.dwFlags);
+		return DSERR_CONTROLUNAVAIL;
+	}
+
+	if ((vol > DSBVOLUME_MAX) || (vol < DSBVOLUME_MIN)) {
+		WARN("invalid parameter: vol = %ld\n", vol);
+		return DSERR_INVALIDPARAM;
+	}
+
+	/* **** */
+	EnterCriticalSection(&(This->lock));
+
+	if (This->dsbd.dwFlags & DSBCAPS_CTRL3D) {
+		oldVol = This->ds3db_lVolume;
+		This->ds3db_lVolume = vol;
+	} else {
+		oldVol = This->volpan.lVolume;
+		This->volpan.lVolume = vol;
+		if (vol != oldVol)
+			DSOUND_RecalcVolPan(&(This->volpan));
+	}
+
+	if (vol != oldVol) {
+		if (This->hwbuf) {
+			hres = IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan));
+	    		if (hres != DS_OK)
+		    		WARN("IDsDriverBuffer_SetVolumePan failed\n");
+		} else
+			DSOUND_ForceRemix(This);
+	}
+
+	LeaveCriticalSection(&(This->lock));
+	/* **** */
+
+	return hres;
+}
+
+static HRESULT WINAPI IDirectSoundBufferImpl_GetVolume(
+	LPDIRECTSOUNDBUFFER8 iface,LPLONG vol
+) {
+	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
+	TRACE("(%p,%p)\n",This,vol);
+
+	if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) {
+		WARN("control unavailable\n");
+		return DSERR_CONTROLUNAVAIL;
+	}
+
+	if (vol == NULL) {
+		WARN("invalid parameter: vol == NULL\n");
+		return DSERR_INVALIDPARAM;
+	}
+
+	*vol = This->volpan.lVolume;
+
+	return DS_OK;
+}
+
+static HRESULT WINAPI IDirectSoundBufferImpl_SetFrequency(
+	LPDIRECTSOUNDBUFFER8 iface,DWORD freq
+) {
+	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
+	DWORD oldFreq;
+
+	TRACE("(%p,%ld)\n",This,freq);
+
+	if (!(This->dsbd.dwFlags & DSBCAPS_CTRLFREQUENCY)) {
+		WARN("control unavailable\n");
+		return DSERR_CONTROLUNAVAIL;
+	}
+
+	if (freq == DSBFREQUENCY_ORIGINAL)
+		freq = This->pwfx->nSamplesPerSec;
+
+	if ((freq < DSBFREQUENCY_MIN) || (freq > DSBFREQUENCY_MAX)) {
+		WARN("invalid parameter: freq = %ld\n", freq);
+		return DSERR_INVALIDPARAM;
+	}
+
+	/* **** */
+	EnterCriticalSection(&(This->lock));
+
+	oldFreq = This->freq;
+	This->freq = freq;
+	if (freq != oldFreq) {
+		This->freqAdjust = (freq << DSOUND_FREQSHIFT) / This->dsound->pwfx->nSamplesPerSec;
+		This->nAvgBytesPerSec = freq * This->pwfx->nBlockAlign;
+		DSOUND_RecalcFormat(This);
+		if (!This->hwbuf)
+			DSOUND_ForceRemix(This);
+	}
+
+	LeaveCriticalSection(&(This->lock));
+	/* **** */
+
+	return DS_OK;
+}
+
+static HRESULT WINAPI IDirectSoundBufferImpl_Play(
+	LPDIRECTSOUNDBUFFER8 iface,DWORD reserved1,DWORD reserved2,DWORD flags
+) {
+	HRESULT hres = DS_OK;
+	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
+	TRACE("(%p,%08lx,%08lx,%08lx)\n",This,reserved1,reserved2,flags);
+
+	/* **** */
+	EnterCriticalSection(&(This->lock));
+
+	This->playflags = flags;
+	if (This->state == STATE_STOPPED) {
+		This->leadin = TRUE;
+		This->startpos = This->buf_mixpos;
+		This->state = STATE_STARTING;
+	} else if (This->state == STATE_STOPPING)
+		This->state = STATE_PLAYING;
+	if (This->hwbuf) {
+		hres = IDsDriverBuffer_Play(This->hwbuf, 0, 0, This->playflags);
+		if (hres != DS_OK)
+			WARN("IDsDriverBuffer_Play failed\n");
+		else
+			This->state = STATE_PLAYING;
+	}
+
+	LeaveCriticalSection(&(This->lock));
+	/* **** */
+
+	return hres;
+}
+
+static HRESULT WINAPI IDirectSoundBufferImpl_Stop(LPDIRECTSOUNDBUFFER8 iface)
+{
+	HRESULT hres = DS_OK;
+	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
+	TRACE("(%p)\n",This);
+
+	/* **** */
+	EnterCriticalSection(&(This->lock));
+
+	if (This->state == STATE_PLAYING)
+		This->state = STATE_STOPPING;
+	else if (This->state == STATE_STARTING)
+		This->state = STATE_STOPPED;
+	if (This->hwbuf) {
+		hres = IDsDriverBuffer_Stop(This->hwbuf);
+		if (hres != DS_OK)
+			WARN("IDsDriverBuffer_Stop failed\n");
+		else
+			This->state = STATE_STOPPED;
+	}
+	DSOUND_CheckEvent(This, 0);
+
+	LeaveCriticalSection(&(This->lock));
+	/* **** */
+
+	return hres;
+}
+
+static ULONG WINAPI IDirectSoundBufferImpl_AddRef(LPDIRECTSOUNDBUFFER8 iface)
+{
+	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
+	TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
+	return InterlockedIncrement(&(This->ref));
+}
+
+static ULONG WINAPI IDirectSoundBufferImpl_Release(LPDIRECTSOUNDBUFFER8 iface)
+{
+	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
+	ULONG ref;
+
+	TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
+
+	ref = InterlockedDecrement(&(This->ref));
+	if (ref)
+		return ref;
+
+	DSOUND_RemoveBuffer(This->dsound, This);
+
+	This->lock.DebugInfo->Spare[1] = 0;
+	DeleteCriticalSection(&(This->lock));
+
+	if (This->hwbuf) {
+		IDsDriverBuffer_Release(This->hwbuf);
+		if (This->dsound->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) {
+			This->buffer->ref--;
+			if (This->buffer->ref==0) {
+				HeapFree(GetProcessHeap(),0,This->buffer->memory);
+				HeapFree(GetProcessHeap(),0,This->buffer);
+			}
+		}
+	} else {
+		This->buffer->ref--;
+		if (This->buffer->ref==0) {
+			HeapFree(GetProcessHeap(),0,This->buffer->memory);
+			HeapFree(GetProcessHeap(),0,This->buffer);
+		}
+	}
+
+	if (This->notifies != NULL)
+		HeapFree(GetProcessHeap(), 0, This->notifies);
+
+	if (This->pwfx)
+		HeapFree(GetProcessHeap(), 0, This->pwfx);
+
+	HeapFree(GetProcessHeap(),0,This);
+
+	TRACE("(%p) released\n",This);
+	return 0;
+}
+
+DWORD DSOUND_CalcPlayPosition(IDirectSoundBufferImpl *This,
+			      DWORD state, DWORD pplay, DWORD pwrite, DWORD pmix, DWORD bmix)
+{
+	DWORD bplay;
+
+	TRACE("primary playpos=%ld, mixpos=%ld\n", pplay, pmix);
+	TRACE("this mixpos=%ld, time=%ld\n", bmix, GetTickCount());
+
+	/* the actual primary play position (pplay) is always behind last mixed (pmix),
+	 * unless the computer is too slow or something */
+	/* we need to know how far away we are from there */
+#if 0 /* we'll never fill the primary entirely */
+	if (pmix == pplay) {
+		if ((state == STATE_PLAYING) || (state == STATE_STOPPING)) {
+			/* wow, the software mixer is really doing well,
+			 * seems the entire primary buffer is filled! */
+			pmix += This->dsound->buflen;
+		}
+		/* else: the primary buffer is not playing, so probably empty */
+	}
+#endif
+	if (pmix < pplay) pmix += This->dsound->buflen; /* wraparound */
+	pmix -= pplay;
+	/* detect buffer underrun */
+	if (pwrite < pplay) pwrite += This->dsound->buflen; /* wraparound */
+	pwrite -= pplay;
+	if (pmix > (ds_snd_queue_max * This->dsound->fraglen + pwrite + This->dsound->writelead)) {
+		WARN("detected an underrun: primary queue was %ld\n",pmix);
+		pmix = 0;
+	}
+	/* divide the offset by its sample size */
+	pmix /= This->dsound->pwfx->nBlockAlign;
+	TRACE("primary back-samples=%ld\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=%ld\n", pmix);
+	/* subtract from our last mixed position */
+	bplay = bmix;
+	while (bplay < pmix) bplay += This->buflen; /* wraparound */
+	bplay -= pmix;
+	if (This->leadin && ((bplay < This->startpos) || (bplay > bmix))) {
+		/* seems we haven't started playing yet */
+		TRACE("this still in lead-in phase\n");
+		bplay = This->startpos;
+	}
+	/* return the result */
+	return bplay;
+}
+
+static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition(
+	LPDIRECTSOUNDBUFFER8 iface,LPDWORD playpos,LPDWORD writepos
+) {
+	HRESULT	hres;
+	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
+	TRACE("(%p,%p,%p)\n",This,playpos,writepos);
+	if (This->hwbuf) {
+		hres=IDsDriverBuffer_GetPosition(This->hwbuf,playpos,writepos);
+		if (hres != DS_OK) {
+		    WARN("IDsDriverBuffer_GetPosition failed\n");
+		    return hres;
+		}
+	} else {
+		if (playpos && (This->state != STATE_PLAYING)) {
+			/* we haven't been merged into the primary buffer (yet) */
+			*playpos = This->buf_mixpos;
+		} else if (playpos) {
+			DWORD pplay, pwrite, lplay, splay, pstate;
+			/* let's get this exact; first, recursively call GetPosition on the primary */
+			EnterCriticalSection(&(This->dsound->mixlock));
+			if (DSOUND_PrimaryGetPosition(This->dsound, &pplay, &pwrite) != DS_OK)
+				WARN("DSOUND_PrimaryGetPosition failed\n");
+			/* detect HEL mode underrun */
+			pstate = This->dsound->state;
+			if (!(This->dsound->hwbuf || This->dsound->pwqueue)) {
+				TRACE("detected an underrun\n");
+				/* pplay = ? */
+				if (pstate == STATE_PLAYING)
+					pstate = STATE_STARTING;
+				else if (pstate == STATE_STOPPING)
+					pstate = STATE_STOPPED;
+			}
+			/* get data for ourselves while we still have the lock */
+			pstate &= This->state;
+			lplay = This->primary_mixpos;
+			splay = This->buf_mixpos;
+			if ((This->dsbd.dwFlags & DSBCAPS_GETCURRENTPOSITION2) || This->dsound->hwbuf) {
+				/* calculate play position using this */
+				*playpos = DSOUND_CalcPlayPosition(This, pstate, pplay, pwrite, lplay, splay);
+			} else {
+				/* (unless the app isn't using GETCURRENTPOSITION2) */
+				/* don't know exactly how this should be handled...
+				 * the docs says that play cursor is reported as directly
+				 * behind write cursor, hmm... */
+				/* let's just do what might work for Half-Life */
+				DWORD wp;
+				wp = (This->dsound->pwplay + ds_hel_margin) * This->dsound->fraglen;
+				wp %= This->dsound->buflen;
+				*playpos = DSOUND_CalcPlayPosition(This, pstate, wp, pwrite, lplay, splay);
+			}
+			LeaveCriticalSection(&(This->dsound->mixlock));
+		}
+		if (writepos)
+                    *writepos = This->buf_mixpos;
+	}
+	if (writepos) {
+		if (This->state != STATE_STOPPED) {
+			/* apply the documented 10ms lead to writepos */
+			*writepos += This->writelead;
+		}
+		*writepos %= This->buflen;
+	}
+	if (playpos)
+            This->last_playpos = *playpos;
+	TRACE("playpos = %ld, writepos = %ld (%p, time=%ld)\n", playpos?*playpos:0, writepos?*writepos:0, This, GetTickCount());
+	return DS_OK;
+}
+
+static HRESULT WINAPI IDirectSoundBufferImpl_GetStatus(
+	LPDIRECTSOUNDBUFFER8 iface,LPDWORD status
+) {
+	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
+	TRACE("(%p,%p), thread is %04lx\n",This,status,GetCurrentThreadId());
+
+	if (status == NULL) {
+		WARN("invalid parameter: status = NULL\n");
+		return DSERR_INVALIDPARAM;
+	}
+
+	*status = 0;
+	if ((This->state == STATE_STARTING) || (This->state == STATE_PLAYING)) {
+		*status |= DSBSTATUS_PLAYING;
+		if (This->playflags & DSBPLAY_LOOPING)
+			*status |= DSBSTATUS_LOOPING;
+	}
+
+	TRACE("status=%lx\n", *status);
+	return DS_OK;
+}
+
+
+static HRESULT WINAPI IDirectSoundBufferImpl_GetFormat(
+    LPDIRECTSOUNDBUFFER8 iface,
+    LPWAVEFORMATEX lpwf,
+    DWORD wfsize,
+    LPDWORD wfwritten)
+{
+    DWORD size;
+    IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
+    TRACE("(%p,%p,%ld,%p)\n",This,lpwf,wfsize,wfwritten);
+
+    size = sizeof(WAVEFORMATEX) + This->pwfx->cbSize;
+
+    if (lpwf) { /* NULL is valid */
+        if (wfsize >= size) {
+            memcpy(lpwf,This->pwfx,size);
+            if (wfwritten)
+                *wfwritten = size;
+        } else {
+            WARN("invalid parameter: wfsize to small\n");
+            if (wfwritten)
+                *wfwritten = 0;
+            return DSERR_INVALIDPARAM;
+        }
+    } else {
+        if (wfwritten)
+            *wfwritten = sizeof(WAVEFORMATEX) + This->pwfx->cbSize;
+        else {
+            WARN("invalid parameter: wfwritten == NULL\n");
+            return DSERR_INVALIDPARAM;
+        }
+    }
+
+    return DS_OK;
+}
+
+static HRESULT WINAPI IDirectSoundBufferImpl_Lock(
+	LPDIRECTSOUNDBUFFER8 iface,DWORD writecursor,DWORD writebytes,LPVOID lplpaudioptr1,LPDWORD audiobytes1,LPVOID lplpaudioptr2,LPDWORD audiobytes2,DWORD flags
+) {
+	HRESULT hres = DS_OK;
+	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
+
+	TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx) at %ld\n",
+		This,
+		writecursor,
+		writebytes,
+		lplpaudioptr1,
+		audiobytes1,
+		lplpaudioptr2,
+		audiobytes2,
+		flags,
+		GetTickCount()
+	);
+
+	if (flags & DSBLOCK_FROMWRITECURSOR) {
+		DWORD writepos;
+		/* GetCurrentPosition does too much magic to duplicate here */
+		hres = IDirectSoundBufferImpl_GetCurrentPosition(iface, NULL, &writepos);
+		if (hres != DS_OK) {
+			WARN("IDirectSoundBufferImpl_GetCurrentPosition failed\n");
+			return hres;
+		}
+		writecursor += writepos;
+	}
+	writecursor %= This->buflen;
+	if (flags & DSBLOCK_ENTIREBUFFER)
+		writebytes = This->buflen;
+	if (writebytes > This->buflen)
+		writebytes = This->buflen;
+
+	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->dsound->drvdesc.dwFlags & DSDDESC_DONTNEEDSECONDARYLOCK) && This->hwbuf) {
+		hres = IDsDriverBuffer_Lock(This->hwbuf,
+				     lplpaudioptr1, audiobytes1,
+				     lplpaudioptr2, audiobytes2,
+				     writecursor, writebytes,
+				     0);
+		if (hres != DS_OK) {
+			WARN("IDsDriverBuffer_Lock failed\n");
+			LeaveCriticalSection(&(This->lock));
+			return hres;
+		}
+	} else {
+		BOOL remix = FALSE;
+		if (writecursor+writebytes <= This->buflen) {
+			*(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
+			*audiobytes1 = writebytes;
+			if (lplpaudioptr2)
+				*(LPBYTE*)lplpaudioptr2 = NULL;
+			if (audiobytes2)
+				*audiobytes2 = 0;
+			TRACE("->%ld.0\n",writebytes);
+		} else {
+			*(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
+			*audiobytes1 = This->buflen-writecursor;
+			if (lplpaudioptr2)
+				*(LPBYTE*)lplpaudioptr2 = This->buffer->memory;
+			if (audiobytes2)
+				*audiobytes2 = writebytes-(This->buflen-writecursor);
+			TRACE("->%ld.%ld\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);
+			}
+		}
+	}
+
+	LeaveCriticalSection(&(This->lock));
+	return DS_OK;
+}
+
+static HRESULT WINAPI IDirectSoundBufferImpl_SetCurrentPosition(
+	LPDIRECTSOUNDBUFFER8 iface,DWORD newpos
+) {
+	HRESULT hres = DS_OK;
+	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
+	TRACE("(%p,%ld)\n",This,newpos);
+
+	/* **** */
+	EnterCriticalSection(&(This->lock));
+
+	newpos %= This->buflen;
+	This->buf_mixpos = newpos;
+	if (This->hwbuf) {
+		hres = IDsDriverBuffer_SetPosition(This->hwbuf, This->buf_mixpos);
+		if (hres != DS_OK)
+			WARN("IDsDriverBuffer_SetPosition failed\n");
+	}
+
+	LeaveCriticalSection(&(This->lock));
+	/* **** */
+
+	return hres;
+}
+
+static HRESULT WINAPI IDirectSoundBufferImpl_SetPan(
+	LPDIRECTSOUNDBUFFER8 iface,LONG pan
+) {
+	HRESULT hres = DS_OK;
+	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
+
+	TRACE("(%p,%ld)\n",This,pan);
+
+	if ((pan > DSBPAN_RIGHT) || (pan < DSBPAN_LEFT)) {
+		WARN("invalid parameter: pan = %ld\n", pan);
+		return DSERR_INVALIDPARAM;
+	}
+
+	/* You cannot use both pan and 3D controls */
+	if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN) ||
+	    (This->dsbd.dwFlags & DSBCAPS_CTRL3D)) {
+		WARN("control unavailable\n");
+		return DSERR_CONTROLUNAVAIL;
+	}
+
+	/* **** */
+	EnterCriticalSection(&(This->lock));
+
+	if (This->volpan.lPan != pan) {
+		This->volpan.lPan = pan;
+		DSOUND_RecalcVolPan(&(This->volpan));
+
+		if (This->hwbuf) {
+			hres = IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan));
+			if (hres != DS_OK)
+				WARN("IDsDriverBuffer_SetVolumePan failed\n");
+		} else
+			DSOUND_ForceRemix(This);
+	}
+
+	LeaveCriticalSection(&(This->lock));
+	/* **** */
+
+	return hres;
+}
+
+static HRESULT WINAPI IDirectSoundBufferImpl_GetPan(
+	LPDIRECTSOUNDBUFFER8 iface,LPLONG pan
+) {
+	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
+	TRACE("(%p,%p)\n",This,pan);
+
+	if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN)) {
+		WARN("control unavailable\n");
+		return DSERR_CONTROLUNAVAIL;
+	}
+
+	if (pan == NULL) {
+		WARN("invalid parameter: pan = NULL\n");
+		return DSERR_INVALIDPARAM;
+	}
+
+	*pan = This->volpan.lPan;
+
+	return DS_OK;
+}
+
+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,%ld,%p,%ld)\n", This,p1,x1,p2,x2);
+
+	/* **** */
+	EnterCriticalSection(&(This->lock));
+
+	if (!(This->dsound->drvdesc.dwFlags & DSDDESC_DONTNEEDSECONDARYLOCK) && This->hwbuf) {
+		hres = IDsDriverBuffer_Unlock(This->hwbuf, p1, x1, p2, x2);
+		if (hres != DS_OK)
+			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=%ld\n", This->probably_valid_to);
+	return hres;
+}
+
+static HRESULT WINAPI IDirectSoundBufferImpl_Restore(
+	LPDIRECTSOUNDBUFFER8 iface
+) {
+	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
+	FIXME("(%p):stub\n",This);
+	return DS_OK;
+}
+
+static HRESULT WINAPI IDirectSoundBufferImpl_GetFrequency(
+	LPDIRECTSOUNDBUFFER8 iface,LPDWORD freq
+) {
+	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
+	TRACE("(%p,%p)\n",This,freq);
+
+	if (freq == NULL) {
+		WARN("invalid parameter: freq = NULL\n");
+		return DSERR_INVALIDPARAM;
+	}
+
+	*freq = This->freq;
+	TRACE("-> %ld\n", *freq);
+
+	return DS_OK;
+}
+
+static HRESULT WINAPI IDirectSoundBufferImpl_SetFX(
+	LPDIRECTSOUNDBUFFER8 iface,DWORD dwEffectsCount,LPDSEFFECTDESC pDSFXDesc,LPDWORD pdwResultCodes
+) {
+	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
+	DWORD u;
+
+	FIXME("(%p,%lu,%p,%p): stub\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes);
+
+	if (pdwResultCodes)
+		for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
+
+	WARN("control unavailable\n");
+	return DSERR_CONTROLUNAVAIL;
+}
+
+static HRESULT WINAPI IDirectSoundBufferImpl_AcquireResources(
+	LPDIRECTSOUNDBUFFER8 iface,DWORD dwFlags,DWORD dwEffectsCount,LPDWORD pdwResultCodes
+) {
+	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
+	DWORD u;
+
+	FIXME("(%p,%08lu,%lu,%p): stub\n",This,dwFlags,dwEffectsCount,pdwResultCodes);
+
+	if (pdwResultCodes)
+		for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
+
+	WARN("control unavailable\n");
+	return DSERR_CONTROLUNAVAIL;
+}
+
+static HRESULT WINAPI IDirectSoundBufferImpl_GetObjectInPath(
+	LPDIRECTSOUNDBUFFER8 iface,REFGUID rguidObject,DWORD dwIndex,REFGUID rguidInterface,LPVOID* ppObject
+) {
+	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
+
+	FIXME("(%p,%s,%lu,%s,%p): stub\n",This,debugstr_guid(rguidObject),dwIndex,debugstr_guid(rguidInterface),ppObject);
+
+	WARN("control unavailable\n");
+	return DSERR_CONTROLUNAVAIL;
+}
+
+static HRESULT WINAPI IDirectSoundBufferImpl_Initialize(
+	LPDIRECTSOUNDBUFFER8 iface,LPDIRECTSOUND dsound,LPCDSBUFFERDESC dbsd
+) {
+	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
+	FIXME("(%p,%p,%p):stub\n",This,dsound,dbsd);
+	DPRINTF("Re-Init!!!\n");
+	WARN("already initialized\n");
+	return DSERR_ALREADYINITIALIZED;
+}
+
+static HRESULT WINAPI IDirectSoundBufferImpl_GetCaps(
+	LPDIRECTSOUNDBUFFER8 iface,LPDSBCAPS caps
+) {
+	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
+  	TRACE("(%p)->(%p)\n",This,caps);
+
+	if (caps == NULL) {
+		WARN("invalid parameter: caps == NULL\n");
+		return DSERR_INVALIDPARAM;
+	}
+
+	if (caps->dwSize < sizeof(*caps)) {
+		WARN("invalid parameter: caps->dwSize = %ld < %d\n",caps->dwSize, sizeof(*caps));
+		return DSERR_INVALIDPARAM;
+	}
+
+	caps->dwFlags = This->dsbd.dwFlags;
+	if (This->hwbuf) caps->dwFlags |= DSBCAPS_LOCHARDWARE;
+	else caps->dwFlags |= DSBCAPS_LOCSOFTWARE;
+
+	caps->dwBufferBytes = This->buflen;
+
+	/* This value represents the speed of the "unlock" command.
+	   As unlock is quite fast (it does not do anything), I put
+	   4096 ko/s = 4 Mo / s */
+	/* FIXME: hwbuf speed */
+	caps->dwUnlockTransferRate = 4096;
+	caps->dwPlayCpuOverhead = 0;
+
+	return DS_OK;
+}
+
+static HRESULT WINAPI IDirectSoundBufferImpl_QueryInterface(
+	LPDIRECTSOUNDBUFFER8 iface,REFIID riid,LPVOID *ppobj
+) {
+	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
+
+	TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
+
+	if (ppobj == NULL) {
+		WARN("invalid parameter\n");
+		return E_INVALIDARG;
+	}
+
+	*ppobj = NULL;	/* assume failure */
+
+	if ( IsEqualGUID(riid, &IID_IUnknown) ||
+	     IsEqualGUID(riid, &IID_IDirectSoundBuffer) ||
+	     IsEqualGUID(riid, &IID_IDirectSoundBuffer8) ) {
+		if (!This->dsb)
+			SecondaryBufferImpl_Create(This, &(This->dsb));
+		if (This->dsb) {
+			IDirectSoundBuffer8_AddRef((LPDIRECTSOUNDBUFFER8)This->dsb);
+			*ppobj = This->dsb;
+			return S_OK;
+		}
+		WARN("IID_IDirectSoundBuffer\n");
+		return E_NOINTERFACE;
+	}
+
+	if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
+		if (!This->notify)
+			IDirectSoundNotifyImpl_Create(This, &(This->notify));
+		if (This->notify) {
+			IDirectSoundNotify_AddRef((LPDIRECTSOUNDNOTIFY)This->notify);
+			*ppobj = This->notify;
+			return S_OK;
+		}
+		WARN("IID_IDirectSoundNotify\n");
+		return E_NOINTERFACE;
+	}
+
+	if ( IsEqualGUID( &IID_IDirectSound3DBuffer, riid ) ) {
+		if (!This->ds3db)
+			IDirectSound3DBufferImpl_Create(This, &(This->ds3db));
+		if (This->ds3db) {
+			IDirectSound3DBuffer_AddRef((LPDIRECTSOUND3DBUFFER)This->ds3db);
+			*ppobj = This->ds3db;
+			return S_OK;
+		}
+		WARN("IID_IDirectSound3DBuffer\n");
+		return E_NOINTERFACE;
+	}
+
+	if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) {
+		ERR("app requested IDirectSound3DListener on secondary buffer\n");
+		return E_NOINTERFACE;
+	}
+
+	if ( IsEqualGUID( &IID_IKsPropertySet, riid ) ) {
+		if (!This->iks)
+			IKsBufferPropertySetImpl_Create(This, &(This->iks));
+		if (This->iks) {
+			IKsPropertySet_AddRef((LPKSPROPERTYSET)This->iks);
+	    		*ppobj = This->iks;
+			return S_OK;
+		}
[truncated at 1000 lines; 16475 more skipped]