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