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