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 * some settings here should probably get ported to wine.conf */
54 #define DS_EMULDRIVER 1 /* some games (Quake 2, UT) refuse to accept
55 emulated dsound devices. set to 0 ! */
56 #define DS_HEL_FRAGS 48 /* HEL only: number of waveOut fragments in primary buffer */
57 #define DS_HEL_QUEUE 28 /* HEL only: number of waveOut fragments to prebuffer */
58 /* (Starcraft videos won't work with higher than 32 x10ms) */
59 #define DS_HEL_MARGIN 4 /* HEL only: number of waveOut fragments ahead to mix in new buffers */
61 #define DS_HAL_QUEUE 28 /* HAL only: max number of fragments to prebuffer */
63 /* Linux does not support better timing than 10ms */
64 #define DS_TIME_RES 10 /* Resolution of multimedia timer */
65 #define DS_TIME_DEL 10 /* Delay of multimedia timer callback, and duration of HEL fragment */
67 /*****************************************************************************
68 * Predeclare the interface implementation structures
70 typedef struct IDirectSoundImpl IDirectSoundImpl
;
71 typedef struct IDirectSoundBufferImpl IDirectSoundBufferImpl
;
72 typedef struct IDirectSoundNotifyImpl IDirectSoundNotifyImpl
;
73 typedef struct IDirectSound3DListenerImpl IDirectSound3DListenerImpl
;
74 typedef struct IDirectSound3DBufferImpl IDirectSound3DBufferImpl
;
75 typedef struct IDirectSoundCaptureImpl IDirectSoundCaptureImpl
;
76 typedef struct IDirectSoundCaptureBufferImpl IDirectSoundCaptureBufferImpl
;
78 /*****************************************************************************
79 * IDirectSound implementation structure
81 struct IDirectSoundImpl
84 ICOM_VFIELD(IDirectSound
);
86 /* IDirectSoundImpl fields */
91 LPWAVEHDR pwave
[DS_HEL_FRAGS
];
92 UINT timerID
, pwplay
, pwwrite
, pwqueue
;
96 IDirectSoundBufferImpl
** buffers
;
97 IDirectSoundBufferImpl
* primary
;
98 IDirectSound3DListenerImpl
* listener
;
99 WAVEFORMATEX wfx
; /* current main waveformat */
100 CRITICAL_SECTION lock
;
103 /*****************************************************************************
104 * IDirectSoundBuffer implementation structure
106 struct IDirectSoundBufferImpl
108 /* IUnknown fields */
109 ICOM_VFIELD(IDirectSoundBuffer
);
111 /* IDirectSoundBufferImpl fields */
112 PIDSDRIVERBUFFER hwbuf
;
115 IDirectSound3DBufferImpl
* ds3db
;
116 DWORD playflags
,state
,leadin
;
117 DWORD playpos
,mixpos
,startpos
,writelead
,buflen
;
118 DWORD nAvgBytesPerSec
;
122 IDirectSoundBufferImpl
* parent
; /* for duplicates */
123 IDirectSoundImpl
* dsound
;
125 LPDSBPOSITIONNOTIFY notifies
;
127 CRITICAL_SECTION lock
;
130 #define STATE_STOPPED 0
131 #define STATE_STARTING 1
132 #define STATE_PLAYING 2
133 #define STATE_STOPPING 3
135 /*****************************************************************************
136 * IDirectSoundNotify implementation structure
138 struct IDirectSoundNotifyImpl
140 /* IUnknown fields */
141 ICOM_VFIELD(IDirectSoundNotify
);
143 /* IDirectSoundNotifyImpl fields */
144 IDirectSoundBufferImpl
* dsb
;
147 /*****************************************************************************
148 * IDirectSound3DListener implementation structure
150 struct IDirectSound3DListenerImpl
152 /* IUnknown fields */
153 ICOM_VFIELD(IDirectSound3DListener
);
155 /* IDirectSound3DListenerImpl fields */
156 IDirectSoundBufferImpl
* dsb
;
158 CRITICAL_SECTION lock
;
161 /*****************************************************************************
162 * IDirectSound3DBuffer implementation structure
164 struct IDirectSound3DBufferImpl
166 /* IUnknown fields */
167 ICOM_VFIELD(IDirectSound3DBuffer
);
169 /* IDirectSound3DBufferImpl fields */
170 IDirectSoundBufferImpl
* dsb
;
174 CRITICAL_SECTION lock
;
178 /*****************************************************************************
179 * IDirectSoundCapture implementation structure
181 struct IDirectSoundCaptureImpl
183 /* IUnknown fields */
184 ICOM_VFIELD(IDirectSoundCapture
);
187 /* IDirectSoundCaptureImpl fields */
188 CRITICAL_SECTION lock
;
191 /*****************************************************************************
192 * IDirectSoundCapture implementation structure
194 struct IDirectSoundCaptureBufferImpl
196 /* IUnknown fields */
197 ICOM_VFIELD(IDirectSoundCaptureBuffer
);
200 /* IDirectSoundCaptureBufferImpl fields */
201 CRITICAL_SECTION lock
;
205 /* #define USE_DSOUND3D 1 */
207 #define DSOUND_FREQSHIFT (14)
209 static IDirectSoundImpl
* dsound
= NULL
;
211 static IDirectSoundBufferImpl
* primarybuf
= NULL
;
213 static void DSOUND_CheckEvent(IDirectSoundBufferImpl
*dsb
, int len
);
215 static HRESULT
DSOUND_CreateDirectSoundCapture( LPVOID
* ppobj
);
216 static HRESULT
DSOUND_CreateDirectSoundCaptureBuffer( LPCDSCBUFFERDESC lpcDSCBufferDesc
, LPVOID
* ppobj
);
218 static ICOM_VTABLE(IDirectSoundCapture
) dscvt
;
219 static ICOM_VTABLE(IDirectSoundCaptureBuffer
) dscbvt
;
221 static HRESULT
mmErr(UINT err
)
224 case MMSYSERR_NOERROR
:
226 case MMSYSERR_ALLOCATED
:
227 return DSERR_ALLOCATED
;
228 case MMSYSERR_INVALHANDLE
:
229 return DSERR_GENERIC
; /* FIXME */
230 case MMSYSERR_NODRIVER
:
231 return DSERR_NODRIVER
;
233 return DSERR_OUTOFMEMORY
;
234 case MMSYSERR_INVALPARAM
:
235 return DSERR_INVALIDPARAM
;
237 FIXME("Unknown MMSYS error %d\n",err
);
238 return DSERR_GENERIC
;
242 /***************************************************************************
243 * DirectSoundEnumerateA [DSOUND.2]
245 * Enumerate all DirectSound drivers installed in the system
249 * Failure: DSERR_INVALIDPARAM
251 HRESULT WINAPI
DirectSoundEnumerateA(
252 LPDSENUMCALLBACKA lpDSEnumCallback
,
255 TRACE("lpDSEnumCallback = %p, lpContext = %p\n",
256 lpDSEnumCallback
, lpContext
);
259 if (lpDSEnumCallback
!= NULL
)
260 lpDSEnumCallback(NULL
,"WINE DirectSound using Open Sound System",
267 /***************************************************************************
268 * DirectSoundEnumerateW [DSOUND.3]
270 * Enumerate all DirectSound drivers installed in the system
274 * Failure: DSERR_INVALIDPARAM
276 HRESULT WINAPI
DirectSoundEnumerateW(
277 LPDSENUMCALLBACKW lpDSEnumCallback
,
280 FIXME("lpDSEnumCallback = %p, lpContext = %p: stub\n",
281 lpDSEnumCallback
, lpContext
);
287 static void _dump_DSBCAPS(DWORD xmask
) {
292 #define FE(x) { x, #x },
293 FE(DSBCAPS_PRIMARYBUFFER
)
295 FE(DSBCAPS_LOCHARDWARE
)
296 FE(DSBCAPS_LOCSOFTWARE
)
298 FE(DSBCAPS_CTRLFREQUENCY
)
300 FE(DSBCAPS_CTRLVOLUME
)
301 FE(DSBCAPS_CTRLPOSITIONNOTIFY
)
302 FE(DSBCAPS_CTRLDEFAULT
)
304 FE(DSBCAPS_STICKYFOCUS
)
305 FE(DSBCAPS_GLOBALFOCUS
)
306 FE(DSBCAPS_GETCURRENTPOSITION2
)
307 FE(DSBCAPS_MUTE3DATMAXDISTANCE
)
312 for (i
=0;i
<sizeof(flags
)/sizeof(flags
[0]);i
++)
313 if ((flags
[i
].mask
& xmask
) == flags
[i
].mask
)
314 DPRINTF("%s ",flags
[i
].name
);
317 /*******************************************************************************
318 * IDirectSound3DBuffer
321 /* IUnknown methods */
323 static HRESULT WINAPI
IDirectSound3DBufferImpl_QueryInterface(
324 LPDIRECTSOUND3DBUFFER iface
, REFIID riid
, LPVOID
*ppobj
)
326 ICOM_THIS(IDirectSound3DBufferImpl
,iface
);
328 TRACE("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
334 static ULONG WINAPI
IDirectSound3DBufferImpl_AddRef(LPDIRECTSOUND3DBUFFER iface
)
336 ICOM_THIS(IDirectSound3DBufferImpl
,iface
);
343 static ULONG WINAPI
IDirectSound3DBufferImpl_Release(LPDIRECTSOUND3DBUFFER iface
)
345 ICOM_THIS(IDirectSound3DBufferImpl
,iface
);
347 TRACE("(%p) ref was %ld\n", This
, This
->ref
);
353 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)This
->dsb
);
355 DeleteCriticalSection(&This
->lock
);
357 HeapFree(GetProcessHeap(),0,This
->buffer
);
358 HeapFree(GetProcessHeap(),0,This
);
364 /* IDirectSound3DBuffer methods */
366 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetAllParameters(
367 LPDIRECTSOUND3DBUFFER iface
,
368 LPDS3DBUFFER lpDs3dBuffer
)
376 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetConeAngles(
377 LPDIRECTSOUND3DBUFFER iface
,
378 LPDWORD lpdwInsideConeAngle
,
379 LPDWORD lpdwOutsideConeAngle
)
387 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetConeOrientation(
388 LPDIRECTSOUND3DBUFFER iface
,
389 LPD3DVECTOR lpvConeOrientation
)
397 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetConeOutsideVolume(
398 LPDIRECTSOUND3DBUFFER iface
,
399 LPLONG lplConeOutsideVolume
)
407 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetMaxDistance(
408 LPDIRECTSOUND3DBUFFER iface
,
409 LPD3DVALUE lpfMaxDistance
)
417 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetMinDistance(
418 LPDIRECTSOUND3DBUFFER iface
,
419 LPD3DVALUE lpfMinDistance
)
427 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetMode(
428 LPDIRECTSOUND3DBUFFER iface
,
437 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetPosition(
438 LPDIRECTSOUND3DBUFFER iface
,
439 LPD3DVECTOR lpvPosition
)
447 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetVelocity(
448 LPDIRECTSOUND3DBUFFER iface
,
449 LPD3DVECTOR lpvVelocity
)
457 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetAllParameters(
458 LPDIRECTSOUND3DBUFFER iface
,
459 LPCDS3DBUFFER lpcDs3dBuffer
,
468 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetConeAngles(
469 LPDIRECTSOUND3DBUFFER iface
,
470 DWORD dwInsideConeAngle
,
471 DWORD dwOutsideConeAngle
,
480 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetConeOrientation(
481 LPDIRECTSOUND3DBUFFER iface
,
482 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
491 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetConeOutsideVolume(
492 LPDIRECTSOUND3DBUFFER iface
,
493 LONG lConeOutsideVolume
,
502 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetMaxDistance(
503 LPDIRECTSOUND3DBUFFER iface
,
504 D3DVALUE fMaxDistance
,
513 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetMinDistance(
514 LPDIRECTSOUND3DBUFFER iface
,
515 D3DVALUE fMinDistance
,
524 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetMode(
525 LPDIRECTSOUND3DBUFFER iface
,
529 ICOM_THIS(IDirectSound3DBufferImpl
,iface
);
530 TRACE("mode = %lx\n", dwMode
);
531 This
->ds3db
.dwMode
= dwMode
;
537 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetPosition(
538 LPDIRECTSOUND3DBUFFER iface
,
539 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
548 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetVelocity(
549 LPDIRECTSOUND3DBUFFER iface
,
550 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
559 static ICOM_VTABLE(IDirectSound3DBuffer
) ds3dbvt
=
561 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
562 /* IUnknown methods */
563 IDirectSound3DBufferImpl_QueryInterface
,
564 IDirectSound3DBufferImpl_AddRef
,
565 IDirectSound3DBufferImpl_Release
,
566 /* IDirectSound3DBuffer methods */
567 IDirectSound3DBufferImpl_GetAllParameters
,
568 IDirectSound3DBufferImpl_GetConeAngles
,
569 IDirectSound3DBufferImpl_GetConeOrientation
,
570 IDirectSound3DBufferImpl_GetConeOutsideVolume
,
571 IDirectSound3DBufferImpl_GetMaxDistance
,
572 IDirectSound3DBufferImpl_GetMinDistance
,
573 IDirectSound3DBufferImpl_GetMode
,
574 IDirectSound3DBufferImpl_GetPosition
,
575 IDirectSound3DBufferImpl_GetVelocity
,
576 IDirectSound3DBufferImpl_SetAllParameters
,
577 IDirectSound3DBufferImpl_SetConeAngles
,
578 IDirectSound3DBufferImpl_SetConeOrientation
,
579 IDirectSound3DBufferImpl_SetConeOutsideVolume
,
580 IDirectSound3DBufferImpl_SetMaxDistance
,
581 IDirectSound3DBufferImpl_SetMinDistance
,
582 IDirectSound3DBufferImpl_SetMode
,
583 IDirectSound3DBufferImpl_SetPosition
,
584 IDirectSound3DBufferImpl_SetVelocity
,
589 static int DSOUND_Create3DBuffer(IDirectSoundBufferImpl
* dsb
)
591 DWORD i
, temp
, iSize
, oSize
, offset
;
592 LPBYTE bIbuf
, bObuf
, bTbuf
= NULL
;
593 LPWORD wIbuf
, wObuf
, wTbuf
= NULL
;
595 /* Inside DirectX says it's stupid but allowed */
596 if (dsb
->wfx
.nChannels
== 2) {
597 /* Convert to mono */
598 if (dsb
->wfx
.wBitsPerSample
== 16) {
599 iSize
= dsb
->buflen
/ 4;
600 wTbuf
= malloc(dsb
->buflen
/ 2);
602 return DSERR_OUTOFMEMORY
;
603 for (i
= 0; i
< iSize
; i
++)
604 wTbuf
[i
] = (dsb
->buffer
[i
] + dsb
->buffer
[(i
* 2) + 1]) / 2;
607 iSize
= dsb
->buflen
/ 2;
608 bTbuf
= malloc(dsb
->buflen
/ 2);
610 return DSERR_OUTOFMEMORY
;
611 for (i
= 0; i
< iSize
; i
++)
612 bTbuf
[i
] = (dsb
->buffer
[i
] + dsb
->buffer
[(i
* 2) + 1]) / 2;
616 if (dsb
->wfx
.wBitsPerSample
== 16) {
617 iSize
= dsb
->buflen
/ 2;
618 wIbuf
= (LPWORD
) dsb
->buffer
;
620 bIbuf
= (LPBYTE
) dsb
->buffer
;
625 if (primarybuf
->wfx
.wBitsPerSample
== 16) {
626 wObuf
= (LPWORD
) dsb
->ds3db
->buffer
;
627 oSize
= dsb
->ds3db
->buflen
/ 2;
629 bObuf
= (LPBYTE
) dsb
->ds3db
->buffer
;
630 oSize
= dsb
->ds3db
->buflen
;
633 offset
= primarybuf
->wfx
.nSamplesPerSec
/ 100; /* 10ms */
634 if (primarybuf
->wfx
.wBitsPerSample
== 16 && dsb
->wfx
.wBitsPerSample
== 16)
635 for (i
= 0; i
< iSize
; i
++) {
638 temp
+= wIbuf
[i
- offset
] >> 9;
640 temp
+= wIbuf
[i
+ iSize
- offset
] >> 9;
642 wObuf
[(i
* 2) + 1] = temp
;
644 else if (primarybuf
->wfx
.wBitsPerSample
== 8 && dsb
->wfx
.wBitsPerSample
== 8)
645 for (i
= 0; i
< iSize
; i
++) {
648 temp
+= bIbuf
[i
- offset
] >> 5;
650 temp
+= bIbuf
[i
+ iSize
- offset
] >> 5;
652 bObuf
[(i
* 2) + 1] = temp
;
663 /*******************************************************************************
664 * IDirectSound3DListener
667 /* IUnknown methods */
668 static HRESULT WINAPI
IDirectSound3DListenerImpl_QueryInterface(
669 LPDIRECTSOUND3DLISTENER iface
, REFIID riid
, LPVOID
*ppobj
)
671 ICOM_THIS(IDirectSound3DListenerImpl
,iface
);
673 TRACE("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
677 static ULONG WINAPI
IDirectSound3DListenerImpl_AddRef(LPDIRECTSOUND3DLISTENER iface
)
679 ICOM_THIS(IDirectSound3DListenerImpl
,iface
);
684 static ULONG WINAPI
IDirectSound3DListenerImpl_Release(LPDIRECTSOUND3DLISTENER iface
)
687 ICOM_THIS(IDirectSound3DListenerImpl
,iface
);
689 TRACE("(%p) ref was %ld\n", This
, This
->ref
);
691 ulReturn
= --This
->ref
;
693 /* Free all resources */
694 if( ulReturn
== 0 ) {
696 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)This
->dsb
);
697 DeleteCriticalSection(&This
->lock
);
698 HeapFree(GetProcessHeap(),0,This
);
704 /* IDirectSound3DListener methods */
705 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetAllParameter(
706 LPDIRECTSOUND3DLISTENER iface
,
707 LPDS3DLISTENER lpDS3DL
)
713 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetDistanceFactor(
714 LPDIRECTSOUND3DLISTENER iface
,
715 LPD3DVALUE lpfDistanceFactor
)
721 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetDopplerFactor(
722 LPDIRECTSOUND3DLISTENER iface
,
723 LPD3DVALUE lpfDopplerFactor
)
729 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetOrientation(
730 LPDIRECTSOUND3DLISTENER iface
,
731 LPD3DVECTOR lpvOrientFront
,
732 LPD3DVECTOR lpvOrientTop
)
738 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetPosition(
739 LPDIRECTSOUND3DLISTENER iface
,
740 LPD3DVECTOR lpvPosition
)
746 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetRolloffFactor(
747 LPDIRECTSOUND3DLISTENER iface
,
748 LPD3DVALUE lpfRolloffFactor
)
754 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetVelocity(
755 LPDIRECTSOUND3DLISTENER iface
,
756 LPD3DVECTOR lpvVelocity
)
762 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetAllParameters(
763 LPDIRECTSOUND3DLISTENER iface
,
764 LPCDS3DLISTENER lpcDS3DL
,
771 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetDistanceFactor(
772 LPDIRECTSOUND3DLISTENER iface
,
773 D3DVALUE fDistanceFactor
,
780 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetDopplerFactor(
781 LPDIRECTSOUND3DLISTENER iface
,
782 D3DVALUE fDopplerFactor
,
789 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetOrientation(
790 LPDIRECTSOUND3DLISTENER iface
,
791 D3DVALUE xFront
, D3DVALUE yFront
, D3DVALUE zFront
,
792 D3DVALUE xTop
, D3DVALUE yTop
, D3DVALUE zTop
,
799 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetPosition(
800 LPDIRECTSOUND3DLISTENER iface
,
801 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
808 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetRolloffFactor(
809 LPDIRECTSOUND3DLISTENER iface
,
810 D3DVALUE fRolloffFactor
,
817 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetVelocity(
818 LPDIRECTSOUND3DLISTENER iface
,
819 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
826 static HRESULT WINAPI
IDirectSound3DListenerImpl_CommitDeferredSettings(
827 LPDIRECTSOUND3DLISTENER iface
)
834 static ICOM_VTABLE(IDirectSound3DListener
) ds3dlvt
=
836 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
837 /* IUnknown methods */
838 IDirectSound3DListenerImpl_QueryInterface
,
839 IDirectSound3DListenerImpl_AddRef
,
840 IDirectSound3DListenerImpl_Release
,
841 /* IDirectSound3DListener methods */
842 IDirectSound3DListenerImpl_GetAllParameter
,
843 IDirectSound3DListenerImpl_GetDistanceFactor
,
844 IDirectSound3DListenerImpl_GetDopplerFactor
,
845 IDirectSound3DListenerImpl_GetOrientation
,
846 IDirectSound3DListenerImpl_GetPosition
,
847 IDirectSound3DListenerImpl_GetRolloffFactor
,
848 IDirectSound3DListenerImpl_GetVelocity
,
849 IDirectSound3DListenerImpl_SetAllParameters
,
850 IDirectSound3DListenerImpl_SetDistanceFactor
,
851 IDirectSound3DListenerImpl_SetDopplerFactor
,
852 IDirectSound3DListenerImpl_SetOrientation
,
853 IDirectSound3DListenerImpl_SetPosition
,
854 IDirectSound3DListenerImpl_SetRolloffFactor
,
855 IDirectSound3DListenerImpl_SetVelocity
,
856 IDirectSound3DListenerImpl_CommitDeferredSettings
,
859 /*******************************************************************************
862 static HRESULT WINAPI
IDirectSoundNotifyImpl_QueryInterface(
863 LPDIRECTSOUNDNOTIFY iface
,REFIID riid
,LPVOID
*ppobj
865 ICOM_THIS(IDirectSoundNotifyImpl
,iface
);
867 TRACE("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
871 static ULONG WINAPI
IDirectSoundNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface
) {
872 ICOM_THIS(IDirectSoundNotifyImpl
,iface
);
873 return ++(This
->ref
);
876 static ULONG WINAPI
IDirectSoundNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface
) {
877 ICOM_THIS(IDirectSoundNotifyImpl
,iface
);
879 TRACE("(%p) ref was %ld\n", This
, This
->ref
);
883 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)This
->dsb
);
884 HeapFree(GetProcessHeap(),0,This
);
890 static HRESULT WINAPI
IDirectSoundNotifyImpl_SetNotificationPositions(
891 LPDIRECTSOUNDNOTIFY iface
,DWORD howmuch
,LPCDSBPOSITIONNOTIFY notify
893 ICOM_THIS(IDirectSoundNotifyImpl
,iface
);
896 if (TRACE_ON(dsound
)) {
897 TRACE("(%p,0x%08lx,%p)\n",This
,howmuch
,notify
);
898 for (i
=0;i
<howmuch
;i
++)
899 TRACE("notify at %ld to 0x%08lx\n",
900 notify
[i
].dwOffset
,(DWORD
)notify
[i
].hEventNotify
);
902 This
->dsb
->notifies
= HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,This
->dsb
->notifies
,(This
->dsb
->nrofnotifies
+howmuch
)*sizeof(DSBPOSITIONNOTIFY
));
903 memcpy( This
->dsb
->notifies
+This
->dsb
->nrofnotifies
,
905 howmuch
*sizeof(DSBPOSITIONNOTIFY
)
907 This
->dsb
->nrofnotifies
+=howmuch
;
912 static ICOM_VTABLE(IDirectSoundNotify
) dsnvt
=
914 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
915 IDirectSoundNotifyImpl_QueryInterface
,
916 IDirectSoundNotifyImpl_AddRef
,
917 IDirectSoundNotifyImpl_Release
,
918 IDirectSoundNotifyImpl_SetNotificationPositions
,
921 /*******************************************************************************
925 static void DSOUND_RecalcVolPan(PDSVOLUMEPAN volpan
)
929 /* the AmpFactors are expressed in 16.16 fixed point */
930 volpan
->dwVolAmpFactor
= (ULONG
) (pow(2.0, volpan
->lVolume
/ 600.0) * 65536);
931 /* FIXME: dwPan{Left|Right}AmpFactor */
933 /* FIXME: use calculated vol and pan ampfactors */
934 temp
= (double) (volpan
->lVolume
- (volpan
->lPan
> 0 ? volpan
->lPan
: 0));
935 volpan
->dwTotalLeftAmpFactor
= (ULONG
) (pow(2.0, temp
/ 600.0) * 65536);
936 temp
= (double) (volpan
->lVolume
+ (volpan
->lPan
< 0 ? volpan
->lPan
: 0));
937 volpan
->dwTotalRightAmpFactor
= (ULONG
) (pow(2.0, temp
/ 600.0) * 65536);
939 TRACE("left = %lx, right = %lx\n", volpan
->dwTotalLeftAmpFactor
, volpan
->dwTotalRightAmpFactor
);
942 static void DSOUND_RecalcFormat(IDirectSoundBufferImpl
*dsb
)
946 sw
= dsb
->wfx
.nChannels
* (dsb
->wfx
.wBitsPerSample
/ 8);
947 if ((dsb
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
) && dsb
->hwbuf
) {
949 /* let fragment size approximate the timer delay */
950 fraglen
= (dsb
->freq
* DS_TIME_DEL
/ 1000) * sw
;
951 /* reduce fragment size until an integer number of them fits in the buffer */
952 /* (FIXME: this may or may not be a good idea) */
953 while (dsb
->buflen
% fraglen
) fraglen
-= sw
;
954 dsb
->dsound
->fraglen
= fraglen
;
955 TRACE("fraglen=%ld\n", dsb
->dsound
->fraglen
);
957 /* calculate the 10ms write lead */
958 dsb
->writelead
= (dsb
->freq
/ 100) * sw
;
961 static HRESULT
DSOUND_PrimaryOpen(IDirectSoundBufferImpl
*dsb
)
965 /* are we using waveOut stuff? */
969 HRESULT merr
= DS_OK
;
970 /* Start in pause mode, to allow buffers to get filled */
971 waveOutPause(dsb
->dsound
->hwo
);
972 /* use fragments of 10ms (1/100s) each (which should get us within
973 * the documented write cursor lead of 10-15ms) */
974 buflen
= ((dsb
->wfx
.nAvgBytesPerSec
/ 100) & ~3) * DS_HEL_FRAGS
;
975 TRACE("desired buflen=%ld, old buffer=%p\n", buflen
, dsb
->buffer
);
976 /* reallocate emulated primary buffer */
977 newbuf
= (LPBYTE
)HeapReAlloc(GetProcessHeap(),0,dsb
->buffer
,buflen
);
978 if (newbuf
== NULL
) {
979 ERR("failed to allocate primary buffer\n");
980 merr
= DSERR_OUTOFMEMORY
;
981 /* but the old buffer might still exists and must be re-prepared */
983 dsb
->buffer
= newbuf
;
984 dsb
->buflen
= buflen
;
988 IDirectSoundImpl
*ds
= dsb
->dsound
;
990 ds
->fraglen
= dsb
->buflen
/ DS_HEL_FRAGS
;
992 /* prepare fragment headers */
993 for (c
=0; c
<DS_HEL_FRAGS
; c
++) {
994 ds
->pwave
[c
]->lpData
= dsb
->buffer
+ c
*ds
->fraglen
;
995 ds
->pwave
[c
]->dwBufferLength
= ds
->fraglen
;
996 ds
->pwave
[c
]->dwUser
= (DWORD
)dsb
;
997 ds
->pwave
[c
]->dwFlags
= 0;
998 ds
->pwave
[c
]->dwLoops
= 0;
999 err
= mmErr(waveOutPrepareHeader(ds
->hwo
,ds
->pwave
[c
],sizeof(WAVEHDR
)));
1002 waveOutUnprepareHeader(ds
->hwo
,ds
->pwave
[c
],sizeof(WAVEHDR
));
1010 memset(dsb
->buffer
, (dsb
->wfx
.wBitsPerSample
== 16) ? 0 : 128, dsb
->buflen
);
1011 TRACE("fraglen=%ld\n", ds
->fraglen
);
1013 if ((err
== DS_OK
) && (merr
!= DS_OK
))
1020 static void DSOUND_PrimaryClose(IDirectSoundBufferImpl
*dsb
)
1022 /* are we using waveOut stuff? */
1025 IDirectSoundImpl
*ds
= dsb
->dsound
;
1027 waveOutReset(ds
->hwo
);
1028 for (c
=0; c
<DS_HEL_FRAGS
; c
++)
1029 waveOutUnprepareHeader(ds
->hwo
, ds
->pwave
[c
], sizeof(WAVEHDR
));
1033 /* This sets this format for the <em>Primary Buffer Only</em> */
1034 /* See file:///cdrom/sdk52/docs/worddoc/dsound.doc page 120 */
1035 static HRESULT WINAPI
IDirectSoundBufferImpl_SetFormat(
1036 LPDIRECTSOUNDBUFFER iface
,LPWAVEFORMATEX wfex
1038 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1039 IDirectSoundBufferImpl
** dsb
;
1040 HRESULT err
= DS_OK
;
1043 /* Let's be pedantic! */
1044 if ((wfex
== NULL
) ||
1045 (wfex
->wFormatTag
!= WAVE_FORMAT_PCM
) ||
1046 (wfex
->nChannels
< 1) || (wfex
->nChannels
> 2) ||
1047 (wfex
->nSamplesPerSec
< 1) ||
1048 (wfex
->nBlockAlign
< 1) || (wfex
->nChannels
> 4) ||
1049 ((wfex
->wBitsPerSample
!= 8) && (wfex
->wBitsPerSample
!= 16))) {
1050 TRACE("failed pedantic check!\n");
1051 return DSERR_INVALIDPARAM
;
1055 EnterCriticalSection(&(This
->dsound
->lock
));
1057 if (primarybuf
->wfx
.nSamplesPerSec
!= wfex
->nSamplesPerSec
) {
1058 dsb
= dsound
->buffers
;
1059 for (i
= 0; i
< dsound
->nrofbuffers
; i
++, dsb
++) {
1061 EnterCriticalSection(&((*dsb
)->lock
));
1063 (*dsb
)->freqAdjust
= ((*dsb
)->freq
<< DSOUND_FREQSHIFT
) /
1064 wfex
->nSamplesPerSec
;
1066 LeaveCriticalSection(&((*dsb
)->lock
));
1071 memcpy(&(primarybuf
->wfx
), wfex
, sizeof(primarybuf
->wfx
));
1073 TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld,"
1074 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
1075 wfex
->wFormatTag
, wfex
->nChannels
, wfex
->nSamplesPerSec
,
1076 wfex
->nAvgBytesPerSec
, wfex
->nBlockAlign
,
1077 wfex
->wBitsPerSample
, wfex
->cbSize
);
1079 primarybuf
->wfx
.nAvgBytesPerSec
=
1080 This
->wfx
.nSamplesPerSec
* This
->wfx
.nBlockAlign
;
1081 if (primarybuf
->dsound
->drvdesc
.dwFlags
& DSDDESC_DOMMSYSTEMSETFORMAT
) {
1082 /* FIXME: check for errors */
1083 DSOUND_PrimaryClose(primarybuf
);
1084 waveOutClose(This
->dsound
->hwo
);
1085 This
->dsound
->hwo
= 0;
1086 waveOutOpen(&(This
->dsound
->hwo
), This
->dsound
->drvdesc
.dnDevNode
,
1087 &(primarybuf
->wfx
), 0, 0, CALLBACK_NULL
| WAVE_DIRECTSOUND
);
1088 DSOUND_PrimaryOpen(primarybuf
);
1090 if (primarybuf
->hwbuf
) {
1091 err
= IDsDriverBuffer_SetFormat(primarybuf
->hwbuf
, &(primarybuf
->wfx
));
1092 if (err
== DSERR_BUFFERLOST
) {
1093 /* Wine-only: the driver wants us to recreate the HW buffer */
1094 IDsDriverBuffer_Release(primarybuf
->hwbuf
);
1095 err
= IDsDriver_CreateSoundBuffer(primarybuf
->dsound
->driver
,&(primarybuf
->wfx
),primarybuf
->dsbd
.dwFlags
,0,
1096 &(primarybuf
->buflen
),&(primarybuf
->buffer
),
1097 (LPVOID
)&(primarybuf
->hwbuf
));
1100 DSOUND_RecalcFormat(primarybuf
);
1102 LeaveCriticalSection(&(This
->dsound
->lock
));
1108 static HRESULT WINAPI
IDirectSoundBufferImpl_SetVolume(
1109 LPDIRECTSOUNDBUFFER iface
,LONG vol
1111 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1113 TRACE("(%p,%ld)\n",This
,vol
);
1115 /* I'm not sure if we need this for primary buffer */
1116 if (!(This
->dsbd
.dwFlags
& DSBCAPS_CTRLVOLUME
))
1117 return DSERR_CONTROLUNAVAIL
;
1119 if ((vol
> DSBVOLUME_MAX
) || (vol
< DSBVOLUME_MIN
))
1120 return DSERR_INVALIDPARAM
;
1123 EnterCriticalSection(&(This
->lock
));
1125 This
->volpan
.lVolume
= vol
;
1127 DSOUND_RecalcVolPan(&(This
->volpan
));
1130 IDsDriverBuffer_SetVolumePan(This
->hwbuf
, &(This
->volpan
));
1132 else if (This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
1133 #if 0 /* should we really do this? */
1134 /* the DS volume ranges from 0 (max, 0dB attenuation) to -10000 (min, 100dB attenuation) */
1135 /* the MM volume ranges from 0 to 0xffff in an unspecified logarithmic scale */
1136 WORD cvol
= 0xffff + vol
*6 + vol
/2;
1137 DWORD vol
= cvol
| ((DWORD
)cvol
<< 16)
1138 waveOutSetVolume(This
->dsound
->hwo
, vol
);
1142 LeaveCriticalSection(&(This
->lock
));
1148 static HRESULT WINAPI
IDirectSoundBufferImpl_GetVolume(
1149 LPDIRECTSOUNDBUFFER iface
,LPLONG vol
1151 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1152 TRACE("(%p,%p)\n",This
,vol
);
1155 return DSERR_INVALIDPARAM
;
1157 *vol
= This
->volpan
.lVolume
;
1161 static HRESULT WINAPI
IDirectSoundBufferImpl_SetFrequency(
1162 LPDIRECTSOUNDBUFFER iface
,DWORD freq
1164 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1165 TRACE("(%p,%ld)\n",This
,freq
);
1167 /* You cannot set the frequency of the primary buffer */
1168 if (!(This
->dsbd
.dwFlags
& DSBCAPS_CTRLFREQUENCY
) ||
1169 (This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
))
1170 return DSERR_CONTROLUNAVAIL
;
1172 if (!freq
) freq
= This
->wfx
.nSamplesPerSec
;
1174 if ((freq
< DSBFREQUENCY_MIN
) || (freq
> DSBFREQUENCY_MAX
))
1175 return DSERR_INVALIDPARAM
;
1178 EnterCriticalSection(&(This
->lock
));
1181 This
->freqAdjust
= (freq
<< DSOUND_FREQSHIFT
) / primarybuf
->wfx
.nSamplesPerSec
;
1182 This
->nAvgBytesPerSec
= freq
* This
->wfx
.nBlockAlign
;
1183 DSOUND_RecalcFormat(This
);
1185 LeaveCriticalSection(&(This
->lock
));
1191 static HRESULT WINAPI
IDirectSoundBufferImpl_Play(
1192 LPDIRECTSOUNDBUFFER iface
,DWORD reserved1
,DWORD reserved2
,DWORD flags
1194 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1195 TRACE("(%p,%08lx,%08lx,%08lx)\n",
1196 This
,reserved1
,reserved2
,flags
1198 This
->playflags
= flags
;
1199 if (This
->state
== STATE_STOPPED
) {
1200 This
->leadin
= TRUE
;
1201 This
->startpos
= This
->mixpos
;
1202 This
->state
= STATE_STARTING
;
1203 } else if (This
->state
== STATE_STOPPING
)
1204 This
->state
= STATE_PLAYING
;
1205 if (!(This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
) && This
->hwbuf
) {
1206 IDsDriverBuffer_Play(This
->hwbuf
, 0, 0, This
->playflags
);
1207 This
->state
= STATE_PLAYING
;
1212 static HRESULT WINAPI
IDirectSoundBufferImpl_Stop(LPDIRECTSOUNDBUFFER iface
)
1214 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1215 TRACE("(%p)\n",This
);
1218 EnterCriticalSection(&(This
->lock
));
1220 if (This
->state
== STATE_PLAYING
)
1221 This
->state
= STATE_STOPPING
;
1222 else if (This
->state
== STATE_STARTING
)
1223 This
->state
= STATE_STOPPED
;
1224 if (!(This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
) && This
->hwbuf
) {
1225 IDsDriverBuffer_Stop(This
->hwbuf
);
1226 This
->state
= STATE_STOPPED
;
1228 DSOUND_CheckEvent(This
, 0);
1230 LeaveCriticalSection(&(This
->lock
));
1236 static DWORD WINAPI
IDirectSoundBufferImpl_AddRef(LPDIRECTSOUNDBUFFER iface
) {
1237 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1240 TRACE("(%p) ref was %ld, thread is %lx\n",This
, This
->ref
, GetCurrentThreadId());
1242 ref
= InterlockedIncrement(&(This
->ref
));
1244 FIXME("thread-safety alert! AddRef-ing with a zero refcount!\n");
1248 static DWORD WINAPI
IDirectSoundBufferImpl_Release(LPDIRECTSOUNDBUFFER iface
) {
1249 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1253 TRACE("(%p) ref was %ld, thread is %lx\n",This
, This
->ref
, GetCurrentThreadId());
1255 ref
= InterlockedDecrement(&(This
->ref
));
1256 if (ref
) return ref
;
1258 EnterCriticalSection(&(This
->dsound
->lock
));
1259 for (i
=0;i
<This
->dsound
->nrofbuffers
;i
++)
1260 if (This
->dsound
->buffers
[i
] == This
)
1263 if (i
< This
->dsound
->nrofbuffers
) {
1264 /* Put the last buffer of the list in the (now empty) position */
1265 This
->dsound
->buffers
[i
] = This
->dsound
->buffers
[This
->dsound
->nrofbuffers
- 1];
1266 This
->dsound
->nrofbuffers
--;
1267 This
->dsound
->buffers
= HeapReAlloc(GetProcessHeap(),0,This
->dsound
->buffers
,sizeof(LPDIRECTSOUNDBUFFER
)*This
->dsound
->nrofbuffers
);
1268 TRACE("buffer count is now %d\n", This
->dsound
->nrofbuffers
);
1269 IDirectSound_Release((LPDIRECTSOUND
)This
->dsound
);
1271 LeaveCriticalSection(&(This
->dsound
->lock
));
1273 DeleteCriticalSection(&(This
->lock
));
1274 if (This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
)
1275 DSOUND_PrimaryClose(This
);
1277 IDsDriverBuffer_Release(This
->hwbuf
);
1280 IDirectSound3DBuffer_Release((LPDIRECTSOUND3DBUFFER
)This
->ds3db
);
1282 /* this is a duplicate buffer */
1283 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)This
->parent
);
1285 /* this is a toplevel buffer */
1286 HeapFree(GetProcessHeap(),0,This
->buffer
);
1288 HeapFree(GetProcessHeap(),0,This
);
1290 if (This
== primarybuf
)
1296 static HRESULT WINAPI
IDirectSoundBufferImpl_GetCurrentPosition(
1297 LPDIRECTSOUNDBUFFER iface
,LPDWORD playpos
,LPDWORD writepos
1299 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1300 TRACE("(%p,%p,%p)\n",This
,playpos
,writepos
);
1302 IDsDriverBuffer_GetPosition(This
->hwbuf
, playpos
, writepos
);
1304 else if (This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
1305 if (playpos
&& (This
->dsbd
.dwFlags
& DSBCAPS_GETCURRENTPOSITION2
)) {
1307 mtime
.wType
= TIME_BYTES
;
1308 waveOutGetPosition(This
->dsound
->hwo
, &mtime
, sizeof(mtime
));
1309 mtime
.u
.cb
= mtime
.u
.cb
% This
->buflen
;
1310 *playpos
= mtime
.u
.cb
;
1312 /* don't know how exactly non-GETCURRENTPOSITION2 behaves,
1313 * but I think this works for Starcraft */
1314 else if (playpos
) *playpos
= This
->playpos
;
1316 /* the writepos should only be used by apps with WRITEPRIMARY priority,
1317 * in which case our software mixer is disabled anyway */
1318 *writepos
= This
->playpos
+ DS_HEL_MARGIN
* This
->dsound
->fraglen
;
1319 while (*writepos
>= This
->buflen
)
1320 *writepos
-= This
->buflen
;
1323 if (playpos
&& (This
->state
!= STATE_PLAYING
)) {
1324 /* we haven't been merged into the primary buffer (yet) */
1325 *playpos
= This
->mixpos
;
1328 DWORD pplay
, lplay
, splay
, tplay
, pstate
;
1329 /* let's get this exact; first, recursively call GetPosition on the primary */
1330 EnterCriticalSection(&(primarybuf
->lock
));
1331 if ((This
->dsbd
.dwFlags
& DSBCAPS_GETCURRENTPOSITION2
) || primarybuf
->hwbuf
) {
1332 IDirectSoundBufferImpl_GetCurrentPosition((LPDIRECTSOUNDBUFFER
)primarybuf
, &pplay
, NULL
);
1334 /* (unless the app isn't using GETCURRENTPOSITION2) */
1335 /* don't know exactly how this should be handled either */
1336 pplay
= primarybuf
->playpos
;
1338 /* get last mixed primary play position */
1339 lplay
= primarybuf
->mixpos
;
1340 pstate
= primarybuf
->state
;
1341 /* detect HEL mode underrun */
1342 if (!(primarybuf
->hwbuf
|| primarybuf
->dsound
->pwqueue
)) {
1343 TRACE("detected an underrun\n");
1345 if (pstate
== STATE_PLAYING
)
1346 pstate
= STATE_STARTING
;
1347 else if (pstate
== STATE_STOPPING
)
1348 pstate
= STATE_STOPPED
;
1350 /* get our own last mixed position while we still have the lock */
1351 splay
= This
->mixpos
;
1352 LeaveCriticalSection(&(primarybuf
->lock
));
1353 TRACE("primary playpos=%ld, mixpos=%ld\n", pplay
, lplay
);
1354 TRACE("this mixpos=%ld\n", splay
);
1356 /* the actual primary play position (pplay) is always behind last mixed (lplay),
1357 * unless the computer is too slow or something */
1358 /* we need to know how far away we are from there */
1359 if (lplay
== pplay
) {
1360 if ((pstate
== STATE_PLAYING
) || (pstate
== STATE_STOPPING
)) {
1361 /* wow, the software mixer is really doing well,
1362 * seems the entire primary buffer is filled! */
1363 lplay
+= primarybuf
->buflen
;
1365 /* else: the primary buffer is not playing, so probably empty */
1367 if (lplay
< pplay
) lplay
+= primarybuf
->buflen
; /* wraparound */
1369 /* detect HAL mode underrun */
1370 if (primarybuf
->hwbuf
&&
1371 (lplay
> ((DS_HAL_QUEUE
+ 1) * primarybuf
->dsound
->fraglen
+ primarybuf
->writelead
))) {
1372 TRACE("detected an underrun: primary queue was %ld\n",lplay
);
1375 /* divide the offset by its sample size */
1376 lplay
/= primarybuf
->wfx
.nChannels
* (primarybuf
->wfx
.wBitsPerSample
/ 8);
1377 TRACE("primary back-samples=%ld\n",lplay
);
1378 /* adjust for our frequency */
1379 lplay
= (lplay
* This
->freqAdjust
) >> DSOUND_FREQSHIFT
;
1380 /* multiply by our own sample size */
1381 lplay
*= This
->wfx
.nChannels
* (This
->wfx
.wBitsPerSample
/ 8);
1382 TRACE("this back-offset=%ld\n", lplay
);
1383 /* subtract from our last mixed position */
1385 while (tplay
< lplay
) tplay
+= This
->buflen
; /* wraparound */
1387 if (This
->leadin
&& ((tplay
< This
->startpos
) || (tplay
> splay
))) {
1388 /* seems we haven't started playing yet */
1389 TRACE("this still in lead-in phase\n");
1390 tplay
= This
->startpos
;
1392 /* return the result */
1395 if (writepos
) *writepos
= This
->mixpos
;
1398 if (This
->state
!= STATE_STOPPED
)
1399 /* apply the documented 10ms lead to writepos */
1400 *writepos
+= This
->writelead
;
1401 while (*writepos
>= This
->buflen
) *writepos
-= This
->buflen
;
1403 TRACE("playpos = %ld, writepos = %ld (%p, time=%ld)\n", playpos
?*playpos
:0, writepos
?*writepos
:0, This
, GetTickCount());
1407 static HRESULT WINAPI
IDirectSoundBufferImpl_GetStatus(
1408 LPDIRECTSOUNDBUFFER iface
,LPDWORD status
1410 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1411 TRACE("(%p,%p), thread is %lx\n",This
,status
,GetCurrentThreadId());
1414 return DSERR_INVALIDPARAM
;
1417 if ((This
->state
== STATE_STARTING
) || (This
->state
== STATE_PLAYING
))
1418 *status
|= DSBSTATUS_PLAYING
;
1419 if (This
->playflags
& DSBPLAY_LOOPING
)
1420 *status
|= DSBSTATUS_LOOPING
;
1422 TRACE("status=%lx\n", *status
);
1427 static HRESULT WINAPI
IDirectSoundBufferImpl_GetFormat(
1428 LPDIRECTSOUNDBUFFER iface
,LPWAVEFORMATEX lpwf
,DWORD wfsize
,LPDWORD wfwritten
1430 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1431 TRACE("(%p,%p,%ld,%p)\n",This
,lpwf
,wfsize
,wfwritten
);
1433 if (wfsize
>sizeof(This
->wfx
))
1434 wfsize
= sizeof(This
->wfx
);
1435 if (lpwf
) { /* NULL is valid */
1436 memcpy(lpwf
,&(This
->wfx
),wfsize
);
1438 *wfwritten
= wfsize
;
1441 *wfwritten
= sizeof(This
->wfx
);
1443 return DSERR_INVALIDPARAM
;
1448 static HRESULT WINAPI
IDirectSoundBufferImpl_Lock(
1449 LPDIRECTSOUNDBUFFER iface
,DWORD writecursor
,DWORD writebytes
,LPVOID lplpaudioptr1
,LPDWORD audiobytes1
,LPVOID lplpaudioptr2
,LPDWORD audiobytes2
,DWORD flags
1451 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1454 TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx)\n",
1465 if (flags
& DSBLOCK_FROMWRITECURSOR
) {
1467 /* GetCurrentPosition does too much magic to duplicate here */
1468 IDirectSoundBufferImpl_GetCurrentPosition(iface
, NULL
, &writepos
);
1469 writecursor
+= writepos
;
1471 if (flags
& DSBLOCK_ENTIREBUFFER
)
1472 writebytes
= This
->buflen
;
1473 if (writebytes
> This
->buflen
)
1474 writebytes
= This
->buflen
;
1476 assert(audiobytes1
!=audiobytes2
);
1477 assert(lplpaudioptr1
!=lplpaudioptr2
);
1479 if (This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
)
1480 capf
= DSDDESC_DONTNEEDPRIMARYLOCK
;
1482 capf
= DSDDESC_DONTNEEDSECONDARYLOCK
;
1483 if (!(This
->dsound
->drvdesc
.dwFlags
& capf
) && This
->hwbuf
) {
1484 IDsDriverBuffer_Lock(This
->hwbuf
,
1485 lplpaudioptr1
, audiobytes1
,
1486 lplpaudioptr2
, audiobytes2
,
1487 writecursor
, writebytes
,
1490 if (writecursor
+writebytes
<= This
->buflen
) {
1491 *(LPBYTE
*)lplpaudioptr1
= This
->buffer
+writecursor
;
1492 *audiobytes1
= writebytes
;
1494 *(LPBYTE
*)lplpaudioptr2
= NULL
;
1497 TRACE("->%ld.0\n",writebytes
);
1499 *(LPBYTE
*)lplpaudioptr1
= This
->buffer
+writecursor
;
1500 *audiobytes1
= This
->buflen
-writecursor
;
1502 *(LPBYTE
*)lplpaudioptr2
= This
->buffer
;
1504 *audiobytes2
= writebytes
-(This
->buflen
-writecursor
);
1505 TRACE("->%ld.%ld\n",*audiobytes1
,audiobytes2
?*audiobytes2
:0);
1510 static HRESULT WINAPI
IDirectSoundBufferImpl_SetCurrentPosition(
1511 LPDIRECTSOUNDBUFFER iface
,DWORD newpos
1513 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1514 TRACE("(%p,%ld)\n",This
,newpos
);
1517 EnterCriticalSection(&(This
->lock
));
1519 This
->mixpos
= newpos
;
1521 IDsDriverBuffer_SetPosition(This
->hwbuf
, This
->mixpos
);
1523 LeaveCriticalSection(&(This
->lock
));
1529 static HRESULT WINAPI
IDirectSoundBufferImpl_SetPan(
1530 LPDIRECTSOUNDBUFFER iface
,LONG pan
1532 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1534 TRACE("(%p,%ld)\n",This
,pan
);
1536 if ((pan
> DSBPAN_RIGHT
) || (pan
< DSBPAN_LEFT
))
1537 return DSERR_INVALIDPARAM
;
1539 /* You cannot set the pan of the primary buffer */
1540 /* and you cannot use both pan and 3D controls */
1541 if (!(This
->dsbd
.dwFlags
& DSBCAPS_CTRLPAN
) ||
1542 (This
->dsbd
.dwFlags
& DSBCAPS_CTRL3D
) ||
1543 (This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
))
1544 return DSERR_CONTROLUNAVAIL
;
1547 EnterCriticalSection(&(This
->lock
));
1549 This
->volpan
.lPan
= pan
;
1551 DSOUND_RecalcVolPan(&(This
->volpan
));
1554 IDsDriverBuffer_SetVolumePan(This
->hwbuf
, &(This
->volpan
));
1557 LeaveCriticalSection(&(This
->lock
));
1563 static HRESULT WINAPI
IDirectSoundBufferImpl_GetPan(
1564 LPDIRECTSOUNDBUFFER iface
,LPLONG pan
1566 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1567 TRACE("(%p,%p)\n",This
,pan
);
1570 return DSERR_INVALIDPARAM
;
1572 *pan
= This
->volpan
.lPan
;
1577 static HRESULT WINAPI
IDirectSoundBufferImpl_Unlock(
1578 LPDIRECTSOUNDBUFFER iface
,LPVOID p1
,DWORD x1
,LPVOID p2
,DWORD x2
1580 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1583 TRACE("(%p,%p,%ld,%p,%ld):stub\n", This
,p1
,x1
,p2
,x2
);
1586 /* Preprocess 3D buffers... */
1588 /* This is highly experimental and liable to break things */
1589 if (This
->dsbd
.dwFlags
& DSBCAPS_CTRL3D
)
1590 DSOUND_Create3DBuffer(This
);
1593 if (This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
)
1594 capf
= DSDDESC_DONTNEEDPRIMARYLOCK
;
1596 capf
= DSDDESC_DONTNEEDSECONDARYLOCK
;
1597 if (!(This
->dsound
->drvdesc
.dwFlags
& capf
) && This
->hwbuf
) {
1598 IDsDriverBuffer_Unlock(This
->hwbuf
, p1
, x1
, p2
, x2
);
1604 static HRESULT WINAPI
IDirectSoundBufferImpl_Restore(
1605 LPDIRECTSOUNDBUFFER iface
1607 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1608 FIXME("(%p):stub\n",This
);
1612 static HRESULT WINAPI
IDirectSoundBufferImpl_GetFrequency(
1613 LPDIRECTSOUNDBUFFER iface
,LPDWORD freq
1615 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1616 TRACE("(%p,%p)\n",This
,freq
);
1619 return DSERR_INVALIDPARAM
;
1622 TRACE("-> %ld\n", *freq
);
1627 static HRESULT WINAPI
IDirectSoundBufferImpl_Initialize(
1628 LPDIRECTSOUNDBUFFER iface
,LPDIRECTSOUND dsound
,LPDSBUFFERDESC dbsd
1630 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1631 FIXME("(%p,%p,%p):stub\n",This
,dsound
,dbsd
);
1632 DPRINTF("Re-Init!!!\n");
1633 return DSERR_ALREADYINITIALIZED
;
1636 static HRESULT WINAPI
IDirectSoundBufferImpl_GetCaps(
1637 LPDIRECTSOUNDBUFFER iface
,LPDSBCAPS caps
1639 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1640 TRACE("(%p)->(%p)\n",This
,caps
);
1643 return DSERR_INVALIDPARAM
;
1645 /* I think we should check this value, not set it. See */
1646 /* Inside DirectX, p215. That should apply here, too. */
1647 caps
->dwSize
= sizeof(*caps
);
1649 caps
->dwFlags
= This
->dsbd
.dwFlags
;
1650 if (This
->hwbuf
) caps
->dwFlags
|= DSBCAPS_LOCHARDWARE
;
1651 else caps
->dwFlags
|= DSBCAPS_LOCSOFTWARE
;
1653 caps
->dwBufferBytes
= This
->dsbd
.dwBufferBytes
;
1655 /* This value represents the speed of the "unlock" command.
1656 As unlock is quite fast (it does not do anything), I put
1657 4096 ko/s = 4 Mo / s */
1658 /* FIXME: hwbuf speed */
1659 caps
->dwUnlockTransferRate
= 4096;
1660 caps
->dwPlayCpuOverhead
= 0;
1665 static HRESULT WINAPI
IDirectSoundBufferImpl_QueryInterface(
1666 LPDIRECTSOUNDBUFFER iface
,REFIID riid
,LPVOID
*ppobj
1668 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1670 TRACE("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
1672 if ( IsEqualGUID( &IID_IDirectSoundNotify
, riid
) ) {
1673 IDirectSoundNotifyImpl
*dsn
;
1675 dsn
= (IDirectSoundNotifyImpl
*)HeapAlloc(GetProcessHeap(),0,sizeof(*dsn
));
1678 IDirectSoundBuffer_AddRef(iface
);
1679 ICOM_VTBL(dsn
) = &dsnvt
;
1680 *ppobj
= (LPVOID
)dsn
;
1685 if ( IsEqualGUID( &IID_IDirectSound3DBuffer
, riid
) ) {
1686 IDirectSound3DBufferImpl
*ds3db
;
1688 *ppobj
= This
->ds3db
;
1690 IDirectSound3DBuffer_AddRef((LPDIRECTSOUND3DBUFFER
)This
->ds3db
);
1694 ds3db
= (IDirectSound3DBufferImpl
*)HeapAlloc(GetProcessHeap(),
1697 ds3db
->dsb
= (*ippdsb
);
1698 ICOM_VTBL(ds3db
) = &ds3dbvt
;
1699 InitializeCriticalSection(&ds3db
->lock
);
1701 ds3db
->ds3db
= This
;
1702 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER
)This
);
1704 ds3db
->ds3db
.dwSize
= sizeof(DS3DBUFFER
);
1705 ds3db
->ds3db
.vPosition
.x
.x
= 0.0;
1706 ds3db
->ds3db
.vPosition
.y
.y
= 0.0;
1707 ds3db
->ds3db
.vPosition
.z
.z
= 0.0;
1708 ds3db
->ds3db
.vVelocity
.x
.x
= 0.0;
1709 ds3db
->ds3db
.vVelocity
.y
.y
= 0.0;
1710 ds3db
->ds3db
.vVelocity
.z
.z
= 0.0;
1711 ds3db
->ds3db
.dwInsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
1712 ds3db
->ds3db
.dwOutsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
1713 ds3db
->ds3db
.vConeOrientation
.x
.x
= 0.0;
1714 ds3db
->ds3db
.vConeOrientation
.y
.y
= 0.0;
1715 ds3db
->ds3db
.vConeOrientation
.z
.z
= 0.0;
1716 ds3db
->ds3db
.lConeOutsideVolume
= DS3D_DEFAULTCONEOUTSIDEVOLUME
; ds3db
->ds3db
.flMinDistance
= DS3D_DEFAULTMINDISTANCE
;
1717 ds3db
->ds3db
.flMaxDistance
= DS3D_DEFAULTMAXDISTANCE
;
1718 ds3db
->ds3db
.dwMode
= DS3DMODE_NORMAL
;
1719 ds3db
->buflen
= ((*ippdsb
)->buflen
* primarybuf
->wfx
.nBlockAlign
) /
1720 (*ippdsb
)->wfx
.nBlockAlign
;
1721 ds3db
->buffer
= HeapAlloc(GetProcessHeap(), 0, ds3db
->buflen
);
1722 if (ds3db
->buffer
== NULL
) {
1724 ds3db
->ds3db
.dwMode
= DS3DMODE_DISABLE
;
1731 if ( IsEqualGUID( &IID_IDirectSound3DListener
, riid
) ) {
1732 IDirectSound3DListenerImpl
* dsl
;
1734 if (This
->dsound
->listener
) {
1735 *ppobj
= This
->dsound
->listener
;
1736 IDirectSound3DListener_AddRef((LPDIRECTSOUND3DLISTENER
)This
->dsound
->listener
);
1740 dsl
= (IDirectSound3DListenerImpl
*)HeapAlloc(GetProcessHeap(),0,sizeof(*dsl
));
1742 ICOM_VTBL(dsl
) = &ds3dlvt
;
1743 *ppobj
= (LPVOID
)dsl
;
1745 dsl
->ds3dl
.dwSize
= sizeof(DS3DLISTENER
);
1746 dsl
->ds3dl
.vPosition
.u1
.x
= 0.0;
1747 dsl
->ds3dl
.vPosition
.u2
.y
= 0.0;
1748 dsl
->ds3dl
.vPosition
.u3
.z
= 0.0;
1749 dsl
->ds3dl
.vVelocity
.u1
.x
= 0.0;
1750 dsl
->ds3dl
.vVelocity
.u2
.y
= 0.0;
1751 dsl
->ds3dl
.vVelocity
.u3
.z
= 0.0;
1752 dsl
->ds3dl
.vOrientFront
.u1
.x
= 0.0;
1753 dsl
->ds3dl
.vOrientFront
.u2
.y
= 0.0;
1754 dsl
->ds3dl
.vOrientFront
.u3
.z
= 1.0;
1755 dsl
->ds3dl
.vOrientTop
.u1
.x
= 0.0;
1756 dsl
->ds3dl
.vOrientTop
.u2
.y
= 1.0;
1757 dsl
->ds3dl
.vOrientTop
.u3
.z
= 0.0;
1758 dsl
->ds3dl
.flDistanceFactor
= DS3D_DEFAULTDISTANCEFACTOR
;
1759 dsl
->ds3dl
.flRolloffFactor
= DS3D_DEFAULTROLLOFFFACTOR
;
1761 InitializeCriticalSection(&dsl
->lock
);
1764 IDirectSoundBuffer_AddRef(iface
);
1766 This
->dsound
->listener
= dsl
;
1767 IDirectSound3DListener_AddRef((LPDIRECTSOUND3DLISTENER
)dsl
);
1772 FIXME( "Unknown GUID %s\n", debugstr_guid( riid
) );
1779 static ICOM_VTABLE(IDirectSoundBuffer
) dsbvt
=
1781 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1782 IDirectSoundBufferImpl_QueryInterface
,
1783 IDirectSoundBufferImpl_AddRef
,
1784 IDirectSoundBufferImpl_Release
,
1785 IDirectSoundBufferImpl_GetCaps
,
1786 IDirectSoundBufferImpl_GetCurrentPosition
,
1787 IDirectSoundBufferImpl_GetFormat
,
1788 IDirectSoundBufferImpl_GetVolume
,
1789 IDirectSoundBufferImpl_GetPan
,
1790 IDirectSoundBufferImpl_GetFrequency
,
1791 IDirectSoundBufferImpl_GetStatus
,
1792 IDirectSoundBufferImpl_Initialize
,
1793 IDirectSoundBufferImpl_Lock
,
1794 IDirectSoundBufferImpl_Play
,
1795 IDirectSoundBufferImpl_SetCurrentPosition
,
1796 IDirectSoundBufferImpl_SetFormat
,
1797 IDirectSoundBufferImpl_SetVolume
,
1798 IDirectSoundBufferImpl_SetPan
,
1799 IDirectSoundBufferImpl_SetFrequency
,
1800 IDirectSoundBufferImpl_Stop
,
1801 IDirectSoundBufferImpl_Unlock
,
1802 IDirectSoundBufferImpl_Restore
1805 /*******************************************************************************
1809 static HRESULT WINAPI
IDirectSoundImpl_SetCooperativeLevel(
1810 LPDIRECTSOUND iface
,HWND hwnd
,DWORD level
1812 ICOM_THIS(IDirectSoundImpl
,iface
);
1814 FIXME("(%p,%08lx,%ld):stub\n",This
,(DWORD
)hwnd
,level
);
1816 This
->priolevel
= level
;
1821 static HRESULT WINAPI
IDirectSoundImpl_CreateSoundBuffer(
1822 LPDIRECTSOUND iface
,LPDSBUFFERDESC dsbd
,LPLPDIRECTSOUNDBUFFER ppdsb
,LPUNKNOWN lpunk
1824 ICOM_THIS(IDirectSoundImpl
,iface
);
1825 IDirectSoundBufferImpl
** ippdsb
=(IDirectSoundBufferImpl
**)ppdsb
;
1826 LPWAVEFORMATEX wfex
;
1827 HRESULT err
= DS_OK
;
1829 TRACE("(%p,%p,%p,%p)\n",This
,dsbd
,ippdsb
,lpunk
);
1831 if ((This
== NULL
) || (dsbd
== NULL
) || (ippdsb
== NULL
))
1832 return DSERR_INVALIDPARAM
;
1834 if (TRACE_ON(dsound
)) {
1835 TRACE("(structsize=%ld)\n",dsbd
->dwSize
);
1836 TRACE("(flags=0x%08lx:\n",dsbd
->dwFlags
);
1837 _dump_DSBCAPS(dsbd
->dwFlags
);
1839 TRACE("(bufferbytes=%ld)\n",dsbd
->dwBufferBytes
);
1840 TRACE("(lpwfxFormat=%p)\n",dsbd
->lpwfxFormat
);
1843 wfex
= dsbd
->lpwfxFormat
;
1846 TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld,"
1847 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
1848 wfex
->wFormatTag
, wfex
->nChannels
, wfex
->nSamplesPerSec
,
1849 wfex
->nAvgBytesPerSec
, wfex
->nBlockAlign
,
1850 wfex
->wBitsPerSample
, wfex
->cbSize
);
1852 if (dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
1854 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER
)primarybuf
);
1855 *ippdsb
= primarybuf
;
1856 primarybuf
->dsbd
.dwFlags
= dsbd
->dwFlags
;
1858 } /* Else create primary buffer */
1861 *ippdsb
= (IDirectSoundBufferImpl
*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDirectSoundBufferImpl
));
1862 if (*ippdsb
== NULL
)
1863 return DSERR_OUTOFMEMORY
;
1864 ICOM_VTBL(*ippdsb
) = &dsbvt
;
1866 (*ippdsb
)->dsound
= This
;
1867 (*ippdsb
)->parent
= NULL
;
1868 (*ippdsb
)->buffer
= NULL
;
1870 memcpy(&((*ippdsb
)->dsbd
),dsbd
,sizeof(*dsbd
));
1871 if (dsbd
->lpwfxFormat
)
1872 memcpy(&((*ippdsb
)->wfx
), dsbd
->lpwfxFormat
, sizeof((*ippdsb
)->wfx
));
1874 TRACE("Created buffer at %p\n", *ippdsb
);
1876 if (dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
1877 (*ippdsb
)->buflen
= dsound
->wfx
.nAvgBytesPerSec
;
1878 (*ippdsb
)->freq
= dsound
->wfx
.nSamplesPerSec
;
1880 /* FIXME: verify that hardware capabilities (DSCAPS_PRIMARY flags) match */
1883 err
= IDsDriver_CreateSoundBuffer(This
->driver
,wfex
,dsbd
->dwFlags
,0,
1884 &((*ippdsb
)->buflen
),&((*ippdsb
)->buffer
),
1885 (LPVOID
*)&((*ippdsb
)->hwbuf
));
1888 err
= DSOUND_PrimaryOpen(*ippdsb
);
1893 (*ippdsb
)->buflen
= dsbd
->dwBufferBytes
;
1894 (*ippdsb
)->freq
= dsbd
->lpwfxFormat
->nSamplesPerSec
;
1896 /* Check necessary hardware mixing capabilities */
1897 if (wfex
->nChannels
==2) capf
|= DSCAPS_SECONDARYSTEREO
;
1898 else capf
|= DSCAPS_SECONDARYMONO
;
1899 if (wfex
->wBitsPerSample
==16) capf
|= DSCAPS_SECONDARY16BIT
;
1900 else capf
|= DSCAPS_SECONDARY8BIT
;
1901 use_hw
= (This
->drvcaps
.dwFlags
& capf
) == capf
;
1903 /* FIXME: check hardware sample rate mixing capabilities */
1904 /* FIXME: check app hints for software/hardware buffer (STATIC, LOCHARDWARE, etc) */
1905 /* FIXME: check whether any hardware buffers are left */
1906 /* FIXME: handle DSDHEAP_CREATEHEAP for hardware buffers */
1908 /* Allocate system memory if applicable */
1909 if ((This
->drvdesc
.dwFlags
& DSDDESC_USESYSTEMMEMORY
) || !use_hw
) {
1910 (*ippdsb
)->buffer
= (LPBYTE
)HeapAlloc(GetProcessHeap(),0,(*ippdsb
)->buflen
);
1911 if ((*ippdsb
)->buffer
== NULL
)
1912 err
= DSERR_OUTOFMEMORY
;
1915 /* Allocate the hardware buffer */
1916 if (use_hw
&& (err
== DS_OK
)) {
1917 err
= IDsDriver_CreateSoundBuffer(This
->driver
,wfex
,dsbd
->dwFlags
,0,
1918 &((*ippdsb
)->buflen
),&((*ippdsb
)->buffer
),
1919 (LPVOID
*)&((*ippdsb
)->hwbuf
));
1924 if ((*ippdsb
)->buffer
)
1925 HeapFree(GetProcessHeap(),0,(*ippdsb
)->buffer
);
1926 HeapFree(GetProcessHeap(),0,(*ippdsb
));
1930 /* calculate fragment size and write lead */
1931 DSOUND_RecalcFormat(*ippdsb
);
1933 /* It's not necessary to initialize values to zero since */
1934 /* we allocated this structure with HEAP_ZERO_MEMORY... */
1935 (*ippdsb
)->playpos
= 0;
1936 (*ippdsb
)->mixpos
= 0;
1937 (*ippdsb
)->state
= STATE_STOPPED
;
1938 DSOUND_RecalcVolPan(&((*ippdsb
)->volpan
));
1940 if (!(dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
)) {
1941 (*ippdsb
)->freqAdjust
= ((*ippdsb
)->freq
<< DSOUND_FREQSHIFT
) /
1942 primarybuf
->wfx
.nSamplesPerSec
;
1943 (*ippdsb
)->nAvgBytesPerSec
= (*ippdsb
)->freq
*
1944 dsbd
->lpwfxFormat
->nBlockAlign
;
1947 EnterCriticalSection(&(This
->lock
));
1948 /* register buffer */
1949 if (!(dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
)) {
1950 IDirectSoundBufferImpl
**newbuffers
= (IDirectSoundBufferImpl
**)HeapReAlloc(GetProcessHeap(),0,This
->buffers
,sizeof(IDirectSoundBufferImpl
*)*(This
->nrofbuffers
+1));
1952 This
->buffers
= newbuffers
;
1953 This
->buffers
[This
->nrofbuffers
] = *ippdsb
;
1954 This
->nrofbuffers
++;
1955 TRACE("buffer count is now %d\n", This
->nrofbuffers
);
1957 ERR("out of memory for buffer list! Current buffer count is %d\n", This
->nrofbuffers
);
1958 err
= DSERR_OUTOFMEMORY
;
1961 LeaveCriticalSection(&(This
->lock
));
1963 IDirectSound_AddRef(iface
);
1965 InitializeCriticalSection(&((*ippdsb
)->lock
));
1969 IDirectSoundBuffer_Release(*ppdsb
);
1975 if (dsbd
->dwFlags
& DSBCAPS_CTRL3D
) {
1976 IDirectSound3DBufferImpl
*ds3db
;
1978 ds3db
= (IDirectSound3DBufferImpl
*)HeapAlloc(GetProcessHeap(),
1980 ICOM_VTBL(ds3db
) = &ds3dbvt
;
1982 (*ippdsb
)->ds3db
= ds3db
;
1984 ds3db
->dsb
= (*ippdsb
);
1985 IDirectSoundBufferImpl_AddRef((LPDIRECTSOUNDBUFFER
)ippdsb
);
1987 InitializeCriticalSection(&ds3db
->lock
);
1989 ds3db
->ds3db
.dwSize
= sizeof(DS3DBUFFER
);
1990 ds3db
->ds3db
.vPosition
.x
.x
= 0.0;
1991 ds3db
->ds3db
.vPosition
.y
.y
= 0.0;
1992 ds3db
->ds3db
.vPosition
.z
.z
= 0.0;
1993 ds3db
->ds3db
.vVelocity
.x
.x
= 0.0;
1994 ds3db
->ds3db
.vVelocity
.y
.y
= 0.0;
1995 ds3db
->ds3db
.vVelocity
.z
.z
= 0.0;
1996 ds3db
->ds3db
.dwInsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
1997 ds3db
->ds3db
.dwOutsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
1998 ds3db
->ds3db
.vConeOrientation
.x
.x
= 0.0;
1999 ds3db
->ds3db
.vConeOrientation
.y
.y
= 0.0;
2000 ds3db
->ds3db
.vConeOrientation
.z
.z
= 0.0;
2001 ds3db
->ds3db
.lConeOutsideVolume
= DS3D_DEFAULTCONEOUTSIDEVOLUME
;
2002 ds3db
->ds3db
.flMinDistance
= DS3D_DEFAULTMINDISTANCE
;
2003 ds3db
->ds3db
.flMaxDistance
= DS3D_DEFAULTMAXDISTANCE
;
2004 ds3db
->ds3db
.dwMode
= DS3DMODE_NORMAL
;
2005 ds3db
->buflen
= ((*ippdsb
)->buflen
* primarybuf
->wfx
.nBlockAlign
) /
2006 (*ippdsb
)->wfx
.nBlockAlign
;
2007 ds3db
->buffer
= HeapAlloc(GetProcessHeap(), 0, ds3db
->buflen
);
2008 if (ds3db
->buffer
== NULL
) {
2010 ds3db
->ds3db
.dwMode
= DS3DMODE_DISABLE
;
2017 static HRESULT WINAPI
IDirectSoundImpl_DuplicateSoundBuffer(
2018 LPDIRECTSOUND iface
,LPDIRECTSOUNDBUFFER pdsb
,LPLPDIRECTSOUNDBUFFER ppdsb
2020 ICOM_THIS(IDirectSoundImpl
,iface
);
2021 IDirectSoundBufferImpl
* ipdsb
=(IDirectSoundBufferImpl
*)pdsb
;
2022 IDirectSoundBufferImpl
** ippdsb
=(IDirectSoundBufferImpl
**)ppdsb
;
2023 TRACE("(%p,%p,%p)\n",This
,ipdsb
,ippdsb
);
2026 FIXME("need to duplicate hardware buffer\n");
2029 *ippdsb
= (IDirectSoundBufferImpl
*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDirectSoundBufferImpl
));
2031 IDirectSoundBuffer_AddRef(pdsb
);
2032 memcpy(*ippdsb
, ipdsb
, sizeof(IDirectSoundBufferImpl
));
2034 (*ippdsb
)->playpos
= 0;
2035 (*ippdsb
)->mixpos
= 0;
2036 (*ippdsb
)->dsound
= This
;
2037 (*ippdsb
)->parent
= ipdsb
;
2038 memcpy(&((*ippdsb
)->wfx
), &(ipdsb
->wfx
), sizeof((*ippdsb
)->wfx
));
2039 InitializeCriticalSection(&(*ippdsb
)->lock
);
2040 /* register buffer */
2041 EnterCriticalSection(&(This
->lock
));
2043 IDirectSoundBufferImpl
**newbuffers
= (IDirectSoundBufferImpl
**)HeapReAlloc(GetProcessHeap(),0,This
->buffers
,sizeof(IDirectSoundBufferImpl
**)*(This
->nrofbuffers
+1));
2045 This
->buffers
= newbuffers
;
2046 This
->buffers
[This
->nrofbuffers
] = *ippdsb
;
2047 This
->nrofbuffers
++;
2048 TRACE("buffer count is now %d\n", This
->nrofbuffers
);
2050 ERR("out of memory for buffer list! Current buffer count is %d\n", This
->nrofbuffers
);
2051 /* FIXME: release buffer */
2054 LeaveCriticalSection(&(This
->lock
));
2055 IDirectSound_AddRef(iface
);
2060 static HRESULT WINAPI
IDirectSoundImpl_GetCaps(LPDIRECTSOUND iface
,LPDSCAPS caps
) {
2061 ICOM_THIS(IDirectSoundImpl
,iface
);
2062 TRACE("(%p,%p)\n",This
,caps
);
2063 TRACE("(flags=0x%08lx)\n",caps
->dwFlags
);
2066 return DSERR_INVALIDPARAM
;
2068 /* We should check this value, not set it. See Inside DirectX, p215. */
2069 caps
->dwSize
= sizeof(*caps
);
2071 caps
->dwFlags
= This
->drvcaps
.dwFlags
;
2073 /* FIXME: copy caps from This->drvcaps */
2074 caps
->dwMinSecondarySampleRate
= DSBFREQUENCY_MIN
;
2075 caps
->dwMaxSecondarySampleRate
= DSBFREQUENCY_MAX
;
2077 caps
->dwPrimaryBuffers
= 1;
2079 caps
->dwMaxHwMixingAllBuffers
= 0;
2080 caps
->dwMaxHwMixingStaticBuffers
= 0;
2081 caps
->dwMaxHwMixingStreamingBuffers
= 0;
2083 caps
->dwFreeHwMixingAllBuffers
= 0;
2084 caps
->dwFreeHwMixingStaticBuffers
= 0;
2085 caps
->dwFreeHwMixingStreamingBuffers
= 0;
2087 caps
->dwMaxHw3DAllBuffers
= 0;
2088 caps
->dwMaxHw3DStaticBuffers
= 0;
2089 caps
->dwMaxHw3DStreamingBuffers
= 0;
2091 caps
->dwFreeHw3DAllBuffers
= 0;
2092 caps
->dwFreeHw3DStaticBuffers
= 0;
2093 caps
->dwFreeHw3DStreamingBuffers
= 0;
2095 caps
->dwTotalHwMemBytes
= 0;
2097 caps
->dwFreeHwMemBytes
= 0;
2099 caps
->dwMaxContigFreeHwMemBytes
= 0;
2101 caps
->dwUnlockTransferRateHwBuffers
= 4096; /* But we have none... */
2103 caps
->dwPlayCpuOverheadSwBuffers
= 1; /* 1% */
2108 static ULONG WINAPI
IDirectSoundImpl_AddRef(LPDIRECTSOUND iface
) {
2109 ICOM_THIS(IDirectSoundImpl
,iface
);
2110 return ++(This
->ref
);
2113 static ULONG WINAPI
IDirectSoundImpl_Release(LPDIRECTSOUND iface
) {
2114 ICOM_THIS(IDirectSoundImpl
,iface
);
2115 TRACE("(%p), ref was %ld\n",This
,This
->ref
);
2116 if (!--(This
->ref
)) {
2119 timeKillEvent(This
->timerID
);
2120 timeEndPeriod(DS_TIME_RES
);
2123 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)primarybuf
);
2125 if (This
->buffers
) {
2126 for( i
=0;i
<This
->nrofbuffers
;i
++)
2127 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)This
->buffers
[i
]);
2131 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)This
->primary
);
2133 DeleteCriticalSection(&This
->lock
);
2135 IDsDriver_Close(This
->driver
);
2138 for (c
=0; c
<DS_HEL_FRAGS
; c
++)
2139 HeapFree(GetProcessHeap(),0,This
->pwave
[c
]);
2141 if (This
->drvdesc
.dwFlags
& DSDDESC_DOMMSYSTEMOPEN
) {
2142 waveOutClose(This
->hwo
);
2145 IDsDriver_Release(This
->driver
);
2147 HeapFree(GetProcessHeap(),0,This
);
2154 static HRESULT WINAPI
IDirectSoundImpl_SetSpeakerConfig(
2155 LPDIRECTSOUND iface
,DWORD config
2157 ICOM_THIS(IDirectSoundImpl
,iface
);
2158 FIXME("(%p,0x%08lx):stub\n",This
,config
);
2162 static HRESULT WINAPI
IDirectSoundImpl_QueryInterface(
2163 LPDIRECTSOUND iface
,REFIID riid
,LPVOID
*ppobj
2165 ICOM_THIS(IDirectSoundImpl
,iface
);
2167 if ( IsEqualGUID( &IID_IDirectSound3DListener
, riid
) ) {
2169 if (This
->listener
) {
2170 *ppobj
= This
->listener
;
2171 IDirectSound3DListener_AddRef((LPDIRECTSOUND3DLISTENER
)This
->listener
);
2175 This
->listener
= (IDirectSound3DListenerImpl
*)HeapAlloc(
2176 GetProcessHeap(), 0, sizeof(*(This
->listener
)));
2177 This
->listener
->ref
= 1;
2178 ICOM_VTBL(This
->listener
) = &ds3dlvt
;
2179 *ppobj
= (LPVOID
)This
->listener
;
2180 IDirectSound3DListener_AddRef((LPDIRECTSOUND3DLISTENER
)*ppobj
);
2182 This
->listener
->dsb
= NULL
;
2184 This
->listener
->ds3dl
.dwSize
= sizeof(DS3DLISTENER
);
2185 This
->listener
->ds3dl
.vPosition
.u1
.x
= 0.0;
2186 This
->listener
->ds3dl
.vPosition
.u2
.y
= 0.0;
2187 This
->listener
->ds3dl
.vPosition
.u3
.z
= 0.0;
2188 This
->listener
->ds3dl
.vVelocity
.u1
.x
= 0.0;
2189 This
->listener
->ds3dl
.vVelocity
.u2
.y
= 0.0;
2190 This
->listener
->ds3dl
.vVelocity
.u3
.z
= 0.0;
2191 This
->listener
->ds3dl
.vOrientFront
.u1
.x
= 0.0;
2192 This
->listener
->ds3dl
.vOrientFront
.u2
.y
= 0.0;
2193 This
->listener
->ds3dl
.vOrientFront
.u3
.z
= 1.0;
2194 This
->listener
->ds3dl
.vOrientTop
.u1
.x
= 0.0;
2195 This
->listener
->ds3dl
.vOrientTop
.u2
.y
= 1.0;
2196 This
->listener
->ds3dl
.vOrientTop
.u3
.z
= 0.0;
2197 This
->listener
->ds3dl
.flDistanceFactor
= DS3D_DEFAULTDISTANCEFACTOR
;
2198 This
->listener
->ds3dl
.flRolloffFactor
= DS3D_DEFAULTROLLOFFFACTOR
;
2199 This
->listener
->ds3dl
.flDopplerFactor
= DS3D_DEFAULTDOPPLERFACTOR
;
2201 InitializeCriticalSection(&This
->listener
->lock
);
2206 FIXME("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
2210 static HRESULT WINAPI
IDirectSoundImpl_Compact(
2211 LPDIRECTSOUND iface
)
2213 ICOM_THIS(IDirectSoundImpl
,iface
);
2214 TRACE("(%p)\n", This
);
2218 static HRESULT WINAPI
IDirectSoundImpl_GetSpeakerConfig(
2219 LPDIRECTSOUND iface
,
2220 LPDWORD lpdwSpeakerConfig
)
2222 ICOM_THIS(IDirectSoundImpl
,iface
);
2223 TRACE("(%p, %p)\n", This
, lpdwSpeakerConfig
);
2224 *lpdwSpeakerConfig
= DSSPEAKER_STEREO
| (DSSPEAKER_GEOMETRY_NARROW
<< 16);
2228 static HRESULT WINAPI
IDirectSoundImpl_Initialize(
2229 LPDIRECTSOUND iface
,
2232 ICOM_THIS(IDirectSoundImpl
,iface
);
2233 TRACE("(%p, %p)\n", This
, lpcGuid
);
2237 static ICOM_VTABLE(IDirectSound
) dsvt
=
2239 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
2240 IDirectSoundImpl_QueryInterface
,
2241 IDirectSoundImpl_AddRef
,
2242 IDirectSoundImpl_Release
,
2243 IDirectSoundImpl_CreateSoundBuffer
,
2244 IDirectSoundImpl_GetCaps
,
2245 IDirectSoundImpl_DuplicateSoundBuffer
,
2246 IDirectSoundImpl_SetCooperativeLevel
,
2247 IDirectSoundImpl_Compact
,
2248 IDirectSoundImpl_GetSpeakerConfig
,
2249 IDirectSoundImpl_SetSpeakerConfig
,
2250 IDirectSoundImpl_Initialize
2254 static void DSOUND_CheckEvent(IDirectSoundBufferImpl
*dsb
, int len
)
2258 LPDSBPOSITIONNOTIFY event
;
2260 if (dsb
->nrofnotifies
== 0)
2263 TRACE("(%p) buflen = %ld, playpos = %ld, len = %d\n",
2264 dsb
, dsb
->buflen
, dsb
->playpos
, len
);
2265 for (i
= 0; i
< dsb
->nrofnotifies
; i
++) {
2266 event
= dsb
->notifies
+ i
;
2267 offset
= event
->dwOffset
;
2268 TRACE("checking %d, position %ld, event = %d\n",
2269 i
, offset
, event
->hEventNotify
);
2270 /* DSBPN_OFFSETSTOP has to be the last element. So this is */
2271 /* OK. [Inside DirectX, p274] */
2273 /* This also means we can't sort the entries by offset, */
2274 /* because DSBPN_OFFSETSTOP == -1 */
2275 if (offset
== DSBPN_OFFSETSTOP
) {
2276 if (dsb
->state
== STATE_STOPPED
) {
2277 SetEvent(event
->hEventNotify
);
2278 TRACE("signalled event %d (%d)\n", event
->hEventNotify
, i
);
2283 if ((dsb
->playpos
+ len
) >= dsb
->buflen
) {
2284 if ((offset
< ((dsb
->playpos
+ len
) % dsb
->buflen
)) ||
2285 (offset
>= dsb
->playpos
)) {
2286 TRACE("signalled event %d (%d)\n", event
->hEventNotify
, i
);
2287 SetEvent(event
->hEventNotify
);
2290 if ((offset
>= dsb
->playpos
) && (offset
< (dsb
->playpos
+ len
))) {
2291 TRACE("signalled event %d (%d)\n", event
->hEventNotify
, i
);
2292 SetEvent(event
->hEventNotify
);
2298 /* WAV format info can be found at: */
2300 /* http://www.cwi.nl/ftp/audio/AudioFormats.part2 */
2301 /* ftp://ftp.cwi.nl/pub/audio/RIFF-format */
2303 /* Import points to remember: */
2305 /* 8-bit WAV is unsigned */
2306 /* 16-bit WAV is signed */
2308 static inline INT16
cvtU8toS16(BYTE byte
)
2310 INT16 s
= (byte
- 128) << 8;
2315 static inline BYTE
cvtS16toU8(INT16 word
)
2317 BYTE b
= (word
+ 32768) >> 8;
2323 /* We should be able to optimize these two inline functions */
2324 /* so that we aren't doing 8->16->8 conversions when it is */
2325 /* not necessary. But this is still a WIP. Optimize later. */
2326 static inline void get_fields(const IDirectSoundBufferImpl
*dsb
, BYTE
*buf
, INT
*fl
, INT
*fr
)
2328 INT16
*bufs
= (INT16
*) buf
;
2330 /* TRACE("(%p)", buf); */
2331 if ((dsb
->wfx
.wBitsPerSample
== 8) && dsb
->wfx
.nChannels
== 2) {
2332 *fl
= cvtU8toS16(*buf
);
2333 *fr
= cvtU8toS16(*(buf
+ 1));
2337 if ((dsb
->wfx
.wBitsPerSample
== 16) && dsb
->wfx
.nChannels
== 2) {
2343 if ((dsb
->wfx
.wBitsPerSample
== 8) && dsb
->wfx
.nChannels
== 1) {
2344 *fl
= cvtU8toS16(*buf
);
2349 if ((dsb
->wfx
.wBitsPerSample
== 16) && dsb
->wfx
.nChannels
== 1) {
2355 FIXME("get_fields found an unsupported configuration\n");
2359 static inline void set_fields(BYTE
*buf
, INT fl
, INT fr
)
2361 INT16
*bufs
= (INT16
*) buf
;
2363 if ((primarybuf
->wfx
.wBitsPerSample
== 8) && (primarybuf
->wfx
.nChannels
== 2)) {
2364 *buf
= cvtS16toU8(fl
);
2365 *(buf
+ 1) = cvtS16toU8(fr
);
2369 if ((primarybuf
->wfx
.wBitsPerSample
== 16) && (primarybuf
->wfx
.nChannels
== 2)) {
2375 if ((primarybuf
->wfx
.wBitsPerSample
== 8) && (primarybuf
->wfx
.nChannels
== 1)) {
2376 *buf
= cvtS16toU8((fl
+ fr
) >> 1);
2380 if ((primarybuf
->wfx
.wBitsPerSample
== 16) && (primarybuf
->wfx
.nChannels
== 1)) {
2381 *bufs
= (fl
+ fr
) >> 1;
2384 FIXME("set_fields found an unsupported configuration\n");
2388 /* Now with PerfectPitch (tm) technology */
2389 static INT
DSOUND_MixerNorm(IDirectSoundBufferImpl
*dsb
, BYTE
*buf
, INT len
)
2391 INT i
, size
, ipos
, ilen
, fieldL
, fieldR
;
2393 INT iAdvance
= dsb
->wfx
.nBlockAlign
;
2394 INT oAdvance
= primarybuf
->wfx
.nBlockAlign
;
2396 ibp
= dsb
->buffer
+ dsb
->mixpos
;
2399 TRACE("(%p, %p, %p), mixpos=%ld\n", dsb
, ibp
, obp
, dsb
->mixpos
);
2400 /* Check for the best case */
2401 if ((dsb
->freq
== primarybuf
->wfx
.nSamplesPerSec
) &&
2402 (dsb
->wfx
.wBitsPerSample
== primarybuf
->wfx
.wBitsPerSample
) &&
2403 (dsb
->wfx
.nChannels
== primarybuf
->wfx
.nChannels
)) {
2404 DWORD bytesleft
= dsb
->buflen
- dsb
->mixpos
;
2405 TRACE("(%p) Best case\n", dsb
);
2406 if (len
<= bytesleft
)
2407 memcpy(obp
, ibp
, len
);
2409 memcpy(obp
, ibp
, bytesleft
);
2410 memcpy(obp
+ bytesleft
, dsb
->buffer
, len
- bytesleft
);
2415 /* Check for same sample rate */
2416 if (dsb
->freq
== primarybuf
->wfx
.nSamplesPerSec
) {
2417 TRACE("(%p) Same sample rate %ld = primary %ld\n", dsb
,
2418 dsb
->freq
, primarybuf
->wfx
.nSamplesPerSec
);
2420 for (i
= 0; i
< len
; i
+= oAdvance
) {
2421 get_fields(dsb
, ibp
, &fieldL
, &fieldR
);
2424 set_fields(obp
, fieldL
, fieldR
);
2426 if (ibp
>= (BYTE
*)(dsb
->buffer
+ dsb
->buflen
))
2427 ibp
= dsb
->buffer
; /* wrap */
2432 /* Mix in different sample rates */
2434 /* New PerfectPitch(tm) Technology (c) 1998 Rob Riggs */
2435 /* Patent Pending :-] */
2437 TRACE("(%p) Adjusting frequency: %ld -> %ld\n",
2438 dsb
, dsb
->freq
, primarybuf
->wfx
.nSamplesPerSec
);
2440 size
= len
/ oAdvance
;
2441 ilen
= ((size
* dsb
->freqAdjust
) >> DSOUND_FREQSHIFT
) * iAdvance
;
2442 for (i
= 0; i
< size
; i
++) {
2444 ipos
= (((i
* dsb
->freqAdjust
) >> DSOUND_FREQSHIFT
) * iAdvance
) + dsb
->mixpos
;
2446 if (ipos
>= dsb
->buflen
)
2447 ipos
%= dsb
->buflen
; /* wrap */
2449 get_fields(dsb
, (dsb
->buffer
+ ipos
), &fieldL
, &fieldR
);
2450 set_fields(obp
, fieldL
, fieldR
);
2456 static void DSOUND_MixerVol(IDirectSoundBufferImpl
*dsb
, BYTE
*buf
, INT len
)
2458 INT i
, inc
= primarybuf
->wfx
.wBitsPerSample
>> 3;
2460 INT16
*bps
= (INT16
*) buf
;
2462 TRACE("(%p) left = %lx, right = %lx\n", dsb
,
2463 dsb
->volpan
.dwTotalLeftAmpFactor
, dsb
->volpan
.dwTotalRightAmpFactor
);
2464 if ((!(dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLPAN
) || (dsb
->volpan
.lPan
== 0)) &&
2465 (!(dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLVOLUME
) || (dsb
->volpan
.lVolume
== 0)) &&
2466 !(dsb
->dsbd
.dwFlags
& DSBCAPS_CTRL3D
))
2467 return; /* Nothing to do */
2469 /* If we end up with some bozo coder using panning or 3D sound */
2470 /* with a mono primary buffer, it could sound very weird using */
2471 /* this method. Oh well, tough patooties. */
2473 for (i
= 0; i
< len
; i
+= inc
) {
2479 /* 8-bit WAV is unsigned, but we need to operate */
2480 /* on signed data for this to work properly */
2482 val
= ((val
* (i
& inc
? dsb
->volpan
.dwTotalRightAmpFactor
: dsb
->volpan
.dwTotalLeftAmpFactor
)) >> 16);
2487 /* 16-bit WAV is signed -- much better */
2489 val
= ((val
* ((i
& inc
) ? dsb
->volpan
.dwTotalRightAmpFactor
: dsb
->volpan
.dwTotalLeftAmpFactor
)) >> 16);
2495 FIXME("MixerVol had a nasty error\n");
2501 static void DSOUND_Mixer3D(IDirectSoundBufferImpl
*dsb
, BYTE
*buf
, INT len
)
2504 DWORD buflen
, mixpos
;
2506 buflen
= dsb
->ds3db
->buflen
;
2507 mixpos
= (dsb
->mixpos
* primarybuf
->wfx
.nBlockAlign
) / dsb
->wfx
.nBlockAlign
;
2508 ibp
= dsb
->ds3db
->buffer
+ mixpos
;
2511 if (mixpos
> buflen
) {
2512 FIXME("Major breakage");
2516 if (len
<= (mixpos
+ buflen
))
2517 memcpy(obp
, ibp
, len
);
2519 memcpy(obp
, ibp
, buflen
- mixpos
);
2520 memcpy(obp
+ (buflen
- mixpos
),
2522 len
- (buflen
- mixpos
));
2528 static void *tmp_buffer
;
2529 static size_t tmp_buffer_len
= 0;
2531 static void *DSOUND_tmpbuffer(size_t len
)
2533 if (len
>tmp_buffer_len
) {
2534 void *new_buffer
= realloc(tmp_buffer
, len
);
2536 tmp_buffer
= new_buffer
;
2537 tmp_buffer_len
= len
;
2544 static DWORD
DSOUND_MixInBuffer(IDirectSoundBufferImpl
*dsb
, DWORD writepos
, DWORD fraglen
)
2546 INT i
, len
, ilen
, temp
, field
;
2547 INT advance
= primarybuf
->wfx
.wBitsPerSample
>> 3;
2548 BYTE
*buf
, *ibuf
, *obuf
;
2549 INT16
*ibufs
, *obufs
;
2552 if (!(dsb
->playflags
& DSBPLAY_LOOPING
)) {
2553 temp
= MulDiv(primarybuf
->wfx
.nAvgBytesPerSec
, dsb
->buflen
,
2554 dsb
->nAvgBytesPerSec
) -
2555 MulDiv(primarybuf
->wfx
.nAvgBytesPerSec
, dsb
->mixpos
,
2556 dsb
->nAvgBytesPerSec
);
2557 len
= (len
> temp
) ? temp
: len
;
2559 len
&= ~3; /* 4 byte alignment */
2562 /* This should only happen if we aren't looping and temp < 4 */
2564 /* We skip the remainder, so check for possible events */
2565 DSOUND_CheckEvent(dsb
, dsb
->buflen
- dsb
->mixpos
);
2567 dsb
->state
= STATE_STOPPED
;
2570 dsb
->leadin
= FALSE
;
2571 /* Check for DSBPN_OFFSETSTOP */
2572 DSOUND_CheckEvent(dsb
, 0);
2576 /* Been seeing segfaults in malloc() for some reason... */
2577 TRACE("allocating buffer (size = %d)\n", len
);
2578 if ((buf
= ibuf
= (BYTE
*) DSOUND_tmpbuffer(len
)) == NULL
)
2581 TRACE("MixInBuffer (%p) len = %d, dest = %ld\n", dsb
, len
, writepos
);
2583 ilen
= DSOUND_MixerNorm(dsb
, ibuf
, len
);
2584 if ((dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLPAN
) ||
2585 (dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLVOLUME
))
2586 DSOUND_MixerVol(dsb
, ibuf
, len
);
2588 obuf
= primarybuf
->buffer
+ writepos
;
2589 for (i
= 0; i
< len
; i
+= advance
) {
2590 obufs
= (INT16
*) obuf
;
2591 ibufs
= (INT16
*) ibuf
;
2592 if (primarybuf
->wfx
.wBitsPerSample
== 8) {
2593 /* 8-bit WAV is unsigned */
2594 field
= (*ibuf
- 128);
2595 field
+= (*obuf
- 128);
2596 field
= field
> 127 ? 127 : field
;
2597 field
= field
< -128 ? -128 : field
;
2598 *obuf
= field
+ 128;
2600 /* 16-bit WAV is signed */
2603 field
= field
> 32767 ? 32767 : field
;
2604 field
= field
< -32768 ? -32768 : field
;
2609 if (obuf
>= (BYTE
*)(primarybuf
->buffer
+ primarybuf
->buflen
))
2610 obuf
= primarybuf
->buffer
;
2614 if (dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLPOSITIONNOTIFY
)
2615 DSOUND_CheckEvent(dsb
, ilen
);
2617 if (dsb
->leadin
&& (dsb
->startpos
> dsb
->mixpos
) && (dsb
->startpos
<= dsb
->mixpos
+ ilen
)) {
2618 /* HACK... leadin should be reset when the PLAY position reaches the startpos,
2619 * not the MIX position... but if the sound buffer is bigger than our prebuffering
2620 * (which must be the case for the streaming buffers that need this hack anyway)
2621 * plus DS_HEL_MARGIN or equivalent, then this ought to work anyway. */
2622 dsb
->leadin
= FALSE
;
2625 dsb
->mixpos
+= ilen
;
2627 if (dsb
->mixpos
>= dsb
->buflen
) {
2628 if (!(dsb
->playflags
& DSBPLAY_LOOPING
)) {
2629 dsb
->state
= STATE_STOPPED
;
2632 dsb
->leadin
= FALSE
;
2633 DSOUND_CheckEvent(dsb
, 0); /* For DSBPN_OFFSETSTOP */
2636 while (dsb
->mixpos
>= dsb
->buflen
)
2637 dsb
->mixpos
-= dsb
->buflen
;
2638 if (dsb
->leadin
&& (dsb
->startpos
<= dsb
->mixpos
))
2639 dsb
->leadin
= FALSE
; /* HACK: see above */
2646 static DWORD WINAPI
DSOUND_MixPrimary(DWORD writepos
, DWORD fraglen
, BOOL starting
)
2648 INT i
, len
, maxlen
= 0;
2649 IDirectSoundBufferImpl
*dsb
;
2651 TRACE("(%ld,%ld,%d)\n", writepos
, fraglen
, starting
);
2652 for (i
= dsound
->nrofbuffers
- 1; i
>= 0; i
--) {
2653 dsb
= dsound
->buffers
[i
];
2655 if (!dsb
|| !(ICOM_VTBL(dsb
)))
2657 if (dsb
->buflen
&& dsb
->state
&& !(starting
&& (dsb
->state
!= STATE_STARTING
))) {
2658 TRACE("Checking %p\n", dsb
);
2659 EnterCriticalSection(&(dsb
->lock
));
2660 if (dsb
->state
== STATE_STOPPING
) {
2661 /* FIXME: perhaps attempt to remove the buffer from the prebuffer */
2662 dsb
->state
= STATE_STOPPED
;
2664 len
= DSOUND_MixInBuffer(dsb
, writepos
, fraglen
);
2665 maxlen
= len
> maxlen
? len
: maxlen
;
2667 LeaveCriticalSection(&(dsb
->lock
));
2674 static void WINAPI
DSOUND_MarkPlaying(void)
2677 IDirectSoundBufferImpl
*dsb
;
2679 for (i
= dsound
->nrofbuffers
- 1; i
>= 0; i
--) {
2680 dsb
= dsound
->buffers
[i
];
2682 if (!dsb
|| !(ICOM_VTBL(dsb
)))
2684 if (dsb
->buflen
&& (dsb
->state
== STATE_STARTING
))
2685 dsb
->state
= STATE_PLAYING
;
2689 static void CALLBACK
DSOUND_timer(UINT timerID
, UINT msg
, DWORD dwUser
, DWORD dw1
, DWORD dw2
)
2695 if (!dsound
|| !primarybuf
) {
2696 ERR("dsound died without killing us?\n");
2697 timeKillEvent(timerID
);
2698 timeEndPeriod(DS_TIME_RES
);
2702 EnterCriticalSection(&(dsound
->lock
));
2704 if (!primarybuf
|| !primarybuf
->ref
) {
2705 /* seems the primary buffer is currently being released */
2706 LeaveCriticalSection(&(dsound
->lock
));
2710 /* the sound of silence */
2711 nfiller
= primarybuf
->wfx
.wBitsPerSample
== 8 ? 128 : 0;
2713 /* whether the primary is forced to play even without secondary buffers */
2714 forced
= ((primarybuf
->state
== STATE_PLAYING
) || (primarybuf
->state
== STATE_STARTING
));
2716 if (primarybuf
->hwbuf
) {
2717 if (dsound
->priolevel
!= DSSCL_WRITEPRIMARY
) {
2718 BOOL paused
= ((primarybuf
->state
== STATE_STOPPED
) || (primarybuf
->state
== STATE_STARTING
));
2719 DWORD playpos
, writepos
, inq
, maxq
, mixq
, frag
;
2720 IDsDriverBuffer_GetPosition(primarybuf
->hwbuf
, &playpos
, &writepos
);
2721 /* Well, we *could* do Just-In-Time mixing using the writepos,
2722 * but that's a little bit ambitious and unnecessary... */
2723 /* rather add our safety margin to the writepos, if we're playing */
2725 writepos
+= primarybuf
->writelead
;
2726 while (writepos
>= primarybuf
->buflen
)
2727 writepos
-= primarybuf
->buflen
;
2728 } else writepos
= playpos
;
2729 TRACE("primary playpos=%ld, writepos=%ld, clrpos=%ld, mixpos=%ld\n",
2730 playpos
,writepos
,primarybuf
->playpos
,primarybuf
->mixpos
);
2731 /* wipe out just-played sound data */
2732 if (playpos
< primarybuf
->playpos
) {
2733 memset(primarybuf
->buffer
+ primarybuf
->playpos
, nfiller
, primarybuf
->buflen
- primarybuf
->playpos
);
2734 memset(primarybuf
->buffer
, nfiller
, playpos
);
2736 memset(primarybuf
->buffer
+ primarybuf
->playpos
, nfiller
, playpos
- primarybuf
->playpos
);
2738 primarybuf
->playpos
= playpos
;
2740 /* check how much prebuffering is left */
2741 inq
= primarybuf
->mixpos
;
2743 inq
+= primarybuf
->buflen
;
2746 /* find the maximum we can prebuffer */
2749 if (maxq
< writepos
)
2750 maxq
+= primarybuf
->buflen
;
2752 } else maxq
= primarybuf
->buflen
;
2754 /* clip maxq to DS_HAL_QUEUE */
2755 frag
= DS_HAL_QUEUE
* dsound
->fraglen
;
2756 if (maxq
> frag
) maxq
= frag
;
2758 EnterCriticalSection(&(primarybuf
->lock
));
2760 /* check for consistency */
2762 /* the playback position must have passed our last
2763 * mixed position, i.e. it's an underrun, or we have
2764 * nothing more to play */
2766 /* stop the playback now, to allow buffers to refill */
2767 IDsDriverBuffer_Stop(primarybuf
->hwbuf
);
2768 if (primarybuf
->state
== STATE_PLAYING
) {
2769 primarybuf
->state
= STATE_STARTING
;
2771 else if (primarybuf
->state
== STATE_STOPPING
) {
2772 primarybuf
->state
= STATE_STOPPED
;
2775 /* how can we have an underrun if we aren't playing? */
2776 ERR("unexpected primary state (%ld)\n", primarybuf
->state
);
2778 /* the Stop is supposed to reset play position to beginning of buffer */
2779 /* unfortunately, OSS is not able to do so, so get current pointer */
2780 IDsDriverBuffer_GetPosition(primarybuf
->hwbuf
, &playpos
, NULL
);
2782 primarybuf
->playpos
= playpos
;
2783 primarybuf
->mixpos
= playpos
;
2785 maxq
= primarybuf
->buflen
;
2786 if (maxq
> frag
) maxq
= frag
;
2787 memset(primarybuf
->buffer
, nfiller
, primarybuf
->buflen
);
2791 /* see if some new buffers have been started that we want to merge into our prebuffer;
2792 * this should minimize latency even when we have a large prebuffer */
2794 if (primarybuf
->mixpos
< writepos
) {
2795 /* mix to end of buffer */
2796 len
= DSOUND_MixPrimary(writepos
, primarybuf
->buflen
- writepos
, TRUE
);
2797 if ((len
+ writepos
) < primarybuf
->buflen
)
2798 goto addmix_complete
;
2799 /* mix from beginning of buffer */
2800 if (primarybuf
->mixpos
)
2801 len
= DSOUND_MixPrimary(0, primarybuf
->mixpos
, TRUE
);
2803 /* mix middle of buffer */
2804 len
= DSOUND_MixPrimary(writepos
, primarybuf
->mixpos
- writepos
, TRUE
);
2808 DSOUND_MarkPlaying();
2811 TRACE("queued %ld, max %ld, mixing %ld, paused %d\n", inq
, maxq
, mixq
, paused
);
2812 /* it's too inefficient to mix less than a fragment at a time */
2813 if (mixq
>= dsound
->fraglen
) {
2815 #define FRAG_MIXER \
2816 if (frag > mixq) frag = mixq; \
2817 len = DSOUND_MixPrimary(primarybuf->mixpos, frag, FALSE); \
2818 if (forced) len = frag; \
2819 primarybuf->mixpos += len; \
2820 mixq -= len; inq += len
2822 if ((playpos
< writepos
) || (paused
&& (playpos
== writepos
))) {
2823 if (primarybuf
->mixpos
) {
2824 /* mix to end of buffer */
2825 frag
= primarybuf
->buflen
- primarybuf
->mixpos
;
2827 if (primarybuf
->mixpos
< primarybuf
->buflen
)
2829 primarybuf
->mixpos
= 0;
2831 if (mixq
>= dsound
->fraglen
) {
2832 /* mix from beginning of buffer */
2834 if ((!frag
) && paused
) frag
= primarybuf
->buflen
;
2838 else if (playpos
> writepos
) {
2839 /* mix middle of buffer */
2840 frag
= playpos
- primarybuf
->mixpos
;
2844 /* this should preferably not happen... */
2845 ERR("mixer malfunction (ambiguous writepos)!\n");
2851 /* buffers have been filled, restart playback */
2852 if (primarybuf
->state
== STATE_STARTING
) {
2853 IDsDriverBuffer_Play(primarybuf
->hwbuf
, 0, 0, DSBPLAY_LOOPING
);
2854 primarybuf
->state
= STATE_PLAYING
;
2856 else if (primarybuf
->state
== STATE_STOPPED
) {
2857 /* the primarybuf is supposed to play if there's something to play
2858 * even if it is reported as stopped, so don't let this confuse you */
2859 IDsDriverBuffer_Play(primarybuf
->hwbuf
, 0, 0, DSBPLAY_LOOPING
);
2860 primarybuf
->state
= STATE_STOPPING
;
2863 LeaveCriticalSection(&(primarybuf
->lock
));
2865 /* in the DSSCL_WRITEPRIMARY mode, the app is totally in charge... */
2866 if (primarybuf
->state
== STATE_STARTING
) {
2867 IDsDriverBuffer_Play(primarybuf
->hwbuf
, 0, 0, DSBPLAY_LOOPING
);
2868 primarybuf
->state
= STATE_PLAYING
;
2870 else if (primarybuf
->state
== STATE_STOPPING
) {
2871 IDsDriverBuffer_Stop(primarybuf
->hwbuf
);
2872 primarybuf
->state
= STATE_STOPPED
;
2876 /* using waveOut stuff */
2877 /* if no buffers are playing, we should be in pause mode now */
2879 /* clean out completed fragments */
2880 while (dsound
->pwqueue
&& (dsound
->pwave
[dsound
->pwplay
]->dwFlags
& WHDR_DONE
)) {
2881 if (dsound
->priolevel
!= DSSCL_WRITEPRIMARY
) {
2882 DWORD pos
= dsound
->pwplay
* dsound
->fraglen
;
2883 TRACE("done playing primary pos=%ld\n",pos
);
2884 memset(primarybuf
->buffer
+ pos
, nfiller
, dsound
->fraglen
);
2887 if (dsound
->pwplay
>= DS_HEL_FRAGS
) dsound
->pwplay
= 0;
2890 primarybuf
->playpos
= dsound
->pwplay
* dsound
->fraglen
;
2891 TRACE("primary playpos=%ld, mixpos=%ld\n",primarybuf
->playpos
,primarybuf
->mixpos
);
2892 EnterCriticalSection(&(primarybuf
->lock
));
2893 if (!dsound
->pwqueue
) {
2894 /* this is either an underrun or we have nothing more to play...
2895 * since playback has already stopped now, we can enter pause mode,
2896 * in order to allow buffers to refill */
2897 if (primarybuf
->state
== STATE_PLAYING
) {
2898 waveOutPause(dsound
->hwo
);
2899 primarybuf
->state
= STATE_STARTING
;
2901 else if (primarybuf
->state
== STATE_STOPPING
) {
2902 waveOutPause(dsound
->hwo
);
2903 primarybuf
->state
= STATE_STOPPED
;
2907 /* find next write position, plus some extra margin */
2908 writepos
= primarybuf
->playpos
+ DS_HEL_MARGIN
* dsound
->fraglen
;
2909 while (writepos
>= primarybuf
->buflen
) writepos
-= primarybuf
->buflen
;
2911 /* see if some new buffers have been started that we want to merge into our prebuffer;
2912 * this should minimize latency even when we have a large prebuffer */
2913 if (dsound
->priolevel
!= DSSCL_WRITEPRIMARY
) {
2914 if ((primarybuf
->state
== STATE_PLAYING
) || (primarybuf
->state
== STATE_STOPPING
)) {
2915 while (writepos
!= primarybuf
->mixpos
) {
2916 len
= DSOUND_MixPrimary(writepos
, dsound
->fraglen
, TRUE
);
2918 writepos
+= dsound
->fraglen
;
2919 if (writepos
>= primarybuf
->buflen
)
2920 writepos
-= primarybuf
->buflen
;
2923 DSOUND_MarkPlaying();
2926 /* we want at least DS_HEL_QUEUE fragments in the prebuffer outqueue;
2927 * mix a bunch of fragments now as necessary */
2928 while (dsound
->pwqueue
< DS_HEL_QUEUE
) {
2929 if (dsound
->priolevel
!= DSSCL_WRITEPRIMARY
) {
2930 len
= DSOUND_MixPrimary(primarybuf
->mixpos
, dsound
->fraglen
, FALSE
);
2932 if (forced
) len
= dsound
->fraglen
;
2933 /* if we have nothing to play, don't bother to */
2935 if (len
< dsound
->fraglen
) {
2936 TRACE("len=%ld is less than fraglen=%ld\n",len
,dsound
->fraglen
);
2938 /* ok, we have something to play */
2939 /* advance mix positions */
2940 primarybuf
->mixpos
+= dsound
->fraglen
;
2941 if (primarybuf
->mixpos
>= primarybuf
->buflen
)
2942 primarybuf
->mixpos
-= primarybuf
->buflen
;
2944 waveOutWrite(dsound
->hwo
, dsound
->pwave
[dsound
->pwwrite
], sizeof(WAVEHDR
));
2946 if (dsound
->pwwrite
>= DS_HEL_FRAGS
) dsound
->pwwrite
= 0;
2949 if (dsound
->pwqueue
) {
2950 /* buffers have been filled, restart playback */
2951 if (primarybuf
->state
== STATE_STARTING
) {
2952 waveOutRestart(dsound
->hwo
);
2953 primarybuf
->state
= STATE_PLAYING
;
2955 else if (primarybuf
->state
== STATE_STOPPED
) {
2956 /* the primarybuf is supposed to play if there's something to play
2957 * even if it is reported as stopped, so don't let this confuse you */
2958 waveOutRestart(dsound
->hwo
);
2959 primarybuf
->state
= STATE_STOPPING
;
2962 LeaveCriticalSection(&(primarybuf
->lock
));
2964 LeaveCriticalSection(&(dsound
->lock
));
2967 /*******************************************************************************
2970 HRESULT WINAPI
DirectSoundCreate(REFGUID lpGUID
,LPDIRECTSOUND
*ppDS
,IUnknown
*pUnkOuter
)
2972 IDirectSoundImpl
** ippDS
=(IDirectSoundImpl
**)ppDS
;
2973 PIDSDRIVER drv
= NULL
;
2976 HRESULT err
= DS_OK
;
2979 TRACE("(%p,%p,%p)\n",lpGUID
,ippDS
,pUnkOuter
);
2981 TRACE("DirectSoundCreate (%p)\n", ippDS
);
2984 return DSERR_INVALIDPARAM
;
2987 IDirectSound_AddRef((LPDIRECTSOUND
)dsound
);
2992 /* Enumerate WINMM audio devices and find the one we want */
2993 wodn
= waveOutGetNumDevs();
2994 if (!wodn
) return DSERR_NODRIVER
;
2996 /* FIXME: How do we find the GUID of an audio device? */
2997 /* Well, just use the first available device for now... */
2999 /* Get output device caps */
3000 waveOutGetDevCapsA(wod
, &wcaps
, sizeof(wcaps
));
3001 /* 0x810 is a "Wine extension" to get the DSound interface */
3002 waveOutMessage(wod
, 0x810, (DWORD
)&drv
, 0);
3004 /* Allocate memory */
3005 *ippDS
= (IDirectSoundImpl
*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundImpl
));
3007 return DSERR_OUTOFMEMORY
;
3009 ICOM_VTBL(*ippDS
) = &dsvt
;
3012 (*ippDS
)->driver
= drv
;
3013 (*ippDS
)->fraglen
= 0;
3014 (*ippDS
)->priolevel
= DSSCL_NORMAL
;
3015 (*ippDS
)->nrofbuffers
= 0;
3016 (*ippDS
)->buffers
= NULL
;
3017 (*ippDS
)->primary
= NULL
;
3018 (*ippDS
)->listener
= NULL
;
3020 /* Get driver description */
3022 IDsDriver_GetDriverDesc(drv
,&((*ippDS
)->drvdesc
));
3024 /* if no DirectSound interface available, use WINMM API instead */
3025 (*ippDS
)->drvdesc
.dwFlags
= DSDDESC_DOMMSYSTEMOPEN
| DSDDESC_DOMMSYSTEMSETFORMAT
;
3026 (*ippDS
)->drvdesc
.dnDevNode
= wod
; /* FIXME? */
3029 /* Set default wave format (may need it for waveOutOpen) */
3030 (*ippDS
)->wfx
.wFormatTag
= WAVE_FORMAT_PCM
;
3031 (*ippDS
)->wfx
.nChannels
= 2;
3032 (*ippDS
)->wfx
.nSamplesPerSec
= 22050;
3033 (*ippDS
)->wfx
.nAvgBytesPerSec
= 44100;
3034 (*ippDS
)->wfx
.nBlockAlign
= 2;
3035 (*ippDS
)->wfx
.wBitsPerSample
= 8;
3037 /* If the driver requests being opened through MMSYSTEM
3038 * (which is recommended by the DDK), it is supposed to happen
3039 * before the DirectSound interface is opened */
3040 if ((*ippDS
)->drvdesc
.dwFlags
& DSDDESC_DOMMSYSTEMOPEN
) {
3041 /* FIXME: is this right? */
3042 err
= mmErr(waveOutOpen(&((*ippDS
)->hwo
), (*ippDS
)->drvdesc
.dnDevNode
, &((*ippDS
)->wfx
),
3043 0, 0, CALLBACK_NULL
| WAVE_DIRECTSOUND
));
3046 if (drv
&& (err
== DS_OK
))
3047 err
= IDsDriver_Open(drv
);
3049 /* FIXME: do we want to handle a temporarily busy device? */
3051 HeapFree(GetProcessHeap(),0,*ippDS
);
3056 /* the driver is now open, so it's now allowed to call GetCaps */
3058 IDsDriver_GetCaps(drv
,&((*ippDS
)->drvcaps
));
3062 /* FIXME: look at wcaps */
3063 (*ippDS
)->drvcaps
.dwFlags
=
3064 DSCAPS_PRIMARY16BIT
| DSCAPS_PRIMARYSTEREO
;
3066 (*ippDS
)->drvcaps
.dwFlags
|= DSCAPS_EMULDRIVER
;
3068 /* Allocate memory for HEL buffer headers */
3069 for (c
=0; c
<DS_HEL_FRAGS
; c
++) {
3070 (*ippDS
)->pwave
[c
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(WAVEHDR
));
3071 if (!(*ippDS
)->pwave
[c
]) {
3072 /* Argh, out of memory */
3074 HeapFree(GetProcessHeap(),0,(*ippDS
)->pwave
[c
]);
3075 waveOutClose((*ippDS
)->hwo
);
3076 HeapFree(GetProcessHeap(),0,*ippDS
);
3078 return DSERR_OUTOFMEMORY
;
3084 InitializeCriticalSection(&((*ippDS
)->lock
));
3088 if (primarybuf
== NULL
) {
3092 dsbd
.dwSize
= sizeof(DSBUFFERDESC
);
3093 dsbd
.dwFlags
= DSBCAPS_PRIMARYBUFFER
| DSBCAPS_GETCURRENTPOSITION2
;
3094 dsbd
.dwBufferBytes
= 0;
3095 dsbd
.lpwfxFormat
= &(dsound
->wfx
);
3096 hr
= IDirectSound_CreateSoundBuffer(*ppDS
, &dsbd
, (LPDIRECTSOUNDBUFFER
*)&primarybuf
, NULL
);
3100 /* dsound->primary is NULL - don't need to Release */
3101 dsound
->primary
= primarybuf
;
3102 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER
)primarybuf
);
3104 timeBeginPeriod(DS_TIME_RES
);
3105 dsound
->timerID
= timeSetEvent(DS_TIME_DEL
, DS_TIME_RES
, DSOUND_timer
,
3106 (DWORD
)dsound
, TIME_PERIODIC
| TIME_CALLBACK_FUNCTION
);
3111 /***************************************************************************
3112 * DirectSoundCaptureCreate [DSOUND.6]
3114 * Create and initialize a DirectSoundCapture interface
3118 * Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
3121 HRESULT WINAPI
DirectSoundCaptureCreate(
3123 LPDIRECTSOUNDCAPTURE
* lplpDSC
,
3124 LPUNKNOWN pUnkOuter
)
3126 TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID
), lplpDSC
, pUnkOuter
);
3129 return DSERR_NOAGGREGATION
;
3132 /* Default device? */
3134 return DSOUND_CreateDirectSoundCapture( (LPVOID
*)lplpDSC
);
3137 FIXME( "Unknown GUID %s\n", debugstr_guid(lpcGUID
) );
3140 return DSERR_OUTOFMEMORY
;
3143 /***************************************************************************
3144 * DirectSoundCaptureEnumerateA [DSOUND.7]
3146 * Enumerate all DirectSound drivers installed in the system
3150 * Failure: DSERR_INVALIDPARAM
3152 HRESULT WINAPI
DirectSoundCaptureEnumerateA(
3153 LPDSENUMCALLBACKA lpDSEnumCallback
,
3156 TRACE("(%p,%p)\n", lpDSEnumCallback
, lpContext
);
3158 if ( lpDSEnumCallback
)
3159 lpDSEnumCallback(NULL
,"WINE Primary Sound Capture Driver",
3160 "SoundCap",lpContext
);
3166 /***************************************************************************
3167 * DirectSoundCaptureEnumerateW [DSOUND.8]
3169 * Enumerate all DirectSound drivers installed in the system
3173 * Failure: DSERR_INVALIDPARAM
3175 HRESULT WINAPI
DirectSoundCaptureEnumerateW(
3176 LPDSENUMCALLBACKW lpDSEnumCallback
,
3179 FIXME("(%p,%p):stub\n", lpDSEnumCallback
, lpContext
);
3184 DSOUND_CreateDirectSoundCapture( LPVOID
* ppobj
)
3186 *ppobj
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof( IDirectSoundCaptureImpl
) );
3188 if ( *ppobj
== NULL
) {
3189 return DSERR_OUTOFMEMORY
;
3193 ICOM_THIS(IDirectSoundCaptureImpl
,*ppobj
);
3196 ICOM_VTBL(This
) = &dscvt
;
3198 InitializeCriticalSection( &This
->lock
);
3204 static HRESULT WINAPI
3205 IDirectSoundCaptureImpl_QueryInterface(
3206 LPDIRECTSOUNDCAPTURE iface
,
3210 ICOM_THIS(IDirectSoundCaptureImpl
,iface
);
3212 FIXME( "(%p)->(%s,%p): stub\n", This
, debugstr_guid(riid
), ppobj
);
3218 IDirectSoundCaptureImpl_AddRef( LPDIRECTSOUNDCAPTURE iface
)
3221 ICOM_THIS(IDirectSoundCaptureImpl
,iface
);
3223 EnterCriticalSection( &This
->lock
);
3225 TRACE( "(%p) was 0x%08lx\n", This
, This
->ref
);
3226 uRef
= ++(This
->ref
);
3228 LeaveCriticalSection( &This
->lock
);
3234 IDirectSoundCaptureImpl_Release( LPDIRECTSOUNDCAPTURE iface
)
3237 ICOM_THIS(IDirectSoundCaptureImpl
,iface
);
3239 EnterCriticalSection( &This
->lock
);
3241 TRACE( "(%p) was 0x%08lx\n", This
, This
->ref
);
3242 uRef
= --(This
->ref
);
3244 LeaveCriticalSection( &This
->lock
);
3247 DeleteCriticalSection( &This
->lock
);
3248 HeapFree( GetProcessHeap(), 0, This
);
3254 static HRESULT WINAPI
3255 IDirectSoundCaptureImpl_CreateCaptureBuffer(
3256 LPDIRECTSOUNDCAPTURE iface
,
3257 LPCDSCBUFFERDESC lpcDSCBufferDesc
,
3258 LPDIRECTSOUNDCAPTUREBUFFER
* lplpDSCaptureBuffer
,
3262 ICOM_THIS(IDirectSoundCaptureImpl
,iface
);
3264 TRACE( "(%p)->(%p,%p,%p)\n", This
, lpcDSCBufferDesc
, lplpDSCaptureBuffer
, pUnk
);
3267 return DSERR_INVALIDPARAM
;
3270 hr
= DSOUND_CreateDirectSoundCaptureBuffer( lpcDSCBufferDesc
, (LPVOID
*)lplpDSCaptureBuffer
);
3275 static HRESULT WINAPI
3276 IDirectSoundCaptureImpl_GetCaps(
3277 LPDIRECTSOUNDCAPTURE iface
,
3278 LPDSCCAPS lpDSCCaps
)
3280 ICOM_THIS(IDirectSoundCaptureImpl
,iface
);
3282 FIXME( "(%p)->(%p): stub\n", This
, lpDSCCaps
);
3287 static HRESULT WINAPI
3288 IDirectSoundCaptureImpl_Initialize(
3289 LPDIRECTSOUNDCAPTURE iface
,
3292 ICOM_THIS(IDirectSoundCaptureImpl
,iface
);
3294 FIXME( "(%p)->(%p): stub\n", This
, lpcGUID
);
3300 static ICOM_VTABLE(IDirectSoundCapture
) dscvt
=
3302 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
3303 /* IUnknown methods */
3304 IDirectSoundCaptureImpl_QueryInterface
,
3305 IDirectSoundCaptureImpl_AddRef
,
3306 IDirectSoundCaptureImpl_Release
,
3308 /* IDirectSoundCapture methods */
3309 IDirectSoundCaptureImpl_CreateCaptureBuffer
,
3310 IDirectSoundCaptureImpl_GetCaps
,
3311 IDirectSoundCaptureImpl_Initialize
3315 DSOUND_CreateDirectSoundCaptureBuffer( LPCDSCBUFFERDESC lpcDSCBufferDesc
, LPVOID
* ppobj
)
3318 FIXME( "(%p,%p): ignoring lpcDSCBufferDesc\n", lpcDSCBufferDesc
, ppobj
);
3320 *ppobj
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof( IDirectSoundCaptureBufferImpl
) );
3322 if ( *ppobj
== NULL
) {
3323 return DSERR_OUTOFMEMORY
;
3327 ICOM_THIS(IDirectSoundCaptureBufferImpl
,*ppobj
);
3330 ICOM_VTBL(This
) = &dscbvt
;
3332 InitializeCriticalSection( &This
->lock
);
3339 static HRESULT WINAPI
3340 IDirectSoundCaptureBufferImpl_QueryInterface(
3341 LPDIRECTSOUNDCAPTUREBUFFER iface
,
3345 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
3347 FIXME( "(%p)->(%s,%p): stub\n", This
, debugstr_guid(riid
), ppobj
);
3353 IDirectSoundCaptureBufferImpl_AddRef( LPDIRECTSOUNDCAPTUREBUFFER iface
)
3356 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
3358 EnterCriticalSection( &This
->lock
);
3360 TRACE( "(%p) was 0x%08lx\n", This
, This
->ref
);
3361 uRef
= ++(This
->ref
);
3363 LeaveCriticalSection( &This
->lock
);
3369 IDirectSoundCaptureBufferImpl_Release( LPDIRECTSOUNDCAPTUREBUFFER iface
)
3372 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
3374 EnterCriticalSection( &This
->lock
);
3376 TRACE( "(%p) was 0x%08lx\n", This
, This
->ref
);
3377 uRef
= --(This
->ref
);
3379 LeaveCriticalSection( &This
->lock
);
3382 DeleteCriticalSection( &This
->lock
);
3383 HeapFree( GetProcessHeap(), 0, This
);
3389 static HRESULT WINAPI
3390 IDirectSoundCaptureBufferImpl_GetCaps(
3391 LPDIRECTSOUNDCAPTUREBUFFER iface
,
3392 LPDSCBCAPS lpDSCBCaps
)
3394 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
3396 FIXME( "(%p)->(%p): stub\n", This
, lpDSCBCaps
);
3401 static HRESULT WINAPI
3402 IDirectSoundCaptureBufferImpl_GetCurrentPosition(
3403 LPDIRECTSOUNDCAPTUREBUFFER iface
,
3404 LPDWORD lpdwCapturePosition
,
3405 LPDWORD lpdwReadPosition
)
3407 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
3409 FIXME( "(%p)->(%p,%p): stub\n", This
, lpdwCapturePosition
, lpdwReadPosition
);
3414 static HRESULT WINAPI
3415 IDirectSoundCaptureBufferImpl_GetFormat(
3416 LPDIRECTSOUNDCAPTUREBUFFER iface
,
3417 LPWAVEFORMATEX lpwfxFormat
,
3418 DWORD dwSizeAllocated
,
3419 LPDWORD lpdwSizeWritten
)
3421 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
3423 FIXME( "(%p)->(%p,0x%08lx,%p): stub\n", This
, lpwfxFormat
, dwSizeAllocated
, lpdwSizeWritten
);
3428 static HRESULT WINAPI
3429 IDirectSoundCaptureBufferImpl_GetStatus(
3430 LPDIRECTSOUNDCAPTUREBUFFER iface
,
3431 LPDWORD lpdwStatus
)
3433 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
3435 FIXME( "(%p)->(%p): stub\n", This
, lpdwStatus
);
3440 static HRESULT WINAPI
3441 IDirectSoundCaptureBufferImpl_Initialize(
3442 LPDIRECTSOUNDCAPTUREBUFFER iface
,
3443 LPDIRECTSOUNDCAPTURE lpDSC
,
3444 LPCDSCBUFFERDESC lpcDSCBDesc
)
3446 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
3448 FIXME( "(%p)->(%p,%p): stub\n", This
, lpDSC
, lpcDSCBDesc
);
3453 static HRESULT WINAPI
3454 IDirectSoundCaptureBufferImpl_Lock(
3455 LPDIRECTSOUNDCAPTUREBUFFER iface
,
3458 LPVOID
* lplpvAudioPtr1
,
3459 LPDWORD lpdwAudioBytes1
,
3460 LPVOID
* lplpvAudioPtr2
,
3461 LPDWORD lpdwAudioBytes2
,
3464 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
3466 FIXME( "(%p)->(%08lu,%08lu,%p,%p,%p,%p,0x%08lx): stub\n", This
, dwReadCusor
, dwReadBytes
, lplpvAudioPtr1
, lpdwAudioBytes1
, lplpvAudioPtr2
, lpdwAudioBytes2
, dwFlags
);
3471 static HRESULT WINAPI
3472 IDirectSoundCaptureBufferImpl_Start(
3473 LPDIRECTSOUNDCAPTUREBUFFER iface
,
3476 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
3478 FIXME( "(%p)->(0x%08lx): stub\n", This
, dwFlags
);
3483 static HRESULT WINAPI
3484 IDirectSoundCaptureBufferImpl_Stop( LPDIRECTSOUNDCAPTUREBUFFER iface
)
3486 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
3488 FIXME( "(%p): stub\n", This
);
3493 static HRESULT WINAPI
3494 IDirectSoundCaptureBufferImpl_Unlock(
3495 LPDIRECTSOUNDCAPTUREBUFFER iface
,
3496 LPVOID lpvAudioPtr1
,
3497 DWORD dwAudioBytes1
,
3498 LPVOID lpvAudioPtr2
,
3499 DWORD dwAudioBytes2
)
3501 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
3503 FIXME( "(%p)->(%p,%08lu,%p,%08lu): stub\n", This
, lpvAudioPtr1
, dwAudioBytes1
, lpvAudioPtr2
, dwAudioBytes2
);
3509 static ICOM_VTABLE(IDirectSoundCaptureBuffer
) dscbvt
=
3511 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
3512 /* IUnknown methods */
3513 IDirectSoundCaptureBufferImpl_QueryInterface
,
3514 IDirectSoundCaptureBufferImpl_AddRef
,
3515 IDirectSoundCaptureBufferImpl_Release
,
3517 /* IDirectSoundCaptureBuffer methods */
3518 IDirectSoundCaptureBufferImpl_GetCaps
,
3519 IDirectSoundCaptureBufferImpl_GetCurrentPosition
,
3520 IDirectSoundCaptureBufferImpl_GetFormat
,
3521 IDirectSoundCaptureBufferImpl_GetStatus
,
3522 IDirectSoundCaptureBufferImpl_Initialize
,
3523 IDirectSoundCaptureBufferImpl_Lock
,
3524 IDirectSoundCaptureBufferImpl_Start
,
3525 IDirectSoundCaptureBufferImpl_Stop
,
3526 IDirectSoundCaptureBufferImpl_Unlock
3529 /*******************************************************************************
3530 * DirectSound ClassFactory
3534 /* IUnknown fields */
3535 ICOM_VFIELD(IClassFactory
);
3537 } IClassFactoryImpl
;
3539 static HRESULT WINAPI
3540 DSCF_QueryInterface(LPCLASSFACTORY iface
,REFIID riid
,LPVOID
*ppobj
) {
3541 ICOM_THIS(IClassFactoryImpl
,iface
);
3543 FIXME("(%p)->(%s,%p),stub!\n",This
,debugstr_guid(riid
),ppobj
);
3544 return E_NOINTERFACE
;
3548 DSCF_AddRef(LPCLASSFACTORY iface
) {
3549 ICOM_THIS(IClassFactoryImpl
,iface
);
3550 return ++(This
->ref
);
3553 static ULONG WINAPI
DSCF_Release(LPCLASSFACTORY iface
) {
3554 ICOM_THIS(IClassFactoryImpl
,iface
);
3555 /* static class, won't be freed */
3556 return --(This
->ref
);
3559 static HRESULT WINAPI
DSCF_CreateInstance(
3560 LPCLASSFACTORY iface
,LPUNKNOWN pOuter
,REFIID riid
,LPVOID
*ppobj
3562 ICOM_THIS(IClassFactoryImpl
,iface
);
3564 TRACE("(%p)->(%p,%s,%p)\n",This
,pOuter
,debugstr_guid(riid
),ppobj
);
3565 if ( IsEqualGUID( &IID_IDirectSound
, riid
) ) {
3566 /* FIXME: reuse already created dsound if present? */
3567 return DirectSoundCreate(riid
,(LPDIRECTSOUND
*)ppobj
,pOuter
);
3569 return E_NOINTERFACE
;
3572 static HRESULT WINAPI
DSCF_LockServer(LPCLASSFACTORY iface
,BOOL dolock
) {
3573 ICOM_THIS(IClassFactoryImpl
,iface
);
3574 FIXME("(%p)->(%d),stub!\n",This
,dolock
);
3578 static ICOM_VTABLE(IClassFactory
) DSCF_Vtbl
= {
3579 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
3580 DSCF_QueryInterface
,
3583 DSCF_CreateInstance
,
3586 static IClassFactoryImpl DSOUND_CF
= {&DSCF_Vtbl
, 1 };
3588 /*******************************************************************************
3589 * DllGetClassObject [DSOUND.4]
3590 * Retrieves class object from a DLL object
3593 * Docs say returns STDAPI
3596 * rclsid [I] CLSID for the class object
3597 * riid [I] Reference to identifier of interface for class object
3598 * ppv [O] Address of variable to receive interface pointer for riid
3602 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
3605 DWORD WINAPI
DSOUND_DllGetClassObject(REFCLSID rclsid
,REFIID riid
,LPVOID
*ppv
)
3607 TRACE("(%p,%p,%p)\n", debugstr_guid(rclsid
), debugstr_guid(riid
), ppv
);
3608 if ( IsEqualCLSID( &IID_IClassFactory
, riid
) ) {
3609 *ppv
= (LPVOID
)&DSOUND_CF
;
3610 IClassFactory_AddRef((IClassFactory
*)*ppv
);
3614 FIXME("(%p,%p,%p): no interface found.\n", debugstr_guid(rclsid
), debugstr_guid(riid
), ppv
);
3615 return CLASS_E_CLASSNOTAVAILABLE
;
3619 /*******************************************************************************
3620 * DllCanUnloadNow [DSOUND.3] Determines whether the DLL is in use.
3626 DWORD WINAPI
DSOUND_DllCanUnloadNow(void)
3628 FIXME("(void): stub\n");