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