3 * Copyright 1998 Marcus Meissner
4 * Copyright 1998 Rob Riggs
5 * Copyright 2000 Ove Kåven, TransGaming Technologies, Inc.
8 * Most thread locking is complete. There may be a few race
9 * conditions still lurking.
11 * Tested with a Soundblaster clone, a Gravis UltraSound Classic,
12 * and a Turtle Beach Tropez+.
15 * Implement DirectSoundCapture API
16 * Implement SetCooperativeLevel properly (need to address focus issues)
17 * Implement DirectSound3DBuffers (stubs in place)
18 * Use hardware 3D support if available
19 * Add critical section locking inside Release and AddRef methods
20 * Handle static buffers - put those in hardware, non-static not in hardware
21 * Hardware DuplicateSoundBuffer
22 * Proper volume calculation, and setting volume in HEL primary buffer
23 * Optimize WINMM and negotiate fragment size, decrease DS_HEL_MARGIN
29 #include <sys/types.h>
30 #include <sys/fcntl.h>
34 #include <math.h> /* Insomnia - pow() function */
41 #include "wine/windef16.h"
42 #include "debugtools.h"
48 DEFAULT_DEBUG_CHANNEL(dsound
);
50 /* these are eligible for tuning... they must be high on slow machines... */
51 /* especially since the WINMM overhead is pretty high, and could be improved quite a bit;
52 * the high DS_HEL_MARGIN reflects the currently high wineoss/HEL latency */
53 #define DS_HEL_FRAGS 48 /* HEL only: number of waveOut fragments in primary buffer */
54 #define DS_HEL_QUEUE 28 /* HEL only: number of waveOut fragments to prebuffer */
55 /* (Starcraft videos won't work with higher than 32 x10ms) */
56 #define DS_HEL_MARGIN 4 /* HEL only: number of waveOut fragments ahead to mix in new buffers */
58 #define DS_HAL_QUEUE 28 /* HAL only: max number of fragments to prebuffer */
60 /* Linux does not support better timing than 10ms */
61 #define DS_TIME_RES 10 /* Resolution of multimedia timer */
62 #define DS_TIME_DEL 10 /* Delay of multimedia timer callback, and duration of HEL fragment */
64 /*****************************************************************************
65 * Predeclare the interface implementation structures
67 typedef struct IDirectSoundImpl IDirectSoundImpl
;
68 typedef struct IDirectSoundBufferImpl IDirectSoundBufferImpl
;
69 typedef struct IDirectSoundNotifyImpl IDirectSoundNotifyImpl
;
70 typedef struct IDirectSound3DListenerImpl IDirectSound3DListenerImpl
;
71 typedef struct IDirectSound3DBufferImpl IDirectSound3DBufferImpl
;
72 typedef struct IDirectSoundCaptureImpl IDirectSoundCaptureImpl
;
73 typedef struct IDirectSoundCaptureBufferImpl IDirectSoundCaptureBufferImpl
;
75 /*****************************************************************************
76 * IDirectSound implementation structure
78 struct IDirectSoundImpl
81 ICOM_VFIELD(IDirectSound
);
83 /* IDirectSoundImpl fields */
88 LPWAVEHDR pwave
[DS_HEL_FRAGS
];
89 UINT timerID
, pwplay
, pwwrite
, pwqueue
;
93 IDirectSoundBufferImpl
** buffers
;
94 IDirectSoundBufferImpl
* primary
;
95 IDirectSound3DListenerImpl
* listener
;
96 WAVEFORMATEX wfx
; /* current main waveformat */
97 CRITICAL_SECTION lock
;
100 /*****************************************************************************
101 * IDirectSoundBuffer implementation structure
103 struct IDirectSoundBufferImpl
105 /* IUnknown fields */
106 ICOM_VFIELD(IDirectSoundBuffer
);
108 /* IDirectSoundBufferImpl fields */
109 PIDSDRIVERBUFFER hwbuf
;
112 IDirectSound3DBufferImpl
* ds3db
;
113 DWORD playflags
,state
,leadin
;
114 DWORD playpos
,mixpos
,startpos
,writelead
,buflen
;
115 DWORD nAvgBytesPerSec
;
119 IDirectSoundBufferImpl
* parent
; /* for duplicates */
120 IDirectSoundImpl
* dsound
;
122 LPDSBPOSITIONNOTIFY notifies
;
124 CRITICAL_SECTION lock
;
127 #define STATE_STOPPED 0
128 #define STATE_STARTING 1
129 #define STATE_PLAYING 2
130 #define STATE_STOPPING 3
132 /*****************************************************************************
133 * IDirectSoundNotify implementation structure
135 struct IDirectSoundNotifyImpl
137 /* IUnknown fields */
138 ICOM_VFIELD(IDirectSoundNotify
);
140 /* IDirectSoundNotifyImpl fields */
141 IDirectSoundBufferImpl
* dsb
;
144 /*****************************************************************************
145 * IDirectSound3DListener implementation structure
147 struct IDirectSound3DListenerImpl
149 /* IUnknown fields */
150 ICOM_VFIELD(IDirectSound3DListener
);
152 /* IDirectSound3DListenerImpl fields */
153 IDirectSoundBufferImpl
* dsb
;
155 CRITICAL_SECTION lock
;
158 /*****************************************************************************
159 * IDirectSound3DBuffer implementation structure
161 struct IDirectSound3DBufferImpl
163 /* IUnknown fields */
164 ICOM_VFIELD(IDirectSound3DBuffer
);
166 /* IDirectSound3DBufferImpl fields */
167 IDirectSoundBufferImpl
* dsb
;
171 CRITICAL_SECTION lock
;
175 /*****************************************************************************
176 * IDirectSoundCapture implementation structure
178 struct IDirectSoundCaptureImpl
180 /* IUnknown fields */
181 ICOM_VFIELD(IDirectSoundCapture
);
184 /* IDirectSoundCaptureImpl fields */
185 CRITICAL_SECTION lock
;
188 /*****************************************************************************
189 * IDirectSoundCapture implementation structure
191 struct IDirectSoundCaptureBufferImpl
193 /* IUnknown fields */
194 ICOM_VFIELD(IDirectSoundCaptureBuffer
);
197 /* IDirectSoundCaptureBufferImpl fields */
198 CRITICAL_SECTION lock
;
202 /* #define USE_DSOUND3D 1 */
204 #define DSOUND_FREQSHIFT (14)
206 static IDirectSoundImpl
* dsound
= NULL
;
208 static IDirectSoundBufferImpl
* primarybuf
= NULL
;
210 static void DSOUND_CheckEvent(IDirectSoundBufferImpl
*dsb
, int len
);
212 static HRESULT
DSOUND_CreateDirectSoundCapture( LPVOID
* ppobj
);
213 static HRESULT
DSOUND_CreateDirectSoundCaptureBuffer( LPCDSCBUFFERDESC lpcDSCBufferDesc
, LPVOID
* ppobj
);
215 static ICOM_VTABLE(IDirectSoundCapture
) dscvt
;
216 static ICOM_VTABLE(IDirectSoundCaptureBuffer
) dscbvt
;
218 static HRESULT
mmErr(UINT err
)
221 case MMSYSERR_NOERROR
:
223 case MMSYSERR_ALLOCATED
:
224 return DSERR_ALLOCATED
;
225 case MMSYSERR_INVALHANDLE
:
226 return DSERR_GENERIC
; /* FIXME */
227 case MMSYSERR_NODRIVER
:
228 return DSERR_NODRIVER
;
230 return DSERR_OUTOFMEMORY
;
231 case MMSYSERR_INVALPARAM
:
232 return DSERR_INVALIDPARAM
;
234 FIXME("Unknown MMSYS error %d\n",err
);
235 return DSERR_GENERIC
;
239 /***************************************************************************
240 * DirectSoundEnumerateA [DSOUND.2]
242 * Enumerate all DirectSound drivers installed in the system
246 * Failure: DSERR_INVALIDPARAM
248 HRESULT WINAPI
DirectSoundEnumerateA(
249 LPDSENUMCALLBACKA lpDSEnumCallback
,
252 TRACE("lpDSEnumCallback = %p, lpContext = %p\n",
253 lpDSEnumCallback
, lpContext
);
256 if (lpDSEnumCallback
!= NULL
)
257 lpDSEnumCallback(NULL
,"WINE DirectSound using Open Sound System",
264 /***************************************************************************
265 * DirectSoundEnumerateW [DSOUND.3]
267 * Enumerate all DirectSound drivers installed in the system
271 * Failure: DSERR_INVALIDPARAM
273 HRESULT WINAPI
DirectSoundEnumerateW(
274 LPDSENUMCALLBACKW lpDSEnumCallback
,
277 FIXME("lpDSEnumCallback = %p, lpContext = %p: stub\n",
278 lpDSEnumCallback
, lpContext
);
284 static void _dump_DSBCAPS(DWORD xmask
) {
289 #define FE(x) { x, #x },
290 FE(DSBCAPS_PRIMARYBUFFER
)
292 FE(DSBCAPS_LOCHARDWARE
)
293 FE(DSBCAPS_LOCSOFTWARE
)
295 FE(DSBCAPS_CTRLFREQUENCY
)
297 FE(DSBCAPS_CTRLVOLUME
)
298 FE(DSBCAPS_CTRLPOSITIONNOTIFY
)
299 FE(DSBCAPS_CTRLDEFAULT
)
301 FE(DSBCAPS_STICKYFOCUS
)
302 FE(DSBCAPS_GLOBALFOCUS
)
303 FE(DSBCAPS_GETCURRENTPOSITION2
)
304 FE(DSBCAPS_MUTE3DATMAXDISTANCE
)
309 for (i
=0;i
<sizeof(flags
)/sizeof(flags
[0]);i
++)
310 if ((flags
[i
].mask
& xmask
) == flags
[i
].mask
)
311 DPRINTF("%s ",flags
[i
].name
);
314 /*******************************************************************************
315 * IDirectSound3DBuffer
318 /* IUnknown methods */
320 static HRESULT WINAPI
IDirectSound3DBufferImpl_QueryInterface(
321 LPDIRECTSOUND3DBUFFER iface
, REFIID riid
, LPVOID
*ppobj
)
323 ICOM_THIS(IDirectSound3DBufferImpl
,iface
);
325 TRACE("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
331 static ULONG WINAPI
IDirectSound3DBufferImpl_AddRef(LPDIRECTSOUND3DBUFFER iface
)
333 ICOM_THIS(IDirectSound3DBufferImpl
,iface
);
340 static ULONG WINAPI
IDirectSound3DBufferImpl_Release(LPDIRECTSOUND3DBUFFER iface
)
342 ICOM_THIS(IDirectSound3DBufferImpl
,iface
);
344 TRACE("(%p) ref was %ld\n", This
, This
->ref
);
350 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)This
->dsb
);
352 DeleteCriticalSection(&This
->lock
);
354 HeapFree(GetProcessHeap(),0,This
->buffer
);
355 HeapFree(GetProcessHeap(),0,This
);
361 /* IDirectSound3DBuffer methods */
363 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetAllParameters(
364 LPDIRECTSOUND3DBUFFER iface
,
365 LPDS3DBUFFER lpDs3dBuffer
)
373 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetConeAngles(
374 LPDIRECTSOUND3DBUFFER iface
,
375 LPDWORD lpdwInsideConeAngle
,
376 LPDWORD lpdwOutsideConeAngle
)
384 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetConeOrientation(
385 LPDIRECTSOUND3DBUFFER iface
,
386 LPD3DVECTOR lpvConeOrientation
)
394 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetConeOutsideVolume(
395 LPDIRECTSOUND3DBUFFER iface
,
396 LPLONG lplConeOutsideVolume
)
404 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetMaxDistance(
405 LPDIRECTSOUND3DBUFFER iface
,
406 LPD3DVALUE lpfMaxDistance
)
414 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetMinDistance(
415 LPDIRECTSOUND3DBUFFER iface
,
416 LPD3DVALUE lpfMinDistance
)
424 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetMode(
425 LPDIRECTSOUND3DBUFFER iface
,
434 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetPosition(
435 LPDIRECTSOUND3DBUFFER iface
,
436 LPD3DVECTOR lpvPosition
)
444 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetVelocity(
445 LPDIRECTSOUND3DBUFFER iface
,
446 LPD3DVECTOR lpvVelocity
)
454 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetAllParameters(
455 LPDIRECTSOUND3DBUFFER iface
,
456 LPCDS3DBUFFER lpcDs3dBuffer
,
465 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetConeAngles(
466 LPDIRECTSOUND3DBUFFER iface
,
467 DWORD dwInsideConeAngle
,
468 DWORD dwOutsideConeAngle
,
477 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetConeOrientation(
478 LPDIRECTSOUND3DBUFFER iface
,
479 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
488 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetConeOutsideVolume(
489 LPDIRECTSOUND3DBUFFER iface
,
490 LONG lConeOutsideVolume
,
499 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetMaxDistance(
500 LPDIRECTSOUND3DBUFFER iface
,
501 D3DVALUE fMaxDistance
,
510 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetMinDistance(
511 LPDIRECTSOUND3DBUFFER iface
,
512 D3DVALUE fMinDistance
,
521 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetMode(
522 LPDIRECTSOUND3DBUFFER iface
,
526 ICOM_THIS(IDirectSound3DBufferImpl
,iface
);
527 TRACE("mode = %lx\n", dwMode
);
528 This
->ds3db
.dwMode
= dwMode
;
534 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetPosition(
535 LPDIRECTSOUND3DBUFFER iface
,
536 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
545 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetVelocity(
546 LPDIRECTSOUND3DBUFFER iface
,
547 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
556 static ICOM_VTABLE(IDirectSound3DBuffer
) ds3dbvt
=
558 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
559 /* IUnknown methods */
560 IDirectSound3DBufferImpl_QueryInterface
,
561 IDirectSound3DBufferImpl_AddRef
,
562 IDirectSound3DBufferImpl_Release
,
563 /* IDirectSound3DBuffer methods */
564 IDirectSound3DBufferImpl_GetAllParameters
,
565 IDirectSound3DBufferImpl_GetConeAngles
,
566 IDirectSound3DBufferImpl_GetConeOrientation
,
567 IDirectSound3DBufferImpl_GetConeOutsideVolume
,
568 IDirectSound3DBufferImpl_GetMaxDistance
,
569 IDirectSound3DBufferImpl_GetMinDistance
,
570 IDirectSound3DBufferImpl_GetMode
,
571 IDirectSound3DBufferImpl_GetPosition
,
572 IDirectSound3DBufferImpl_GetVelocity
,
573 IDirectSound3DBufferImpl_SetAllParameters
,
574 IDirectSound3DBufferImpl_SetConeAngles
,
575 IDirectSound3DBufferImpl_SetConeOrientation
,
576 IDirectSound3DBufferImpl_SetConeOutsideVolume
,
577 IDirectSound3DBufferImpl_SetMaxDistance
,
578 IDirectSound3DBufferImpl_SetMinDistance
,
579 IDirectSound3DBufferImpl_SetMode
,
580 IDirectSound3DBufferImpl_SetPosition
,
581 IDirectSound3DBufferImpl_SetVelocity
,
586 static int DSOUND_Create3DBuffer(IDirectSoundBufferImpl
* dsb
)
588 DWORD i
, temp
, iSize
, oSize
, offset
;
589 LPBYTE bIbuf
, bObuf
, bTbuf
= NULL
;
590 LPWORD wIbuf
, wObuf
, wTbuf
= NULL
;
592 /* Inside DirectX says it's stupid but allowed */
593 if (dsb
->wfx
.nChannels
== 2) {
594 /* Convert to mono */
595 if (dsb
->wfx
.wBitsPerSample
== 16) {
596 iSize
= dsb
->buflen
/ 4;
597 wTbuf
= malloc(dsb
->buflen
/ 2);
599 return DSERR_OUTOFMEMORY
;
600 for (i
= 0; i
< iSize
; i
++)
601 wTbuf
[i
] = (dsb
->buffer
[i
] + dsb
->buffer
[(i
* 2) + 1]) / 2;
604 iSize
= dsb
->buflen
/ 2;
605 bTbuf
= malloc(dsb
->buflen
/ 2);
607 return DSERR_OUTOFMEMORY
;
608 for (i
= 0; i
< iSize
; i
++)
609 bTbuf
[i
] = (dsb
->buffer
[i
] + dsb
->buffer
[(i
* 2) + 1]) / 2;
613 if (dsb
->wfx
.wBitsPerSample
== 16) {
614 iSize
= dsb
->buflen
/ 2;
615 wIbuf
= (LPWORD
) dsb
->buffer
;
617 bIbuf
= (LPBYTE
) dsb
->buffer
;
622 if (primarybuf
->wfx
.wBitsPerSample
== 16) {
623 wObuf
= (LPWORD
) dsb
->ds3db
->buffer
;
624 oSize
= dsb
->ds3db
->buflen
/ 2;
626 bObuf
= (LPBYTE
) dsb
->ds3db
->buffer
;
627 oSize
= dsb
->ds3db
->buflen
;
630 offset
= primarybuf
->wfx
.nSamplesPerSec
/ 100; /* 10ms */
631 if (primarybuf
->wfx
.wBitsPerSample
== 16 && dsb
->wfx
.wBitsPerSample
== 16)
632 for (i
= 0; i
< iSize
; i
++) {
635 temp
+= wIbuf
[i
- offset
] >> 9;
637 temp
+= wIbuf
[i
+ iSize
- offset
] >> 9;
639 wObuf
[(i
* 2) + 1] = temp
;
641 else if (primarybuf
->wfx
.wBitsPerSample
== 8 && dsb
->wfx
.wBitsPerSample
== 8)
642 for (i
= 0; i
< iSize
; i
++) {
645 temp
+= bIbuf
[i
- offset
] >> 5;
647 temp
+= bIbuf
[i
+ iSize
- offset
] >> 5;
649 bObuf
[(i
* 2) + 1] = temp
;
660 /*******************************************************************************
661 * IDirectSound3DListener
664 /* IUnknown methods */
665 static HRESULT WINAPI
IDirectSound3DListenerImpl_QueryInterface(
666 LPDIRECTSOUND3DLISTENER iface
, REFIID riid
, LPVOID
*ppobj
)
668 ICOM_THIS(IDirectSound3DListenerImpl
,iface
);
670 TRACE("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
674 static ULONG WINAPI
IDirectSound3DListenerImpl_AddRef(LPDIRECTSOUND3DLISTENER iface
)
676 ICOM_THIS(IDirectSound3DListenerImpl
,iface
);
681 static ULONG WINAPI
IDirectSound3DListenerImpl_Release(LPDIRECTSOUND3DLISTENER iface
)
684 ICOM_THIS(IDirectSound3DListenerImpl
,iface
);
686 TRACE("(%p) ref was %ld\n", This
, This
->ref
);
688 ulReturn
= --This
->ref
;
690 /* Free all resources */
691 if( ulReturn
== 0 ) {
693 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)This
->dsb
);
694 DeleteCriticalSection(&This
->lock
);
695 HeapFree(GetProcessHeap(),0,This
);
701 /* IDirectSound3DListener methods */
702 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetAllParameter(
703 LPDIRECTSOUND3DLISTENER iface
,
704 LPDS3DLISTENER lpDS3DL
)
710 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetDistanceFactor(
711 LPDIRECTSOUND3DLISTENER iface
,
712 LPD3DVALUE lpfDistanceFactor
)
718 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetDopplerFactor(
719 LPDIRECTSOUND3DLISTENER iface
,
720 LPD3DVALUE lpfDopplerFactor
)
726 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetOrientation(
727 LPDIRECTSOUND3DLISTENER iface
,
728 LPD3DVECTOR lpvOrientFront
,
729 LPD3DVECTOR lpvOrientTop
)
735 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetPosition(
736 LPDIRECTSOUND3DLISTENER iface
,
737 LPD3DVECTOR lpvPosition
)
743 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetRolloffFactor(
744 LPDIRECTSOUND3DLISTENER iface
,
745 LPD3DVALUE lpfRolloffFactor
)
751 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetVelocity(
752 LPDIRECTSOUND3DLISTENER iface
,
753 LPD3DVECTOR lpvVelocity
)
759 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetAllParameters(
760 LPDIRECTSOUND3DLISTENER iface
,
761 LPCDS3DLISTENER lpcDS3DL
,
768 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetDistanceFactor(
769 LPDIRECTSOUND3DLISTENER iface
,
770 D3DVALUE fDistanceFactor
,
777 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetDopplerFactor(
778 LPDIRECTSOUND3DLISTENER iface
,
779 D3DVALUE fDopplerFactor
,
786 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetOrientation(
787 LPDIRECTSOUND3DLISTENER iface
,
788 D3DVALUE xFront
, D3DVALUE yFront
, D3DVALUE zFront
,
789 D3DVALUE xTop
, D3DVALUE yTop
, D3DVALUE zTop
,
796 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetPosition(
797 LPDIRECTSOUND3DLISTENER iface
,
798 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
805 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetRolloffFactor(
806 LPDIRECTSOUND3DLISTENER iface
,
807 D3DVALUE fRolloffFactor
,
814 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetVelocity(
815 LPDIRECTSOUND3DLISTENER iface
,
816 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
823 static HRESULT WINAPI
IDirectSound3DListenerImpl_CommitDeferredSettings(
824 LPDIRECTSOUND3DLISTENER iface
)
831 static ICOM_VTABLE(IDirectSound3DListener
) ds3dlvt
=
833 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
834 /* IUnknown methods */
835 IDirectSound3DListenerImpl_QueryInterface
,
836 IDirectSound3DListenerImpl_AddRef
,
837 IDirectSound3DListenerImpl_Release
,
838 /* IDirectSound3DListener methods */
839 IDirectSound3DListenerImpl_GetAllParameter
,
840 IDirectSound3DListenerImpl_GetDistanceFactor
,
841 IDirectSound3DListenerImpl_GetDopplerFactor
,
842 IDirectSound3DListenerImpl_GetOrientation
,
843 IDirectSound3DListenerImpl_GetPosition
,
844 IDirectSound3DListenerImpl_GetRolloffFactor
,
845 IDirectSound3DListenerImpl_GetVelocity
,
846 IDirectSound3DListenerImpl_SetAllParameters
,
847 IDirectSound3DListenerImpl_SetDistanceFactor
,
848 IDirectSound3DListenerImpl_SetDopplerFactor
,
849 IDirectSound3DListenerImpl_SetOrientation
,
850 IDirectSound3DListenerImpl_SetPosition
,
851 IDirectSound3DListenerImpl_SetRolloffFactor
,
852 IDirectSound3DListenerImpl_SetVelocity
,
853 IDirectSound3DListenerImpl_CommitDeferredSettings
,
856 /*******************************************************************************
859 static HRESULT WINAPI
IDirectSoundNotifyImpl_QueryInterface(
860 LPDIRECTSOUNDNOTIFY iface
,REFIID riid
,LPVOID
*ppobj
862 ICOM_THIS(IDirectSoundNotifyImpl
,iface
);
864 TRACE("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
868 static ULONG WINAPI
IDirectSoundNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface
) {
869 ICOM_THIS(IDirectSoundNotifyImpl
,iface
);
870 return ++(This
->ref
);
873 static ULONG WINAPI
IDirectSoundNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface
) {
874 ICOM_THIS(IDirectSoundNotifyImpl
,iface
);
876 TRACE("(%p) ref was %ld\n", This
, This
->ref
);
880 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)This
->dsb
);
881 HeapFree(GetProcessHeap(),0,This
);
887 static HRESULT WINAPI
IDirectSoundNotifyImpl_SetNotificationPositions(
888 LPDIRECTSOUNDNOTIFY iface
,DWORD howmuch
,LPCDSBPOSITIONNOTIFY notify
890 ICOM_THIS(IDirectSoundNotifyImpl
,iface
);
893 if (TRACE_ON(dsound
)) {
894 TRACE("(%p,0x%08lx,%p)\n",This
,howmuch
,notify
);
895 for (i
=0;i
<howmuch
;i
++)
896 TRACE("notify at %ld to 0x%08lx\n",
897 notify
[i
].dwOffset
,(DWORD
)notify
[i
].hEventNotify
);
899 This
->dsb
->notifies
= HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,This
->dsb
->notifies
,(This
->dsb
->nrofnotifies
+howmuch
)*sizeof(DSBPOSITIONNOTIFY
));
900 memcpy( This
->dsb
->notifies
+This
->dsb
->nrofnotifies
,
902 howmuch
*sizeof(DSBPOSITIONNOTIFY
)
904 This
->dsb
->nrofnotifies
+=howmuch
;
909 static ICOM_VTABLE(IDirectSoundNotify
) dsnvt
=
911 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
912 IDirectSoundNotifyImpl_QueryInterface
,
913 IDirectSoundNotifyImpl_AddRef
,
914 IDirectSoundNotifyImpl_Release
,
915 IDirectSoundNotifyImpl_SetNotificationPositions
,
918 /*******************************************************************************
922 static void DSOUND_RecalcVolPan(PDSVOLUMEPAN volpan
)
926 /* the AmpFactors are expressed in 16.16 fixed point */
927 volpan
->dwVolAmpFactor
= (ULONG
) (pow(2.0, volpan
->lVolume
/ 600.0) * 65536);
928 /* FIXME: dwPan{Left|Right}AmpFactor */
930 /* FIXME: use calculated vol and pan ampfactors */
931 temp
= (double) (volpan
->lVolume
- (volpan
->lPan
> 0 ? volpan
->lPan
: 0));
932 volpan
->dwTotalLeftAmpFactor
= (ULONG
) (pow(2.0, temp
/ 600.0) * 65536);
933 temp
= (double) (volpan
->lVolume
+ (volpan
->lPan
< 0 ? volpan
->lPan
: 0));
934 volpan
->dwTotalRightAmpFactor
= (ULONG
) (pow(2.0, temp
/ 600.0) * 65536);
936 TRACE("left = %lx, right = %lx\n", volpan
->dwTotalLeftAmpFactor
, volpan
->dwTotalRightAmpFactor
);
939 static void DSOUND_RecalcFormat(IDirectSoundBufferImpl
*dsb
)
943 sw
= dsb
->wfx
.nChannels
* (dsb
->wfx
.wBitsPerSample
/ 8);
944 if ((dsb
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
) && dsb
->hwbuf
) {
946 /* let fragment size approximate the timer delay */
947 fraglen
= (dsb
->freq
* DS_TIME_DEL
/ 1000) * sw
;
948 /* reduce fragment size until an integer number of them fits in the buffer */
949 /* (FIXME: this may or may not be a good idea) */
950 while (dsb
->buflen
% fraglen
) fraglen
-= sw
;
951 dsb
->dsound
->fraglen
= fraglen
;
952 TRACE("fraglen=%ld\n", dsb
->dsound
->fraglen
);
954 /* calculate the 10ms write lead */
955 dsb
->writelead
= (dsb
->freq
/ 100) * sw
;
958 static HRESULT
DSOUND_PrimaryOpen(IDirectSoundBufferImpl
*dsb
)
962 /* are we using waveOut stuff? */
966 HRESULT merr
= DS_OK
;
967 /* Start in pause mode, to allow buffers to get filled */
968 waveOutPause(dsb
->dsound
->hwo
);
969 /* use fragments of 10ms (1/100s) each (which should get us within
970 * the documented write cursor lead of 10-15ms) */
971 buflen
= ((dsb
->wfx
.nAvgBytesPerSec
/ 100) & ~3) * DS_HEL_FRAGS
;
972 TRACE("desired buflen=%ld, old buffer=%p\n", buflen
, dsb
->buffer
);
973 /* reallocate emulated primary buffer */
974 newbuf
= (LPBYTE
)HeapReAlloc(GetProcessHeap(),0,dsb
->buffer
,buflen
);
975 if (newbuf
== NULL
) {
976 ERR("failed to allocate primary buffer\n");
977 merr
= DSERR_OUTOFMEMORY
;
978 /* but the old buffer might still exists and must be re-prepared */
980 dsb
->buffer
= newbuf
;
981 dsb
->buflen
= buflen
;
985 IDirectSoundImpl
*ds
= dsb
->dsound
;
987 ds
->fraglen
= dsb
->buflen
/ DS_HEL_FRAGS
;
989 /* prepare fragment headers */
990 for (c
=0; c
<DS_HEL_FRAGS
; c
++) {
991 ds
->pwave
[c
]->lpData
= dsb
->buffer
+ c
*ds
->fraglen
;
992 ds
->pwave
[c
]->dwBufferLength
= ds
->fraglen
;
993 ds
->pwave
[c
]->dwUser
= (DWORD
)dsb
;
994 ds
->pwave
[c
]->dwFlags
= 0;
995 ds
->pwave
[c
]->dwLoops
= 0;
996 err
= mmErr(waveOutPrepareHeader(ds
->hwo
,ds
->pwave
[c
],sizeof(WAVEHDR
)));
999 waveOutUnprepareHeader(ds
->hwo
,ds
->pwave
[c
],sizeof(WAVEHDR
));
1007 memset(dsb
->buffer
, (dsb
->wfx
.wBitsPerSample
== 16) ? 0 : 128, dsb
->buflen
);
1008 TRACE("fraglen=%ld\n", ds
->fraglen
);
1010 if ((err
== DS_OK
) && (merr
!= DS_OK
))
1017 static void DSOUND_PrimaryClose(IDirectSoundBufferImpl
*dsb
)
1019 /* are we using waveOut stuff? */
1022 IDirectSoundImpl
*ds
= dsb
->dsound
;
1024 waveOutReset(ds
->hwo
);
1025 for (c
=0; c
<DS_HEL_FRAGS
; c
++)
1026 waveOutUnprepareHeader(ds
->hwo
, ds
->pwave
[c
], sizeof(WAVEHDR
));
1030 /* This sets this format for the <em>Primary Buffer Only</em> */
1031 /* See file:///cdrom/sdk52/docs/worddoc/dsound.doc page 120 */
1032 static HRESULT WINAPI
IDirectSoundBufferImpl_SetFormat(
1033 LPDIRECTSOUNDBUFFER iface
,LPWAVEFORMATEX wfex
1035 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1036 IDirectSoundBufferImpl
** dsb
;
1037 HRESULT err
= DS_OK
;
1040 /* Let's be pedantic! */
1041 if ((wfex
== NULL
) ||
1042 (wfex
->wFormatTag
!= WAVE_FORMAT_PCM
) ||
1043 (wfex
->nChannels
< 1) || (wfex
->nChannels
> 2) ||
1044 (wfex
->nSamplesPerSec
< 1) ||
1045 (wfex
->nBlockAlign
< 1) || (wfex
->nChannels
> 4) ||
1046 ((wfex
->wBitsPerSample
!= 8) && (wfex
->wBitsPerSample
!= 16))) {
1047 TRACE("failed pedantic check!\n");
1048 return DSERR_INVALIDPARAM
;
1052 EnterCriticalSection(&(This
->dsound
->lock
));
1054 if (primarybuf
->wfx
.nSamplesPerSec
!= wfex
->nSamplesPerSec
) {
1055 dsb
= dsound
->buffers
;
1056 for (i
= 0; i
< dsound
->nrofbuffers
; i
++, dsb
++) {
1058 EnterCriticalSection(&((*dsb
)->lock
));
1060 (*dsb
)->freqAdjust
= ((*dsb
)->freq
<< DSOUND_FREQSHIFT
) /
1061 wfex
->nSamplesPerSec
;
1063 LeaveCriticalSection(&((*dsb
)->lock
));
1068 memcpy(&(primarybuf
->wfx
), wfex
, sizeof(primarybuf
->wfx
));
1070 TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld,"
1071 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
1072 wfex
->wFormatTag
, wfex
->nChannels
, wfex
->nSamplesPerSec
,
1073 wfex
->nAvgBytesPerSec
, wfex
->nBlockAlign
,
1074 wfex
->wBitsPerSample
, wfex
->cbSize
);
1076 primarybuf
->wfx
.nAvgBytesPerSec
=
1077 This
->wfx
.nSamplesPerSec
* This
->wfx
.nBlockAlign
;
1078 if (primarybuf
->dsound
->drvdesc
.dwFlags
& DSDDESC_DOMMSYSTEMSETFORMAT
) {
1079 /* FIXME: check for errors */
1080 DSOUND_PrimaryClose(primarybuf
);
1081 waveOutClose(This
->dsound
->hwo
);
1082 This
->dsound
->hwo
= 0;
1083 waveOutOpen(&(This
->dsound
->hwo
), This
->dsound
->drvdesc
.dnDevNode
,
1084 &(primarybuf
->wfx
), 0, 0, CALLBACK_NULL
| WAVE_DIRECTSOUND
);
1085 DSOUND_PrimaryOpen(primarybuf
);
1087 if (primarybuf
->hwbuf
) {
1088 err
= IDsDriverBuffer_SetFormat(primarybuf
->hwbuf
, &(primarybuf
->wfx
));
1089 if (err
== DSERR_BUFFERLOST
) {
1090 /* Wine-only: the driver wants us to recreate the HW buffer */
1091 IDsDriverBuffer_Release(primarybuf
->hwbuf
);
1092 err
= IDsDriver_CreateSoundBuffer(primarybuf
->dsound
->driver
,&(primarybuf
->wfx
),primarybuf
->dsbd
.dwFlags
,0,
1093 &(primarybuf
->buflen
),&(primarybuf
->buffer
),
1094 (LPVOID
)&(primarybuf
->hwbuf
));
1097 DSOUND_RecalcFormat(primarybuf
);
1099 LeaveCriticalSection(&(This
->dsound
->lock
));
1105 static HRESULT WINAPI
IDirectSoundBufferImpl_SetVolume(
1106 LPDIRECTSOUNDBUFFER iface
,LONG vol
1108 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1110 TRACE("(%p,%ld)\n",This
,vol
);
1112 /* I'm not sure if we need this for primary buffer */
1113 if (!(This
->dsbd
.dwFlags
& DSBCAPS_CTRLVOLUME
))
1114 return DSERR_CONTROLUNAVAIL
;
1116 if ((vol
> DSBVOLUME_MAX
) || (vol
< DSBVOLUME_MIN
))
1117 return DSERR_INVALIDPARAM
;
1120 EnterCriticalSection(&(This
->lock
));
1122 This
->volpan
.lVolume
= vol
;
1124 DSOUND_RecalcVolPan(&(This
->volpan
));
1127 IDsDriverBuffer_SetVolumePan(This
->hwbuf
, &(This
->volpan
));
1129 else if (This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
1130 #if 0 /* should we really do this? */
1131 /* the DS volume ranges from 0 (max, 0dB attenuation) to -10000 (min, 100dB attenuation) */
1132 /* the MM volume ranges from 0 to 0xffff in an unspecified logarithmic scale */
1133 WORD cvol
= 0xffff + vol
*6 + vol
/2;
1134 DWORD vol
= cvol
| ((DWORD
)cvol
<< 16)
1135 waveOutSetVolume(This
->dsound
->hwo
, vol
);
1139 LeaveCriticalSection(&(This
->lock
));
1145 static HRESULT WINAPI
IDirectSoundBufferImpl_GetVolume(
1146 LPDIRECTSOUNDBUFFER iface
,LPLONG vol
1148 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1149 TRACE("(%p,%p)\n",This
,vol
);
1152 return DSERR_INVALIDPARAM
;
1154 *vol
= This
->volpan
.lVolume
;
1158 static HRESULT WINAPI
IDirectSoundBufferImpl_SetFrequency(
1159 LPDIRECTSOUNDBUFFER iface
,DWORD freq
1161 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1162 TRACE("(%p,%ld)\n",This
,freq
);
1164 /* You cannot set the frequency of the primary buffer */
1165 if (!(This
->dsbd
.dwFlags
& DSBCAPS_CTRLFREQUENCY
) ||
1166 (This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
))
1167 return DSERR_CONTROLUNAVAIL
;
1169 if (!freq
) freq
= This
->wfx
.nSamplesPerSec
;
1171 if ((freq
< DSBFREQUENCY_MIN
) || (freq
> DSBFREQUENCY_MAX
))
1172 return DSERR_INVALIDPARAM
;
1175 EnterCriticalSection(&(This
->lock
));
1178 This
->freqAdjust
= (freq
<< DSOUND_FREQSHIFT
) / primarybuf
->wfx
.nSamplesPerSec
;
1179 This
->nAvgBytesPerSec
= freq
* This
->wfx
.nBlockAlign
;
1180 DSOUND_RecalcFormat(This
);
1182 LeaveCriticalSection(&(This
->lock
));
1188 static HRESULT WINAPI
IDirectSoundBufferImpl_Play(
1189 LPDIRECTSOUNDBUFFER iface
,DWORD reserved1
,DWORD reserved2
,DWORD flags
1191 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1192 TRACE("(%p,%08lx,%08lx,%08lx)\n",
1193 This
,reserved1
,reserved2
,flags
1195 This
->playflags
= flags
;
1196 if (This
->state
== STATE_STOPPED
) {
1197 This
->leadin
= TRUE
;
1198 This
->startpos
= This
->mixpos
;
1199 This
->state
= STATE_STARTING
;
1200 } else if (This
->state
== STATE_STOPPING
)
1201 This
->state
= STATE_PLAYING
;
1202 if (!(This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
) && This
->hwbuf
) {
1203 IDsDriverBuffer_Play(This
->hwbuf
, 0, 0, This
->playflags
);
1204 This
->state
= STATE_PLAYING
;
1209 static HRESULT WINAPI
IDirectSoundBufferImpl_Stop(LPDIRECTSOUNDBUFFER iface
)
1211 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1212 TRACE("(%p)\n",This
);
1215 EnterCriticalSection(&(This
->lock
));
1217 if (This
->state
== STATE_PLAYING
)
1218 This
->state
= STATE_STOPPING
;
1219 else if (This
->state
== STATE_STARTING
)
1220 This
->state
= STATE_STOPPED
;
1221 if (!(This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
) && This
->hwbuf
) {
1222 IDsDriverBuffer_Stop(This
->hwbuf
);
1223 This
->state
= STATE_STOPPED
;
1225 DSOUND_CheckEvent(This
, 0);
1227 LeaveCriticalSection(&(This
->lock
));
1233 static DWORD WINAPI
IDirectSoundBufferImpl_AddRef(LPDIRECTSOUNDBUFFER iface
) {
1234 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1237 TRACE("(%p) ref was %ld, thread is %lx\n",This
, This
->ref
, GetCurrentThreadId());
1239 ref
= InterlockedIncrement(&(This
->ref
));
1241 FIXME("thread-safety alert! AddRef-ing with a zero refcount!\n");
1245 static DWORD WINAPI
IDirectSoundBufferImpl_Release(LPDIRECTSOUNDBUFFER iface
) {
1246 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1250 TRACE("(%p) ref was %ld, thread is %lx\n",This
, This
->ref
, GetCurrentThreadId());
1252 ref
= InterlockedDecrement(&(This
->ref
));
1253 if (ref
) return ref
;
1255 EnterCriticalSection(&(This
->dsound
->lock
));
1256 for (i
=0;i
<This
->dsound
->nrofbuffers
;i
++)
1257 if (This
->dsound
->buffers
[i
] == This
)
1260 if (i
< This
->dsound
->nrofbuffers
) {
1261 /* Put the last buffer of the list in the (now empty) position */
1262 This
->dsound
->buffers
[i
] = This
->dsound
->buffers
[This
->dsound
->nrofbuffers
- 1];
1263 This
->dsound
->nrofbuffers
--;
1264 This
->dsound
->buffers
= HeapReAlloc(GetProcessHeap(),0,This
->dsound
->buffers
,sizeof(LPDIRECTSOUNDBUFFER
)*This
->dsound
->nrofbuffers
);
1265 TRACE("buffer count is now %d\n", This
->dsound
->nrofbuffers
);
1266 IDirectSound_Release((LPDIRECTSOUND
)This
->dsound
);
1268 LeaveCriticalSection(&(This
->dsound
->lock
));
1270 DeleteCriticalSection(&(This
->lock
));
1271 if (This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
)
1272 DSOUND_PrimaryClose(This
);
1274 IDsDriverBuffer_Release(This
->hwbuf
);
1277 IDirectSound3DBuffer_Release((LPDIRECTSOUND3DBUFFER
)This
->ds3db
);
1279 /* this is a duplicate buffer */
1280 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)This
->parent
);
1282 /* this is a toplevel buffer */
1283 HeapFree(GetProcessHeap(),0,This
->buffer
);
1285 HeapFree(GetProcessHeap(),0,This
);
1287 if (This
== primarybuf
)
1293 static HRESULT WINAPI
IDirectSoundBufferImpl_GetCurrentPosition(
1294 LPDIRECTSOUNDBUFFER iface
,LPDWORD playpos
,LPDWORD writepos
1296 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1297 TRACE("(%p,%p,%p)\n",This
,playpos
,writepos
);
1299 IDsDriverBuffer_GetPosition(This
->hwbuf
, playpos
, writepos
);
1301 else if (This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
1302 if (playpos
&& (This
->dsbd
.dwFlags
& DSBCAPS_GETCURRENTPOSITION2
)) {
1304 mtime
.wType
= TIME_BYTES
;
1305 waveOutGetPosition(This
->dsound
->hwo
, &mtime
, sizeof(mtime
));
1306 mtime
.u
.cb
= mtime
.u
.cb
% This
->buflen
;
1307 *playpos
= mtime
.u
.cb
;
1309 /* don't know how exactly non-GETCURRENTPOSITION2 behaves,
1310 * but I think this works for Starcraft */
1311 else if (playpos
) *playpos
= This
->playpos
;
1313 /* the writepos should only be used by apps with WRITEPRIMARY priority,
1314 * in which case our software mixer is disabled anyway */
1315 *writepos
= This
->playpos
+ DS_HEL_MARGIN
* This
->dsound
->fraglen
;
1316 while (*writepos
>= This
->buflen
)
1317 *writepos
-= This
->buflen
;
1320 if (playpos
&& (This
->state
!= STATE_PLAYING
)) {
1321 /* we haven't been merged into the primary buffer (yet) */
1322 *playpos
= This
->mixpos
;
1325 DWORD pplay
, lplay
, splay
, tplay
, pstate
;
1326 /* let's get this exact; first, recursively call GetPosition on the primary */
1327 EnterCriticalSection(&(primarybuf
->lock
));
1328 if ((This
->dsbd
.dwFlags
& DSBCAPS_GETCURRENTPOSITION2
) || primarybuf
->hwbuf
) {
1329 IDirectSoundBufferImpl_GetCurrentPosition((LPDIRECTSOUNDBUFFER
)primarybuf
, &pplay
, NULL
);
1331 /* (unless the app isn't using GETCURRENTPOSITION2) */
1332 /* don't know exactly how this should be handled either */
1333 pplay
= primarybuf
->playpos
;
1335 /* get last mixed primary play position */
1336 lplay
= primarybuf
->mixpos
;
1337 pstate
= primarybuf
->state
;
1338 /* detect HEL mode underrun */
1339 if (!(primarybuf
->hwbuf
|| primarybuf
->dsound
->pwqueue
)) {
1340 TRACE("detected an underrun\n");
1342 if (pstate
== STATE_PLAYING
)
1343 pstate
= STATE_STARTING
;
1344 else if (pstate
== STATE_STOPPING
)
1345 pstate
= STATE_STOPPED
;
1347 /* get our own last mixed position while we still have the lock */
1348 splay
= This
->mixpos
;
1349 LeaveCriticalSection(&(primarybuf
->lock
));
1350 TRACE("primary playpos=%ld, mixpos=%ld\n", pplay
, lplay
);
1351 TRACE("this mixpos=%ld\n", splay
);
1353 /* the actual primary play position (pplay) is always behind last mixed (lplay),
1354 * unless the computer is too slow or something */
1355 /* we need to know how far away we are from there */
1356 if (lplay
== pplay
) {
1357 if ((pstate
== STATE_PLAYING
) || (pstate
== STATE_STOPPING
)) {
1358 /* wow, the software mixer is really doing well,
1359 * seems the entire primary buffer is filled! */
1360 lplay
+= primarybuf
->buflen
;
1362 /* else: the primary buffer is not playing, so probably empty */
1364 if (lplay
< pplay
) lplay
+= primarybuf
->buflen
; /* wraparound */
1366 /* detect HAL mode underrun */
1367 if (primarybuf
->hwbuf
&&
1368 (lplay
> ((DS_HAL_QUEUE
+ 1) * primarybuf
->dsound
->fraglen
+ primarybuf
->writelead
))) {
1369 TRACE("detected an underrun: primary queue was %ld\n",lplay
);
1372 /* divide the offset by its sample size */
1373 lplay
/= primarybuf
->wfx
.nChannels
* (primarybuf
->wfx
.wBitsPerSample
/ 8);
1374 TRACE("primary back-samples=%ld\n",lplay
);
1375 /* adjust for our frequency */
1376 lplay
= (lplay
* This
->freqAdjust
) >> DSOUND_FREQSHIFT
;
1377 /* multiply by our own sample size */
1378 lplay
*= This
->wfx
.nChannels
* (This
->wfx
.wBitsPerSample
/ 8);
1379 TRACE("this back-offset=%ld\n", lplay
);
1380 /* subtract from our last mixed position */
1382 while (tplay
< lplay
) tplay
+= This
->buflen
; /* wraparound */
1384 if (This
->leadin
&& ((tplay
< This
->startpos
) || (tplay
> splay
))) {
1385 /* seems we haven't started playing yet */
1386 TRACE("this still in lead-in phase\n");
1387 tplay
= This
->startpos
;
1389 /* return the result */
1392 if (writepos
) *writepos
= This
->mixpos
;
1395 if (This
->state
!= STATE_STOPPED
)
1396 /* apply the documented 10ms lead to writepos */
1397 *writepos
+= This
->writelead
;
1398 while (*writepos
>= This
->buflen
) *writepos
-= This
->buflen
;
1400 TRACE("playpos = %ld, writepos = %ld (%p, time=%ld)\n", playpos
?*playpos
:0, writepos
?*writepos
:0, This
, GetTickCount());
1404 static HRESULT WINAPI
IDirectSoundBufferImpl_GetStatus(
1405 LPDIRECTSOUNDBUFFER iface
,LPDWORD status
1407 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1408 TRACE("(%p,%p), thread is %lx\n",This
,status
,GetCurrentThreadId());
1411 return DSERR_INVALIDPARAM
;
1414 if ((This
->state
== STATE_STARTING
) || (This
->state
== STATE_PLAYING
))
1415 *status
|= DSBSTATUS_PLAYING
;
1416 if (This
->playflags
& DSBPLAY_LOOPING
)
1417 *status
|= DSBSTATUS_LOOPING
;
1419 TRACE("status=%lx\n", *status
);
1424 static HRESULT WINAPI
IDirectSoundBufferImpl_GetFormat(
1425 LPDIRECTSOUNDBUFFER iface
,LPWAVEFORMATEX lpwf
,DWORD wfsize
,LPDWORD wfwritten
1427 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1428 TRACE("(%p,%p,%ld,%p)\n",This
,lpwf
,wfsize
,wfwritten
);
1430 if (wfsize
>sizeof(This
->wfx
))
1431 wfsize
= sizeof(This
->wfx
);
1432 if (lpwf
) { /* NULL is valid */
1433 memcpy(lpwf
,&(This
->wfx
),wfsize
);
1435 *wfwritten
= wfsize
;
1438 *wfwritten
= sizeof(This
->wfx
);
1440 return DSERR_INVALIDPARAM
;
1445 static HRESULT WINAPI
IDirectSoundBufferImpl_Lock(
1446 LPDIRECTSOUNDBUFFER iface
,DWORD writecursor
,DWORD writebytes
,LPVOID lplpaudioptr1
,LPDWORD audiobytes1
,LPVOID lplpaudioptr2
,LPDWORD audiobytes2
,DWORD flags
1448 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1451 TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx)\n",
1462 if (flags
& DSBLOCK_FROMWRITECURSOR
) {
1464 /* GetCurrentPosition does too much magic to duplicate here */
1465 IDirectSoundBufferImpl_GetCurrentPosition(iface
, NULL
, &writepos
);
1466 writecursor
+= writepos
;
1468 if (flags
& DSBLOCK_ENTIREBUFFER
)
1469 writebytes
= This
->buflen
;
1470 if (writebytes
> This
->buflen
)
1471 writebytes
= This
->buflen
;
1473 assert(audiobytes1
!=audiobytes2
);
1474 assert(lplpaudioptr1
!=lplpaudioptr2
);
1476 if (This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
)
1477 capf
= DSDDESC_DONTNEEDPRIMARYLOCK
;
1479 capf
= DSDDESC_DONTNEEDSECONDARYLOCK
;
1480 if (!(This
->dsound
->drvdesc
.dwFlags
& capf
) && This
->hwbuf
) {
1481 IDsDriverBuffer_Lock(This
->hwbuf
,
1482 lplpaudioptr1
, audiobytes1
,
1483 lplpaudioptr2
, audiobytes2
,
1484 writecursor
, writebytes
,
1487 if (writecursor
+writebytes
<= This
->buflen
) {
1488 *(LPBYTE
*)lplpaudioptr1
= This
->buffer
+writecursor
;
1489 *audiobytes1
= writebytes
;
1491 *(LPBYTE
*)lplpaudioptr2
= NULL
;
1494 TRACE("->%ld.0\n",writebytes
);
1496 *(LPBYTE
*)lplpaudioptr1
= This
->buffer
+writecursor
;
1497 *audiobytes1
= This
->buflen
-writecursor
;
1499 *(LPBYTE
*)lplpaudioptr2
= This
->buffer
;
1501 *audiobytes2
= writebytes
-(This
->buflen
-writecursor
);
1502 TRACE("->%ld.%ld\n",*audiobytes1
,audiobytes2
?*audiobytes2
:0);
1507 static HRESULT WINAPI
IDirectSoundBufferImpl_SetCurrentPosition(
1508 LPDIRECTSOUNDBUFFER iface
,DWORD newpos
1510 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1511 TRACE("(%p,%ld)\n",This
,newpos
);
1514 EnterCriticalSection(&(This
->lock
));
1516 This
->mixpos
= newpos
;
1518 IDsDriverBuffer_SetPosition(This
->hwbuf
, This
->mixpos
);
1520 LeaveCriticalSection(&(This
->lock
));
1526 static HRESULT WINAPI
IDirectSoundBufferImpl_SetPan(
1527 LPDIRECTSOUNDBUFFER iface
,LONG pan
1529 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1531 TRACE("(%p,%ld)\n",This
,pan
);
1533 if ((pan
> DSBPAN_RIGHT
) || (pan
< DSBPAN_LEFT
))
1534 return DSERR_INVALIDPARAM
;
1536 /* You cannot set the pan of the primary buffer */
1537 /* and you cannot use both pan and 3D controls */
1538 if (!(This
->dsbd
.dwFlags
& DSBCAPS_CTRLPAN
) ||
1539 (This
->dsbd
.dwFlags
& DSBCAPS_CTRL3D
) ||
1540 (This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
))
1541 return DSERR_CONTROLUNAVAIL
;
1544 EnterCriticalSection(&(This
->lock
));
1546 This
->volpan
.lPan
= pan
;
1548 DSOUND_RecalcVolPan(&(This
->volpan
));
1551 IDsDriverBuffer_SetVolumePan(This
->hwbuf
, &(This
->volpan
));
1554 LeaveCriticalSection(&(This
->lock
));
1560 static HRESULT WINAPI
IDirectSoundBufferImpl_GetPan(
1561 LPDIRECTSOUNDBUFFER iface
,LPLONG pan
1563 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1564 TRACE("(%p,%p)\n",This
,pan
);
1567 return DSERR_INVALIDPARAM
;
1569 *pan
= This
->volpan
.lPan
;
1574 static HRESULT WINAPI
IDirectSoundBufferImpl_Unlock(
1575 LPDIRECTSOUNDBUFFER iface
,LPVOID p1
,DWORD x1
,LPVOID p2
,DWORD x2
1577 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1580 TRACE("(%p,%p,%ld,%p,%ld):stub\n", This
,p1
,x1
,p2
,x2
);
1583 /* Preprocess 3D buffers... */
1585 /* This is highly experimental and liable to break things */
1586 if (This
->dsbd
.dwFlags
& DSBCAPS_CTRL3D
)
1587 DSOUND_Create3DBuffer(This
);
1590 if (This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
)
1591 capf
= DSDDESC_DONTNEEDPRIMARYLOCK
;
1593 capf
= DSDDESC_DONTNEEDSECONDARYLOCK
;
1594 if (!(This
->dsound
->drvdesc
.dwFlags
& capf
) && This
->hwbuf
) {
1595 IDsDriverBuffer_Unlock(This
->hwbuf
, p1
, x1
, p2
, x2
);
1601 static HRESULT WINAPI
IDirectSoundBufferImpl_GetFrequency(
1602 LPDIRECTSOUNDBUFFER iface
,LPDWORD freq
1604 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1605 TRACE("(%p,%p)\n",This
,freq
);
1608 return DSERR_INVALIDPARAM
;
1611 TRACE("-> %ld\n", *freq
);
1616 static HRESULT WINAPI
IDirectSoundBufferImpl_Initialize(
1617 LPDIRECTSOUNDBUFFER iface
,LPDIRECTSOUND dsound
,LPDSBUFFERDESC dbsd
1619 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1620 FIXME("(%p,%p,%p):stub\n",This
,dsound
,dbsd
);
1621 DPRINTF("Re-Init!!!\n");
1622 return DSERR_ALREADYINITIALIZED
;
1625 static HRESULT WINAPI
IDirectSoundBufferImpl_GetCaps(
1626 LPDIRECTSOUNDBUFFER iface
,LPDSBCAPS caps
1628 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1629 TRACE("(%p)->(%p)\n",This
,caps
);
1632 return DSERR_INVALIDPARAM
;
1634 /* I think we should check this value, not set it. See */
1635 /* Inside DirectX, p215. That should apply here, too. */
1636 caps
->dwSize
= sizeof(*caps
);
1638 caps
->dwFlags
= This
->dsbd
.dwFlags
;
1639 if (This
->hwbuf
) caps
->dwFlags
|= DSBCAPS_LOCHARDWARE
;
1640 else caps
->dwFlags
|= DSBCAPS_LOCSOFTWARE
;
1642 caps
->dwBufferBytes
= This
->dsbd
.dwBufferBytes
;
1644 /* This value represents the speed of the "unlock" command.
1645 As unlock is quite fast (it does not do anything), I put
1646 4096 ko/s = 4 Mo / s */
1647 /* FIXME: hwbuf speed */
1648 caps
->dwUnlockTransferRate
= 4096;
1649 caps
->dwPlayCpuOverhead
= 0;
1654 static HRESULT WINAPI
IDirectSoundBufferImpl_QueryInterface(
1655 LPDIRECTSOUNDBUFFER iface
,REFIID riid
,LPVOID
*ppobj
1657 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1659 TRACE("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
1661 if ( IsEqualGUID( &IID_IDirectSoundNotify
, riid
) ) {
1662 IDirectSoundNotifyImpl
*dsn
;
1664 dsn
= (IDirectSoundNotifyImpl
*)HeapAlloc(GetProcessHeap(),0,sizeof(*dsn
));
1667 IDirectSoundBuffer_AddRef(iface
);
1668 ICOM_VTBL(dsn
) = &dsnvt
;
1669 *ppobj
= (LPVOID
)dsn
;
1674 if ( IsEqualGUID( &IID_IDirectSound3DBuffer
, riid
) ) {
1675 IDirectSound3DBufferImpl
*ds3db
;
1677 *ppobj
= This
->ds3db
;
1679 IDirectSound3DBuffer_AddRef((LPDIRECTSOUND3DBUFFER
)This
->ds3db
);
1683 ds3db
= (IDirectSound3DBufferImpl
*)HeapAlloc(GetProcessHeap(),
1686 ds3db
->dsb
= (*ippdsb
);
1687 ICOM_VTBL(ds3db
) = &ds3dbvt
;
1688 InitializeCriticalSection(&ds3db
->lock
);
1690 ds3db
->ds3db
= This
;
1691 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER
)This
);
1693 ds3db
->ds3db
.dwSize
= sizeof(DS3DBUFFER
);
1694 ds3db
->ds3db
.vPosition
.x
.x
= 0.0;
1695 ds3db
->ds3db
.vPosition
.y
.y
= 0.0;
1696 ds3db
->ds3db
.vPosition
.z
.z
= 0.0;
1697 ds3db
->ds3db
.vVelocity
.x
.x
= 0.0;
1698 ds3db
->ds3db
.vVelocity
.y
.y
= 0.0;
1699 ds3db
->ds3db
.vVelocity
.z
.z
= 0.0;
1700 ds3db
->ds3db
.dwInsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
1701 ds3db
->ds3db
.dwOutsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
1702 ds3db
->ds3db
.vConeOrientation
.x
.x
= 0.0;
1703 ds3db
->ds3db
.vConeOrientation
.y
.y
= 0.0;
1704 ds3db
->ds3db
.vConeOrientation
.z
.z
= 0.0;
1705 ds3db
->ds3db
.lConeOutsideVolume
= DS3D_DEFAULTCONEOUTSIDEVOLUME
; ds3db
->ds3db
.flMinDistance
= DS3D_DEFAULTMINDISTANCE
;
1706 ds3db
->ds3db
.flMaxDistance
= DS3D_DEFAULTMAXDISTANCE
;
1707 ds3db
->ds3db
.dwMode
= DS3DMODE_NORMAL
;
1708 ds3db
->buflen
= ((*ippdsb
)->buflen
* primarybuf
->wfx
.nBlockAlign
) /
1709 (*ippdsb
)->wfx
.nBlockAlign
;
1710 ds3db
->buffer
= HeapAlloc(GetProcessHeap(), 0, ds3db
->buflen
);
1711 if (ds3db
->buffer
== NULL
) {
1713 ds3db
->ds3db
.dwMode
= DS3DMODE_DISABLE
;
1720 if ( IsEqualGUID( &IID_IDirectSound3DListener
, riid
) ) {
1721 IDirectSound3DListenerImpl
* dsl
;
1723 if (This
->dsound
->listener
) {
1724 *ppobj
= This
->dsound
->listener
;
1725 IDirectSound3DListener_AddRef((LPDIRECTSOUND3DLISTENER
)This
->dsound
->listener
);
1729 dsl
= (IDirectSound3DListenerImpl
*)HeapAlloc(GetProcessHeap(),0,sizeof(*dsl
));
1731 ICOM_VTBL(dsl
) = &ds3dlvt
;
1732 *ppobj
= (LPVOID
)dsl
;
1734 dsl
->ds3dl
.dwSize
= sizeof(DS3DLISTENER
);
1735 dsl
->ds3dl
.vPosition
.u1
.x
= 0.0;
1736 dsl
->ds3dl
.vPosition
.u2
.y
= 0.0;
1737 dsl
->ds3dl
.vPosition
.u3
.z
= 0.0;
1738 dsl
->ds3dl
.vVelocity
.u1
.x
= 0.0;
1739 dsl
->ds3dl
.vVelocity
.u2
.y
= 0.0;
1740 dsl
->ds3dl
.vVelocity
.u3
.z
= 0.0;
1741 dsl
->ds3dl
.vOrientFront
.u1
.x
= 0.0;
1742 dsl
->ds3dl
.vOrientFront
.u2
.y
= 0.0;
1743 dsl
->ds3dl
.vOrientFront
.u3
.z
= 1.0;
1744 dsl
->ds3dl
.vOrientTop
.u1
.x
= 0.0;
1745 dsl
->ds3dl
.vOrientTop
.u2
.y
= 1.0;
1746 dsl
->ds3dl
.vOrientTop
.u3
.z
= 0.0;
1747 dsl
->ds3dl
.flDistanceFactor
= DS3D_DEFAULTDISTANCEFACTOR
;
1748 dsl
->ds3dl
.flRolloffFactor
= DS3D_DEFAULTROLLOFFFACTOR
;
1750 InitializeCriticalSection(&dsl
->lock
);
1753 IDirectSoundBuffer_AddRef(iface
);
1755 This
->dsound
->listener
= dsl
;
1756 IDirectSound3DListener_AddRef((LPDIRECTSOUND3DLISTENER
)dsl
);
1761 FIXME( "Unknown GUID %s\n", debugstr_guid( riid
) );
1768 static ICOM_VTABLE(IDirectSoundBuffer
) dsbvt
=
1770 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1771 IDirectSoundBufferImpl_QueryInterface
,
1772 IDirectSoundBufferImpl_AddRef
,
1773 IDirectSoundBufferImpl_Release
,
1774 IDirectSoundBufferImpl_GetCaps
,
1775 IDirectSoundBufferImpl_GetCurrentPosition
,
1776 IDirectSoundBufferImpl_GetFormat
,
1777 IDirectSoundBufferImpl_GetVolume
,
1778 IDirectSoundBufferImpl_GetPan
,
1779 IDirectSoundBufferImpl_GetFrequency
,
1780 IDirectSoundBufferImpl_GetStatus
,
1781 IDirectSoundBufferImpl_Initialize
,
1782 IDirectSoundBufferImpl_Lock
,
1783 IDirectSoundBufferImpl_Play
,
1784 IDirectSoundBufferImpl_SetCurrentPosition
,
1785 IDirectSoundBufferImpl_SetFormat
,
1786 IDirectSoundBufferImpl_SetVolume
,
1787 IDirectSoundBufferImpl_SetPan
,
1788 IDirectSoundBufferImpl_SetFrequency
,
1789 IDirectSoundBufferImpl_Stop
,
1790 IDirectSoundBufferImpl_Unlock
1793 /*******************************************************************************
1797 static HRESULT WINAPI
IDirectSoundImpl_SetCooperativeLevel(
1798 LPDIRECTSOUND iface
,HWND hwnd
,DWORD level
1800 ICOM_THIS(IDirectSoundImpl
,iface
);
1802 FIXME("(%p,%08lx,%ld):stub\n",This
,(DWORD
)hwnd
,level
);
1804 This
->priolevel
= level
;
1809 static HRESULT WINAPI
IDirectSoundImpl_CreateSoundBuffer(
1810 LPDIRECTSOUND iface
,LPDSBUFFERDESC dsbd
,LPLPDIRECTSOUNDBUFFER ppdsb
,LPUNKNOWN lpunk
1812 ICOM_THIS(IDirectSoundImpl
,iface
);
1813 IDirectSoundBufferImpl
** ippdsb
=(IDirectSoundBufferImpl
**)ppdsb
;
1814 LPWAVEFORMATEX wfex
;
1815 HRESULT err
= DS_OK
;
1817 TRACE("(%p,%p,%p,%p)\n",This
,dsbd
,ippdsb
,lpunk
);
1819 if ((This
== NULL
) || (dsbd
== NULL
) || (ippdsb
== NULL
))
1820 return DSERR_INVALIDPARAM
;
1822 if (TRACE_ON(dsound
)) {
1823 TRACE("(structsize=%ld)\n",dsbd
->dwSize
);
1824 TRACE("(flags=0x%08lx:\n",dsbd
->dwFlags
);
1825 _dump_DSBCAPS(dsbd
->dwFlags
);
1827 TRACE("(bufferbytes=%ld)\n",dsbd
->dwBufferBytes
);
1828 TRACE("(lpwfxFormat=%p)\n",dsbd
->lpwfxFormat
);
1831 wfex
= dsbd
->lpwfxFormat
;
1834 TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld,"
1835 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
1836 wfex
->wFormatTag
, wfex
->nChannels
, wfex
->nSamplesPerSec
,
1837 wfex
->nAvgBytesPerSec
, wfex
->nBlockAlign
,
1838 wfex
->wBitsPerSample
, wfex
->cbSize
);
1840 if (dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
1842 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER
)primarybuf
);
1843 *ippdsb
= primarybuf
;
1844 primarybuf
->dsbd
.dwFlags
= dsbd
->dwFlags
;
1846 } /* Else create primary buffer */
1849 *ippdsb
= (IDirectSoundBufferImpl
*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDirectSoundBufferImpl
));
1850 if (*ippdsb
== NULL
)
1851 return DSERR_OUTOFMEMORY
;
1852 ICOM_VTBL(*ippdsb
) = &dsbvt
;
1854 (*ippdsb
)->dsound
= This
;
1855 (*ippdsb
)->parent
= NULL
;
1856 (*ippdsb
)->buffer
= NULL
;
1858 memcpy(&((*ippdsb
)->dsbd
),dsbd
,sizeof(*dsbd
));
1859 if (dsbd
->lpwfxFormat
)
1860 memcpy(&((*ippdsb
)->wfx
), dsbd
->lpwfxFormat
, sizeof((*ippdsb
)->wfx
));
1862 TRACE("Created buffer at %p\n", *ippdsb
);
1864 if (dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
1865 (*ippdsb
)->buflen
= dsound
->wfx
.nAvgBytesPerSec
;
1866 (*ippdsb
)->freq
= dsound
->wfx
.nSamplesPerSec
;
1868 /* FIXME: verify that hardware capabilities (DSCAPS_PRIMARY flags) match */
1871 err
= IDsDriver_CreateSoundBuffer(This
->driver
,wfex
,dsbd
->dwFlags
,0,
1872 &((*ippdsb
)->buflen
),&((*ippdsb
)->buffer
),
1873 (LPVOID
*)&((*ippdsb
)->hwbuf
));
1876 err
= DSOUND_PrimaryOpen(*ippdsb
);
1881 (*ippdsb
)->buflen
= dsbd
->dwBufferBytes
;
1882 (*ippdsb
)->freq
= dsbd
->lpwfxFormat
->nSamplesPerSec
;
1884 /* Check necessary hardware mixing capabilities */
1885 if (wfex
->nChannels
==2) capf
|= DSCAPS_SECONDARYSTEREO
;
1886 else capf
|= DSCAPS_SECONDARYMONO
;
1887 if (wfex
->wBitsPerSample
==16) capf
|= DSCAPS_SECONDARY16BIT
;
1888 else capf
|= DSCAPS_SECONDARY8BIT
;
1889 use_hw
= (This
->drvcaps
.dwFlags
& capf
) == capf
;
1891 /* FIXME: check hardware sample rate mixing capabilities */
1892 /* FIXME: check app hints for software/hardware buffer (STATIC, LOCHARDWARE, etc) */
1893 /* FIXME: check whether any hardware buffers are left */
1894 /* FIXME: handle DSDHEAP_CREATEHEAP for hardware buffers */
1896 /* Allocate system memory if applicable */
1897 if ((This
->drvdesc
.dwFlags
& DSDDESC_USESYSTEMMEMORY
) || !use_hw
) {
1898 (*ippdsb
)->buffer
= (LPBYTE
)HeapAlloc(GetProcessHeap(),0,(*ippdsb
)->buflen
);
1899 if ((*ippdsb
)->buffer
== NULL
)
1900 err
= DSERR_OUTOFMEMORY
;
1903 /* Allocate the hardware buffer */
1904 if (use_hw
&& (err
== DS_OK
)) {
1905 err
= IDsDriver_CreateSoundBuffer(This
->driver
,wfex
,dsbd
->dwFlags
,0,
1906 &((*ippdsb
)->buflen
),&((*ippdsb
)->buffer
),
1907 (LPVOID
*)&((*ippdsb
)->hwbuf
));
1912 if ((*ippdsb
)->buffer
)
1913 HeapFree(GetProcessHeap(),0,(*ippdsb
)->buffer
);
1914 HeapFree(GetProcessHeap(),0,(*ippdsb
));
1918 /* calculate fragment size and write lead */
1919 DSOUND_RecalcFormat(*ippdsb
);
1921 /* It's not necessary to initialize values to zero since */
1922 /* we allocated this structure with HEAP_ZERO_MEMORY... */
1923 (*ippdsb
)->playpos
= 0;
1924 (*ippdsb
)->mixpos
= 0;
1925 (*ippdsb
)->state
= STATE_STOPPED
;
1926 DSOUND_RecalcVolPan(&((*ippdsb
)->volpan
));
1928 if (!(dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
)) {
1929 (*ippdsb
)->freqAdjust
= ((*ippdsb
)->freq
<< DSOUND_FREQSHIFT
) /
1930 primarybuf
->wfx
.nSamplesPerSec
;
1931 (*ippdsb
)->nAvgBytesPerSec
= (*ippdsb
)->freq
*
1932 dsbd
->lpwfxFormat
->nBlockAlign
;
1935 EnterCriticalSection(&(This
->lock
));
1936 /* register buffer */
1937 if (!(dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
)) {
1938 IDirectSoundBufferImpl
**newbuffers
= (IDirectSoundBufferImpl
**)HeapReAlloc(GetProcessHeap(),0,This
->buffers
,sizeof(IDirectSoundBufferImpl
*)*(This
->nrofbuffers
+1));
1940 This
->buffers
= newbuffers
;
1941 This
->buffers
[This
->nrofbuffers
] = *ippdsb
;
1942 This
->nrofbuffers
++;
1943 TRACE("buffer count is now %d\n", This
->nrofbuffers
);
1945 ERR("out of memory for buffer list! Current buffer count is %d\n", This
->nrofbuffers
);
1946 err
= DSERR_OUTOFMEMORY
;
1949 LeaveCriticalSection(&(This
->lock
));
1951 IDirectSound_AddRef(iface
);
1953 InitializeCriticalSection(&((*ippdsb
)->lock
));
1957 IDirectSoundBuffer_Release(*ppdsb
);
1963 if (dsbd
->dwFlags
& DSBCAPS_CTRL3D
) {
1964 IDirectSound3DBufferImpl
*ds3db
;
1966 ds3db
= (IDirectSound3DBufferImpl
*)HeapAlloc(GetProcessHeap(),
1968 ICOM_VTBL(ds3db
) = &ds3dbvt
;
1970 (*ippdsb
)->ds3db
= ds3db
;
1972 ds3db
->dsb
= (*ippdsb
);
1973 IDirectSoundBufferImpl_AddRef((LPDIRECTSOUNDBUFFER
)ippdsb
);
1975 InitializeCriticalSection(&ds3db
->lock
);
1977 ds3db
->ds3db
.dwSize
= sizeof(DS3DBUFFER
);
1978 ds3db
->ds3db
.vPosition
.x
.x
= 0.0;
1979 ds3db
->ds3db
.vPosition
.y
.y
= 0.0;
1980 ds3db
->ds3db
.vPosition
.z
.z
= 0.0;
1981 ds3db
->ds3db
.vVelocity
.x
.x
= 0.0;
1982 ds3db
->ds3db
.vVelocity
.y
.y
= 0.0;
1983 ds3db
->ds3db
.vVelocity
.z
.z
= 0.0;
1984 ds3db
->ds3db
.dwInsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
1985 ds3db
->ds3db
.dwOutsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
1986 ds3db
->ds3db
.vConeOrientation
.x
.x
= 0.0;
1987 ds3db
->ds3db
.vConeOrientation
.y
.y
= 0.0;
1988 ds3db
->ds3db
.vConeOrientation
.z
.z
= 0.0;
1989 ds3db
->ds3db
.lConeOutsideVolume
= DS3D_DEFAULTCONEOUTSIDEVOLUME
;
1990 ds3db
->ds3db
.flMinDistance
= DS3D_DEFAULTMINDISTANCE
;
1991 ds3db
->ds3db
.flMaxDistance
= DS3D_DEFAULTMAXDISTANCE
;
1992 ds3db
->ds3db
.dwMode
= DS3DMODE_NORMAL
;
1993 ds3db
->buflen
= ((*ippdsb
)->buflen
* primarybuf
->wfx
.nBlockAlign
) /
1994 (*ippdsb
)->wfx
.nBlockAlign
;
1995 ds3db
->buffer
= HeapAlloc(GetProcessHeap(), 0, ds3db
->buflen
);
1996 if (ds3db
->buffer
== NULL
) {
1998 ds3db
->ds3db
.dwMode
= DS3DMODE_DISABLE
;
2005 static HRESULT WINAPI
IDirectSoundImpl_DuplicateSoundBuffer(
2006 LPDIRECTSOUND iface
,LPDIRECTSOUNDBUFFER pdsb
,LPLPDIRECTSOUNDBUFFER ppdsb
2008 ICOM_THIS(IDirectSoundImpl
,iface
);
2009 IDirectSoundBufferImpl
* ipdsb
=(IDirectSoundBufferImpl
*)pdsb
;
2010 IDirectSoundBufferImpl
** ippdsb
=(IDirectSoundBufferImpl
**)ppdsb
;
2011 TRACE("(%p,%p,%p)\n",This
,ipdsb
,ippdsb
);
2014 FIXME("need to duplicate hardware buffer\n");
2017 *ippdsb
= (IDirectSoundBufferImpl
*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDirectSoundBufferImpl
));
2019 IDirectSoundBuffer_AddRef(pdsb
);
2020 memcpy(*ippdsb
, ipdsb
, sizeof(IDirectSoundBufferImpl
));
2022 (*ippdsb
)->playpos
= 0;
2023 (*ippdsb
)->mixpos
= 0;
2024 (*ippdsb
)->dsound
= This
;
2025 (*ippdsb
)->parent
= ipdsb
;
2026 memcpy(&((*ippdsb
)->wfx
), &(ipdsb
->wfx
), sizeof((*ippdsb
)->wfx
));
2027 InitializeCriticalSection(&(*ippdsb
)->lock
);
2028 /* register buffer */
2029 EnterCriticalSection(&(This
->lock
));
2031 IDirectSoundBufferImpl
**newbuffers
= (IDirectSoundBufferImpl
**)HeapReAlloc(GetProcessHeap(),0,This
->buffers
,sizeof(IDirectSoundBufferImpl
**)*(This
->nrofbuffers
+1));
2033 This
->buffers
= newbuffers
;
2034 This
->buffers
[This
->nrofbuffers
] = *ippdsb
;
2035 This
->nrofbuffers
++;
2036 TRACE("buffer count is now %d\n", This
->nrofbuffers
);
2038 ERR("out of memory for buffer list! Current buffer count is %d\n", This
->nrofbuffers
);
2039 /* FIXME: release buffer */
2042 LeaveCriticalSection(&(This
->lock
));
2043 IDirectSound_AddRef(iface
);
2048 static HRESULT WINAPI
IDirectSoundImpl_GetCaps(LPDIRECTSOUND iface
,LPDSCAPS caps
) {
2049 ICOM_THIS(IDirectSoundImpl
,iface
);
2050 TRACE("(%p,%p)\n",This
,caps
);
2051 TRACE("(flags=0x%08lx)\n",caps
->dwFlags
);
2054 return DSERR_INVALIDPARAM
;
2056 /* We should check this value, not set it. See Inside DirectX, p215. */
2057 caps
->dwSize
= sizeof(*caps
);
2059 caps
->dwFlags
= This
->drvcaps
.dwFlags
;
2061 /* FIXME: copy caps from This->drvcaps */
2062 caps
->dwMinSecondarySampleRate
= DSBFREQUENCY_MIN
;
2063 caps
->dwMaxSecondarySampleRate
= DSBFREQUENCY_MAX
;
2065 caps
->dwPrimaryBuffers
= 1;
2067 caps
->dwMaxHwMixingAllBuffers
= 0;
2068 caps
->dwMaxHwMixingStaticBuffers
= 0;
2069 caps
->dwMaxHwMixingStreamingBuffers
= 0;
2071 caps
->dwFreeHwMixingAllBuffers
= 0;
2072 caps
->dwFreeHwMixingStaticBuffers
= 0;
2073 caps
->dwFreeHwMixingStreamingBuffers
= 0;
2075 caps
->dwMaxHw3DAllBuffers
= 0;
2076 caps
->dwMaxHw3DStaticBuffers
= 0;
2077 caps
->dwMaxHw3DStreamingBuffers
= 0;
2079 caps
->dwFreeHw3DAllBuffers
= 0;
2080 caps
->dwFreeHw3DStaticBuffers
= 0;
2081 caps
->dwFreeHw3DStreamingBuffers
= 0;
2083 caps
->dwTotalHwMemBytes
= 0;
2085 caps
->dwFreeHwMemBytes
= 0;
2087 caps
->dwMaxContigFreeHwMemBytes
= 0;
2089 caps
->dwUnlockTransferRateHwBuffers
= 4096; /* But we have none... */
2091 caps
->dwPlayCpuOverheadSwBuffers
= 1; /* 1% */
2096 static ULONG WINAPI
IDirectSoundImpl_AddRef(LPDIRECTSOUND iface
) {
2097 ICOM_THIS(IDirectSoundImpl
,iface
);
2098 return ++(This
->ref
);
2101 static ULONG WINAPI
IDirectSoundImpl_Release(LPDIRECTSOUND iface
) {
2102 ICOM_THIS(IDirectSoundImpl
,iface
);
2103 TRACE("(%p), ref was %ld\n",This
,This
->ref
);
2104 if (!--(This
->ref
)) {
2107 timeKillEvent(This
->timerID
);
2108 timeEndPeriod(DS_TIME_RES
);
2111 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)primarybuf
);
2113 if (This
->buffers
) {
2114 for( i
=0;i
<This
->nrofbuffers
;i
++)
2115 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)This
->buffers
[i
]);
2119 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)This
->primary
);
2121 DeleteCriticalSection(&This
->lock
);
2123 IDsDriver_Close(This
->driver
);
2126 for (c
=0; c
<DS_HEL_FRAGS
; c
++)
2127 HeapFree(GetProcessHeap(),0,This
->pwave
[c
]);
2129 if (This
->drvdesc
.dwFlags
& DSDDESC_DOMMSYSTEMOPEN
) {
2130 waveOutClose(This
->hwo
);
2133 IDsDriver_Release(This
->driver
);
2135 HeapFree(GetProcessHeap(),0,This
);
2142 static HRESULT WINAPI
IDirectSoundImpl_SetSpeakerConfig(
2143 LPDIRECTSOUND iface
,DWORD config
2145 ICOM_THIS(IDirectSoundImpl
,iface
);
2146 FIXME("(%p,0x%08lx):stub\n",This
,config
);
2150 static HRESULT WINAPI
IDirectSoundImpl_QueryInterface(
2151 LPDIRECTSOUND iface
,REFIID riid
,LPVOID
*ppobj
2153 ICOM_THIS(IDirectSoundImpl
,iface
);
2155 if ( IsEqualGUID( &IID_IDirectSound3DListener
, riid
) ) {
2157 if (This
->listener
) {
2158 *ppobj
= This
->listener
;
2159 IDirectSound3DListener_AddRef((LPDIRECTSOUND3DLISTENER
)This
->listener
);
2163 This
->listener
= (IDirectSound3DListenerImpl
*)HeapAlloc(
2164 GetProcessHeap(), 0, sizeof(*(This
->listener
)));
2165 This
->listener
->ref
= 1;
2166 ICOM_VTBL(This
->listener
) = &ds3dlvt
;
2167 *ppobj
= (LPVOID
)This
->listener
;
2168 IDirectSound3DListener_AddRef((LPDIRECTSOUND3DLISTENER
)*ppobj
);
2170 This
->listener
->dsb
= NULL
;
2172 This
->listener
->ds3dl
.dwSize
= sizeof(DS3DLISTENER
);
2173 This
->listener
->ds3dl
.vPosition
.u1
.x
= 0.0;
2174 This
->listener
->ds3dl
.vPosition
.u2
.y
= 0.0;
2175 This
->listener
->ds3dl
.vPosition
.u3
.z
= 0.0;
2176 This
->listener
->ds3dl
.vVelocity
.u1
.x
= 0.0;
2177 This
->listener
->ds3dl
.vVelocity
.u2
.y
= 0.0;
2178 This
->listener
->ds3dl
.vVelocity
.u3
.z
= 0.0;
2179 This
->listener
->ds3dl
.vOrientFront
.u1
.x
= 0.0;
2180 This
->listener
->ds3dl
.vOrientFront
.u2
.y
= 0.0;
2181 This
->listener
->ds3dl
.vOrientFront
.u3
.z
= 1.0;
2182 This
->listener
->ds3dl
.vOrientTop
.u1
.x
= 0.0;
2183 This
->listener
->ds3dl
.vOrientTop
.u2
.y
= 1.0;
2184 This
->listener
->ds3dl
.vOrientTop
.u3
.z
= 0.0;
2185 This
->listener
->ds3dl
.flDistanceFactor
= DS3D_DEFAULTDISTANCEFACTOR
;
2186 This
->listener
->ds3dl
.flRolloffFactor
= DS3D_DEFAULTROLLOFFFACTOR
;
2187 This
->listener
->ds3dl
.flDopplerFactor
= DS3D_DEFAULTDOPPLERFACTOR
;
2189 InitializeCriticalSection(&This
->listener
->lock
);
2194 FIXME("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
2198 static HRESULT WINAPI
IDirectSoundImpl_Compact(
2199 LPDIRECTSOUND iface
)
2201 ICOM_THIS(IDirectSoundImpl
,iface
);
2202 TRACE("(%p)\n", This
);
2206 static HRESULT WINAPI
IDirectSoundImpl_GetSpeakerConfig(
2207 LPDIRECTSOUND iface
,
2208 LPDWORD lpdwSpeakerConfig
)
2210 ICOM_THIS(IDirectSoundImpl
,iface
);
2211 TRACE("(%p, %p)\n", This
, lpdwSpeakerConfig
);
2212 *lpdwSpeakerConfig
= DSSPEAKER_STEREO
| (DSSPEAKER_GEOMETRY_NARROW
<< 16);
2216 static HRESULT WINAPI
IDirectSoundImpl_Initialize(
2217 LPDIRECTSOUND iface
,
2220 ICOM_THIS(IDirectSoundImpl
,iface
);
2221 TRACE("(%p, %p)\n", This
, lpcGuid
);
2225 static ICOM_VTABLE(IDirectSound
) dsvt
=
2227 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
2228 IDirectSoundImpl_QueryInterface
,
2229 IDirectSoundImpl_AddRef
,
2230 IDirectSoundImpl_Release
,
2231 IDirectSoundImpl_CreateSoundBuffer
,
2232 IDirectSoundImpl_GetCaps
,
2233 IDirectSoundImpl_DuplicateSoundBuffer
,
2234 IDirectSoundImpl_SetCooperativeLevel
,
2235 IDirectSoundImpl_Compact
,
2236 IDirectSoundImpl_GetSpeakerConfig
,
2237 IDirectSoundImpl_SetSpeakerConfig
,
2238 IDirectSoundImpl_Initialize
2242 static void DSOUND_CheckEvent(IDirectSoundBufferImpl
*dsb
, int len
)
2246 LPDSBPOSITIONNOTIFY event
;
2248 if (dsb
->nrofnotifies
== 0)
2251 TRACE("(%p) buflen = %ld, playpos = %ld, len = %d\n",
2252 dsb
, dsb
->buflen
, dsb
->playpos
, len
);
2253 for (i
= 0; i
< dsb
->nrofnotifies
; i
++) {
2254 event
= dsb
->notifies
+ i
;
2255 offset
= event
->dwOffset
;
2256 TRACE("checking %d, position %ld, event = %d\n",
2257 i
, offset
, event
->hEventNotify
);
2258 /* DSBPN_OFFSETSTOP has to be the last element. So this is */
2259 /* OK. [Inside DirectX, p274] */
2261 /* This also means we can't sort the entries by offset, */
2262 /* because DSBPN_OFFSETSTOP == -1 */
2263 if (offset
== DSBPN_OFFSETSTOP
) {
2264 if (dsb
->state
== STATE_STOPPED
) {
2265 SetEvent(event
->hEventNotify
);
2266 TRACE("signalled event %d (%d)\n", event
->hEventNotify
, i
);
2271 if ((dsb
->playpos
+ len
) >= dsb
->buflen
) {
2272 if ((offset
< ((dsb
->playpos
+ len
) % dsb
->buflen
)) ||
2273 (offset
>= dsb
->playpos
)) {
2274 TRACE("signalled event %d (%d)\n", event
->hEventNotify
, i
);
2275 SetEvent(event
->hEventNotify
);
2278 if ((offset
>= dsb
->playpos
) && (offset
< (dsb
->playpos
+ len
))) {
2279 TRACE("signalled event %d (%d)\n", event
->hEventNotify
, i
);
2280 SetEvent(event
->hEventNotify
);
2286 /* WAV format info can be found at: */
2288 /* http://www.cwi.nl/ftp/audio/AudioFormats.part2 */
2289 /* ftp://ftp.cwi.nl/pub/audio/RIFF-format */
2291 /* Import points to remember: */
2293 /* 8-bit WAV is unsigned */
2294 /* 16-bit WAV is signed */
2296 static inline INT16
cvtU8toS16(BYTE byte
)
2298 INT16 s
= (byte
- 128) << 8;
2303 static inline BYTE
cvtS16toU8(INT16 word
)
2305 BYTE b
= (word
+ 32768) >> 8;
2311 /* We should be able to optimize these two inline functions */
2312 /* so that we aren't doing 8->16->8 conversions when it is */
2313 /* not necessary. But this is still a WIP. Optimize later. */
2314 static inline void get_fields(const IDirectSoundBufferImpl
*dsb
, BYTE
*buf
, INT
*fl
, INT
*fr
)
2316 INT16
*bufs
= (INT16
*) buf
;
2318 /* TRACE("(%p)", buf); */
2319 if ((dsb
->wfx
.wBitsPerSample
== 8) && dsb
->wfx
.nChannels
== 2) {
2320 *fl
= cvtU8toS16(*buf
);
2321 *fr
= cvtU8toS16(*(buf
+ 1));
2325 if ((dsb
->wfx
.wBitsPerSample
== 16) && dsb
->wfx
.nChannels
== 2) {
2331 if ((dsb
->wfx
.wBitsPerSample
== 8) && dsb
->wfx
.nChannels
== 1) {
2332 *fl
= cvtU8toS16(*buf
);
2337 if ((dsb
->wfx
.wBitsPerSample
== 16) && dsb
->wfx
.nChannels
== 1) {
2343 FIXME("get_fields found an unsupported configuration\n");
2347 static inline void set_fields(BYTE
*buf
, INT fl
, INT fr
)
2349 INT16
*bufs
= (INT16
*) buf
;
2351 if ((primarybuf
->wfx
.wBitsPerSample
== 8) && (primarybuf
->wfx
.nChannels
== 2)) {
2352 *buf
= cvtS16toU8(fl
);
2353 *(buf
+ 1) = cvtS16toU8(fr
);
2357 if ((primarybuf
->wfx
.wBitsPerSample
== 16) && (primarybuf
->wfx
.nChannels
== 2)) {
2363 if ((primarybuf
->wfx
.wBitsPerSample
== 8) && (primarybuf
->wfx
.nChannels
== 1)) {
2364 *buf
= cvtS16toU8((fl
+ fr
) >> 1);
2368 if ((primarybuf
->wfx
.wBitsPerSample
== 16) && (primarybuf
->wfx
.nChannels
== 1)) {
2369 *bufs
= (fl
+ fr
) >> 1;
2372 FIXME("set_fields found an unsupported configuration\n");
2376 /* Now with PerfectPitch (tm) technology */
2377 static INT
DSOUND_MixerNorm(IDirectSoundBufferImpl
*dsb
, BYTE
*buf
, INT len
)
2379 INT i
, size
, ipos
, ilen
, fieldL
, fieldR
;
2381 INT iAdvance
= dsb
->wfx
.nBlockAlign
;
2382 INT oAdvance
= primarybuf
->wfx
.nBlockAlign
;
2384 ibp
= dsb
->buffer
+ dsb
->mixpos
;
2387 TRACE("(%p, %p, %p), mixpos=%ld\n", dsb
, ibp
, obp
, dsb
->mixpos
);
2388 /* Check for the best case */
2389 if ((dsb
->freq
== primarybuf
->wfx
.nSamplesPerSec
) &&
2390 (dsb
->wfx
.wBitsPerSample
== primarybuf
->wfx
.wBitsPerSample
) &&
2391 (dsb
->wfx
.nChannels
== primarybuf
->wfx
.nChannels
)) {
2392 DWORD bytesleft
= dsb
->buflen
- dsb
->mixpos
;
2393 TRACE("(%p) Best case\n", dsb
);
2394 if (len
<= bytesleft
)
2395 memcpy(obp
, ibp
, len
);
2397 memcpy(obp
, ibp
, bytesleft
);
2398 memcpy(obp
+ bytesleft
, dsb
->buffer
, len
- bytesleft
);
2403 /* Check for same sample rate */
2404 if (dsb
->freq
== primarybuf
->wfx
.nSamplesPerSec
) {
2405 TRACE("(%p) Same sample rate %ld = primary %ld\n", dsb
,
2406 dsb
->freq
, primarybuf
->wfx
.nSamplesPerSec
);
2408 for (i
= 0; i
< len
; i
+= oAdvance
) {
2409 get_fields(dsb
, ibp
, &fieldL
, &fieldR
);
2412 set_fields(obp
, fieldL
, fieldR
);
2414 if (ibp
>= (BYTE
*)(dsb
->buffer
+ dsb
->buflen
))
2415 ibp
= dsb
->buffer
; /* wrap */
2420 /* Mix in different sample rates */
2422 /* New PerfectPitch(tm) Technology (c) 1998 Rob Riggs */
2423 /* Patent Pending :-] */
2425 TRACE("(%p) Adjusting frequency: %ld -> %ld\n",
2426 dsb
, dsb
->freq
, primarybuf
->wfx
.nSamplesPerSec
);
2428 size
= len
/ oAdvance
;
2429 ilen
= ((size
* dsb
->freqAdjust
) >> DSOUND_FREQSHIFT
) * iAdvance
;
2430 for (i
= 0; i
< size
; i
++) {
2432 ipos
= (((i
* dsb
->freqAdjust
) >> DSOUND_FREQSHIFT
) * iAdvance
) + dsb
->mixpos
;
2434 if (ipos
>= dsb
->buflen
)
2435 ipos
%= dsb
->buflen
; /* wrap */
2437 get_fields(dsb
, (dsb
->buffer
+ ipos
), &fieldL
, &fieldR
);
2438 set_fields(obp
, fieldL
, fieldR
);
2444 static void DSOUND_MixerVol(IDirectSoundBufferImpl
*dsb
, BYTE
*buf
, INT len
)
2446 INT i
, inc
= primarybuf
->wfx
.wBitsPerSample
>> 3;
2448 INT16
*bps
= (INT16
*) buf
;
2450 TRACE("(%p) left = %lx, right = %lx\n", dsb
,
2451 dsb
->volpan
.dwTotalLeftAmpFactor
, dsb
->volpan
.dwTotalRightAmpFactor
);
2452 if ((!(dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLPAN
) || (dsb
->volpan
.lPan
== 0)) &&
2453 (!(dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLVOLUME
) || (dsb
->volpan
.lVolume
== 0)) &&
2454 !(dsb
->dsbd
.dwFlags
& DSBCAPS_CTRL3D
))
2455 return; /* Nothing to do */
2457 /* If we end up with some bozo coder using panning or 3D sound */
2458 /* with a mono primary buffer, it could sound very weird using */
2459 /* this method. Oh well, tough patooties. */
2461 for (i
= 0; i
< len
; i
+= inc
) {
2467 /* 8-bit WAV is unsigned, but we need to operate */
2468 /* on signed data for this to work properly */
2470 val
= ((val
* (i
& inc
? dsb
->volpan
.dwTotalRightAmpFactor
: dsb
->volpan
.dwTotalLeftAmpFactor
)) >> 16);
2475 /* 16-bit WAV is signed -- much better */
2477 val
= ((val
* ((i
& inc
) ? dsb
->volpan
.dwTotalRightAmpFactor
: dsb
->volpan
.dwTotalLeftAmpFactor
)) >> 16);
2483 FIXME("MixerVol had a nasty error\n");
2489 static void DSOUND_Mixer3D(IDirectSoundBufferImpl
*dsb
, BYTE
*buf
, INT len
)
2492 DWORD buflen
, mixpos
;
2494 buflen
= dsb
->ds3db
->buflen
;
2495 mixpos
= (dsb
->mixpos
* primarybuf
->wfx
.nBlockAlign
) / dsb
->wfx
.nBlockAlign
;
2496 ibp
= dsb
->ds3db
->buffer
+ mixpos
;
2499 if (mixpos
> buflen
) {
2500 FIXME("Major breakage");
2504 if (len
<= (mixpos
+ buflen
))
2505 memcpy(obp
, ibp
, len
);
2507 memcpy(obp
, ibp
, buflen
- mixpos
);
2508 memcpy(obp
+ (buflen
- mixpos
),
2510 len
- (buflen
- mixpos
));
2516 static void *tmp_buffer
;
2517 static size_t tmp_buffer_len
= 0;
2519 static void *DSOUND_tmpbuffer(size_t len
)
2521 if (len
>tmp_buffer_len
) {
2522 void *new_buffer
= realloc(tmp_buffer
, len
);
2524 tmp_buffer
= new_buffer
;
2525 tmp_buffer_len
= len
;
2532 static DWORD
DSOUND_MixInBuffer(IDirectSoundBufferImpl
*dsb
, DWORD writepos
, DWORD fraglen
)
2534 INT i
, len
, ilen
, temp
, field
;
2535 INT advance
= primarybuf
->wfx
.wBitsPerSample
>> 3;
2536 BYTE
*buf
, *ibuf
, *obuf
;
2537 INT16
*ibufs
, *obufs
;
2540 if (!(dsb
->playflags
& DSBPLAY_LOOPING
)) {
2541 temp
= MulDiv(primarybuf
->wfx
.nAvgBytesPerSec
, dsb
->buflen
,
2542 dsb
->nAvgBytesPerSec
) -
2543 MulDiv(primarybuf
->wfx
.nAvgBytesPerSec
, dsb
->mixpos
,
2544 dsb
->nAvgBytesPerSec
);
2545 len
= (len
> temp
) ? temp
: len
;
2547 len
&= ~3; /* 4 byte alignment */
2550 /* This should only happen if we aren't looping and temp < 4 */
2552 /* We skip the remainder, so check for possible events */
2553 DSOUND_CheckEvent(dsb
, dsb
->buflen
- dsb
->mixpos
);
2555 dsb
->state
= STATE_STOPPED
;
2558 dsb
->leadin
= FALSE
;
2559 /* Check for DSBPN_OFFSETSTOP */
2560 DSOUND_CheckEvent(dsb
, 0);
2564 /* Been seeing segfaults in malloc() for some reason... */
2565 TRACE("allocating buffer (size = %d)\n", len
);
2566 if ((buf
= ibuf
= (BYTE
*) DSOUND_tmpbuffer(len
)) == NULL
)
2569 TRACE("MixInBuffer (%p) len = %d, dest = %ld\n", dsb
, len
, writepos
);
2571 ilen
= DSOUND_MixerNorm(dsb
, ibuf
, len
);
2572 if ((dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLPAN
) ||
2573 (dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLVOLUME
))
2574 DSOUND_MixerVol(dsb
, ibuf
, len
);
2576 obuf
= primarybuf
->buffer
+ writepos
;
2577 for (i
= 0; i
< len
; i
+= advance
) {
2578 obufs
= (INT16
*) obuf
;
2579 ibufs
= (INT16
*) ibuf
;
2580 if (primarybuf
->wfx
.wBitsPerSample
== 8) {
2581 /* 8-bit WAV is unsigned */
2582 field
= (*ibuf
- 128);
2583 field
+= (*obuf
- 128);
2584 field
= field
> 127 ? 127 : field
;
2585 field
= field
< -128 ? -128 : field
;
2586 *obuf
= field
+ 128;
2588 /* 16-bit WAV is signed */
2591 field
= field
> 32767 ? 32767 : field
;
2592 field
= field
< -32768 ? -32768 : field
;
2597 if (obuf
>= (BYTE
*)(primarybuf
->buffer
+ primarybuf
->buflen
))
2598 obuf
= primarybuf
->buffer
;
2602 if (dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLPOSITIONNOTIFY
)
2603 DSOUND_CheckEvent(dsb
, ilen
);
2605 if (dsb
->leadin
&& (dsb
->startpos
> dsb
->mixpos
) && (dsb
->startpos
<= dsb
->mixpos
+ ilen
)) {
2606 /* HACK... leadin should be reset when the PLAY position reaches the startpos,
2607 * not the MIX position... but if the sound buffer is bigger than our prebuffering
2608 * (which must be the case for the streaming buffers that need this hack anyway)
2609 * plus DS_HEL_MARGIN or equivalent, then this ought to work anyway. */
2610 dsb
->leadin
= FALSE
;
2613 dsb
->mixpos
+= ilen
;
2615 if (dsb
->mixpos
>= dsb
->buflen
) {
2616 if (!(dsb
->playflags
& DSBPLAY_LOOPING
)) {
2617 dsb
->state
= STATE_STOPPED
;
2620 dsb
->leadin
= FALSE
;
2621 DSOUND_CheckEvent(dsb
, 0); /* For DSBPN_OFFSETSTOP */
2624 while (dsb
->mixpos
>= dsb
->buflen
)
2625 dsb
->mixpos
-= dsb
->buflen
;
2626 if (dsb
->leadin
&& (dsb
->startpos
<= dsb
->mixpos
))
2627 dsb
->leadin
= FALSE
; /* HACK: see above */
2634 static DWORD WINAPI
DSOUND_MixPrimary(DWORD writepos
, DWORD fraglen
, BOOL starting
)
2636 INT i
, len
, maxlen
= 0;
2637 IDirectSoundBufferImpl
*dsb
;
2639 TRACE("(%ld,%ld,%d)\n", writepos
, fraglen
, starting
);
2640 for (i
= dsound
->nrofbuffers
- 1; i
>= 0; i
--) {
2641 dsb
= dsound
->buffers
[i
];
2643 if (!dsb
|| !(ICOM_VTBL(dsb
)))
2645 if (dsb
->buflen
&& dsb
->state
&& !(starting
&& (dsb
->state
!= STATE_STARTING
))) {
2646 TRACE("Checking %p\n", dsb
);
2647 EnterCriticalSection(&(dsb
->lock
));
2648 if (dsb
->state
== STATE_STOPPING
) {
2649 /* FIXME: perhaps attempt to remove the buffer from the prebuffer */
2650 dsb
->state
= STATE_STOPPED
;
2652 len
= DSOUND_MixInBuffer(dsb
, writepos
, fraglen
);
2653 maxlen
= len
> maxlen
? len
: maxlen
;
2655 LeaveCriticalSection(&(dsb
->lock
));
2662 static void WINAPI
DSOUND_MarkPlaying(void)
2665 IDirectSoundBufferImpl
*dsb
;
2667 for (i
= dsound
->nrofbuffers
- 1; i
>= 0; i
--) {
2668 dsb
= dsound
->buffers
[i
];
2670 if (!dsb
|| !(ICOM_VTBL(dsb
)))
2672 if (dsb
->buflen
&& (dsb
->state
== STATE_STARTING
))
2673 dsb
->state
= STATE_PLAYING
;
2677 static void CALLBACK
DSOUND_timer(UINT timerID
, UINT msg
, DWORD dwUser
, DWORD dw1
, DWORD dw2
)
2683 if (!dsound
|| !primarybuf
) {
2684 ERR("dsound died without killing us?\n");
2685 timeKillEvent(timerID
);
2686 timeEndPeriod(DS_TIME_RES
);
2690 EnterCriticalSection(&(dsound
->lock
));
2692 if (!primarybuf
|| !primarybuf
->ref
) {
2693 /* seems the primary buffer is currently being released */
2694 LeaveCriticalSection(&(dsound
->lock
));
2698 /* the sound of silence */
2699 nfiller
= primarybuf
->wfx
.wBitsPerSample
== 8 ? 128 : 0;
2701 /* whether the primary is forced to play even without secondary buffers */
2702 forced
= ((primarybuf
->state
== STATE_PLAYING
) || (primarybuf
->state
== STATE_STARTING
));
2704 if (primarybuf
->hwbuf
) {
2705 if (dsound
->priolevel
!= DSSCL_WRITEPRIMARY
) {
2706 BOOL paused
= ((primarybuf
->state
== STATE_STOPPED
) || (primarybuf
->state
== STATE_STARTING
));
2707 DWORD playpos
, writepos
, inq
, maxq
, mixq
, frag
;
2708 IDsDriverBuffer_GetPosition(primarybuf
->hwbuf
, &playpos
, &writepos
);
2709 /* Well, we *could* do Just-In-Time mixing using the writepos,
2710 * but that's a little bit ambitious and unnecessary... */
2711 /* rather add our safety margin to the writepos, if we're playing */
2713 writepos
+= primarybuf
->writelead
;
2714 while (writepos
>= primarybuf
->buflen
)
2715 writepos
-= primarybuf
->buflen
;
2716 } else writepos
= playpos
;
2717 TRACE("primary playpos=%ld, writepos=%ld, clrpos=%ld, mixpos=%ld\n",
2718 playpos
,writepos
,primarybuf
->playpos
,primarybuf
->mixpos
);
2719 /* wipe out just-played sound data */
2720 if (playpos
< primarybuf
->playpos
) {
2721 memset(primarybuf
->buffer
+ primarybuf
->playpos
, nfiller
, primarybuf
->buflen
- primarybuf
->playpos
);
2722 memset(primarybuf
->buffer
, nfiller
, playpos
);
2724 memset(primarybuf
->buffer
+ primarybuf
->playpos
, nfiller
, playpos
- primarybuf
->playpos
);
2726 primarybuf
->playpos
= playpos
;
2728 /* check how much prebuffering is left */
2729 inq
= primarybuf
->mixpos
;
2731 inq
+= primarybuf
->buflen
;
2734 /* find the maximum we can prebuffer */
2737 if (maxq
< writepos
)
2738 maxq
+= primarybuf
->buflen
;
2740 } else maxq
= primarybuf
->buflen
;
2742 /* clip maxq to DS_HAL_QUEUE */
2743 frag
= DS_HAL_QUEUE
* dsound
->fraglen
;
2744 if (maxq
> frag
) maxq
= frag
;
2746 EnterCriticalSection(&(primarybuf
->lock
));
2748 /* check for consistency */
2750 /* the playback position must have passed our last
2751 * mixed position, i.e. it's an underrun, or we have
2752 * nothing more to play */
2754 /* stop the playback now, to allow buffers to refill */
2755 IDsDriverBuffer_Stop(primarybuf
->hwbuf
);
2756 if (primarybuf
->state
== STATE_PLAYING
) {
2757 primarybuf
->state
= STATE_STARTING
;
2759 else if (primarybuf
->state
== STATE_STOPPING
) {
2760 primarybuf
->state
= STATE_STOPPED
;
2763 /* how can we have an underrun if we aren't playing? */
2764 ERR("unexpected primary state (%ld)\n", primarybuf
->state
);
2766 /* the Stop is supposed to reset play position to beginning of buffer */
2767 /* unfortunately, OSS is not able to do so, so get current pointer */
2768 IDsDriverBuffer_GetPosition(primarybuf
->hwbuf
, &playpos
, NULL
);
2770 primarybuf
->playpos
= playpos
;
2771 primarybuf
->mixpos
= playpos
;
2773 maxq
= primarybuf
->buflen
;
2774 if (maxq
> frag
) maxq
= frag
;
2775 memset(primarybuf
->buffer
, nfiller
, primarybuf
->buflen
);
2779 /* see if some new buffers have been started that we want to merge into our prebuffer;
2780 * this should minimize latency even when we have a large prebuffer */
2782 if (primarybuf
->mixpos
< writepos
) {
2783 /* mix to end of buffer */
2784 len
= DSOUND_MixPrimary(writepos
, primarybuf
->buflen
- writepos
, TRUE
);
2785 if ((len
+ writepos
) < primarybuf
->buflen
)
2786 goto addmix_complete
;
2787 /* mix from beginning of buffer */
2788 if (primarybuf
->mixpos
)
2789 len
= DSOUND_MixPrimary(0, primarybuf
->mixpos
, TRUE
);
2791 /* mix middle of buffer */
2792 len
= DSOUND_MixPrimary(writepos
, primarybuf
->mixpos
- writepos
, TRUE
);
2796 DSOUND_MarkPlaying();
2799 TRACE("queued %ld, max %ld, mixing %ld, paused %d\n", inq
, maxq
, mixq
, paused
);
2800 /* it's too inefficient to mix less than a fragment at a time */
2801 if (mixq
>= dsound
->fraglen
) {
2803 #define FRAG_MIXER \
2804 if (frag > mixq) frag = mixq; \
2805 len = DSOUND_MixPrimary(primarybuf->mixpos, frag, FALSE); \
2806 if (forced) len = frag; \
2807 primarybuf->mixpos += len; \
2808 mixq -= len; inq += len
2810 if ((playpos
< writepos
) || (paused
&& (playpos
== writepos
))) {
2811 if (primarybuf
->mixpos
) {
2812 /* mix to end of buffer */
2813 frag
= primarybuf
->buflen
- primarybuf
->mixpos
;
2815 if (primarybuf
->mixpos
< primarybuf
->buflen
)
2817 primarybuf
->mixpos
= 0;
2819 if (mixq
>= dsound
->fraglen
) {
2820 /* mix from beginning of buffer */
2822 if ((!frag
) && paused
) frag
= primarybuf
->buflen
;
2826 else if (playpos
> writepos
) {
2827 /* mix middle of buffer */
2828 frag
= playpos
- primarybuf
->mixpos
;
2832 /* this should preferably not happen... */
2833 ERR("mixer malfunction (ambiguous writepos)!\n");
2839 /* buffers have been filled, restart playback */
2840 if (primarybuf
->state
== STATE_STARTING
) {
2841 IDsDriverBuffer_Play(primarybuf
->hwbuf
, 0, 0, DSBPLAY_LOOPING
);
2842 primarybuf
->state
= STATE_PLAYING
;
2844 else if (primarybuf
->state
== STATE_STOPPED
) {
2845 /* the primarybuf is supposed to play if there's something to play
2846 * even if it is reported as stopped, so don't let this confuse you */
2847 IDsDriverBuffer_Play(primarybuf
->hwbuf
, 0, 0, DSBPLAY_LOOPING
);
2848 primarybuf
->state
= STATE_STOPPING
;
2851 LeaveCriticalSection(&(primarybuf
->lock
));
2853 /* in the DSSCL_WRITEPRIMARY mode, the app is totally in charge... */
2854 if (primarybuf
->state
== STATE_STARTING
) {
2855 IDsDriverBuffer_Play(primarybuf
->hwbuf
, 0, 0, DSBPLAY_LOOPING
);
2856 primarybuf
->state
= STATE_PLAYING
;
2858 else if (primarybuf
->state
== STATE_STOPPING
) {
2859 IDsDriverBuffer_Stop(primarybuf
->hwbuf
);
2860 primarybuf
->state
= STATE_STOPPED
;
2864 /* using waveOut stuff */
2865 /* if no buffers are playing, we should be in pause mode now */
2867 /* clean out completed fragments */
2868 while (dsound
->pwqueue
&& (dsound
->pwave
[dsound
->pwplay
]->dwFlags
& WHDR_DONE
)) {
2869 if (dsound
->priolevel
!= DSSCL_WRITEPRIMARY
) {
2870 DWORD pos
= dsound
->pwplay
* dsound
->fraglen
;
2871 TRACE("done playing primary pos=%ld\n",pos
);
2872 memset(primarybuf
->buffer
+ pos
, nfiller
, dsound
->fraglen
);
2875 if (dsound
->pwplay
>= DS_HEL_FRAGS
) dsound
->pwplay
= 0;
2878 primarybuf
->playpos
= dsound
->pwplay
* dsound
->fraglen
;
2879 TRACE("primary playpos=%ld, mixpos=%ld\n",primarybuf
->playpos
,primarybuf
->mixpos
);
2880 EnterCriticalSection(&(primarybuf
->lock
));
2881 if (!dsound
->pwqueue
) {
2882 /* this is either an underrun or we have nothing more to play...
2883 * since playback has already stopped now, we can enter pause mode,
2884 * in order to allow buffers to refill */
2885 if (primarybuf
->state
== STATE_PLAYING
) {
2886 waveOutPause(dsound
->hwo
);
2887 primarybuf
->state
= STATE_STARTING
;
2889 else if (primarybuf
->state
== STATE_STOPPING
) {
2890 waveOutPause(dsound
->hwo
);
2891 primarybuf
->state
= STATE_STOPPED
;
2895 /* find next write position, plus some extra margin */
2896 writepos
= primarybuf
->playpos
+ DS_HEL_MARGIN
* dsound
->fraglen
;
2897 while (writepos
>= primarybuf
->buflen
) writepos
-= primarybuf
->buflen
;
2899 /* see if some new buffers have been started that we want to merge into our prebuffer;
2900 * this should minimize latency even when we have a large prebuffer */
2901 if (dsound
->priolevel
!= DSSCL_WRITEPRIMARY
) {
2902 if ((primarybuf
->state
== STATE_PLAYING
) || (primarybuf
->state
== STATE_STOPPING
)) {
2903 while (writepos
!= primarybuf
->mixpos
) {
2904 len
= DSOUND_MixPrimary(writepos
, dsound
->fraglen
, TRUE
);
2906 writepos
+= dsound
->fraglen
;
2907 if (writepos
>= primarybuf
->buflen
)
2908 writepos
-= primarybuf
->buflen
;
2911 DSOUND_MarkPlaying();
2914 /* we want at least DS_HEL_QUEUE fragments in the prebuffer outqueue;
2915 * mix a bunch of fragments now as necessary */
2916 while (dsound
->pwqueue
< DS_HEL_QUEUE
) {
2917 if (dsound
->priolevel
!= DSSCL_WRITEPRIMARY
) {
2918 len
= DSOUND_MixPrimary(primarybuf
->mixpos
, dsound
->fraglen
, FALSE
);
2920 if (forced
) len
= dsound
->fraglen
;
2921 /* if we have nothing to play, don't bother to */
2923 if (len
< dsound
->fraglen
) {
2924 TRACE("len=%ld is less than fraglen=%ld\n",len
,dsound
->fraglen
);
2926 /* ok, we have something to play */
2927 /* advance mix positions */
2928 primarybuf
->mixpos
+= dsound
->fraglen
;
2929 if (primarybuf
->mixpos
>= primarybuf
->buflen
)
2930 primarybuf
->mixpos
-= primarybuf
->buflen
;
2932 waveOutWrite(dsound
->hwo
, dsound
->pwave
[dsound
->pwwrite
], sizeof(WAVEHDR
));
2934 if (dsound
->pwwrite
>= DS_HEL_FRAGS
) dsound
->pwwrite
= 0;
2937 if (dsound
->pwqueue
) {
2938 /* buffers have been filled, restart playback */
2939 if (primarybuf
->state
== STATE_STARTING
) {
2940 waveOutRestart(dsound
->hwo
);
2941 primarybuf
->state
= STATE_PLAYING
;
2943 else if (primarybuf
->state
== STATE_STOPPED
) {
2944 /* the primarybuf is supposed to play if there's something to play
2945 * even if it is reported as stopped, so don't let this confuse you */
2946 waveOutRestart(dsound
->hwo
);
2947 primarybuf
->state
= STATE_STOPPING
;
2950 LeaveCriticalSection(&(primarybuf
->lock
));
2952 LeaveCriticalSection(&(dsound
->lock
));
2955 /*******************************************************************************
2958 HRESULT WINAPI
DirectSoundCreate(REFGUID lpGUID
,LPDIRECTSOUND
*ppDS
,IUnknown
*pUnkOuter
)
2960 IDirectSoundImpl
** ippDS
=(IDirectSoundImpl
**)ppDS
;
2961 PIDSDRIVER drv
= NULL
;
2964 HRESULT err
= DS_OK
;
2967 TRACE("(%p,%p,%p)\n",lpGUID
,ippDS
,pUnkOuter
);
2969 TRACE("DirectSoundCreate (%p)\n", ippDS
);
2972 return DSERR_INVALIDPARAM
;
2975 IDirectSound_AddRef((LPDIRECTSOUND
)dsound
);
2980 /* Enumerate WINMM audio devices and find the one we want */
2981 wodn
= waveOutGetNumDevs();
2982 if (!wodn
) return DSERR_NODRIVER
;
2984 /* FIXME: How do we find the GUID of an audio device? */
2985 /* Well, just use the first available device for now... */
2987 /* Get output device caps */
2988 waveOutGetDevCapsA(wod
, &wcaps
, sizeof(wcaps
));
2989 /* 0x810 is a "Wine extension" to get the DSound interface */
2990 waveOutMessage(wod
, 0x810, (DWORD
)&drv
, 0);
2992 /* Allocate memory */
2993 *ippDS
= (IDirectSoundImpl
*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundImpl
));
2995 return DSERR_OUTOFMEMORY
;
2997 ICOM_VTBL(*ippDS
) = &dsvt
;
3000 (*ippDS
)->driver
= drv
;
3001 (*ippDS
)->fraglen
= 0;
3002 (*ippDS
)->priolevel
= DSSCL_NORMAL
;
3003 (*ippDS
)->nrofbuffers
= 0;
3004 (*ippDS
)->buffers
= NULL
;
3005 (*ippDS
)->primary
= NULL
;
3006 (*ippDS
)->listener
= NULL
;
3008 /* Get driver description */
3010 IDsDriver_GetDriverDesc(drv
,&((*ippDS
)->drvdesc
));
3012 /* if no DirectSound interface available, use WINMM API instead */
3013 (*ippDS
)->drvdesc
.dwFlags
= DSDDESC_DOMMSYSTEMOPEN
| DSDDESC_DOMMSYSTEMSETFORMAT
;
3014 (*ippDS
)->drvdesc
.dnDevNode
= wod
; /* FIXME? */
3017 /* Set default wave format (may need it for waveOutOpen) */
3018 (*ippDS
)->wfx
.wFormatTag
= WAVE_FORMAT_PCM
;
3019 (*ippDS
)->wfx
.nChannels
= 2;
3020 (*ippDS
)->wfx
.nSamplesPerSec
= 22050;
3021 (*ippDS
)->wfx
.nAvgBytesPerSec
= 44100;
3022 (*ippDS
)->wfx
.nBlockAlign
= 2;
3023 (*ippDS
)->wfx
.wBitsPerSample
= 8;
3025 /* If the driver requests being opened through MMSYSTEM
3026 * (which is recommended by the DDK), it is supposed to happen
3027 * before the DirectSound interface is opened */
3028 if ((*ippDS
)->drvdesc
.dwFlags
& DSDDESC_DOMMSYSTEMOPEN
) {
3029 /* FIXME: is this right? */
3030 err
= mmErr(waveOutOpen(&((*ippDS
)->hwo
), (*ippDS
)->drvdesc
.dnDevNode
, &((*ippDS
)->wfx
),
3031 0, 0, CALLBACK_NULL
| WAVE_DIRECTSOUND
));
3034 if (drv
&& (err
== DS_OK
))
3035 err
= IDsDriver_Open(drv
);
3037 /* FIXME: do we want to handle a temporarily busy device? */
3039 HeapFree(GetProcessHeap(),0,*ippDS
);
3044 /* the driver is now open, so it's now allowed to call GetCaps */
3046 IDsDriver_GetCaps(drv
,&((*ippDS
)->drvcaps
));
3050 /* FIXME: look at wcaps */
3051 (*ippDS
)->drvcaps
.dwFlags
= DSCAPS_EMULDRIVER
|
3052 DSCAPS_PRIMARY16BIT
| DSCAPS_PRIMARYSTEREO
;
3054 /* Allocate memory for HEL buffer headers */
3055 for (c
=0; c
<DS_HEL_FRAGS
; c
++) {
3056 (*ippDS
)->pwave
[c
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(WAVEHDR
));
3057 if (!(*ippDS
)->pwave
[c
]) {
3058 /* Argh, out of memory */
3060 HeapFree(GetProcessHeap(),0,(*ippDS
)->pwave
[c
]);
3061 waveOutClose((*ippDS
)->hwo
);
3062 HeapFree(GetProcessHeap(),0,*ippDS
);
3064 return DSERR_OUTOFMEMORY
;
3070 InitializeCriticalSection(&((*ippDS
)->lock
));
3074 if (primarybuf
== NULL
) {
3078 dsbd
.dwSize
= sizeof(DSBUFFERDESC
);
3079 dsbd
.dwFlags
= DSBCAPS_PRIMARYBUFFER
| DSBCAPS_GETCURRENTPOSITION2
;
3080 dsbd
.dwBufferBytes
= 0;
3081 dsbd
.lpwfxFormat
= &(dsound
->wfx
);
3082 hr
= IDirectSound_CreateSoundBuffer(*ppDS
, &dsbd
, (LPDIRECTSOUNDBUFFER
*)&primarybuf
, NULL
);
3086 /* dsound->primary is NULL - don't need to Release */
3087 dsound
->primary
= primarybuf
;
3088 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER
)primarybuf
);
3090 timeBeginPeriod(DS_TIME_RES
);
3091 dsound
->timerID
= timeSetEvent(DS_TIME_DEL
, DS_TIME_RES
, DSOUND_timer
,
3092 (DWORD
)dsound
, TIME_PERIODIC
| TIME_CALLBACK_FUNCTION
);
3097 /***************************************************************************
3098 * DirectSoundCaptureCreate [DSOUND.6]
3100 * Create and initialize a DirectSoundCapture interface
3104 * Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
3107 HRESULT WINAPI
DirectSoundCaptureCreate(
3109 LPDIRECTSOUNDCAPTURE
* lplpDSC
,
3110 LPUNKNOWN pUnkOuter
)
3112 TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID
), lplpDSC
, pUnkOuter
);
3115 return DSERR_NOAGGREGATION
;
3118 /* Default device? */
3120 return DSOUND_CreateDirectSoundCapture( (LPVOID
*)lplpDSC
);
3123 FIXME( "Unknown GUID %s\n", debugstr_guid(lpcGUID
) );
3126 return DSERR_OUTOFMEMORY
;
3129 /***************************************************************************
3130 * DirectSoundCaptureEnumerateA [DSOUND.7]
3132 * Enumerate all DirectSound drivers installed in the system
3136 * Failure: DSERR_INVALIDPARAM
3138 HRESULT WINAPI
DirectSoundCaptureEnumerateA(
3139 LPDSENUMCALLBACKA lpDSEnumCallback
,
3142 TRACE("(%p,%p)\n", lpDSEnumCallback
, lpContext
);
3144 if ( lpDSEnumCallback
)
3145 lpDSEnumCallback(NULL
,"WINE Primary Sound Capture Driver",
3146 "SoundCap",lpContext
);
3152 /***************************************************************************
3153 * DirectSoundCaptureEnumerateW [DSOUND.8]
3155 * Enumerate all DirectSound drivers installed in the system
3159 * Failure: DSERR_INVALIDPARAM
3161 HRESULT WINAPI
DirectSoundCaptureEnumerateW(
3162 LPDSENUMCALLBACKW lpDSEnumCallback
,
3165 FIXME("(%p,%p):stub\n", lpDSEnumCallback
, lpContext
);
3170 DSOUND_CreateDirectSoundCapture( LPVOID
* ppobj
)
3172 *ppobj
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof( IDirectSoundCaptureImpl
) );
3174 if ( *ppobj
== NULL
) {
3175 return DSERR_OUTOFMEMORY
;
3179 ICOM_THIS(IDirectSoundCaptureImpl
,*ppobj
);
3182 ICOM_VTBL(This
) = &dscvt
;
3184 InitializeCriticalSection( &This
->lock
);
3190 static HRESULT WINAPI
3191 IDirectSoundCaptureImpl_QueryInterface(
3192 LPDIRECTSOUNDCAPTURE iface
,
3196 ICOM_THIS(IDirectSoundCaptureImpl
,iface
);
3198 FIXME( "(%p)->(%s,%p): stub\n", This
, debugstr_guid(riid
), ppobj
);
3204 IDirectSoundCaptureImpl_AddRef( LPDIRECTSOUNDCAPTURE iface
)
3207 ICOM_THIS(IDirectSoundCaptureImpl
,iface
);
3209 EnterCriticalSection( &This
->lock
);
3211 TRACE( "(%p) was 0x%08lx\n", This
, This
->ref
);
3212 uRef
= ++(This
->ref
);
3214 LeaveCriticalSection( &This
->lock
);
3220 IDirectSoundCaptureImpl_Release( LPDIRECTSOUNDCAPTURE iface
)
3223 ICOM_THIS(IDirectSoundCaptureImpl
,iface
);
3225 EnterCriticalSection( &This
->lock
);
3227 TRACE( "(%p) was 0x%08lx\n", This
, This
->ref
);
3228 uRef
= --(This
->ref
);
3230 LeaveCriticalSection( &This
->lock
);
3233 DeleteCriticalSection( &This
->lock
);
3234 HeapFree( GetProcessHeap(), 0, This
);
3240 static HRESULT WINAPI
3241 IDirectSoundCaptureImpl_CreateCaptureBuffer(
3242 LPDIRECTSOUNDCAPTURE iface
,
3243 LPCDSCBUFFERDESC lpcDSCBufferDesc
,
3244 LPDIRECTSOUNDCAPTUREBUFFER
* lplpDSCaptureBuffer
,
3248 ICOM_THIS(IDirectSoundCaptureImpl
,iface
);
3250 TRACE( "(%p)->(%p,%p,%p)\n", This
, lpcDSCBufferDesc
, lplpDSCaptureBuffer
, pUnk
);
3253 return DSERR_INVALIDPARAM
;
3256 hr
= DSOUND_CreateDirectSoundCaptureBuffer( lpcDSCBufferDesc
, (LPVOID
*)lplpDSCaptureBuffer
);
3261 static HRESULT WINAPI
3262 IDirectSoundCaptureImpl_GetCaps(
3263 LPDIRECTSOUNDCAPTURE iface
,
3264 LPDSCCAPS lpDSCCaps
)
3266 ICOM_THIS(IDirectSoundCaptureImpl
,iface
);
3268 FIXME( "(%p)->(%p): stub\n", This
, lpDSCCaps
);
3273 static HRESULT WINAPI
3274 IDirectSoundCaptureImpl_Initialize(
3275 LPDIRECTSOUNDCAPTURE iface
,
3278 ICOM_THIS(IDirectSoundCaptureImpl
,iface
);
3280 FIXME( "(%p)->(%p): stub\n", This
, lpcGUID
);
3286 static ICOM_VTABLE(IDirectSoundCapture
) dscvt
=
3288 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
3289 /* IUnknown methods */
3290 IDirectSoundCaptureImpl_QueryInterface
,
3291 IDirectSoundCaptureImpl_AddRef
,
3292 IDirectSoundCaptureImpl_Release
,
3294 /* IDirectSoundCapture methods */
3295 IDirectSoundCaptureImpl_CreateCaptureBuffer
,
3296 IDirectSoundCaptureImpl_GetCaps
,
3297 IDirectSoundCaptureImpl_Initialize
3301 DSOUND_CreateDirectSoundCaptureBuffer( LPCDSCBUFFERDESC lpcDSCBufferDesc
, LPVOID
* ppobj
)
3304 FIXME( "(%p,%p): ignoring lpcDSCBufferDesc\n", lpcDSCBufferDesc
, ppobj
);
3306 *ppobj
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof( IDirectSoundCaptureBufferImpl
) );
3308 if ( *ppobj
== NULL
) {
3309 return DSERR_OUTOFMEMORY
;
3313 ICOM_THIS(IDirectSoundCaptureBufferImpl
,*ppobj
);
3316 ICOM_VTBL(This
) = &dscbvt
;
3318 InitializeCriticalSection( &This
->lock
);
3325 static HRESULT WINAPI
3326 IDirectSoundCaptureBufferImpl_QueryInterface(
3327 LPDIRECTSOUNDCAPTUREBUFFER iface
,
3331 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
3333 FIXME( "(%p)->(%s,%p): stub\n", This
, debugstr_guid(riid
), ppobj
);
3339 IDirectSoundCaptureBufferImpl_AddRef( LPDIRECTSOUNDCAPTUREBUFFER iface
)
3342 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
3344 EnterCriticalSection( &This
->lock
);
3346 TRACE( "(%p) was 0x%08lx\n", This
, This
->ref
);
3347 uRef
= ++(This
->ref
);
3349 LeaveCriticalSection( &This
->lock
);
3355 IDirectSoundCaptureBufferImpl_Release( LPDIRECTSOUNDCAPTUREBUFFER iface
)
3358 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
3360 EnterCriticalSection( &This
->lock
);
3362 TRACE( "(%p) was 0x%08lx\n", This
, This
->ref
);
3363 uRef
= --(This
->ref
);
3365 LeaveCriticalSection( &This
->lock
);
3368 DeleteCriticalSection( &This
->lock
);
3369 HeapFree( GetProcessHeap(), 0, This
);
3375 static HRESULT WINAPI
3376 IDirectSoundCaptureBufferImpl_GetCaps(
3377 LPDIRECTSOUNDCAPTUREBUFFER iface
,
3378 LPDSCBCAPS lpDSCBCaps
)
3380 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
3382 FIXME( "(%p)->(%p): stub\n", This
, lpDSCBCaps
);
3387 static HRESULT WINAPI
3388 IDirectSoundCaptureBufferImpl_GetCurrentPosition(
3389 LPDIRECTSOUNDCAPTUREBUFFER iface
,
3390 LPDWORD lpdwCapturePosition
,
3391 LPDWORD lpdwReadPosition
)
3393 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
3395 FIXME( "(%p)->(%p,%p): stub\n", This
, lpdwCapturePosition
, lpdwReadPosition
);
3400 static HRESULT WINAPI
3401 IDirectSoundCaptureBufferImpl_GetFormat(
3402 LPDIRECTSOUNDCAPTUREBUFFER iface
,
3403 LPWAVEFORMATEX lpwfxFormat
,
3404 DWORD dwSizeAllocated
,
3405 LPDWORD lpdwSizeWritten
)
3407 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
3409 FIXME( "(%p)->(%p,0x%08lx,%p): stub\n", This
, lpwfxFormat
, dwSizeAllocated
, lpdwSizeWritten
);
3414 static HRESULT WINAPI
3415 IDirectSoundCaptureBufferImpl_GetStatus(
3416 LPDIRECTSOUNDCAPTUREBUFFER iface
,
3417 LPDWORD lpdwStatus
)
3419 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
3421 FIXME( "(%p)->(%p): stub\n", This
, lpdwStatus
);
3426 static HRESULT WINAPI
3427 IDirectSoundCaptureBufferImpl_Initialize(
3428 LPDIRECTSOUNDCAPTUREBUFFER iface
,
3429 LPDIRECTSOUNDCAPTURE lpDSC
,
3430 LPCDSCBUFFERDESC lpcDSCBDesc
)
3432 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
3434 FIXME( "(%p)->(%p,%p): stub\n", This
, lpDSC
, lpcDSCBDesc
);
3439 static HRESULT WINAPI
3440 IDirectSoundCaptureBufferImpl_Lock(
3441 LPDIRECTSOUNDCAPTUREBUFFER iface
,
3444 LPVOID
* lplpvAudioPtr1
,
3445 LPDWORD lpdwAudioBytes1
,
3446 LPVOID
* lplpvAudioPtr2
,
3447 LPDWORD lpdwAudioBytes2
,
3450 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
3452 FIXME( "(%p)->(%08lu,%08lu,%p,%p,%p,%p,0x%08lx): stub\n", This
, dwReadCusor
, dwReadBytes
, lplpvAudioPtr1
, lpdwAudioBytes1
, lplpvAudioPtr2
, lpdwAudioBytes2
, dwFlags
);
3457 static HRESULT WINAPI
3458 IDirectSoundCaptureBufferImpl_Start(
3459 LPDIRECTSOUNDCAPTUREBUFFER iface
,
3462 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
3464 FIXME( "(%p)->(0x%08lx): stub\n", This
, dwFlags
);
3469 static HRESULT WINAPI
3470 IDirectSoundCaptureBufferImpl_Stop( LPDIRECTSOUNDCAPTUREBUFFER iface
)
3472 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
3474 FIXME( "(%p): stub\n", This
);
3479 static HRESULT WINAPI
3480 IDirectSoundCaptureBufferImpl_Unlock(
3481 LPDIRECTSOUNDCAPTUREBUFFER iface
,
3482 LPVOID lpvAudioPtr1
,
3483 DWORD dwAudioBytes1
,
3484 LPVOID lpvAudioPtr2
,
3485 DWORD dwAudioBytes2
)
3487 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
3489 FIXME( "(%p)->(%p,%08lu,%p,%08lu): stub\n", This
, lpvAudioPtr1
, dwAudioBytes1
, lpvAudioPtr2
, dwAudioBytes2
);
3495 static ICOM_VTABLE(IDirectSoundCaptureBuffer
) dscbvt
=
3497 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
3498 /* IUnknown methods */
3499 IDirectSoundCaptureBufferImpl_QueryInterface
,
3500 IDirectSoundCaptureBufferImpl_AddRef
,
3501 IDirectSoundCaptureBufferImpl_Release
,
3503 /* IDirectSoundCaptureBuffer methods */
3504 IDirectSoundCaptureBufferImpl_GetCaps
,
3505 IDirectSoundCaptureBufferImpl_GetCurrentPosition
,
3506 IDirectSoundCaptureBufferImpl_GetFormat
,
3507 IDirectSoundCaptureBufferImpl_GetStatus
,
3508 IDirectSoundCaptureBufferImpl_Initialize
,
3509 IDirectSoundCaptureBufferImpl_Lock
,
3510 IDirectSoundCaptureBufferImpl_Start
,
3511 IDirectSoundCaptureBufferImpl_Stop
,
3512 IDirectSoundCaptureBufferImpl_Unlock
3515 /*******************************************************************************
3516 * DirectSound ClassFactory
3520 /* IUnknown fields */
3521 ICOM_VFIELD(IClassFactory
);
3523 } IClassFactoryImpl
;
3525 static HRESULT WINAPI
3526 DSCF_QueryInterface(LPCLASSFACTORY iface
,REFIID riid
,LPVOID
*ppobj
) {
3527 ICOM_THIS(IClassFactoryImpl
,iface
);
3529 FIXME("(%p)->(%s,%p),stub!\n",This
,debugstr_guid(riid
),ppobj
);
3530 return E_NOINTERFACE
;
3534 DSCF_AddRef(LPCLASSFACTORY iface
) {
3535 ICOM_THIS(IClassFactoryImpl
,iface
);
3536 return ++(This
->ref
);
3539 static ULONG WINAPI
DSCF_Release(LPCLASSFACTORY iface
) {
3540 ICOM_THIS(IClassFactoryImpl
,iface
);
3541 /* static class, won't be freed */
3542 return --(This
->ref
);
3545 static HRESULT WINAPI
DSCF_CreateInstance(
3546 LPCLASSFACTORY iface
,LPUNKNOWN pOuter
,REFIID riid
,LPVOID
*ppobj
3548 ICOM_THIS(IClassFactoryImpl
,iface
);
3550 TRACE("(%p)->(%p,%s,%p)\n",This
,pOuter
,debugstr_guid(riid
),ppobj
);
3551 if ( IsEqualGUID( &IID_IDirectSound
, riid
) ) {
3552 /* FIXME: reuse already created dsound if present? */
3553 return DirectSoundCreate(riid
,(LPDIRECTSOUND
*)ppobj
,pOuter
);
3555 return E_NOINTERFACE
;
3558 static HRESULT WINAPI
DSCF_LockServer(LPCLASSFACTORY iface
,BOOL dolock
) {
3559 ICOM_THIS(IClassFactoryImpl
,iface
);
3560 FIXME("(%p)->(%d),stub!\n",This
,dolock
);
3564 static ICOM_VTABLE(IClassFactory
) DSCF_Vtbl
= {
3565 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
3566 DSCF_QueryInterface
,
3569 DSCF_CreateInstance
,
3572 static IClassFactoryImpl DSOUND_CF
= {&DSCF_Vtbl
, 1 };
3574 /*******************************************************************************
3575 * DllGetClassObject [DSOUND.4]
3576 * Retrieves class object from a DLL object
3579 * Docs say returns STDAPI
3582 * rclsid [I] CLSID for the class object
3583 * riid [I] Reference to identifier of interface for class object
3584 * ppv [O] Address of variable to receive interface pointer for riid
3588 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
3591 DWORD WINAPI
DSOUND_DllGetClassObject(REFCLSID rclsid
,REFIID riid
,LPVOID
*ppv
)
3593 TRACE("(%p,%p,%p)\n", debugstr_guid(rclsid
), debugstr_guid(riid
), ppv
);
3594 if ( IsEqualCLSID( &IID_IClassFactory
, riid
) ) {
3595 *ppv
= (LPVOID
)&DSOUND_CF
;
3596 IClassFactory_AddRef((IClassFactory
*)*ppv
);
3600 FIXME("(%p,%p,%p): no interface found.\n", debugstr_guid(rclsid
), debugstr_guid(riid
), ppv
);
3601 return CLASS_E_CLASSNOTAVAILABLE
;
3605 /*******************************************************************************
3606 * DllCanUnloadNow [DSOUND.3] Determines whether the DLL is in use.
3612 DWORD WINAPI
DSOUND_DllCanUnloadNow(void)
3614 FIXME("(void): stub\n");