[REACTOS] Fix 64 bit build (#465)
[reactos.git] / dll / directx / wine / dsound / buffer.c
index a574449..e70501f 100644 (file)
  *             IDirectSoundNotify
  */
 
-static inline struct IDirectSoundBufferImpl *impl_from_IDirectSoundNotify(IDirectSoundNotify *iface)
+struct IDirectSoundNotifyImpl
 {
-    return CONTAINING_RECORD(iface, struct IDirectSoundBufferImpl, IDirectSoundNotify_iface);
-}
+    /* IUnknown fields */
+    const IDirectSoundNotifyVtbl *lpVtbl;
+    LONG                        ref;
+    IDirectSoundBufferImpl*     dsb;
+};
 
-static HRESULT WINAPI IDirectSoundNotifyImpl_QueryInterface(IDirectSoundNotify *iface, REFIID riid,
-        void **ppobj)
-{
-    IDirectSoundBufferImpl *This = impl_from_IDirectSoundNotify(iface);
+static HRESULT IDirectSoundNotifyImpl_Create(IDirectSoundBufferImpl *dsb,
+                                             IDirectSoundNotifyImpl **pdsn);
+static HRESULT IDirectSoundNotifyImpl_Destroy(IDirectSoundNotifyImpl *pdsn);
+
+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);
 
-    TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj);
+       if (This->dsb == NULL) {
+               WARN("invalid parameter\n");
+               return E_INVALIDARG;
+       }
 
-    return IDirectSoundBuffer8_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppobj);
+       return IDirectSoundBuffer_QueryInterface((LPDIRECTSOUNDBUFFER)This->dsb, riid, ppobj);
 }
 
-static ULONG WINAPI IDirectSoundNotifyImpl_AddRef(IDirectSoundNotify *iface)
+static ULONG WINAPI IDirectSoundNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface)
 {
-    IDirectSoundBufferImpl *This = impl_from_IDirectSoundNotify(iface);
-    ULONG ref = InterlockedIncrement(&This->refn);
-
+    IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface;
+    ULONG ref = InterlockedIncrement(&(This->ref));
     TRACE("(%p) ref was %d\n", This, ref - 1);
-
-    if(ref == 1)
-        InterlockedIncrement(&This->numIfaces);
-
     return ref;
 }
 
-static ULONG WINAPI IDirectSoundNotifyImpl_Release(IDirectSoundNotify *iface)
+static ULONG WINAPI IDirectSoundNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface)
 {
-    IDirectSoundBufferImpl *This = impl_from_IDirectSoundNotify(iface);
-    ULONG ref = InterlockedDecrement(&This->refn);
-
+    IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface;
+    ULONG ref = InterlockedDecrement(&(This->ref));
     TRACE("(%p) ref was %d\n", This, ref + 1);
 
-    if (!ref && !InterlockedDecrement(&This->numIfaces))
-        secondarybuffer_destroy(This);
-
+    if (!ref) {
+        This->dsb->notify = NULL;
+        IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)This->dsb);
+        HeapFree(GetProcessHeap(), 0, This);
+        TRACE("(%p) released\n", This);
+    }
     return ref;
 }
 
-static HRESULT WINAPI IDirectSoundNotifyImpl_SetNotificationPositions(IDirectSoundNotify *iface,
-        DWORD howmuch, const DSBPOSITIONNOTIFY *notify)
-{
-        IDirectSoundBufferImpl *This = impl_from_IDirectSoundNotify(iface);
-
+static HRESULT WINAPI IDirectSoundNotifyImpl_SetNotificationPositions(
+       LPDIRECTSOUNDNOTIFY iface,DWORD howmuch,LPCDSBPOSITIONNOTIFY notify
+) {
+       IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface;
        TRACE("(%p,0x%08x,%p)\n",This,howmuch,notify);
 
         if (howmuch > 0 && notify == NULL) {
@@ -85,24 +92,30 @@ static HRESULT WINAPI IDirectSoundNotifyImpl_SetNotificationPositions(IDirectSou
                    notify[i].dwOffset,notify[i].hEventNotify);
        }
 
-       if (howmuch > 0) {
+       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. */
-            HeapFree(GetProcessHeap(), 0, This->notifies);
-            This->notifies = HeapAlloc(GetProcessHeap(), 0,
+           HeapFree(GetProcessHeap(), 0, This->dsb->notifies);
+           This->dsb->notifies = HeapAlloc(GetProcessHeap(), 0,
                        howmuch * sizeof(DSBPOSITIONNOTIFY));
 
-            if (This->notifies == NULL) {
+           if (This->dsb->notifies == NULL) {
                    WARN("out of memory\n");
                    return DSERR_OUTOFMEMORY;
            }
-            CopyMemory(This->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY));
-            This->nrofnotifies = howmuch;
-       } else {
-           HeapFree(GetProcessHeap(), 0, This->notifies);
-           This->notifies = NULL;
-           This->nrofnotifies = 0;
-       }
+           CopyMemory(This->dsb->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY));
+           This->dsb->nrofnotifies = howmuch;
+        } else {
+           HeapFree(GetProcessHeap(), 0, This->dsb->notifies);
+           This->dsb->notifies = NULL;
+           This->dsb->nrofnotifies = 0;
+        }
 
        return S_OK;
 }
@@ -115,6 +128,40 @@ static const IDirectSoundNotifyVtbl dsnvt =
     IDirectSoundNotifyImpl_SetNotificationPositions,
 };
 
+static HRESULT 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;
+}
+
+static HRESULT IDirectSoundNotifyImpl_Destroy(
+    IDirectSoundNotifyImpl *pdsn)
+{
+    TRACE("(%p)\n",pdsn);
+
+    while (IDirectSoundNotifyImpl_Release((LPDIRECTSOUNDNOTIFY)pdsn) > 0);
+
+    return DS_OK;
+}
+
 /*******************************************************************************
  *             IDirectSoundBuffer
  */
@@ -126,7 +173,7 @@ static inline IDirectSoundBufferImpl *impl_from_IDirectSoundBuffer8(IDirectSound
 
 static inline BOOL is_primary_buffer(IDirectSoundBufferImpl *This)
 {
-    return (This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER) != 0;
+    return This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER ? TRUE : FALSE;
 }
 
 static HRESULT WINAPI IDirectSoundBufferImpl_SetFormat(IDirectSoundBuffer8 *iface,
@@ -179,6 +226,14 @@ static HRESULT WINAPI IDirectSoundBufferImpl_SetVolume(IDirectSoundBuffer8 *ifac
                        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");
+               }
+       }
+
        RtlReleaseResource(&This->lock);
        /* **** */
 
@@ -237,9 +292,10 @@ static HRESULT WINAPI IDirectSoundBufferImpl_SetFrequency(IDirectSoundBuffer8 *i
        oldFreq = This->freq;
        This->freq = freq;
        if (freq != oldFreq) {
-               This->freqAdjust = This->freq / (float)This->device->pwfx->nSamplesPerSec;
+               This->freqAdjust = ((DWORD64)This->freq << DSOUND_FREQSHIFT) / This->device->pwfx->nSamplesPerSec;
                This->nAvgBytesPerSec = freq * This->pwfx->nBlockAlign;
                DSOUND_RecalcFormat(This);
+               DSOUND_MixToTemporary(This, 0, This->buflen, FALSE);
        }
 
        RtlReleaseResource(&This->lock);
@@ -260,11 +316,18 @@ static HRESULT WINAPI IDirectSoundBufferImpl_Play(IDirectSoundBuffer8 *iface, DW
        RtlAcquireResourceExclusive(&This->lock, TRUE);
 
        This->playflags = flags;
-       if (This->state == STATE_STOPPED) {
+       if (This->state == STATE_STOPPED && !This->hwbuf) {
                This->leadin = TRUE;
                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;
+       }
 
        RtlReleaseResource(&This->lock);
        /* **** */
@@ -289,6 +352,13 @@ static HRESULT WINAPI IDirectSoundBufferImpl_Stop(IDirectSoundBuffer8 *iface)
                This->state = STATE_STOPPED;
                DSOUND_CheckEvent(This, 0, 0);
        }
+       if (This->hwbuf) {
+               hres = IDsDriverBuffer_Stop(This->hwbuf);
+               if (hres != DS_OK)
+                       WARN("IDsDriverBuffer_Stop failed\n");
+               else
+                       This->state = STATE_STOPPED;
+       }
 
        RtlReleaseResource(&This->lock);
        /* **** */
@@ -312,22 +382,16 @@ static ULONG WINAPI IDirectSoundBufferImpl_AddRef(IDirectSoundBuffer8 *iface)
 static ULONG WINAPI IDirectSoundBufferImpl_Release(IDirectSoundBuffer8 *iface)
 {
     IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
-    ULONG ref;
-
-    if (is_primary_buffer(This)){
-        ref = capped_refcount_dec(&This->ref);
-        if(!ref)
-            capped_refcount_dec(&This->numIfaces);
-        TRACE("(%p) ref is now: %d\n", This, ref);
-        return ref;
-    }
-
-    ref = InterlockedDecrement(&This->ref);
-    if (!ref && !InterlockedDecrement(&This->numIfaces))
-            secondarybuffer_destroy(This);
+    ULONG ref = InterlockedDecrement(&This->ref);
 
-    TRACE("(%p) ref is now %d\n", This, ref);
+    TRACE("(%p) ref was %d\n", This, ref + 1);
 
+    if (!ref && !InterlockedDecrement(&This->numIfaces)) {
+        if (is_primary_buffer(This))
+            primarybuffer_destroy(This);
+        else
+            secondarybuffer_destroy(This);
+    }
     return ref;
 }
 
@@ -335,31 +399,36 @@ static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition(IDirectSoundBuff
         DWORD *playpos, DWORD *writepos)
 {
         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
-       DWORD pos;
+       HRESULT hres;
 
        TRACE("(%p,%p,%p)\n",This,playpos,writepos);
 
        RtlAcquireResourceShared(&This->lock, TRUE);
+       if (This->hwbuf) {
+               hres=IDsDriverBuffer_GetPosition(This->hwbuf,playpos,writepos);
+               if (hres != DS_OK) {
+                   WARN("IDsDriverBuffer_GetPosition failed\n");
+                   return hres;
+               }
+       } else {
+               DWORD pos = This->sec_mixpos;
 
-       pos = This->sec_mixpos;
+               /* sanity */
+               if (pos >= This->buflen){
+                       FIXME("Bad play position. playpos: %d, buflen: %d\n", pos, This->buflen);
+                       pos %= This->buflen;
+               }
 
-       /* sanity */
-       if (pos >= This->buflen){
-               FIXME("Bad play position. playpos: %d, buflen: %d\n", pos, This->buflen);
-               pos %= This->buflen;
+               if (playpos)
+                       *playpos = pos;
+               if (writepos)
+                       *writepos = pos;
        }
-
-       if (playpos)
-               *playpos = pos;
-       if (writepos)
-               *writepos = pos;
-
-       if (writepos && This->state != STATE_STOPPED) {
+       if (writepos && This->state != STATE_STOPPED && (!This->hwbuf || !(This->device->drvdesc.dwFlags & DSDDESC_DONTNEEDWRITELEAD))) {
                /* apply the documented 10ms lead to writepos */
                *writepos += This->writelead;
                *writepos %= This->buflen;
        }
-
        RtlReleaseResource(&This->lock);
 
        TRACE("playpos = %d, writepos = %d, buflen=%d (%p, time=%d)\n",
@@ -469,31 +538,44 @@ static HRESULT WINAPI IDirectSoundBufferImpl_Lock(IDirectSoundBuffer8 *iface, DW
        /* **** */
        RtlAcquireResourceShared(&This->lock, TRUE);
 
-       if (writecursor+writebytes <= This->buflen) {
-               *(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
-               if (This->sec_mixpos >= writecursor && This->sec_mixpos < writecursor + writebytes && This->state == STATE_PLAYING)
-                       WARN("Overwriting mixing position, case 1\n");
-               *audiobytes1 = writebytes;
-               if (lplpaudioptr2)
-                       *(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);
+       if (!(This->device->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");
+                       RtlReleaseResource(&This->lock);
+                       return hres;
+               }
        } else {
-               DWORD remainder = writebytes + writecursor - This->buflen;
-               *(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
-               *audiobytes1 = This->buflen-writecursor;
-               if (This->sec_mixpos >= writecursor && This->sec_mixpos < writecursor + writebytes && This->state == STATE_PLAYING)
-                       WARN("Overwriting mixing position, case 2\n");
-               if (lplpaudioptr2)
-                       *(LPBYTE*)lplpaudioptr2 = This->buffer->memory;
-               if (audiobytes2)
-                       *audiobytes2 = writebytes-(This->buflen-writecursor);
-               if (audiobytes2 && This->sec_mixpos < remainder && This->state == STATE_PLAYING)
-                       WARN("Overwriting mixing position, case 3\n");
-               TRACE("Locked %p(%i bytes) and %p(%i bytes) writecursor=%d\n", *(LPBYTE*)lplpaudioptr1, *audiobytes1, lplpaudioptr2 ? *(LPBYTE*)lplpaudioptr2 : NULL, audiobytes2 ? *audiobytes2: 0, writecursor);
+               if (writecursor+writebytes <= This->buflen) {
+                       *(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
+                       if (This->sec_mixpos >= writecursor && This->sec_mixpos < writecursor + writebytes && This->state == STATE_PLAYING)
+                               WARN("Overwriting mixing position, case 1\n");
+                       *audiobytes1 = writebytes;
+                       if (lplpaudioptr2)
+                               *(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 {
+                       DWORD remainder = writebytes + writecursor - This->buflen;
+                       *(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
+                       *audiobytes1 = This->buflen-writecursor;
+                       if (This->sec_mixpos >= writecursor && This->sec_mixpos < writecursor + writebytes && This->state == STATE_PLAYING)
+                               WARN("Overwriting mixing position, case 2\n");
+                       if (lplpaudioptr2)
+                               *(LPBYTE*)lplpaudioptr2 = This->buffer->memory;
+                       if (audiobytes2)
+                               *audiobytes2 = writebytes-(This->buflen-writecursor);
+                       if (audiobytes2 && This->sec_mixpos < remainder && This->state == STATE_PLAYING)
+                               WARN("Overwriting mixing position, case 3\n");
+                       TRACE("Locked %p(%i bytes) and %p(%i bytes) writecursor=%d\n", *(LPBYTE*)lplpaudioptr1, *audiobytes1, lplpaudioptr2 ? *(LPBYTE*)lplpaudioptr2 : NULL, audiobytes2 ? *audiobytes2: 0, writecursor);
+               }
        }
 
        RtlReleaseResource(&This->lock);
@@ -507,12 +589,15 @@ static HRESULT WINAPI IDirectSoundBufferImpl_SetCurrentPosition(IDirectSoundBuff
 {
         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
        HRESULT hres = DS_OK;
+       DWORD oldpos;
 
        TRACE("(%p,%d)\n",This,newpos);
 
        /* **** */
        RtlAcquireResourceExclusive(&This->lock, TRUE);
 
+       oldpos = This->sec_mixpos;
+
        /* start mixing from this new location instead */
        newpos %= This->buflen;
        newpos -= newpos%This->pwfx->nBlockAlign;
@@ -521,6 +606,16 @@ static HRESULT WINAPI IDirectSoundBufferImpl_SetCurrentPosition(IDirectSoundBuff
        /* at this point, do not attempt to reset buffers, mess with primary mix position,
            or anything like that to reduce latency. The data already prebuffered cannot be changed */
 
+       /* position HW buffer if applicable, else just start mixing from new location instead */
+       if (This->hwbuf) {
+               hres = IDsDriverBuffer_SetPosition(This->hwbuf, This->buf_mixpos);
+               if (hres != DS_OK)
+                       WARN("IDsDriverBuffer_SetPosition failed\n");
+       }
+       else if (oldpos != newpos)
+               /* FIXME: Perhaps add a call to DSOUND_MixToTemporary here? Not sure it's needed */
+               This->buf_mixpos = DSOUND_secpos_to_bufpos(This, newpos, 0, NULL);
+
        RtlReleaseResource(&This->lock);
        /* **** */
 
@@ -552,6 +647,12 @@ static HRESULT WINAPI IDirectSoundBufferImpl_SetPan(IDirectSoundBuffer8 *iface,
        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");
+               }
        }
 
        RtlReleaseResource(&This->lock);
@@ -589,14 +690,22 @@ static HRESULT WINAPI IDirectSoundBufferImpl_Unlock(IDirectSoundBuffer8 *iface,
 
        TRACE("(%p,%p,%d,%p,%d)\n", This,p1,x1,p2,x2);
 
+       /* **** */
+       RtlAcquireResourceShared(&This->lock, TRUE);
+
+       if (!(This->device->drvdesc.dwFlags & DSDDESC_DONTNEEDSECONDARYLOCK) && This->hwbuf) {
+               hres = IDsDriverBuffer_Unlock(This->hwbuf, p1, x1, p2, x2);
+               if (hres != DS_OK)
+                       WARN("IDsDriverBuffer_Unlock failed\n");
+       }
+
+       RtlReleaseResource(&This->lock);
+       /* **** */
+
        if (!p2)
                x2 = 0;
 
-       if((p1 && ((BYTE*)p1 < This->buffer->memory || (BYTE*)p1 >= This->buffer->memory + This->buflen)) ||
-          (p2 && ((BYTE*)p2 < This->buffer->memory || (BYTE*)p2 >= This->buffer->memory + This->buflen)))
-               return DSERR_INVALIDPARAM;
-
-       if (x1 || x2)
+       if (!This->hwbuf && (x1 || x2))
        {
                RtlAcquireResourceShared(&This->device->buffer_list_lock, TRUE);
                LIST_FOR_EACH_ENTRY(iter, &This->buffer->buffers, IDirectSoundBufferImpl, entry )
@@ -606,7 +715,11 @@ static HRESULT WINAPI IDirectSoundBufferImpl_Unlock(IDirectSoundBuffer8 *iface,
                         {
                            if(x1 + (DWORD_PTR)p1 - (DWORD_PTR)iter->buffer->memory > iter->buflen)
                              hres = DSERR_INVALIDPARAM;
+                           else
+                             DSOUND_MixToTemporary(iter, (DWORD_PTR)p1 - (DWORD_PTR)iter->buffer->memory, x1, FALSE);
                         }
+                       if (x2)
+                               DSOUND_MixToTemporary(iter, 0, x2, FALSE);
                        RtlReleaseResource(&iter->lock);
                }
                RtlReleaseResource(&This->device->buffer_list_lock);
@@ -707,7 +820,8 @@ static HRESULT WINAPI IDirectSoundBufferImpl_GetCaps(IDirectSoundBuffer8 *iface,
        }
 
        caps->dwFlags = This->dsbd.dwFlags;
-       caps->dwFlags |= DSBCAPS_LOCSOFTWARE;
+       if (This->hwbuf) caps->dwFlags |= DSBCAPS_LOCHARDWARE;
+       else caps->dwFlags |= DSBCAPS_LOCSOFTWARE;
 
        caps->dwBufferBytes = This->buflen;
 
@@ -741,19 +855,27 @@ static HRESULT WINAPI IDirectSoundBufferImpl_QueryInterface(IDirectSoundBuffer8
        }
 
        if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
-                IDirectSoundNotify_AddRef(&This->IDirectSoundNotify_iface);
-                *ppobj = &This->IDirectSoundNotify_iface;
-                return S_OK;
+               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->dsbd.dwFlags & DSBCAPS_CTRL3D){
-                IDirectSound3DBuffer_AddRef(&This->IDirectSound3DBuffer_iface);
-                *ppobj = &This->IDirectSound3DBuffer_iface;
-                return S_OK;
-            }
-            TRACE("app requested IDirectSound3DBuffer on non-3D secondary buffer\n");
-            return E_NOINTERFACE;
+               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 ) ) {
@@ -762,9 +884,15 @@ static HRESULT WINAPI IDirectSoundBufferImpl_QueryInterface(IDirectSoundBuffer8
        }
 
        if ( IsEqualGUID( &IID_IKsPropertySet, riid ) ) {
-                IKsPropertySet_AddRef(&This->IKsPropertySet_iface);
-                *ppobj = &This->IKsPropertySet_iface;
-                return S_OK;
+               if (!This->iks)
+                       IKsBufferPropertySetImpl_Create(This, &(This->iks));
+               if (This->iks) {
+                       IKsPropertySet_AddRef((LPKSPROPERTYSET)This->iks);
+                       *ppobj = This->iks;
+                       return S_OK;
+               }
+               WARN("IID_IKsPropertySet\n");
+               return E_NOINTERFACE;
        }
 
        FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
@@ -809,6 +937,7 @@ HRESULT IDirectSoundBufferImpl_Create(
        LPWAVEFORMATEX wfex = dsbd->lpwfxFormat;
        HRESULT err = DS_OK;
        DWORD capf = 0;
+       int use_hw;
        TRACE("(%p,%p,%p)\n",device,pdsb,dsbd);
 
        if (dsbd->dwBufferBytes < DSBSIZE_MIN || dsbd->dwBufferBytes > DSBSIZE_MAX) {
@@ -827,16 +956,11 @@ HRESULT IDirectSoundBufferImpl_Create(
 
        TRACE("Created buffer at %p\n", dsb);
 
-       dsb->ref = 0;
-        dsb->refn = 0;
-        dsb->ref3D = 0;
-        dsb->refiks = 0;
-       dsb->numIfaces = 0;
+        dsb->ref = 1;
+        dsb->numIfaces = 1;
        dsb->device = device;
-       dsb->IDirectSoundBuffer8_iface.lpVtbl = &dsbvt;
-        dsb->IDirectSoundNotify_iface.lpVtbl = &dsnvt;
-        dsb->IDirectSound3DBuffer_iface.lpVtbl = &ds3dbvt;
-        dsb->IKsPropertySet_iface.lpVtbl = &iksbvt;
+        dsb->IDirectSoundBuffer8_iface.lpVtbl = &dsbvt;
+       dsb->iks = NULL;
 
        /* size depends on version */
        CopyMemory(&dsb->dsbd, dsbd, dsbd->dwSize);
@@ -856,8 +980,10 @@ HRESULT IDirectSoundBufferImpl_Create(
                dsb->buflen = dsbd->dwBufferBytes;
 
        dsb->freq = dsbd->lpwfxFormat->nSamplesPerSec;
+       dsb->notify = NULL;
        dsb->notifies = NULL;
        dsb->nrofnotifies = 0;
+       dsb->hwnotify = 0;
 
        /* Check necessary hardware mixing capabilities */
        if (wfex->nChannels==2) capf |= DSCAPS_SECONDARYSTEREO;
@@ -865,7 +991,24 @@ HRESULT IDirectSoundBufferImpl_Create(
        if (wfex->wBitsPerSample==16) capf |= DSCAPS_SECONDARY16BIT;
        else capf |= DSCAPS_SECONDARY8BIT;
 
-       TRACE("capf = 0x%08x, device->drvcaps.dwFlags = 0x%08x\n", capf, device->drvcaps.dwFlags);
+       use_hw = !!(dsbd->dwFlags & DSBCAPS_LOCHARDWARE);
+       TRACE("use_hw = %d, capf = 0x%08x, device->drvcaps.dwFlags = 0x%08x\n", use_hw, capf, device->drvcaps.dwFlags);
+       if (use_hw && ((device->drvcaps.dwFlags & capf) != capf || !device->driver))
+       {
+               if (device->driver)
+                       WARN("Format not supported for hardware buffer\n");
+               HeapFree(GetProcessHeap(),0,dsb->pwfx);
+               HeapFree(GetProcessHeap(),0,dsb);
+               *pdsb = NULL;
+               if ((device->drvcaps.dwFlags & capf) != capf)
+                       return DSERR_BADFORMAT;
+               return DSERR_GENERIC;
+       }
+
+       /* FIXME: check hardware sample rate mixing capabilities */
+       /* FIXME: check app hints for software/hardware buffer (STATIC, LOCHARDWARE, etc) */
+       /* FIXME: check whether any hardware buffers are left */
+       /* FIXME: handle DSDHEAP_CREATEHEAP for hardware buffers */
 
        /* Allocate an empty buffer */
        dsb->buffer = HeapAlloc(GetProcessHeap(),0,sizeof(*(dsb->buffer)));
@@ -877,15 +1020,35 @@ HRESULT IDirectSoundBufferImpl_Create(
                return DSERR_OUTOFMEMORY;
        }
 
-       /* Allocate system memory for buffer */
-       dsb->buffer->memory = HeapAlloc(GetProcessHeap(),0,dsb->buflen);
-       if (dsb->buffer->memory == NULL) {
-               WARN("out of memory\n");
-               HeapFree(GetProcessHeap(),0,dsb->pwfx);
-               HeapFree(GetProcessHeap(),0,dsb->buffer);
-               HeapFree(GetProcessHeap(),0,dsb);
-               *pdsb = NULL;
-               return DSERR_OUTOFMEMORY;
+       /* Allocate system memory for buffer if applicable */
+       if ((device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) || !use_hw) {
+               dsb->buffer->memory = HeapAlloc(GetProcessHeap(),0,dsb->buflen);
+               if (dsb->buffer->memory == NULL) {
+                       WARN("out of memory\n");
+                       HeapFree(GetProcessHeap(),0,dsb->pwfx);
+                       HeapFree(GetProcessHeap(),0,dsb->buffer);
+                       HeapFree(GetProcessHeap(),0,dsb);
+                       *pdsb = NULL;
+                       return DSERR_OUTOFMEMORY;
+               }
+       }
+
+       /* Allocate the hardware buffer */
+       if (use_hw) {
+               err = IDsDriver_CreateSoundBuffer(device->driver,wfex,dsbd->dwFlags,0,
+                                                 &(dsb->buflen),&(dsb->buffer->memory),
+                                                 (LPVOID*)&(dsb->hwbuf));
+               if (FAILED(err))
+               {
+                       WARN("Failed to create hardware secondary buffer: %08x\n", err);
+                       if (device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY)
+                               HeapFree(GetProcessHeap(),0,dsb->buffer->memory);
+                       HeapFree(GetProcessHeap(),0,dsb->buffer);
+                       HeapFree(GetProcessHeap(),0,dsb->pwfx);
+                       HeapFree(GetProcessHeap(),0,dsb);
+                       *pdsb = NULL;
+                       return DSERR_GENERIC;
+               }
        }
 
        dsb->buffer->ref = 1;
@@ -895,10 +1058,10 @@ HRESULT IDirectSoundBufferImpl_Create(
 
        /* It's not necessary to initialize values to zero since */
        /* we allocated this structure with HEAP_ZERO_MEMORY... */
-       dsb->sec_mixpos = 0;
+       dsb->buf_mixpos = dsb->sec_mixpos = 0;
        dsb->state = STATE_STOPPED;
 
-       dsb->freqAdjust = dsb->freq / (float)device->pwfx->nSamplesPerSec;
+       dsb->freqAdjust = ((DWORD64)dsb->freq << DSOUND_FREQSHIFT) / device->pwfx->nSamplesPerSec;
        dsb->nAvgBytesPerSec = dsb->freq *
                dsbd->lpwfxFormat->nBlockAlign;
 
@@ -943,28 +1106,27 @@ HRESULT IDirectSoundBufferImpl_Create(
                }
        }
 
-        IDirectSoundBuffer8_AddRef(&dsb->IDirectSoundBuffer8_iface);
        *pdsb = dsb;
        return err;
 }
 
 void secondarybuffer_destroy(IDirectSoundBufferImpl *This)
 {
-    ULONG ref = InterlockedIncrement(&This->numIfaces);
-
-    if (ref > 1)
-        WARN("Destroying buffer with %u in use interfaces\n", ref - 1);
-
     DirectSoundDevice_RemoveBuffer(This->device, This);
     RtlDeleteResource(&This->lock);
 
-    This->buffer->ref--;
-    list_remove(&This->entry);
-    if (This->buffer->ref == 0) {
-        HeapFree(GetProcessHeap(), 0, This->buffer->memory);
-        HeapFree(GetProcessHeap(), 0, This->buffer);
+    if (This->hwbuf)
+        IDsDriverBuffer_Release(This->hwbuf);
+    if (!This->hwbuf || (This->device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY)) {
+        This->buffer->ref--;
+        list_remove(&This->entry);
+        if (This->buffer->ref == 0) {
+            HeapFree(GetProcessHeap(), 0, This->buffer->memory);
+            HeapFree(GetProcessHeap(), 0, This->buffer);
+        }
     }
 
+    HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
     HeapFree(GetProcessHeap(), 0, This->notifies);
     HeapFree(GetProcessHeap(), 0, This->pwfx);
     HeapFree(GetProcessHeap(), 0, This);
@@ -972,6 +1134,38 @@ void secondarybuffer_destroy(IDirectSoundBufferImpl *This)
     TRACE("(%p) released\n", This);
 }
 
+HRESULT IDirectSoundBufferImpl_Destroy(
+    IDirectSoundBufferImpl *pdsb)
+{
+    TRACE("(%p)\n",pdsb);
+
+    /* This keeps the *_Destroy functions from possibly deleting
+     * this object until it is ready to be deleted */
+    InterlockedIncrement(&pdsb->numIfaces);
+
+    if (pdsb->iks) {
+        WARN("iks not NULL\n");
+        IKsBufferPropertySetImpl_Destroy(pdsb->iks);
+        pdsb->iks = NULL;
+    }
+
+    if (pdsb->ds3db) {
+        WARN("ds3db not NULL\n");
+        IDirectSound3DBufferImpl_Destroy(pdsb->ds3db);
+        pdsb->ds3db = NULL;
+    }
+
+    if (pdsb->notify) {
+        WARN("notify not NULL\n");
+        IDirectSoundNotifyImpl_Destroy(pdsb->notify);
+        pdsb->notify = NULL;
+    }
+
+    secondarybuffer_destroy(pdsb);
+
+    return S_OK;
+}
+
 HRESULT IDirectSoundBufferImpl_Duplicate(
     DirectSoundDevice *device,
     IDirectSoundBufferImpl **ppdsb,
@@ -987,34 +1181,44 @@ HRESULT IDirectSoundBufferImpl_Duplicate(
         *ppdsb = NULL;
         return DSERR_OUTOFMEMORY;
     }
-
-    RtlAcquireResourceShared(&pdsb->lock, TRUE);
-
     CopyMemory(dsb, pdsb, sizeof(*dsb));
 
     dsb->pwfx = DSOUND_CopyFormat(pdsb->pwfx);
-
-    RtlReleaseResource(&pdsb->lock);
-
     if (dsb->pwfx == NULL) {
         HeapFree(GetProcessHeap(),0,dsb);
         *ppdsb = NULL;
         return DSERR_OUTOFMEMORY;
     }
 
+    if (pdsb->hwbuf) {
+        TRACE("duplicating hardware buffer\n");
+
+        hres = IDsDriver_DuplicateSoundBuffer(device->driver, pdsb->hwbuf,
+                                              (LPVOID *)&dsb->hwbuf);
+        if (FAILED(hres)) {
+            WARN("IDsDriver_DuplicateSoundBuffer failed (%08x)\n", hres);
+            HeapFree(GetProcessHeap(),0,dsb->pwfx);
+            HeapFree(GetProcessHeap(),0,dsb);
+            *ppdsb = NULL;
+            return hres;
+        }
+    }
+
     dsb->buffer->ref++;
     list_add_head(&dsb->buffer->buffers, &dsb->entry);
-    dsb->ref = 0;
-    dsb->refn = 0;
-    dsb->ref3D = 0;
-    dsb->refiks = 0;
-    dsb->numIfaces = 0;
+    dsb->ref = 1;
+    dsb->numIfaces = 1;
     dsb->state = STATE_STOPPED;
-    dsb->sec_mixpos = 0;
+    dsb->buf_mixpos = dsb->sec_mixpos = 0;
+    dsb->notify = NULL;
     dsb->notifies = NULL;
     dsb->nrofnotifies = 0;
     dsb->device = device;
+    dsb->ds3db = NULL;
+    dsb->iks = NULL; /* FIXME? */
+    dsb->tmp_buffer = NULL;
     DSOUND_RecalcFormat(dsb);
+    DSOUND_MixToTemporary(dsb, 0, dsb->buflen, FALSE);
 
     RtlInitializeResource(&dsb->lock);
 
@@ -1022,6 +1226,7 @@ HRESULT IDirectSoundBufferImpl_Duplicate(
     hres = DirectSoundDevice_AddBuffer(device, dsb);
     if (hres != DS_OK) {
         RtlDeleteResource(&dsb->lock);
+        HeapFree(GetProcessHeap(),0,dsb->tmp_buffer);
         list_remove(&dsb->entry);
         dsb->buffer->ref--;
         HeapFree(GetProcessHeap(),0,dsb->pwfx);
@@ -1029,104 +1234,191 @@ HRESULT IDirectSoundBufferImpl_Duplicate(
         dsb = NULL;
     }
 
-    IDirectSoundBuffer8_AddRef(&dsb->IDirectSoundBuffer8_iface);
     *ppdsb = dsb;
     return hres;
 }
 
 /*******************************************************************************
- *              IKsPropertySet
+ *              IKsBufferPropertySet
  */
 
-static inline IDirectSoundBufferImpl *impl_from_IKsPropertySet(IKsPropertySet *iface)
-{
-    return CONTAINING_RECORD(iface, IDirectSoundBufferImpl, IKsPropertySet_iface);
-}
-
 /* IUnknown methods */
-static HRESULT WINAPI IKsPropertySetImpl_QueryInterface(IKsPropertySet *iface, REFIID riid,
-        void **ppobj)
+static HRESULT WINAPI IKsBufferPropertySetImpl_QueryInterface(
+    LPKSPROPERTYSET iface,
+    REFIID riid,
+    LPVOID *ppobj )
 {
-    IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
-
+    IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface;
     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
 
-    return IDirectSoundBuffer_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppobj);
+    return IDirectSoundBuffer_QueryInterface((LPDIRECTSOUNDBUFFER8)This->dsb, riid, ppobj);
 }
 
-static ULONG WINAPI IKsPropertySetImpl_AddRef(IKsPropertySet *iface)
+static ULONG WINAPI IKsBufferPropertySetImpl_AddRef(LPKSPROPERTYSET iface)
 {
-    IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
-    ULONG ref = InterlockedIncrement(&This->refiks);
-
+    IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface;
+    ULONG ref = InterlockedIncrement(&(This->ref));
     TRACE("(%p) ref was %d\n", This, ref - 1);
-
-    if(ref == 1)
-        InterlockedIncrement(&This->numIfaces);
-
     return ref;
 }
 
-static ULONG WINAPI IKsPropertySetImpl_Release(IKsPropertySet *iface)
+static ULONG WINAPI IKsBufferPropertySetImpl_Release(LPKSPROPERTYSET iface)
 {
-    IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
-    ULONG ref;
-
-    if (is_primary_buffer(This)){
-        ref = capped_refcount_dec(&This->refiks);
-        if(!ref)
-            capped_refcount_dec(&This->numIfaces);
-        TRACE("(%p) ref is now: %d\n", This, ref);
-        return ref;
-    }
-
-    ref = InterlockedDecrement(&This->refiks);
-    if (!ref && !InterlockedDecrement(&This->numIfaces))
-        secondarybuffer_destroy(This);
-
-    TRACE("(%p) ref is now %d\n", This, ref);
+    IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface;
+    ULONG ref = InterlockedDecrement(&(This->ref));
+    TRACE("(%p) ref was %d\n", This, ref + 1);
 
+    if (!ref) {
+    This->dsb->iks = 0;
+    IDirectSoundBuffer_Release((LPDIRECTSOUND3DBUFFER)This->dsb);
+    HeapFree(GetProcessHeap(), 0, This);
+    TRACE("(%p) released\n", This);
+    }
     return ref;
 }
 
-static HRESULT WINAPI IKsPropertySetImpl_Get(IKsPropertySet *iface, REFGUID guidPropSet,
-        ULONG dwPropID, void *pInstanceData, ULONG cbInstanceData, void *pPropData,
-        ULONG cbPropData, ULONG *pcbReturned)
+static HRESULT WINAPI IKsBufferPropertySetImpl_Get(
+    LPKSPROPERTYSET iface,
+    REFGUID guidPropSet,
+    ULONG dwPropID,
+    LPVOID pInstanceData,
+    ULONG cbInstanceData,
+    LPVOID pPropData,
+    ULONG cbPropData,
+    PULONG pcbReturned )
 {
-    IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
-
+    IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface;
+    PIDSDRIVERPROPERTYSET ps;
     TRACE("(iface=%p,guidPropSet=%s,dwPropID=%d,pInstanceData=%p,cbInstanceData=%d,pPropData=%p,cbPropData=%d,pcbReturned=%p)\n",
     This,debugstr_guid(guidPropSet),dwPropID,pInstanceData,cbInstanceData,pPropData,cbPropData,pcbReturned);
 
+    if (This->dsb->hwbuf) {
+        IDsDriver_QueryInterface(This->dsb->hwbuf, &IID_IDsDriverPropertySet, (void **)&ps);
+
+        if (ps) {
+        DSPROPERTY prop;
+        HRESULT hres;
+
+        prop.s.Set = *guidPropSet;
+        prop.s.Id = dwPropID;
+        prop.s.Flags = 0;  /* unused */
+        prop.s.InstanceId = (ULONG_PTR)This->dsb->device;
+
+
+        hres = IDsDriverPropertySet_Get(ps, &prop, pInstanceData, cbInstanceData, pPropData, cbPropData, pcbReturned);
+
+        IDsDriverPropertySet_Release(ps);
+
+        return hres;
+        }
+    }
+
     return E_PROP_ID_UNSUPPORTED;
 }
 
-static HRESULT WINAPI IKsPropertySetImpl_Set(IKsPropertySet *iface, REFGUID guidPropSet,
-        ULONG dwPropID, void *pInstanceData, ULONG cbInstanceData, void *pPropData,
-        ULONG cbPropData)
+static HRESULT WINAPI IKsBufferPropertySetImpl_Set(
+    LPKSPROPERTYSET iface,
+    REFGUID guidPropSet,
+    ULONG dwPropID,
+    LPVOID pInstanceData,
+    ULONG cbInstanceData,
+    LPVOID pPropData,
+    ULONG cbPropData )
 {
-    IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
-
+    IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface;
+    PIDSDRIVERPROPERTYSET ps;
     TRACE("(%p,%s,%d,%p,%d,%p,%d)\n",This,debugstr_guid(guidPropSet),dwPropID,pInstanceData,cbInstanceData,pPropData,cbPropData);
 
+    if (This->dsb->hwbuf) {
+        IDsDriver_QueryInterface(This->dsb->hwbuf, &IID_IDsDriverPropertySet, (void **)&ps);
+
+        if (ps) {
+        DSPROPERTY prop;
+        HRESULT hres;
+
+        prop.s.Set = *guidPropSet;
+        prop.s.Id = dwPropID;
+        prop.s.Flags = 0;  /* unused */
+        prop.s.InstanceId = (ULONG_PTR)This->dsb->device;
+        hres = IDsDriverPropertySet_Set(ps,&prop,pInstanceData,cbInstanceData,pPropData,cbPropData);
+
+        IDsDriverPropertySet_Release(ps);
+
+        return hres;
+        }
+    }
+
     return E_PROP_ID_UNSUPPORTED;
 }
 
-static HRESULT WINAPI IKsPropertySetImpl_QuerySupport(IKsPropertySet *iface, REFGUID guidPropSet,
-        ULONG dwPropID, ULONG *pTypeSupport)
+static HRESULT WINAPI IKsBufferPropertySetImpl_QuerySupport(
+    LPKSPROPERTYSET iface,
+    REFGUID guidPropSet,
+    ULONG dwPropID,
+    PULONG pTypeSupport )
 {
-    IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
-
+    IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface;
+    PIDSDRIVERPROPERTYSET ps;
     TRACE("(%p,%s,%d,%p)\n",This,debugstr_guid(guidPropSet),dwPropID,pTypeSupport);
 
+    if (This->dsb->hwbuf) {
+        IDsDriver_QueryInterface(This->dsb->hwbuf, &IID_IDsDriverPropertySet, (void **)&ps);
+
+        if (ps) {
+            HRESULT hres;
+
+            hres = IDsDriverPropertySet_QuerySupport(ps,guidPropSet, dwPropID,pTypeSupport);
+
+            IDsDriverPropertySet_Release(ps);
+
+            return hres;
+        }
+    }
+
     return E_PROP_ID_UNSUPPORTED;
 }
 
-const IKsPropertySetVtbl iksbvt = {
-    IKsPropertySetImpl_QueryInterface,
-    IKsPropertySetImpl_AddRef,
-    IKsPropertySetImpl_Release,
-    IKsPropertySetImpl_Get,
-    IKsPropertySetImpl_Set,
-    IKsPropertySetImpl_QuerySupport
+static const IKsPropertySetVtbl iksbvt = {
+    IKsBufferPropertySetImpl_QueryInterface,
+    IKsBufferPropertySetImpl_AddRef,
+    IKsBufferPropertySetImpl_Release,
+    IKsBufferPropertySetImpl_Get,
+    IKsBufferPropertySetImpl_Set,
+    IKsBufferPropertySetImpl_QuerySupport
 };
+
+HRESULT IKsBufferPropertySetImpl_Create(
+    IDirectSoundBufferImpl *dsb,
+    IKsBufferPropertySetImpl **piks)
+{
+    IKsBufferPropertySetImpl *iks;
+    TRACE("(%p,%p)\n",dsb,piks);
+    *piks = NULL;
+
+    iks = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*iks));
+    if (iks == 0) {
+        WARN("out of memory\n");
+        *piks = NULL;
+        return DSERR_OUTOFMEMORY;
+    }
+
+    iks->ref = 0;
+    iks->dsb = dsb;
+    dsb->iks = iks;
+    iks->lpVtbl = &iksbvt;
+
+    IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)dsb);
+
+    *piks = iks;
+    return S_OK;
+}
+
+HRESULT IKsBufferPropertySetImpl_Destroy(
+    IKsBufferPropertySetImpl *piks)
+{
+    TRACE("(%p)\n",piks);
+
+    while (IKsBufferPropertySetImpl_Release((LPKSPROPERTYSET)piks) > 0);
+
+    return S_OK;
+}