3 * Copyright 1998 Marcus Meissner
4 * Copyright 1998 Rob Riggs
5 * Copyright 2000-2001 TransGaming Technologies, Inc.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * Most thread locking is complete. There may be a few race
23 * conditions still lurking.
25 * Tested with a Soundblaster clone, a Gravis UltraSound Classic,
26 * and a Turtle Beach Tropez+.
29 * Implement DirectSoundCapture API
30 * Implement SetCooperativeLevel properly (need to address focus issues)
31 * Implement DirectSound3DBuffers (stubs in place)
32 * Use hardware 3D support if available
33 * Add critical section locking inside Release and AddRef methods
34 * Handle static buffers - put those in hardware, non-static not in hardware
35 * Hardware DuplicateSoundBuffer
36 * Proper volume calculation, and setting volume in HEL primary buffer
37 * Optimize WINMM and negotiate fragment size, decrease DS_HEL_MARGIN
43 #include <sys/types.h>
44 #include <sys/fcntl.h>
48 #include <math.h> /* Insomnia - pow() function */
57 #include "wine/windef16.h"
58 #include "wine/debug.h"
62 WINE_DEFAULT_DEBUG_CHANNEL(dsound
);
64 /* these are eligible for tuning... they must be high on slow machines... */
65 /* some stuff may get more responsive with lower values though... */
66 #define DS_EMULDRIVER 1 /* some games (Quake 2, UT) refuse to accept
67 emulated dsound devices. set to 0 ! */
68 #define DS_HEL_FRAGS 48 /* HEL only: number of waveOut fragments in primary buffer
69 * (changing this won't help you) */
70 #define DS_HEL_MARGIN 5 /* HEL only: number of waveOut fragments ahead to mix in new buffers
71 * (keep this close or equal to DS_HEL_QUEUE for best results) */
72 #define DS_HEL_QUEUE 5 /* HEL only: number of waveOut fragments ahead to queue to driver
73 * (this will affect HEL sound reliability and latency) */
75 #define DS_SND_QUEUE_MAX 28 /* max number of fragments to prebuffer */
76 #define DS_SND_QUEUE_MIN 12 /* min number of fragments to prebuffer */
78 /* Linux does not support better timing than 10ms */
79 #define DS_TIME_RES 10 /* Resolution of multimedia timer */
80 #define DS_TIME_DEL 10 /* Delay of multimedia timer callback, and duration of HEL fragment */
82 /*****************************************************************************
83 * Predeclare the interface implementation structures
85 typedef struct IDirectSoundImpl IDirectSoundImpl
;
86 typedef struct IDirectSoundBufferImpl IDirectSoundBufferImpl
;
87 typedef struct IDirectSoundNotifyImpl IDirectSoundNotifyImpl
;
88 typedef struct IDirectSound3DListenerImpl IDirectSound3DListenerImpl
;
89 typedef struct IDirectSound3DBufferImpl IDirectSound3DBufferImpl
;
90 typedef struct IDirectSoundCaptureImpl IDirectSoundCaptureImpl
;
91 typedef struct IDirectSoundCaptureBufferImpl IDirectSoundCaptureBufferImpl
;
92 typedef struct IKsPropertySetImpl IKsPropertySetImpl
;
94 /*****************************************************************************
95 * IDirectSound implementation structure
97 struct IDirectSoundImpl
100 ICOM_VFIELD(IDirectSound
);
102 /* IDirectSoundImpl fields */
104 DSDRIVERDESC drvdesc
;
105 DSDRIVERCAPS drvcaps
;
107 LPWAVEHDR pwave
[DS_HEL_FRAGS
];
108 UINT timerID
, pwplay
, pwwrite
, pwqueue
, prebuf
;
112 IDirectSoundBufferImpl
** buffers
;
113 IDirectSoundBufferImpl
* primary
;
114 IDirectSound3DListenerImpl
* listener
;
115 WAVEFORMATEX wfx
; /* current main waveformat */
116 CRITICAL_SECTION lock
;
119 /*****************************************************************************
120 * IDirectSoundBuffer implementation structure
122 struct IDirectSoundBufferImpl
124 /* FIXME: document */
125 /* IUnknown fields */
126 ICOM_VFIELD(IDirectSoundBuffer
);
128 /* IDirectSoundBufferImpl fields */
129 PIDSDRIVERBUFFER hwbuf
;
132 IDirectSound3DBufferImpl
* ds3db
;
133 DWORD playflags
,state
,leadin
;
134 DWORD playpos
,startpos
,writelead
,buflen
;
135 DWORD nAvgBytesPerSec
;
138 IDirectSoundBufferImpl
* parent
; /* for duplicates */
139 IDirectSoundImpl
* dsound
;
141 LPDSBPOSITIONNOTIFY notifies
;
143 CRITICAL_SECTION lock
;
144 /* used for frequency conversion (PerfectPitch) */
145 ULONG freqAdjust
, freqAcc
;
146 /* used for intelligent (well, sort of) prebuffering */
147 DWORD probably_valid_to
;
148 DWORD primary_mixpos
, buf_mixpos
;
152 #define STATE_STOPPED 0
153 #define STATE_STARTING 1
154 #define STATE_PLAYING 2
155 #define STATE_STOPPING 3
157 /*****************************************************************************
158 * IDirectSoundNotify implementation structure
160 struct IDirectSoundNotifyImpl
162 /* IUnknown fields */
163 ICOM_VFIELD(IDirectSoundNotify
);
165 /* IDirectSoundNotifyImpl fields */
166 IDirectSoundBufferImpl
* dsb
;
169 /*****************************************************************************
170 * IDirectSound3DListener implementation structure
172 struct IDirectSound3DListenerImpl
174 /* IUnknown fields */
175 ICOM_VFIELD(IDirectSound3DListener
);
177 /* IDirectSound3DListenerImpl fields */
178 IDirectSoundBufferImpl
* dsb
;
180 CRITICAL_SECTION lock
;
183 struct IKsPropertySetImpl
185 /* IUnknown fields */
186 ICOM_VFIELD(IKsPropertySet
);
188 /* IKsPropertySetImpl fields */
189 IDirectSound3DBufferImpl
*ds3db
; /* backptr, no ref */
192 /*****************************************************************************
193 * IDirectSound3DBuffer implementation structure
195 struct IDirectSound3DBufferImpl
197 /* IUnknown fields */
198 ICOM_VFIELD(IDirectSound3DBuffer
);
200 /* IDirectSound3DBufferImpl fields */
201 IDirectSoundBufferImpl
* dsb
;
205 CRITICAL_SECTION lock
;
206 IKsPropertySetImpl
* iks
;
210 /*****************************************************************************
211 * IDirectSoundCapture implementation structure
213 struct IDirectSoundCaptureImpl
215 /* IUnknown fields */
216 ICOM_VFIELD(IDirectSoundCapture
);
219 /* IDirectSoundCaptureImpl fields */
220 CRITICAL_SECTION lock
;
223 /*****************************************************************************
224 * IDirectSoundCapture implementation structure
226 struct IDirectSoundCaptureBufferImpl
228 /* IUnknown fields */
229 ICOM_VFIELD(IDirectSoundCaptureBuffer
);
232 /* IDirectSoundCaptureBufferImpl fields */
233 CRITICAL_SECTION lock
;
237 /* #define USE_DSOUND3D 1 */
239 #define DSOUND_FREQSHIFT (14)
241 static IDirectSoundImpl
* dsound
= NULL
;
243 static IDirectSoundBufferImpl
* primarybuf
= NULL
;
245 static void DSOUND_CheckEvent(IDirectSoundBufferImpl
*dsb
, int len
);
246 static void DSOUND_MixCancelAt(IDirectSoundBufferImpl
*dsb
, DWORD buf_writepos
);
248 static void DSOUND_WaveQueue(IDirectSoundImpl
*dsound
, DWORD mixq
);
249 static void DSOUND_PerformMix(void);
250 static void CALLBACK
DSOUND_callback(HWAVEOUT hwo
, UINT msg
, DWORD dwUser
, DWORD dw1
, DWORD dw2
);
252 static HRESULT
DSOUND_CreateDirectSoundCapture( LPVOID
* ppobj
);
253 static HRESULT
DSOUND_CreateDirectSoundCaptureBuffer( LPCDSCBUFFERDESC lpcDSCBufferDesc
, LPVOID
* ppobj
);
255 static ICOM_VTABLE(IDirectSoundCapture
) dscvt
;
256 static ICOM_VTABLE(IDirectSoundCaptureBuffer
) dscbvt
;
258 static HRESULT
mmErr(UINT err
)
261 case MMSYSERR_NOERROR
:
263 case MMSYSERR_ALLOCATED
:
264 return DSERR_ALLOCATED
;
265 case MMSYSERR_INVALHANDLE
:
266 return DSERR_GENERIC
; /* FIXME */
267 case MMSYSERR_NODRIVER
:
268 return DSERR_NODRIVER
;
270 return DSERR_OUTOFMEMORY
;
271 case MMSYSERR_INVALPARAM
:
272 return DSERR_INVALIDPARAM
;
274 FIXME("Unknown MMSYS error %d\n",err
);
275 return DSERR_GENERIC
;
279 /***************************************************************************
280 * DirectSoundEnumerateA [DSOUND.2]
282 * Enumerate all DirectSound drivers installed in the system
286 * Failure: DSERR_INVALIDPARAM
288 HRESULT WINAPI
DirectSoundEnumerateA(
289 LPDSENUMCALLBACKA lpDSEnumCallback
,
292 TRACE("lpDSEnumCallback = %p, lpContext = %p\n",
293 lpDSEnumCallback
, lpContext
);
296 if (lpDSEnumCallback
!= NULL
)
297 lpDSEnumCallback(NULL
,"WINE DirectSound",
304 /***************************************************************************
305 * DirectSoundEnumerateW [DSOUND.3]
307 * Enumerate all DirectSound drivers installed in the system
311 * Failure: DSERR_INVALIDPARAM
313 HRESULT WINAPI
DirectSoundEnumerateW(
314 LPDSENUMCALLBACKW lpDSEnumCallback
,
317 FIXME("lpDSEnumCallback = %p, lpContext = %p: stub\n",
318 lpDSEnumCallback
, lpContext
);
324 static void _dump_DSBCAPS(DWORD xmask
) {
329 #define FE(x) { x, #x },
330 FE(DSBCAPS_PRIMARYBUFFER
)
332 FE(DSBCAPS_LOCHARDWARE
)
333 FE(DSBCAPS_LOCSOFTWARE
)
335 FE(DSBCAPS_CTRLFREQUENCY
)
337 FE(DSBCAPS_CTRLVOLUME
)
338 FE(DSBCAPS_CTRLPOSITIONNOTIFY
)
339 FE(DSBCAPS_CTRLDEFAULT
)
341 FE(DSBCAPS_STICKYFOCUS
)
342 FE(DSBCAPS_GLOBALFOCUS
)
343 FE(DSBCAPS_GETCURRENTPOSITION2
)
344 FE(DSBCAPS_MUTE3DATMAXDISTANCE
)
349 for (i
=0;i
<sizeof(flags
)/sizeof(flags
[0]);i
++)
350 if ((flags
[i
].mask
& xmask
) == flags
[i
].mask
)
351 DPRINTF("%s ",flags
[i
].name
);
354 /*******************************************************************************
358 /* IUnknown methods */
360 static HRESULT WINAPI
IKsPropertySetImpl_QueryInterface(
361 LPKSPROPERTYSET iface
, REFIID riid
, LPVOID
*ppobj
363 ICOM_THIS(IKsPropertySetImpl
,iface
);
365 FIXME("(%p,%s,%p), stub!\n",This
,debugstr_guid(riid
),ppobj
);
371 static ULONG WINAPI
IKsPropertySetImpl_AddRef(LPKSPROPERTYSET iface
) {
372 ICOM_THIS(IKsPropertySetImpl
,iface
);
380 static ULONG WINAPI
IKsPropertySetImpl_Release(LPKSPROPERTYSET iface
) {
381 ICOM_THIS(IKsPropertySetImpl
,iface
);
389 static HRESULT WINAPI
IKsPropertySetImpl_Get(LPKSPROPERTYSET iface
,
390 REFGUID guidPropSet
, ULONG dwPropID
,
391 LPVOID pInstanceData
, ULONG cbInstanceData
,
392 LPVOID pPropData
, ULONG cbPropData
,
395 ICOM_THIS(IKsPropertySetImpl
,iface
);
397 FIXME("(%p,%s,%ld,%p,%ld,%p,%ld,%p), stub!\n",This
,debugstr_guid(guidPropSet
),dwPropID
,pInstanceData
,cbInstanceData
,pPropData
,cbPropData
,pcbReturned
);
398 return E_PROP_ID_UNSUPPORTED
;
403 static HRESULT WINAPI
IKsPropertySetImpl_Set(LPKSPROPERTYSET iface
,
404 REFGUID guidPropSet
, ULONG dwPropID
,
405 LPVOID pInstanceData
, ULONG cbInstanceData
,
406 LPVOID pPropData
, ULONG cbPropData
408 ICOM_THIS(IKsPropertySetImpl
,iface
);
410 FIXME("(%p,%s,%ld,%p,%ld,%p,%ld), stub!\n",This
,debugstr_guid(guidPropSet
),dwPropID
,pInstanceData
,cbInstanceData
,pPropData
,cbPropData
);
411 return E_PROP_ID_UNSUPPORTED
;
416 static HRESULT WINAPI
IKsPropertySetImpl_QuerySupport(LPKSPROPERTYSET iface
,
417 REFGUID guidPropSet
, ULONG dwPropID
, PULONG pTypeSupport
419 ICOM_THIS(IKsPropertySetImpl
,iface
);
421 FIXME("(%p,%s,%ld,%p), stub!\n",This
,debugstr_guid(guidPropSet
),dwPropID
,pTypeSupport
);
422 return E_PROP_ID_UNSUPPORTED
;
427 static ICOM_VTABLE(IKsPropertySet
) iksvt
= {
428 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
429 IKsPropertySetImpl_QueryInterface
,
430 IKsPropertySetImpl_AddRef
,
431 IKsPropertySetImpl_Release
,
432 IKsPropertySetImpl_Get
,
433 IKsPropertySetImpl_Set
,
434 IKsPropertySetImpl_QuerySupport
438 /*******************************************************************************
439 * IDirectSound3DBuffer
442 /* IUnknown methods */
444 static HRESULT WINAPI
IDirectSound3DBufferImpl_QueryInterface(
445 LPDIRECTSOUND3DBUFFER iface
, REFIID riid
, LPVOID
*ppobj
)
447 ICOM_THIS(IDirectSound3DBufferImpl
,iface
);
449 if ( IsEqualGUID( &IID_IKsPropertySet
, riid
) ) {
450 IDirectSound3DBuffer_AddRef(iface
);
455 FIXME("(%p,%s,%p), no such interface.\n",This
,debugstr_guid(riid
),ppobj
);
461 static ULONG WINAPI
IDirectSound3DBufferImpl_AddRef(LPDIRECTSOUND3DBUFFER iface
)
463 ICOM_THIS(IDirectSound3DBufferImpl
,iface
);
470 static ULONG WINAPI
IDirectSound3DBufferImpl_Release(LPDIRECTSOUND3DBUFFER iface
)
472 ICOM_THIS(IDirectSound3DBufferImpl
,iface
);
474 TRACE("(%p) ref was %ld\n", This
, This
->ref
);
480 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)This
->dsb
);
482 DeleteCriticalSection(&This
->lock
);
484 HeapFree(GetProcessHeap(),0,This
->buffer
);
485 HeapFree(GetProcessHeap(),0,This
);
491 /* IDirectSound3DBuffer methods */
493 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetAllParameters(
494 LPDIRECTSOUND3DBUFFER iface
,
495 LPDS3DBUFFER lpDs3dBuffer
)
503 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetConeAngles(
504 LPDIRECTSOUND3DBUFFER iface
,
505 LPDWORD lpdwInsideConeAngle
,
506 LPDWORD lpdwOutsideConeAngle
)
514 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetConeOrientation(
515 LPDIRECTSOUND3DBUFFER iface
,
516 LPD3DVECTOR lpvConeOrientation
)
524 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetConeOutsideVolume(
525 LPDIRECTSOUND3DBUFFER iface
,
526 LPLONG lplConeOutsideVolume
)
534 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetMaxDistance(
535 LPDIRECTSOUND3DBUFFER iface
,
536 LPD3DVALUE lpfMaxDistance
)
544 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetMinDistance(
545 LPDIRECTSOUND3DBUFFER iface
,
546 LPD3DVALUE lpfMinDistance
)
554 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetMode(
555 LPDIRECTSOUND3DBUFFER iface
,
564 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetPosition(
565 LPDIRECTSOUND3DBUFFER iface
,
566 LPD3DVECTOR lpvPosition
)
574 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetVelocity(
575 LPDIRECTSOUND3DBUFFER iface
,
576 LPD3DVECTOR lpvVelocity
)
584 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetAllParameters(
585 LPDIRECTSOUND3DBUFFER iface
,
586 LPCDS3DBUFFER lpcDs3dBuffer
,
595 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetConeAngles(
596 LPDIRECTSOUND3DBUFFER iface
,
597 DWORD dwInsideConeAngle
,
598 DWORD dwOutsideConeAngle
,
607 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetConeOrientation(
608 LPDIRECTSOUND3DBUFFER iface
,
609 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
618 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetConeOutsideVolume(
619 LPDIRECTSOUND3DBUFFER iface
,
620 LONG lConeOutsideVolume
,
629 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetMaxDistance(
630 LPDIRECTSOUND3DBUFFER iface
,
631 D3DVALUE fMaxDistance
,
640 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetMinDistance(
641 LPDIRECTSOUND3DBUFFER iface
,
642 D3DVALUE fMinDistance
,
651 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetMode(
652 LPDIRECTSOUND3DBUFFER iface
,
656 ICOM_THIS(IDirectSound3DBufferImpl
,iface
);
657 TRACE("mode = %lx\n", dwMode
);
658 This
->ds3db
.dwMode
= dwMode
;
664 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetPosition(
665 LPDIRECTSOUND3DBUFFER iface
,
666 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
675 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetVelocity(
676 LPDIRECTSOUND3DBUFFER iface
,
677 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
686 static ICOM_VTABLE(IDirectSound3DBuffer
) ds3dbvt
=
688 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
689 /* IUnknown methods */
690 IDirectSound3DBufferImpl_QueryInterface
,
691 IDirectSound3DBufferImpl_AddRef
,
692 IDirectSound3DBufferImpl_Release
,
693 /* IDirectSound3DBuffer methods */
694 IDirectSound3DBufferImpl_GetAllParameters
,
695 IDirectSound3DBufferImpl_GetConeAngles
,
696 IDirectSound3DBufferImpl_GetConeOrientation
,
697 IDirectSound3DBufferImpl_GetConeOutsideVolume
,
698 IDirectSound3DBufferImpl_GetMaxDistance
,
699 IDirectSound3DBufferImpl_GetMinDistance
,
700 IDirectSound3DBufferImpl_GetMode
,
701 IDirectSound3DBufferImpl_GetPosition
,
702 IDirectSound3DBufferImpl_GetVelocity
,
703 IDirectSound3DBufferImpl_SetAllParameters
,
704 IDirectSound3DBufferImpl_SetConeAngles
,
705 IDirectSound3DBufferImpl_SetConeOrientation
,
706 IDirectSound3DBufferImpl_SetConeOutsideVolume
,
707 IDirectSound3DBufferImpl_SetMaxDistance
,
708 IDirectSound3DBufferImpl_SetMinDistance
,
709 IDirectSound3DBufferImpl_SetMode
,
710 IDirectSound3DBufferImpl_SetPosition
,
711 IDirectSound3DBufferImpl_SetVelocity
,
716 static int DSOUND_Create3DBuffer(IDirectSoundBufferImpl
* dsb
)
718 DWORD i
, temp
, iSize
, oSize
, offset
;
719 LPBYTE bIbuf
, bObuf
, bTbuf
= NULL
;
720 LPWORD wIbuf
, wObuf
, wTbuf
= NULL
;
722 /* Inside DirectX says it's stupid but allowed */
723 if (dsb
->wfx
.nChannels
== 2) {
724 /* Convert to mono */
725 if (dsb
->wfx
.wBitsPerSample
== 16) {
726 iSize
= dsb
->buflen
/ 4;
727 wTbuf
= malloc(dsb
->buflen
/ 2);
729 return DSERR_OUTOFMEMORY
;
730 for (i
= 0; i
< iSize
; i
++)
731 wTbuf
[i
] = (dsb
->buffer
[i
* 2] + dsb
->buffer
[(i
* 2) + 1]) / 2;
734 iSize
= dsb
->buflen
/ 2;
735 bTbuf
= malloc(dsb
->buflen
/ 2);
737 return DSERR_OUTOFMEMORY
;
738 for (i
= 0; i
< iSize
; i
++)
739 bTbuf
[i
] = (dsb
->buffer
[i
* 2] + dsb
->buffer
[(i
* 2) + 1]) / 2;
743 if (dsb
->wfx
.wBitsPerSample
== 16) {
744 iSize
= dsb
->buflen
/ 2;
745 wIbuf
= (LPWORD
) dsb
->buffer
;
747 bIbuf
= (LPBYTE
) dsb
->buffer
;
752 if (primarybuf
->wfx
.wBitsPerSample
== 16) {
753 wObuf
= (LPWORD
) dsb
->ds3db
->buffer
;
754 oSize
= dsb
->ds3db
->buflen
/ 2;
756 bObuf
= (LPBYTE
) dsb
->ds3db
->buffer
;
757 oSize
= dsb
->ds3db
->buflen
;
760 offset
= primarybuf
->wfx
.nSamplesPerSec
/ 100; /* 10ms */
761 if (primarybuf
->wfx
.wBitsPerSample
== 16 && dsb
->wfx
.wBitsPerSample
== 16)
762 for (i
= 0; i
< iSize
; i
++) {
765 temp
+= wIbuf
[i
- offset
] >> 9;
767 temp
+= wIbuf
[i
+ iSize
- offset
] >> 9;
769 wObuf
[(i
* 2) + 1] = temp
;
771 else if (primarybuf
->wfx
.wBitsPerSample
== 8 && dsb
->wfx
.wBitsPerSample
== 8)
772 for (i
= 0; i
< iSize
; i
++) {
775 temp
+= bIbuf
[i
- offset
] >> 5;
777 temp
+= bIbuf
[i
+ iSize
- offset
] >> 5;
779 bObuf
[(i
* 2) + 1] = temp
;
790 /*******************************************************************************
791 * IDirectSound3DListener
794 /* IUnknown methods */
795 static HRESULT WINAPI
IDirectSound3DListenerImpl_QueryInterface(
796 LPDIRECTSOUND3DLISTENER iface
, REFIID riid
, LPVOID
*ppobj
)
798 ICOM_THIS(IDirectSound3DListenerImpl
,iface
);
800 TRACE("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
804 static ULONG WINAPI
IDirectSound3DListenerImpl_AddRef(LPDIRECTSOUND3DLISTENER iface
)
806 ICOM_THIS(IDirectSound3DListenerImpl
,iface
);
811 static ULONG WINAPI
IDirectSound3DListenerImpl_Release(LPDIRECTSOUND3DLISTENER iface
)
814 ICOM_THIS(IDirectSound3DListenerImpl
,iface
);
816 TRACE("(%p) ref was %ld\n", This
, This
->ref
);
818 ulReturn
= --This
->ref
;
820 /* Free all resources */
821 if( ulReturn
== 0 ) {
823 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)This
->dsb
);
824 DeleteCriticalSection(&This
->lock
);
825 HeapFree(GetProcessHeap(),0,This
);
831 /* IDirectSound3DListener methods */
832 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetAllParameter(
833 LPDIRECTSOUND3DLISTENER iface
,
834 LPDS3DLISTENER lpDS3DL
)
840 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetDistanceFactor(
841 LPDIRECTSOUND3DLISTENER iface
,
842 LPD3DVALUE lpfDistanceFactor
)
848 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetDopplerFactor(
849 LPDIRECTSOUND3DLISTENER iface
,
850 LPD3DVALUE lpfDopplerFactor
)
856 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetOrientation(
857 LPDIRECTSOUND3DLISTENER iface
,
858 LPD3DVECTOR lpvOrientFront
,
859 LPD3DVECTOR lpvOrientTop
)
865 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetPosition(
866 LPDIRECTSOUND3DLISTENER iface
,
867 LPD3DVECTOR lpvPosition
)
873 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetRolloffFactor(
874 LPDIRECTSOUND3DLISTENER iface
,
875 LPD3DVALUE lpfRolloffFactor
)
881 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetVelocity(
882 LPDIRECTSOUND3DLISTENER iface
,
883 LPD3DVECTOR lpvVelocity
)
889 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetAllParameters(
890 LPDIRECTSOUND3DLISTENER iface
,
891 LPCDS3DLISTENER lpcDS3DL
,
898 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetDistanceFactor(
899 LPDIRECTSOUND3DLISTENER iface
,
900 D3DVALUE fDistanceFactor
,
907 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetDopplerFactor(
908 LPDIRECTSOUND3DLISTENER iface
,
909 D3DVALUE fDopplerFactor
,
916 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetOrientation(
917 LPDIRECTSOUND3DLISTENER iface
,
918 D3DVALUE xFront
, D3DVALUE yFront
, D3DVALUE zFront
,
919 D3DVALUE xTop
, D3DVALUE yTop
, D3DVALUE zTop
,
926 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetPosition(
927 LPDIRECTSOUND3DLISTENER iface
,
928 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
935 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetRolloffFactor(
936 LPDIRECTSOUND3DLISTENER iface
,
937 D3DVALUE fRolloffFactor
,
944 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetVelocity(
945 LPDIRECTSOUND3DLISTENER iface
,
946 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
953 static HRESULT WINAPI
IDirectSound3DListenerImpl_CommitDeferredSettings(
954 LPDIRECTSOUND3DLISTENER iface
)
961 static ICOM_VTABLE(IDirectSound3DListener
) ds3dlvt
=
963 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
964 /* IUnknown methods */
965 IDirectSound3DListenerImpl_QueryInterface
,
966 IDirectSound3DListenerImpl_AddRef
,
967 IDirectSound3DListenerImpl_Release
,
968 /* IDirectSound3DListener methods */
969 IDirectSound3DListenerImpl_GetAllParameter
,
970 IDirectSound3DListenerImpl_GetDistanceFactor
,
971 IDirectSound3DListenerImpl_GetDopplerFactor
,
972 IDirectSound3DListenerImpl_GetOrientation
,
973 IDirectSound3DListenerImpl_GetPosition
,
974 IDirectSound3DListenerImpl_GetRolloffFactor
,
975 IDirectSound3DListenerImpl_GetVelocity
,
976 IDirectSound3DListenerImpl_SetAllParameters
,
977 IDirectSound3DListenerImpl_SetDistanceFactor
,
978 IDirectSound3DListenerImpl_SetDopplerFactor
,
979 IDirectSound3DListenerImpl_SetOrientation
,
980 IDirectSound3DListenerImpl_SetPosition
,
981 IDirectSound3DListenerImpl_SetRolloffFactor
,
982 IDirectSound3DListenerImpl_SetVelocity
,
983 IDirectSound3DListenerImpl_CommitDeferredSettings
,
986 /*******************************************************************************
989 static HRESULT WINAPI
IDirectSoundNotifyImpl_QueryInterface(
990 LPDIRECTSOUNDNOTIFY iface
,REFIID riid
,LPVOID
*ppobj
992 ICOM_THIS(IDirectSoundNotifyImpl
,iface
);
994 TRACE("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
998 static ULONG WINAPI
IDirectSoundNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface
) {
999 ICOM_THIS(IDirectSoundNotifyImpl
,iface
);
1000 return ++(This
->ref
);
1003 static ULONG WINAPI
IDirectSoundNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface
) {
1004 ICOM_THIS(IDirectSoundNotifyImpl
,iface
);
1006 TRACE("(%p) ref was %ld\n", This
, This
->ref
);
1010 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)This
->dsb
);
1011 HeapFree(GetProcessHeap(),0,This
);
1017 static HRESULT WINAPI
IDirectSoundNotifyImpl_SetNotificationPositions(
1018 LPDIRECTSOUNDNOTIFY iface
,DWORD howmuch
,LPCDSBPOSITIONNOTIFY notify
1020 ICOM_THIS(IDirectSoundNotifyImpl
,iface
);
1023 if (TRACE_ON(dsound
)) {
1024 TRACE("(%p,0x%08lx,%p)\n",This
,howmuch
,notify
);
1025 for (i
=0;i
<howmuch
;i
++)
1026 TRACE("notify at %ld to 0x%08lx\n",
1027 notify
[i
].dwOffset
,(DWORD
)notify
[i
].hEventNotify
);
1029 This
->dsb
->notifies
= HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,This
->dsb
->notifies
,(This
->dsb
->nrofnotifies
+howmuch
)*sizeof(DSBPOSITIONNOTIFY
));
1030 memcpy( This
->dsb
->notifies
+This
->dsb
->nrofnotifies
,
1032 howmuch
*sizeof(DSBPOSITIONNOTIFY
)
1034 This
->dsb
->nrofnotifies
+=howmuch
;
1039 static ICOM_VTABLE(IDirectSoundNotify
) dsnvt
=
1041 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1042 IDirectSoundNotifyImpl_QueryInterface
,
1043 IDirectSoundNotifyImpl_AddRef
,
1044 IDirectSoundNotifyImpl_Release
,
1045 IDirectSoundNotifyImpl_SetNotificationPositions
,
1048 /*******************************************************************************
1049 * IDirectSoundBuffer
1052 static void DSOUND_RecalcVolPan(PDSVOLUMEPAN volpan
)
1056 /* the AmpFactors are expressed in 16.16 fixed point */
1057 volpan
->dwVolAmpFactor
= (ULONG
) (pow(2.0, volpan
->lVolume
/ 600.0) * 65536);
1058 /* FIXME: dwPan{Left|Right}AmpFactor */
1060 /* FIXME: use calculated vol and pan ampfactors */
1061 temp
= (double) (volpan
->lVolume
- (volpan
->lPan
> 0 ? volpan
->lPan
: 0));
1062 volpan
->dwTotalLeftAmpFactor
= (ULONG
) (pow(2.0, temp
/ 600.0) * 65536);
1063 temp
= (double) (volpan
->lVolume
+ (volpan
->lPan
< 0 ? volpan
->lPan
: 0));
1064 volpan
->dwTotalRightAmpFactor
= (ULONG
) (pow(2.0, temp
/ 600.0) * 65536);
1066 TRACE("left = %lx, right = %lx\n", volpan
->dwTotalLeftAmpFactor
, volpan
->dwTotalRightAmpFactor
);
1069 static void DSOUND_RecalcFormat(IDirectSoundBufferImpl
*dsb
)
1073 sw
= dsb
->wfx
.nChannels
* (dsb
->wfx
.wBitsPerSample
/ 8);
1074 if ((dsb
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
) && dsb
->hwbuf
) {
1076 /* let fragment size approximate the timer delay */
1077 fraglen
= (dsb
->freq
* DS_TIME_DEL
/ 1000) * sw
;
1078 /* reduce fragment size until an integer number of them fits in the buffer */
1079 /* (FIXME: this may or may not be a good idea) */
1080 while (dsb
->buflen
% fraglen
) fraglen
-= sw
;
1081 dsb
->dsound
->fraglen
= fraglen
;
1082 TRACE("fraglen=%ld\n", dsb
->dsound
->fraglen
);
1084 /* calculate the 10ms write lead */
1085 dsb
->writelead
= (dsb
->freq
/ 100) * sw
;
1088 static HRESULT
DSOUND_PrimaryOpen(IDirectSoundBufferImpl
*dsb
)
1090 HRESULT err
= DS_OK
;
1092 /* are we using waveOut stuff? */
1096 HRESULT merr
= DS_OK
;
1097 /* Start in pause mode, to allow buffers to get filled */
1098 waveOutPause(dsb
->dsound
->hwo
);
1099 if (dsb
->state
== STATE_PLAYING
) dsb
->state
= STATE_STARTING
;
1100 else if (dsb
->state
== STATE_STOPPING
) dsb
->state
= STATE_STOPPED
;
1101 /* use fragments of 10ms (1/100s) each (which should get us within
1102 * the documented write cursor lead of 10-15ms) */
1103 buflen
= ((dsb
->wfx
.nAvgBytesPerSec
/ 100) & ~3) * DS_HEL_FRAGS
;
1104 TRACE("desired buflen=%ld, old buffer=%p\n", buflen
, dsb
->buffer
);
1105 /* reallocate emulated primary buffer */
1106 newbuf
= (LPBYTE
)HeapReAlloc(GetProcessHeap(),0,dsb
->buffer
,buflen
);
1107 if (newbuf
== NULL
) {
1108 ERR("failed to allocate primary buffer\n");
1109 merr
= DSERR_OUTOFMEMORY
;
1110 /* but the old buffer might still exists and must be re-prepared */
1112 dsb
->buffer
= newbuf
;
1113 dsb
->buflen
= buflen
;
1117 IDirectSoundImpl
*ds
= dsb
->dsound
;
1119 ds
->fraglen
= dsb
->buflen
/ DS_HEL_FRAGS
;
1121 /* prepare fragment headers */
1122 for (c
=0; c
<DS_HEL_FRAGS
; c
++) {
1123 ds
->pwave
[c
]->lpData
= dsb
->buffer
+ c
*ds
->fraglen
;
1124 ds
->pwave
[c
]->dwBufferLength
= ds
->fraglen
;
1125 ds
->pwave
[c
]->dwUser
= (DWORD
)dsb
;
1126 ds
->pwave
[c
]->dwFlags
= 0;
1127 ds
->pwave
[c
]->dwLoops
= 0;
1128 err
= mmErr(waveOutPrepareHeader(ds
->hwo
,ds
->pwave
[c
],sizeof(WAVEHDR
)));
1131 waveOutUnprepareHeader(ds
->hwo
,ds
->pwave
[c
],sizeof(WAVEHDR
));
1139 memset(dsb
->buffer
, (dsb
->wfx
.wBitsPerSample
== 16) ? 0 : 128, dsb
->buflen
);
1140 TRACE("fraglen=%ld\n", ds
->fraglen
);
1141 DSOUND_WaveQueue(dsb
->dsound
, (DWORD
)-1);
1143 if ((err
== DS_OK
) && (merr
!= DS_OK
))
1150 static void DSOUND_PrimaryClose(IDirectSoundBufferImpl
*dsb
)
1152 /* are we using waveOut stuff? */
1155 IDirectSoundImpl
*ds
= dsb
->dsound
;
1157 ds
->pwqueue
= (DWORD
)-1; /* resetting queues */
1158 waveOutReset(ds
->hwo
);
1159 for (c
=0; c
<DS_HEL_FRAGS
; c
++)
1160 waveOutUnprepareHeader(ds
->hwo
, ds
->pwave
[c
], sizeof(WAVEHDR
));
1165 static HRESULT
DSOUND_PrimaryPlay(IDirectSoundBufferImpl
*dsb
)
1167 HRESULT err
= DS_OK
;
1169 err
= IDsDriverBuffer_Play(dsb
->hwbuf
, 0, 0, DSBPLAY_LOOPING
);
1171 err
= mmErr(waveOutRestart(dsb
->dsound
->hwo
));
1175 static HRESULT
DSOUND_PrimaryStop(IDirectSoundBufferImpl
*dsb
)
1177 HRESULT err
= DS_OK
;
1182 err
= IDsDriverBuffer_Stop(dsb
->hwbuf
);
1183 if (err
== DSERR_BUFFERLOST
) {
1184 /* Wine-only: the driver wants us to reopen the device */
1185 /* FIXME: check for errors */
1186 IDsDriverBuffer_Release(primarybuf
->hwbuf
);
1187 waveOutClose(dsb
->dsound
->hwo
);
1188 dsb
->dsound
->hwo
= 0;
1189 waveOutOpen(&(dsb
->dsound
->hwo
), dsb
->dsound
->drvdesc
.dnDevNode
,
1190 &(primarybuf
->wfx
), (DWORD
)DSOUND_callback
, (DWORD
)dsb
->dsound
,
1191 CALLBACK_FUNCTION
| WAVE_DIRECTSOUND
);
1192 err
= IDsDriver_CreateSoundBuffer(dsb
->dsound
->driver
,&(dsb
->wfx
),dsb
->dsbd
.dwFlags
,0,
1193 &(dsb
->buflen
),&(dsb
->buffer
),
1194 (LPVOID
)&(dsb
->hwbuf
));
1198 err
= mmErr(waveOutPause(dsb
->dsound
->hwo
));
1202 /* This sets this format for the <em>Primary Buffer Only</em> */
1203 /* See file:///cdrom/sdk52/docs/worddoc/dsound.doc page 120 */
1204 static HRESULT WINAPI
IDirectSoundBufferImpl_SetFormat(
1205 LPDIRECTSOUNDBUFFER iface
,LPWAVEFORMATEX wfex
1207 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1208 IDirectSoundBufferImpl
** dsb
;
1209 HRESULT err
= DS_OK
;
1212 /* Let's be pedantic! */
1213 if ((wfex
== NULL
) ||
1214 (wfex
->wFormatTag
!= WAVE_FORMAT_PCM
) ||
1215 (wfex
->nChannels
< 1) || (wfex
->nChannels
> 2) ||
1216 (wfex
->nSamplesPerSec
< 1) ||
1217 (wfex
->nBlockAlign
< 1) || (wfex
->nChannels
> 4) ||
1218 ((wfex
->wBitsPerSample
!= 8) && (wfex
->wBitsPerSample
!= 16))) {
1219 TRACE("failed pedantic check!\n");
1220 return DSERR_INVALIDPARAM
;
1224 EnterCriticalSection(&(This
->dsound
->lock
));
1226 if (primarybuf
->wfx
.nSamplesPerSec
!= wfex
->nSamplesPerSec
) {
1227 dsb
= dsound
->buffers
;
1228 for (i
= 0; i
< dsound
->nrofbuffers
; i
++, dsb
++) {
1230 EnterCriticalSection(&((*dsb
)->lock
));
1232 (*dsb
)->freqAdjust
= ((*dsb
)->freq
<< DSOUND_FREQSHIFT
) /
1233 wfex
->nSamplesPerSec
;
1235 LeaveCriticalSection(&((*dsb
)->lock
));
1240 memcpy(&(primarybuf
->wfx
), wfex
, sizeof(primarybuf
->wfx
));
1242 TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld,"
1243 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
1244 wfex
->wFormatTag
, wfex
->nChannels
, wfex
->nSamplesPerSec
,
1245 wfex
->nAvgBytesPerSec
, wfex
->nBlockAlign
,
1246 wfex
->wBitsPerSample
, wfex
->cbSize
);
1248 primarybuf
->wfx
.nAvgBytesPerSec
=
1249 This
->wfx
.nSamplesPerSec
* This
->wfx
.nBlockAlign
;
1251 if (primarybuf
->dsound
->drvdesc
.dwFlags
& DSDDESC_DOMMSYSTEMSETFORMAT
) {
1252 /* FIXME: check for errors */
1253 DSOUND_PrimaryClose(primarybuf
);
1254 waveOutClose(This
->dsound
->hwo
);
1255 This
->dsound
->hwo
= 0;
1256 waveOutOpen(&(This
->dsound
->hwo
), This
->dsound
->drvdesc
.dnDevNode
,
1257 &(primarybuf
->wfx
), (DWORD
)DSOUND_callback
, (DWORD
)This
->dsound
,
1258 CALLBACK_FUNCTION
| WAVE_DIRECTSOUND
);
1259 DSOUND_PrimaryOpen(primarybuf
);
1261 if (primarybuf
->hwbuf
) {
1262 err
= IDsDriverBuffer_SetFormat(primarybuf
->hwbuf
, &(primarybuf
->wfx
));
1263 if (err
== DSERR_BUFFERLOST
) {
1264 /* Wine-only: the driver wants us to recreate the HW buffer */
1265 IDsDriverBuffer_Release(primarybuf
->hwbuf
);
1266 err
= IDsDriver_CreateSoundBuffer(primarybuf
->dsound
->driver
,&(primarybuf
->wfx
),primarybuf
->dsbd
.dwFlags
,0,
1267 &(primarybuf
->buflen
),&(primarybuf
->buffer
),
1268 (LPVOID
)&(primarybuf
->hwbuf
));
1269 if (primarybuf
->state
== STATE_PLAYING
) primarybuf
->state
= STATE_STARTING
;
1270 else if (primarybuf
->state
== STATE_STOPPING
) primarybuf
->state
= STATE_STOPPED
;
1273 DSOUND_RecalcFormat(primarybuf
);
1275 LeaveCriticalSection(&(This
->dsound
->lock
));
1281 static HRESULT WINAPI
IDirectSoundBufferImpl_SetVolume(
1282 LPDIRECTSOUNDBUFFER iface
,LONG vol
1284 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1286 TRACE("(%p,%ld)\n",This
,vol
);
1288 /* I'm not sure if we need this for primary buffer */
1289 if (!(This
->dsbd
.dwFlags
& DSBCAPS_CTRLVOLUME
))
1290 return DSERR_CONTROLUNAVAIL
;
1292 if ((vol
> DSBVOLUME_MAX
) || (vol
< DSBVOLUME_MIN
))
1293 return DSERR_INVALIDPARAM
;
1296 EnterCriticalSection(&(This
->lock
));
1298 This
->volpan
.lVolume
= vol
;
1300 DSOUND_RecalcVolPan(&(This
->volpan
));
1303 IDsDriverBuffer_SetVolumePan(This
->hwbuf
, &(This
->volpan
));
1305 else if (This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
1306 #if 0 /* should we really do this? */
1307 /* the DS volume ranges from 0 (max, 0dB attenuation) to -10000 (min, 100dB attenuation) */
1308 /* the MM volume ranges from 0 to 0xffff in an unspecified logarithmic scale */
1309 WORD cvol
= 0xffff + vol
*6 + vol
/2;
1310 DWORD vol
= cvol
| ((DWORD
)cvol
<< 16)
1311 waveOutSetVolume(This
->dsound
->hwo
, vol
);
1315 LeaveCriticalSection(&(This
->lock
));
1321 static HRESULT WINAPI
IDirectSoundBufferImpl_GetVolume(
1322 LPDIRECTSOUNDBUFFER iface
,LPLONG vol
1324 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1325 TRACE("(%p,%p)\n",This
,vol
);
1328 return DSERR_INVALIDPARAM
;
1330 *vol
= This
->volpan
.lVolume
;
1334 static HRESULT WINAPI
IDirectSoundBufferImpl_SetFrequency(
1335 LPDIRECTSOUNDBUFFER iface
,DWORD freq
1337 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1338 TRACE("(%p,%ld)\n",This
,freq
);
1340 /* You cannot set the frequency of the primary buffer */
1341 if (!(This
->dsbd
.dwFlags
& DSBCAPS_CTRLFREQUENCY
) ||
1342 (This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
))
1343 return DSERR_CONTROLUNAVAIL
;
1345 if (!freq
) freq
= This
->wfx
.nSamplesPerSec
;
1347 if ((freq
< DSBFREQUENCY_MIN
) || (freq
> DSBFREQUENCY_MAX
))
1348 return DSERR_INVALIDPARAM
;
1351 EnterCriticalSection(&(This
->lock
));
1354 This
->freqAdjust
= (freq
<< DSOUND_FREQSHIFT
) / primarybuf
->wfx
.nSamplesPerSec
;
1355 This
->nAvgBytesPerSec
= freq
* This
->wfx
.nBlockAlign
;
1356 DSOUND_RecalcFormat(This
);
1358 LeaveCriticalSection(&(This
->lock
));
1364 static HRESULT WINAPI
IDirectSoundBufferImpl_Play(
1365 LPDIRECTSOUNDBUFFER iface
,DWORD reserved1
,DWORD reserved2
,DWORD flags
1367 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1368 TRACE("(%p,%08lx,%08lx,%08lx)\n",
1369 This
,reserved1
,reserved2
,flags
1373 EnterCriticalSection(&(This
->lock
));
1375 This
->playflags
= flags
;
1376 if (This
->state
== STATE_STOPPED
) {
1377 This
->leadin
= TRUE
;
1378 This
->startpos
= This
->buf_mixpos
;
1379 This
->state
= STATE_STARTING
;
1380 } else if (This
->state
== STATE_STOPPING
)
1381 This
->state
= STATE_PLAYING
;
1382 if (!(This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
) && This
->hwbuf
) {
1383 IDsDriverBuffer_Play(This
->hwbuf
, 0, 0, This
->playflags
);
1384 This
->state
= STATE_PLAYING
;
1387 LeaveCriticalSection(&(This
->lock
));
1393 static HRESULT WINAPI
IDirectSoundBufferImpl_Stop(LPDIRECTSOUNDBUFFER iface
)
1395 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1396 TRACE("(%p)\n",This
);
1399 EnterCriticalSection(&(This
->lock
));
1401 if (This
->state
== STATE_PLAYING
)
1402 This
->state
= STATE_STOPPING
;
1403 else if (This
->state
== STATE_STARTING
)
1404 This
->state
= STATE_STOPPED
;
1405 if (!(This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
) && This
->hwbuf
) {
1406 IDsDriverBuffer_Stop(This
->hwbuf
);
1407 This
->state
= STATE_STOPPED
;
1409 DSOUND_CheckEvent(This
, 0);
1411 LeaveCriticalSection(&(This
->lock
));
1417 static DWORD WINAPI
IDirectSoundBufferImpl_AddRef(LPDIRECTSOUNDBUFFER iface
) {
1418 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1421 TRACE("(%p) ref was %ld, thread is %lx\n",This
, This
->ref
, GetCurrentThreadId());
1423 ref
= InterlockedIncrement(&(This
->ref
));
1425 FIXME("thread-safety alert! AddRef-ing with a zero refcount!\n");
1429 static DWORD WINAPI
IDirectSoundBufferImpl_Release(LPDIRECTSOUNDBUFFER iface
) {
1430 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1434 TRACE("(%p) ref was %ld, thread is %lx\n",This
, This
->ref
, GetCurrentThreadId());
1436 ref
= InterlockedDecrement(&(This
->ref
));
1437 if (ref
) return ref
;
1439 EnterCriticalSection(&(This
->dsound
->lock
));
1440 for (i
=0;i
<This
->dsound
->nrofbuffers
;i
++)
1441 if (This
->dsound
->buffers
[i
] == This
)
1444 if (i
< This
->dsound
->nrofbuffers
) {
1445 /* Put the last buffer of the list in the (now empty) position */
1446 This
->dsound
->buffers
[i
] = This
->dsound
->buffers
[This
->dsound
->nrofbuffers
- 1];
1447 This
->dsound
->nrofbuffers
--;
1448 This
->dsound
->buffers
= HeapReAlloc(GetProcessHeap(),0,This
->dsound
->buffers
,sizeof(LPDIRECTSOUNDBUFFER
)*This
->dsound
->nrofbuffers
);
1449 TRACE("buffer count is now %d\n", This
->dsound
->nrofbuffers
);
1450 IDirectSound_Release((LPDIRECTSOUND
)This
->dsound
);
1452 LeaveCriticalSection(&(This
->dsound
->lock
));
1454 DeleteCriticalSection(&(This
->lock
));
1455 if (This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
)
1456 DSOUND_PrimaryClose(This
);
1458 IDsDriverBuffer_Release(This
->hwbuf
);
1461 IDirectSound3DBuffer_Release((LPDIRECTSOUND3DBUFFER
)This
->ds3db
);
1463 /* this is a duplicate buffer */
1464 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)This
->parent
);
1466 /* this is a toplevel buffer */
1467 HeapFree(GetProcessHeap(),0,This
->buffer
);
1469 HeapFree(GetProcessHeap(),0,This
);
1471 if (This
== primarybuf
)
1477 static DWORD
DSOUND_CalcPlayPosition(IDirectSoundBufferImpl
*This
,
1478 DWORD state
, DWORD pplay
, DWORD pwrite
, DWORD pmix
, DWORD bmix
)
1482 TRACE("primary playpos=%ld, mixpos=%ld\n", pplay
, pmix
);
1483 TRACE("this mixpos=%ld, time=%ld\n", bmix
, GetTickCount());
1485 /* the actual primary play position (pplay) is always behind last mixed (pmix),
1486 * unless the computer is too slow or something */
1487 /* we need to know how far away we are from there */
1488 #if 0 /* we'll never fill the primary entirely */
1489 if (pmix
== pplay
) {
1490 if ((state
== STATE_PLAYING
) || (state
== STATE_STOPPING
)) {
1491 /* wow, the software mixer is really doing well,
1492 * seems the entire primary buffer is filled! */
1493 pmix
+= primarybuf
->buflen
;
1495 /* else: the primary buffer is not playing, so probably empty */
1498 if (pmix
< pplay
) pmix
+= primarybuf
->buflen
; /* wraparound */
1500 /* detect buffer underrun */
1501 if (pwrite
< pplay
) pwrite
+= primarybuf
->buflen
; /* wraparound */
1503 if (pmix
> (DS_SND_QUEUE_MAX
* primarybuf
->dsound
->fraglen
+ pwrite
+ primarybuf
->writelead
)) {
1504 WARN("detected an underrun: primary queue was %ld\n",pmix
);
1507 /* divide the offset by its sample size */
1508 pmix
/= primarybuf
->wfx
.nBlockAlign
;
1509 TRACE("primary back-samples=%ld\n",pmix
);
1510 /* adjust for our frequency */
1511 pmix
= (pmix
* This
->freqAdjust
) >> DSOUND_FREQSHIFT
;
1512 /* multiply by our own sample size */
1513 pmix
*= This
->wfx
.nBlockAlign
;
1514 TRACE("this back-offset=%ld\n", pmix
);
1515 /* subtract from our last mixed position */
1517 while (bplay
< pmix
) bplay
+= This
->buflen
; /* wraparound */
1519 if (This
->leadin
&& ((bplay
< This
->startpos
) || (bplay
> bmix
))) {
1520 /* seems we haven't started playing yet */
1521 TRACE("this still in lead-in phase\n");
1522 bplay
= This
->startpos
;
1524 /* return the result */
1528 static HRESULT WINAPI
IDirectSoundBufferImpl_GetCurrentPosition(
1529 LPDIRECTSOUNDBUFFER iface
,LPDWORD playpos
,LPDWORD writepos
1532 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1533 TRACE("(%p,%p,%p)\n",This
,playpos
,writepos
);
1535 hres
=IDsDriverBuffer_GetPosition(This
->hwbuf
,playpos
,writepos
);
1539 else if (This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
1542 mtime
.wType
= TIME_BYTES
;
1543 waveOutGetPosition(This
->dsound
->hwo
, &mtime
, sizeof(mtime
));
1544 mtime
.u
.cb
= mtime
.u
.cb
% This
->buflen
;
1545 *playpos
= mtime
.u
.cb
;
1548 /* the writepos should only be used by apps with WRITEPRIMARY priority,
1549 * in which case our software mixer is disabled anyway */
1550 *writepos
= (This
->dsound
->pwplay
+ DS_HEL_MARGIN
) * This
->dsound
->fraglen
;
1551 while (*writepos
>= This
->buflen
)
1552 *writepos
-= This
->buflen
;
1555 if (playpos
&& (This
->state
!= STATE_PLAYING
)) {
1556 /* we haven't been merged into the primary buffer (yet) */
1557 *playpos
= This
->buf_mixpos
;
1560 DWORD pplay
, pwrite
, lplay
, splay
, pstate
;
1561 /* let's get this exact; first, recursively call GetPosition on the primary */
1562 EnterCriticalSection(&(primarybuf
->lock
));
1563 IDirectSoundBufferImpl_GetCurrentPosition((LPDIRECTSOUNDBUFFER
)primarybuf
, &pplay
, &pwrite
);
1564 /* detect HEL mode underrun */
1565 pstate
= primarybuf
->state
;
1566 if (!(primarybuf
->hwbuf
|| primarybuf
->dsound
->pwqueue
)) {
1567 TRACE("detected an underrun\n");
1569 if (pstate
== STATE_PLAYING
)
1570 pstate
= STATE_STARTING
;
1571 else if (pstate
== STATE_STOPPING
)
1572 pstate
= STATE_STOPPED
;
1574 /* get data for ourselves while we still have the lock */
1575 pstate
&= This
->state
;
1576 lplay
= This
->primary_mixpos
;
1577 splay
= This
->buf_mixpos
;
1578 if ((This
->dsbd
.dwFlags
& DSBCAPS_GETCURRENTPOSITION2
) || primarybuf
->hwbuf
) {
1579 /* calculate play position using this */
1580 *playpos
= DSOUND_CalcPlayPosition(This
, pstate
, pplay
, pwrite
, lplay
, splay
);
1582 /* (unless the app isn't using GETCURRENTPOSITION2) */
1583 /* don't know exactly how this should be handled...
1584 * the docs says that play cursor is reported as directly
1585 * behind write cursor, hmm... */
1586 /* let's just do what might work for Half-Life */
1588 wp
= (This
->dsound
->pwplay
+ DS_HEL_MARGIN
) * This
->dsound
->fraglen
;
1589 while (wp
>= primarybuf
->buflen
)
1590 wp
-= primarybuf
->buflen
;
1591 *playpos
= DSOUND_CalcPlayPosition(This
, pstate
, wp
, pwrite
, lplay
, splay
);
1593 LeaveCriticalSection(&(primarybuf
->lock
));
1595 if (writepos
) *writepos
= This
->buf_mixpos
;
1598 if (This
->state
!= STATE_STOPPED
)
1599 /* apply the documented 10ms lead to writepos */
1600 *writepos
+= This
->writelead
;
1601 while (*writepos
>= This
->buflen
) *writepos
-= This
->buflen
;
1603 TRACE("playpos = %ld, writepos = %ld (%p, time=%ld)\n", playpos
?*playpos
:0, writepos
?*writepos
:0, This
, GetTickCount());
1607 static HRESULT WINAPI
IDirectSoundBufferImpl_GetStatus(
1608 LPDIRECTSOUNDBUFFER iface
,LPDWORD status
1610 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1611 TRACE("(%p,%p), thread is %lx\n",This
,status
,GetCurrentThreadId());
1614 return DSERR_INVALIDPARAM
;
1617 if ((This
->state
== STATE_STARTING
) || (This
->state
== STATE_PLAYING
)) {
1618 *status
|= DSBSTATUS_PLAYING
;
1619 if (This
->playflags
& DSBPLAY_LOOPING
)
1620 *status
|= DSBSTATUS_LOOPING
;
1623 TRACE("status=%lx\n", *status
);
1628 static HRESULT WINAPI
IDirectSoundBufferImpl_GetFormat(
1629 LPDIRECTSOUNDBUFFER iface
,LPWAVEFORMATEX lpwf
,DWORD wfsize
,LPDWORD wfwritten
1631 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1632 TRACE("(%p,%p,%ld,%p)\n",This
,lpwf
,wfsize
,wfwritten
);
1634 if (wfsize
>sizeof(This
->wfx
))
1635 wfsize
= sizeof(This
->wfx
);
1636 if (lpwf
) { /* NULL is valid */
1637 memcpy(lpwf
,&(This
->wfx
),wfsize
);
1639 *wfwritten
= wfsize
;
1642 *wfwritten
= sizeof(This
->wfx
);
1644 return DSERR_INVALIDPARAM
;
1649 static HRESULT WINAPI
IDirectSoundBufferImpl_Lock(
1650 LPDIRECTSOUNDBUFFER iface
,DWORD writecursor
,DWORD writebytes
,LPVOID lplpaudioptr1
,LPDWORD audiobytes1
,LPVOID lplpaudioptr2
,LPDWORD audiobytes2
,DWORD flags
1652 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1655 TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx) at %ld\n",
1667 if (flags
& DSBLOCK_FROMWRITECURSOR
) {
1669 /* GetCurrentPosition does too much magic to duplicate here */
1670 IDirectSoundBufferImpl_GetCurrentPosition(iface
, NULL
, &writepos
);
1671 writecursor
+= writepos
;
1673 if (flags
& DSBLOCK_ENTIREBUFFER
)
1674 writebytes
= This
->buflen
;
1675 if (writebytes
> This
->buflen
)
1676 writebytes
= This
->buflen
;
1678 assert(audiobytes1
!=audiobytes2
);
1679 assert(lplpaudioptr1
!=lplpaudioptr2
);
1681 if ((writebytes
== This
->buflen
) &&
1682 ((This
->state
== STATE_STARTING
) ||
1683 (This
->state
== STATE_PLAYING
)))
1684 /* some games, like Half-Life, try to be clever (not) and
1685 * keep one secondary buffer, and mix sounds into it itself,
1686 * locking the entire buffer every time... so we can just forget
1687 * about tracking the last-written-to-position... */
1688 This
->probably_valid_to
= (DWORD
)-1;
1690 This
->probably_valid_to
= writecursor
;
1692 if (This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
)
1693 capf
= DSDDESC_DONTNEEDPRIMARYLOCK
;
1695 capf
= DSDDESC_DONTNEEDSECONDARYLOCK
;
1696 if (!(This
->dsound
->drvdesc
.dwFlags
& capf
) && This
->hwbuf
) {
1697 IDsDriverBuffer_Lock(This
->hwbuf
,
1698 lplpaudioptr1
, audiobytes1
,
1699 lplpaudioptr2
, audiobytes2
,
1700 writecursor
, writebytes
,
1705 if (writecursor
+writebytes
<= This
->buflen
) {
1706 *(LPBYTE
*)lplpaudioptr1
= This
->buffer
+writecursor
;
1707 *audiobytes1
= writebytes
;
1709 *(LPBYTE
*)lplpaudioptr2
= NULL
;
1712 TRACE("->%ld.0\n",writebytes
);
1714 *(LPBYTE
*)lplpaudioptr1
= This
->buffer
+writecursor
;
1715 *audiobytes1
= This
->buflen
-writecursor
;
1717 *(LPBYTE
*)lplpaudioptr2
= This
->buffer
;
1719 *audiobytes2
= writebytes
-(This
->buflen
-writecursor
);
1720 TRACE("->%ld.%ld\n",*audiobytes1
,audiobytes2
?*audiobytes2
:0);
1722 /* if the segment between playpos and buf_mixpos is touched,
1723 * we need to cancel some mixing */
1724 if (This
->buf_mixpos
>= This
->playpos
) {
1725 if (This
->buf_mixpos
> writecursor
&&
1726 This
->playpos
<= writecursor
+writebytes
)
1730 if (This
->buf_mixpos
> writecursor
||
1731 This
->playpos
<= writecursor
+writebytes
)
1735 TRACE("locking prebuffered region, ouch\n");
1736 DSOUND_MixCancelAt(This
, writecursor
);
1742 static HRESULT WINAPI
IDirectSoundBufferImpl_SetCurrentPosition(
1743 LPDIRECTSOUNDBUFFER iface
,DWORD newpos
1745 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1746 TRACE("(%p,%ld)\n",This
,newpos
);
1749 EnterCriticalSection(&(This
->lock
));
1751 This
->buf_mixpos
= newpos
;
1753 IDsDriverBuffer_SetPosition(This
->hwbuf
, This
->buf_mixpos
);
1755 LeaveCriticalSection(&(This
->lock
));
1761 static HRESULT WINAPI
IDirectSoundBufferImpl_SetPan(
1762 LPDIRECTSOUNDBUFFER iface
,LONG pan
1764 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1766 TRACE("(%p,%ld)\n",This
,pan
);
1768 if ((pan
> DSBPAN_RIGHT
) || (pan
< DSBPAN_LEFT
))
1769 return DSERR_INVALIDPARAM
;
1771 /* You cannot set the pan of the primary buffer */
1772 /* and you cannot use both pan and 3D controls */
1773 if (!(This
->dsbd
.dwFlags
& DSBCAPS_CTRLPAN
) ||
1774 (This
->dsbd
.dwFlags
& DSBCAPS_CTRL3D
) ||
1775 (This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
))
1776 return DSERR_CONTROLUNAVAIL
;
1779 EnterCriticalSection(&(This
->lock
));
1781 This
->volpan
.lPan
= pan
;
1783 DSOUND_RecalcVolPan(&(This
->volpan
));
1786 IDsDriverBuffer_SetVolumePan(This
->hwbuf
, &(This
->volpan
));
1789 LeaveCriticalSection(&(This
->lock
));
1795 static HRESULT WINAPI
IDirectSoundBufferImpl_GetPan(
1796 LPDIRECTSOUNDBUFFER iface
,LPLONG pan
1798 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1799 TRACE("(%p,%p)\n",This
,pan
);
1802 return DSERR_INVALIDPARAM
;
1804 *pan
= This
->volpan
.lPan
;
1809 static HRESULT WINAPI
IDirectSoundBufferImpl_Unlock(
1810 LPDIRECTSOUNDBUFFER iface
,LPVOID p1
,DWORD x1
,LPVOID p2
,DWORD x2
1812 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1813 DWORD capf
, probably_valid_to
;
1815 TRACE("(%p,%p,%ld,%p,%ld):stub\n", This
,p1
,x1
,p2
,x2
);
1818 /* Preprocess 3D buffers... */
1820 /* This is highly experimental and liable to break things */
1821 if (This
->dsbd
.dwFlags
& DSBCAPS_CTRL3D
)
1822 DSOUND_Create3DBuffer(This
);
1825 if (This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
)
1826 capf
= DSDDESC_DONTNEEDPRIMARYLOCK
;
1828 capf
= DSDDESC_DONTNEEDSECONDARYLOCK
;
1829 if (!(This
->dsound
->drvdesc
.dwFlags
& capf
) && This
->hwbuf
) {
1830 IDsDriverBuffer_Unlock(This
->hwbuf
, p1
, x1
, p2
, x2
);
1833 if (p2
) probably_valid_to
= (((LPBYTE
)p2
)-This
->buffer
) + x2
;
1834 else probably_valid_to
= (((LPBYTE
)p1
)-This
->buffer
) + x1
;
1835 while (probably_valid_to
>= This
->buflen
)
1836 probably_valid_to
-= This
->buflen
;
1837 if ((probably_valid_to
== 0) && ((x1
+x2
) == This
->buflen
) &&
1838 ((This
->state
== STATE_STARTING
) ||
1839 (This
->state
== STATE_PLAYING
)))
1840 /* see IDirectSoundBufferImpl_Lock */
1841 probably_valid_to
= (DWORD
)-1;
1842 This
->probably_valid_to
= probably_valid_to
;
1847 static HRESULT WINAPI
IDirectSoundBufferImpl_Restore(
1848 LPDIRECTSOUNDBUFFER iface
1850 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1851 FIXME("(%p):stub\n",This
);
1855 static HRESULT WINAPI
IDirectSoundBufferImpl_GetFrequency(
1856 LPDIRECTSOUNDBUFFER iface
,LPDWORD freq
1858 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1859 TRACE("(%p,%p)\n",This
,freq
);
1862 return DSERR_INVALIDPARAM
;
1865 TRACE("-> %ld\n", *freq
);
1870 static HRESULT WINAPI
IDirectSoundBufferImpl_Initialize(
1871 LPDIRECTSOUNDBUFFER iface
,LPDIRECTSOUND dsound
,LPDSBUFFERDESC dbsd
1873 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1874 FIXME("(%p,%p,%p):stub\n",This
,dsound
,dbsd
);
1875 DPRINTF("Re-Init!!!\n");
1876 return DSERR_ALREADYINITIALIZED
;
1879 static HRESULT WINAPI
IDirectSoundBufferImpl_GetCaps(
1880 LPDIRECTSOUNDBUFFER iface
,LPDSBCAPS caps
1882 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1883 TRACE("(%p)->(%p)\n",This
,caps
);
1886 return DSERR_INVALIDPARAM
;
1888 /* I think we should check this value, not set it. See */
1889 /* Inside DirectX, p215. That should apply here, too. */
1890 caps
->dwSize
= sizeof(*caps
);
1892 caps
->dwFlags
= This
->dsbd
.dwFlags
;
1893 if (This
->hwbuf
) caps
->dwFlags
|= DSBCAPS_LOCHARDWARE
;
1894 else caps
->dwFlags
|= DSBCAPS_LOCSOFTWARE
;
1896 caps
->dwBufferBytes
= This
->buflen
;
1898 /* This value represents the speed of the "unlock" command.
1899 As unlock is quite fast (it does not do anything), I put
1900 4096 ko/s = 4 Mo / s */
1901 /* FIXME: hwbuf speed */
1902 caps
->dwUnlockTransferRate
= 4096;
1903 caps
->dwPlayCpuOverhead
= 0;
1908 static HRESULT WINAPI
IDirectSoundBufferImpl_QueryInterface(
1909 LPDIRECTSOUNDBUFFER iface
,REFIID riid
,LPVOID
*ppobj
1911 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1913 TRACE("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
1915 if ( IsEqualGUID( &IID_IDirectSoundNotify
, riid
) ) {
1916 IDirectSoundNotifyImpl
*dsn
;
1918 dsn
= (IDirectSoundNotifyImpl
*)HeapAlloc(GetProcessHeap(),0,sizeof(*dsn
));
1921 IDirectSoundBuffer_AddRef(iface
);
1922 ICOM_VTBL(dsn
) = &dsnvt
;
1923 *ppobj
= (LPVOID
)dsn
;
1928 if ( IsEqualGUID( &IID_IDirectSound3DBuffer
, riid
) ) {
1929 IDirectSound3DBufferImpl
*ds3db
;
1931 *ppobj
= This
->ds3db
;
1933 IDirectSound3DBuffer_AddRef((LPDIRECTSOUND3DBUFFER
)This
->ds3db
);
1937 ds3db
= (IDirectSound3DBufferImpl
*)HeapAlloc(GetProcessHeap(),
1941 ICOM_VTBL(ds3db
) = &ds3dbvt
;
1942 InitializeCriticalSection(&ds3db
->lock
);
1944 IDirectSoundBuffer_AddRef(iface
);
1946 ds3db
->ds3db
.dwSize
= sizeof(DS3DBUFFER
);
1947 ds3db
->ds3db
.vPosition
.u1
.x
= 0.0;
1948 ds3db
->ds3db
.vPosition
.u2
.y
= 0.0;
1949 ds3db
->ds3db
.vPosition
.u3
.z
= 0.0;
1950 ds3db
->ds3db
.vVelocity
.u1
.x
= 0.0;
1951 ds3db
->ds3db
.vVelocity
.u2
.y
= 0.0;
1952 ds3db
->ds3db
.vVelocity
.u3
.z
= 0.0;
1953 ds3db
->ds3db
.dwInsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
1954 ds3db
->ds3db
.dwOutsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
1955 ds3db
->ds3db
.vConeOrientation
.u1
.x
= 0.0;
1956 ds3db
->ds3db
.vConeOrientation
.u2
.y
= 0.0;
1957 ds3db
->ds3db
.vConeOrientation
.u3
.z
= 0.0;
1958 ds3db
->ds3db
.lConeOutsideVolume
= DS3D_DEFAULTCONEOUTSIDEVOLUME
; ds3db
->ds3db
.flMinDistance
= DS3D_DEFAULTMINDISTANCE
;
1959 ds3db
->ds3db
.flMaxDistance
= DS3D_DEFAULTMAXDISTANCE
;
1960 ds3db
->ds3db
.dwMode
= DS3DMODE_NORMAL
;
1961 ds3db
->buflen
= (This
->buflen
* primarybuf
->wfx
.nBlockAlign
) /
1962 This
->wfx
.nBlockAlign
;
1963 ds3db
->buffer
= HeapAlloc(GetProcessHeap(), 0, ds3db
->buflen
);
1964 if (ds3db
->buffer
== NULL
) {
1966 ds3db
->ds3db
.dwMode
= DS3DMODE_DISABLE
;
1969 ds3db
->iks
= (IKsPropertySetImpl
*)HeapAlloc(GetProcessHeap(),0,sizeof(*(ds3db
->iks
)));
1970 ds3db
->iks
->ref
= 1;
1971 ds3db
->iks
->ds3db
= ds3db
;
1972 ICOM_VTBL(ds3db
->iks
) = &iksvt
;
1977 if ( IsEqualGUID( &IID_IDirectSound3DBuffer
, riid
) ) {
1978 FIXME("%s: I know about this GUID, but don't support it yet\n",
1979 debugstr_guid( riid
));
1986 if ( IsEqualGUID( &IID_IDirectSound3DListener
, riid
) ) {
1987 IDirectSound3DListenerImpl
* dsl
;
1989 if (This
->dsound
->listener
) {
1990 *ppobj
= This
->dsound
->listener
;
1991 IDirectSound3DListener_AddRef((LPDIRECTSOUND3DLISTENER
)This
->dsound
->listener
);
1995 dsl
= (IDirectSound3DListenerImpl
*)HeapAlloc(GetProcessHeap(),0,sizeof(*dsl
));
1997 ICOM_VTBL(dsl
) = &ds3dlvt
;
1998 *ppobj
= (LPVOID
)dsl
;
2000 dsl
->ds3dl
.dwSize
= sizeof(DS3DLISTENER
);
2001 dsl
->ds3dl
.vPosition
.u1
.x
= 0.0;
2002 dsl
->ds3dl
.vPosition
.u2
.y
= 0.0;
2003 dsl
->ds3dl
.vPosition
.u3
.z
= 0.0;
2004 dsl
->ds3dl
.vVelocity
.u1
.x
= 0.0;
2005 dsl
->ds3dl
.vVelocity
.u2
.y
= 0.0;
2006 dsl
->ds3dl
.vVelocity
.u3
.z
= 0.0;
2007 dsl
->ds3dl
.vOrientFront
.u1
.x
= 0.0;
2008 dsl
->ds3dl
.vOrientFront
.u2
.y
= 0.0;
2009 dsl
->ds3dl
.vOrientFront
.u3
.z
= 1.0;
2010 dsl
->ds3dl
.vOrientTop
.u1
.x
= 0.0;
2011 dsl
->ds3dl
.vOrientTop
.u2
.y
= 1.0;
2012 dsl
->ds3dl
.vOrientTop
.u3
.z
= 0.0;
2013 dsl
->ds3dl
.flDistanceFactor
= DS3D_DEFAULTDISTANCEFACTOR
;
2014 dsl
->ds3dl
.flRolloffFactor
= DS3D_DEFAULTROLLOFFFACTOR
;
2016 InitializeCriticalSection(&dsl
->lock
);
2019 IDirectSoundBuffer_AddRef(iface
);
2021 This
->dsound
->listener
= dsl
;
2022 IDirectSound3DListener_AddRef((LPDIRECTSOUND3DLISTENER
)dsl
);
2027 if ( IsEqualGUID( &IID_IDirectSound3DListener
, riid
) ) {
2028 FIXME("%s: I know about this GUID, but don't support it yet\n",
2029 debugstr_guid( riid
));
2035 FIXME( "Unknown GUID %s\n", debugstr_guid( riid
) );
2042 static ICOM_VTABLE(IDirectSoundBuffer
) dsbvt
=
2044 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
2045 IDirectSoundBufferImpl_QueryInterface
,
2046 IDirectSoundBufferImpl_AddRef
,
2047 IDirectSoundBufferImpl_Release
,
2048 IDirectSoundBufferImpl_GetCaps
,
2049 IDirectSoundBufferImpl_GetCurrentPosition
,
2050 IDirectSoundBufferImpl_GetFormat
,
2051 IDirectSoundBufferImpl_GetVolume
,
2052 IDirectSoundBufferImpl_GetPan
,
2053 IDirectSoundBufferImpl_GetFrequency
,
2054 IDirectSoundBufferImpl_GetStatus
,
2055 IDirectSoundBufferImpl_Initialize
,
2056 IDirectSoundBufferImpl_Lock
,
2057 IDirectSoundBufferImpl_Play
,
2058 IDirectSoundBufferImpl_SetCurrentPosition
,
2059 IDirectSoundBufferImpl_SetFormat
,
2060 IDirectSoundBufferImpl_SetVolume
,
2061 IDirectSoundBufferImpl_SetPan
,
2062 IDirectSoundBufferImpl_SetFrequency
,
2063 IDirectSoundBufferImpl_Stop
,
2064 IDirectSoundBufferImpl_Unlock
,
2065 IDirectSoundBufferImpl_Restore
2068 /*******************************************************************************
2072 static HRESULT WINAPI
IDirectSoundImpl_SetCooperativeLevel(
2073 LPDIRECTSOUND iface
,HWND hwnd
,DWORD level
2075 ICOM_THIS(IDirectSoundImpl
,iface
);
2077 FIXME("(%p,%08lx,%ld):stub\n",This
,(DWORD
)hwnd
,level
);
2079 This
->priolevel
= level
;
2084 static HRESULT WINAPI
IDirectSoundImpl_CreateSoundBuffer(
2085 LPDIRECTSOUND iface
,LPDSBUFFERDESC dsbd
,LPLPDIRECTSOUNDBUFFER ppdsb
,LPUNKNOWN lpunk
2087 ICOM_THIS(IDirectSoundImpl
,iface
);
2088 IDirectSoundBufferImpl
** ippdsb
=(IDirectSoundBufferImpl
**)ppdsb
;
2089 LPWAVEFORMATEX wfex
;
2090 HRESULT err
= DS_OK
;
2092 TRACE("(%p,%p,%p,%p)\n",This
,dsbd
,ippdsb
,lpunk
);
2094 if ((This
== NULL
) || (dsbd
== NULL
) || (ippdsb
== NULL
))
2095 return DSERR_INVALIDPARAM
;
2097 if (TRACE_ON(dsound
)) {
2098 TRACE("(structsize=%ld)\n",dsbd
->dwSize
);
2099 TRACE("(flags=0x%08lx:\n",dsbd
->dwFlags
);
2100 _dump_DSBCAPS(dsbd
->dwFlags
);
2102 TRACE("(bufferbytes=%ld)\n",dsbd
->dwBufferBytes
);
2103 TRACE("(lpwfxFormat=%p)\n",dsbd
->lpwfxFormat
);
2106 wfex
= dsbd
->lpwfxFormat
;
2109 TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld,"
2110 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
2111 wfex
->wFormatTag
, wfex
->nChannels
, wfex
->nSamplesPerSec
,
2112 wfex
->nAvgBytesPerSec
, wfex
->nBlockAlign
,
2113 wfex
->wBitsPerSample
, wfex
->cbSize
);
2115 if (dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
2117 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER
)primarybuf
);
2118 *ippdsb
= primarybuf
;
2119 primarybuf
->dsbd
.dwFlags
= dsbd
->dwFlags
;
2121 } /* Else create primary buffer */
2123 if (dsbd
->dwBufferBytes
< DSBSIZE_MIN
|| dsbd
->dwBufferBytes
> DSBSIZE_MAX
) {
2124 ERR("invalid sound buffer size %ld\n", dsbd
->dwBufferBytes
);
2125 return DSERR_INVALIDPARAM
; /* FIXME: which error? */
2129 *ippdsb
= (IDirectSoundBufferImpl
*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDirectSoundBufferImpl
));
2130 if (*ippdsb
== NULL
)
2131 return DSERR_OUTOFMEMORY
;
2132 ICOM_VTBL(*ippdsb
) = &dsbvt
;
2134 (*ippdsb
)->dsound
= This
;
2135 (*ippdsb
)->parent
= NULL
;
2136 (*ippdsb
)->buffer
= NULL
;
2138 memcpy(&((*ippdsb
)->dsbd
),dsbd
,sizeof(*dsbd
));
2139 if (dsbd
->lpwfxFormat
)
2140 memcpy(&((*ippdsb
)->wfx
), dsbd
->lpwfxFormat
, sizeof((*ippdsb
)->wfx
));
2142 TRACE("Created buffer at %p\n", *ippdsb
);
2144 if (dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
2145 (*ippdsb
)->buflen
= dsound
->wfx
.nAvgBytesPerSec
;
2146 (*ippdsb
)->freq
= dsound
->wfx
.nSamplesPerSec
;
2148 /* FIXME: verify that hardware capabilities (DSCAPS_PRIMARY flags) match */
2151 err
= IDsDriver_CreateSoundBuffer(This
->driver
,wfex
,dsbd
->dwFlags
,0,
2152 &((*ippdsb
)->buflen
),&((*ippdsb
)->buffer
),
2153 (LPVOID
*)&((*ippdsb
)->hwbuf
));
2156 err
= DSOUND_PrimaryOpen(*ippdsb
);
2161 (*ippdsb
)->buflen
= dsbd
->dwBufferBytes
;
2162 (*ippdsb
)->freq
= dsbd
->lpwfxFormat
->nSamplesPerSec
;
2164 /* Check necessary hardware mixing capabilities */
2165 if (wfex
->nChannels
==2) capf
|= DSCAPS_SECONDARYSTEREO
;
2166 else capf
|= DSCAPS_SECONDARYMONO
;
2167 if (wfex
->wBitsPerSample
==16) capf
|= DSCAPS_SECONDARY16BIT
;
2168 else capf
|= DSCAPS_SECONDARY8BIT
;
2169 use_hw
= (This
->drvcaps
.dwFlags
& capf
) == capf
;
2171 /* FIXME: check hardware sample rate mixing capabilities */
2172 /* FIXME: check app hints for software/hardware buffer (STATIC, LOCHARDWARE, etc) */
2173 /* FIXME: check whether any hardware buffers are left */
2174 /* FIXME: handle DSDHEAP_CREATEHEAP for hardware buffers */
2176 /* Allocate system memory if applicable */
2177 if ((This
->drvdesc
.dwFlags
& DSDDESC_USESYSTEMMEMORY
) || !use_hw
) {
2178 (*ippdsb
)->buffer
= (LPBYTE
)HeapAlloc(GetProcessHeap(),0,(*ippdsb
)->buflen
);
2179 if ((*ippdsb
)->buffer
== NULL
)
2180 err
= DSERR_OUTOFMEMORY
;
2183 /* Allocate the hardware buffer */
2184 if (use_hw
&& (err
== DS_OK
)) {
2185 err
= IDsDriver_CreateSoundBuffer(This
->driver
,wfex
,dsbd
->dwFlags
,0,
2186 &((*ippdsb
)->buflen
),&((*ippdsb
)->buffer
),
2187 (LPVOID
*)&((*ippdsb
)->hwbuf
));
2192 if ((*ippdsb
)->buffer
)
2193 HeapFree(GetProcessHeap(),0,(*ippdsb
)->buffer
);
2194 HeapFree(GetProcessHeap(),0,(*ippdsb
));
2198 /* calculate fragment size and write lead */
2199 DSOUND_RecalcFormat(*ippdsb
);
2201 /* It's not necessary to initialize values to zero since */
2202 /* we allocated this structure with HEAP_ZERO_MEMORY... */
2203 (*ippdsb
)->playpos
= 0;
2204 (*ippdsb
)->buf_mixpos
= 0;
2205 (*ippdsb
)->state
= STATE_STOPPED
;
2206 DSOUND_RecalcVolPan(&((*ippdsb
)->volpan
));
2208 if (!(dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
)) {
2209 (*ippdsb
)->freqAdjust
= ((*ippdsb
)->freq
<< DSOUND_FREQSHIFT
) /
2210 primarybuf
->wfx
.nSamplesPerSec
;
2211 (*ippdsb
)->nAvgBytesPerSec
= (*ippdsb
)->freq
*
2212 dsbd
->lpwfxFormat
->nBlockAlign
;
2215 EnterCriticalSection(&(This
->lock
));
2216 /* register buffer */
2217 if (!(dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
)) {
2218 IDirectSoundBufferImpl
**newbuffers
= (IDirectSoundBufferImpl
**)HeapReAlloc(GetProcessHeap(),0,This
->buffers
,sizeof(IDirectSoundBufferImpl
*)*(This
->nrofbuffers
+1));
2220 This
->buffers
= newbuffers
;
2221 This
->buffers
[This
->nrofbuffers
] = *ippdsb
;
2222 This
->nrofbuffers
++;
2223 TRACE("buffer count is now %d\n", This
->nrofbuffers
);
2225 ERR("out of memory for buffer list! Current buffer count is %d\n", This
->nrofbuffers
);
2226 err
= DSERR_OUTOFMEMORY
;
2229 LeaveCriticalSection(&(This
->lock
));
2231 IDirectSound_AddRef(iface
);
2233 InitializeCriticalSection(&((*ippdsb
)->lock
));
2237 IDirectSoundBuffer_Release(*ppdsb
);
2243 if (dsbd
->dwFlags
& DSBCAPS_CTRL3D
) {
2244 IDirectSound3DBufferImpl
*ds3db
;
2246 ds3db
= (IDirectSound3DBufferImpl
*)HeapAlloc(GetProcessHeap(),
2248 ICOM_VTBL(ds3db
) = &ds3dbvt
;
2250 (*ippdsb
)->ds3db
= ds3db
;
2252 ds3db
->dsb
= (*ippdsb
);
2253 IDirectSoundBufferImpl_AddRef((LPDIRECTSOUNDBUFFER
)(*ippdsb
));
2255 InitializeCriticalSection(&ds3db
->lock
);
2257 ds3db
->ds3db
.dwSize
= sizeof(DS3DBUFFER
);
2258 ds3db
->ds3db
.vPosition
.u1
.x
= 0.0;
2259 ds3db
->ds3db
.vPosition
.u2
.y
= 0.0;
2260 ds3db
->ds3db
.vPosition
.u3
.z
= 0.0;
2261 ds3db
->ds3db
.vVelocity
.u1
.x
= 0.0;
2262 ds3db
->ds3db
.vVelocity
.u2
.y
= 0.0;
2263 ds3db
->ds3db
.vVelocity
.u3
.z
= 0.0;
2264 ds3db
->ds3db
.dwInsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
2265 ds3db
->ds3db
.dwOutsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
2266 ds3db
->ds3db
.vConeOrientation
.u1
.x
= 0.0;
2267 ds3db
->ds3db
.vConeOrientation
.u2
.y
= 0.0;
2268 ds3db
->ds3db
.vConeOrientation
.u3
.z
= 0.0;
2269 ds3db
->ds3db
.lConeOutsideVolume
= DS3D_DEFAULTCONEOUTSIDEVOLUME
;
2270 ds3db
->ds3db
.flMinDistance
= DS3D_DEFAULTMINDISTANCE
;
2271 ds3db
->ds3db
.flMaxDistance
= DS3D_DEFAULTMAXDISTANCE
;
2272 ds3db
->ds3db
.dwMode
= DS3DMODE_NORMAL
;
2273 ds3db
->buflen
= ((*ippdsb
)->buflen
* primarybuf
->wfx
.nBlockAlign
) /
2274 (*ippdsb
)->wfx
.nBlockAlign
;
2275 ds3db
->buffer
= HeapAlloc(GetProcessHeap(), 0, ds3db
->buflen
);
2276 if (ds3db
->buffer
== NULL
) {
2278 ds3db
->ds3db
.dwMode
= DS3DMODE_DISABLE
;
2280 ds3db
->iks
= (IKsPropertySetImpl
*)HeapAlloc(GetProcessHeap(),0,sizeof(*(ds3db
->iks
)));
2281 ds3db
->iks
->ref
= 1;
2282 ds3db
->iks
->ds3db
= ds3db
;
2283 ICOM_VTBL(ds3db
->iks
) = &iksvt
;
2290 static HRESULT WINAPI
IDirectSoundImpl_DuplicateSoundBuffer(
2291 LPDIRECTSOUND iface
,LPDIRECTSOUNDBUFFER pdsb
,LPLPDIRECTSOUNDBUFFER ppdsb
2293 ICOM_THIS(IDirectSoundImpl
,iface
);
2294 IDirectSoundBufferImpl
* ipdsb
=(IDirectSoundBufferImpl
*)pdsb
;
2295 IDirectSoundBufferImpl
** ippdsb
=(IDirectSoundBufferImpl
**)ppdsb
;
2296 TRACE("(%p,%p,%p)\n",This
,ipdsb
,ippdsb
);
2299 FIXME("need to duplicate hardware buffer\n");
2302 *ippdsb
= (IDirectSoundBufferImpl
*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDirectSoundBufferImpl
));
2304 IDirectSoundBuffer_AddRef(pdsb
);
2305 memcpy(*ippdsb
, ipdsb
, sizeof(IDirectSoundBufferImpl
));
2307 (*ippdsb
)->state
= STATE_STOPPED
;
2308 (*ippdsb
)->playpos
= 0;
2309 (*ippdsb
)->buf_mixpos
= 0;
2310 (*ippdsb
)->dsound
= This
;
2311 (*ippdsb
)->parent
= ipdsb
;
2312 memcpy(&((*ippdsb
)->wfx
), &(ipdsb
->wfx
), sizeof((*ippdsb
)->wfx
));
2313 InitializeCriticalSection(&(*ippdsb
)->lock
);
2314 /* register buffer */
2315 EnterCriticalSection(&(This
->lock
));
2317 IDirectSoundBufferImpl
**newbuffers
= (IDirectSoundBufferImpl
**)HeapReAlloc(GetProcessHeap(),0,This
->buffers
,sizeof(IDirectSoundBufferImpl
**)*(This
->nrofbuffers
+1));
2319 This
->buffers
= newbuffers
;
2320 This
->buffers
[This
->nrofbuffers
] = *ippdsb
;
2321 This
->nrofbuffers
++;
2322 TRACE("buffer count is now %d\n", This
->nrofbuffers
);
2324 ERR("out of memory for buffer list! Current buffer count is %d\n", This
->nrofbuffers
);
2325 /* FIXME: release buffer */
2328 LeaveCriticalSection(&(This
->lock
));
2329 IDirectSound_AddRef(iface
);
2334 static HRESULT WINAPI
IDirectSoundImpl_GetCaps(LPDIRECTSOUND iface
,LPDSCAPS caps
) {
2335 ICOM_THIS(IDirectSoundImpl
,iface
);
2336 TRACE("(%p,%p)\n",This
,caps
);
2337 TRACE("(flags=0x%08lx)\n",caps
->dwFlags
);
2340 return DSERR_INVALIDPARAM
;
2342 /* We should check this value, not set it. See Inside DirectX, p215. */
2343 caps
->dwSize
= sizeof(*caps
);
2345 caps
->dwFlags
= This
->drvcaps
.dwFlags
;
2347 /* FIXME: copy caps from This->drvcaps */
2348 caps
->dwMinSecondarySampleRate
= DSBFREQUENCY_MIN
;
2349 caps
->dwMaxSecondarySampleRate
= DSBFREQUENCY_MAX
;
2351 caps
->dwPrimaryBuffers
= 1;
2353 caps
->dwMaxHwMixingAllBuffers
= 0;
2354 caps
->dwMaxHwMixingStaticBuffers
= 0;
2355 caps
->dwMaxHwMixingStreamingBuffers
= 0;
2357 caps
->dwFreeHwMixingAllBuffers
= 0;
2358 caps
->dwFreeHwMixingStaticBuffers
= 0;
2359 caps
->dwFreeHwMixingStreamingBuffers
= 0;
2361 caps
->dwMaxHw3DAllBuffers
= 0;
2362 caps
->dwMaxHw3DStaticBuffers
= 0;
2363 caps
->dwMaxHw3DStreamingBuffers
= 0;
2365 caps
->dwFreeHw3DAllBuffers
= 0;
2366 caps
->dwFreeHw3DStaticBuffers
= 0;
2367 caps
->dwFreeHw3DStreamingBuffers
= 0;
2369 caps
->dwTotalHwMemBytes
= 0;
2371 caps
->dwFreeHwMemBytes
= 0;
2373 caps
->dwMaxContigFreeHwMemBytes
= 0;
2375 caps
->dwUnlockTransferRateHwBuffers
= 4096; /* But we have none... */
2377 caps
->dwPlayCpuOverheadSwBuffers
= 1; /* 1% */
2382 static ULONG WINAPI
IDirectSoundImpl_AddRef(LPDIRECTSOUND iface
) {
2383 ICOM_THIS(IDirectSoundImpl
,iface
);
2384 return ++(This
->ref
);
2387 static ULONG WINAPI
IDirectSoundImpl_Release(LPDIRECTSOUND iface
) {
2388 ICOM_THIS(IDirectSoundImpl
,iface
);
2389 TRACE("(%p), ref was %ld\n",This
,This
->ref
);
2390 if (!--(This
->ref
)) {
2393 timeKillEvent(This
->timerID
);
2394 timeEndPeriod(DS_TIME_RES
);
2397 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)primarybuf
);
2399 if (This
->buffers
) {
2400 for( i
=0;i
<This
->nrofbuffers
;i
++)
2401 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)This
->buffers
[i
]);
2405 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)This
->primary
);
2407 DeleteCriticalSection(&This
->lock
);
2409 IDsDriver_Close(This
->driver
);
2412 for (c
=0; c
<DS_HEL_FRAGS
; c
++)
2413 HeapFree(GetProcessHeap(),0,This
->pwave
[c
]);
2415 if (This
->drvdesc
.dwFlags
& DSDDESC_DOMMSYSTEMOPEN
) {
2416 waveOutClose(This
->hwo
);
2419 IDsDriver_Release(This
->driver
);
2421 HeapFree(GetProcessHeap(),0,This
);
2428 static HRESULT WINAPI
IDirectSoundImpl_SetSpeakerConfig(
2429 LPDIRECTSOUND iface
,DWORD config
2431 ICOM_THIS(IDirectSoundImpl
,iface
);
2432 FIXME("(%p,0x%08lx):stub\n",This
,config
);
2436 static HRESULT WINAPI
IDirectSoundImpl_QueryInterface(
2437 LPDIRECTSOUND iface
,REFIID riid
,LPVOID
*ppobj
2439 ICOM_THIS(IDirectSoundImpl
,iface
);
2441 if ( IsEqualGUID( &IID_IDirectSound3DListener
, riid
) ) {
2443 if (This
->listener
) {
2444 *ppobj
= This
->listener
;
2445 IDirectSound3DListener_AddRef((LPDIRECTSOUND3DLISTENER
)This
->listener
);
2449 This
->listener
= (IDirectSound3DListenerImpl
*)HeapAlloc(
2450 GetProcessHeap(), 0, sizeof(*(This
->listener
)));
2451 This
->listener
->ref
= 1;
2452 ICOM_VTBL(This
->listener
) = &ds3dlvt
;
2453 *ppobj
= (LPVOID
)This
->listener
;
2454 IDirectSound3DListener_AddRef((LPDIRECTSOUND3DLISTENER
)*ppobj
);
2456 This
->listener
->dsb
= NULL
;
2458 This
->listener
->ds3dl
.dwSize
= sizeof(DS3DLISTENER
);
2459 This
->listener
->ds3dl
.vPosition
.u1
.x
= 0.0;
2460 This
->listener
->ds3dl
.vPosition
.u2
.y
= 0.0;
2461 This
->listener
->ds3dl
.vPosition
.u3
.z
= 0.0;
2462 This
->listener
->ds3dl
.vVelocity
.u1
.x
= 0.0;
2463 This
->listener
->ds3dl
.vVelocity
.u2
.y
= 0.0;
2464 This
->listener
->ds3dl
.vVelocity
.u3
.z
= 0.0;
2465 This
->listener
->ds3dl
.vOrientFront
.u1
.x
= 0.0;
2466 This
->listener
->ds3dl
.vOrientFront
.u2
.y
= 0.0;
2467 This
->listener
->ds3dl
.vOrientFront
.u3
.z
= 1.0;
2468 This
->listener
->ds3dl
.vOrientTop
.u1
.x
= 0.0;
2469 This
->listener
->ds3dl
.vOrientTop
.u2
.y
= 1.0;
2470 This
->listener
->ds3dl
.vOrientTop
.u3
.z
= 0.0;
2471 This
->listener
->ds3dl
.flDistanceFactor
= DS3D_DEFAULTDISTANCEFACTOR
;
2472 This
->listener
->ds3dl
.flRolloffFactor
= DS3D_DEFAULTROLLOFFFACTOR
;
2473 This
->listener
->ds3dl
.flDopplerFactor
= DS3D_DEFAULTDOPPLERFACTOR
;
2475 InitializeCriticalSection(&This
->listener
->lock
);
2480 FIXME("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
2484 static HRESULT WINAPI
IDirectSoundImpl_Compact(
2485 LPDIRECTSOUND iface
)
2487 ICOM_THIS(IDirectSoundImpl
,iface
);
2488 TRACE("(%p)\n", This
);
2492 static HRESULT WINAPI
IDirectSoundImpl_GetSpeakerConfig(
2493 LPDIRECTSOUND iface
,
2494 LPDWORD lpdwSpeakerConfig
)
2496 ICOM_THIS(IDirectSoundImpl
,iface
);
2497 TRACE("(%p, %p)\n", This
, lpdwSpeakerConfig
);
2498 *lpdwSpeakerConfig
= DSSPEAKER_STEREO
| (DSSPEAKER_GEOMETRY_NARROW
<< 16);
2502 static HRESULT WINAPI
IDirectSoundImpl_Initialize(
2503 LPDIRECTSOUND iface
,
2506 ICOM_THIS(IDirectSoundImpl
,iface
);
2507 TRACE("(%p, %p)\n", This
, lpcGuid
);
2511 static ICOM_VTABLE(IDirectSound
) dsvt
=
2513 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
2514 IDirectSoundImpl_QueryInterface
,
2515 IDirectSoundImpl_AddRef
,
2516 IDirectSoundImpl_Release
,
2517 IDirectSoundImpl_CreateSoundBuffer
,
2518 IDirectSoundImpl_GetCaps
,
2519 IDirectSoundImpl_DuplicateSoundBuffer
,
2520 IDirectSoundImpl_SetCooperativeLevel
,
2521 IDirectSoundImpl_Compact
,
2522 IDirectSoundImpl_GetSpeakerConfig
,
2523 IDirectSoundImpl_SetSpeakerConfig
,
2524 IDirectSoundImpl_Initialize
2528 static void DSOUND_CheckEvent(IDirectSoundBufferImpl
*dsb
, int len
)
2532 LPDSBPOSITIONNOTIFY event
;
2534 if (dsb
->nrofnotifies
== 0)
2537 TRACE("(%p) buflen = %ld, playpos = %ld, len = %d\n",
2538 dsb
, dsb
->buflen
, dsb
->playpos
, len
);
2539 for (i
= 0; i
< dsb
->nrofnotifies
; i
++) {
2540 event
= dsb
->notifies
+ i
;
2541 offset
= event
->dwOffset
;
2542 TRACE("checking %d, position %ld, event = %d\n",
2543 i
, offset
, event
->hEventNotify
);
2544 /* DSBPN_OFFSETSTOP has to be the last element. So this is */
2545 /* OK. [Inside DirectX, p274] */
2547 /* This also means we can't sort the entries by offset, */
2548 /* because DSBPN_OFFSETSTOP == -1 */
2549 if (offset
== DSBPN_OFFSETSTOP
) {
2550 if (dsb
->state
== STATE_STOPPED
) {
2551 SetEvent(event
->hEventNotify
);
2552 TRACE("signalled event %d (%d)\n", event
->hEventNotify
, i
);
2557 if ((dsb
->playpos
+ len
) >= dsb
->buflen
) {
2558 if ((offset
< ((dsb
->playpos
+ len
) % dsb
->buflen
)) ||
2559 (offset
>= dsb
->playpos
)) {
2560 TRACE("signalled event %d (%d)\n", event
->hEventNotify
, i
);
2561 SetEvent(event
->hEventNotify
);
2564 if ((offset
>= dsb
->playpos
) && (offset
< (dsb
->playpos
+ len
))) {
2565 TRACE("signalled event %d (%d)\n", event
->hEventNotify
, i
);
2566 SetEvent(event
->hEventNotify
);
2572 /* WAV format info can be found at: */
2574 /* http://www.cwi.nl/ftp/audio/AudioFormats.part2 */
2575 /* ftp://ftp.cwi.nl/pub/audio/RIFF-format */
2577 /* Import points to remember: */
2579 /* 8-bit WAV is unsigned */
2580 /* 16-bit WAV is signed */
2582 static inline INT16
cvtU8toS16(BYTE byte
)
2584 INT16 s
= (byte
- 128) << 8;
2589 static inline BYTE
cvtS16toU8(INT16 word
)
2591 BYTE b
= (word
+ 32768) >> 8;
2597 /* We should be able to optimize these two inline functions */
2598 /* so that we aren't doing 8->16->8 conversions when it is */
2599 /* not necessary. But this is still a WIP. Optimize later. */
2600 static inline void get_fields(const IDirectSoundBufferImpl
*dsb
, BYTE
*buf
, INT
*fl
, INT
*fr
)
2602 INT16
*bufs
= (INT16
*) buf
;
2604 /* TRACE("(%p)\n", buf); */
2605 if ((dsb
->wfx
.wBitsPerSample
== 8) && dsb
->wfx
.nChannels
== 2) {
2606 *fl
= cvtU8toS16(*buf
);
2607 *fr
= cvtU8toS16(*(buf
+ 1));
2611 if ((dsb
->wfx
.wBitsPerSample
== 16) && dsb
->wfx
.nChannels
== 2) {
2617 if ((dsb
->wfx
.wBitsPerSample
== 8) && dsb
->wfx
.nChannels
== 1) {
2618 *fl
= cvtU8toS16(*buf
);
2623 if ((dsb
->wfx
.wBitsPerSample
== 16) && dsb
->wfx
.nChannels
== 1) {
2629 FIXME("get_fields found an unsupported configuration\n");
2633 static inline void set_fields(BYTE
*buf
, INT fl
, INT fr
)
2635 INT16
*bufs
= (INT16
*) buf
;
2637 if ((primarybuf
->wfx
.wBitsPerSample
== 8) && (primarybuf
->wfx
.nChannels
== 2)) {
2638 *buf
= cvtS16toU8(fl
);
2639 *(buf
+ 1) = cvtS16toU8(fr
);
2643 if ((primarybuf
->wfx
.wBitsPerSample
== 16) && (primarybuf
->wfx
.nChannels
== 2)) {
2649 if ((primarybuf
->wfx
.wBitsPerSample
== 8) && (primarybuf
->wfx
.nChannels
== 1)) {
2650 *buf
= cvtS16toU8((fl
+ fr
) >> 1);
2654 if ((primarybuf
->wfx
.wBitsPerSample
== 16) && (primarybuf
->wfx
.nChannels
== 1)) {
2655 *bufs
= (fl
+ fr
) >> 1;
2658 FIXME("set_fields found an unsupported configuration\n");
2662 /* Now with PerfectPitch (tm) technology */
2663 static INT
DSOUND_MixerNorm(IDirectSoundBufferImpl
*dsb
, BYTE
*buf
, INT len
)
2665 INT i
, size
, ipos
, ilen
, fieldL
, fieldR
;
2667 INT iAdvance
= dsb
->wfx
.nBlockAlign
;
2668 INT oAdvance
= primarybuf
->wfx
.nBlockAlign
;
2670 ibp
= dsb
->buffer
+ dsb
->buf_mixpos
;
2673 TRACE("(%p, %p, %p), buf_mixpos=%ld\n", dsb
, ibp
, obp
, dsb
->buf_mixpos
);
2674 /* Check for the best case */
2675 if ((dsb
->freq
== primarybuf
->wfx
.nSamplesPerSec
) &&
2676 (dsb
->wfx
.wBitsPerSample
== primarybuf
->wfx
.wBitsPerSample
) &&
2677 (dsb
->wfx
.nChannels
== primarybuf
->wfx
.nChannels
)) {
2678 DWORD bytesleft
= dsb
->buflen
- dsb
->buf_mixpos
;
2679 TRACE("(%p) Best case\n", dsb
);
2680 if (len
<= bytesleft
)
2681 memcpy(obp
, ibp
, len
);
2683 memcpy(obp
, ibp
, bytesleft
);
2684 memcpy(obp
+ bytesleft
, dsb
->buffer
, len
- bytesleft
);
2689 /* Check for same sample rate */
2690 if (dsb
->freq
== primarybuf
->wfx
.nSamplesPerSec
) {
2691 TRACE("(%p) Same sample rate %ld = primary %ld\n", dsb
,
2692 dsb
->freq
, primarybuf
->wfx
.nSamplesPerSec
);
2694 for (i
= 0; i
< len
; i
+= oAdvance
) {
2695 get_fields(dsb
, ibp
, &fieldL
, &fieldR
);
2698 set_fields(obp
, fieldL
, fieldR
);
2700 if (ibp
>= (BYTE
*)(dsb
->buffer
+ dsb
->buflen
))
2701 ibp
= dsb
->buffer
; /* wrap */
2706 /* Mix in different sample rates */
2708 /* New PerfectPitch(tm) Technology (c) 1998 Rob Riggs */
2709 /* Patent Pending :-] */
2711 /* Patent enhancements (c) 2000 Ove KÃ¥ven,
2712 * TransGaming Technologies Inc. */
2714 FIXME("(%p) Adjusting frequency: %ld -> %ld (need optimization)\n",
2715 dsb
, dsb
->freq
, primarybuf
->wfx
.nSamplesPerSec
);
2717 size
= len
/ oAdvance
;
2719 ipos
= dsb
->buf_mixpos
;
2720 for (i
= 0; i
< size
; i
++) {
2721 get_fields(dsb
, (dsb
->buffer
+ ipos
), &fieldL
, &fieldR
);
2722 set_fields(obp
, fieldL
, fieldR
);
2725 dsb
->freqAcc
+= dsb
->freqAdjust
;
2726 if (dsb
->freqAcc
>= (1<<DSOUND_FREQSHIFT
)) {
2727 ULONG adv
= (dsb
->freqAcc
>>DSOUND_FREQSHIFT
) * iAdvance
;
2728 dsb
->freqAcc
&= (1<<DSOUND_FREQSHIFT
)-1;
2729 ipos
+= adv
; ilen
+= adv
;
2730 while (ipos
>= dsb
->buflen
)
2731 ipos
-= dsb
->buflen
;
2737 static void DSOUND_MixerVol(IDirectSoundBufferImpl
*dsb
, BYTE
*buf
, INT len
)
2739 INT i
, inc
= primarybuf
->wfx
.wBitsPerSample
>> 3;
2741 INT16
*bps
= (INT16
*) buf
;
2743 TRACE("(%p) left = %lx, right = %lx\n", dsb
,
2744 dsb
->volpan
.dwTotalLeftAmpFactor
, dsb
->volpan
.dwTotalRightAmpFactor
);
2745 if ((!(dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLPAN
) || (dsb
->volpan
.lPan
== 0)) &&
2746 (!(dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLVOLUME
) || (dsb
->volpan
.lVolume
== 0)) &&
2747 !(dsb
->dsbd
.dwFlags
& DSBCAPS_CTRL3D
))
2748 return; /* Nothing to do */
2750 /* If we end up with some bozo coder using panning or 3D sound */
2751 /* with a mono primary buffer, it could sound very weird using */
2752 /* this method. Oh well, tough patooties. */
2754 for (i
= 0; i
< len
; i
+= inc
) {
2760 /* 8-bit WAV is unsigned, but we need to operate */
2761 /* on signed data for this to work properly */
2763 val
= ((val
* (i
& inc
? dsb
->volpan
.dwTotalRightAmpFactor
: dsb
->volpan
.dwTotalLeftAmpFactor
)) >> 16);
2768 /* 16-bit WAV is signed -- much better */
2770 val
= ((val
* ((i
& inc
) ? dsb
->volpan
.dwTotalRightAmpFactor
: dsb
->volpan
.dwTotalLeftAmpFactor
)) >> 16);
2776 FIXME("MixerVol had a nasty error\n");
2782 static void DSOUND_Mixer3D(IDirectSoundBufferImpl
*dsb
, BYTE
*buf
, INT len
)
2785 DWORD buflen
, buf_mixpos
;
2787 buflen
= dsb
->ds3db
->buflen
;
2788 buf_mixpos
= (dsb
->buf_mixpos
* primarybuf
->wfx
.nBlockAlign
) / dsb
->wfx
.nBlockAlign
;
2789 ibp
= dsb
->ds3db
->buffer
+ buf_mixpos
;
2792 if (buf_mixpos
> buflen
) {
2793 FIXME("Major breakage\n");
2797 if (len
<= (buf_mixpos
+ buflen
))
2798 memcpy(obp
, ibp
, len
);
2800 memcpy(obp
, ibp
, buflen
- buf_mixpos
);
2801 memcpy(obp
+ (buflen
- buf_mixpos
),
2803 len
- (buflen
- buf_mixpos
));
2809 static void *tmp_buffer
;
2810 static size_t tmp_buffer_len
= 0;
2812 static void *DSOUND_tmpbuffer(size_t len
)
2814 if (len
>tmp_buffer_len
) {
2815 void *new_buffer
= realloc(tmp_buffer
, len
);
2817 tmp_buffer
= new_buffer
;
2818 tmp_buffer_len
= len
;
2825 static DWORD
DSOUND_MixInBuffer(IDirectSoundBufferImpl
*dsb
, DWORD writepos
, DWORD fraglen
)
2827 INT i
, len
, ilen
, temp
, field
;
2828 INT advance
= primarybuf
->wfx
.wBitsPerSample
>> 3;
2829 BYTE
*buf
, *ibuf
, *obuf
;
2830 INT16
*ibufs
, *obufs
;
2833 if (!(dsb
->playflags
& DSBPLAY_LOOPING
)) {
2834 temp
= MulDiv(primarybuf
->wfx
.nAvgBytesPerSec
, dsb
->buflen
,
2835 dsb
->nAvgBytesPerSec
) -
2836 MulDiv(primarybuf
->wfx
.nAvgBytesPerSec
, dsb
->buf_mixpos
,
2837 dsb
->nAvgBytesPerSec
);
2838 len
= (len
> temp
) ? temp
: len
;
2840 len
&= ~3; /* 4 byte alignment */
2843 /* This should only happen if we aren't looping and temp < 4 */
2845 /* We skip the remainder, so check for possible events */
2846 DSOUND_CheckEvent(dsb
, dsb
->buflen
- dsb
->buf_mixpos
);
2848 dsb
->state
= STATE_STOPPED
;
2850 dsb
->buf_mixpos
= 0;
2851 dsb
->leadin
= FALSE
;
2852 /* Check for DSBPN_OFFSETSTOP */
2853 DSOUND_CheckEvent(dsb
, 0);
2857 /* Been seeing segfaults in malloc() for some reason... */
2858 TRACE("allocating buffer (size = %d)\n", len
);
2859 if ((buf
= ibuf
= (BYTE
*) DSOUND_tmpbuffer(len
)) == NULL
)
2862 TRACE("MixInBuffer (%p) len = %d, dest = %ld\n", dsb
, len
, writepos
);
2864 ilen
= DSOUND_MixerNorm(dsb
, ibuf
, len
);
2865 if ((dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLPAN
) ||
2866 (dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLVOLUME
))
2867 DSOUND_MixerVol(dsb
, ibuf
, len
);
2869 obuf
= primarybuf
->buffer
+ writepos
;
2870 for (i
= 0; i
< len
; i
+= advance
) {
2871 obufs
= (INT16
*) obuf
;
2872 ibufs
= (INT16
*) ibuf
;
2873 if (primarybuf
->wfx
.wBitsPerSample
== 8) {
2874 /* 8-bit WAV is unsigned */
2875 field
= (*ibuf
- 128);
2876 field
+= (*obuf
- 128);
2877 field
= field
> 127 ? 127 : field
;
2878 field
= field
< -128 ? -128 : field
;
2879 *obuf
= field
+ 128;
2881 /* 16-bit WAV is signed */
2884 field
= field
> 32767 ? 32767 : field
;
2885 field
= field
< -32768 ? -32768 : field
;
2890 if (obuf
>= (BYTE
*)(primarybuf
->buffer
+ primarybuf
->buflen
))
2891 obuf
= primarybuf
->buffer
;
2895 if (dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLPOSITIONNOTIFY
)
2896 DSOUND_CheckEvent(dsb
, ilen
);
2898 if (dsb
->leadin
&& (dsb
->startpos
> dsb
->buf_mixpos
) && (dsb
->startpos
<= dsb
->buf_mixpos
+ ilen
)) {
2899 /* HACK... leadin should be reset when the PLAY position reaches the startpos,
2900 * not the MIX position... but if the sound buffer is bigger than our prebuffering
2901 * (which must be the case for the streaming buffers that need this hack anyway)
2902 * plus DS_HEL_MARGIN or equivalent, then this ought to work anyway. */
2903 dsb
->leadin
= FALSE
;
2906 dsb
->buf_mixpos
+= ilen
;
2908 if (dsb
->buf_mixpos
>= dsb
->buflen
) {
2909 if (!(dsb
->playflags
& DSBPLAY_LOOPING
)) {
2910 dsb
->state
= STATE_STOPPED
;
2912 dsb
->buf_mixpos
= 0;
2913 dsb
->leadin
= FALSE
;
2914 DSOUND_CheckEvent(dsb
, 0); /* For DSBPN_OFFSETSTOP */
2917 while (dsb
->buf_mixpos
>= dsb
->buflen
)
2918 dsb
->buf_mixpos
-= dsb
->buflen
;
2919 if (dsb
->leadin
&& (dsb
->startpos
<= dsb
->buf_mixpos
))
2920 dsb
->leadin
= FALSE
; /* HACK: see above */
2927 static void DSOUND_PhaseCancel(IDirectSoundBufferImpl
*dsb
, DWORD writepos
, DWORD len
)
2930 INT advance
= primarybuf
->wfx
.wBitsPerSample
>> 3;
2931 BYTE
*buf
, *ibuf
, *obuf
;
2932 INT16
*ibufs
, *obufs
;
2934 len
&= ~3; /* 4 byte alignment */
2936 TRACE("allocating buffer (size = %ld)\n", len
);
2937 if ((buf
= ibuf
= (BYTE
*) DSOUND_tmpbuffer(len
)) == NULL
)
2940 TRACE("PhaseCancel (%p) len = %ld, dest = %ld\n", dsb
, len
, writepos
);
2942 ilen
= DSOUND_MixerNorm(dsb
, ibuf
, len
);
2943 if ((dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLPAN
) ||
2944 (dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLVOLUME
))
2945 DSOUND_MixerVol(dsb
, ibuf
, len
);
2947 /* subtract instead of add, to phase out premixed data */
2948 obuf
= primarybuf
->buffer
+ writepos
;
2949 for (i
= 0; i
< len
; i
+= advance
) {
2950 obufs
= (INT16
*) obuf
;
2951 ibufs
= (INT16
*) ibuf
;
2952 if (primarybuf
->wfx
.wBitsPerSample
== 8) {
2953 /* 8-bit WAV is unsigned */
2954 field
= (*ibuf
- 128);
2955 field
-= (*obuf
- 128);
2956 field
= field
> 127 ? 127 : field
;
2957 field
= field
< -128 ? -128 : field
;
2958 *obuf
= field
+ 128;
2960 /* 16-bit WAV is signed */
2963 field
= field
> 32767 ? 32767 : field
;
2964 field
= field
< -32768 ? -32768 : field
;
2969 if (obuf
>= (BYTE
*)(primarybuf
->buffer
+ primarybuf
->buflen
))
2970 obuf
= primarybuf
->buffer
;
2975 static void DSOUND_MixCancel(IDirectSoundBufferImpl
*dsb
, DWORD writepos
, BOOL cancel
)
2977 DWORD size
, flen
, len
, npos
, nlen
;
2978 INT iAdvance
= dsb
->wfx
.nBlockAlign
;
2979 INT oAdvance
= primarybuf
->wfx
.nBlockAlign
;
2980 /* determine amount of premixed data to cancel */
2981 DWORD primary_done
=
2982 ((dsb
->primary_mixpos
< writepos
) ? primarybuf
->buflen
: 0) +
2983 dsb
->primary_mixpos
- writepos
;
2985 TRACE("(%p, %ld), buf_mixpos=%ld\n", dsb
, writepos
, dsb
->buf_mixpos
);
2987 /* backtrack the mix position */
2988 size
= primary_done
/ oAdvance
;
2989 flen
= size
* dsb
->freqAdjust
;
2990 len
= (flen
>> DSOUND_FREQSHIFT
) * iAdvance
;
2991 flen
&= (1<<DSOUND_FREQSHIFT
)-1;
2992 while (dsb
->freqAcc
< flen
) {
2994 dsb
->freqAcc
+= 1<<DSOUND_FREQSHIFT
;
2997 npos
= ((dsb
->buf_mixpos
< len
) ? dsb
->buflen
: 0) +
2998 dsb
->buf_mixpos
- len
;
2999 if (dsb
->leadin
&& (dsb
->startpos
> npos
) && (dsb
->startpos
<= npos
+ len
)) {
3000 /* stop backtracking at startpos */
3001 npos
= dsb
->startpos
;
3002 len
= ((dsb
->buf_mixpos
< npos
) ? dsb
->buflen
: 0) +
3003 dsb
->buf_mixpos
- npos
;
3004 flen
= dsb
->freqAcc
;
3005 nlen
= len
/ dsb
->wfx
.nBlockAlign
;
3006 nlen
= ((nlen
<< DSOUND_FREQSHIFT
) + flen
) / dsb
->freqAdjust
;
3007 nlen
*= primarybuf
->wfx
.nBlockAlign
;
3009 ((dsb
->primary_mixpos
< nlen
) ? primarybuf
->buflen
: 0) +
3010 dsb
->primary_mixpos
- nlen
;
3013 dsb
->freqAcc
-= flen
;
3014 dsb
->buf_mixpos
= npos
;
3015 dsb
->primary_mixpos
= writepos
;
3017 TRACE("new buf_mixpos=%ld, primary_mixpos=%ld (len=%ld)\n",
3018 dsb
->buf_mixpos
, dsb
->primary_mixpos
, len
);
3020 if (cancel
) DSOUND_PhaseCancel(dsb
, writepos
, len
);
3023 static void DSOUND_MixCancelAt(IDirectSoundBufferImpl
*dsb
, DWORD buf_writepos
)
3026 DWORD i
, size
, flen
, len
, npos
, nlen
;
3027 INT iAdvance
= dsb
->wfx
.nBlockAlign
;
3028 INT oAdvance
= primarybuf
->wfx
.nBlockAlign
;
3029 /* determine amount of premixed data to cancel */
3031 ((dsb
->buf_mixpos
< buf_writepos
) ? dsb
->buflen
: 0) +
3032 dsb
->buf_mixpos
- buf_writepos
;
3035 WARN("(%p, %ld), buf_mixpos=%ld\n", dsb
, buf_writepos
, dsb
->buf_mixpos
);
3036 /* since this is not implemented yet, just cancel *ALL* prebuffering for now
3037 * (which is faster anyway when there's one a single secondary buffer) */
3038 primarybuf
->need_remix
= TRUE
;
3041 static DWORD
DSOUND_MixOne(IDirectSoundBufferImpl
*dsb
, DWORD playpos
, DWORD writepos
, DWORD mixlen
)
3044 /* determine this buffer's write position */
3045 DWORD buf_writepos
= DSOUND_CalcPlayPosition(dsb
, dsb
->state
& primarybuf
->state
, writepos
,
3046 writepos
, dsb
->primary_mixpos
, dsb
->buf_mixpos
);
3047 /* determine how much already-mixed data exists */
3049 ((dsb
->buf_mixpos
< buf_writepos
) ? dsb
->buflen
: 0) +
3050 dsb
->buf_mixpos
- buf_writepos
;
3051 DWORD primary_done
=
3052 ((dsb
->primary_mixpos
< writepos
) ? primarybuf
->buflen
: 0) +
3053 dsb
->primary_mixpos
- writepos
;
3055 ((primarybuf
->buf_mixpos
< writepos
) ? primarybuf
->buflen
: 0) +
3056 primarybuf
->buf_mixpos
- writepos
;
3059 TRACE("buf_writepos=%ld, primary_writepos=%ld\n", buf_writepos
, writepos
);
3060 TRACE("buf_done=%ld, primary_done=%ld\n", buf_done
, primary_done
);
3061 TRACE("buf_mixpos=%ld, primary_mixpos=%ld, mixlen=%ld\n", dsb
->buf_mixpos
, dsb
->primary_mixpos
,
3063 TRACE("looping=%ld, startpos=%ld, leadin=%ld\n", dsb
->playflags
, dsb
->startpos
, dsb
->leadin
);
3065 /* save write position for non-GETCURRENTPOSITION2... */
3066 dsb
->playpos
= buf_writepos
;
3068 /* check whether CalcPlayPosition detected a mixing underrun */
3069 if ((buf_done
== 0) && (dsb
->primary_mixpos
!= writepos
)) {
3070 /* it did, but did we have more to play? */
3071 if ((dsb
->playflags
& DSBPLAY_LOOPING
) ||
3072 (dsb
->buf_mixpos
< dsb
->buflen
)) {
3073 /* yes, have to recover */
3074 ERR("underrun on sound buffer %p\n", dsb
);
3075 TRACE("recovering from underrun: primary_mixpos=%ld\n", writepos
);
3077 dsb
->primary_mixpos
= writepos
;
3080 /* determine how far ahead we should mix */
3081 if (((dsb
->playflags
& DSBPLAY_LOOPING
) ||
3082 (dsb
->leadin
&& (dsb
->probably_valid_to
!= 0))) &&
3083 !(dsb
->dsbd
.dwFlags
& DSBCAPS_STATIC
)) {
3084 /* if this is a streaming buffer, it typically means that
3085 * we should defer mixing past probably_valid_to as long
3086 * as we can, to avoid unnecessary remixing */
3087 /* the heavy-looking calculations shouldn't be that bad,
3088 * as any game isn't likely to be have more than 1 or 2
3089 * streaming buffers in use at any time anyway... */
3090 DWORD probably_valid_left
=
3091 (dsb
->probably_valid_to
== (DWORD
)-1) ? dsb
->buflen
:
3092 ((dsb
->probably_valid_to
< buf_writepos
) ? dsb
->buflen
: 0) +
3093 dsb
->probably_valid_to
- buf_writepos
;
3094 /* check for leadin condition */
3095 if ((probably_valid_left
== 0) &&
3096 (dsb
->probably_valid_to
== dsb
->startpos
) &&
3098 probably_valid_left
= dsb
->buflen
;
3099 TRACE("streaming buffer probably_valid_to=%ld, probably_valid_left=%ld\n",
3100 dsb
->probably_valid_to
, probably_valid_left
);
3101 /* check whether the app's time is already up */
3102 if (probably_valid_left
< dsb
->writelead
) {
3103 WARN("probably_valid_to now within writelead, possible streaming underrun\n");
3104 /* once we pass the point of no return,
3105 * no reason to hold back anymore */
3106 dsb
->probably_valid_to
= (DWORD
)-1;
3107 /* we just have to go ahead and mix what we have,
3108 * there's no telling what the app is thinking anyway */
3110 /* adjust for our frequency and our sample size */
3111 probably_valid_left
= MulDiv(probably_valid_left
,
3112 1 << DSOUND_FREQSHIFT
,
3113 dsb
->wfx
.nBlockAlign
* dsb
->freqAdjust
) *
3114 primarybuf
->wfx
.nBlockAlign
;
3115 /* check whether to clip mix_len */
3116 if (probably_valid_left
< mixlen
) {
3117 TRACE("clipping to probably_valid_left=%ld\n", probably_valid_left
);
3118 mixlen
= probably_valid_left
;
3122 /* cut mixlen with what's already been mixed */
3123 if (mixlen
< primary_done
) {
3124 /* huh? and still CalcPlayPosition didn't
3125 * detect an underrun? */
3126 FIXME("problem with underrun detection (mixlen=%ld < primary_done=%ld)\n", mixlen
, primary_done
);
3129 len
= mixlen
- primary_done
;
3130 TRACE("remaining mixlen=%ld\n", len
);
3132 if (len
< primarybuf
->dsound
->fraglen
) {
3133 /* smaller than a fragment, wait until it gets larger
3134 * before we take the mixing overhead */
3135 TRACE("mixlen not worth it, deferring mixing\n");
3139 /* ok, we know how much to mix, let's go */
3140 still_behind
= (adv_done
> primary_done
);
3142 slen
= primarybuf
->buflen
- dsb
->primary_mixpos
;
3143 if (slen
> len
) slen
= len
;
3144 slen
= DSOUND_MixInBuffer(dsb
, dsb
->primary_mixpos
, slen
);
3146 if ((dsb
->primary_mixpos
< primarybuf
->buf_mixpos
) &&
3147 (dsb
->primary_mixpos
+ slen
>= primarybuf
->buf_mixpos
))
3148 still_behind
= FALSE
;
3150 dsb
->primary_mixpos
+= slen
; len
-= slen
;
3151 while (dsb
->primary_mixpos
>= primarybuf
->buflen
)
3152 dsb
->primary_mixpos
-= primarybuf
->buflen
;
3154 if ((dsb
->state
== STATE_STOPPED
) || !slen
) break;
3156 TRACE("new primary_mixpos=%ld, primary_advbase=%ld\n", dsb
->primary_mixpos
, primarybuf
->buf_mixpos
);
3157 TRACE("mixed data len=%ld, still_behind=%d\n", mixlen
-len
, still_behind
);
3158 /* return how far we think the primary buffer can
3159 * advance its underrun detector...*/
3160 if (still_behind
) return 0;
3161 if ((mixlen
- len
) < primary_done
) return 0;
3162 slen
= ((dsb
->primary_mixpos
< primarybuf
->buf_mixpos
) ?
3163 primarybuf
->buflen
: 0) + dsb
->primary_mixpos
-
3164 primarybuf
->buf_mixpos
;
3165 if (slen
> mixlen
) {
3166 /* the primary_done and still_behind checks above should have worked */
3167 FIXME("problem with advancement calculation (advlen=%ld > mixlen=%ld)\n", slen
, mixlen
);
3173 static DWORD
DSOUND_MixToPrimary(DWORD playpos
, DWORD writepos
, DWORD mixlen
, BOOL recover
)
3175 INT i
, len
, maxlen
= 0;
3176 IDirectSoundBufferImpl
*dsb
;
3178 TRACE("(%ld,%ld,%ld)\n", playpos
, writepos
, mixlen
);
3179 for (i
= dsound
->nrofbuffers
- 1; i
>= 0; i
--) {
3180 dsb
= dsound
->buffers
[i
];
3182 if (!dsb
|| !(ICOM_VTBL(dsb
)))
3184 if (dsb
->buflen
&& dsb
->state
&& !dsb
->hwbuf
) {
3185 TRACE("Checking %p, mixlen=%ld\n", dsb
, mixlen
);
3186 EnterCriticalSection(&(dsb
->lock
));
3187 if (dsb
->state
== STATE_STOPPING
) {
3188 DSOUND_MixCancel(dsb
, writepos
, TRUE
);
3189 dsb
->state
= STATE_STOPPED
;
3191 if ((dsb
->state
== STATE_STARTING
) || recover
)
3192 dsb
->primary_mixpos
= writepos
;
3193 len
= DSOUND_MixOne(dsb
, playpos
, writepos
, mixlen
);
3194 if (dsb
->state
== STATE_STARTING
)
3195 dsb
->state
= STATE_PLAYING
;
3196 maxlen
= (len
> maxlen
) ? len
: maxlen
;
3198 LeaveCriticalSection(&(dsb
->lock
));
3205 static void DSOUND_MixReset(DWORD writepos
)
3208 IDirectSoundBufferImpl
*dsb
;
3211 TRACE("(%ld)\n", writepos
);
3213 /* the sound of silence */
3214 nfiller
= primarybuf
->wfx
.wBitsPerSample
== 8 ? 128 : 0;
3216 /* reset all buffer mix positions */
3217 for (i
= dsound
->nrofbuffers
- 1; i
>= 0; i
--) {
3218 dsb
= dsound
->buffers
[i
];
3220 if (!dsb
|| !(ICOM_VTBL(dsb
)))
3222 if (dsb
->buflen
&& dsb
->state
&& !dsb
->hwbuf
) {
3223 TRACE("Resetting %p\n", dsb
);
3224 EnterCriticalSection(&(dsb
->lock
));
3225 if (dsb
->state
== STATE_STOPPING
) {
3226 dsb
->state
= STATE_STOPPED
;
3228 else if (dsb
->state
== STATE_STARTING
) {
3231 DSOUND_MixCancel(dsb
, writepos
, FALSE
);
3233 LeaveCriticalSection(&(dsb
->lock
));
3237 /* wipe out premixed data */
3238 if (primarybuf
->buf_mixpos
< writepos
) {
3239 memset(primarybuf
->buffer
+ writepos
, nfiller
, primarybuf
->buflen
- writepos
);
3240 memset(primarybuf
->buffer
, nfiller
, primarybuf
->buf_mixpos
);
3242 memset(primarybuf
->buffer
+ writepos
, nfiller
, primarybuf
->buf_mixpos
- writepos
);
3245 /* reset primary mix position */
3246 primarybuf
->buf_mixpos
= writepos
;
3249 static void DSOUND_CheckReset(IDirectSoundImpl
*dsound
, DWORD writepos
)
3251 if (primarybuf
->need_remix
) {
3252 DSOUND_MixReset(writepos
);
3253 primarybuf
->need_remix
= FALSE
;
3254 /* maximize Half-Life performance */
3255 dsound
->prebuf
= DS_SND_QUEUE_MIN
;
3257 /* if (dsound->prebuf < DS_SND_QUEUE_MAX) dsound->prebuf++; */
3259 TRACE("premix adjust: %d\n", dsound
->prebuf
);
3262 static void DSOUND_WaveQueue(IDirectSoundImpl
*dsound
, DWORD mixq
)
3264 if (mixq
+ dsound
->pwqueue
> DS_HEL_QUEUE
) mixq
= DS_HEL_QUEUE
- dsound
->pwqueue
;
3265 TRACE("queueing %ld buffers, starting at %d\n", mixq
, dsound
->pwwrite
);
3266 for (; mixq
; mixq
--) {
3267 waveOutWrite(dsound
->hwo
, dsound
->pwave
[dsound
->pwwrite
], sizeof(WAVEHDR
));
3269 if (dsound
->pwwrite
>= DS_HEL_FRAGS
) dsound
->pwwrite
= 0;
3274 /* #define SYNC_CALLBACK */
3276 static void DSOUND_PerformMix(void)
3282 EnterCriticalSection(&(dsound
->lock
));
3284 if (!primarybuf
|| !primarybuf
->ref
) {
3285 /* seems the primary buffer is currently being released */
3286 LeaveCriticalSection(&(dsound
->lock
));
3290 /* the sound of silence */
3291 nfiller
= primarybuf
->wfx
.wBitsPerSample
== 8 ? 128 : 0;
3293 /* whether the primary is forced to play even without secondary buffers */
3294 forced
= ((primarybuf
->state
== STATE_PLAYING
) || (primarybuf
->state
== STATE_STARTING
));
3296 TRACE("entering at %ld\n", GetTickCount());
3297 if (dsound
->priolevel
!= DSSCL_WRITEPRIMARY
) {
3298 BOOL paused
= ((primarybuf
->state
== STATE_STOPPED
) || (primarybuf
->state
== STATE_STARTING
));
3299 /* FIXME: document variables */
3300 DWORD playpos
, writepos
, inq
, maxq
, frag
;
3301 if (primarybuf
->hwbuf
) {
3302 hres
= IDsDriverBuffer_GetPosition(primarybuf
->hwbuf
, &playpos
, &writepos
);
3304 LeaveCriticalSection(&(dsound
->lock
));
3307 /* Well, we *could* do Just-In-Time mixing using the writepos,
3308 * but that's a little bit ambitious and unnecessary... */
3309 /* rather add our safety margin to the writepos, if we're playing */
3311 writepos
+= primarybuf
->writelead
;
3312 while (writepos
>= primarybuf
->buflen
)
3313 writepos
-= primarybuf
->buflen
;
3314 } else writepos
= playpos
;
3317 playpos
= dsound
->pwplay
* dsound
->fraglen
;
3320 writepos
+= DS_HEL_MARGIN
* dsound
->fraglen
;
3321 while (writepos
>= primarybuf
->buflen
)
3322 writepos
-= primarybuf
->buflen
;
3325 TRACE("primary playpos=%ld, writepos=%ld, clrpos=%ld, mixpos=%ld\n",
3326 playpos
,writepos
,primarybuf
->playpos
,primarybuf
->buf_mixpos
);
3327 /* wipe out just-played sound data */
3328 if (playpos
< primarybuf
->playpos
) {
3329 memset(primarybuf
->buffer
+ primarybuf
->playpos
, nfiller
, primarybuf
->buflen
- primarybuf
->playpos
);
3330 memset(primarybuf
->buffer
, nfiller
, playpos
);
3332 memset(primarybuf
->buffer
+ primarybuf
->playpos
, nfiller
, playpos
- primarybuf
->playpos
);
3334 primarybuf
->playpos
= playpos
;
3336 EnterCriticalSection(&(primarybuf
->lock
));
3338 /* reset mixing if necessary */
3339 DSOUND_CheckReset(dsound
, writepos
);
3341 /* check how much prebuffering is left */
3342 inq
= primarybuf
->buf_mixpos
;
3344 inq
+= primarybuf
->buflen
;
3347 /* find the maximum we can prebuffer */
3350 if (maxq
< writepos
)
3351 maxq
+= primarybuf
->buflen
;
3353 } else maxq
= primarybuf
->buflen
;
3355 /* clip maxq to dsound->prebuf */
3356 frag
= dsound
->prebuf
* dsound
->fraglen
;
3357 if (maxq
> frag
) maxq
= frag
;
3359 /* check for consistency */
3361 /* the playback position must have passed our last
3362 * mixed position, i.e. it's an underrun, or we have
3363 * nothing more to play */
3364 TRACE("reached end of mixed data (inq=%ld, maxq=%ld)\n", inq
, maxq
);
3366 /* stop the playback now, to allow buffers to refill */
3367 if (primarybuf
->state
== STATE_PLAYING
) {
3368 primarybuf
->state
= STATE_STARTING
;
3370 else if (primarybuf
->state
== STATE_STOPPING
) {
3371 primarybuf
->state
= STATE_STOPPED
;
3374 /* how can we have an underrun if we aren't playing? */
3375 WARN("unexpected primary state (%ld)\n", primarybuf
->state
);
3377 #ifdef SYNC_CALLBACK
3378 /* DSOUND_callback may need this lock */
3379 LeaveCriticalSection(&(primarybuf
->lock
));
3381 DSOUND_PrimaryStop(primarybuf
);
3382 #ifdef SYNC_CALLBACK
3383 EnterCriticalSection(&(primarybuf
->lock
));
3385 if (primarybuf
->hwbuf
) {
3386 /* the Stop is supposed to reset play position to beginning of buffer */
3387 /* unfortunately, OSS is not able to do so, so get current pointer */
3388 hres
= IDsDriverBuffer_GetPosition(primarybuf
->hwbuf
, &playpos
, NULL
);
3390 LeaveCriticalSection(&(dsound
->lock
));
3391 LeaveCriticalSection(&(primarybuf
->lock
));
3395 playpos
= dsound
->pwplay
* dsound
->fraglen
;
3398 primarybuf
->playpos
= playpos
;
3399 primarybuf
->buf_mixpos
= writepos
;
3401 maxq
= primarybuf
->buflen
;
3402 if (maxq
> frag
) maxq
= frag
;
3403 memset(primarybuf
->buffer
, nfiller
, primarybuf
->buflen
);
3408 frag
= DSOUND_MixToPrimary(playpos
, writepos
, maxq
, paused
);
3409 if (forced
) frag
= maxq
- inq
;
3410 primarybuf
->buf_mixpos
+= frag
;
3411 while (primarybuf
->buf_mixpos
>= primarybuf
->buflen
)
3412 primarybuf
->buf_mixpos
-= primarybuf
->buflen
;
3415 /* buffers have been filled, restart playback */
3416 if (primarybuf
->state
== STATE_STARTING
) {
3417 primarybuf
->state
= STATE_PLAYING
;
3419 else if (primarybuf
->state
== STATE_STOPPED
) {
3420 /* the primarybuf is supposed to play if there's something to play
3421 * even if it is reported as stopped, so don't let this confuse you */
3422 primarybuf
->state
= STATE_STOPPING
;
3424 LeaveCriticalSection(&(primarybuf
->lock
));
3426 DSOUND_PrimaryPlay(primarybuf
);
3427 TRACE("starting playback\n");
3431 LeaveCriticalSection(&(primarybuf
->lock
));
3433 /* in the DSSCL_WRITEPRIMARY mode, the app is totally in charge... */
3434 if (primarybuf
->state
== STATE_STARTING
) {
3435 DSOUND_PrimaryPlay(primarybuf
);
3436 primarybuf
->state
= STATE_PLAYING
;
3438 else if (primarybuf
->state
== STATE_STOPPING
) {
3439 DSOUND_PrimaryStop(primarybuf
);
3440 primarybuf
->state
= STATE_STOPPED
;
3443 TRACE("completed processing at %ld\n", GetTickCount());
3444 LeaveCriticalSection(&(dsound
->lock
));
3447 static void CALLBACK
DSOUND_timer(UINT timerID
, UINT msg
, DWORD dwUser
, DWORD dw1
, DWORD dw2
)
3449 if (!dsound
|| !primarybuf
) {
3450 ERR("dsound died without killing us?\n");
3451 timeKillEvent(timerID
);
3452 timeEndPeriod(DS_TIME_RES
);
3457 DSOUND_PerformMix();
3460 static void CALLBACK
DSOUND_callback(HWAVEOUT hwo
, UINT msg
, DWORD dwUser
, DWORD dw1
, DWORD dw2
)
3462 IDirectSoundImpl
* This
= (IDirectSoundImpl
*)dwUser
;
3463 TRACE("entering at %ld, msg=%08x\n", GetTickCount(), msg
);
3464 if (msg
== MM_WOM_DONE
) {
3465 DWORD inq
, mixq
, fraglen
, buflen
, pwplay
, playpos
, mixpos
;
3466 if (This
->pwqueue
== (DWORD
)-1) {
3467 TRACE("completed due to reset\n");
3470 /* it could be a bad idea to enter critical section here... if there's lock contention,
3471 * the resulting scheduling delays might obstruct the winmm player thread */
3472 #ifdef SYNC_CALLBACK
3473 EnterCriticalSection(&(primarybuf
->lock
));
3475 /* retrieve current values */
3476 fraglen
= dsound
->fraglen
;
3477 buflen
= primarybuf
->buflen
;
3478 pwplay
= dsound
->pwplay
;
3479 playpos
= pwplay
* fraglen
;
3480 mixpos
= primarybuf
->buf_mixpos
;
3481 /* check remaining mixed data */
3482 inq
= ((mixpos
< playpos
) ? buflen
: 0) + mixpos
- playpos
;
3483 mixq
= inq
/ fraglen
;
3484 if ((inq
- (mixq
* fraglen
)) > 0) mixq
++;
3485 /* complete the playing buffer */
3486 TRACE("done playing primary pos=%ld\n", playpos
);
3488 if (pwplay
>= DS_HEL_FRAGS
) pwplay
= 0;
3489 /* write new values */
3490 dsound
->pwplay
= pwplay
;
3492 /* queue new buffer if we have data for it */
3493 if (inq
>1) DSOUND_WaveQueue(This
, inq
-1);
3494 #ifdef SYNC_CALLBACK
3495 LeaveCriticalSection(&(primarybuf
->lock
));
3498 TRACE("completed\n");
3501 /*******************************************************************************
3502 * DirectSoundCreate (DSOUND.1)
3504 HRESULT WINAPI
DirectSoundCreate(REFGUID lpGUID
,LPDIRECTSOUND
*ppDS
,IUnknown
*pUnkOuter
)
3506 IDirectSoundImpl
** ippDS
=(IDirectSoundImpl
**)ppDS
;
3507 PIDSDRIVER drv
= NULL
;
3510 HRESULT err
= DS_OK
;
3513 TRACE("(%p,%p,%p)\n",lpGUID
,ippDS
,pUnkOuter
);
3515 TRACE("DirectSoundCreate (%p)\n", ippDS
);
3518 return DSERR_INVALIDPARAM
;
3521 IDirectSound_AddRef((LPDIRECTSOUND
)dsound
);
3526 /* Enumerate WINMM audio devices and find the one we want */
3527 wodn
= waveOutGetNumDevs();
3528 if (!wodn
) return DSERR_NODRIVER
;
3530 /* FIXME: How do we find the GUID of an audio device? */
3531 wod
= 0; /* start at the first audio device */
3533 /* Get output device caps */
3534 waveOutGetDevCapsA(wod
, &wcaps
, sizeof(wcaps
));
3535 /* DRV_QUERYDSOUNDIFACE is a "Wine extension" to get the DSound interface */
3536 waveOutMessage(wod
, DRV_QUERYDSOUNDIFACE
, (DWORD
)&drv
, 0);
3538 /* Allocate memory */
3539 *ippDS
= (IDirectSoundImpl
*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundImpl
));
3541 return DSERR_OUTOFMEMORY
;
3543 ICOM_VTBL(*ippDS
) = &dsvt
;
3546 (*ippDS
)->driver
= drv
;
3547 (*ippDS
)->fraglen
= 0;
3548 (*ippDS
)->priolevel
= DSSCL_NORMAL
;
3549 (*ippDS
)->nrofbuffers
= 0;
3550 (*ippDS
)->buffers
= NULL
;
3551 (*ippDS
)->primary
= NULL
;
3552 (*ippDS
)->listener
= NULL
;
3554 (*ippDS
)->prebuf
= DS_SND_QUEUE_MAX
;
3556 /* Get driver description */
3558 IDsDriver_GetDriverDesc(drv
,&((*ippDS
)->drvdesc
));
3560 /* if no DirectSound interface available, use WINMM API instead */
3561 (*ippDS
)->drvdesc
.dwFlags
= DSDDESC_DOMMSYSTEMOPEN
| DSDDESC_DOMMSYSTEMSETFORMAT
;
3562 (*ippDS
)->drvdesc
.dnDevNode
= wod
; /* FIXME? */
3565 /* Set default wave format (may need it for waveOutOpen) */
3566 (*ippDS
)->wfx
.wFormatTag
= WAVE_FORMAT_PCM
;
3567 (*ippDS
)->wfx
.nChannels
= 2;
3568 (*ippDS
)->wfx
.nSamplesPerSec
= 22050;
3569 (*ippDS
)->wfx
.nAvgBytesPerSec
= 44100;
3570 (*ippDS
)->wfx
.nBlockAlign
= 2;
3571 (*ippDS
)->wfx
.wBitsPerSample
= 8;
3573 /* If the driver requests being opened through MMSYSTEM
3574 * (which is recommended by the DDK), it is supposed to happen
3575 * before the DirectSound interface is opened */
3576 if ((*ippDS
)->drvdesc
.dwFlags
& DSDDESC_DOMMSYSTEMOPEN
)
3578 /* FIXME: is this right? */
3580 (*ippDS
)->drvdesc
.dnDevNode
= 0;
3581 err
= DSERR_ALLOCATED
;
3583 /* if this device is busy try the next one */
3584 while((err
== DSERR_ALLOCATED
) &&
3585 ((*ippDS
)->drvdesc
.dnDevNode
< wodn
))
3587 err
= mmErr(waveOutOpen(&((*ippDS
)->hwo
),
3588 (*ippDS
)->drvdesc
.dnDevNode
, &((*ippDS
)->wfx
),
3589 (DWORD
)DSOUND_callback
, (DWORD
)(*ippDS
),
3590 CALLBACK_FUNCTION
| WAVE_DIRECTSOUND
));
3591 (*ippDS
)->drvdesc
.dnDevNode
++; /* next wave device */
3594 (*ippDS
)->drvdesc
.dnDevNode
--; /* take away last increment */
3598 if (drv
&& (err
== DS_OK
))
3599 err
= IDsDriver_Open(drv
);
3601 /* FIXME: do we want to handle a temporarily busy device? */
3603 HeapFree(GetProcessHeap(),0,*ippDS
);
3608 /* the driver is now open, so it's now allowed to call GetCaps */
3610 IDsDriver_GetCaps(drv
,&((*ippDS
)->drvcaps
));
3614 /* FIXME: look at wcaps */
3615 (*ippDS
)->drvcaps
.dwFlags
=
3616 DSCAPS_PRIMARY16BIT
| DSCAPS_PRIMARYSTEREO
;
3618 (*ippDS
)->drvcaps
.dwFlags
|= DSCAPS_EMULDRIVER
;
3620 /* Allocate memory for HEL buffer headers */
3621 for (c
=0; c
<DS_HEL_FRAGS
; c
++) {
3622 (*ippDS
)->pwave
[c
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(WAVEHDR
));
3623 if (!(*ippDS
)->pwave
[c
]) {
3624 /* Argh, out of memory */
3626 HeapFree(GetProcessHeap(),0,(*ippDS
)->pwave
[c
]);
3627 waveOutClose((*ippDS
)->hwo
);
3628 HeapFree(GetProcessHeap(),0,*ippDS
);
3630 return DSERR_OUTOFMEMORY
;
3636 InitializeCriticalSection(&((*ippDS
)->lock
));
3640 if (primarybuf
== NULL
) {
3644 dsbd
.dwSize
= sizeof(DSBUFFERDESC
);
3645 dsbd
.dwFlags
= DSBCAPS_PRIMARYBUFFER
;
3646 dsbd
.dwBufferBytes
= 0;
3647 dsbd
.lpwfxFormat
= &(dsound
->wfx
);
3648 hr
= IDirectSound_CreateSoundBuffer(*ppDS
, &dsbd
, (LPDIRECTSOUNDBUFFER
*)&primarybuf
, NULL
);
3652 /* dsound->primary is NULL - don't need to Release */
3653 dsound
->primary
= primarybuf
;
3654 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER
)primarybuf
);
3656 timeBeginPeriod(DS_TIME_RES
);
3657 dsound
->timerID
= timeSetEvent(DS_TIME_DEL
, DS_TIME_RES
, DSOUND_timer
,
3658 (DWORD
)dsound
, TIME_PERIODIC
| TIME_CALLBACK_FUNCTION
);
3663 /***************************************************************************
3664 * DirectSoundCaptureCreate [DSOUND.6]
3666 * Create and initialize a DirectSoundCapture interface
3670 * Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
3673 HRESULT WINAPI
DirectSoundCaptureCreate(
3675 LPDIRECTSOUNDCAPTURE
* lplpDSC
,
3676 LPUNKNOWN pUnkOuter
)
3678 TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID
), lplpDSC
, pUnkOuter
);
3681 return DSERR_NOAGGREGATION
;
3684 /* Default device? */
3686 return DSOUND_CreateDirectSoundCapture( (LPVOID
*)lplpDSC
);
3689 FIXME( "Unknown GUID %s\n", debugstr_guid(lpcGUID
) );
3692 return DSERR_OUTOFMEMORY
;
3695 /***************************************************************************
3696 * DirectSoundCaptureEnumerateA [DSOUND.7]
3698 * Enumerate all DirectSound drivers installed in the system
3702 * Failure: DSERR_INVALIDPARAM
3704 HRESULT WINAPI
DirectSoundCaptureEnumerateA(
3705 LPDSENUMCALLBACKA lpDSEnumCallback
,
3708 TRACE("(%p,%p)\n", lpDSEnumCallback
, lpContext
);
3710 if ( lpDSEnumCallback
)
3711 lpDSEnumCallback(NULL
,"WINE Primary Sound Capture Driver",
3712 "SoundCap",lpContext
);
3718 /***************************************************************************
3719 * DirectSoundCaptureEnumerateW [DSOUND.8]
3721 * Enumerate all DirectSound drivers installed in the system
3725 * Failure: DSERR_INVALIDPARAM
3727 HRESULT WINAPI
DirectSoundCaptureEnumerateW(
3728 LPDSENUMCALLBACKW lpDSEnumCallback
,
3731 FIXME("(%p,%p):stub\n", lpDSEnumCallback
, lpContext
);
3736 DSOUND_CreateDirectSoundCapture( LPVOID
* ppobj
)
3738 *ppobj
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof( IDirectSoundCaptureImpl
) );
3740 if ( *ppobj
== NULL
) {
3741 return DSERR_OUTOFMEMORY
;
3745 ICOM_THIS(IDirectSoundCaptureImpl
,*ppobj
);
3748 ICOM_VTBL(This
) = &dscvt
;
3750 InitializeCriticalSection( &This
->lock
);
3756 static HRESULT WINAPI
3757 IDirectSoundCaptureImpl_QueryInterface(
3758 LPDIRECTSOUNDCAPTURE iface
,
3762 ICOM_THIS(IDirectSoundCaptureImpl
,iface
);
3764 FIXME( "(%p)->(%s,%p): stub\n", This
, debugstr_guid(riid
), ppobj
);
3770 IDirectSoundCaptureImpl_AddRef( LPDIRECTSOUNDCAPTURE iface
)
3773 ICOM_THIS(IDirectSoundCaptureImpl
,iface
);
3775 EnterCriticalSection( &This
->lock
);
3777 TRACE( "(%p) was 0x%08lx\n", This
, This
->ref
);
3778 uRef
= ++(This
->ref
);
3780 LeaveCriticalSection( &This
->lock
);
3786 IDirectSoundCaptureImpl_Release( LPDIRECTSOUNDCAPTURE iface
)
3789 ICOM_THIS(IDirectSoundCaptureImpl
,iface
);
3791 EnterCriticalSection( &This
->lock
);
3793 TRACE( "(%p) was 0x%08lx\n", This
, This
->ref
);
3794 uRef
= --(This
->ref
);
3796 LeaveCriticalSection( &This
->lock
);
3799 DeleteCriticalSection( &This
->lock
);
3800 HeapFree( GetProcessHeap(), 0, This
);
3806 static HRESULT WINAPI
3807 IDirectSoundCaptureImpl_CreateCaptureBuffer(
3808 LPDIRECTSOUNDCAPTURE iface
,
3809 LPCDSCBUFFERDESC lpcDSCBufferDesc
,
3810 LPDIRECTSOUNDCAPTUREBUFFER
* lplpDSCaptureBuffer
,
3814 ICOM_THIS(IDirectSoundCaptureImpl
,iface
);
3816 TRACE( "(%p)->(%p,%p,%p)\n", This
, lpcDSCBufferDesc
, lplpDSCaptureBuffer
, pUnk
);
3819 return DSERR_INVALIDPARAM
;
3822 hr
= DSOUND_CreateDirectSoundCaptureBuffer( lpcDSCBufferDesc
, (LPVOID
*)lplpDSCaptureBuffer
);
3827 static HRESULT WINAPI
3828 IDirectSoundCaptureImpl_GetCaps(
3829 LPDIRECTSOUNDCAPTURE iface
,
3830 LPDSCCAPS lpDSCCaps
)
3832 ICOM_THIS(IDirectSoundCaptureImpl
,iface
);
3834 FIXME( "(%p)->(%p): stub\n", This
, lpDSCCaps
);
3839 static HRESULT WINAPI
3840 IDirectSoundCaptureImpl_Initialize(
3841 LPDIRECTSOUNDCAPTURE iface
,
3844 ICOM_THIS(IDirectSoundCaptureImpl
,iface
);
3846 FIXME( "(%p)->(%p): stub\n", This
, lpcGUID
);
3852 static ICOM_VTABLE(IDirectSoundCapture
) dscvt
=
3854 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
3855 /* IUnknown methods */
3856 IDirectSoundCaptureImpl_QueryInterface
,
3857 IDirectSoundCaptureImpl_AddRef
,
3858 IDirectSoundCaptureImpl_Release
,
3860 /* IDirectSoundCapture methods */
3861 IDirectSoundCaptureImpl_CreateCaptureBuffer
,
3862 IDirectSoundCaptureImpl_GetCaps
,
3863 IDirectSoundCaptureImpl_Initialize
3867 DSOUND_CreateDirectSoundCaptureBuffer( LPCDSCBUFFERDESC lpcDSCBufferDesc
, LPVOID
* ppobj
)
3870 FIXME( "(%p,%p): ignoring lpcDSCBufferDesc\n", lpcDSCBufferDesc
, ppobj
);
3872 *ppobj
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof( IDirectSoundCaptureBufferImpl
) );
3874 if ( *ppobj
== NULL
) {
3875 return DSERR_OUTOFMEMORY
;
3879 ICOM_THIS(IDirectSoundCaptureBufferImpl
,*ppobj
);
3882 ICOM_VTBL(This
) = &dscbvt
;
3884 InitializeCriticalSection( &This
->lock
);
3891 static HRESULT WINAPI
3892 IDirectSoundCaptureBufferImpl_QueryInterface(
3893 LPDIRECTSOUNDCAPTUREBUFFER iface
,
3897 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
3899 FIXME( "(%p)->(%s,%p): stub\n", This
, debugstr_guid(riid
), ppobj
);
3905 IDirectSoundCaptureBufferImpl_AddRef( LPDIRECTSOUNDCAPTUREBUFFER iface
)
3908 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
3910 EnterCriticalSection( &This
->lock
);
3912 TRACE( "(%p) was 0x%08lx\n", This
, This
->ref
);
3913 uRef
= ++(This
->ref
);
3915 LeaveCriticalSection( &This
->lock
);
3921 IDirectSoundCaptureBufferImpl_Release( LPDIRECTSOUNDCAPTUREBUFFER iface
)
3924 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
3926 EnterCriticalSection( &This
->lock
);
3928 TRACE( "(%p) was 0x%08lx\n", This
, This
->ref
);
3929 uRef
= --(This
->ref
);
3931 LeaveCriticalSection( &This
->lock
);
3934 DeleteCriticalSection( &This
->lock
);
3935 HeapFree( GetProcessHeap(), 0, This
);
3941 static HRESULT WINAPI
3942 IDirectSoundCaptureBufferImpl_GetCaps(
3943 LPDIRECTSOUNDCAPTUREBUFFER iface
,
3944 LPDSCBCAPS lpDSCBCaps
)
3946 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
3948 FIXME( "(%p)->(%p): stub\n", This
, lpDSCBCaps
);
3953 static HRESULT WINAPI
3954 IDirectSoundCaptureBufferImpl_GetCurrentPosition(
3955 LPDIRECTSOUNDCAPTUREBUFFER iface
,
3956 LPDWORD lpdwCapturePosition
,
3957 LPDWORD lpdwReadPosition
)
3959 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
3961 FIXME( "(%p)->(%p,%p): stub\n", This
, lpdwCapturePosition
, lpdwReadPosition
);
3966 static HRESULT WINAPI
3967 IDirectSoundCaptureBufferImpl_GetFormat(
3968 LPDIRECTSOUNDCAPTUREBUFFER iface
,
3969 LPWAVEFORMATEX lpwfxFormat
,
3970 DWORD dwSizeAllocated
,
3971 LPDWORD lpdwSizeWritten
)
3973 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
3975 FIXME( "(%p)->(%p,0x%08lx,%p): stub\n", This
, lpwfxFormat
, dwSizeAllocated
, lpdwSizeWritten
);
3980 static HRESULT WINAPI
3981 IDirectSoundCaptureBufferImpl_GetStatus(
3982 LPDIRECTSOUNDCAPTUREBUFFER iface
,
3983 LPDWORD lpdwStatus
)
3985 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
3987 FIXME( "(%p)->(%p): stub\n", This
, lpdwStatus
);
3992 static HRESULT WINAPI
3993 IDirectSoundCaptureBufferImpl_Initialize(
3994 LPDIRECTSOUNDCAPTUREBUFFER iface
,
3995 LPDIRECTSOUNDCAPTURE lpDSC
,
3996 LPCDSCBUFFERDESC lpcDSCBDesc
)
3998 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
4000 FIXME( "(%p)->(%p,%p): stub\n", This
, lpDSC
, lpcDSCBDesc
);
4005 static HRESULT WINAPI
4006 IDirectSoundCaptureBufferImpl_Lock(
4007 LPDIRECTSOUNDCAPTUREBUFFER iface
,
4010 LPVOID
* lplpvAudioPtr1
,
4011 LPDWORD lpdwAudioBytes1
,
4012 LPVOID
* lplpvAudioPtr2
,
4013 LPDWORD lpdwAudioBytes2
,
4016 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
4018 FIXME( "(%p)->(%08lu,%08lu,%p,%p,%p,%p,0x%08lx): stub\n", This
, dwReadCusor
, dwReadBytes
, lplpvAudioPtr1
, lpdwAudioBytes1
, lplpvAudioPtr2
, lpdwAudioBytes2
, dwFlags
);
4023 static HRESULT WINAPI
4024 IDirectSoundCaptureBufferImpl_Start(
4025 LPDIRECTSOUNDCAPTUREBUFFER iface
,
4028 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
4030 FIXME( "(%p)->(0x%08lx): stub\n", This
, dwFlags
);
4035 static HRESULT WINAPI
4036 IDirectSoundCaptureBufferImpl_Stop( LPDIRECTSOUNDCAPTUREBUFFER iface
)
4038 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
4040 FIXME( "(%p): stub\n", This
);
4045 static HRESULT WINAPI
4046 IDirectSoundCaptureBufferImpl_Unlock(
4047 LPDIRECTSOUNDCAPTUREBUFFER iface
,
4048 LPVOID lpvAudioPtr1
,
4049 DWORD dwAudioBytes1
,
4050 LPVOID lpvAudioPtr2
,
4051 DWORD dwAudioBytes2
)
4053 ICOM_THIS(IDirectSoundCaptureBufferImpl
,iface
);
4055 FIXME( "(%p)->(%p,%08lu,%p,%08lu): stub\n", This
, lpvAudioPtr1
, dwAudioBytes1
, lpvAudioPtr2
, dwAudioBytes2
);
4061 static ICOM_VTABLE(IDirectSoundCaptureBuffer
) dscbvt
=
4063 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
4064 /* IUnknown methods */
4065 IDirectSoundCaptureBufferImpl_QueryInterface
,
4066 IDirectSoundCaptureBufferImpl_AddRef
,
4067 IDirectSoundCaptureBufferImpl_Release
,
4069 /* IDirectSoundCaptureBuffer methods */
4070 IDirectSoundCaptureBufferImpl_GetCaps
,
4071 IDirectSoundCaptureBufferImpl_GetCurrentPosition
,
4072 IDirectSoundCaptureBufferImpl_GetFormat
,
4073 IDirectSoundCaptureBufferImpl_GetStatus
,
4074 IDirectSoundCaptureBufferImpl_Initialize
,
4075 IDirectSoundCaptureBufferImpl_Lock
,
4076 IDirectSoundCaptureBufferImpl_Start
,
4077 IDirectSoundCaptureBufferImpl_Stop
,
4078 IDirectSoundCaptureBufferImpl_Unlock
4081 /*******************************************************************************
4082 * DirectSound ClassFactory
4086 /* IUnknown fields */
4087 ICOM_VFIELD(IClassFactory
);
4089 } IClassFactoryImpl
;
4091 static HRESULT WINAPI
4092 DSCF_QueryInterface(LPCLASSFACTORY iface
,REFIID riid
,LPVOID
*ppobj
) {
4093 ICOM_THIS(IClassFactoryImpl
,iface
);
4095 FIXME("(%p)->(%s,%p),stub!\n",This
,debugstr_guid(riid
),ppobj
);
4096 return E_NOINTERFACE
;
4100 DSCF_AddRef(LPCLASSFACTORY iface
) {
4101 ICOM_THIS(IClassFactoryImpl
,iface
);
4102 return ++(This
->ref
);
4105 static ULONG WINAPI
DSCF_Release(LPCLASSFACTORY iface
) {
4106 ICOM_THIS(IClassFactoryImpl
,iface
);
4107 /* static class, won't be freed */
4108 return --(This
->ref
);
4111 static HRESULT WINAPI
DSCF_CreateInstance(
4112 LPCLASSFACTORY iface
,LPUNKNOWN pOuter
,REFIID riid
,LPVOID
*ppobj
4114 ICOM_THIS(IClassFactoryImpl
,iface
);
4116 TRACE("(%p)->(%p,%s,%p)\n",This
,pOuter
,debugstr_guid(riid
),ppobj
);
4117 if ( IsEqualGUID( &IID_IDirectSound
, riid
) ) {
4118 /* FIXME: reuse already created dsound if present? */
4119 return DirectSoundCreate(riid
,(LPDIRECTSOUND
*)ppobj
,pOuter
);
4121 return E_NOINTERFACE
;
4124 static HRESULT WINAPI
DSCF_LockServer(LPCLASSFACTORY iface
,BOOL dolock
) {
4125 ICOM_THIS(IClassFactoryImpl
,iface
);
4126 FIXME("(%p)->(%d),stub!\n",This
,dolock
);
4130 static ICOM_VTABLE(IClassFactory
) DSCF_Vtbl
= {
4131 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
4132 DSCF_QueryInterface
,
4135 DSCF_CreateInstance
,
4138 static IClassFactoryImpl DSOUND_CF
= {&DSCF_Vtbl
, 1 };
4140 /*******************************************************************************
4141 * DllGetClassObject [DSOUND.5]
4142 * Retrieves class object from a DLL object
4145 * Docs say returns STDAPI
4148 * rclsid [I] CLSID for the class object
4149 * riid [I] Reference to identifier of interface for class object
4150 * ppv [O] Address of variable to receive interface pointer for riid
4154 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
4157 DWORD WINAPI
DSOUND_DllGetClassObject(REFCLSID rclsid
,REFIID riid
,LPVOID
*ppv
)
4159 TRACE("(%p,%p,%p)\n", debugstr_guid(rclsid
), debugstr_guid(riid
), ppv
);
4160 if ( IsEqualCLSID( &IID_IClassFactory
, riid
) ) {
4161 *ppv
= (LPVOID
)&DSOUND_CF
;
4162 IClassFactory_AddRef((IClassFactory
*)*ppv
);
4166 FIXME("(%p,%p,%p): no interface found.\n", debugstr_guid(rclsid
), debugstr_guid(riid
), ppv
);
4167 return CLASS_E_CLASSNOTAVAILABLE
;
4171 /*******************************************************************************
4172 * DllCanUnloadNow [DSOUND.4] Determines whether the DLL is in use.
4178 DWORD WINAPI
DSOUND_DllCanUnloadNow(void)
4180 FIXME("(void): stub\n");