3 * Copyright 1998 Marcus Meissner
4 * Copyright 1998 Rob Riggs
5 * Copyright 2000-2001 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
22 * Most thread locking is complete. There may be a few race
23 * conditions still lurking.
25 * Tested with a Soundblaster clone, a Gravis UltraSound Classic,
26 * and a Turtle Beach Tropez+.
29 * Implement DirectSoundCapture API
30 * Implement SetCooperativeLevel properly (need to address focus issues)
31 * Implement DirectSound3DBuffers (stubs in place)
32 * Use hardware 3D support if available
33 * Add critical section locking inside Release and AddRef methods
34 * Handle static buffers - put those in hardware, non-static not in hardware
35 * Hardware DuplicateSoundBuffer
36 * Proper volume calculation, and setting volume in HEL primary buffer
37 * Optimize WINMM and negotiate fragment size, decrease DS_HEL_MARGIN
41 #include "wine/port.h"
45 #include <sys/types.h>
46 #include <sys/fcntl.h>
50 #include <math.h> /* Insomnia - pow() function */
59 #include "wine/windef16.h"
60 #include "wine/debug.h"
64 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
66 /* these are eligible for tuning... they must be high on slow machines... */
67 /* some stuff may get more responsive with lower values though... */
68 #define DS_EMULDRIVER 1 /* some games (Quake 2, UT) refuse to accept
69 emulated dsound devices. set to 0 ! */
70 #define DS_HEL_FRAGS 48 /* HEL only: number of waveOut fragments in primary buffer
71 * (changing this won't help you) */
72 #define DS_HEL_MARGIN 5 /* HEL only: number of waveOut fragments ahead to mix in new buffers
73 * (keep this close or equal to DS_HEL_QUEUE for best results) */
74 #define DS_HEL_QUEUE 5 /* HEL only: number of waveOut fragments ahead to queue to driver
75 * (this will affect HEL sound reliability and latency) */
77 #define DS_SND_QUEUE_MAX 28 /* max number of fragments to prebuffer */
78 #define DS_SND_QUEUE_MIN 12 /* min number of fragments to prebuffer */
80 /* Linux does not support better timing than 10ms */
81 #define DS_TIME_RES 10 /* Resolution of multimedia timer */
82 #define DS_TIME_DEL 10 /* Delay of multimedia timer callback, and duration of HEL fragment */
84 /*****************************************************************************
85 * Predeclare the interface implementation structures
87 typedef struct IDirectSoundImpl IDirectSoundImpl;
88 typedef struct IDirectSoundBufferImpl IDirectSoundBufferImpl;
89 typedef struct IDirectSoundNotifyImpl IDirectSoundNotifyImpl;
90 typedef struct IDirectSound3DListenerImpl IDirectSound3DListenerImpl;
91 typedef struct IDirectSound3DBufferImpl IDirectSound3DBufferImpl;
92 typedef struct IDirectSoundCaptureImpl IDirectSoundCaptureImpl;
93 typedef struct IDirectSoundCaptureBufferImpl IDirectSoundCaptureBufferImpl;
94 typedef struct IKsPropertySetImpl IKsPropertySetImpl;
96 /*****************************************************************************
97 * IDirectSound implementation structure
99 struct IDirectSoundImpl
101 /* IUnknown fields */
102 ICOM_VFIELD(IDirectSound);
104 /* IDirectSoundImpl fields */
106 DSDRIVERDESC drvdesc;
107 DSDRIVERCAPS drvcaps;
109 LPWAVEHDR pwave[DS_HEL_FRAGS];
110 UINT timerID, pwplay, pwwrite, pwqueue, prebuf;
114 IDirectSoundBufferImpl** buffers;
115 IDirectSoundBufferImpl* primary;
116 IDirectSound3DListenerImpl* listener;
117 WAVEFORMATEX wfx; /* current main waveformat */
118 CRITICAL_SECTION lock;
121 /*****************************************************************************
122 * IDirectSoundBuffer implementation structure
124 struct IDirectSoundBufferImpl
126 /* FIXME: document */
127 /* IUnknown fields */
128 ICOM_VFIELD(IDirectSoundBuffer);
130 /* IDirectSoundBufferImpl fields */
131 PIDSDRIVERBUFFER hwbuf;
134 IDirectSound3DBufferImpl* ds3db;
135 DWORD playflags,state,leadin;
136 DWORD playpos,startpos,writelead,buflen;
137 DWORD nAvgBytesPerSec;
140 IDirectSoundBufferImpl* parent; /* for duplicates */
141 IDirectSoundImpl* dsound;
143 LPDSBPOSITIONNOTIFY notifies;
145 CRITICAL_SECTION lock;
146 /* used for frequency conversion (PerfectPitch) */
147 ULONG freqAdjust, freqAcc;
148 /* used for intelligent (well, sort of) prebuffering */
149 DWORD probably_valid_to;
150 DWORD primary_mixpos, buf_mixpos;
154 #define STATE_STOPPED 0
155 #define STATE_STARTING 1
156 #define STATE_PLAYING 2
157 #define STATE_STOPPING 3
159 /*****************************************************************************
160 * IDirectSoundNotify implementation structure
162 struct IDirectSoundNotifyImpl
164 /* IUnknown fields */
165 ICOM_VFIELD(IDirectSoundNotify);
167 /* IDirectSoundNotifyImpl fields */
168 IDirectSoundBufferImpl* dsb;
171 /*****************************************************************************
172 * IDirectSound3DListener implementation structure
174 struct IDirectSound3DListenerImpl
176 /* IUnknown fields */
177 ICOM_VFIELD(IDirectSound3DListener);
179 /* IDirectSound3DListenerImpl fields */
180 IDirectSoundBufferImpl* dsb;
182 CRITICAL_SECTION lock;
185 struct IKsPropertySetImpl
187 /* IUnknown fields */
188 ICOM_VFIELD(IKsPropertySet);
190 /* IKsPropertySetImpl fields */
191 IDirectSound3DBufferImpl *ds3db; /* backptr, no ref */
194 /*****************************************************************************
195 * IDirectSound3DBuffer implementation structure
197 struct IDirectSound3DBufferImpl
199 /* IUnknown fields */
200 ICOM_VFIELD(IDirectSound3DBuffer);
202 /* IDirectSound3DBufferImpl fields */
203 IDirectSoundBufferImpl* dsb;
207 CRITICAL_SECTION lock;
208 IKsPropertySetImpl* iks;
212 /*****************************************************************************
213 * IDirectSoundCapture implementation structure
215 struct IDirectSoundCaptureImpl
217 /* IUnknown fields */
218 ICOM_VFIELD(IDirectSoundCapture);
221 /* IDirectSoundCaptureImpl fields */
222 CRITICAL_SECTION lock;
225 /*****************************************************************************
226 * IDirectSoundCapture implementation structure
228 struct IDirectSoundCaptureBufferImpl
230 /* IUnknown fields */
231 ICOM_VFIELD(IDirectSoundCaptureBuffer);
234 /* IDirectSoundCaptureBufferImpl fields */
235 CRITICAL_SECTION lock;
239 /* #define USE_DSOUND3D 1 */
241 #define DSOUND_FREQSHIFT (14)
243 static IDirectSoundImpl* dsound = NULL;
245 static IDirectSoundBufferImpl* primarybuf = NULL;
247 static void DSOUND_CheckEvent(IDirectSoundBufferImpl *dsb, int len);
248 static void DSOUND_MixCancelAt(IDirectSoundBufferImpl *dsb, DWORD buf_writepos);
250 static void DSOUND_WaveQueue(IDirectSoundImpl *dsound, DWORD mixq);
251 static void DSOUND_PerformMix(void);
252 static void CALLBACK DSOUND_callback(HWAVEOUT hwo, UINT msg, DWORD dwUser, DWORD dw1, DWORD dw2);
254 static HRESULT DSOUND_CreateDirectSoundCapture( LPVOID* ppobj );
255 static HRESULT DSOUND_CreateDirectSoundCaptureBuffer( LPCDSCBUFFERDESC lpcDSCBufferDesc, LPVOID* ppobj );
257 static ICOM_VTABLE(IDirectSoundCapture) dscvt;
258 static ICOM_VTABLE(IDirectSoundCaptureBuffer) dscbvt;
260 static HRESULT mmErr(UINT err)
263 case MMSYSERR_NOERROR:
265 case MMSYSERR_ALLOCATED:
266 return DSERR_ALLOCATED;
267 case MMSYSERR_INVALHANDLE:
268 return DSERR_GENERIC; /* FIXME */
269 case MMSYSERR_NODRIVER:
270 return DSERR_NODRIVER;
272 return DSERR_OUTOFMEMORY;
273 case MMSYSERR_INVALPARAM:
274 return DSERR_INVALIDPARAM;
276 FIXME("Unknown MMSYS error %d\n",err);
277 return DSERR_GENERIC;
281 /***************************************************************************
282 * DirectSoundEnumerateA [DSOUND.2]
284 * Enumerate all DirectSound drivers installed in the system
288 * Failure: DSERR_INVALIDPARAM
290 HRESULT WINAPI DirectSoundEnumerateA(
291 LPDSENUMCALLBACKA lpDSEnumCallback,
294 TRACE("lpDSEnumCallback = %p, lpContext = %p\n",
295 lpDSEnumCallback, lpContext);
298 if (lpDSEnumCallback != NULL)
299 lpDSEnumCallback(NULL,"WINE DirectSound",
306 /***************************************************************************
307 * DirectSoundEnumerateW [DSOUND.3]
309 * Enumerate all DirectSound drivers installed in the system
313 * Failure: DSERR_INVALIDPARAM
315 HRESULT WINAPI DirectSoundEnumerateW(
316 LPDSENUMCALLBACKW lpDSEnumCallback,
319 FIXME("lpDSEnumCallback = %p, lpContext = %p: stub\n",
320 lpDSEnumCallback, lpContext);
326 static void _dump_DSBCAPS(DWORD xmask) {
331 #define FE(x) { x, #x },
332 FE(DSBCAPS_PRIMARYBUFFER)
334 FE(DSBCAPS_LOCHARDWARE)
335 FE(DSBCAPS_LOCSOFTWARE)
337 FE(DSBCAPS_CTRLFREQUENCY)
339 FE(DSBCAPS_CTRLVOLUME)
340 FE(DSBCAPS_CTRLPOSITIONNOTIFY)
341 FE(DSBCAPS_CTRLDEFAULT)
343 FE(DSBCAPS_STICKYFOCUS)
344 FE(DSBCAPS_GLOBALFOCUS)
345 FE(DSBCAPS_GETCURRENTPOSITION2)
346 FE(DSBCAPS_MUTE3DATMAXDISTANCE)
351 for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++)
352 if ((flags[i].mask & xmask) == flags[i].mask)
353 DPRINTF("%s ",flags[i].name);
356 /*******************************************************************************
360 /* IUnknown methods */
362 static HRESULT WINAPI IKsPropertySetImpl_QueryInterface(
363 LPKSPROPERTYSET iface, REFIID riid, LPVOID *ppobj
365 ICOM_THIS(IKsPropertySetImpl,iface);
367 FIXME("(%p,%s,%p), stub!\n",This,debugstr_guid(riid),ppobj);
373 static ULONG WINAPI IKsPropertySetImpl_AddRef(LPKSPROPERTYSET iface) {
374 ICOM_THIS(IKsPropertySetImpl,iface);
382 static ULONG WINAPI IKsPropertySetImpl_Release(LPKSPROPERTYSET iface) {
383 ICOM_THIS(IKsPropertySetImpl,iface);
391 static HRESULT WINAPI IKsPropertySetImpl_Get(LPKSPROPERTYSET iface,
392 REFGUID guidPropSet, ULONG dwPropID,
393 LPVOID pInstanceData, ULONG cbInstanceData,
394 LPVOID pPropData, ULONG cbPropData,
397 ICOM_THIS(IKsPropertySetImpl,iface);
399 FIXME("(%p,%s,%ld,%p,%ld,%p,%ld,%p), stub!\n",This,debugstr_guid(guidPropSet),dwPropID,pInstanceData,cbInstanceData,pPropData,cbPropData,pcbReturned);
400 return E_PROP_ID_UNSUPPORTED;
405 static HRESULT WINAPI IKsPropertySetImpl_Set(LPKSPROPERTYSET iface,
406 REFGUID guidPropSet, ULONG dwPropID,
407 LPVOID pInstanceData, ULONG cbInstanceData,
408 LPVOID pPropData, ULONG cbPropData
410 ICOM_THIS(IKsPropertySetImpl,iface);
412 FIXME("(%p,%s,%ld,%p,%ld,%p,%ld), stub!\n",This,debugstr_guid(guidPropSet),dwPropID,pInstanceData,cbInstanceData,pPropData,cbPropData);
413 return E_PROP_ID_UNSUPPORTED;
418 static HRESULT WINAPI IKsPropertySetImpl_QuerySupport(LPKSPROPERTYSET iface,
419 REFGUID guidPropSet, ULONG dwPropID, PULONG pTypeSupport
421 ICOM_THIS(IKsPropertySetImpl,iface);
423 FIXME("(%p,%s,%ld,%p), stub!\n",This,debugstr_guid(guidPropSet),dwPropID,pTypeSupport);
424 return E_PROP_ID_UNSUPPORTED;
429 static ICOM_VTABLE(IKsPropertySet) iksvt = {
430 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
431 IKsPropertySetImpl_QueryInterface,
432 IKsPropertySetImpl_AddRef,
433 IKsPropertySetImpl_Release,
434 IKsPropertySetImpl_Get,
435 IKsPropertySetImpl_Set,
436 IKsPropertySetImpl_QuerySupport
440 /*******************************************************************************
441 * IDirectSound3DBuffer
444 /* IUnknown methods */
446 static HRESULT WINAPI IDirectSound3DBufferImpl_QueryInterface(
447 LPDIRECTSOUND3DBUFFER iface, REFIID riid, LPVOID *ppobj)
449 ICOM_THIS(IDirectSound3DBufferImpl,iface);
451 if ( IsEqualGUID( &IID_IKsPropertySet, riid ) ) {
452 IDirectSound3DBuffer_AddRef(iface);
457 FIXME("(%p,%s,%p), no such interface.\n",This,debugstr_guid(riid),ppobj);
463 static ULONG WINAPI IDirectSound3DBufferImpl_AddRef(LPDIRECTSOUND3DBUFFER iface)
465 ICOM_THIS(IDirectSound3DBufferImpl,iface);
472 static ULONG WINAPI IDirectSound3DBufferImpl_Release(LPDIRECTSOUND3DBUFFER iface)
474 ICOM_THIS(IDirectSound3DBufferImpl,iface);
476 TRACE("(%p) ref was %ld\n", This, This->ref);
482 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)This->dsb);
484 DeleteCriticalSection(&This->lock);
486 HeapFree(GetProcessHeap(),0,This->buffer);
487 HeapFree(GetProcessHeap(),0,This);
493 /* IDirectSound3DBuffer methods */
495 static HRESULT WINAPI IDirectSound3DBufferImpl_GetAllParameters(
496 LPDIRECTSOUND3DBUFFER iface,
497 LPDS3DBUFFER lpDs3dBuffer)
505 static HRESULT WINAPI IDirectSound3DBufferImpl_GetConeAngles(
506 LPDIRECTSOUND3DBUFFER iface,
507 LPDWORD lpdwInsideConeAngle,
508 LPDWORD lpdwOutsideConeAngle)
516 static HRESULT WINAPI IDirectSound3DBufferImpl_GetConeOrientation(
517 LPDIRECTSOUND3DBUFFER iface,
518 LPD3DVECTOR lpvConeOrientation)
526 static HRESULT WINAPI IDirectSound3DBufferImpl_GetConeOutsideVolume(
527 LPDIRECTSOUND3DBUFFER iface,
528 LPLONG lplConeOutsideVolume)
536 static HRESULT WINAPI IDirectSound3DBufferImpl_GetMaxDistance(
537 LPDIRECTSOUND3DBUFFER iface,
538 LPD3DVALUE lpfMaxDistance)
546 static HRESULT WINAPI IDirectSound3DBufferImpl_GetMinDistance(
547 LPDIRECTSOUND3DBUFFER iface,
548 LPD3DVALUE lpfMinDistance)
556 static HRESULT WINAPI IDirectSound3DBufferImpl_GetMode(
557 LPDIRECTSOUND3DBUFFER iface,
566 static HRESULT WINAPI IDirectSound3DBufferImpl_GetPosition(
567 LPDIRECTSOUND3DBUFFER iface,
568 LPD3DVECTOR lpvPosition)
576 static HRESULT WINAPI IDirectSound3DBufferImpl_GetVelocity(
577 LPDIRECTSOUND3DBUFFER iface,
578 LPD3DVECTOR lpvVelocity)
586 static HRESULT WINAPI IDirectSound3DBufferImpl_SetAllParameters(
587 LPDIRECTSOUND3DBUFFER iface,
588 LPCDS3DBUFFER lpcDs3dBuffer,
597 static HRESULT WINAPI IDirectSound3DBufferImpl_SetConeAngles(
598 LPDIRECTSOUND3DBUFFER iface,
599 DWORD dwInsideConeAngle,
600 DWORD dwOutsideConeAngle,
609 static HRESULT WINAPI IDirectSound3DBufferImpl_SetConeOrientation(
610 LPDIRECTSOUND3DBUFFER iface,
611 D3DVALUE x, D3DVALUE y, D3DVALUE z,
620 static HRESULT WINAPI IDirectSound3DBufferImpl_SetConeOutsideVolume(
621 LPDIRECTSOUND3DBUFFER iface,
622 LONG lConeOutsideVolume,
631 static HRESULT WINAPI IDirectSound3DBufferImpl_SetMaxDistance(
632 LPDIRECTSOUND3DBUFFER iface,
633 D3DVALUE fMaxDistance,
642 static HRESULT WINAPI IDirectSound3DBufferImpl_SetMinDistance(
643 LPDIRECTSOUND3DBUFFER iface,
644 D3DVALUE fMinDistance,
653 static HRESULT WINAPI IDirectSound3DBufferImpl_SetMode(
654 LPDIRECTSOUND3DBUFFER iface,
658 ICOM_THIS(IDirectSound3DBufferImpl,iface);
659 TRACE("mode = %lx\n", dwMode);
660 This->ds3db.dwMode = dwMode;
666 static HRESULT WINAPI IDirectSound3DBufferImpl_SetPosition(
667 LPDIRECTSOUND3DBUFFER iface,
668 D3DVALUE x, D3DVALUE y, D3DVALUE z,
677 static HRESULT WINAPI IDirectSound3DBufferImpl_SetVelocity(
678 LPDIRECTSOUND3DBUFFER iface,
679 D3DVALUE x, D3DVALUE y, D3DVALUE z,
688 static ICOM_VTABLE(IDirectSound3DBuffer) ds3dbvt =
690 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
691 /* IUnknown methods */
692 IDirectSound3DBufferImpl_QueryInterface,
693 IDirectSound3DBufferImpl_AddRef,
694 IDirectSound3DBufferImpl_Release,
695 /* IDirectSound3DBuffer methods */
696 IDirectSound3DBufferImpl_GetAllParameters,
697 IDirectSound3DBufferImpl_GetConeAngles,
698 IDirectSound3DBufferImpl_GetConeOrientation,
699 IDirectSound3DBufferImpl_GetConeOutsideVolume,
700 IDirectSound3DBufferImpl_GetMaxDistance,
701 IDirectSound3DBufferImpl_GetMinDistance,
702 IDirectSound3DBufferImpl_GetMode,
703 IDirectSound3DBufferImpl_GetPosition,
704 IDirectSound3DBufferImpl_GetVelocity,
705 IDirectSound3DBufferImpl_SetAllParameters,
706 IDirectSound3DBufferImpl_SetConeAngles,
707 IDirectSound3DBufferImpl_SetConeOrientation,
708 IDirectSound3DBufferImpl_SetConeOutsideVolume,
709 IDirectSound3DBufferImpl_SetMaxDistance,
710 IDirectSound3DBufferImpl_SetMinDistance,
711 IDirectSound3DBufferImpl_SetMode,
712 IDirectSound3DBufferImpl_SetPosition,
713 IDirectSound3DBufferImpl_SetVelocity,
718 static int DSOUND_Create3DBuffer(IDirectSoundBufferImpl* dsb)
720 DWORD i, temp, iSize, oSize, offset;
721 LPBYTE bIbuf, bObuf, bTbuf = NULL;
722 LPWORD wIbuf, wObuf, wTbuf = NULL;
724 /* Inside DirectX says it's stupid but allowed */
725 if (dsb->wfx.nChannels == 2) {
726 /* Convert to mono */
727 if (dsb->wfx.wBitsPerSample == 16) {
728 iSize = dsb->buflen / 4;
729 wTbuf = malloc(dsb->buflen / 2);
731 return DSERR_OUTOFMEMORY;
732 for (i = 0; i < iSize; i++)
733 wTbuf[i] = (dsb->buffer[i * 2] + dsb->buffer[(i * 2) + 1]) / 2;
736 iSize = dsb->buflen / 2;
737 bTbuf = malloc(dsb->buflen / 2);
739 return DSERR_OUTOFMEMORY;
740 for (i = 0; i < iSize; i++)
741 bTbuf[i] = (dsb->buffer[i * 2] + dsb->buffer[(i * 2) + 1]) / 2;
745 if (dsb->wfx.wBitsPerSample == 16) {
746 iSize = dsb->buflen / 2;
747 wIbuf = (LPWORD) dsb->buffer;
749 bIbuf = (LPBYTE) dsb->buffer;
754 if (primarybuf->wfx.wBitsPerSample == 16) {
755 wObuf = (LPWORD) dsb->ds3db->buffer;
756 oSize = dsb->ds3db->buflen / 2;
758 bObuf = (LPBYTE) dsb->ds3db->buffer;
759 oSize = dsb->ds3db->buflen;
762 offset = primarybuf->wfx.nSamplesPerSec / 100; /* 10ms */
763 if (primarybuf->wfx.wBitsPerSample == 16 && dsb->wfx.wBitsPerSample == 16)
764 for (i = 0; i < iSize; i++) {
767 temp += wIbuf[i - offset] >> 9;
769 temp += wIbuf[i + iSize - offset] >> 9;
771 wObuf[(i * 2) + 1] = temp;
773 else if (primarybuf->wfx.wBitsPerSample == 8 && dsb->wfx.wBitsPerSample == 8)
774 for (i = 0; i < iSize; i++) {
777 temp += bIbuf[i - offset] >> 5;
779 temp += bIbuf[i + iSize - offset] >> 5;
781 bObuf[(i * 2) + 1] = temp;
792 /*******************************************************************************
793 * IDirectSound3DListener
796 /* IUnknown methods */
797 static HRESULT WINAPI IDirectSound3DListenerImpl_QueryInterface(
798 LPDIRECTSOUND3DLISTENER iface, REFIID riid, LPVOID *ppobj)
800 ICOM_THIS(IDirectSound3DListenerImpl,iface);
802 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
806 static ULONG WINAPI IDirectSound3DListenerImpl_AddRef(LPDIRECTSOUND3DLISTENER iface)
808 ICOM_THIS(IDirectSound3DListenerImpl,iface);
813 static ULONG WINAPI IDirectSound3DListenerImpl_Release(LPDIRECTSOUND3DLISTENER iface)
816 ICOM_THIS(IDirectSound3DListenerImpl,iface);
818 TRACE("(%p) ref was %ld\n", This, This->ref);
820 ulReturn = --This->ref;
822 /* Free all resources */
823 if( ulReturn == 0 ) {
825 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)This->dsb);
826 DeleteCriticalSection(&This->lock);
827 HeapFree(GetProcessHeap(),0,This);
833 /* IDirectSound3DListener methods */
834 static HRESULT WINAPI IDirectSound3DListenerImpl_GetAllParameter(
835 LPDIRECTSOUND3DLISTENER iface,
836 LPDS3DLISTENER lpDS3DL)
842 static HRESULT WINAPI IDirectSound3DListenerImpl_GetDistanceFactor(
843 LPDIRECTSOUND3DLISTENER iface,
844 LPD3DVALUE lpfDistanceFactor)
850 static HRESULT WINAPI IDirectSound3DListenerImpl_GetDopplerFactor(
851 LPDIRECTSOUND3DLISTENER iface,
852 LPD3DVALUE lpfDopplerFactor)
858 static HRESULT WINAPI IDirectSound3DListenerImpl_GetOrientation(
859 LPDIRECTSOUND3DLISTENER iface,
860 LPD3DVECTOR lpvOrientFront,
861 LPD3DVECTOR lpvOrientTop)
867 static HRESULT WINAPI IDirectSound3DListenerImpl_GetPosition(
868 LPDIRECTSOUND3DLISTENER iface,
869 LPD3DVECTOR lpvPosition)
875 static HRESULT WINAPI IDirectSound3DListenerImpl_GetRolloffFactor(
876 LPDIRECTSOUND3DLISTENER iface,
877 LPD3DVALUE lpfRolloffFactor)
883 static HRESULT WINAPI IDirectSound3DListenerImpl_GetVelocity(
884 LPDIRECTSOUND3DLISTENER iface,
885 LPD3DVECTOR lpvVelocity)
891 static HRESULT WINAPI IDirectSound3DListenerImpl_SetAllParameters(
892 LPDIRECTSOUND3DLISTENER iface,
893 LPCDS3DLISTENER lpcDS3DL,
900 static HRESULT WINAPI IDirectSound3DListenerImpl_SetDistanceFactor(
901 LPDIRECTSOUND3DLISTENER iface,
902 D3DVALUE fDistanceFactor,
909 static HRESULT WINAPI IDirectSound3DListenerImpl_SetDopplerFactor(
910 LPDIRECTSOUND3DLISTENER iface,
911 D3DVALUE fDopplerFactor,
918 static HRESULT WINAPI IDirectSound3DListenerImpl_SetOrientation(
919 LPDIRECTSOUND3DLISTENER iface,
920 D3DVALUE xFront, D3DVALUE yFront, D3DVALUE zFront,
921 D3DVALUE xTop, D3DVALUE yTop, D3DVALUE zTop,
928 static HRESULT WINAPI IDirectSound3DListenerImpl_SetPosition(
929 LPDIRECTSOUND3DLISTENER iface,
930 D3DVALUE x, D3DVALUE y, D3DVALUE z,
937 static HRESULT WINAPI IDirectSound3DListenerImpl_SetRolloffFactor(
938 LPDIRECTSOUND3DLISTENER iface,
939 D3DVALUE fRolloffFactor,
946 static HRESULT WINAPI IDirectSound3DListenerImpl_SetVelocity(
947 LPDIRECTSOUND3DLISTENER iface,
948 D3DVALUE x, D3DVALUE y, D3DVALUE z,
955 static HRESULT WINAPI IDirectSound3DListenerImpl_CommitDeferredSettings(
956 LPDIRECTSOUND3DLISTENER iface)
963 static ICOM_VTABLE(IDirectSound3DListener) ds3dlvt =
965 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
966 /* IUnknown methods */
967 IDirectSound3DListenerImpl_QueryInterface,
968 IDirectSound3DListenerImpl_AddRef,
969 IDirectSound3DListenerImpl_Release,
970 /* IDirectSound3DListener methods */
971 IDirectSound3DListenerImpl_GetAllParameter,
972 IDirectSound3DListenerImpl_GetDistanceFactor,
973 IDirectSound3DListenerImpl_GetDopplerFactor,
974 IDirectSound3DListenerImpl_GetOrientation,
975 IDirectSound3DListenerImpl_GetPosition,
976 IDirectSound3DListenerImpl_GetRolloffFactor,
977 IDirectSound3DListenerImpl_GetVelocity,
978 IDirectSound3DListenerImpl_SetAllParameters,
979 IDirectSound3DListenerImpl_SetDistanceFactor,
980 IDirectSound3DListenerImpl_SetDopplerFactor,
981 IDirectSound3DListenerImpl_SetOrientation,
982 IDirectSound3DListenerImpl_SetPosition,
983 IDirectSound3DListenerImpl_SetRolloffFactor,
984 IDirectSound3DListenerImpl_SetVelocity,
985 IDirectSound3DListenerImpl_CommitDeferredSettings,
988 /*******************************************************************************
991 static HRESULT WINAPI IDirectSoundNotifyImpl_QueryInterface(
992 LPDIRECTSOUNDNOTIFY iface,REFIID riid,LPVOID *ppobj
994 ICOM_THIS(IDirectSoundNotifyImpl,iface);
996 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
1000 static ULONG WINAPI IDirectSoundNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface) {
1001 ICOM_THIS(IDirectSoundNotifyImpl,iface);
1002 return ++(This->ref);
1005 static ULONG WINAPI IDirectSoundNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface) {
1006 ICOM_THIS(IDirectSoundNotifyImpl,iface);
1008 TRACE("(%p) ref was %ld\n", This, This->ref);
1012 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)This->dsb);
1013 HeapFree(GetProcessHeap(),0,This);
1019 static HRESULT WINAPI IDirectSoundNotifyImpl_SetNotificationPositions(
1020 LPDIRECTSOUNDNOTIFY iface,DWORD howmuch,LPCDSBPOSITIONNOTIFY notify
1022 ICOM_THIS(IDirectSoundNotifyImpl,iface);
1025 if (TRACE_ON(dsound)) {
1026 TRACE("(%p,0x%08lx,%p)\n",This,howmuch,notify);
1027 for (i=0;i<howmuch;i++)
1028 TRACE("notify at %ld to 0x%08lx\n",
1029 notify[i].dwOffset,(DWORD)notify[i].hEventNotify);
1031 This->dsb->notifies = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,This->dsb->notifies,(This->dsb->nrofnotifies+howmuch)*sizeof(DSBPOSITIONNOTIFY));
1032 memcpy( This->dsb->notifies+This->dsb->nrofnotifies,
1034 howmuch*sizeof(DSBPOSITIONNOTIFY)
1036 This->dsb->nrofnotifies+=howmuch;
1041 static ICOM_VTABLE(IDirectSoundNotify) dsnvt =
1043 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1044 IDirectSoundNotifyImpl_QueryInterface,
1045 IDirectSoundNotifyImpl_AddRef,
1046 IDirectSoundNotifyImpl_Release,
1047 IDirectSoundNotifyImpl_SetNotificationPositions,
1050 /*******************************************************************************
1051 * IDirectSoundBuffer
1054 static void DSOUND_RecalcVolPan(PDSVOLUMEPAN volpan)
1058 /* the AmpFactors are expressed in 16.16 fixed point */
1059 volpan->dwVolAmpFactor = (ULONG) (pow(2.0, volpan->lVolume / 600.0) * 65536);
1060 /* FIXME: dwPan{Left|Right}AmpFactor */
1062 /* FIXME: use calculated vol and pan ampfactors */
1063 temp = (double) (volpan->lVolume - (volpan->lPan > 0 ? volpan->lPan : 0));
1064 volpan->dwTotalLeftAmpFactor = (ULONG) (pow(2.0, temp / 600.0) * 65536);
1065 temp = (double) (volpan->lVolume + (volpan->lPan < 0 ? volpan->lPan : 0));
1066 volpan->dwTotalRightAmpFactor = (ULONG) (pow(2.0, temp / 600.0) * 65536);
1068 TRACE("left = %lx, right = %lx\n", volpan->dwTotalLeftAmpFactor, volpan->dwTotalRightAmpFactor);
1071 static void DSOUND_RecalcFormat(IDirectSoundBufferImpl *dsb)
1075 sw = dsb->wfx.nChannels * (dsb->wfx.wBitsPerSample / 8);
1076 if ((dsb->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER) && dsb->hwbuf) {
1078 /* let fragment size approximate the timer delay */
1079 fraglen = (dsb->freq * DS_TIME_DEL / 1000) * sw;
1080 /* reduce fragment size until an integer number of them fits in the buffer */
1081 /* (FIXME: this may or may not be a good idea) */
1082 while (dsb->buflen % fraglen) fraglen -= sw;
1083 dsb->dsound->fraglen = fraglen;
1084 TRACE("fraglen=%ld\n", dsb->dsound->fraglen);
1086 /* calculate the 10ms write lead */
1087 dsb->writelead = (dsb->freq / 100) * sw;
1090 static HRESULT DSOUND_PrimaryOpen(IDirectSoundBufferImpl *dsb)
1092 HRESULT err = DS_OK;
1094 /* are we using waveOut stuff? */
1098 HRESULT merr = DS_OK;
1099 /* Start in pause mode, to allow buffers to get filled */
1100 waveOutPause(dsb->dsound->hwo);
1101 if (dsb->state == STATE_PLAYING) dsb->state = STATE_STARTING;
1102 else if (dsb->state == STATE_STOPPING) dsb->state = STATE_STOPPED;
1103 /* use fragments of 10ms (1/100s) each (which should get us within
1104 * the documented write cursor lead of 10-15ms) */
1105 buflen = ((dsb->wfx.nAvgBytesPerSec / 100) & ~3) * DS_HEL_FRAGS;
1106 TRACE("desired buflen=%ld, old buffer=%p\n", buflen, dsb->buffer);
1107 /* reallocate emulated primary buffer */
1108 newbuf = (LPBYTE)HeapReAlloc(GetProcessHeap(),0,dsb->buffer,buflen);
1109 if (newbuf == NULL) {
1110 ERR("failed to allocate primary buffer\n");
1111 merr = DSERR_OUTOFMEMORY;
1112 /* but the old buffer might still exists and must be re-prepared */
1114 dsb->buffer = newbuf;
1115 dsb->buflen = buflen;
1119 IDirectSoundImpl *ds = dsb->dsound;
1121 ds->fraglen = dsb->buflen / DS_HEL_FRAGS;
1123 /* prepare fragment headers */
1124 for (c=0; c<DS_HEL_FRAGS; c++) {
1125 ds->pwave[c]->lpData = dsb->buffer + c*ds->fraglen;
1126 ds->pwave[c]->dwBufferLength = ds->fraglen;
1127 ds->pwave[c]->dwUser = (DWORD)dsb;
1128 ds->pwave[c]->dwFlags = 0;
1129 ds->pwave[c]->dwLoops = 0;
1130 err = mmErr(waveOutPrepareHeader(ds->hwo,ds->pwave[c],sizeof(WAVEHDR)));
1133 waveOutUnprepareHeader(ds->hwo,ds->pwave[c],sizeof(WAVEHDR));
1141 memset(dsb->buffer, (dsb->wfx.wBitsPerSample == 16) ? 0 : 128, dsb->buflen);
1142 TRACE("fraglen=%ld\n", ds->fraglen);
1143 DSOUND_WaveQueue(dsb->dsound, (DWORD)-1);
1145 if ((err == DS_OK) && (merr != DS_OK))
1152 static void DSOUND_PrimaryClose(IDirectSoundBufferImpl *dsb)
1154 /* are we using waveOut stuff? */
1157 IDirectSoundImpl *ds = dsb->dsound;
1159 ds->pwqueue = (DWORD)-1; /* resetting queues */
1160 waveOutReset(ds->hwo);
1161 for (c=0; c<DS_HEL_FRAGS; c++)
1162 waveOutUnprepareHeader(ds->hwo, ds->pwave[c], sizeof(WAVEHDR));
1167 static HRESULT DSOUND_PrimaryPlay(IDirectSoundBufferImpl *dsb)
1169 HRESULT err = DS_OK;
1171 err = IDsDriverBuffer_Play(dsb->hwbuf, 0, 0, DSBPLAY_LOOPING);
1173 err = mmErr(waveOutRestart(dsb->dsound->hwo));
1177 static HRESULT DSOUND_PrimaryStop(IDirectSoundBufferImpl *dsb)
1179 HRESULT err = DS_OK;
1184 err = IDsDriverBuffer_Stop(dsb->hwbuf);
1185 if (err == DSERR_BUFFERLOST) {
1186 /* Wine-only: the driver wants us to reopen the device */
1187 /* FIXME: check for errors */
1188 IDsDriverBuffer_Release(primarybuf->hwbuf);
1189 waveOutClose(dsb->dsound->hwo);
1190 dsb->dsound->hwo = 0;
1191 err = mmErr(waveOutOpen(&(dsb->dsound->hwo), dsb->dsound->drvdesc.dnDevNode,
1192 &(primarybuf->wfx), (DWORD)DSOUND_callback, (DWORD)dsb->dsound,
1193 CALLBACK_FUNCTION | WAVE_DIRECTSOUND));
1195 err = IDsDriver_CreateSoundBuffer(dsb->dsound->driver,&(dsb->wfx),dsb->dsbd.dwFlags,0,
1196 &(dsb->buflen),&(dsb->buffer),
1197 (LPVOID)&(dsb->hwbuf));
1201 err = mmErr(waveOutPause(dsb->dsound->hwo));
1205 /* This sets this format for the <em>Primary Buffer Only</em> */
1206 /* See file:///cdrom/sdk52/docs/worddoc/dsound.doc page 120 */
1207 static HRESULT WINAPI IDirectSoundBufferImpl_SetFormat(
1208 LPDIRECTSOUNDBUFFER iface,LPWAVEFORMATEX wfex
1210 ICOM_THIS(IDirectSoundBufferImpl,iface);
1211 IDirectSoundBufferImpl** dsb;
1212 HRESULT err = DS_OK;
1215 /* Let's be pedantic! */
1216 if ((wfex == NULL) ||
1217 (wfex->wFormatTag != WAVE_FORMAT_PCM) ||
1218 (wfex->nChannels < 1) || (wfex->nChannels > 2) ||
1219 (wfex->nSamplesPerSec < 1) ||
1220 (wfex->nBlockAlign < 1) || (wfex->nChannels > 4) ||
1221 ((wfex->wBitsPerSample != 8) && (wfex->wBitsPerSample != 16))) {
1222 TRACE("failed pedantic check!\n");
1223 return DSERR_INVALIDPARAM;
1227 EnterCriticalSection(&(This->dsound->lock));
1229 if (primarybuf->wfx.nSamplesPerSec != wfex->nSamplesPerSec) {
1230 dsb = dsound->buffers;
1231 for (i = 0; i < dsound->nrofbuffers; i++, dsb++) {
1233 EnterCriticalSection(&((*dsb)->lock));
1235 (*dsb)->freqAdjust = ((*dsb)->freq << DSOUND_FREQSHIFT) /
1236 wfex->nSamplesPerSec;
1238 LeaveCriticalSection(&((*dsb)->lock));
1243 memcpy(&(primarybuf->wfx), wfex, sizeof(primarybuf->wfx));
1245 TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld,"
1246 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
1247 wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec,
1248 wfex->nAvgBytesPerSec, wfex->nBlockAlign,
1249 wfex->wBitsPerSample, wfex->cbSize);
1251 primarybuf->wfx.nAvgBytesPerSec =
1252 This->wfx.nSamplesPerSec * This->wfx.nBlockAlign;
1254 if (primarybuf->dsound->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMSETFORMAT) {
1255 /* FIXME: check for errors */
1256 DSOUND_PrimaryClose(primarybuf);
1257 waveOutClose(This->dsound->hwo);
1258 This->dsound->hwo = 0;
1259 err = mmErr(waveOutOpen(&(This->dsound->hwo), This->dsound->drvdesc.dnDevNode,
1260 &(primarybuf->wfx), (DWORD)DSOUND_callback, (DWORD)This->dsound,
1261 CALLBACK_FUNCTION | WAVE_DIRECTSOUND));
1263 DSOUND_PrimaryOpen(primarybuf);
1265 if (primarybuf->hwbuf) {
1266 err = IDsDriverBuffer_SetFormat(primarybuf->hwbuf, &(primarybuf->wfx));
1267 if (err == DSERR_BUFFERLOST) {
1268 /* Wine-only: the driver wants us to recreate the HW buffer */
1269 IDsDriverBuffer_Release(primarybuf->hwbuf);
1270 err = IDsDriver_CreateSoundBuffer(primarybuf->dsound->driver,&(primarybuf->wfx),primarybuf->dsbd.dwFlags,0,
1271 &(primarybuf->buflen),&(primarybuf->buffer),
1272 (LPVOID)&(primarybuf->hwbuf));
1273 if (primarybuf->state == STATE_PLAYING) primarybuf->state = STATE_STARTING;
1274 else if (primarybuf->state == STATE_STOPPING) primarybuf->state = STATE_STOPPED;
1276 /* FIXME: should we set err back to DS_OK in all cases ? */
1278 DSOUND_RecalcFormat(primarybuf);
1280 LeaveCriticalSection(&(This->dsound->lock));
1286 static HRESULT WINAPI IDirectSoundBufferImpl_SetVolume(
1287 LPDIRECTSOUNDBUFFER iface,LONG vol
1289 ICOM_THIS(IDirectSoundBufferImpl,iface);
1291 TRACE("(%p,%ld)\n",This,vol);
1293 /* I'm not sure if we need this for primary buffer */
1294 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME))
1295 return DSERR_CONTROLUNAVAIL;
1297 if ((vol > DSBVOLUME_MAX) || (vol < DSBVOLUME_MIN))
1298 return DSERR_INVALIDPARAM;
1301 EnterCriticalSection(&(This->lock));
1303 This->volpan.lVolume = vol;
1305 DSOUND_RecalcVolPan(&(This->volpan));
1308 IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan));
1310 else if (This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER) {
1311 #if 0 /* should we really do this? */
1312 /* the DS volume ranges from 0 (max, 0dB attenuation) to -10000 (min, 100dB attenuation) */
1313 /* the MM volume ranges from 0 to 0xffff in an unspecified logarithmic scale */
1314 WORD cvol = 0xffff + vol*6 + vol/2;
1315 DWORD vol = cvol | ((DWORD)cvol << 16)
1316 waveOutSetVolume(This->dsound->hwo, vol);
1320 LeaveCriticalSection(&(This->lock));
1326 static HRESULT WINAPI IDirectSoundBufferImpl_GetVolume(
1327 LPDIRECTSOUNDBUFFER iface,LPLONG vol
1329 ICOM_THIS(IDirectSoundBufferImpl,iface);
1330 TRACE("(%p,%p)\n",This,vol);
1333 return DSERR_INVALIDPARAM;
1335 *vol = This->volpan.lVolume;
1339 static HRESULT WINAPI IDirectSoundBufferImpl_SetFrequency(
1340 LPDIRECTSOUNDBUFFER iface,DWORD freq
1342 ICOM_THIS(IDirectSoundBufferImpl,iface);
1343 TRACE("(%p,%ld)\n",This,freq);
1345 /* You cannot set the frequency of the primary buffer */
1346 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLFREQUENCY) ||
1347 (This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER))
1348 return DSERR_CONTROLUNAVAIL;
1350 if (!freq) freq = This->wfx.nSamplesPerSec;
1352 if ((freq < DSBFREQUENCY_MIN) || (freq > DSBFREQUENCY_MAX))
1353 return DSERR_INVALIDPARAM;
1356 EnterCriticalSection(&(This->lock));
1359 This->freqAdjust = (freq << DSOUND_FREQSHIFT) / primarybuf->wfx.nSamplesPerSec;
1360 This->nAvgBytesPerSec = freq * This->wfx.nBlockAlign;
1361 DSOUND_RecalcFormat(This);
1363 LeaveCriticalSection(&(This->lock));
1369 static HRESULT WINAPI IDirectSoundBufferImpl_Play(
1370 LPDIRECTSOUNDBUFFER iface,DWORD reserved1,DWORD reserved2,DWORD flags
1372 ICOM_THIS(IDirectSoundBufferImpl,iface);
1373 TRACE("(%p,%08lx,%08lx,%08lx)\n",
1374 This,reserved1,reserved2,flags
1378 EnterCriticalSection(&(This->lock));
1380 This->playflags = flags;
1381 if (This->state == STATE_STOPPED) {
1382 This->leadin = TRUE;
1383 This->startpos = This->buf_mixpos;
1384 This->state = STATE_STARTING;
1385 } else if (This->state == STATE_STOPPING)
1386 This->state = STATE_PLAYING;
1387 if (!(This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER) && This->hwbuf) {
1388 IDsDriverBuffer_Play(This->hwbuf, 0, 0, This->playflags);
1389 This->state = STATE_PLAYING;
1392 LeaveCriticalSection(&(This->lock));
1398 static HRESULT WINAPI IDirectSoundBufferImpl_Stop(LPDIRECTSOUNDBUFFER iface)
1400 ICOM_THIS(IDirectSoundBufferImpl,iface);
1401 TRACE("(%p)\n",This);
1404 EnterCriticalSection(&(This->lock));
1406 if (This->state == STATE_PLAYING)
1407 This->state = STATE_STOPPING;
1408 else if (This->state == STATE_STARTING)
1409 This->state = STATE_STOPPED;
1410 if (!(This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER) && This->hwbuf) {
1411 IDsDriverBuffer_Stop(This->hwbuf);
1412 This->state = STATE_STOPPED;
1414 DSOUND_CheckEvent(This, 0);
1416 LeaveCriticalSection(&(This->lock));
1422 static DWORD WINAPI IDirectSoundBufferImpl_AddRef(LPDIRECTSOUNDBUFFER iface) {
1423 ICOM_THIS(IDirectSoundBufferImpl,iface);
1426 TRACE("(%p) ref was %ld, thread is %lx\n",This, This->ref, GetCurrentThreadId());
1428 ref = InterlockedIncrement(&(This->ref));
1430 FIXME("thread-safety alert! AddRef-ing with a zero refcount!\n");
1434 static DWORD WINAPI IDirectSoundBufferImpl_Release(LPDIRECTSOUNDBUFFER iface) {
1435 ICOM_THIS(IDirectSoundBufferImpl,iface);
1439 TRACE("(%p) ref was %ld, thread is %lx\n",This, This->ref, GetCurrentThreadId());
1441 ref = InterlockedDecrement(&(This->ref));
1442 if (ref) return ref;
1444 EnterCriticalSection(&(This->dsound->lock));
1445 for (i=0;i<This->dsound->nrofbuffers;i++)
1446 if (This->dsound->buffers[i] == This)
1449 if (i < This->dsound->nrofbuffers) {
1450 /* Put the last buffer of the list in the (now empty) position */
1451 This->dsound->buffers[i] = This->dsound->buffers[This->dsound->nrofbuffers - 1];
1452 This->dsound->nrofbuffers--;
1453 This->dsound->buffers = HeapReAlloc(GetProcessHeap(),0,This->dsound->buffers,sizeof(LPDIRECTSOUNDBUFFER)*This->dsound->nrofbuffers);
1454 TRACE("buffer count is now %d\n", This->dsound->nrofbuffers);
1455 IDirectSound_Release((LPDIRECTSOUND)This->dsound);
1457 LeaveCriticalSection(&(This->dsound->lock));
1459 DeleteCriticalSection(&(This->lock));
1460 if (This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER)
1461 DSOUND_PrimaryClose(This);
1463 IDsDriverBuffer_Release(This->hwbuf);
1466 IDirectSound3DBuffer_Release((LPDIRECTSOUND3DBUFFER)This->ds3db);
1468 /* this is a duplicate buffer */
1469 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)This->parent);
1471 /* this is a toplevel buffer */
1472 HeapFree(GetProcessHeap(),0,This->buffer);
1474 HeapFree(GetProcessHeap(),0,This);
1476 if (This == primarybuf)
1482 static DWORD DSOUND_CalcPlayPosition(IDirectSoundBufferImpl *This,
1483 DWORD state, DWORD pplay, DWORD pwrite, DWORD pmix, DWORD bmix)
1487 TRACE("primary playpos=%ld, mixpos=%ld\n", pplay, pmix);
1488 TRACE("this mixpos=%ld, time=%ld\n", bmix, GetTickCount());
1490 /* the actual primary play position (pplay) is always behind last mixed (pmix),
1491 * unless the computer is too slow or something */
1492 /* we need to know how far away we are from there */
1493 #if 0 /* we'll never fill the primary entirely */
1494 if (pmix == pplay) {
1495 if ((state == STATE_PLAYING) || (state == STATE_STOPPING)) {
1496 /* wow, the software mixer is really doing well,
1497 * seems the entire primary buffer is filled! */
1498 pmix += primarybuf->buflen;
1500 /* else: the primary buffer is not playing, so probably empty */
1503 if (pmix < pplay) pmix += primarybuf->buflen; /* wraparound */
1505 /* detect buffer underrun */
1506 if (pwrite < pplay) pwrite += primarybuf->buflen; /* wraparound */
1508 if (pmix > (DS_SND_QUEUE_MAX * primarybuf->dsound->fraglen + pwrite + primarybuf->writelead)) {
1509 WARN("detected an underrun: primary queue was %ld\n",pmix);
1512 /* divide the offset by its sample size */
1513 pmix /= primarybuf->wfx.nBlockAlign;
1514 TRACE("primary back-samples=%ld\n",pmix);
1515 /* adjust for our frequency */
1516 pmix = (pmix * This->freqAdjust) >> DSOUND_FREQSHIFT;
1517 /* multiply by our own sample size */
1518 pmix *= This->wfx.nBlockAlign;
1519 TRACE("this back-offset=%ld\n", pmix);
1520 /* subtract from our last mixed position */
1522 while (bplay < pmix) bplay += This->buflen; /* wraparound */
1524 if (This->leadin && ((bplay < This->startpos) || (bplay > bmix))) {
1525 /* seems we haven't started playing yet */
1526 TRACE("this still in lead-in phase\n");
1527 bplay = This->startpos;
1529 /* return the result */
1533 static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition(
1534 LPDIRECTSOUNDBUFFER iface,LPDWORD playpos,LPDWORD writepos
1537 ICOM_THIS(IDirectSoundBufferImpl,iface);
1538 TRACE("(%p,%p,%p)\n",This,playpos,writepos);
1540 hres=IDsDriverBuffer_GetPosition(This->hwbuf,playpos,writepos);
1544 else if (This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER) {
1547 mtime.wType = TIME_BYTES;
1548 waveOutGetPosition(This->dsound->hwo, &mtime, sizeof(mtime));
1549 mtime.u.cb = mtime.u.cb % This->buflen;
1550 *playpos = mtime.u.cb;
1553 /* the writepos should only be used by apps with WRITEPRIMARY priority,
1554 * in which case our software mixer is disabled anyway */
1555 *writepos = (This->dsound->pwplay + DS_HEL_MARGIN) * This->dsound->fraglen;
1556 while (*writepos >= This->buflen)
1557 *writepos -= This->buflen;
1560 if (playpos && (This->state != STATE_PLAYING)) {
1561 /* we haven't been merged into the primary buffer (yet) */
1562 *playpos = This->buf_mixpos;
1565 DWORD pplay, pwrite, lplay, splay, pstate;
1566 /* let's get this exact; first, recursively call GetPosition on the primary */
1567 EnterCriticalSection(&(primarybuf->lock));
1568 IDirectSoundBufferImpl_GetCurrentPosition((LPDIRECTSOUNDBUFFER)primarybuf, &pplay, &pwrite);
1569 /* detect HEL mode underrun */
1570 pstate = primarybuf->state;
1571 if (!(primarybuf->hwbuf || primarybuf->dsound->pwqueue)) {
1572 TRACE("detected an underrun\n");
1574 if (pstate == STATE_PLAYING)
1575 pstate = STATE_STARTING;
1576 else if (pstate == STATE_STOPPING)
1577 pstate = STATE_STOPPED;
1579 /* get data for ourselves while we still have the lock */
1580 pstate &= This->state;
1581 lplay = This->primary_mixpos;
1582 splay = This->buf_mixpos;
1583 if ((This->dsbd.dwFlags & DSBCAPS_GETCURRENTPOSITION2) || primarybuf->hwbuf) {
1584 /* calculate play position using this */
1585 *playpos = DSOUND_CalcPlayPosition(This, pstate, pplay, pwrite, lplay, splay);
1587 /* (unless the app isn't using GETCURRENTPOSITION2) */
1588 /* don't know exactly how this should be handled...
1589 * the docs says that play cursor is reported as directly
1590 * behind write cursor, hmm... */
1591 /* let's just do what might work for Half-Life */
1593 wp = (This->dsound->pwplay + DS_HEL_MARGIN) * This->dsound->fraglen;
1594 while (wp >= primarybuf->buflen)
1595 wp -= primarybuf->buflen;
1596 *playpos = DSOUND_CalcPlayPosition(This, pstate, wp, pwrite, lplay, splay);
1598 LeaveCriticalSection(&(primarybuf->lock));
1600 if (writepos) *writepos = This->buf_mixpos;
1603 if (This->state != STATE_STOPPED)
1604 /* apply the documented 10ms lead to writepos */
1605 *writepos += This->writelead;
1606 while (*writepos >= This->buflen) *writepos -= This->buflen;
1608 TRACE("playpos = %ld, writepos = %ld (%p, time=%ld)\n", playpos?*playpos:0, writepos?*writepos:0, This, GetTickCount());
1612 static HRESULT WINAPI IDirectSoundBufferImpl_GetStatus(
1613 LPDIRECTSOUNDBUFFER iface,LPDWORD status
1615 ICOM_THIS(IDirectSoundBufferImpl,iface);
1616 TRACE("(%p,%p), thread is %lx\n",This,status,GetCurrentThreadId());
1619 return DSERR_INVALIDPARAM;
1622 if ((This->state == STATE_STARTING) || (This->state == STATE_PLAYING)) {
1623 *status |= DSBSTATUS_PLAYING;
1624 if (This->playflags & DSBPLAY_LOOPING)
1625 *status |= DSBSTATUS_LOOPING;
1628 TRACE("status=%lx\n", *status);
1633 static HRESULT WINAPI IDirectSoundBufferImpl_GetFormat(
1634 LPDIRECTSOUNDBUFFER iface,LPWAVEFORMATEX lpwf,DWORD wfsize,LPDWORD wfwritten
1636 ICOM_THIS(IDirectSoundBufferImpl,iface);
1637 TRACE("(%p,%p,%ld,%p)\n",This,lpwf,wfsize,wfwritten);
1639 if (wfsize>sizeof(This->wfx))
1640 wfsize = sizeof(This->wfx);
1641 if (lpwf) { /* NULL is valid */
1642 memcpy(lpwf,&(This->wfx),wfsize);
1644 *wfwritten = wfsize;
1647 *wfwritten = sizeof(This->wfx);
1649 return DSERR_INVALIDPARAM;
1654 static HRESULT WINAPI IDirectSoundBufferImpl_Lock(
1655 LPDIRECTSOUNDBUFFER iface,DWORD writecursor,DWORD writebytes,LPVOID lplpaudioptr1,LPDWORD audiobytes1,LPVOID lplpaudioptr2,LPDWORD audiobytes2,DWORD flags
1657 ICOM_THIS(IDirectSoundBufferImpl,iface);
1660 TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx) at %ld\n",
1672 if (flags & DSBLOCK_FROMWRITECURSOR) {
1674 /* GetCurrentPosition does too much magic to duplicate here */
1675 IDirectSoundBufferImpl_GetCurrentPosition(iface, NULL, &writepos);
1676 writecursor += writepos;
1678 if (flags & DSBLOCK_ENTIREBUFFER)
1679 writebytes = This->buflen;
1680 if (writebytes > This->buflen)
1681 writebytes = This->buflen;
1683 assert(audiobytes1!=audiobytes2);
1684 assert(lplpaudioptr1!=lplpaudioptr2);
1686 if ((writebytes == This->buflen) &&
1687 ((This->state == STATE_STARTING) ||
1688 (This->state == STATE_PLAYING)))
1689 /* some games, like Half-Life, try to be clever (not) and
1690 * keep one secondary buffer, and mix sounds into it itself,
1691 * locking the entire buffer every time... so we can just forget
1692 * about tracking the last-written-to-position... */
1693 This->probably_valid_to = (DWORD)-1;
1695 This->probably_valid_to = writecursor;
1697 if (This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER)
1698 capf = DSDDESC_DONTNEEDPRIMARYLOCK;
1700 capf = DSDDESC_DONTNEEDSECONDARYLOCK;
1701 if (!(This->dsound->drvdesc.dwFlags & capf) && This->hwbuf) {
1702 IDsDriverBuffer_Lock(This->hwbuf,
1703 lplpaudioptr1, audiobytes1,
1704 lplpaudioptr2, audiobytes2,
1705 writecursor, writebytes,
1710 if (writecursor+writebytes <= This->buflen) {
1711 *(LPBYTE*)lplpaudioptr1 = This->buffer+writecursor;
1712 *audiobytes1 = writebytes;
1714 *(LPBYTE*)lplpaudioptr2 = NULL;
1717 TRACE("->%ld.0\n",writebytes);
1719 *(LPBYTE*)lplpaudioptr1 = This->buffer+writecursor;
1720 *audiobytes1 = This->buflen-writecursor;
1722 *(LPBYTE*)lplpaudioptr2 = This->buffer;
1724 *audiobytes2 = writebytes-(This->buflen-writecursor);
1725 TRACE("->%ld.%ld\n",*audiobytes1,audiobytes2?*audiobytes2:0);
1727 /* if the segment between playpos and buf_mixpos is touched,
1728 * we need to cancel some mixing */
1729 if (This->buf_mixpos >= This->playpos) {
1730 if (This->buf_mixpos > writecursor &&
1731 This->playpos <= writecursor+writebytes)
1735 if (This->buf_mixpos > writecursor ||
1736 This->playpos <= writecursor+writebytes)
1740 TRACE("locking prebuffered region, ouch\n");
1741 DSOUND_MixCancelAt(This, writecursor);
1747 static HRESULT WINAPI IDirectSoundBufferImpl_SetCurrentPosition(
1748 LPDIRECTSOUNDBUFFER iface,DWORD newpos
1750 ICOM_THIS(IDirectSoundBufferImpl,iface);
1751 TRACE("(%p,%ld)\n",This,newpos);
1754 EnterCriticalSection(&(This->lock));
1756 This->buf_mixpos = newpos;
1758 IDsDriverBuffer_SetPosition(This->hwbuf, This->buf_mixpos);
1760 LeaveCriticalSection(&(This->lock));
1766 static HRESULT WINAPI IDirectSoundBufferImpl_SetPan(
1767 LPDIRECTSOUNDBUFFER iface,LONG pan
1769 ICOM_THIS(IDirectSoundBufferImpl,iface);
1771 TRACE("(%p,%ld)\n",This,pan);
1773 if ((pan > DSBPAN_RIGHT) || (pan < DSBPAN_LEFT))
1774 return DSERR_INVALIDPARAM;
1776 /* You cannot set the pan of the primary buffer */
1777 /* and you cannot use both pan and 3D controls */
1778 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN) ||
1779 (This->dsbd.dwFlags & DSBCAPS_CTRL3D) ||
1780 (This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER))
1781 return DSERR_CONTROLUNAVAIL;
1784 EnterCriticalSection(&(This->lock));
1786 This->volpan.lPan = pan;
1788 DSOUND_RecalcVolPan(&(This->volpan));
1791 IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan));
1794 LeaveCriticalSection(&(This->lock));
1800 static HRESULT WINAPI IDirectSoundBufferImpl_GetPan(
1801 LPDIRECTSOUNDBUFFER iface,LPLONG pan
1803 ICOM_THIS(IDirectSoundBufferImpl,iface);
1804 TRACE("(%p,%p)\n",This,pan);
1807 return DSERR_INVALIDPARAM;
1809 *pan = This->volpan.lPan;
1814 static HRESULT WINAPI IDirectSoundBufferImpl_Unlock(
1815 LPDIRECTSOUNDBUFFER iface,LPVOID p1,DWORD x1,LPVOID p2,DWORD x2
1817 ICOM_THIS(IDirectSoundBufferImpl,iface);
1818 DWORD capf, probably_valid_to;
1820 TRACE("(%p,%p,%ld,%p,%ld):stub\n", This,p1,x1,p2,x2);
1823 /* Preprocess 3D buffers... */
1825 /* This is highly experimental and liable to break things */
1826 if (This->dsbd.dwFlags & DSBCAPS_CTRL3D)
1827 DSOUND_Create3DBuffer(This);
1830 if (This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER)
1831 capf = DSDDESC_DONTNEEDPRIMARYLOCK;
1833 capf = DSDDESC_DONTNEEDSECONDARYLOCK;
1834 if (!(This->dsound->drvdesc.dwFlags & capf) && This->hwbuf) {
1835 IDsDriverBuffer_Unlock(This->hwbuf, p1, x1, p2, x2);
1838 if (p2) probably_valid_to = (((LPBYTE)p2)-This->buffer) + x2;
1839 else probably_valid_to = (((LPBYTE)p1)-This->buffer) + x1;
1840 while (probably_valid_to >= This->buflen)
1841 probably_valid_to -= This->buflen;
1842 if ((probably_valid_to == 0) && ((x1+x2) == This->buflen) &&
1843 ((This->state == STATE_STARTING) ||
1844 (This->state == STATE_PLAYING)))
1845 /* see IDirectSoundBufferImpl_Lock */
1846 probably_valid_to = (DWORD)-1;
1847 This->probably_valid_to = probably_valid_to;
1852 static HRESULT WINAPI IDirectSoundBufferImpl_Restore(
1853 LPDIRECTSOUNDBUFFER iface
1855 ICOM_THIS(IDirectSoundBufferImpl,iface);
1856 FIXME("(%p):stub\n",This);
1860 static HRESULT WINAPI IDirectSoundBufferImpl_GetFrequency(
1861 LPDIRECTSOUNDBUFFER iface,LPDWORD freq
1863 ICOM_THIS(IDirectSoundBufferImpl,iface);
1864 TRACE("(%p,%p)\n",This,freq);
1867 return DSERR_INVALIDPARAM;
1870 TRACE("-> %ld\n", *freq);
1875 static HRESULT WINAPI IDirectSoundBufferImpl_Initialize(
1876 LPDIRECTSOUNDBUFFER iface,LPDIRECTSOUND dsound,LPDSBUFFERDESC dbsd
1878 ICOM_THIS(IDirectSoundBufferImpl,iface);
1879 FIXME("(%p,%p,%p):stub\n",This,dsound,dbsd);
1880 DPRINTF("Re-Init!!!\n");
1881 return DSERR_ALREADYINITIALIZED;
1884 static HRESULT WINAPI IDirectSoundBufferImpl_GetCaps(
1885 LPDIRECTSOUNDBUFFER iface,LPDSBCAPS caps
1887 ICOM_THIS(IDirectSoundBufferImpl,iface);
1888 TRACE("(%p)->(%p)\n",This,caps);
1891 return DSERR_INVALIDPARAM;
1893 /* I think we should check this value, not set it. See */
1894 /* Inside DirectX, p215. That should apply here, too. */
1895 caps->dwSize = sizeof(*caps);
1897 caps->dwFlags = This->dsbd.dwFlags;
1898 if (This->hwbuf) caps->dwFlags |= DSBCAPS_LOCHARDWARE;
1899 else caps->dwFlags |= DSBCAPS_LOCSOFTWARE;
1901 caps->dwBufferBytes = This->buflen;
1903 /* This value represents the speed of the "unlock" command.
1904 As unlock is quite fast (it does not do anything), I put
1905 4096 ko/s = 4 Mo / s */
1906 /* FIXME: hwbuf speed */
1907 caps->dwUnlockTransferRate = 4096;
1908 caps->dwPlayCpuOverhead = 0;
1913 static HRESULT WINAPI IDirectSoundBufferImpl_QueryInterface(
1914 LPDIRECTSOUNDBUFFER iface,REFIID riid,LPVOID *ppobj
1916 ICOM_THIS(IDirectSoundBufferImpl,iface);
1918 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
1920 if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
1921 IDirectSoundNotifyImpl *dsn;
1923 dsn = (IDirectSoundNotifyImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(*dsn));
1926 IDirectSoundBuffer_AddRef(iface);
1927 ICOM_VTBL(dsn) = &dsnvt;
1928 *ppobj = (LPVOID)dsn;
1933 if ( IsEqualGUID( &IID_IDirectSound3DBuffer, riid ) ) {
1934 IDirectSound3DBufferImpl *ds3db;
1936 *ppobj = This->ds3db;
1938 IDirectSound3DBuffer_AddRef((LPDIRECTSOUND3DBUFFER)This->ds3db);
1942 ds3db = (IDirectSound3DBufferImpl*)HeapAlloc(GetProcessHeap(),
1946 ICOM_VTBL(ds3db) = &ds3dbvt;
1947 InitializeCriticalSection(&ds3db->lock);
1949 IDirectSoundBuffer_AddRef(iface);
1951 ds3db->ds3db.dwSize = sizeof(DS3DBUFFER);
1952 ds3db->ds3db.vPosition.u1.x = 0.0;
1953 ds3db->ds3db.vPosition.u2.y = 0.0;
1954 ds3db->ds3db.vPosition.u3.z = 0.0;
1955 ds3db->ds3db.vVelocity.u1.x = 0.0;
1956 ds3db->ds3db.vVelocity.u2.y = 0.0;
1957 ds3db->ds3db.vVelocity.u3.z = 0.0;
1958 ds3db->ds3db.dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
1959 ds3db->ds3db.dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
1960 ds3db->ds3db.vConeOrientation.u1.x = 0.0;
1961 ds3db->ds3db.vConeOrientation.u2.y = 0.0;
1962 ds3db->ds3db.vConeOrientation.u3.z = 0.0;
1963 ds3db->ds3db.lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME; ds3db->ds3db.flMinDistance = DS3D_DEFAULTMINDISTANCE;
1964 ds3db->ds3db.flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
1965 ds3db->ds3db.dwMode = DS3DMODE_NORMAL;
1966 ds3db->buflen = (This->buflen * primarybuf->wfx.nBlockAlign) /
1967 This->wfx.nBlockAlign;
1968 ds3db->buffer = HeapAlloc(GetProcessHeap(), 0, ds3db->buflen);
1969 if (ds3db->buffer == NULL) {
1971 ds3db->ds3db.dwMode = DS3DMODE_DISABLE;
1974 ds3db->iks = (IKsPropertySetImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(*(ds3db->iks)));
1975 ds3db->iks->ref = 1;
1976 ds3db->iks->ds3db = ds3db;
1977 ICOM_VTBL(ds3db->iks) = &iksvt;
1982 if ( IsEqualGUID( &IID_IDirectSound3DBuffer, riid ) ) {
1983 FIXME("%s: I know about this GUID, but don't support it yet\n",
1984 debugstr_guid( riid ));
1991 if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) {
1992 IDirectSound3DListenerImpl* dsl;
1994 if (This->dsound->listener) {
1995 *ppobj = This->dsound->listener;
1996 IDirectSound3DListener_AddRef((LPDIRECTSOUND3DLISTENER)This->dsound->listener);
2000 dsl = (IDirectSound3DListenerImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(*dsl));
2002 ICOM_VTBL(dsl) = &ds3dlvt;
2003 *ppobj = (LPVOID)dsl;
2005 dsl->ds3dl.dwSize = sizeof(DS3DLISTENER);
2006 dsl->ds3dl.vPosition.u1.x = 0.0;
2007 dsl->ds3dl.vPosition.u2.y = 0.0;
2008 dsl->ds3dl.vPosition.u3.z = 0.0;
2009 dsl->ds3dl.vVelocity.u1.x = 0.0;
2010 dsl->ds3dl.vVelocity.u2.y = 0.0;
2011 dsl->ds3dl.vVelocity.u3.z = 0.0;
2012 dsl->ds3dl.vOrientFront.u1.x = 0.0;
2013 dsl->ds3dl.vOrientFront.u2.y = 0.0;
2014 dsl->ds3dl.vOrientFront.u3.z = 1.0;
2015 dsl->ds3dl.vOrientTop.u1.x = 0.0;
2016 dsl->ds3dl.vOrientTop.u2.y = 1.0;
2017 dsl->ds3dl.vOrientTop.u3.z = 0.0;
2018 dsl->ds3dl.flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
2019 dsl->ds3dl.flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
2021 InitializeCriticalSection(&dsl->lock);
2024 IDirectSoundBuffer_AddRef(iface);
2026 This->dsound->listener = dsl;
2027 IDirectSound3DListener_AddRef((LPDIRECTSOUND3DLISTENER)dsl);
2032 if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) {
2033 FIXME("%s: I know about this GUID, but don't support it yet\n",
2034 debugstr_guid( riid ));
2040 FIXME( "Unknown GUID %s\n", debugstr_guid( riid ) );
2047 static ICOM_VTABLE(IDirectSoundBuffer) dsbvt =
2049 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
2050 IDirectSoundBufferImpl_QueryInterface,
2051 IDirectSoundBufferImpl_AddRef,
2052 IDirectSoundBufferImpl_Release,
2053 IDirectSoundBufferImpl_GetCaps,
2054 IDirectSoundBufferImpl_GetCurrentPosition,
2055 IDirectSoundBufferImpl_GetFormat,
2056 IDirectSoundBufferImpl_GetVolume,
2057 IDirectSoundBufferImpl_GetPan,
2058 IDirectSoundBufferImpl_GetFrequency,
2059 IDirectSoundBufferImpl_GetStatus,
2060 IDirectSoundBufferImpl_Initialize,
2061 IDirectSoundBufferImpl_Lock,
2062 IDirectSoundBufferImpl_Play,
2063 IDirectSoundBufferImpl_SetCurrentPosition,
2064 IDirectSoundBufferImpl_SetFormat,
2065 IDirectSoundBufferImpl_SetVolume,
2066 IDirectSoundBufferImpl_SetPan,
2067 IDirectSoundBufferImpl_SetFrequency,
2068 IDirectSoundBufferImpl_Stop,
2069 IDirectSoundBufferImpl_Unlock,
2070 IDirectSoundBufferImpl_Restore
2073 /*******************************************************************************
2077 static HRESULT WINAPI IDirectSoundImpl_SetCooperativeLevel(
2078 LPDIRECTSOUND iface,HWND hwnd,DWORD level
2080 ICOM_THIS(IDirectSoundImpl,iface);
2082 FIXME("(%p,%08lx,%ld):stub\n",This,(DWORD)hwnd,level);
2084 This->priolevel = level;
2089 static HRESULT WINAPI IDirectSoundImpl_CreateSoundBuffer(
2090 LPDIRECTSOUND iface,LPDSBUFFERDESC dsbd,LPLPDIRECTSOUNDBUFFER ppdsb,LPUNKNOWN lpunk
2092 ICOM_THIS(IDirectSoundImpl,iface);
2093 IDirectSoundBufferImpl** ippdsb=(IDirectSoundBufferImpl**)ppdsb;
2094 LPWAVEFORMATEX wfex;
2095 HRESULT err = DS_OK;
2097 TRACE("(%p,%p,%p,%p)\n",This,dsbd,ippdsb,lpunk);
2099 if ((This == NULL) || (dsbd == NULL) || (ippdsb == NULL))
2100 return DSERR_INVALIDPARAM;
2102 if (TRACE_ON(dsound)) {
2103 TRACE("(structsize=%ld)\n",dsbd->dwSize);
2104 TRACE("(flags=0x%08lx:\n",dsbd->dwFlags);
2105 _dump_DSBCAPS(dsbd->dwFlags);
2107 TRACE("(bufferbytes=%ld)\n",dsbd->dwBufferBytes);
2108 TRACE("(lpwfxFormat=%p)\n",dsbd->lpwfxFormat);
2111 wfex = dsbd->lpwfxFormat;
2114 TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld,"
2115 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
2116 wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec,
2117 wfex->nAvgBytesPerSec, wfex->nBlockAlign,
2118 wfex->wBitsPerSample, wfex->cbSize);
2120 if (dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) {
2122 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)primarybuf);
2123 *ippdsb = primarybuf;
2124 primarybuf->dsbd.dwFlags = dsbd->dwFlags;
2126 } /* Else create primary buffer */
2128 if (dsbd->dwBufferBytes < DSBSIZE_MIN || dsbd->dwBufferBytes > DSBSIZE_MAX) {
2129 ERR("invalid sound buffer size %ld\n", dsbd->dwBufferBytes);
2130 return DSERR_INVALIDPARAM; /* FIXME: which error? */
2134 *ippdsb = (IDirectSoundBufferImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectSoundBufferImpl));
2135 if (*ippdsb == NULL)
2136 return DSERR_OUTOFMEMORY;
2137 ICOM_VTBL(*ippdsb) = &dsbvt;
2139 (*ippdsb)->dsound = This;
2140 (*ippdsb)->parent = NULL;
2141 (*ippdsb)->buffer = NULL;
2143 memcpy(&((*ippdsb)->dsbd),dsbd,sizeof(*dsbd));
2144 if (dsbd->lpwfxFormat)
2145 memcpy(&((*ippdsb)->wfx), dsbd->lpwfxFormat, sizeof((*ippdsb)->wfx));
2147 TRACE("Created buffer at %p\n", *ippdsb);
2149 if (dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) {
2150 (*ippdsb)->buflen = dsound->wfx.nAvgBytesPerSec;
2151 (*ippdsb)->freq = dsound->wfx.nSamplesPerSec;
2153 /* FIXME: verify that hardware capabilities (DSCAPS_PRIMARY flags) match */
2156 err = IDsDriver_CreateSoundBuffer(This->driver,wfex,dsbd->dwFlags,0,
2157 &((*ippdsb)->buflen),&((*ippdsb)->buffer),
2158 (LPVOID*)&((*ippdsb)->hwbuf));
2161 err = DSOUND_PrimaryOpen(*ippdsb);
2166 (*ippdsb)->buflen = dsbd->dwBufferBytes;
2167 (*ippdsb)->freq = dsbd->lpwfxFormat->nSamplesPerSec;
2169 /* Check necessary hardware mixing capabilities */
2170 if (wfex->nChannels==2) capf |= DSCAPS_SECONDARYSTEREO;
2171 else capf |= DSCAPS_SECONDARYMONO;
2172 if (wfex->wBitsPerSample==16) capf |= DSCAPS_SECONDARY16BIT;
2173 else capf |= DSCAPS_SECONDARY8BIT;
2174 use_hw = (This->drvcaps.dwFlags & capf) == capf;
2176 /* FIXME: check hardware sample rate mixing capabilities */
2177 /* FIXME: check app hints for software/hardware buffer (STATIC, LOCHARDWARE, etc) */
2178 /* FIXME: check whether any hardware buffers are left */
2179 /* FIXME: handle DSDHEAP_CREATEHEAP for hardware buffers */
2181 /* Allocate system memory if applicable */
2182 if ((This->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) || !use_hw) {
2183 (*ippdsb)->buffer = (LPBYTE)HeapAlloc(GetProcessHeap(),0,(*ippdsb)->buflen);
2184 if ((*ippdsb)->buffer == NULL)
2185 err = DSERR_OUTOFMEMORY;
2188 /* Allocate the hardware buffer */
2189 if (use_hw && (err == DS_OK)) {
2190 err = IDsDriver_CreateSoundBuffer(This->driver,wfex,dsbd->dwFlags,0,
2191 &((*ippdsb)->buflen),&((*ippdsb)->buffer),
2192 (LPVOID*)&((*ippdsb)->hwbuf));
2197 if ((*ippdsb)->buffer)
2198 HeapFree(GetProcessHeap(),0,(*ippdsb)->buffer);
2199 HeapFree(GetProcessHeap(),0,(*ippdsb));
2203 /* calculate fragment size and write lead */
2204 DSOUND_RecalcFormat(*ippdsb);
2206 /* It's not necessary to initialize values to zero since */
2207 /* we allocated this structure with HEAP_ZERO_MEMORY... */
2208 (*ippdsb)->playpos = 0;
2209 (*ippdsb)->buf_mixpos = 0;
2210 (*ippdsb)->state = STATE_STOPPED;
2211 DSOUND_RecalcVolPan(&((*ippdsb)->volpan));
2213 if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
2214 (*ippdsb)->freqAdjust = ((*ippdsb)->freq << DSOUND_FREQSHIFT) /
2215 primarybuf->wfx.nSamplesPerSec;
2216 (*ippdsb)->nAvgBytesPerSec = (*ippdsb)->freq *
2217 dsbd->lpwfxFormat->nBlockAlign;
2220 EnterCriticalSection(&(This->lock));
2221 /* register buffer */
2222 if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
2223 IDirectSoundBufferImpl **newbuffers = (IDirectSoundBufferImpl**)HeapReAlloc(GetProcessHeap(),0,This->buffers,sizeof(IDirectSoundBufferImpl*)*(This->nrofbuffers+1));
2225 This->buffers = newbuffers;
2226 This->buffers[This->nrofbuffers] = *ippdsb;
2227 This->nrofbuffers++;
2228 TRACE("buffer count is now %d\n", This->nrofbuffers);
2230 ERR("out of memory for buffer list! Current buffer count is %d\n", This->nrofbuffers);
2231 err = DSERR_OUTOFMEMORY;
2234 LeaveCriticalSection(&(This->lock));
2236 IDirectSound_AddRef(iface);
2238 InitializeCriticalSection(&((*ippdsb)->lock));
2242 IDirectSoundBuffer_Release(*ppdsb);
2248 if (dsbd->dwFlags & DSBCAPS_CTRL3D) {
2249 IDirectSound3DBufferImpl *ds3db;
2251 ds3db = (IDirectSound3DBufferImpl*)HeapAlloc(GetProcessHeap(),
2253 ICOM_VTBL(ds3db) = &ds3dbvt;
2255 (*ippdsb)->ds3db = ds3db;
2257 ds3db->dsb = (*ippdsb);
2258 IDirectSoundBufferImpl_AddRef((LPDIRECTSOUNDBUFFER)(*ippdsb));
2260 InitializeCriticalSection(&ds3db->lock);
2262 ds3db->ds3db.dwSize = sizeof(DS3DBUFFER);
2263 ds3db->ds3db.vPosition.u1.x = 0.0;
2264 ds3db->ds3db.vPosition.u2.y = 0.0;
2265 ds3db->ds3db.vPosition.u3.z = 0.0;
2266 ds3db->ds3db.vVelocity.u1.x = 0.0;
2267 ds3db->ds3db.vVelocity.u2.y = 0.0;
2268 ds3db->ds3db.vVelocity.u3.z = 0.0;
2269 ds3db->ds3db.dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
2270 ds3db->ds3db.dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
2271 ds3db->ds3db.vConeOrientation.u1.x = 0.0;
2272 ds3db->ds3db.vConeOrientation.u2.y = 0.0;
2273 ds3db->ds3db.vConeOrientation.u3.z = 0.0;
2274 ds3db->ds3db.lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
2275 ds3db->ds3db.flMinDistance = DS3D_DEFAULTMINDISTANCE;
2276 ds3db->ds3db.flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
2277 ds3db->ds3db.dwMode = DS3DMODE_NORMAL;
2278 ds3db->buflen = ((*ippdsb)->buflen * primarybuf->wfx.nBlockAlign) /
2279 (*ippdsb)->wfx.nBlockAlign;
2280 ds3db->buffer = HeapAlloc(GetProcessHeap(), 0, ds3db->buflen);
2281 if (ds3db->buffer == NULL) {
2283 ds3db->ds3db.dwMode = DS3DMODE_DISABLE;
2285 ds3db->iks = (IKsPropertySetImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(*(ds3db->iks)));
2286 ds3db->iks->ref = 1;
2287 ds3db->iks->ds3db = ds3db;
2288 ICOM_VTBL(ds3db->iks) = &iksvt;
2295 static HRESULT WINAPI IDirectSoundImpl_DuplicateSoundBuffer(
2296 LPDIRECTSOUND iface,LPDIRECTSOUNDBUFFER pdsb,LPLPDIRECTSOUNDBUFFER ppdsb
2298 ICOM_THIS(IDirectSoundImpl,iface);
2299 IDirectSoundBufferImpl* ipdsb=(IDirectSoundBufferImpl*)pdsb;
2300 IDirectSoundBufferImpl** ippdsb=(IDirectSoundBufferImpl**)ppdsb;
2301 TRACE("(%p,%p,%p)\n",This,ipdsb,ippdsb);
2304 FIXME("need to duplicate hardware buffer\n");
2307 *ippdsb = (IDirectSoundBufferImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectSoundBufferImpl));
2309 IDirectSoundBuffer_AddRef(pdsb);
2310 memcpy(*ippdsb, ipdsb, sizeof(IDirectSoundBufferImpl));
2312 (*ippdsb)->state = STATE_STOPPED;
2313 (*ippdsb)->playpos = 0;
2314 (*ippdsb)->buf_mixpos = 0;
2315 (*ippdsb)->dsound = This;
2316 (*ippdsb)->parent = ipdsb;
2317 memcpy(&((*ippdsb)->wfx), &(ipdsb->wfx), sizeof((*ippdsb)->wfx));
2318 InitializeCriticalSection(&(*ippdsb)->lock);
2319 /* register buffer */
2320 EnterCriticalSection(&(This->lock));
2322 IDirectSoundBufferImpl **newbuffers = (IDirectSoundBufferImpl**)HeapReAlloc(GetProcessHeap(),0,This->buffers,sizeof(IDirectSoundBufferImpl**)*(This->nrofbuffers+1));
2324 This->buffers = newbuffers;
2325 This->buffers[This->nrofbuffers] = *ippdsb;
2326 This->nrofbuffers++;
2327 TRACE("buffer count is now %d\n", This->nrofbuffers);
2329 ERR("out of memory for buffer list! Current buffer count is %d\n", This->nrofbuffers);
2330 /* FIXME: release buffer */
2333 LeaveCriticalSection(&(This->lock));
2334 IDirectSound_AddRef(iface);
2339 static HRESULT WINAPI IDirectSoundImpl_GetCaps(LPDIRECTSOUND iface,LPDSCAPS caps) {
2340 ICOM_THIS(IDirectSoundImpl,iface);
2341 TRACE("(%p,%p)\n",This,caps);
2342 TRACE("(flags=0x%08lx)\n",caps->dwFlags);
2345 return DSERR_INVALIDPARAM;
2347 /* We should check this value, not set it. See Inside DirectX, p215. */
2348 caps->dwSize = sizeof(*caps);
2350 caps->dwFlags = This->drvcaps.dwFlags;
2352 /* FIXME: copy caps from This->drvcaps */
2353 caps->dwMinSecondarySampleRate = DSBFREQUENCY_MIN;
2354 caps->dwMaxSecondarySampleRate = DSBFREQUENCY_MAX;
2356 caps->dwPrimaryBuffers = 1;
2358 caps->dwMaxHwMixingAllBuffers = 0;
2359 caps->dwMaxHwMixingStaticBuffers = 0;
2360 caps->dwMaxHwMixingStreamingBuffers = 0;
2362 caps->dwFreeHwMixingAllBuffers = 0;
2363 caps->dwFreeHwMixingStaticBuffers = 0;
2364 caps->dwFreeHwMixingStreamingBuffers = 0;
2366 caps->dwMaxHw3DAllBuffers = 0;
2367 caps->dwMaxHw3DStaticBuffers = 0;
2368 caps->dwMaxHw3DStreamingBuffers = 0;
2370 caps->dwFreeHw3DAllBuffers = 0;
2371 caps->dwFreeHw3DStaticBuffers = 0;
2372 caps->dwFreeHw3DStreamingBuffers = 0;
2374 caps->dwTotalHwMemBytes = 0;
2376 caps->dwFreeHwMemBytes = 0;
2378 caps->dwMaxContigFreeHwMemBytes = 0;
2380 caps->dwUnlockTransferRateHwBuffers = 4096; /* But we have none... */
2382 caps->dwPlayCpuOverheadSwBuffers = 1; /* 1% */
2387 static ULONG WINAPI IDirectSoundImpl_AddRef(LPDIRECTSOUND iface) {
2388 ICOM_THIS(IDirectSoundImpl,iface);
2389 return ++(This->ref);
2392 static ULONG WINAPI IDirectSoundImpl_Release(LPDIRECTSOUND iface) {
2393 ICOM_THIS(IDirectSoundImpl,iface);
2394 TRACE("(%p), ref was %ld\n",This,This->ref);
2395 if (!--(This->ref)) {
2398 timeKillEvent(This->timerID);
2399 timeEndPeriod(DS_TIME_RES);
2402 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)primarybuf);
2404 if (This->buffers) {
2405 for( i=0;i<This->nrofbuffers;i++)
2406 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)This->buffers[i]);
2410 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)This->primary);
2412 DeleteCriticalSection(&This->lock);
2414 IDsDriver_Close(This->driver);
2417 for (c=0; c<DS_HEL_FRAGS; c++)
2418 HeapFree(GetProcessHeap(),0,This->pwave[c]);
2420 if (This->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN) {
2421 waveOutClose(This->hwo);
2424 IDsDriver_Release(This->driver);
2426 HeapFree(GetProcessHeap(),0,This);
2433 static HRESULT WINAPI IDirectSoundImpl_SetSpeakerConfig(
2434 LPDIRECTSOUND iface,DWORD config
2436 ICOM_THIS(IDirectSoundImpl,iface);
2437 FIXME("(%p,0x%08lx):stub\n",This,config);
2441 static HRESULT WINAPI IDirectSoundImpl_QueryInterface(
2442 LPDIRECTSOUND iface,REFIID riid,LPVOID *ppobj
2444 ICOM_THIS(IDirectSoundImpl,iface);
2446 if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) {
2448 if (This->listener) {
2449 *ppobj = This->listener;
2450 IDirectSound3DListener_AddRef((LPDIRECTSOUND3DLISTENER)This->listener);
2454 This->listener = (IDirectSound3DListenerImpl*)HeapAlloc(
2455 GetProcessHeap(), 0, sizeof(*(This->listener)));
2456 This->listener->ref = 1;
2457 ICOM_VTBL(This->listener) = &ds3dlvt;
2458 *ppobj = (LPVOID)This->listener;
2459 IDirectSound3DListener_AddRef((LPDIRECTSOUND3DLISTENER)*ppobj);
2461 This->listener->dsb = NULL;
2463 This->listener->ds3dl.dwSize = sizeof(DS3DLISTENER);
2464 This->listener->ds3dl.vPosition.u1.x = 0.0;
2465 This->listener->ds3dl.vPosition.u2.y = 0.0;
2466 This->listener->ds3dl.vPosition.u3.z = 0.0;
2467 This->listener->ds3dl.vVelocity.u1.x = 0.0;
2468 This->listener->ds3dl.vVelocity.u2.y = 0.0;
2469 This->listener->ds3dl.vVelocity.u3.z = 0.0;
2470 This->listener->ds3dl.vOrientFront.u1.x = 0.0;
2471 This->listener->ds3dl.vOrientFront.u2.y = 0.0;
2472 This->listener->ds3dl.vOrientFront.u3.z = 1.0;
2473 This->listener->ds3dl.vOrientTop.u1.x = 0.0;
2474 This->listener->ds3dl.vOrientTop.u2.y = 1.0;
2475 This->listener->ds3dl.vOrientTop.u3.z = 0.0;
2476 This->listener->ds3dl.flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
2477 This->listener->ds3dl.flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
2478 This->listener->ds3dl.flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
2480 InitializeCriticalSection(&This->listener->lock);
2485 FIXME("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
2489 static HRESULT WINAPI IDirectSoundImpl_Compact(
2490 LPDIRECTSOUND iface)
2492 ICOM_THIS(IDirectSoundImpl,iface);
2493 TRACE("(%p)\n", This);
2497 static HRESULT WINAPI IDirectSoundImpl_GetSpeakerConfig(
2498 LPDIRECTSOUND iface,
2499 LPDWORD lpdwSpeakerConfig)
2501 ICOM_THIS(IDirectSoundImpl,iface);
2502 TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
2503 *lpdwSpeakerConfig = DSSPEAKER_STEREO | (DSSPEAKER_GEOMETRY_NARROW << 16);
2507 static HRESULT WINAPI IDirectSoundImpl_Initialize(
2508 LPDIRECTSOUND iface,
2511 ICOM_THIS(IDirectSoundImpl,iface);
2512 TRACE("(%p, %p)\n", This, lpcGuid);
2516 static ICOM_VTABLE(IDirectSound) dsvt =
2518 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
2519 IDirectSoundImpl_QueryInterface,
2520 IDirectSoundImpl_AddRef,
2521 IDirectSoundImpl_Release,
2522 IDirectSoundImpl_CreateSoundBuffer,
2523 IDirectSoundImpl_GetCaps,
2524 IDirectSoundImpl_DuplicateSoundBuffer,
2525 IDirectSoundImpl_SetCooperativeLevel,
2526 IDirectSoundImpl_Compact,
2527 IDirectSoundImpl_GetSpeakerConfig,
2528 IDirectSoundImpl_SetSpeakerConfig,
2529 IDirectSoundImpl_Initialize
2533 static void DSOUND_CheckEvent(IDirectSoundBufferImpl *dsb, int len)
2537 LPDSBPOSITIONNOTIFY event;
2539 if (dsb->nrofnotifies == 0)
2542 TRACE("(%p) buflen = %ld, playpos = %ld, len = %d\n",
2543 dsb, dsb->buflen, dsb->playpos, len);
2544 for (i = 0; i < dsb->nrofnotifies ; i++) {
2545 event = dsb->notifies + i;
2546 offset = event->dwOffset;
2547 TRACE("checking %d, position %ld, event = %d\n",
2548 i, offset, event->hEventNotify);
2549 /* DSBPN_OFFSETSTOP has to be the last element. So this is */
2550 /* OK. [Inside DirectX, p274] */
2552 /* This also means we can't sort the entries by offset, */
2553 /* because DSBPN_OFFSETSTOP == -1 */
2554 if (offset == DSBPN_OFFSETSTOP) {
2555 if (dsb->state == STATE_STOPPED) {
2556 SetEvent(event->hEventNotify);
2557 TRACE("signalled event %d (%d)\n", event->hEventNotify, i);
2562 if ((dsb->playpos + len) >= dsb->buflen) {
2563 if ((offset < ((dsb->playpos + len) % dsb->buflen)) ||
2564 (offset >= dsb->playpos)) {
2565 TRACE("signalled event %d (%d)\n", event->hEventNotify, i);
2566 SetEvent(event->hEventNotify);
2569 if ((offset >= dsb->playpos) && (offset < (dsb->playpos + len))) {
2570 TRACE("signalled event %d (%d)\n", event->hEventNotify, i);
2571 SetEvent(event->hEventNotify);
2577 /* WAV format info can be found at: */
2579 /* http://www.cwi.nl/ftp/audio/AudioFormats.part2 */
2580 /* ftp://ftp.cwi.nl/pub/audio/RIFF-format */
2582 /* Import points to remember: */
2584 /* 8-bit WAV is unsigned */
2585 /* 16-bit WAV is signed */
2587 static inline INT16 cvtU8toS16(BYTE byte)
2589 INT16 s = (byte - 128) << 8;
2594 static inline BYTE cvtS16toU8(INT16 word)
2596 BYTE b = (word + 32768) >> 8;
2602 /* We should be able to optimize these two inline functions */
2603 /* so that we aren't doing 8->16->8 conversions when it is */
2604 /* not necessary. But this is still a WIP. Optimize later. */
2605 static inline void get_fields(const IDirectSoundBufferImpl *dsb, BYTE *buf, INT *fl, INT *fr)
2607 INT16 *bufs = (INT16 *) buf;
2609 /* TRACE("(%p)\n", buf); */
2610 if ((dsb->wfx.wBitsPerSample == 8) && dsb->wfx.nChannels == 2) {
2611 *fl = cvtU8toS16(*buf);
2612 *fr = cvtU8toS16(*(buf + 1));
2616 if ((dsb->wfx.wBitsPerSample == 16) && dsb->wfx.nChannels == 2) {
2622 if ((dsb->wfx.wBitsPerSample == 8) && dsb->wfx.nChannels == 1) {
2623 *fl = cvtU8toS16(*buf);
2628 if ((dsb->wfx.wBitsPerSample == 16) && dsb->wfx.nChannels == 1) {
2634 FIXME("get_fields found an unsupported configuration\n");
2638 static inline void set_fields(BYTE *buf, INT fl, INT fr)
2640 INT16 *bufs = (INT16 *) buf;
2642 if ((primarybuf->wfx.wBitsPerSample == 8) && (primarybuf->wfx.nChannels == 2)) {
2643 *buf = cvtS16toU8(fl);
2644 *(buf + 1) = cvtS16toU8(fr);
2648 if ((primarybuf->wfx.wBitsPerSample == 16) && (primarybuf->wfx.nChannels == 2)) {
2654 if ((primarybuf->wfx.wBitsPerSample == 8) && (primarybuf->wfx.nChannels == 1)) {
2655 *buf = cvtS16toU8((fl + fr) >> 1);
2659 if ((primarybuf->wfx.wBitsPerSample == 16) && (primarybuf->wfx.nChannels == 1)) {
2660 *bufs = (fl + fr) >> 1;
2663 FIXME("set_fields found an unsupported configuration\n");
2667 /* Now with PerfectPitch (tm) technology */
2668 static INT DSOUND_MixerNorm(IDirectSoundBufferImpl *dsb, BYTE *buf, INT len)
2670 INT i, size, ipos, ilen, fieldL, fieldR;
2672 INT iAdvance = dsb->wfx.nBlockAlign;
2673 INT oAdvance = primarybuf->wfx.nBlockAlign;
2675 ibp = dsb->buffer + dsb->buf_mixpos;
2678 TRACE("(%p, %p, %p), buf_mixpos=%ld\n", dsb, ibp, obp, dsb->buf_mixpos);
2679 /* Check for the best case */
2680 if ((dsb->freq == primarybuf->wfx.nSamplesPerSec) &&
2681 (dsb->wfx.wBitsPerSample == primarybuf->wfx.wBitsPerSample) &&
2682 (dsb->wfx.nChannels == primarybuf->wfx.nChannels)) {
2683 DWORD bytesleft = dsb->buflen - dsb->buf_mixpos;
2684 TRACE("(%p) Best case\n", dsb);
2685 if (len <= bytesleft )
2686 memcpy(obp, ibp, len);
2688 memcpy(obp, ibp, bytesleft );
2689 memcpy(obp + bytesleft, dsb->buffer, len - bytesleft);
2694 /* Check for same sample rate */
2695 if (dsb->freq == primarybuf->wfx.nSamplesPerSec) {
2696 TRACE("(%p) Same sample rate %ld = primary %ld\n", dsb,
2697 dsb->freq, primarybuf->wfx.nSamplesPerSec);
2699 for (i = 0; i < len; i += oAdvance) {
2700 get_fields(dsb, ibp, &fieldL, &fieldR);
2703 set_fields(obp, fieldL, fieldR);
2705 if (ibp >= (BYTE *)(dsb->buffer + dsb->buflen))
2706 ibp = dsb->buffer; /* wrap */
2711 /* Mix in different sample rates */
2713 /* New PerfectPitch(tm) Technology (c) 1998 Rob Riggs */
2714 /* Patent Pending :-] */
2716 /* Patent enhancements (c) 2000 Ove KÃ¥ven,
2717 * TransGaming Technologies Inc. */
2719 FIXME("(%p) Adjusting frequency: %ld -> %ld (need optimization)\n",
2720 dsb, dsb->freq, primarybuf->wfx.nSamplesPerSec);
2722 size = len / oAdvance;
2724 ipos = dsb->buf_mixpos;
2725 for (i = 0; i < size; i++) {
2726 get_fields(dsb, (dsb->buffer + ipos), &fieldL, &fieldR);
2727 set_fields(obp, fieldL, fieldR);
2730 dsb->freqAcc += dsb->freqAdjust;
2731 if (dsb->freqAcc >= (1<<DSOUND_FREQSHIFT)) {
2732 ULONG adv = (dsb->freqAcc>>DSOUND_FREQSHIFT) * iAdvance;
2733 dsb->freqAcc &= (1<<DSOUND_FREQSHIFT)-1;
2734 ipos += adv; ilen += adv;
2735 while (ipos >= dsb->buflen)
2736 ipos -= dsb->buflen;
2742 static void DSOUND_MixerVol(IDirectSoundBufferImpl *dsb, BYTE *buf, INT len)
2744 INT i, inc = primarybuf->wfx.wBitsPerSample >> 3;
2746 INT16 *bps = (INT16 *) buf;
2748 TRACE("(%p) left = %lx, right = %lx\n", dsb,
2749 dsb->volpan.dwTotalLeftAmpFactor, dsb->volpan.dwTotalRightAmpFactor);
2750 if ((!(dsb->dsbd.dwFlags & DSBCAPS_CTRLPAN) || (dsb->volpan.lPan == 0)) &&
2751 (!(dsb->dsbd.dwFlags & DSBCAPS_CTRLVOLUME) || (dsb->volpan.lVolume == 0)) &&
2752 !(dsb->dsbd.dwFlags & DSBCAPS_CTRL3D))
2753 return; /* Nothing to do */
2755 /* If we end up with some bozo coder using panning or 3D sound */
2756 /* with a mono primary buffer, it could sound very weird using */
2757 /* this method. Oh well, tough patooties. */
2759 for (i = 0; i < len; i += inc) {
2765 /* 8-bit WAV is unsigned, but we need to operate */
2766 /* on signed data for this to work properly */
2768 val = ((val * (i & inc ? dsb->volpan.dwTotalRightAmpFactor : dsb->volpan.dwTotalLeftAmpFactor)) >> 16);
2773 /* 16-bit WAV is signed -- much better */
2775 val = ((val * ((i & inc) ? dsb->volpan.dwTotalRightAmpFactor : dsb->volpan.dwTotalLeftAmpFactor)) >> 16);
2781 FIXME("MixerVol had a nasty error\n");
2787 static void DSOUND_Mixer3D(IDirectSoundBufferImpl *dsb, BYTE *buf, INT len)
2790 DWORD buflen, buf_mixpos;
2792 buflen = dsb->ds3db->buflen;
2793 buf_mixpos = (dsb->buf_mixpos * primarybuf->wfx.nBlockAlign) / dsb->wfx.nBlockAlign;
2794 ibp = dsb->ds3db->buffer + buf_mixpos;
2797 if (buf_mixpos > buflen) {
2798 FIXME("Major breakage\n");
2802 if (len <= (buf_mixpos + buflen))
2803 memcpy(obp, ibp, len);
2805 memcpy(obp, ibp, buflen - buf_mixpos);
2806 memcpy(obp + (buflen - buf_mixpos),
2808 len - (buflen - buf_mixpos));
2814 static void *tmp_buffer;
2815 static size_t tmp_buffer_len = 0;
2817 static void *DSOUND_tmpbuffer(size_t len)
2819 if (len>tmp_buffer_len) {
2820 void *new_buffer = realloc(tmp_buffer, len);
2822 tmp_buffer = new_buffer;
2823 tmp_buffer_len = len;
2830 static DWORD DSOUND_MixInBuffer(IDirectSoundBufferImpl *dsb, DWORD writepos, DWORD fraglen)
2832 INT i, len, ilen, temp, field;
2833 INT advance = primarybuf->wfx.wBitsPerSample >> 3;
2834 BYTE *buf, *ibuf, *obuf;
2835 INT16 *ibufs, *obufs;
2838 if (!(dsb->playflags & DSBPLAY_LOOPING)) {
2839 temp = MulDiv(primarybuf->wfx.nAvgBytesPerSec, dsb->buflen,
2840 dsb->nAvgBytesPerSec) -
2841 MulDiv(primarybuf->wfx.nAvgBytesPerSec, dsb->buf_mixpos,
2842 dsb->nAvgBytesPerSec);
2843 len = (len > temp) ? temp : len;
2845 len &= ~3; /* 4 byte alignment */
2848 /* This should only happen if we aren't looping and temp < 4 */
2850 /* We skip the remainder, so check for possible events */
2851 DSOUND_CheckEvent(dsb, dsb->buflen - dsb->buf_mixpos);
2853 dsb->state = STATE_STOPPED;
2855 dsb->buf_mixpos = 0;
2856 dsb->leadin = FALSE;
2857 /* Check for DSBPN_OFFSETSTOP */
2858 DSOUND_CheckEvent(dsb, 0);
2862 /* Been seeing segfaults in malloc() for some reason... */
2863 TRACE("allocating buffer (size = %d)\n", len);
2864 if ((buf = ibuf = (BYTE *) DSOUND_tmpbuffer(len)) == NULL)
2867 TRACE("MixInBuffer (%p) len = %d, dest = %ld\n", dsb, len, writepos);
2869 ilen = DSOUND_MixerNorm(dsb, ibuf, len);
2870 if ((dsb->dsbd.dwFlags & DSBCAPS_CTRLPAN) ||
2871 (dsb->dsbd.dwFlags & DSBCAPS_CTRLVOLUME))
2872 DSOUND_MixerVol(dsb, ibuf, len);
2874 obuf = primarybuf->buffer + writepos;
2875 for (i = 0; i < len; i += advance) {
2876 obufs = (INT16 *) obuf;
2877 ibufs = (INT16 *) ibuf;
2878 if (primarybuf->wfx.wBitsPerSample == 8) {
2879 /* 8-bit WAV is unsigned */
2880 field = (*ibuf - 128);
2881 field += (*obuf - 128);
2882 field = field > 127 ? 127 : field;
2883 field = field < -128 ? -128 : field;
2884 *obuf = field + 128;
2886 /* 16-bit WAV is signed */
2889 field = field > 32767 ? 32767 : field;
2890 field = field < -32768 ? -32768 : field;
2895 if (obuf >= (BYTE *)(primarybuf->buffer + primarybuf->buflen))
2896 obuf = primarybuf->buffer;
2900 if (dsb->dsbd.dwFlags & DSBCAPS_CTRLPOSITIONNOTIFY)
2901 DSOUND_CheckEvent(dsb, ilen);
2903 if (dsb->leadin && (dsb->startpos > dsb->buf_mixpos) && (dsb->startpos <= dsb->buf_mixpos + ilen)) {
2904 /* HACK... leadin should be reset when the PLAY position reaches the startpos,
2905 * not the MIX position... but if the sound buffer is bigger than our prebuffering
2906 * (which must be the case for the streaming buffers that need this hack anyway)
2907 * plus DS_HEL_MARGIN or equivalent, then this ought to work anyway. */
2908 dsb->leadin = FALSE;
2911 dsb->buf_mixpos += ilen;
2913 if (dsb->buf_mixpos >= dsb->buflen) {
2914 if (!(dsb->playflags & DSBPLAY_LOOPING)) {
2915 dsb->state = STATE_STOPPED;
2917 dsb->buf_mixpos = 0;
2918 dsb->leadin = FALSE;
2919 DSOUND_CheckEvent(dsb, 0); /* For DSBPN_OFFSETSTOP */
2922 while (dsb->buf_mixpos >= dsb->buflen)
2923 dsb->buf_mixpos -= dsb->buflen;
2924 if (dsb->leadin && (dsb->startpos <= dsb->buf_mixpos))
2925 dsb->leadin = FALSE; /* HACK: see above */
2932 static void DSOUND_PhaseCancel(IDirectSoundBufferImpl *dsb, DWORD writepos, DWORD len)
2935 INT advance = primarybuf->wfx.wBitsPerSample >> 3;
2936 BYTE *buf, *ibuf, *obuf;
2937 INT16 *ibufs, *obufs;
2939 len &= ~3; /* 4 byte alignment */
2941 TRACE("allocating buffer (size = %ld)\n", len);
2942 if ((buf = ibuf = (BYTE *) DSOUND_tmpbuffer(len)) == NULL)
2945 TRACE("PhaseCancel (%p) len = %ld, dest = %ld\n", dsb, len, writepos);
2947 ilen = DSOUND_MixerNorm(dsb, ibuf, len);
2948 if ((dsb->dsbd.dwFlags & DSBCAPS_CTRLPAN) ||
2949 (dsb->dsbd.dwFlags & DSBCAPS_CTRLVOLUME))
2950 DSOUND_MixerVol(dsb, ibuf, len);
2952 /* subtract instead of add, to phase out premixed data */
2953 obuf = primarybuf->buffer + writepos;
2954 for (i = 0; i < len; i += advance) {
2955 obufs = (INT16 *) obuf;
2956 ibufs = (INT16 *) ibuf;
2957 if (primarybuf->wfx.wBitsPerSample == 8) {
2958 /* 8-bit WAV is unsigned */
2959 field = (*ibuf - 128);
2960 field -= (*obuf - 128);
2961 field = field > 127 ? 127 : field;
2962 field = field < -128 ? -128 : field;
2963 *obuf = field + 128;
2965 /* 16-bit WAV is signed */
2968 field = field > 32767 ? 32767 : field;
2969 field = field < -32768 ? -32768 : field;
2974 if (obuf >= (BYTE *)(primarybuf->buffer + primarybuf->buflen))
2975 obuf = primarybuf->buffer;
2980 static void DSOUND_MixCancel(IDirectSoundBufferImpl *dsb, DWORD writepos, BOOL cancel)
2982 DWORD size, flen, len, npos, nlen;
2983 INT iAdvance = dsb->wfx.nBlockAlign;
2984 INT oAdvance = primarybuf->wfx.nBlockAlign;
2985 /* determine amount of premixed data to cancel */
2986 DWORD primary_done =
2987 ((dsb->primary_mixpos < writepos) ? primarybuf->buflen : 0) +
2988 dsb->primary_mixpos - writepos;
2990 TRACE("(%p, %ld), buf_mixpos=%ld\n", dsb, writepos, dsb->buf_mixpos);
2992 /* backtrack the mix position */
2993 size = primary_done / oAdvance;
2994 flen = size * dsb->freqAdjust;
2995 len = (flen >> DSOUND_FREQSHIFT) * iAdvance;
2996 flen &= (1<<DSOUND_FREQSHIFT)-1;
2997 while (dsb->freqAcc < flen) {
2999 dsb->freqAcc += 1<<DSOUND_FREQSHIFT;
3002 npos = ((dsb->buf_mixpos < len) ? dsb->buflen : 0) +
3003 dsb->buf_mixpos - len;
3004 if (dsb->leadin && (dsb->startpos > npos) && (dsb->startpos <= npos + len)) {
3005 /* stop backtracking at startpos */
3006 npos = dsb->startpos;
3007 len = ((dsb->buf_mixpos < npos) ? dsb->buflen : 0) +
3008 dsb->buf_mixpos - npos;
3009 flen = dsb->freqAcc;
3010 nlen = len / dsb->wfx.nBlockAlign;
3011 nlen = ((nlen << DSOUND_FREQSHIFT) + flen) / dsb->freqAdjust;
3012 nlen *= primarybuf->wfx.nBlockAlign;
3014 ((dsb->primary_mixpos < nlen) ? primarybuf->buflen : 0) +
3015 dsb->primary_mixpos - nlen;
3018 dsb->freqAcc -= flen;
3019 dsb->buf_mixpos = npos;
3020 dsb->primary_mixpos = writepos;
3022 TRACE("new buf_mixpos=%ld, primary_mixpos=%ld (len=%ld)\n",
3023 dsb->buf_mixpos, dsb->primary_mixpos, len);
3025 if (cancel) DSOUND_PhaseCancel(dsb, writepos, len);
3028 static void DSOUND_MixCancelAt(IDirectSoundBufferImpl *dsb, DWORD buf_writepos)
3031 DWORD i, size, flen, len, npos, nlen;
3032 INT iAdvance = dsb->wfx.nBlockAlign;
3033 INT oAdvance = primarybuf->wfx.nBlockAlign;
3034 /* determine amount of premixed data to cancel */
3036 ((dsb->buf_mixpos < buf_writepos) ? dsb->buflen : 0) +
3037 dsb->buf_mixpos - buf_writepos;
3040 WARN("(%p, %ld), buf_mixpos=%ld\n", dsb, buf_writepos, dsb->buf_mixpos);
3041 /* since this is not implemented yet, just cancel *ALL* prebuffering for now
3042 * (which is faster anyway when there's one a single secondary buffer) */
3043 primarybuf->need_remix = TRUE;
3046 static DWORD DSOUND_MixOne(IDirectSoundBufferImpl *dsb, DWORD playpos, DWORD writepos, DWORD mixlen)
3049 /* determine this buffer's write position */
3050 DWORD buf_writepos = DSOUND_CalcPlayPosition(dsb, dsb->state & primarybuf->state, writepos,
3051 writepos, dsb->primary_mixpos, dsb->buf_mixpos);
3052 /* determine how much already-mixed data exists */
3054 ((dsb->buf_mixpos < buf_writepos) ? dsb->buflen : 0) +
3055 dsb->buf_mixpos - buf_writepos;
3056 DWORD primary_done =
3057 ((dsb->primary_mixpos < writepos) ? primarybuf->buflen : 0) +
3058 dsb->primary_mixpos - writepos;
3060 ((primarybuf->buf_mixpos < writepos) ? primarybuf->buflen : 0) +
3061 primarybuf->buf_mixpos - writepos;
3064 TRACE("buf_writepos=%ld, primary_writepos=%ld\n", buf_writepos, writepos);
3065 TRACE("buf_done=%ld, primary_done=%ld\n", buf_done, primary_done);
3066 TRACE("buf_mixpos=%ld, primary_mixpos=%ld, mixlen=%ld\n", dsb->buf_mixpos, dsb->primary_mixpos,
3068 TRACE("looping=%ld, startpos=%ld, leadin=%ld\n", dsb->playflags, dsb->startpos, dsb->leadin);
3070 /* save write position for non-GETCURRENTPOSITION2... */
3071 dsb->playpos = buf_writepos;
3073 /* check whether CalcPlayPosition detected a mixing underrun */
3074 if ((buf_done == 0) && (dsb->primary_mixpos != writepos)) {
3075 /* it did, but did we have more to play? */
3076 if ((dsb->playflags & DSBPLAY_LOOPING) ||
3077 (dsb->buf_mixpos < dsb->buflen)) {
3078 /* yes, have to recover */
3079 ERR("underrun on sound buffer %p\n", dsb);
3080 TRACE("recovering from underrun: primary_mixpos=%ld\n", writepos);
3082 dsb->primary_mixpos = writepos;
3085 /* determine how far ahead we should mix */
3086 if (((dsb->playflags & DSBPLAY_LOOPING) ||
3087 (dsb->leadin && (dsb->probably_valid_to != 0))) &&
3088 !(dsb->dsbd.dwFlags & DSBCAPS_STATIC)) {
3089 /* if this is a streaming buffer, it typically means that
3090 * we should defer mixing past probably_valid_to as long
3091 * as we can, to avoid unnecessary remixing */
3092 /* the heavy-looking calculations shouldn't be that bad,
3093 * as any game isn't likely to be have more than 1 or 2
3094 * streaming buffers in use at any time anyway... */
3095 DWORD probably_valid_left =
3096 (dsb->probably_valid_to == (DWORD)-1) ? dsb->buflen :
3097 ((dsb->probably_valid_to < buf_writepos) ? dsb->buflen : 0) +
3098 dsb->probably_valid_to - buf_writepos;
3099 /* check for leadin condition */
3100 if ((probably_valid_left == 0) &&
3101 (dsb->probably_valid_to == dsb->startpos) &&
3103 probably_valid_left = dsb->buflen;
3104 TRACE("streaming buffer probably_valid_to=%ld, probably_valid_left=%ld\n",
3105 dsb->probably_valid_to, probably_valid_left);
3106 /* check whether the app's time is already up */
3107 if (probably_valid_left < dsb->writelead) {
3108 WARN("probably_valid_to now within writelead, possible streaming underrun\n");
3109 /* once we pass the point of no return,
3110 * no reason to hold back anymore */
3111 dsb->probably_valid_to = (DWORD)-1;
3112 /* we just have to go ahead and mix what we have,
3113 * there's no telling what the app is thinking anyway */
3115 /* adjust for our frequency and our sample size */
3116 probably_valid_left = MulDiv(probably_valid_left,
3117 1 << DSOUND_FREQSHIFT,
3118 dsb->wfx.nBlockAlign * dsb->freqAdjust) *
3119 primarybuf->wfx.nBlockAlign;
3120 /* check whether to clip mix_len */
3121 if (probably_valid_left < mixlen) {
3122 TRACE("clipping to probably_valid_left=%ld\n", probably_valid_left);
3123 mixlen = probably_valid_left;
3127 /* cut mixlen with what's already been mixed */
3128 if (mixlen < primary_done) {
3129 /* huh? and still CalcPlayPosition didn't
3130 * detect an underrun? */
3131 FIXME("problem with underrun detection (mixlen=%ld < primary_done=%ld)\n", mixlen, primary_done);
3134 len = mixlen - primary_done;
3135 TRACE("remaining mixlen=%ld\n", len);
3137 if (len < primarybuf->dsound->fraglen) {
3138 /* smaller than a fragment, wait until it gets larger
3139 * before we take the mixing overhead */
3140 TRACE("mixlen not worth it, deferring mixing\n");
3144 /* ok, we know how much to mix, let's go */
3145 still_behind = (adv_done > primary_done);
3147 slen = primarybuf->buflen - dsb->primary_mixpos;
3148 if (slen > len) slen = len;
3149 slen = DSOUND_MixInBuffer(dsb, dsb->primary_mixpos, slen);
3151 if ((dsb->primary_mixpos < primarybuf->buf_mixpos) &&
3152 (dsb->primary_mixpos + slen >= primarybuf->buf_mixpos))
3153 still_behind = FALSE;
3155 dsb->primary_mixpos += slen; len -= slen;
3156 while (dsb->primary_mixpos >= primarybuf->buflen)
3157 dsb->primary_mixpos -= primarybuf->buflen;
3159 if ((dsb->state == STATE_STOPPED) || !slen) break;
3161 TRACE("new primary_mixpos=%ld, primary_advbase=%ld\n", dsb->primary_mixpos, primarybuf->buf_mixpos);
3162 TRACE("mixed data len=%ld, still_behind=%d\n", mixlen-len, still_behind);
3163 /* return how far we think the primary buffer can
3164 * advance its underrun detector...*/
3165 if (still_behind) return 0;
3166 if ((mixlen - len) < primary_done) return 0;
3167 slen = ((dsb->primary_mixpos < primarybuf->buf_mixpos) ?
3168 primarybuf->buflen : 0) + dsb->primary_mixpos -
3169 primarybuf->buf_mixpos;
3170 if (slen > mixlen) {
3171 /* the primary_done and still_behind checks above should have worked */
3172 FIXME("problem with advancement calculation (advlen=%ld > mixlen=%ld)\n", slen, mixlen);
3178 static DWORD DSOUND_MixToPrimary(DWORD playpos, DWORD writepos, DWORD mixlen, BOOL recover)
3180 INT i, len, maxlen = 0;
3181 IDirectSoundBufferImpl *dsb;
3183 TRACE("(%ld,%ld,%ld)\n", playpos, writepos, mixlen);
3184 for (i = dsound->nrofbuffers - 1; i >= 0; i--) {
3185 dsb = dsound->buffers[i];
3187 if (!dsb || !(ICOM_VTBL(dsb)))
3189 if (dsb->buflen && dsb->state && !dsb->hwbuf) {
3190 TRACE("Checking %p, mixlen=%ld\n", dsb, mixlen);
3191 EnterCriticalSection(&(dsb->lock));
3192 if (dsb->state == STATE_STOPPING) {
3193 DSOUND_MixCancel(dsb, writepos, TRUE);
3194 dsb->state = STATE_STOPPED;
3196 if ((dsb->state == STATE_STARTING) || recover)
3197 dsb->primary_mixpos = writepos;
3198 len = DSOUND_MixOne(dsb, playpos, writepos, mixlen);
3199 if (dsb->state == STATE_STARTING)
3200 dsb->state = STATE_PLAYING;
3201 maxlen = (len > maxlen) ? len : maxlen;
3203 LeaveCriticalSection(&(dsb->lock));
3210 static void DSOUND_MixReset(DWORD writepos)
3213 IDirectSoundBufferImpl *dsb;
3216 TRACE("(%ld)\n", writepos);
3218 /* the sound of silence */
3219 nfiller = primarybuf->wfx.wBitsPerSample == 8 ? 128 : 0;
3221 /* reset all buffer mix positions */
3222 for (i = dsound->nrofbuffers - 1; i >= 0; i--) {
3223 dsb = dsound->buffers[i];
3225 if (!dsb || !(ICOM_VTBL(dsb)))
3227 if (dsb->buflen && dsb->state && !dsb->hwbuf) {
3228 TRACE("Resetting %p\n", dsb);
3229 EnterCriticalSection(&(dsb->lock));
3230 if (dsb->state == STATE_STOPPING) {
3231 dsb->state = STATE_STOPPED;
3233 else if (dsb->state == STATE_STARTING) {
3236 DSOUND_MixCancel(dsb, writepos, FALSE);
3238 LeaveCriticalSection(&(dsb->lock));
3242 /* wipe out premixed data */
3243 if (primarybuf->buf_mixpos < writepos) {
3244 memset(primarybuf->buffer + writepos, nfiller, primarybuf->buflen - writepos);
3245 memset(primarybuf->buffer, nfiller, primarybuf->buf_mixpos);
3247 memset(primarybuf->buffer + writepos, nfiller, primarybuf->buf_mixpos - writepos);
3250 /* reset primary mix position */
3251 primarybuf->buf_mixpos = writepos;
3254 static void DSOUND_CheckReset(IDirectSoundImpl *dsound, DWORD writepos)
3256 if (primarybuf->need_remix) {
3257 DSOUND_MixReset(writepos);
3258 primarybuf->need_remix = FALSE;
3259 /* maximize Half-Life performance */
3260 dsound->prebuf = DS_SND_QUEUE_MIN;
3262 /* if (dsound->prebuf < DS_SND_QUEUE_MAX) dsound->prebuf++; */
3264 TRACE("premix adjust: %d\n", dsound->prebuf);
3267 static void DSOUND_WaveQueue(IDirectSoundImpl *dsound, DWORD mixq)
3269 if (mixq + dsound->pwqueue > DS_HEL_QUEUE) mixq = DS_HEL_QUEUE - dsound->pwqueue;
3270 TRACE("queueing %ld buffers, starting at %d\n", mixq, dsound->pwwrite);
3271 for (; mixq; mixq--) {
3272 waveOutWrite(dsound->hwo, dsound->pwave[dsound->pwwrite], sizeof(WAVEHDR));
3274 if (dsound->pwwrite >= DS_HEL_FRAGS) dsound->pwwrite = 0;
3279 /* #define SYNC_CALLBACK */
3281 static void DSOUND_PerformMix(void)
3287 EnterCriticalSection(&(dsound->lock));
3289 if (!primarybuf || !primarybuf->ref) {
3290 /* seems the primary buffer is currently being released */
3291 LeaveCriticalSection(&(dsound->lock));
3295 /* the sound of silence */
3296 nfiller = primarybuf->wfx.wBitsPerSample == 8 ? 128 : 0;
3298 /* whether the primary is forced to play even without secondary buffers */
3299 forced = ((primarybuf->state == STATE_PLAYING) || (primarybuf->state == STATE_STARTING));
3301 TRACE("entering at %ld\n", GetTickCount());
3302 if (dsound->priolevel != DSSCL_WRITEPRIMARY) {
3303 BOOL paused = ((primarybuf->state == STATE_STOPPED) || (primarybuf->state == STATE_STARTING));
3304 /* FIXME: document variables */
3305 DWORD playpos, writepos, inq, maxq, frag;
3306 if (primarybuf->hwbuf) {
3307 hres = IDsDriverBuffer_GetPosition(primarybuf->hwbuf, &playpos, &writepos);
3309 LeaveCriticalSection(&(dsound->lock));
3312 /* Well, we *could* do Just-In-Time mixing using the writepos,
3313 * but that's a little bit ambitious and unnecessary... */
3314 /* rather add our safety margin to the writepos, if we're playing */
3316 writepos += primarybuf->writelead;
3317 while (writepos >= primarybuf->buflen)
3318 writepos -= primarybuf->buflen;
3319 } else writepos = playpos;
3322 playpos = dsound->pwplay * dsound->fraglen;
3325 writepos += DS_HEL_MARGIN * dsound->fraglen;
3326 while (writepos >= primarybuf->buflen)
3327 writepos -= primarybuf->buflen;
3330 TRACE("primary playpos=%ld, writepos=%ld, clrpos=%ld, mixpos=%ld\n",
3331 playpos,writepos,primarybuf->playpos,primarybuf->buf_mixpos);
3332 /* wipe out just-played sound data */
3333 if (playpos < primarybuf->playpos) {
3334 memset(primarybuf->buffer + primarybuf->playpos, nfiller, primarybuf->buflen - primarybuf->playpos);
3335 memset(primarybuf->buffer, nfiller, playpos);
3337 memset(primarybuf->buffer + primarybuf->playpos, nfiller, playpos - primarybuf->playpos);
3339 primarybuf->playpos = playpos;
3341 EnterCriticalSection(&(primarybuf->lock));
3343 /* reset mixing if necessary */
3344 DSOUND_CheckReset(dsound, writepos);
3346 /* check how much prebuffering is left */
3347 inq = primarybuf->buf_mixpos;
3349 inq += primarybuf->buflen;
3352 /* find the maximum we can prebuffer */
3355 if (maxq < writepos)
3356 maxq += primarybuf->buflen;
3358 } else maxq = primarybuf->buflen;
3360 /* clip maxq to dsound->prebuf */
3361 frag = dsound->prebuf * dsound->fraglen;
3362 if (maxq > frag) maxq = frag;
3364 /* check for consistency */
3366 /* the playback position must have passed our last
3367 * mixed position, i.e. it's an underrun, or we have
3368 * nothing more to play */
3369 TRACE("reached end of mixed data (inq=%ld, maxq=%ld)\n", inq, maxq);
3371 /* stop the playback now, to allow buffers to refill */
3372 if (primarybuf->state == STATE_PLAYING) {
3373 primarybuf->state = STATE_STARTING;
3375 else if (primarybuf->state == STATE_STOPPING) {
3376 primarybuf->state = STATE_STOPPED;
3379 /* how can we have an underrun if we aren't playing? */
3380 WARN("unexpected primary state (%ld)\n", primarybuf->state);
3382 #ifdef SYNC_CALLBACK
3383 /* DSOUND_callback may need this lock */
3384 LeaveCriticalSection(&(primarybuf->lock));
3386 DSOUND_PrimaryStop(primarybuf);
3387 #ifdef SYNC_CALLBACK
3388 EnterCriticalSection(&(primarybuf->lock));
3390 if (primarybuf->hwbuf) {
3391 /* the Stop is supposed to reset play position to beginning of buffer */
3392 /* unfortunately, OSS is not able to do so, so get current pointer */
3393 hres = IDsDriverBuffer_GetPosition(primarybuf->hwbuf, &playpos, NULL);
3395 LeaveCriticalSection(&(dsound->lock));
3396 LeaveCriticalSection(&(primarybuf->lock));
3400 playpos = dsound->pwplay * dsound->fraglen;
3403 primarybuf->playpos = playpos;
3404 primarybuf->buf_mixpos = writepos;
3406 maxq = primarybuf->buflen;
3407 if (maxq > frag) maxq = frag;
3408 memset(primarybuf->buffer, nfiller, primarybuf->buflen);
3413 frag = DSOUND_MixToPrimary(playpos, writepos, maxq, paused);
3414 if (forced) frag = maxq - inq;
3415 primarybuf->buf_mixpos += frag;
3416 while (primarybuf->buf_mixpos >= primarybuf->buflen)
3417 primarybuf->buf_mixpos -= primarybuf->buflen;
3420 /* buffers have been filled, restart playback */
3421 if (primarybuf->state == STATE_STARTING) {
3422 primarybuf->state = STATE_PLAYING;
3424 else if (primarybuf->state == STATE_STOPPED) {
3425 /* the primarybuf is supposed to play if there's something to play
3426 * even if it is reported as stopped, so don't let this confuse you */
3427 primarybuf->state = STATE_STOPPING;
3429 LeaveCriticalSection(&(primarybuf->lock));
3431 DSOUND_PrimaryPlay(primarybuf);
3432 TRACE("starting playback\n");
3436 LeaveCriticalSection(&(primarybuf->lock));
3438 /* in the DSSCL_WRITEPRIMARY mode, the app is totally in charge... */
3439 if (primarybuf->state == STATE_STARTING) {
3440 DSOUND_PrimaryPlay(primarybuf);
3441 primarybuf->state = STATE_PLAYING;
3443 else if (primarybuf->state == STATE_STOPPING) {
3444 DSOUND_PrimaryStop(primarybuf);
3445 primarybuf->state = STATE_STOPPED;
3448 TRACE("completed processing at %ld\n", GetTickCount());
3449 LeaveCriticalSection(&(dsound->lock));
3452 static void CALLBACK DSOUND_timer(UINT timerID, UINT msg, DWORD dwUser, DWORD dw1, DWORD dw2)
3454 if (!dsound || !primarybuf) {
3455 ERR("dsound died without killing us?\n");
3456 timeKillEvent(timerID);
3457 timeEndPeriod(DS_TIME_RES);
3462 DSOUND_PerformMix();
3465 static void CALLBACK DSOUND_callback(HWAVEOUT hwo, UINT msg, DWORD dwUser, DWORD dw1, DWORD dw2)
3467 IDirectSoundImpl* This = (IDirectSoundImpl*)dwUser;
3468 TRACE("entering at %ld, msg=%08x\n", GetTickCount(), msg);
3469 if (msg == MM_WOM_DONE) {
3470 DWORD inq, mixq, fraglen, buflen, pwplay, playpos, mixpos;
3471 if (This->pwqueue == (DWORD)-1) {
3472 TRACE("completed due to reset\n");
3475 /* it could be a bad idea to enter critical section here... if there's lock contention,
3476 * the resulting scheduling delays might obstruct the winmm player thread */
3477 #ifdef SYNC_CALLBACK
3478 EnterCriticalSection(&(primarybuf->lock));
3480 /* retrieve current values */
3481 fraglen = dsound->fraglen;
3482 buflen = primarybuf->buflen;
3483 pwplay = dsound->pwplay;
3484 playpos = pwplay * fraglen;
3485 mixpos = primarybuf->buf_mixpos;
3486 /* check remaining mixed data */
3487 inq = ((mixpos < playpos) ? buflen : 0) + mixpos - playpos;
3488 mixq = inq / fraglen;
3489 if ((inq - (mixq * fraglen)) > 0) mixq++;
3490 /* complete the playing buffer */
3491 TRACE("done playing primary pos=%ld\n", playpos);
3493 if (pwplay >= DS_HEL_FRAGS) pwplay = 0;
3494 /* write new values */
3495 dsound->pwplay = pwplay;
3497 /* queue new buffer if we have data for it */
3498 if (inq>1) DSOUND_WaveQueue(This, inq-1);
3499 #ifdef SYNC_CALLBACK
3500 LeaveCriticalSection(&(primarybuf->lock));
3503 TRACE("completed\n");
3506 /*******************************************************************************
3507 * DirectSoundCreate (DSOUND.1)
3509 HRESULT WINAPI DirectSoundCreate(REFGUID lpGUID,LPDIRECTSOUND *ppDS,IUnknown *pUnkOuter )
3511 IDirectSoundImpl** ippDS=(IDirectSoundImpl**)ppDS;
3512 PIDSDRIVER drv = NULL;
3515 HRESULT err = DS_OK;
3518 TRACE("(%p,%p,%p)\n",lpGUID,ippDS,pUnkOuter);
3520 TRACE("DirectSoundCreate (%p)\n", ippDS);
3523 return DSERR_INVALIDPARAM;
3526 IDirectSound_AddRef((LPDIRECTSOUND)dsound);
3531 /* Enumerate WINMM audio devices and find the one we want */
3532 wodn = waveOutGetNumDevs();
3533 if (!wodn) return DSERR_NODRIVER;
3535 /* FIXME: How do we find the GUID of an audio device? */
3536 wod = 0; /* start at the first audio device */
3538 /* Get output device caps */
3539 waveOutGetDevCapsA(wod, &wcaps, sizeof(wcaps));
3540 /* DRV_QUERYDSOUNDIFACE is a "Wine extension" to get the DSound interface */
3541 waveOutMessage(wod, DRV_QUERYDSOUNDIFACE, (DWORD)&drv, 0);
3543 /* Allocate memory */
3544 *ippDS = (IDirectSoundImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundImpl));
3546 return DSERR_OUTOFMEMORY;
3548 ICOM_VTBL(*ippDS) = &dsvt;
3551 (*ippDS)->driver = drv;
3552 (*ippDS)->fraglen = 0;
3553 (*ippDS)->priolevel = DSSCL_NORMAL;
3554 (*ippDS)->nrofbuffers = 0;
3555 (*ippDS)->buffers = NULL;
3556 (*ippDS)->primary = NULL;
3557 (*ippDS)->listener = NULL;
3559 (*ippDS)->prebuf = DS_SND_QUEUE_MAX;
3561 /* Get driver description */
3563 IDsDriver_GetDriverDesc(drv,&((*ippDS)->drvdesc));
3565 /* if no DirectSound interface available, use WINMM API instead */
3566 (*ippDS)->drvdesc.dwFlags = DSDDESC_DOMMSYSTEMOPEN | DSDDESC_DOMMSYSTEMSETFORMAT;
3567 (*ippDS)->drvdesc.dnDevNode = wod; /* FIXME? */
3570 /* Set default wave format (may need it for waveOutOpen) */
3571 (*ippDS)->wfx.wFormatTag = WAVE_FORMAT_PCM;
3572 (*ippDS)->wfx.nChannels = 2;
3573 (*ippDS)->wfx.nSamplesPerSec = 22050;
3574 (*ippDS)->wfx.nAvgBytesPerSec = 44100;
3575 (*ippDS)->wfx.nBlockAlign = 2;
3576 (*ippDS)->wfx.wBitsPerSample = 8;
3578 /* If the driver requests being opened through MMSYSTEM
3579 * (which is recommended by the DDK), it is supposed to happen
3580 * before the DirectSound interface is opened */
3581 if ((*ippDS)->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN)
3583 /* FIXME: is this right? */
3585 (*ippDS)->drvdesc.dnDevNode = 0;
3586 err = DSERR_ALLOCATED;
3588 /* if this device is busy try the next one */
3589 while((err == DSERR_ALLOCATED) &&
3590 ((*ippDS)->drvdesc.dnDevNode < wodn))
3592 err = mmErr(waveOutOpen(&((*ippDS)->hwo),
3593 (*ippDS)->drvdesc.dnDevNode, &((*ippDS)->wfx),
3594 (DWORD)DSOUND_callback, (DWORD)(*ippDS),
3595 CALLBACK_FUNCTION | WAVE_DIRECTSOUND));
3596 (*ippDS)->drvdesc.dnDevNode++; /* next wave device */
3599 (*ippDS)->drvdesc.dnDevNode--; /* take away last increment */
3603 if (drv && (err == DS_OK))
3604 err = IDsDriver_Open(drv);
3606 /* FIXME: do we want to handle a temporarily busy device? */
3608 HeapFree(GetProcessHeap(),0,*ippDS);
3613 /* the driver is now open, so it's now allowed to call GetCaps */
3615 IDsDriver_GetCaps(drv,&((*ippDS)->drvcaps));
3619 /* FIXME: look at wcaps */
3620 (*ippDS)->drvcaps.dwFlags =
3621 DSCAPS_PRIMARY16BIT | DSCAPS_PRIMARYSTEREO;
3623 (*ippDS)->drvcaps.dwFlags |= DSCAPS_EMULDRIVER;
3625 /* Allocate memory for HEL buffer headers */
3626 for (c=0; c<DS_HEL_FRAGS; c++) {
3627 (*ippDS)->pwave[c] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(WAVEHDR));
3628 if (!(*ippDS)->pwave[c]) {
3629 /* Argh, out of memory */
3631 HeapFree(GetProcessHeap(),0,(*ippDS)->pwave[c]);
3632 waveOutClose((*ippDS)->hwo);
3633 HeapFree(GetProcessHeap(),0,*ippDS);
3635 return DSERR_OUTOFMEMORY;
3641 InitializeCriticalSection(&((*ippDS)->lock));
3645 if (primarybuf == NULL) {
3649 dsbd.dwSize = sizeof(DSBUFFERDESC);
3650 dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;
3651 dsbd.dwBufferBytes = 0;
3652 dsbd.lpwfxFormat = &(dsound->wfx);
3653 hr = IDirectSound_CreateSoundBuffer(*ppDS, &dsbd, (LPDIRECTSOUNDBUFFER*)&primarybuf, NULL);
3657 /* dsound->primary is NULL - don't need to Release */
3658 dsound->primary = primarybuf;
3659 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)primarybuf);
3661 timeBeginPeriod(DS_TIME_RES);
3662 dsound->timerID = timeSetEvent(DS_TIME_DEL, DS_TIME_RES, DSOUND_timer,
3663 (DWORD)dsound, TIME_PERIODIC | TIME_CALLBACK_FUNCTION);
3668 /***************************************************************************
3669 * DirectSoundCaptureCreate [DSOUND.6]
3671 * Create and initialize a DirectSoundCapture interface
3675 * Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
3678 HRESULT WINAPI DirectSoundCaptureCreate(
3680 LPDIRECTSOUNDCAPTURE* lplpDSC,
3681 LPUNKNOWN pUnkOuter )
3683 TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), lplpDSC, pUnkOuter);
3686 return DSERR_NOAGGREGATION;
3689 /* Default device? */
3691 return DSOUND_CreateDirectSoundCapture( (LPVOID*)lplpDSC );
3694 FIXME( "Unknown GUID %s\n", debugstr_guid(lpcGUID) );
3697 return DSERR_OUTOFMEMORY;
3700 /***************************************************************************
3701 * DirectSoundCaptureEnumerateA [DSOUND.7]
3703 * Enumerate all DirectSound drivers installed in the system
3707 * Failure: DSERR_INVALIDPARAM
3709 HRESULT WINAPI DirectSoundCaptureEnumerateA(
3710 LPDSENUMCALLBACKA lpDSEnumCallback,
3713 TRACE("(%p,%p)\n", lpDSEnumCallback, lpContext );
3715 if ( lpDSEnumCallback )
3716 lpDSEnumCallback(NULL,"WINE Primary Sound Capture Driver",
3717 "SoundCap",lpContext);
3723 /***************************************************************************
3724 * DirectSoundCaptureEnumerateW [DSOUND.8]
3726 * Enumerate all DirectSound drivers installed in the system
3730 * Failure: DSERR_INVALIDPARAM
3732 HRESULT WINAPI DirectSoundCaptureEnumerateW(
3733 LPDSENUMCALLBACKW lpDSEnumCallback,
3736 FIXME("(%p,%p):stub\n", lpDSEnumCallback, lpContext );
3741 DSOUND_CreateDirectSoundCapture( LPVOID* ppobj )
3743 *ppobj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( IDirectSoundCaptureImpl ) );
3745 if ( *ppobj == NULL ) {
3746 return DSERR_OUTOFMEMORY;
3750 ICOM_THIS(IDirectSoundCaptureImpl,*ppobj);
3753 ICOM_VTBL(This) = &dscvt;
3755 InitializeCriticalSection( &This->lock );
3761 static HRESULT WINAPI
3762 IDirectSoundCaptureImpl_QueryInterface(
3763 LPDIRECTSOUNDCAPTURE iface,
3767 ICOM_THIS(IDirectSoundCaptureImpl,iface);
3769 FIXME( "(%p)->(%s,%p): stub\n", This, debugstr_guid(riid), ppobj );
3775 IDirectSoundCaptureImpl_AddRef( LPDIRECTSOUNDCAPTURE iface )
3778 ICOM_THIS(IDirectSoundCaptureImpl,iface);
3780 EnterCriticalSection( &This->lock );
3782 TRACE( "(%p) was 0x%08lx\n", This, This->ref );
3783 uRef = ++(This->ref);
3785 LeaveCriticalSection( &This->lock );
3791 IDirectSoundCaptureImpl_Release( LPDIRECTSOUNDCAPTURE iface )
3794 ICOM_THIS(IDirectSoundCaptureImpl,iface);
3796 EnterCriticalSection( &This->lock );
3798 TRACE( "(%p) was 0x%08lx\n", This, This->ref );
3799 uRef = --(This->ref);
3801 LeaveCriticalSection( &This->lock );
3804 DeleteCriticalSection( &This->lock );
3805 HeapFree( GetProcessHeap(), 0, This );
3811 static HRESULT WINAPI
3812 IDirectSoundCaptureImpl_CreateCaptureBuffer(
3813 LPDIRECTSOUNDCAPTURE iface,
3814 LPCDSCBUFFERDESC lpcDSCBufferDesc,
3815 LPDIRECTSOUNDCAPTUREBUFFER* lplpDSCaptureBuffer,
3819 ICOM_THIS(IDirectSoundCaptureImpl,iface);
3821 TRACE( "(%p)->(%p,%p,%p)\n", This, lpcDSCBufferDesc, lplpDSCaptureBuffer, pUnk );
3824 return DSERR_INVALIDPARAM;
3827 hr = DSOUND_CreateDirectSoundCaptureBuffer( lpcDSCBufferDesc, (LPVOID*)lplpDSCaptureBuffer );
3832 static HRESULT WINAPI
3833 IDirectSoundCaptureImpl_GetCaps(
3834 LPDIRECTSOUNDCAPTURE iface,
3835 LPDSCCAPS lpDSCCaps )
3837 ICOM_THIS(IDirectSoundCaptureImpl,iface);
3839 FIXME( "(%p)->(%p): stub\n", This, lpDSCCaps );
3844 static HRESULT WINAPI
3845 IDirectSoundCaptureImpl_Initialize(
3846 LPDIRECTSOUNDCAPTURE iface,
3849 ICOM_THIS(IDirectSoundCaptureImpl,iface);
3851 FIXME( "(%p)->(%p): stub\n", This, lpcGUID );
3857 static ICOM_VTABLE(IDirectSoundCapture) dscvt =
3859 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
3860 /* IUnknown methods */
3861 IDirectSoundCaptureImpl_QueryInterface,
3862 IDirectSoundCaptureImpl_AddRef,
3863 IDirectSoundCaptureImpl_Release,
3865 /* IDirectSoundCapture methods */
3866 IDirectSoundCaptureImpl_CreateCaptureBuffer,
3867 IDirectSoundCaptureImpl_GetCaps,
3868 IDirectSoundCaptureImpl_Initialize
3872 DSOUND_CreateDirectSoundCaptureBuffer( LPCDSCBUFFERDESC lpcDSCBufferDesc, LPVOID* ppobj )
3875 FIXME( "(%p,%p): ignoring lpcDSCBufferDesc\n", lpcDSCBufferDesc, ppobj );
3877 *ppobj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( IDirectSoundCaptureBufferImpl ) );
3879 if ( *ppobj == NULL ) {
3880 return DSERR_OUTOFMEMORY;
3884 ICOM_THIS(IDirectSoundCaptureBufferImpl,*ppobj);
3887 ICOM_VTBL(This) = &dscbvt;
3889 InitializeCriticalSection( &This->lock );
3896 static HRESULT WINAPI
3897 IDirectSoundCaptureBufferImpl_QueryInterface(
3898 LPDIRECTSOUNDCAPTUREBUFFER iface,
3902 ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
3904 FIXME( "(%p)->(%s,%p): stub\n", This, debugstr_guid(riid), ppobj );
3910 IDirectSoundCaptureBufferImpl_AddRef( LPDIRECTSOUNDCAPTUREBUFFER iface )
3913 ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
3915 EnterCriticalSection( &This->lock );
3917 TRACE( "(%p) was 0x%08lx\n", This, This->ref );
3918 uRef = ++(This->ref);
3920 LeaveCriticalSection( &This->lock );
3926 IDirectSoundCaptureBufferImpl_Release( LPDIRECTSOUNDCAPTUREBUFFER iface )
3929 ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
3931 EnterCriticalSection( &This->lock );
3933 TRACE( "(%p) was 0x%08lx\n", This, This->ref );
3934 uRef = --(This->ref);
3936 LeaveCriticalSection( &This->lock );
3939 DeleteCriticalSection( &This->lock );
3940 HeapFree( GetProcessHeap(), 0, This );
3946 static HRESULT WINAPI
3947 IDirectSoundCaptureBufferImpl_GetCaps(
3948 LPDIRECTSOUNDCAPTUREBUFFER iface,
3949 LPDSCBCAPS lpDSCBCaps )
3951 ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
3953 FIXME( "(%p)->(%p): stub\n", This, lpDSCBCaps );
3958 static HRESULT WINAPI
3959 IDirectSoundCaptureBufferImpl_GetCurrentPosition(
3960 LPDIRECTSOUNDCAPTUREBUFFER iface,
3961 LPDWORD lpdwCapturePosition,
3962 LPDWORD lpdwReadPosition )
3964 ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
3966 FIXME( "(%p)->(%p,%p): stub\n", This, lpdwCapturePosition, lpdwReadPosition );
3971 static HRESULT WINAPI
3972 IDirectSoundCaptureBufferImpl_GetFormat(
3973 LPDIRECTSOUNDCAPTUREBUFFER iface,
3974 LPWAVEFORMATEX lpwfxFormat,
3975 DWORD dwSizeAllocated,
3976 LPDWORD lpdwSizeWritten )
3978 ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
3980 FIXME( "(%p)->(%p,0x%08lx,%p): stub\n", This, lpwfxFormat, dwSizeAllocated, lpdwSizeWritten );
3985 static HRESULT WINAPI
3986 IDirectSoundCaptureBufferImpl_GetStatus(
3987 LPDIRECTSOUNDCAPTUREBUFFER iface,
3988 LPDWORD lpdwStatus )
3990 ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
3992 FIXME( "(%p)->(%p): stub\n", This, lpdwStatus );
3997 static HRESULT WINAPI
3998 IDirectSoundCaptureBufferImpl_Initialize(
3999 LPDIRECTSOUNDCAPTUREBUFFER iface,
4000 LPDIRECTSOUNDCAPTURE lpDSC,
4001 LPCDSCBUFFERDESC lpcDSCBDesc )
4003 ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
4005 FIXME( "(%p)->(%p,%p): stub\n", This, lpDSC, lpcDSCBDesc );
4010 static HRESULT WINAPI
4011 IDirectSoundCaptureBufferImpl_Lock(
4012 LPDIRECTSOUNDCAPTUREBUFFER iface,
4015 LPVOID* lplpvAudioPtr1,
4016 LPDWORD lpdwAudioBytes1,
4017 LPVOID* lplpvAudioPtr2,
4018 LPDWORD lpdwAudioBytes2,
4021 ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
4023 FIXME( "(%p)->(%08lu,%08lu,%p,%p,%p,%p,0x%08lx): stub\n", This, dwReadCusor, dwReadBytes, lplpvAudioPtr1, lpdwAudioBytes1, lplpvAudioPtr2, lpdwAudioBytes2, dwFlags );
4028 static HRESULT WINAPI
4029 IDirectSoundCaptureBufferImpl_Start(
4030 LPDIRECTSOUNDCAPTUREBUFFER iface,
4033 ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
4035 FIXME( "(%p)->(0x%08lx): stub\n", This, dwFlags );
4040 static HRESULT WINAPI
4041 IDirectSoundCaptureBufferImpl_Stop( LPDIRECTSOUNDCAPTUREBUFFER iface )
4043 ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
4045 FIXME( "(%p): stub\n", This );
4050 static HRESULT WINAPI
4051 IDirectSoundCaptureBufferImpl_Unlock(
4052 LPDIRECTSOUNDCAPTUREBUFFER iface,
4053 LPVOID lpvAudioPtr1,
4054 DWORD dwAudioBytes1,
4055 LPVOID lpvAudioPtr2,
4056 DWORD dwAudioBytes2 )
4058 ICOM_THIS(IDirectSoundCaptureBufferImpl,iface);
4060 FIXME( "(%p)->(%p,%08lu,%p,%08lu): stub\n", This, lpvAudioPtr1, dwAudioBytes1, lpvAudioPtr2, dwAudioBytes2 );
4066 static ICOM_VTABLE(IDirectSoundCaptureBuffer) dscbvt =
4068 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
4069 /* IUnknown methods */
4070 IDirectSoundCaptureBufferImpl_QueryInterface,
4071 IDirectSoundCaptureBufferImpl_AddRef,
4072 IDirectSoundCaptureBufferImpl_Release,
4074 /* IDirectSoundCaptureBuffer methods */
4075 IDirectSoundCaptureBufferImpl_GetCaps,
4076 IDirectSoundCaptureBufferImpl_GetCurrentPosition,
4077 IDirectSoundCaptureBufferImpl_GetFormat,
4078 IDirectSoundCaptureBufferImpl_GetStatus,
4079 IDirectSoundCaptureBufferImpl_Initialize,
4080 IDirectSoundCaptureBufferImpl_Lock,
4081 IDirectSoundCaptureBufferImpl_Start,
4082 IDirectSoundCaptureBufferImpl_Stop,
4083 IDirectSoundCaptureBufferImpl_Unlock
4086 /*******************************************************************************
4087 * DirectSound ClassFactory
4091 /* IUnknown fields */
4092 ICOM_VFIELD(IClassFactory);
4094 } IClassFactoryImpl;
4096 static HRESULT WINAPI
4097 DSCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
4098 ICOM_THIS(IClassFactoryImpl,iface);
4100 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
4101 return E_NOINTERFACE;
4105 DSCF_AddRef(LPCLASSFACTORY iface) {
4106 ICOM_THIS(IClassFactoryImpl,iface);
4107 return ++(This->ref);
4110 static ULONG WINAPI DSCF_Release(LPCLASSFACTORY iface) {
4111 ICOM_THIS(IClassFactoryImpl,iface);
4112 /* static class, won't be freed */
4113 return --(This->ref);
4116 static HRESULT WINAPI DSCF_CreateInstance(
4117 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
4119 ICOM_THIS(IClassFactoryImpl,iface);
4121 TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
4122 if ( IsEqualGUID( &IID_IDirectSound, riid ) ) {
4123 /* FIXME: reuse already created dsound if present? */
4124 return DirectSoundCreate(riid,(LPDIRECTSOUND*)ppobj,pOuter);
4126 return E_NOINTERFACE;
4129 static HRESULT WINAPI DSCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
4130 ICOM_THIS(IClassFactoryImpl,iface);
4131 FIXME("(%p)->(%d),stub!\n",This,dolock);
4135 static ICOM_VTABLE(IClassFactory) DSCF_Vtbl = {
4136 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
4137 DSCF_QueryInterface,
4140 DSCF_CreateInstance,
4143 static IClassFactoryImpl DSOUND_CF = {&DSCF_Vtbl, 1 };
4145 /*******************************************************************************
4146 * DllGetClassObject [DSOUND.5]
4147 * Retrieves class object from a DLL object
4150 * Docs say returns STDAPI
4153 * rclsid [I] CLSID for the class object
4154 * riid [I] Reference to identifier of interface for class object
4155 * ppv [O] Address of variable to receive interface pointer for riid
4159 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
4162 DWORD WINAPI DSOUND_DllGetClassObject(REFCLSID rclsid,REFIID riid,LPVOID *ppv)
4164 TRACE("(%p,%p,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
4165 if ( IsEqualCLSID( &IID_IClassFactory, riid ) ) {
4166 *ppv = (LPVOID)&DSOUND_CF;
4167 IClassFactory_AddRef((IClassFactory*)*ppv);
4171 FIXME("(%p,%p,%p): no interface found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
4172 return CLASS_E_CLASSNOTAVAILABLE;
4176 /*******************************************************************************
4177 * DllCanUnloadNow [DSOUND.4] Determines whether the DLL is in use.
4183 DWORD WINAPI DSOUND_DllCanUnloadNow(void)
4185 FIXME("(void): stub\n");