3 * Copyright 1998 Marcus Meissner
4 * Copyright 1998 Rob Riggs
5 * Copyright 2000-2002 TransGaming Technologies, Inc.
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.
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.
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
25 #include <sys/types.h>
26 #include <sys/fcntl.h>
30 #include <math.h> /* Insomnia - pow() function */
40 #include "wine/windef16.h"
41 #include "wine/debug.h"
44 #include "dsound_private.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
48 /*******************************************************************************
51 static HRESULT WINAPI IDirectSoundNotifyImpl_QueryInterface(
52 LPDIRECTSOUNDNOTIFY iface,REFIID riid,LPVOID *ppobj
54 ICOM_THIS(IDirectSoundNotifyImpl,iface);
56 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
57 return IDirectSoundBuffer8_QueryInterface((LPDIRECTSOUNDBUFFER8)This->dsb, riid, ppobj);
60 static ULONG WINAPI IDirectSoundNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface) {
61 ICOM_THIS(IDirectSoundNotifyImpl,iface);
64 TRACE("(%p) ref was %ld\n", This, This->ref);
66 ref = InterlockedIncrement(&(This->ref));
70 static ULONG WINAPI IDirectSoundNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface) {
71 ICOM_THIS(IDirectSoundNotifyImpl,iface);
74 TRACE("(%p) ref was %ld\n", This, This->ref);
76 ref = InterlockedDecrement(&(This->ref));
78 IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8)This->dsb);
79 HeapFree(GetProcessHeap(),0,This);
85 static HRESULT WINAPI IDirectSoundNotifyImpl_SetNotificationPositions(
86 LPDIRECTSOUNDNOTIFY iface,DWORD howmuch,LPCDSBPOSITIONNOTIFY notify
88 ICOM_THIS(IDirectSoundNotifyImpl,iface);
91 if (TRACE_ON(dsound)) {
92 TRACE("(%p,0x%08lx,%p)\n",This,howmuch,notify);
93 for (i=0;i<howmuch;i++)
94 TRACE("notify at %ld to 0x%08lx\n",
95 notify[i].dwOffset,(DWORD)notify[i].hEventNotify);
97 This->dsb->notifies = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,This->dsb->notifies,(This->dsb->nrofnotifies+howmuch)*sizeof(DSBPOSITIONNOTIFY));
98 memcpy( This->dsb->notifies+This->dsb->nrofnotifies,
100 howmuch*sizeof(DSBPOSITIONNOTIFY)
102 This->dsb->nrofnotifies+=howmuch;
107 static ICOM_VTABLE(IDirectSoundNotify) dsnvt =
109 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
110 IDirectSoundNotifyImpl_QueryInterface,
111 IDirectSoundNotifyImpl_AddRef,
112 IDirectSoundNotifyImpl_Release,
113 IDirectSoundNotifyImpl_SetNotificationPositions,
116 /*******************************************************************************
120 static HRESULT WINAPI IDirectSoundBufferImpl_SetFormat(
121 LPDIRECTSOUNDBUFFER8 iface,LPWAVEFORMATEX wfex
123 ICOM_THIS(IDirectSoundBufferImpl,iface);
125 TRACE("(%p,%p)\n",This,wfex);
126 /* This method is not available on secondary buffers */
127 return DSERR_INVALIDCALL;
130 static HRESULT WINAPI IDirectSoundBufferImpl_SetVolume(
131 LPDIRECTSOUNDBUFFER8 iface,LONG vol
133 ICOM_THIS(IDirectSoundBufferImpl,iface);
136 TRACE("(%p,%ld)\n",This,vol);
138 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME))
139 return DSERR_CONTROLUNAVAIL;
141 if ((vol > DSBVOLUME_MAX) || (vol < DSBVOLUME_MIN))
142 return DSERR_INVALIDPARAM;
145 EnterCriticalSection(&(This->lock));
147 if (This->dsbd.dwFlags & DSBCAPS_CTRL3D) {
148 oldVol = This->ds3db->lVolume;
149 This->ds3db->lVolume = vol;
151 oldVol = This->volpan.lVolume;
152 This->volpan.lVolume = vol;
153 if (vol != oldVol) DSOUND_RecalcVolPan(&(This->volpan));
158 IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan));
160 else DSOUND_ForceRemix(This);
163 LeaveCriticalSection(&(This->lock));
169 static HRESULT WINAPI IDirectSoundBufferImpl_GetVolume(
170 LPDIRECTSOUNDBUFFER8 iface,LPLONG vol
172 ICOM_THIS(IDirectSoundBufferImpl,iface);
173 TRACE("(%p,%p)\n",This,vol);
176 return DSERR_INVALIDPARAM;
178 if (This->dsbd.dwFlags & DSBCAPS_CTRL3D)
179 *vol = This->ds3db->lVolume;
181 *vol = This->volpan.lVolume;
185 static HRESULT WINAPI IDirectSoundBufferImpl_SetFrequency(
186 LPDIRECTSOUNDBUFFER8 iface,DWORD freq
188 ICOM_THIS(IDirectSoundBufferImpl,iface);
191 TRACE("(%p,%ld)\n",This,freq);
193 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLFREQUENCY))
194 return DSERR_CONTROLUNAVAIL;
196 if (freq == DSBFREQUENCY_ORIGINAL)
197 freq = This->wfx.nSamplesPerSec;
199 if ((freq < DSBFREQUENCY_MIN) || (freq > DSBFREQUENCY_MAX))
200 return DSERR_INVALIDPARAM;
203 EnterCriticalSection(&(This->lock));
205 oldFreq = This->freq;
207 if (freq != oldFreq) {
208 This->freqAdjust = (freq << DSOUND_FREQSHIFT) / This->dsound->wfx.nSamplesPerSec;
209 This->nAvgBytesPerSec = freq * This->wfx.nBlockAlign;
210 DSOUND_RecalcFormat(This);
211 if (!This->hwbuf) DSOUND_ForceRemix(This);
214 LeaveCriticalSection(&(This->lock));
220 static HRESULT WINAPI IDirectSoundBufferImpl_Play(
221 LPDIRECTSOUNDBUFFER8 iface,DWORD reserved1,DWORD reserved2,DWORD flags
223 ICOM_THIS(IDirectSoundBufferImpl,iface);
224 TRACE("(%p,%08lx,%08lx,%08lx)\n",
225 This,reserved1,reserved2,flags
229 EnterCriticalSection(&(This->lock));
231 This->playflags = flags;
232 if (This->state == STATE_STOPPED) {
234 This->startpos = This->buf_mixpos;
235 This->state = STATE_STARTING;
236 } else if (This->state == STATE_STOPPING)
237 This->state = STATE_PLAYING;
239 IDsDriverBuffer_Play(This->hwbuf, 0, 0, This->playflags);
240 This->state = STATE_PLAYING;
243 LeaveCriticalSection(&(This->lock));
249 static HRESULT WINAPI IDirectSoundBufferImpl_Stop(LPDIRECTSOUNDBUFFER8 iface)
251 ICOM_THIS(IDirectSoundBufferImpl,iface);
252 TRACE("(%p)\n",This);
255 EnterCriticalSection(&(This->lock));
257 if (This->state == STATE_PLAYING)
258 This->state = STATE_STOPPING;
259 else if (This->state == STATE_STARTING)
260 This->state = STATE_STOPPED;
262 IDsDriverBuffer_Stop(This->hwbuf);
263 This->state = STATE_STOPPED;
265 DSOUND_CheckEvent(This, 0);
267 LeaveCriticalSection(&(This->lock));
273 static DWORD WINAPI IDirectSoundBufferImpl_AddRef(LPDIRECTSOUNDBUFFER8 iface) {
274 ICOM_THIS(IDirectSoundBufferImpl,iface);
277 TRACE("(%p) ref was %ld, thread is %lx\n",This, This->ref, GetCurrentThreadId());
279 ref = InterlockedIncrement(&(This->ref));
281 FIXME("thread-safety alert! AddRef-ing with a zero refcount!\n");
285 static DWORD WINAPI IDirectSoundBufferImpl_Release(LPDIRECTSOUNDBUFFER8 iface) {
286 ICOM_THIS(IDirectSoundBufferImpl,iface);
290 TRACE("(%p) ref was %ld, thread is %lx\n",This, This->ref, GetCurrentThreadId());
292 ref = InterlockedDecrement(&(This->ref));
295 RtlAcquireResourceExclusive(&(This->dsound->lock), TRUE);
296 for (i=0;i<This->dsound->nrofbuffers;i++)
297 if (This->dsound->buffers[i] == This)
300 if (i < This->dsound->nrofbuffers) {
301 /* Put the last buffer of the list in the (now empty) position */
302 This->dsound->buffers[i] = This->dsound->buffers[This->dsound->nrofbuffers - 1];
303 This->dsound->nrofbuffers--;
304 This->dsound->buffers = HeapReAlloc(GetProcessHeap(),0,This->dsound->buffers,sizeof(LPDIRECTSOUNDBUFFER8)*This->dsound->nrofbuffers);
305 TRACE("buffer count is now %d\n", This->dsound->nrofbuffers);
306 IDirectSound_Release((LPDIRECTSOUND)This->dsound);
308 RtlReleaseResource(&(This->dsound->lock));
310 DeleteCriticalSection(&(This->lock));
312 IDsDriverBuffer_Release(This->hwbuf);
313 if (This->dsound->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY)
314 HeapFree(GetProcessHeap(),0,This->buffer);
316 else if (!This->parent)
317 HeapFree(GetProcessHeap(),0,This->buffer);
319 DeleteCriticalSection(&This->ds3db->lock);
320 HeapFree(GetProcessHeap(), 0, This->ds3db);
323 HeapFree(GetProcessHeap(), 0, This->iks);
326 IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8)This->parent);
328 HeapFree(GetProcessHeap(),0,This);
333 DWORD DSOUND_CalcPlayPosition(IDirectSoundBufferImpl *This,
334 DWORD state, DWORD pplay, DWORD pwrite, DWORD pmix, DWORD bmix)
338 TRACE("primary playpos=%ld, mixpos=%ld\n", pplay, pmix);
339 TRACE("this mixpos=%ld, time=%ld\n", bmix, GetTickCount());
341 /* the actual primary play position (pplay) is always behind last mixed (pmix),
342 * unless the computer is too slow or something */
343 /* we need to know how far away we are from there */
344 #if 0 /* we'll never fill the primary entirely */
346 if ((state == STATE_PLAYING) || (state == STATE_STOPPING)) {
347 /* wow, the software mixer is really doing well,
348 * seems the entire primary buffer is filled! */
349 pmix += This->dsound->buflen;
351 /* else: the primary buffer is not playing, so probably empty */
354 if (pmix < pplay) pmix += This->dsound->buflen; /* wraparound */
356 /* detect buffer underrun */
357 if (pwrite < pplay) pwrite += This->dsound->buflen; /* wraparound */
359 if (pmix > (ds_snd_queue_max * This->dsound->fraglen + pwrite + This->dsound->writelead)) {
360 WARN("detected an underrun: primary queue was %ld\n",pmix);
363 /* divide the offset by its sample size */
364 pmix /= This->dsound->wfx.nBlockAlign;
365 TRACE("primary back-samples=%ld\n",pmix);
366 /* adjust for our frequency */
367 pmix = (pmix * This->freqAdjust) >> DSOUND_FREQSHIFT;
368 /* multiply by our own sample size */
369 pmix *= This->wfx.nBlockAlign;
370 TRACE("this back-offset=%ld\n", pmix);
371 /* subtract from our last mixed position */
373 while (bplay < pmix) bplay += This->buflen; /* wraparound */
375 if (This->leadin && ((bplay < This->startpos) || (bplay > bmix))) {
376 /* seems we haven't started playing yet */
377 TRACE("this still in lead-in phase\n");
378 bplay = This->startpos;
380 /* return the result */
384 static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition(
385 LPDIRECTSOUNDBUFFER8 iface,LPDWORD playpos,LPDWORD writepos
388 ICOM_THIS(IDirectSoundBufferImpl,iface);
389 TRACE("(%p,%p,%p)\n",This,playpos,writepos);
391 hres=IDsDriverBuffer_GetPosition(This->hwbuf,playpos,writepos);
396 if (playpos && (This->state != STATE_PLAYING)) {
397 /* we haven't been merged into the primary buffer (yet) */
398 *playpos = This->buf_mixpos;
401 DWORD pplay, pwrite, lplay, splay, pstate;
402 /* let's get this exact; first, recursively call GetPosition on the primary */
403 EnterCriticalSection(&(This->dsound->mixlock));
404 DSOUND_PrimaryGetPosition(This->dsound, &pplay, &pwrite);
405 /* detect HEL mode underrun */
406 pstate = This->dsound->state;
407 if (!(This->dsound->hwbuf || This->dsound->pwqueue)) {
408 TRACE("detected an underrun\n");
410 if (pstate == STATE_PLAYING)
411 pstate = STATE_STARTING;
412 else if (pstate == STATE_STOPPING)
413 pstate = STATE_STOPPED;
415 /* get data for ourselves while we still have the lock */
416 pstate &= This->state;
417 lplay = This->primary_mixpos;
418 splay = This->buf_mixpos;
419 if ((This->dsbd.dwFlags & DSBCAPS_GETCURRENTPOSITION2) || This->dsound->hwbuf) {
420 /* calculate play position using this */
421 *playpos = DSOUND_CalcPlayPosition(This, pstate, pplay, pwrite, lplay, splay);
423 /* (unless the app isn't using GETCURRENTPOSITION2) */
424 /* don't know exactly how this should be handled...
425 * the docs says that play cursor is reported as directly
426 * behind write cursor, hmm... */
427 /* let's just do what might work for Half-Life */
429 wp = (This->dsound->pwplay + ds_hel_margin) * This->dsound->fraglen;
430 while (wp >= This->dsound->buflen)
431 wp -= This->dsound->buflen;
432 *playpos = DSOUND_CalcPlayPosition(This, pstate, wp, pwrite, lplay, splay);
434 LeaveCriticalSection(&(This->dsound->mixlock));
436 if (writepos) *writepos = This->buf_mixpos;
439 if (This->state != STATE_STOPPED)
440 /* apply the documented 10ms lead to writepos */
441 *writepos += This->writelead;
442 while (*writepos >= This->buflen) *writepos -= This->buflen;
444 if (playpos) This->last_playpos = *playpos;
445 TRACE("playpos = %ld, writepos = %ld (%p, time=%ld)\n", playpos?*playpos:0, writepos?*writepos:0, This, GetTickCount());
449 static HRESULT WINAPI IDirectSoundBufferImpl_GetStatus(
450 LPDIRECTSOUNDBUFFER8 iface,LPDWORD status
452 ICOM_THIS(IDirectSoundBufferImpl,iface);
453 TRACE("(%p,%p), thread is %lx\n",This,status,GetCurrentThreadId());
456 return DSERR_INVALIDPARAM;
459 if ((This->state == STATE_STARTING) || (This->state == STATE_PLAYING)) {
460 *status |= DSBSTATUS_PLAYING;
461 if (This->playflags & DSBPLAY_LOOPING)
462 *status |= DSBSTATUS_LOOPING;
465 TRACE("status=%lx\n", *status);
470 static HRESULT WINAPI IDirectSoundBufferImpl_GetFormat(
471 LPDIRECTSOUNDBUFFER8 iface,LPWAVEFORMATEX lpwf,DWORD wfsize,LPDWORD wfwritten
473 ICOM_THIS(IDirectSoundBufferImpl,iface);
474 TRACE("(%p,%p,%ld,%p)\n",This,lpwf,wfsize,wfwritten);
476 if (wfsize>sizeof(This->wfx))
477 wfsize = sizeof(This->wfx);
478 if (lpwf) { /* NULL is valid */
479 memcpy(lpwf,&(This->wfx),wfsize);
484 *wfwritten = sizeof(This->wfx);
486 return DSERR_INVALIDPARAM;
491 static HRESULT WINAPI IDirectSoundBufferImpl_Lock(
492 LPDIRECTSOUNDBUFFER8 iface,DWORD writecursor,DWORD writebytes,LPVOID lplpaudioptr1,LPDWORD audiobytes1,LPVOID lplpaudioptr2,LPDWORD audiobytes2,DWORD flags
494 ICOM_THIS(IDirectSoundBufferImpl,iface);
496 TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx) at %ld\n",
508 if (flags & DSBLOCK_FROMWRITECURSOR) {
510 /* GetCurrentPosition does too much magic to duplicate here */
511 IDirectSoundBufferImpl_GetCurrentPosition(iface, NULL, &writepos);
512 writecursor += writepos;
514 while (writecursor >= This->buflen)
515 writecursor -= This->buflen;
516 if (flags & DSBLOCK_ENTIREBUFFER)
517 writebytes = This->buflen;
518 if (writebytes > This->buflen)
519 writebytes = This->buflen;
521 assert(audiobytes1!=audiobytes2);
522 assert(lplpaudioptr1!=lplpaudioptr2);
524 if ((writebytes == This->buflen) &&
525 ((This->state == STATE_STARTING) ||
526 (This->state == STATE_PLAYING)))
527 /* some games, like Half-Life, try to be clever (not) and
528 * keep one secondary buffer, and mix sounds into it itself,
529 * locking the entire buffer every time... so we can just forget
530 * about tracking the last-written-to-position... */
531 This->probably_valid_to = (DWORD)-1;
533 This->probably_valid_to = writecursor;
535 if (!(This->dsound->drvdesc.dwFlags & DSDDESC_DONTNEEDSECONDARYLOCK) && This->hwbuf) {
536 IDsDriverBuffer_Lock(This->hwbuf,
537 lplpaudioptr1, audiobytes1,
538 lplpaudioptr2, audiobytes2,
539 writecursor, writebytes,
544 if (writecursor+writebytes <= This->buflen) {
545 *(LPBYTE*)lplpaudioptr1 = This->buffer+writecursor;
546 *audiobytes1 = writebytes;
548 *(LPBYTE*)lplpaudioptr2 = NULL;
551 TRACE("->%ld.0\n",writebytes);
553 *(LPBYTE*)lplpaudioptr1 = This->buffer+writecursor;
554 *audiobytes1 = This->buflen-writecursor;
556 *(LPBYTE*)lplpaudioptr2 = This->buffer;
558 *audiobytes2 = writebytes-(This->buflen-writecursor);
559 TRACE("->%ld.%ld\n",*audiobytes1,audiobytes2?*audiobytes2:0);
561 if (This->state == STATE_PLAYING) {
562 /* if the segment between playpos and buf_mixpos is touched,
563 * we need to cancel some mixing */
564 /* we'll assume that the app always calls GetCurrentPosition before
565 * locking a playing buffer, so that last_playpos is up-to-date */
566 if (This->buf_mixpos >= This->last_playpos) {
567 if (This->buf_mixpos > writecursor &&
568 This->last_playpos < writecursor+writebytes)
572 if (This->buf_mixpos > writecursor ||
573 This->last_playpos < writecursor+writebytes)
577 TRACE("locking prebuffered region, ouch\n");
578 DSOUND_MixCancelAt(This, writecursor);
585 static HRESULT WINAPI IDirectSoundBufferImpl_SetCurrentPosition(
586 LPDIRECTSOUNDBUFFER8 iface,DWORD newpos
588 ICOM_THIS(IDirectSoundBufferImpl,iface);
589 TRACE("(%p,%ld)\n",This,newpos);
592 EnterCriticalSection(&(This->lock));
594 while (newpos >= This->buflen)
595 newpos -= This->buflen;
596 This->buf_mixpos = newpos;
598 IDsDriverBuffer_SetPosition(This->hwbuf, This->buf_mixpos);
600 LeaveCriticalSection(&(This->lock));
606 static HRESULT WINAPI IDirectSoundBufferImpl_SetPan(
607 LPDIRECTSOUNDBUFFER8 iface,LONG pan
609 ICOM_THIS(IDirectSoundBufferImpl,iface);
612 TRACE("(%p,%ld)\n",This,pan);
614 if ((pan > DSBPAN_RIGHT) || (pan < DSBPAN_LEFT))
615 return DSERR_INVALIDPARAM;
617 /* You cannot use both pan and 3D controls */
618 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN) ||
619 (This->dsbd.dwFlags & DSBCAPS_CTRL3D))
620 return DSERR_CONTROLUNAVAIL;
623 EnterCriticalSection(&(This->lock));
625 oldPan = This->volpan.lPan;
626 This->volpan.lPan = pan;
629 DSOUND_RecalcVolPan(&(This->volpan));
632 IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan));
634 else DSOUND_ForceRemix(This);
637 LeaveCriticalSection(&(This->lock));
643 static HRESULT WINAPI IDirectSoundBufferImpl_GetPan(
644 LPDIRECTSOUNDBUFFER8 iface,LPLONG pan
646 ICOM_THIS(IDirectSoundBufferImpl,iface);
647 TRACE("(%p,%p)\n",This,pan);
650 return DSERR_INVALIDPARAM;
652 *pan = This->volpan.lPan;
657 static HRESULT WINAPI IDirectSoundBufferImpl_Unlock(
658 LPDIRECTSOUNDBUFFER8 iface,LPVOID p1,DWORD x1,LPVOID p2,DWORD x2
660 ICOM_THIS(IDirectSoundBufferImpl,iface);
661 DWORD probably_valid_to;
663 TRACE("(%p,%p,%ld,%p,%ld):stub\n", This,p1,x1,p2,x2);
666 /* Preprocess 3D buffers... */
668 /* This is highly experimental and liable to break things */
669 if (This->dsbd.dwFlags & DSBCAPS_CTRL3D)
670 DSOUND_Create3DBuffer(This);
673 if (!(This->dsound->drvdesc.dwFlags & DSDDESC_DONTNEEDSECONDARYLOCK) && This->hwbuf) {
674 IDsDriverBuffer_Unlock(This->hwbuf, p1, x1, p2, x2);
677 if (p2) probably_valid_to = (((LPBYTE)p2)-This->buffer) + x2;
678 else probably_valid_to = (((LPBYTE)p1)-This->buffer) + x1;
679 while (probably_valid_to >= This->buflen)
680 probably_valid_to -= This->buflen;
681 if ((probably_valid_to == 0) && ((x1+x2) == This->buflen) &&
682 ((This->state == STATE_STARTING) ||
683 (This->state == STATE_PLAYING)))
684 /* see IDirectSoundBufferImpl_Lock */
685 probably_valid_to = (DWORD)-1;
686 This->probably_valid_to = probably_valid_to;
691 static HRESULT WINAPI IDirectSoundBufferImpl_Restore(
692 LPDIRECTSOUNDBUFFER8 iface
694 ICOM_THIS(IDirectSoundBufferImpl,iface);
695 FIXME("(%p):stub\n",This);
699 static HRESULT WINAPI IDirectSoundBufferImpl_GetFrequency(
700 LPDIRECTSOUNDBUFFER8 iface,LPDWORD freq
702 ICOM_THIS(IDirectSoundBufferImpl,iface);
703 TRACE("(%p,%p)\n",This,freq);
706 return DSERR_INVALIDPARAM;
709 TRACE("-> %ld\n", *freq);
714 static HRESULT WINAPI IDirectSoundBufferImpl_SetFX(
715 LPDIRECTSOUNDBUFFER8 iface,DWORD dwEffectsCount,LPDSEFFECTDESC pDSFXDesc,LPDWORD pdwResultCodes
717 ICOM_THIS(IDirectSoundBufferImpl,iface);
720 FIXME("(%p,%lu,%p,%p): stub\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes);
723 for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
725 return DSERR_CONTROLUNAVAIL;
728 static HRESULT WINAPI IDirectSoundBufferImpl_AcquireResources(
729 LPDIRECTSOUNDBUFFER8 iface,DWORD dwFlags,DWORD dwEffectsCount,LPDWORD pdwResultCodes
731 ICOM_THIS(IDirectSoundBufferImpl,iface);
734 FIXME("(%p,%08lu,%lu,%p): stub\n",This,dwFlags,dwEffectsCount,pdwResultCodes);
737 for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
739 return DSERR_CONTROLUNAVAIL;
742 static HRESULT WINAPI IDirectSoundBufferImpl_GetObjectInPath(
743 LPDIRECTSOUNDBUFFER8 iface,REFGUID rguidObject,DWORD dwIndex,REFGUID rguidInterface,LPVOID* ppObject
745 ICOM_THIS(IDirectSoundBufferImpl,iface);
747 FIXME("(%p,%s,%lu,%s,%p): stub\n",This,debugstr_guid(rguidObject),dwIndex,debugstr_guid(rguidInterface),ppObject);
749 return DSERR_CONTROLUNAVAIL;
752 static HRESULT WINAPI IDirectSoundBufferImpl_Initialize(
753 LPDIRECTSOUNDBUFFER8 iface,LPDIRECTSOUND8 dsound,LPDSBUFFERDESC dbsd
755 ICOM_THIS(IDirectSoundBufferImpl,iface);
756 FIXME("(%p,%p,%p):stub\n",This,dsound,dbsd);
757 DPRINTF("Re-Init!!!\n");
758 return DSERR_ALREADYINITIALIZED;
761 static HRESULT WINAPI IDirectSoundBufferImpl_GetCaps(
762 LPDIRECTSOUNDBUFFER8 iface,LPDSBCAPS caps
764 ICOM_THIS(IDirectSoundBufferImpl,iface);
765 TRACE("(%p)->(%p)\n",This,caps);
768 return DSERR_INVALIDPARAM;
770 /* I think we should check this value, not set it. See */
771 /* Inside DirectX, p215. That should apply here, too. */
772 caps->dwSize = sizeof(*caps);
774 caps->dwFlags = This->dsbd.dwFlags;
775 if (This->hwbuf) caps->dwFlags |= DSBCAPS_LOCHARDWARE;
776 else caps->dwFlags |= DSBCAPS_LOCSOFTWARE;
778 caps->dwBufferBytes = This->buflen;
780 /* This value represents the speed of the "unlock" command.
781 As unlock is quite fast (it does not do anything), I put
782 4096 ko/s = 4 Mo / s */
783 /* FIXME: hwbuf speed */
784 caps->dwUnlockTransferRate = 4096;
785 caps->dwPlayCpuOverhead = 0;
790 static HRESULT WINAPI IDirectSoundBufferImpl_QueryInterface(
791 LPDIRECTSOUNDBUFFER8 iface,REFIID riid,LPVOID *ppobj
793 ICOM_THIS(IDirectSoundBufferImpl,iface);
795 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
797 if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
798 IDirectSoundNotifyImpl *dsn;
800 dsn = (IDirectSoundNotifyImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(*dsn));
803 IDirectSoundBuffer8_AddRef(iface);
804 ICOM_VTBL(dsn) = &dsnvt;
805 *ppobj = (LPVOID)dsn;
809 if ( IsEqualGUID( &IID_IDirectSound3DBuffer, riid ) ) {
811 IDirectSound3DBufferImpl_Create(This, &This->ds3db);
812 *ppobj = This->ds3db;
814 IDirectSound3DBuffer_AddRef((LPDIRECTSOUND3DBUFFER)*ppobj);
820 if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) {
821 ERR("app requested IDirectSound3DListener on secondary buffer\n");
826 if ( IsEqualGUID( &IID_IKsPropertySet, riid ) ) {
828 IKsPropertySetImpl_Create(This, &This->iks);
831 IKsPropertySet_AddRef((LPKSPROPERTYSET)*ppobj);
837 FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
841 return E_NOINTERFACE;
844 static ICOM_VTABLE(IDirectSoundBuffer8) dsbvt =
846 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
847 IDirectSoundBufferImpl_QueryInterface,
848 IDirectSoundBufferImpl_AddRef,
849 IDirectSoundBufferImpl_Release,
850 IDirectSoundBufferImpl_GetCaps,
851 IDirectSoundBufferImpl_GetCurrentPosition,
852 IDirectSoundBufferImpl_GetFormat,
853 IDirectSoundBufferImpl_GetVolume,
854 IDirectSoundBufferImpl_GetPan,
855 IDirectSoundBufferImpl_GetFrequency,
856 IDirectSoundBufferImpl_GetStatus,
857 IDirectSoundBufferImpl_Initialize,
858 IDirectSoundBufferImpl_Lock,
859 IDirectSoundBufferImpl_Play,
860 IDirectSoundBufferImpl_SetCurrentPosition,
861 IDirectSoundBufferImpl_SetFormat,
862 IDirectSoundBufferImpl_SetVolume,
863 IDirectSoundBufferImpl_SetPan,
864 IDirectSoundBufferImpl_SetFrequency,
865 IDirectSoundBufferImpl_Stop,
866 IDirectSoundBufferImpl_Unlock,
867 IDirectSoundBufferImpl_Restore,
868 IDirectSoundBufferImpl_SetFX,
869 IDirectSoundBufferImpl_AcquireResources,
870 IDirectSoundBufferImpl_GetObjectInPath
873 HRESULT WINAPI SecondaryBuffer_Create(
874 IDirectSoundImpl *This,
875 IDirectSoundBufferImpl **pdsb,
878 IDirectSoundBufferImpl *dsb;
879 LPWAVEFORMATEX wfex = dsbd->lpwfxFormat;
884 if (dsbd->dwBufferBytes < DSBSIZE_MIN || dsbd->dwBufferBytes > DSBSIZE_MAX) {
885 ERR("invalid sound buffer size %ld\n", dsbd->dwBufferBytes);
886 return DSERR_INVALIDPARAM; /* FIXME: which error? */
889 dsb = (IDirectSoundBufferImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb));
893 ICOM_VTBL(dsb) = &dsbvt;
895 memcpy(&dsb->dsbd, dsbd, sizeof(*dsbd));
897 memcpy(&dsb->wfx, wfex, sizeof(dsb->wfx));
899 TRACE("Created buffer at %p\n", dsb);
901 dsb->buflen = dsbd->dwBufferBytes;
902 dsb->freq = dsbd->lpwfxFormat->nSamplesPerSec;
904 /* Check necessary hardware mixing capabilities */
905 if (wfex->nChannels==2) capf |= DSCAPS_SECONDARYSTEREO;
906 else capf |= DSCAPS_SECONDARYMONO;
907 if (wfex->wBitsPerSample==16) capf |= DSCAPS_SECONDARY16BIT;
908 else capf |= DSCAPS_SECONDARY8BIT;
909 use_hw = (This->drvcaps.dwFlags & capf) == capf;
911 /* FIXME: check hardware sample rate mixing capabilities */
912 /* FIXME: check app hints for software/hardware buffer (STATIC, LOCHARDWARE, etc) */
913 /* FIXME: check whether any hardware buffers are left */
914 /* FIXME: handle DSDHEAP_CREATEHEAP for hardware buffers */
916 /* Allocate system memory if applicable */
917 if ((This->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) || !use_hw) {
918 dsb->buffer = (LPBYTE)HeapAlloc(GetProcessHeap(),0,dsb->buflen);
919 if (dsb->buffer == NULL)
920 err = DSERR_OUTOFMEMORY;
923 /* Allocate the hardware buffer */
924 if (use_hw && (err == DS_OK)) {
925 err = IDsDriver_CreateSoundBuffer(This->driver,wfex,dsbd->dwFlags,0,
926 &(dsb->buflen),&(dsb->buffer),
927 (LPVOID*)&(dsb->hwbuf));
932 HeapFree(GetProcessHeap(),0,dsb->buffer);
933 HeapFree(GetProcessHeap(),0,dsb);
937 /* calculate fragment size and write lead */
938 DSOUND_RecalcFormat(dsb);
940 /* It's not necessary to initialize values to zero since */
941 /* we allocated this structure with HEAP_ZERO_MEMORY... */
944 dsb->state = STATE_STOPPED;
946 dsb->freqAdjust = (dsb->freq << DSOUND_FREQSHIFT) /
947 This->wfx.nSamplesPerSec;
948 dsb->nAvgBytesPerSec = dsb->freq *
949 dsbd->lpwfxFormat->nBlockAlign;
951 if (dsbd->dwFlags & DSBCAPS_CTRL3D) {
952 IDirectSound3DBufferImpl_Create(dsb, &dsb->ds3db);
955 DSOUND_RecalcVolPan(&(dsb->volpan));
957 InitializeCriticalSection(&(dsb->lock));
959 /* register buffer */
960 RtlAcquireResourceExclusive(&(This->lock), TRUE);
961 if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
962 IDirectSoundBufferImpl **newbuffers = (IDirectSoundBufferImpl**)HeapReAlloc(GetProcessHeap(),0,This->buffers,sizeof(IDirectSoundBufferImpl*)*(This->nrofbuffers+1));
964 This->buffers = newbuffers;
965 This->buffers[This->nrofbuffers] = dsb;
967 TRACE("buffer count is now %d\n", This->nrofbuffers);
969 ERR("out of memory for buffer list! Current buffer count is %d\n", This->nrofbuffers);
970 err = DSERR_OUTOFMEMORY;
973 RtlReleaseResource(&(This->lock));
974 IDirectSound8_AddRef((LPDIRECTSOUND8)This);
978 IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8)dsb);