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