wined3d: Don't call glCompressedTexImage2DARB without allocatedMemory.
[wine] / dlls / dsound / buffer.c
1 /*                      DirectSound
2  *
3  * Copyright 1998 Marcus Meissner
4  * Copyright 1998 Rob Riggs
5  * Copyright 2000-2002 TransGaming Technologies, Inc.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include <stdarg.h>
23
24 #define NONAMELESSSTRUCT
25 #define NONAMELESSUNION
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "mmsystem.h"
30 #include "winreg.h"
31 #include "winternl.h"
32 #include "wine/debug.h"
33 #include "dsound.h"
34 #include "dsdriver.h"
35 #include "dsound_private.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
38
39 /*******************************************************************************
40  *              IDirectSoundNotify
41  */
42 static HRESULT WINAPI IDirectSoundNotifyImpl_QueryInterface(
43         LPDIRECTSOUNDNOTIFY iface,REFIID riid,LPVOID *ppobj
44 ) {
45         IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface;
46         TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
47
48         if (This->dsb == NULL) {
49                 WARN("invalid parameter\n");
50                 return E_INVALIDARG;
51         }
52
53         return IDirectSoundBuffer_QueryInterface((LPDIRECTSOUNDBUFFER)This->dsb, riid, ppobj);
54 }
55
56 static ULONG WINAPI IDirectSoundNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface)
57 {
58     IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface;
59     ULONG ref = InterlockedIncrement(&(This->ref));
60     TRACE("(%p) ref was %ld\n", This, ref - 1);
61     return ref;
62 }
63
64 static ULONG WINAPI IDirectSoundNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface)
65 {
66     IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface;
67     ULONG ref = InterlockedDecrement(&(This->ref));
68     TRACE("(%p) ref was %ld\n", This, ref + 1);
69
70     if (!ref) {
71         IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)This->dsb);
72         This->dsb->notify = NULL;
73         HeapFree(GetProcessHeap(), 0, This);
74         TRACE("(%p) released\n", This);
75     }
76     return ref;
77 }
78
79 static HRESULT WINAPI IDirectSoundNotifyImpl_SetNotificationPositions(
80         LPDIRECTSOUNDNOTIFY iface,DWORD howmuch,LPCDSBPOSITIONNOTIFY notify
81 ) {
82         IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface;
83         TRACE("(%p,0x%08lx,%p)\n",This,howmuch,notify);
84
85         if (howmuch > 0 && notify == NULL) {
86             WARN("invalid parameter: notify == NULL\n");
87             return DSERR_INVALIDPARAM;
88         }
89
90         if (TRACE_ON(dsound)) {
91             unsigned int        i;
92             for (i=0;i<howmuch;i++)
93                 TRACE("notify at %ld to %p\n",
94                     notify[i].dwOffset,notify[i].hEventNotify);
95         }
96
97         if (This->dsb->hwnotify) {
98             HRESULT hres;
99             hres = IDsDriverNotify_SetNotificationPositions(This->dsb->hwnotify, howmuch, notify);
100             if (hres != DS_OK)
101                     WARN("IDsDriverNotify_SetNotificationPositions failed\n");
102             return hres;
103         } else if (howmuch > 0) {
104             /* Make an internal copy of the caller-supplied array.
105              * Replace the existing copy if one is already present. */
106             if (This->dsb->notifies)
107                     This->dsb->notifies = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
108                         This->dsb->notifies, howmuch * sizeof(DSBPOSITIONNOTIFY));
109             else
110                     This->dsb->notifies = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
111                         howmuch * sizeof(DSBPOSITIONNOTIFY));
112
113             if (This->dsb->notifies == NULL) {
114                     WARN("out of memory\n");
115                     return DSERR_OUTOFMEMORY;
116             }
117             CopyMemory(This->dsb->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY));
118             This->dsb->nrofnotifies = howmuch;
119         } else {
120            HeapFree(GetProcessHeap(), 0, This->dsb->notifies);
121            This->dsb->notifies = NULL;
122            This->dsb->nrofnotifies = 0;
123         }
124
125         return S_OK;
126 }
127
128 static const IDirectSoundNotifyVtbl dsnvt =
129 {
130     IDirectSoundNotifyImpl_QueryInterface,
131     IDirectSoundNotifyImpl_AddRef,
132     IDirectSoundNotifyImpl_Release,
133     IDirectSoundNotifyImpl_SetNotificationPositions,
134 };
135
136 HRESULT IDirectSoundNotifyImpl_Create(
137     IDirectSoundBufferImpl * dsb,
138     IDirectSoundNotifyImpl **pdsn)
139 {
140     IDirectSoundNotifyImpl * dsn;
141     TRACE("(%p,%p)\n",dsb,pdsn);
142
143     dsn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(dsn));
144
145     if (dsn == NULL) {
146         WARN("out of memory\n");
147         return DSERR_OUTOFMEMORY;
148     }
149
150     dsn->ref = 0;
151     dsn->lpVtbl = &dsnvt;
152     dsn->dsb = dsb;
153     dsb->notify = dsn;
154     IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)dsb);
155
156     *pdsn = dsn;
157     return DS_OK;
158 }
159
160 HRESULT IDirectSoundNotifyImpl_Destroy(
161     IDirectSoundNotifyImpl *pdsn)
162 {
163     TRACE("(%p)\n",pdsn);
164
165     while (IDirectSoundNotifyImpl_Release((LPDIRECTSOUNDNOTIFY)pdsn) > 0);
166
167     return DS_OK;
168 }
169
170 /*******************************************************************************
171  *              IDirectSoundBuffer
172  */
173
174 static HRESULT WINAPI IDirectSoundBufferImpl_SetFormat(
175         LPDIRECTSOUNDBUFFER8 iface,LPCWAVEFORMATEX wfex
176 ) {
177         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
178
179         TRACE("(%p,%p)\n",This,wfex);
180         /* This method is not available on secondary buffers */
181         WARN("invalid call\n");
182         return DSERR_INVALIDCALL;
183 }
184
185 static HRESULT WINAPI IDirectSoundBufferImpl_SetVolume(
186         LPDIRECTSOUNDBUFFER8 iface,LONG vol
187 ) {
188         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
189         LONG oldVol;
190         HRESULT hres = DS_OK;
191
192         TRACE("(%p,%ld)\n",This,vol);
193
194         if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) {
195                 WARN("control unavailable: This->dsbd.dwFlags = 0x%08lx\n", This->dsbd.dwFlags);
196                 return DSERR_CONTROLUNAVAIL;
197         }
198
199         if ((vol > DSBVOLUME_MAX) || (vol < DSBVOLUME_MIN)) {
200                 WARN("invalid parameter: vol = %ld\n", vol);
201                 return DSERR_INVALIDPARAM;
202         }
203
204         /* **** */
205         EnterCriticalSection(&(This->lock));
206
207         if (This->dsbd.dwFlags & DSBCAPS_CTRL3D) {
208                 oldVol = This->ds3db_lVolume;
209                 This->ds3db_lVolume = vol;
210         } else {
211                 oldVol = This->volpan.lVolume;
212                 This->volpan.lVolume = vol;
213                 if (vol != oldVol)
214                         DSOUND_RecalcVolPan(&(This->volpan));
215         }
216
217         if (vol != oldVol) {
218                 if (This->hwbuf) {
219                         hres = IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan));
220                         if (hres != DS_OK)
221                                 WARN("IDsDriverBuffer_SetVolumePan failed\n");
222                 } else
223                         DSOUND_ForceRemix(This);
224         }
225
226         LeaveCriticalSection(&(This->lock));
227         /* **** */
228
229         return hres;
230 }
231
232 static HRESULT WINAPI IDirectSoundBufferImpl_GetVolume(
233         LPDIRECTSOUNDBUFFER8 iface,LPLONG vol
234 ) {
235         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
236         TRACE("(%p,%p)\n",This,vol);
237
238         if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) {
239                 WARN("control unavailable\n");
240                 return DSERR_CONTROLUNAVAIL;
241         }
242
243         if (vol == NULL) {
244                 WARN("invalid parameter: vol == NULL\n");
245                 return DSERR_INVALIDPARAM;
246         }
247
248         *vol = This->volpan.lVolume;
249
250         return DS_OK;
251 }
252
253 static HRESULT WINAPI IDirectSoundBufferImpl_SetFrequency(
254         LPDIRECTSOUNDBUFFER8 iface,DWORD freq
255 ) {
256         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
257         DWORD oldFreq;
258
259         TRACE("(%p,%ld)\n",This,freq);
260
261         if (!(This->dsbd.dwFlags & DSBCAPS_CTRLFREQUENCY)) {
262                 WARN("control unavailable\n");
263                 return DSERR_CONTROLUNAVAIL;
264         }
265
266         if (freq == DSBFREQUENCY_ORIGINAL)
267                 freq = This->pwfx->nSamplesPerSec;
268
269         if ((freq < DSBFREQUENCY_MIN) || (freq > DSBFREQUENCY_MAX)) {
270                 WARN("invalid parameter: freq = %ld\n", freq);
271                 return DSERR_INVALIDPARAM;
272         }
273
274         /* **** */
275         EnterCriticalSection(&(This->lock));
276
277         oldFreq = This->freq;
278         This->freq = freq;
279         if (freq != oldFreq) {
280                 This->freqAdjust = (freq << DSOUND_FREQSHIFT) / This->device->pwfx->nSamplesPerSec;
281                 This->nAvgBytesPerSec = freq * This->pwfx->nBlockAlign;
282                 DSOUND_RecalcFormat(This);
283                 if (!This->hwbuf)
284                         DSOUND_ForceRemix(This);
285         }
286
287         LeaveCriticalSection(&(This->lock));
288         /* **** */
289
290         return DS_OK;
291 }
292
293 static HRESULT WINAPI IDirectSoundBufferImpl_Play(
294         LPDIRECTSOUNDBUFFER8 iface,DWORD reserved1,DWORD reserved2,DWORD flags
295 ) {
296         HRESULT hres = DS_OK;
297         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
298         TRACE("(%p,%08lx,%08lx,%08lx)\n",This,reserved1,reserved2,flags);
299
300         /* **** */
301         EnterCriticalSection(&(This->lock));
302
303         This->playflags = flags;
304         if (This->state == STATE_STOPPED) {
305                 This->leadin = TRUE;
306                 This->startpos = This->buf_mixpos;
307                 This->state = STATE_STARTING;
308         } else if (This->state == STATE_STOPPING)
309                 This->state = STATE_PLAYING;
310         if (This->hwbuf) {
311                 hres = IDsDriverBuffer_Play(This->hwbuf, 0, 0, This->playflags);
312                 if (hres != DS_OK)
313                         WARN("IDsDriverBuffer_Play failed\n");
314                 else
315                         This->state = STATE_PLAYING;
316         }
317
318         LeaveCriticalSection(&(This->lock));
319         /* **** */
320
321         return hres;
322 }
323
324 static HRESULT WINAPI IDirectSoundBufferImpl_Stop(LPDIRECTSOUNDBUFFER8 iface)
325 {
326         HRESULT hres = DS_OK;
327         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
328         TRACE("(%p)\n",This);
329
330         /* **** */
331         EnterCriticalSection(&(This->lock));
332
333         if (This->state == STATE_PLAYING)
334                 This->state = STATE_STOPPING;
335         else if (This->state == STATE_STARTING)
336                 This->state = STATE_STOPPED;
337         if (This->hwbuf) {
338                 hres = IDsDriverBuffer_Stop(This->hwbuf);
339                 if (hres != DS_OK)
340                         WARN("IDsDriverBuffer_Stop failed\n");
341                 else
342                         This->state = STATE_STOPPED;
343         }
344         DSOUND_CheckEvent(This, 0);
345
346         LeaveCriticalSection(&(This->lock));
347         /* **** */
348
349         return hres;
350 }
351
352 static ULONG WINAPI IDirectSoundBufferImpl_AddRef(LPDIRECTSOUNDBUFFER8 iface)
353 {
354     IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
355     ULONG ref = InterlockedIncrement(&(This->ref));
356     TRACE("(%p) ref was %ld\n", This, ref - 1);
357     return ref;
358 }
359
360 static ULONG WINAPI IDirectSoundBufferImpl_Release(LPDIRECTSOUNDBUFFER8 iface)
361 {
362     IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
363     ULONG ref = InterlockedDecrement(&(This->ref));
364     TRACE("(%p) ref was %ld\n", This, ref + 1);
365
366     if (!ref) {
367         DirectSoundDevice_RemoveBuffer(This->device, This);
368
369         This->lock.DebugInfo->Spare[0] = 0;
370         DeleteCriticalSection(&(This->lock));
371
372         if (This->hwbuf) {
373                 IDsDriverBuffer_Release(This->hwbuf);
374                 if (This->device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) {
375                         This->buffer->ref--;
376                         if (This->buffer->ref==0) {
377                                 HeapFree(GetProcessHeap(),0,This->buffer->memory);
378                                 HeapFree(GetProcessHeap(),0,This->buffer);
379                         }
380                 }
381         } else {
382                 This->buffer->ref--;
383                 if (This->buffer->ref==0) {
384                         HeapFree(GetProcessHeap(),0,This->buffer->memory);
385                         HeapFree(GetProcessHeap(),0,This->buffer);
386                 }
387         }
388
389         HeapFree(GetProcessHeap(), 0, This->notifies);
390         HeapFree(GetProcessHeap(), 0, This->pwfx);
391         HeapFree(GetProcessHeap(), 0, This);
392
393         TRACE("(%p) released\n", This);
394     }
395     return ref;
396 }
397
398 DWORD DSOUND_CalcPlayPosition(IDirectSoundBufferImpl *This, DWORD pplay, DWORD pwrite)
399 {
400         DWORD bplay = This->buf_mixpos;
401         DWORD pmix = This->primary_mixpos;
402         DirectSoundDevice * device = This->device;
403         TRACE("(%p, pplay=%lu, pwrite=%lu)\n", This, pplay, pwrite);
404
405         /* the actual primary play position (pplay) is always behind last mixed (pmix),
406          * unless the computer is too slow or something */
407         /* we need to know how far away we are from there */
408         if (pmix < pplay) pmix += device->buflen; /* wraparound */
409         pmix -= pplay;
410         /* detect buffer underrun */
411         if (pwrite < pplay) pwrite += device->buflen; /* wraparound */
412         pwrite -= pplay;
413         if (pmix > (ds_snd_queue_max * device->fraglen + pwrite + device->writelead)) {
414                 WARN("detected an underrun: primary queue was %ld\n",pmix);
415                 pmix = 0;
416         }
417         /* divide the offset by its sample size */
418         pmix /= device->pwfx->nBlockAlign;
419         TRACE("primary back-samples=%ld\n",pmix);
420         /* adjust for our frequency */
421         pmix = (pmix * This->freqAdjust) >> DSOUND_FREQSHIFT;
422         /* multiply by our own sample size */
423         pmix *= This->pwfx->nBlockAlign;
424         TRACE("this back-offset=%ld\n", pmix);
425         /* subtract from our last mixed position */
426         while (bplay < pmix) bplay += This->buflen; /* wraparound */
427         bplay -= pmix;
428         if (This->leadin && ((bplay < This->startpos) || (bplay > This->buf_mixpos))) {
429                 /* seems we haven't started playing yet */
430                 TRACE("this still in lead-in phase\n");
431                 bplay = This->startpos;
432         }
433         /* return the result */
434         return bplay;
435 }
436
437 static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition(
438         LPDIRECTSOUNDBUFFER8 iface,LPDWORD playpos,LPDWORD writepos
439 ) {
440         HRESULT hres;
441         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
442         TRACE("(%p,%p,%p)\n",This,playpos,writepos);
443         if (This->hwbuf) {
444                 hres=IDsDriverBuffer_GetPosition(This->hwbuf,playpos,writepos);
445                 if (hres != DS_OK) {
446                     WARN("IDsDriverBuffer_GetPosition failed\n");
447                     return hres;
448                 }
449         } else {
450                 if (playpos && (This->state != STATE_PLAYING)) {
451                         /* we haven't been merged into the primary buffer (yet) */
452                         *playpos = This->buf_mixpos;
453                 } else if (playpos) {
454                         DWORD pplay, pwrite;
455                         /* let's get this exact; first, recursively call GetPosition on the primary */
456                         EnterCriticalSection(&(This->device->mixlock));
457                         if (DSOUND_PrimaryGetPosition(This->device, &pplay, &pwrite) != DS_OK)
458                                 WARN("DSOUND_PrimaryGetPosition failed\n");
459                         /* detect HEL mode underrun */
460                         if (!(This->device->hwbuf || This->device->pwqueue))
461                                 TRACE("detected an underrun\n");
462                         if ((This->dsbd.dwFlags & DSBCAPS_GETCURRENTPOSITION2) || This->device->hwbuf) {
463                                 /* calculate play position using this */
464                                 *playpos = DSOUND_CalcPlayPosition(This, pplay, pwrite);
465                         } else {
466                                 /* (unless the app isn't using GETCURRENTPOSITION2) */
467                                 /* don't know exactly how this should be handled...
468                                  * the docs says that play cursor is reported as directly
469                                  * behind write cursor, hmm... */
470                                 /* let's just do what might work for Half-Life */
471                                 DWORD wp;
472                                 wp = (This->device->pwplay + ds_hel_margin) * This->device->fraglen;
473                                 wp %= This->device->buflen;
474                                 *playpos = DSOUND_CalcPlayPosition(This, wp, pwrite);
475                         }
476                         LeaveCriticalSection(&(This->device->mixlock));
477                 }
478                 if (writepos)
479                     *writepos = This->buf_mixpos;
480         }
481         if (writepos) {
482                 if (This->state != STATE_STOPPED) {
483                         /* apply the documented 10ms lead to writepos */
484                         *writepos += This->writelead;
485                 }
486                 *writepos %= This->buflen;
487         }
488         if (playpos)
489             This->last_playpos = *playpos;
490         TRACE("playpos = %ld, writepos = %ld (%p, time=%ld)\n", playpos?*playpos:0, writepos?*writepos:0, This, GetTickCount());
491         return DS_OK;
492 }
493
494 static HRESULT WINAPI IDirectSoundBufferImpl_GetStatus(
495         LPDIRECTSOUNDBUFFER8 iface,LPDWORD status
496 ) {
497         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
498         TRACE("(%p,%p), thread is %04lx\n",This,status,GetCurrentThreadId());
499
500         if (status == NULL) {
501                 WARN("invalid parameter: status = NULL\n");
502                 return DSERR_INVALIDPARAM;
503         }
504
505         *status = 0;
506         if ((This->state == STATE_STARTING) || (This->state == STATE_PLAYING)) {
507                 *status |= DSBSTATUS_PLAYING;
508                 if (This->playflags & DSBPLAY_LOOPING)
509                         *status |= DSBSTATUS_LOOPING;
510         }
511
512         TRACE("status=%lx\n", *status);
513         return DS_OK;
514 }
515
516
517 static HRESULT WINAPI IDirectSoundBufferImpl_GetFormat(
518     LPDIRECTSOUNDBUFFER8 iface,
519     LPWAVEFORMATEX lpwf,
520     DWORD wfsize,
521     LPDWORD wfwritten)
522 {
523     DWORD size;
524     IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
525     TRACE("(%p,%p,%ld,%p)\n",This,lpwf,wfsize,wfwritten);
526
527     size = sizeof(WAVEFORMATEX) + This->pwfx->cbSize;
528
529     if (lpwf) { /* NULL is valid */
530         if (wfsize >= size) {
531             CopyMemory(lpwf,This->pwfx,size);
532             if (wfwritten)
533                 *wfwritten = size;
534         } else {
535             WARN("invalid parameter: wfsize too small\n");
536             if (wfwritten)
537                 *wfwritten = 0;
538             return DSERR_INVALIDPARAM;
539         }
540     } else {
541         if (wfwritten)
542             *wfwritten = sizeof(WAVEFORMATEX) + This->pwfx->cbSize;
543         else {
544             WARN("invalid parameter: wfwritten == NULL\n");
545             return DSERR_INVALIDPARAM;
546         }
547     }
548
549     return DS_OK;
550 }
551
552 static HRESULT WINAPI IDirectSoundBufferImpl_Lock(
553         LPDIRECTSOUNDBUFFER8 iface,DWORD writecursor,DWORD writebytes,LPVOID lplpaudioptr1,LPDWORD audiobytes1,LPVOID lplpaudioptr2,LPDWORD audiobytes2,DWORD flags
554 ) {
555         HRESULT hres = DS_OK;
556         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
557
558         TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx) at %ld\n",
559                 This,
560                 writecursor,
561                 writebytes,
562                 lplpaudioptr1,
563                 audiobytes1,
564                 lplpaudioptr2,
565                 audiobytes2,
566                 flags,
567                 GetTickCount()
568         );
569
570         if (flags & DSBLOCK_FROMWRITECURSOR) {
571                 DWORD writepos;
572                 /* GetCurrentPosition does too much magic to duplicate here */
573                 hres = IDirectSoundBufferImpl_GetCurrentPosition(iface, NULL, &writepos);
574                 if (hres != DS_OK) {
575                         WARN("IDirectSoundBufferImpl_GetCurrentPosition failed\n");
576                         return hres;
577                 }
578                 writecursor += writepos;
579         }
580         writecursor %= This->buflen;
581         if (flags & DSBLOCK_ENTIREBUFFER)
582                 writebytes = This->buflen;
583         if (writebytes > This->buflen)
584                 writebytes = This->buflen;
585
586         EnterCriticalSection(&(This->lock));
587
588         if ((writebytes == This->buflen) &&
589             ((This->state == STATE_STARTING) ||
590              (This->state == STATE_PLAYING)))
591                 /* some games, like Half-Life, try to be clever (not) and
592                  * keep one secondary buffer, and mix sounds into it itself,
593                  * locking the entire buffer every time... so we can just forget
594                  * about tracking the last-written-to-position... */
595                 This->probably_valid_to = (DWORD)-1;
596         else
597                 This->probably_valid_to = writecursor;
598
599         if (!(This->device->drvdesc.dwFlags & DSDDESC_DONTNEEDSECONDARYLOCK) && This->hwbuf) {
600                 hres = IDsDriverBuffer_Lock(This->hwbuf,
601                                      lplpaudioptr1, audiobytes1,
602                                      lplpaudioptr2, audiobytes2,
603                                      writecursor, writebytes,
604                                      0);
605                 if (hres != DS_OK) {
606                         WARN("IDsDriverBuffer_Lock failed\n");
607                         LeaveCriticalSection(&(This->lock));
608                         return hres;
609                 }
610         } else {
611                 BOOL remix = FALSE;
612                 if (writecursor+writebytes <= This->buflen) {
613                         *(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
614                         *audiobytes1 = writebytes;
615                         if (lplpaudioptr2)
616                                 *(LPBYTE*)lplpaudioptr2 = NULL;
617                         if (audiobytes2)
618                                 *audiobytes2 = 0;
619                         TRACE("->%ld.0\n",writebytes);
620                 } else {
621                         *(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
622                         *audiobytes1 = This->buflen-writecursor;
623                         if (lplpaudioptr2)
624                                 *(LPBYTE*)lplpaudioptr2 = This->buffer->memory;
625                         if (audiobytes2)
626                                 *audiobytes2 = writebytes-(This->buflen-writecursor);
627                         TRACE("->%ld.%ld\n",*audiobytes1,audiobytes2?*audiobytes2:0);
628                 }
629                 if (This->state == STATE_PLAYING) {
630                         /* if the segment between playpos and buf_mixpos is touched,
631                          * we need to cancel some mixing */
632                         /* we'll assume that the app always calls GetCurrentPosition before
633                          * locking a playing buffer, so that last_playpos is up-to-date */
634                         if (This->buf_mixpos >= This->last_playpos) {
635                                 if (This->buf_mixpos > writecursor &&
636                                     This->last_playpos < writecursor+writebytes)
637                                         remix = TRUE;
638                         } else {
639                                 if (This->buf_mixpos > writecursor ||
640                                     This->last_playpos < writecursor+writebytes)
641                                         remix = TRUE;
642                         }
643                         if (remix) {
644                                 TRACE("locking prebuffered region, ouch\n");
645                                 DSOUND_MixCancelAt(This, writecursor);
646                         }
647                 }
648         }
649
650         LeaveCriticalSection(&(This->lock));
651         return DS_OK;
652 }
653
654 static HRESULT WINAPI IDirectSoundBufferImpl_SetCurrentPosition(
655         LPDIRECTSOUNDBUFFER8 iface,DWORD newpos
656 ) {
657         HRESULT hres = DS_OK;
658         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
659         TRACE("(%p,%ld)\n",This,newpos);
660
661         /* **** */
662         EnterCriticalSection(&(This->lock));
663
664         newpos %= This->buflen;
665         This->buf_mixpos = newpos;
666         if (This->hwbuf) {
667                 hres = IDsDriverBuffer_SetPosition(This->hwbuf, This->buf_mixpos);
668                 if (hres != DS_OK)
669                         WARN("IDsDriverBuffer_SetPosition failed\n");
670         }
671
672         LeaveCriticalSection(&(This->lock));
673         /* **** */
674
675         return hres;
676 }
677
678 static HRESULT WINAPI IDirectSoundBufferImpl_SetPan(
679         LPDIRECTSOUNDBUFFER8 iface,LONG pan
680 ) {
681         HRESULT hres = DS_OK;
682         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
683
684         TRACE("(%p,%ld)\n",This,pan);
685
686         if ((pan > DSBPAN_RIGHT) || (pan < DSBPAN_LEFT)) {
687                 WARN("invalid parameter: pan = %ld\n", pan);
688                 return DSERR_INVALIDPARAM;
689         }
690
691         /* You cannot use both pan and 3D controls */
692         if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN) ||
693             (This->dsbd.dwFlags & DSBCAPS_CTRL3D)) {
694                 WARN("control unavailable\n");
695                 return DSERR_CONTROLUNAVAIL;
696         }
697
698         /* **** */
699         EnterCriticalSection(&(This->lock));
700
701         if (This->volpan.lPan != pan) {
702                 This->volpan.lPan = pan;
703                 DSOUND_RecalcVolPan(&(This->volpan));
704
705                 if (This->hwbuf) {
706                         hres = IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan));
707                         if (hres != DS_OK)
708                                 WARN("IDsDriverBuffer_SetVolumePan failed\n");
709                 } else
710                         DSOUND_ForceRemix(This);
711         }
712
713         LeaveCriticalSection(&(This->lock));
714         /* **** */
715
716         return hres;
717 }
718
719 static HRESULT WINAPI IDirectSoundBufferImpl_GetPan(
720         LPDIRECTSOUNDBUFFER8 iface,LPLONG pan
721 ) {
722         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
723         TRACE("(%p,%p)\n",This,pan);
724
725         if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN)) {
726                 WARN("control unavailable\n");
727                 return DSERR_CONTROLUNAVAIL;
728         }
729
730         if (pan == NULL) {
731                 WARN("invalid parameter: pan = NULL\n");
732                 return DSERR_INVALIDPARAM;
733         }
734
735         *pan = This->volpan.lPan;
736
737         return DS_OK;
738 }
739
740 static HRESULT WINAPI IDirectSoundBufferImpl_Unlock(
741         LPDIRECTSOUNDBUFFER8 iface,LPVOID p1,DWORD x1,LPVOID p2,DWORD x2
742 ) {
743         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
744         DWORD probably_valid_to;
745         HRESULT hres = DS_OK;
746
747         TRACE("(%p,%p,%ld,%p,%ld)\n", This,p1,x1,p2,x2);
748
749         /* **** */
750         EnterCriticalSection(&(This->lock));
751
752         if (!(This->device->drvdesc.dwFlags & DSDDESC_DONTNEEDSECONDARYLOCK) && This->hwbuf) {
753                 hres = IDsDriverBuffer_Unlock(This->hwbuf, p1, x1, p2, x2);
754                 if (hres != DS_OK)
755                         WARN("IDsDriverBuffer_Unlock failed\n");
756         }
757
758         if (hres == DS_OK) {
759                 if (p2) probably_valid_to = (((LPBYTE)p2)-This->buffer->memory) + x2;
760                 else probably_valid_to = (((LPBYTE)p1)-This->buffer->memory) + x1;
761                 probably_valid_to %= This->buflen;
762                 if ((probably_valid_to == 0) && ((x1+x2) == This->buflen) &&
763                     ((This->state == STATE_STARTING) ||
764                      (This->state == STATE_PLAYING)))
765                         /* see IDirectSoundBufferImpl_Lock */
766                         probably_valid_to = (DWORD)-1;
767                 This->probably_valid_to = probably_valid_to;
768         }
769
770         LeaveCriticalSection(&(This->lock));
771         /* **** */
772
773         TRACE("probably_valid_to=%ld\n", This->probably_valid_to);
774         return hres;
775 }
776
777 static HRESULT WINAPI IDirectSoundBufferImpl_Restore(
778         LPDIRECTSOUNDBUFFER8 iface
779 ) {
780         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
781         FIXME("(%p):stub\n",This);
782         return DS_OK;
783 }
784
785 static HRESULT WINAPI IDirectSoundBufferImpl_GetFrequency(
786         LPDIRECTSOUNDBUFFER8 iface,LPDWORD freq
787 ) {
788         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
789         TRACE("(%p,%p)\n",This,freq);
790
791         if (freq == NULL) {
792                 WARN("invalid parameter: freq = NULL\n");
793                 return DSERR_INVALIDPARAM;
794         }
795
796         *freq = This->freq;
797         TRACE("-> %ld\n", *freq);
798
799         return DS_OK;
800 }
801
802 static HRESULT WINAPI IDirectSoundBufferImpl_SetFX(
803         LPDIRECTSOUNDBUFFER8 iface,DWORD dwEffectsCount,LPDSEFFECTDESC pDSFXDesc,LPDWORD pdwResultCodes
804 ) {
805         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
806         DWORD u;
807
808         FIXME("(%p,%lu,%p,%p): stub\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes);
809
810         if (pdwResultCodes)
811                 for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
812
813         WARN("control unavailable\n");
814         return DSERR_CONTROLUNAVAIL;
815 }
816
817 static HRESULT WINAPI IDirectSoundBufferImpl_AcquireResources(
818         LPDIRECTSOUNDBUFFER8 iface,DWORD dwFlags,DWORD dwEffectsCount,LPDWORD pdwResultCodes
819 ) {
820         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
821         DWORD u;
822
823         FIXME("(%p,%08lu,%lu,%p): stub\n",This,dwFlags,dwEffectsCount,pdwResultCodes);
824
825         if (pdwResultCodes)
826                 for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
827
828         WARN("control unavailable\n");
829         return DSERR_CONTROLUNAVAIL;
830 }
831
832 static HRESULT WINAPI IDirectSoundBufferImpl_GetObjectInPath(
833         LPDIRECTSOUNDBUFFER8 iface,REFGUID rguidObject,DWORD dwIndex,REFGUID rguidInterface,LPVOID* ppObject
834 ) {
835         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
836
837         FIXME("(%p,%s,%lu,%s,%p): stub\n",This,debugstr_guid(rguidObject),dwIndex,debugstr_guid(rguidInterface),ppObject);
838
839         WARN("control unavailable\n");
840         return DSERR_CONTROLUNAVAIL;
841 }
842
843 static HRESULT WINAPI IDirectSoundBufferImpl_Initialize(
844         LPDIRECTSOUNDBUFFER8 iface,LPDIRECTSOUND dsound,LPCDSBUFFERDESC dbsd
845 ) {
846         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
847         FIXME("(%p,%p,%p):stub\n",This,dsound,dbsd);
848         DPRINTF("Re-Init!!!\n");
849         WARN("already initialized\n");
850         return DSERR_ALREADYINITIALIZED;
851 }
852
853 static HRESULT WINAPI IDirectSoundBufferImpl_GetCaps(
854         LPDIRECTSOUNDBUFFER8 iface,LPDSBCAPS caps
855 ) {
856         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
857         TRACE("(%p)->(%p)\n",This,caps);
858
859         if (caps == NULL) {
860                 WARN("invalid parameter: caps == NULL\n");
861                 return DSERR_INVALIDPARAM;
862         }
863
864         if (caps->dwSize < sizeof(*caps)) {
865                 WARN("invalid parameter: caps->dwSize = %ld < %d\n",caps->dwSize, sizeof(*caps));
866                 return DSERR_INVALIDPARAM;
867         }
868
869         caps->dwFlags = This->dsbd.dwFlags;
870         if (This->hwbuf) caps->dwFlags |= DSBCAPS_LOCHARDWARE;
871         else caps->dwFlags |= DSBCAPS_LOCSOFTWARE;
872
873         caps->dwBufferBytes = This->buflen;
874
875         /* This value represents the speed of the "unlock" command.
876            As unlock is quite fast (it does not do anything), I put
877            4096 ko/s = 4 Mo / s */
878         /* FIXME: hwbuf speed */
879         caps->dwUnlockTransferRate = 4096;
880         caps->dwPlayCpuOverhead = 0;
881
882         return DS_OK;
883 }
884
885 static HRESULT WINAPI IDirectSoundBufferImpl_QueryInterface(
886         LPDIRECTSOUNDBUFFER8 iface,REFIID riid,LPVOID *ppobj
887 ) {
888         IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
889
890         TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
891
892         if (ppobj == NULL) {
893                 WARN("invalid parameter\n");
894                 return E_INVALIDARG;
895         }
896
897         *ppobj = NULL;  /* assume failure */
898
899         if ( IsEqualGUID(riid, &IID_IUnknown) ||
900              IsEqualGUID(riid, &IID_IDirectSoundBuffer) ||
901              IsEqualGUID(riid, &IID_IDirectSoundBuffer8) ) {
902                 if (!This->secondary)
903                         SecondaryBufferImpl_Create(This, &(This->secondary));
904                 if (This->secondary) {
905                         IDirectSoundBuffer8_AddRef((LPDIRECTSOUNDBUFFER8)This->secondary);
906                         *ppobj = This->secondary;
907                         return S_OK;
908                 }
909                 WARN("IID_IDirectSoundBuffer\n");
910                 return E_NOINTERFACE;
911         }
912
913         if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
914                 if (!This->notify)
915                         IDirectSoundNotifyImpl_Create(This, &(This->notify));
916                 if (This->notify) {
917                         IDirectSoundNotify_AddRef((LPDIRECTSOUNDNOTIFY)This->notify);
918                         *ppobj = This->notify;
919                         return S_OK;
920                 }
921                 WARN("IID_IDirectSoundNotify\n");
922                 return E_NOINTERFACE;
923         }
924
925         if ( IsEqualGUID( &IID_IDirectSound3DBuffer, riid ) ) {
926                 if (!This->ds3db)
927                         IDirectSound3DBufferImpl_Create(This, &(This->ds3db));
928                 if (This->ds3db) {
929                         IDirectSound3DBuffer_AddRef((LPDIRECTSOUND3DBUFFER)This->ds3db);
930                         *ppobj = This->ds3db;
931                         return S_OK;
932                 }
933                 WARN("IID_IDirectSound3DBuffer\n");
934                 return E_NOINTERFACE;
935         }
936
937         if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) {
938                 ERR("app requested IDirectSound3DListener on secondary buffer\n");
939                 return E_NOINTERFACE;
940         }
941
942         if ( IsEqualGUID( &IID_IKsPropertySet, riid ) ) {
943                 if (!This->iks)
944                         IKsBufferPropertySetImpl_Create(This, &(This->iks));
945                 if (This->iks) {
946                         IKsPropertySet_AddRef((LPKSPROPERTYSET)This->iks);
947                         *ppobj = This->iks;
948                         return S_OK;
949                 }
950                 WARN("IID_IKsPropertySet\n");
951                 return E_NOINTERFACE;
952         }
953
954         FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
955
956         return E_NOINTERFACE;
957 }
958
959 static const IDirectSoundBuffer8Vtbl dsbvt =
960 {
961         IDirectSoundBufferImpl_QueryInterface,
962         IDirectSoundBufferImpl_AddRef,
963         IDirectSoundBufferImpl_Release,
964         IDirectSoundBufferImpl_GetCaps,
965         IDirectSoundBufferImpl_GetCurrentPosition,
966         IDirectSoundBufferImpl_GetFormat,
967         IDirectSoundBufferImpl_GetVolume,
968         IDirectSoundBufferImpl_GetPan,
969         IDirectSoundBufferImpl_GetFrequency,
970         IDirectSoundBufferImpl_GetStatus,
971         IDirectSoundBufferImpl_Initialize,
972         IDirectSoundBufferImpl_Lock,
973         IDirectSoundBufferImpl_Play,
974         IDirectSoundBufferImpl_SetCurrentPosition,
975         IDirectSoundBufferImpl_SetFormat,
976         IDirectSoundBufferImpl_SetVolume,
977         IDirectSoundBufferImpl_SetPan,
978         IDirectSoundBufferImpl_SetFrequency,
979         IDirectSoundBufferImpl_Stop,
980         IDirectSoundBufferImpl_Unlock,
981         IDirectSoundBufferImpl_Restore,
982         IDirectSoundBufferImpl_SetFX,
983         IDirectSoundBufferImpl_AcquireResources,
984         IDirectSoundBufferImpl_GetObjectInPath
985 };
986
987 HRESULT IDirectSoundBufferImpl_Create(
988         DirectSoundDevice * device,
989         IDirectSoundBufferImpl **pdsb,
990         LPCDSBUFFERDESC dsbd)
991 {
992         IDirectSoundBufferImpl *dsb;
993         LPWAVEFORMATEX wfex = dsbd->lpwfxFormat;
994         HRESULT err = DS_OK;
995         DWORD capf = 0;
996         int use_hw, alloc_size, cp_size;
997         TRACE("(%p,%p,%p)\n",device,pdsb,dsbd);
998
999         if (dsbd->dwBufferBytes < DSBSIZE_MIN || dsbd->dwBufferBytes > DSBSIZE_MAX) {
1000                 WARN("invalid parameter: dsbd->dwBufferBytes = %ld\n", dsbd->dwBufferBytes);
1001                 *pdsb = NULL;
1002                 return DSERR_INVALIDPARAM; /* FIXME: which error? */
1003         }
1004
1005         dsb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb));
1006
1007         if (dsb == 0) {
1008                 WARN("out of memory\n");
1009                 *pdsb = NULL;
1010                 return DSERR_OUTOFMEMORY;
1011         }
1012
1013         TRACE("Created buffer at %p\n", dsb);
1014
1015         dsb->ref = 0;
1016         dsb->secondary = 0;
1017         dsb->device = device;
1018         dsb->lpVtbl = &dsbvt;
1019         dsb->iks = NULL;
1020
1021         /* size depends on version */
1022         CopyMemory(&dsb->dsbd, dsbd, dsbd->dwSize);
1023
1024         /* variable sized struct so calculate size based on format */
1025         if (wfex->wFormatTag == WAVE_FORMAT_PCM) {
1026                 alloc_size = sizeof(WAVEFORMATEX);
1027                 cp_size = sizeof(PCMWAVEFORMAT);
1028         } else 
1029                 alloc_size = cp_size = sizeof(WAVEFORMATEX) + wfex->cbSize;
1030
1031         dsb->pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,alloc_size);
1032         if (dsb->pwfx == NULL) {
1033                 WARN("out of memory\n");
1034                 HeapFree(GetProcessHeap(),0,dsb);
1035                 *pdsb = NULL;
1036                 return DSERR_OUTOFMEMORY;
1037         }
1038
1039         CopyMemory(dsb->pwfx, wfex, cp_size);
1040
1041         if (dsbd->dwBufferBytes % dsbd->lpwfxFormat->nBlockAlign)
1042                 dsb->buflen = dsbd->dwBufferBytes + 
1043                         (dsbd->lpwfxFormat->nBlockAlign - 
1044                         (dsbd->dwBufferBytes % dsbd->lpwfxFormat->nBlockAlign));
1045         else
1046                 dsb->buflen = dsbd->dwBufferBytes;
1047
1048         dsb->freq = dsbd->lpwfxFormat->nSamplesPerSec;
1049         dsb->notify = NULL;
1050         dsb->notifies = NULL;
1051         dsb->nrofnotifies = 0;
1052         dsb->hwnotify = 0;
1053
1054         /* Check necessary hardware mixing capabilities */
1055         if (wfex->nChannels==2) capf |= DSCAPS_SECONDARYSTEREO;
1056         else capf |= DSCAPS_SECONDARYMONO;
1057         if (wfex->wBitsPerSample==16) capf |= DSCAPS_SECONDARY16BIT;
1058         else capf |= DSCAPS_SECONDARY8BIT;
1059
1060         use_hw = (device->drvcaps.dwFlags & capf) == capf;
1061         TRACE("use_hw = 0x%08x, capf = 0x%08lx, device->drvcaps.dwFlags = 0x%08lx\n", use_hw, capf, device->drvcaps.dwFlags);
1062
1063         /* FIXME: check hardware sample rate mixing capabilities */
1064         /* FIXME: check app hints for software/hardware buffer (STATIC, LOCHARDWARE, etc) */
1065         /* FIXME: check whether any hardware buffers are left */
1066         /* FIXME: handle DSDHEAP_CREATEHEAP for hardware buffers */
1067
1068         /* Allocate an empty buffer */
1069         dsb->buffer = HeapAlloc(GetProcessHeap(),0,sizeof(*(dsb->buffer)));
1070         if (dsb->buffer == NULL) {
1071                 WARN("out of memory\n");
1072                 HeapFree(GetProcessHeap(),0,dsb->pwfx);
1073                 HeapFree(GetProcessHeap(),0,dsb);
1074                 *pdsb = NULL;
1075                 return DSERR_OUTOFMEMORY;
1076         }
1077
1078         /* Allocate system memory for buffer if applicable */
1079         if ((device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) || !use_hw) {
1080                 dsb->buffer->memory = HeapAlloc(GetProcessHeap(),0,dsb->buflen);
1081                 if (dsb->buffer->memory == NULL) {
1082                         WARN("out of memory\n");
1083                         HeapFree(GetProcessHeap(),0,dsb->pwfx);
1084                         HeapFree(GetProcessHeap(),0,dsb->buffer);
1085                         HeapFree(GetProcessHeap(),0,dsb);
1086                         *pdsb = NULL;
1087                         return DSERR_OUTOFMEMORY;
1088                 }
1089                 dsb->buffer->ref = 1;
1090                 FillMemory(dsb->buffer->memory, dsb->buflen, dsbd->lpwfxFormat->wBitsPerSample == 8 ? 128 : 0);
1091         }
1092
1093         /* Allocate the hardware buffer */
1094         if (use_hw) {
1095                 err = IDsDriver_CreateSoundBuffer(device->driver,wfex,dsbd->dwFlags,0,
1096                                                   &(dsb->buflen),&(dsb->buffer->memory),
1097                                                   (LPVOID*)&(dsb->hwbuf));
1098                 /* fall back to software buffer on failure */
1099                 if (err != DS_OK) {
1100                         TRACE("IDsDriver_CreateSoundBuffer failed, falling back to software buffer\n");
1101                         use_hw = 0;
1102                         if (device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) {
1103                                 dsb->buffer->memory = HeapAlloc(GetProcessHeap(),0,dsb->buflen);
1104                                 if (dsb->buffer->memory == NULL) {
1105                                         WARN("out of memory\n");
1106                                         HeapFree(GetProcessHeap(),0,dsb->buffer);
1107                                         HeapFree(GetProcessHeap(),0,dsb->pwfx);
1108                                         HeapFree(GetProcessHeap(),0,dsb);
1109                                         *pdsb = NULL;
1110                                         return DSERR_OUTOFMEMORY;
1111                                 }
1112                                 dsb->buffer->ref = 1;
1113                                 FillMemory(dsb->buffer->memory, dsb->buflen, dsbd->lpwfxFormat->wBitsPerSample == 8 ? 128 : 0);
1114                         }
1115                         err = DS_OK;
1116                 }
1117         }
1118
1119         /* calculate fragment size and write lead */
1120         DSOUND_RecalcFormat(dsb);
1121
1122         /* It's not necessary to initialize values to zero since */
1123         /* we allocated this structure with HEAP_ZERO_MEMORY... */
1124         dsb->playpos = 0;
1125         dsb->buf_mixpos = 0;
1126         dsb->state = STATE_STOPPED;
1127
1128         dsb->freqAdjust = (dsb->freq << DSOUND_FREQSHIFT) /
1129                 device->pwfx->nSamplesPerSec;
1130         dsb->nAvgBytesPerSec = dsb->freq *
1131                 dsbd->lpwfxFormat->nBlockAlign;
1132
1133         if (dsb->dsbd.dwFlags & DSBCAPS_CTRL3D) {
1134                 dsb->ds3db_ds3db.dwSize = sizeof(DS3DBUFFER);
1135                 dsb->ds3db_ds3db.vPosition.x = 0.0;
1136                 dsb->ds3db_ds3db.vPosition.y = 0.0;
1137                 dsb->ds3db_ds3db.vPosition.z = 0.0;
1138                 dsb->ds3db_ds3db.vVelocity.x = 0.0;
1139                 dsb->ds3db_ds3db.vVelocity.y = 0.0;
1140                 dsb->ds3db_ds3db.vVelocity.z = 0.0;
1141                 dsb->ds3db_ds3db.dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
1142                 dsb->ds3db_ds3db.dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
1143                 dsb->ds3db_ds3db.vConeOrientation.x = 0.0;
1144                 dsb->ds3db_ds3db.vConeOrientation.y = 0.0;
1145                 dsb->ds3db_ds3db.vConeOrientation.z = 0.0;
1146                 dsb->ds3db_ds3db.lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
1147                 dsb->ds3db_ds3db.flMinDistance = DS3D_DEFAULTMINDISTANCE;
1148                 dsb->ds3db_ds3db.flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
1149                 dsb->ds3db_ds3db.dwMode = DS3DMODE_NORMAL;
1150
1151                 dsb->ds3db_need_recalc = FALSE;
1152                 DSOUND_Calc3DBuffer(dsb);
1153         } else
1154                 DSOUND_RecalcVolPan(&(dsb->volpan));
1155
1156         InitializeCriticalSection(&(dsb->lock));
1157         dsb->lock.DebugInfo->Spare[0] = (DWORD_PTR)"DSOUNDBUFFER_lock";
1158
1159         /* register buffer if not primary */
1160         if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
1161                 err = DirectSoundDevice_AddBuffer(device, dsb);
1162                 if (err != DS_OK) {
1163                         HeapFree(GetProcessHeap(),0,dsb->buffer->memory);
1164                         HeapFree(GetProcessHeap(),0,dsb->buffer);
1165                         dsb->lock.DebugInfo->Spare[0] = 0;
1166                         DeleteCriticalSection(&(dsb->lock));
1167                         HeapFree(GetProcessHeap(),0,dsb->pwfx);
1168                         HeapFree(GetProcessHeap(),0,dsb);
1169                         dsb = NULL;
1170                 }
1171         }
1172
1173         *pdsb = dsb;
1174         return err;
1175 }
1176
1177 HRESULT IDirectSoundBufferImpl_Destroy(
1178     IDirectSoundBufferImpl *pdsb)
1179 {
1180     TRACE("(%p)\n",pdsb);
1181
1182     /* This keeps the *_Destroy functions from possibly deleting
1183      * this object until it is ready to be deleted */
1184     IDirectSoundBufferImpl_AddRef((LPDIRECTSOUNDBUFFER8)pdsb);
1185
1186     if (pdsb->iks) {
1187         WARN("iks not NULL\n");
1188         IKsBufferPropertySetImpl_Destroy(pdsb->iks);
1189         pdsb->iks = NULL;
1190     }
1191
1192     if (pdsb->ds3db) {
1193         WARN("ds3db not NULL\n");
1194         IDirectSound3DBufferImpl_Destroy(pdsb->ds3db);
1195         pdsb->ds3db = NULL;
1196     }
1197
1198     if (pdsb->notify) {
1199         WARN("notify not NULL\n");
1200         IDirectSoundNotifyImpl_Destroy(pdsb->notify);
1201         pdsb->notify = NULL;
1202     }
1203
1204     if (pdsb->secondary) {
1205         WARN("dsb not NULL\n");
1206         SecondaryBufferImpl_Destroy(pdsb->secondary);
1207         pdsb->secondary = NULL;
1208     }
1209
1210     while (IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8)pdsb) > 0);
1211
1212     return S_OK;
1213 }
1214
1215 HRESULT IDirectSoundBufferImpl_Duplicate(
1216     DirectSoundDevice *device,
1217     IDirectSoundBufferImpl **ppdsb,
1218     IDirectSoundBufferImpl *pdsb)
1219 {
1220     IDirectSoundBufferImpl *dsb;
1221     HRESULT hres = DS_OK;
1222     int size;
1223     TRACE("(%p,%p,%p)\n", device, pdsb, pdsb);
1224
1225     dsb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb));
1226
1227     if (dsb == NULL) {
1228         WARN("out of memory\n");
1229         *ppdsb = NULL;
1230         return DSERR_OUTOFMEMORY;
1231     }
1232
1233     CopyMemory(dsb, pdsb, sizeof(IDirectSoundBufferImpl));
1234
1235     if (pdsb->hwbuf) {
1236         TRACE("duplicating hardware buffer\n");
1237
1238         hres = IDsDriver_DuplicateSoundBuffer(device->driver, pdsb->hwbuf,
1239                                               (LPVOID *)&dsb->hwbuf);
1240         if (hres != DS_OK) {
1241             TRACE("IDsDriver_DuplicateSoundBuffer failed, falling back to "
1242                   "software buffer\n");
1243             dsb->hwbuf = NULL;
1244             /* allocate buffer */
1245             if (device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) {
1246                 dsb->buffer = HeapAlloc(GetProcessHeap(),0,sizeof(*(dsb->buffer)));
1247                 if (dsb->buffer == NULL) {
1248                     WARN("out of memory\n");
1249                     HeapFree(GetProcessHeap(),0,dsb);
1250                     *ppdsb = NULL;
1251                     return DSERR_OUTOFMEMORY;
1252                 }
1253
1254                 dsb->buffer->memory = HeapAlloc(GetProcessHeap(),0,dsb->buflen);
1255                 if (dsb->buffer->memory == NULL) {
1256                     WARN("out of memory\n");
1257                     HeapFree(GetProcessHeap(),0,dsb->buffer);
1258                     HeapFree(GetProcessHeap(),0,dsb);
1259                     *ppdsb = NULL;
1260                     return DSERR_OUTOFMEMORY;
1261                 }
1262                 dsb->buffer->ref = 1;
1263
1264                 /* FIXME: copy buffer ? */
1265             }
1266         }
1267     } else {
1268         dsb->hwbuf = NULL;
1269         dsb->buffer->ref++;
1270     }
1271
1272     dsb->ref = 0;
1273     dsb->state = STATE_STOPPED;
1274     dsb->playpos = 0;
1275     dsb->buf_mixpos = 0;
1276     dsb->device = device;
1277     dsb->ds3db = NULL;
1278     dsb->iks = NULL; /* FIXME? */
1279     dsb->secondary = NULL;
1280
1281     /* variable sized struct so calculate size based on format */
1282     size = sizeof(WAVEFORMATEX) + pdsb->pwfx->cbSize;
1283
1284     dsb->pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
1285     if (dsb->pwfx == NULL) {
1286             WARN("out of memory\n");
1287             HeapFree(GetProcessHeap(),0,dsb->buffer);
1288             HeapFree(GetProcessHeap(),0,dsb);
1289             *ppdsb = NULL;
1290             return DSERR_OUTOFMEMORY;
1291     }
1292
1293     CopyMemory(dsb->pwfx, pdsb->pwfx, size);
1294
1295     InitializeCriticalSection(&(dsb->lock));
1296     dsb->lock.DebugInfo->Spare[0] = (DWORD_PTR)"DSOUNDBUFFER_lock";
1297
1298     /* register buffer */
1299     hres = DirectSoundDevice_AddBuffer(device, dsb);
1300     if (hres != DS_OK) {
1301         dsb->lock.DebugInfo->Spare[0] = 0;
1302         DeleteCriticalSection(&(dsb->lock));
1303         HeapFree(GetProcessHeap(),0,dsb->buffer);
1304         HeapFree(GetProcessHeap(),0,dsb->pwfx);
1305         HeapFree(GetProcessHeap(),0,dsb);
1306         *ppdsb = 0;
1307     }
1308
1309     *ppdsb = dsb;
1310     return hres;
1311 }
1312
1313 /*******************************************************************************
1314  *              SecondaryBuffer
1315  */
1316
1317 static HRESULT WINAPI SecondaryBufferImpl_QueryInterface(
1318         LPDIRECTSOUNDBUFFER8 iface,REFIID riid,LPVOID *ppobj)
1319 {
1320         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1321         TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
1322
1323         return IDirectSoundBufferImpl_QueryInterface((LPDIRECTSOUNDBUFFER8)This->dsb,riid,ppobj);
1324 }
1325
1326 static ULONG WINAPI SecondaryBufferImpl_AddRef(LPDIRECTSOUNDBUFFER8 iface)
1327 {
1328     SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1329     ULONG ref = InterlockedIncrement(&(This->ref));
1330     TRACE("(%p) ref was %ld\n", This, ref - 1);
1331     return ref;
1332 }
1333
1334 static ULONG WINAPI SecondaryBufferImpl_Release(LPDIRECTSOUNDBUFFER8 iface)
1335 {
1336     SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1337     ULONG ref;
1338     TRACE("(%p)\n", This);
1339     ref = InterlockedDecrement(&(This->ref));
1340     TRACE("ref was %ld\n", ref + 1);
1341
1342     if (!ref) {
1343         This->dsb->secondary = NULL;
1344         IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER8)This->dsb);
1345         HeapFree(GetProcessHeap(), 0, This);
1346         TRACE("(%p) released\n", This);
1347     }
1348     return ref;
1349 }
1350
1351 static HRESULT WINAPI SecondaryBufferImpl_GetCaps(
1352         LPDIRECTSOUNDBUFFER8 iface,LPDSBCAPS caps)
1353 {
1354         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1355         TRACE("(%p)->(%p)\n",This,caps);
1356
1357         return IDirectSoundBufferImpl_GetCaps((LPDIRECTSOUNDBUFFER8)This->dsb,caps);
1358 }
1359
1360 static HRESULT WINAPI SecondaryBufferImpl_GetCurrentPosition(
1361         LPDIRECTSOUNDBUFFER8 iface,LPDWORD playpos,LPDWORD writepos)
1362 {
1363         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1364         TRACE("(%p,%p,%p)\n",This,playpos,writepos);
1365
1366         return IDirectSoundBufferImpl_GetCurrentPosition((LPDIRECTSOUNDBUFFER8)This->dsb,playpos,writepos);
1367 }
1368
1369 static HRESULT WINAPI SecondaryBufferImpl_GetFormat(
1370         LPDIRECTSOUNDBUFFER8 iface,LPWAVEFORMATEX lpwf,DWORD wfsize,LPDWORD wfwritten)
1371 {
1372         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1373         TRACE("(%p,%p,%ld,%p)\n",This,lpwf,wfsize,wfwritten);
1374
1375         return IDirectSoundBufferImpl_GetFormat((LPDIRECTSOUNDBUFFER8)This->dsb,lpwf,wfsize,wfwritten);
1376 }
1377
1378 static HRESULT WINAPI SecondaryBufferImpl_GetVolume(
1379         LPDIRECTSOUNDBUFFER8 iface,LPLONG vol)
1380 {
1381         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1382         TRACE("(%p,%p)\n",This,vol);
1383
1384         return IDirectSoundBufferImpl_GetVolume((LPDIRECTSOUNDBUFFER8)This->dsb,vol);
1385 }
1386
1387 static HRESULT WINAPI SecondaryBufferImpl_GetPan(
1388         LPDIRECTSOUNDBUFFER8 iface,LPLONG pan)
1389 {
1390         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1391         TRACE("(%p,%p)\n",This,pan);
1392
1393         return IDirectSoundBufferImpl_GetPan((LPDIRECTSOUNDBUFFER8)This->dsb,pan);
1394 }
1395
1396 static HRESULT WINAPI SecondaryBufferImpl_GetFrequency(
1397         LPDIRECTSOUNDBUFFER8 iface,LPDWORD freq)
1398 {
1399         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1400         TRACE("(%p,%p)\n",This,freq);
1401
1402         return IDirectSoundBufferImpl_GetFrequency((LPDIRECTSOUNDBUFFER8)This->dsb,freq);
1403 }
1404
1405 static HRESULT WINAPI SecondaryBufferImpl_GetStatus(
1406         LPDIRECTSOUNDBUFFER8 iface,LPDWORD status)
1407 {
1408         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1409         TRACE("(%p,%p)\n",This,status);
1410
1411         return IDirectSoundBufferImpl_GetStatus((LPDIRECTSOUNDBUFFER8)This->dsb,status);
1412 }
1413
1414 static HRESULT WINAPI SecondaryBufferImpl_Initialize(
1415         LPDIRECTSOUNDBUFFER8 iface,LPDIRECTSOUND dsound,LPCDSBUFFERDESC dbsd)
1416 {
1417         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1418         TRACE("(%p,%p,%p)\n",This,dsound,dbsd);
1419
1420         return IDirectSoundBufferImpl_Initialize((LPDIRECTSOUNDBUFFER8)This->dsb,dsound,dbsd);
1421 }
1422
1423 static HRESULT WINAPI SecondaryBufferImpl_Lock(
1424     LPDIRECTSOUNDBUFFER8 iface,
1425     DWORD writecursor,
1426     DWORD writebytes,
1427     LPVOID lplpaudioptr1,
1428     LPDWORD audiobytes1,
1429     LPVOID lplpaudioptr2,
1430     LPDWORD audiobytes2,
1431     DWORD dwFlags)
1432 {
1433     SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1434     TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx)\n",
1435         This,writecursor,writebytes,lplpaudioptr1,audiobytes1,lplpaudioptr2,audiobytes2,dwFlags);
1436
1437     return IDirectSoundBufferImpl_Lock((LPDIRECTSOUNDBUFFER8)This->dsb,
1438         writecursor,writebytes,lplpaudioptr1,audiobytes1,lplpaudioptr2,audiobytes2,dwFlags);
1439 }
1440
1441 static HRESULT WINAPI SecondaryBufferImpl_Play(
1442         LPDIRECTSOUNDBUFFER8 iface,DWORD reserved1,DWORD reserved2,DWORD flags)
1443 {
1444         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1445         TRACE("(%p,%08lx,%08lx,%08lx)\n",This,reserved1,reserved2,flags);
1446
1447         return IDirectSoundBufferImpl_Play((LPDIRECTSOUNDBUFFER8)This->dsb,reserved1,reserved2,flags);
1448 }
1449
1450 static HRESULT WINAPI SecondaryBufferImpl_SetCurrentPosition(
1451         LPDIRECTSOUNDBUFFER8 iface,DWORD newpos)
1452 {
1453         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1454         TRACE("(%p,%ld)\n",This,newpos);
1455
1456         return IDirectSoundBufferImpl_SetCurrentPosition((LPDIRECTSOUNDBUFFER8)This->dsb,newpos);
1457 }
1458
1459 static HRESULT WINAPI SecondaryBufferImpl_SetFormat(
1460         LPDIRECTSOUNDBUFFER8 iface,LPCWAVEFORMATEX wfex)
1461 {
1462         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1463         TRACE("(%p,%p)\n",This,wfex);
1464
1465         return IDirectSoundBufferImpl_SetFormat((LPDIRECTSOUNDBUFFER8)This->dsb,wfex);
1466 }
1467
1468 static HRESULT WINAPI SecondaryBufferImpl_SetVolume(
1469         LPDIRECTSOUNDBUFFER8 iface,LONG vol)
1470 {
1471         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1472         TRACE("(%p,%ld)\n",This,vol);
1473
1474         return IDirectSoundBufferImpl_SetVolume((LPDIRECTSOUNDBUFFER8)This->dsb,vol);
1475 }
1476
1477 static HRESULT WINAPI SecondaryBufferImpl_SetPan(
1478         LPDIRECTSOUNDBUFFER8 iface,LONG pan)
1479 {
1480         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1481         TRACE("(%p,%ld)\n",This,pan);
1482
1483         return IDirectSoundBufferImpl_SetPan((LPDIRECTSOUNDBUFFER8)This->dsb,pan);
1484 }
1485
1486 static HRESULT WINAPI SecondaryBufferImpl_SetFrequency(
1487         LPDIRECTSOUNDBUFFER8 iface,DWORD freq)
1488 {
1489         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1490         TRACE("(%p,%ld)\n",This,freq);
1491
1492         return IDirectSoundBufferImpl_SetFrequency((LPDIRECTSOUNDBUFFER8)This->dsb,freq);
1493 }
1494
1495 static HRESULT WINAPI SecondaryBufferImpl_Stop(LPDIRECTSOUNDBUFFER8 iface)
1496 {
1497         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1498         TRACE("(%p)\n",This);
1499
1500         return IDirectSoundBufferImpl_Stop((LPDIRECTSOUNDBUFFER8)This->dsb);
1501 }
1502
1503 static HRESULT WINAPI SecondaryBufferImpl_Unlock(
1504     LPDIRECTSOUNDBUFFER8 iface,
1505     LPVOID lpvAudioPtr1,
1506     DWORD dwAudioBytes1,
1507     LPVOID lpvAudioPtr2,
1508     DWORD dwAudioBytes2)
1509 {
1510     SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1511     TRACE("(%p,%p,%ld,%p,%ld)\n",
1512         This, lpvAudioPtr1, dwAudioBytes1, lpvAudioPtr2, dwAudioBytes2);
1513
1514     return IDirectSoundBufferImpl_Unlock((LPDIRECTSOUNDBUFFER8)This->dsb,
1515         lpvAudioPtr1,dwAudioBytes1,lpvAudioPtr2,dwAudioBytes2);
1516 }
1517
1518 static HRESULT WINAPI SecondaryBufferImpl_Restore(
1519         LPDIRECTSOUNDBUFFER8 iface)
1520 {
1521         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1522         TRACE("(%p)\n",This);
1523
1524         return IDirectSoundBufferImpl_Restore((LPDIRECTSOUNDBUFFER8)This->dsb);
1525 }
1526
1527 static HRESULT WINAPI SecondaryBufferImpl_SetFX(
1528         LPDIRECTSOUNDBUFFER8 iface,DWORD dwEffectsCount,LPDSEFFECTDESC pDSFXDesc,LPDWORD pdwResultCodes)
1529 {
1530         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1531         TRACE("(%p,%lu,%p,%p)\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes);
1532
1533         return IDirectSoundBufferImpl_SetFX((LPDIRECTSOUNDBUFFER8)This->dsb,dwEffectsCount,pDSFXDesc,pdwResultCodes);
1534 }
1535
1536 static HRESULT WINAPI SecondaryBufferImpl_AcquireResources(
1537         LPDIRECTSOUNDBUFFER8 iface,DWORD dwFlags,DWORD dwEffectsCount,LPDWORD pdwResultCodes)
1538 {
1539         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1540         TRACE("(%p,%08lu,%lu,%p)\n",This,dwFlags,dwEffectsCount,pdwResultCodes);
1541
1542         return IDirectSoundBufferImpl_AcquireResources((LPDIRECTSOUNDBUFFER8)This->dsb,dwFlags,dwEffectsCount,pdwResultCodes);
1543 }
1544
1545 static HRESULT WINAPI SecondaryBufferImpl_GetObjectInPath(
1546         LPDIRECTSOUNDBUFFER8 iface,REFGUID rguidObject,DWORD dwIndex,REFGUID rguidInterface,LPVOID* ppObject)
1547 {
1548         SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1549         TRACE("(%p,%s,%lu,%s,%p)\n",This,debugstr_guid(rguidObject),dwIndex,debugstr_guid(rguidInterface),ppObject);
1550
1551         return IDirectSoundBufferImpl_GetObjectInPath((LPDIRECTSOUNDBUFFER8)This->dsb,rguidObject,dwIndex,rguidInterface,ppObject);
1552 }
1553
1554 static const IDirectSoundBuffer8Vtbl sbvt =
1555 {
1556         SecondaryBufferImpl_QueryInterface,
1557         SecondaryBufferImpl_AddRef,
1558         SecondaryBufferImpl_Release,
1559         SecondaryBufferImpl_GetCaps,
1560         SecondaryBufferImpl_GetCurrentPosition,
1561         SecondaryBufferImpl_GetFormat,
1562         SecondaryBufferImpl_GetVolume,
1563         SecondaryBufferImpl_GetPan,
1564         SecondaryBufferImpl_GetFrequency,
1565         SecondaryBufferImpl_GetStatus,
1566         SecondaryBufferImpl_Initialize,
1567         SecondaryBufferImpl_Lock,
1568         SecondaryBufferImpl_Play,
1569         SecondaryBufferImpl_SetCurrentPosition,
1570         SecondaryBufferImpl_SetFormat,
1571         SecondaryBufferImpl_SetVolume,
1572         SecondaryBufferImpl_SetPan,
1573         SecondaryBufferImpl_SetFrequency,
1574         SecondaryBufferImpl_Stop,
1575         SecondaryBufferImpl_Unlock,
1576         SecondaryBufferImpl_Restore,
1577         SecondaryBufferImpl_SetFX,
1578         SecondaryBufferImpl_AcquireResources,
1579         SecondaryBufferImpl_GetObjectInPath
1580 };
1581
1582 HRESULT SecondaryBufferImpl_Create(
1583         IDirectSoundBufferImpl *dsb,
1584         SecondaryBufferImpl **psb)
1585 {
1586         SecondaryBufferImpl *sb;
1587         TRACE("(%p,%p)\n",dsb,psb);
1588
1589         sb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*sb));
1590
1591         if (sb == 0) {
1592                 WARN("out of memory\n");
1593                 *psb = NULL;
1594                 return DSERR_OUTOFMEMORY;
1595         }
1596         sb->ref = 0;
1597         sb->dsb = dsb;
1598         sb->lpVtbl = &sbvt;
1599
1600         IDirectSoundBuffer8_AddRef((LPDIRECTSOUNDBUFFER8)dsb);
1601         *psb = sb;
1602         return S_OK;
1603 }
1604
1605 HRESULT SecondaryBufferImpl_Destroy(
1606     SecondaryBufferImpl *pdsb)
1607 {
1608     TRACE("(%p)\n",pdsb);
1609
1610     while (SecondaryBufferImpl_Release((LPDIRECTSOUNDBUFFER8)pdsb) > 0);
1611
1612     return S_OK;
1613 }