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