3 * Copyright 1998 Marcus Meissner
4 * Copyright 1998 Rob Riggs
7 * Note: This file requires multithread ability. It is not possible to
8 * implement the stuff in a single thread anyway. And most DirectX apps
9 * require threading themselves.
11 * Most thread locking is complete. There may be a few race
12 * conditions still lurking.
14 * Tested with a Soundblaster clone, a Gravis UltraSound Classic,
15 * and a Turtle Beach Tropez+.
18 * Implement DirectSoundCapture API
19 * Implement SetCooperativeLevel properly (need to address focus issues)
20 * Use wavetable synth for static buffers if available
21 * Implement DirectSound3DBuffers (stubs in place)
22 * Use hardware 3D support if available (OSS support may be needed first)
23 * Add support for APIs other than OSS: ALSA (http://alsa.jcu.cz/)
24 * and esound (http://www.gnome.org), for instance
26 * FIXME: Status needs updating.
29 * - Wing Commander 4/W95:
30 * The intromovie plays without problems. Nearly lipsynchron.
32 * The sound works, but noticeable chunks are left out (from the sound and
33 * the animation). Don't know why yet.
35 * Sound works, but slows down the movieplayer.
39 * The background sound of the startscreen works ;)
40 * - WingCommander Prophecy Demo:
41 * Sound works for the intromovie.
42 * - Total Annihilation (1998/12/04):
43 * Sound plays perfectly in the game, but the Smacker movies
44 * (http://www.smacker.com/) play silently.
45 * - A-10 Cuba! Demo (1998/12/04):
46 * Sound works properly (for some people).
47 * - dsstream.exe, from DirectX 5.2 SDK (1998/12/04):
48 * Works properly, but requires "-dll -winmm".
49 * - dsshow.exe, from DirectX 5.2 SDK (1998/12/04):
50 * Initializes the DLL properly with CoCreateInstance(), but the
51 * FileOpen dialog box is broken - could not test properly
52 * - The Dilbert Desktop Game: works (SB16)
59 #include <sys/types.h>
61 #include <sys/fcntl.h>
65 #include <math.h> /* Insomnia - pow() function */
71 #include "wine/obj_base.h"
73 #include "debugtools.h"
75 DEFAULT_DEBUG_CHANNEL(dsound
);
78 /*****************************************************************************
79 * Predeclare the interface implementation structures
81 typedef struct IDirectSoundImpl IDirectSoundImpl
;
82 typedef struct IDirectSoundBufferImpl IDirectSoundBufferImpl
;
83 typedef struct IDirectSoundNotifyImpl IDirectSoundNotifyImpl
;
84 typedef struct IDirectSound3DListenerImpl IDirectSound3DListenerImpl
;
85 typedef struct IDirectSound3DBufferImpl IDirectSound3DBufferImpl
;
87 /*****************************************************************************
88 * IDirectSound implementation structure
90 struct IDirectSoundImpl
93 ICOM_VFIELD(IDirectSound
);
95 /* IDirectSoundImpl fields */
98 IDirectSoundBufferImpl
** buffers
;
99 IDirectSoundBufferImpl
* primary
;
100 IDirectSound3DListenerImpl
* listener
;
101 WAVEFORMATEX wfx
; /* current main waveformat */
102 CRITICAL_SECTION lock
;
105 /*****************************************************************************
106 * IDirectSoundBuffer implementation structure
108 struct IDirectSoundBufferImpl
110 /* IUnknown fields */
111 ICOM_VFIELD(IDirectSoundBuffer
);
113 /* IDirectSoundBufferImpl fields */
116 IDirectSound3DBufferImpl
* ds3db
;
117 DWORD playflags
,playing
;
118 DWORD playpos
,writepos
,buflen
;
119 DWORD nAvgBytesPerSec
;
123 LONG lVolAdjust
,rVolAdjust
;
124 IDirectSoundBufferImpl
* parent
; /* for duplicates */
125 IDirectSoundImpl
* dsound
;
127 LPDSBPOSITIONNOTIFY notifies
;
129 CRITICAL_SECTION lock
;
132 /*****************************************************************************
133 * IDirectSoundNotify implementation structure
135 struct IDirectSoundNotifyImpl
137 /* IUnknown fields */
138 ICOM_VFIELD(IDirectSoundNotify
);
140 /* IDirectSoundNotifyImpl fields */
141 IDirectSoundBufferImpl
* dsb
;
144 /*****************************************************************************
145 * IDirectSound3DListener implementation structure
147 struct IDirectSound3DListenerImpl
149 /* IUnknown fields */
150 ICOM_VFIELD(IDirectSound3DListener
);
152 /* IDirectSound3DListenerImpl fields */
153 IDirectSoundBufferImpl
* dsb
;
155 CRITICAL_SECTION lock
;
158 /*****************************************************************************
159 * IDirectSound3DBuffer implementation structure
161 struct IDirectSound3DBufferImpl
163 /* IUnknown fields */
164 ICOM_VFIELD(IDirectSound3DBuffer
);
166 /* IDirectSound3DBufferImpl fields */
167 IDirectSoundBufferImpl
* dsb
;
171 CRITICAL_SECTION lock
;
176 # include <sys/ioctl.h>
177 # ifdef HAVE_MACHINE_SOUNDCARD_H
178 # include <machine/soundcard.h>
180 # ifdef HAVE_SYS_SOUNDCARD_H
181 # include <sys/soundcard.h>
183 # ifdef HAVE_SOUNDCARD_H
184 # include <soundcard.h>
187 /* #define USE_DSOUND3D 1 */
189 #define DSOUND_FRAGLEN ((primarybuf->wfx.nAvgBytesPerSec >> 4) & ~3)
190 #define DSOUND_FREQSHIFT (14)
192 static int audiofd
= -1;
193 static int audioOK
= 0;
195 static IDirectSoundImpl
* dsound
= NULL
;
197 static IDirectSoundBufferImpl
* primarybuf
= NULL
;
199 static int DSOUND_setformat(LPWAVEFORMATEX wfex
);
200 static void DSOUND_CheckEvent(IDirectSoundBufferImpl
*dsb
, int len
);
201 static void DSOUND_CloseAudio(void);
205 /***************************************************************************
206 * DirectSoundEnumerateA [DSOUND.2]
208 * Enumerate all DirectSound drivers installed in the system
212 * Failure: DSERR_INVALIDPARAM
214 HRESULT WINAPI
DirectSoundEnumerateA(
215 LPDSENUMCALLBACKA lpDSEnumCallback
,
218 TRACE("lpDSEnumCallback = %p, lpContext = %p\n",
219 lpDSEnumCallback
, lpContext
);
222 if (lpDSEnumCallback
!= NULL
)
223 lpDSEnumCallback(NULL
,"WINE DirectSound using Open Sound System",
230 /***************************************************************************
231 * DirectSoundEnumerateW [DSOUND.3]
233 * Enumerate all DirectSound drivers installed in the system
237 * Failure: DSERR_INVALIDPARAM
239 HRESULT WINAPI
DirectSoundEnumerateW(
240 LPDSENUMCALLBACKW lpDSEnumCallback
,
243 FIXME("lpDSEnumCallback = %p, lpContext = %p: stub\n",
244 lpDSEnumCallback
, lpContext
);
251 static void _dump_DSBCAPS(DWORD xmask
) {
256 #define FE(x) { x, #x },
257 FE(DSBCAPS_PRIMARYBUFFER
)
259 FE(DSBCAPS_LOCHARDWARE
)
260 FE(DSBCAPS_LOCSOFTWARE
)
261 FE(DSBCAPS_CTRLFREQUENCY
)
263 FE(DSBCAPS_CTRLVOLUME
)
264 FE(DSBCAPS_CTRLDEFAULT
)
266 FE(DSBCAPS_STICKYFOCUS
)
267 FE(DSBCAPS_GETCURRENTPOSITION2
)
271 for (i
=0;i
<sizeof(flags
)/sizeof(flags
[0]);i
++)
272 if ((flags
[i
].mask
& xmask
) == flags
[i
].mask
)
273 DPRINTF("%s ",flags
[i
].name
);
276 /*******************************************************************************
277 * IDirectSound3DBuffer
280 /* IUnknown methods */
281 static HRESULT WINAPI
IDirectSound3DBufferImpl_QueryInterface(
282 LPDIRECTSOUND3DBUFFER iface
, REFIID riid
, LPVOID
*ppobj
)
284 ICOM_THIS(IDirectSound3DBufferImpl
,iface
);
286 TRACE("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
290 static ULONG WINAPI
IDirectSound3DBufferImpl_AddRef(LPDIRECTSOUND3DBUFFER iface
)
292 ICOM_THIS(IDirectSound3DBufferImpl
,iface
);
297 static ULONG WINAPI
IDirectSound3DBufferImpl_Release(LPDIRECTSOUND3DBUFFER iface
)
299 ICOM_THIS(IDirectSound3DBufferImpl
,iface
);
303 HeapFree(GetProcessHeap(),0,This
->buffer
);
304 HeapFree(GetProcessHeap(),0,This
);
309 /* IDirectSound3DBuffer methods */
310 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetAllParameters(
311 LPDIRECTSOUND3DBUFFER iface
,
312 LPDS3DBUFFER lpDs3dBuffer
)
318 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetConeAngles(
319 LPDIRECTSOUND3DBUFFER iface
,
320 LPDWORD lpdwInsideConeAngle
,
321 LPDWORD lpdwOutsideConeAngle
)
327 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetConeOrientation(
328 LPDIRECTSOUND3DBUFFER iface
,
329 LPD3DVECTOR lpvConeOrientation
)
335 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetConeOutsideVolume(
336 LPDIRECTSOUND3DBUFFER iface
,
337 LPLONG lplConeOutsideVolume
)
343 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetMaxDistance(
344 LPDIRECTSOUND3DBUFFER iface
,
345 LPD3DVALUE lpfMaxDistance
)
351 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetMinDistance(
352 LPDIRECTSOUND3DBUFFER iface
,
353 LPD3DVALUE lpfMinDistance
)
359 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetMode(
360 LPDIRECTSOUND3DBUFFER iface
,
367 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetPosition(
368 LPDIRECTSOUND3DBUFFER iface
,
369 LPD3DVECTOR lpvPosition
)
375 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetVelocity(
376 LPDIRECTSOUND3DBUFFER iface
,
377 LPD3DVECTOR lpvVelocity
)
383 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetAllParameters(
384 LPDIRECTSOUND3DBUFFER iface
,
385 LPCDS3DBUFFER lpcDs3dBuffer
,
392 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetConeAngles(
393 LPDIRECTSOUND3DBUFFER iface
,
394 DWORD dwInsideConeAngle
,
395 DWORD dwOutsideConeAngle
,
402 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetConeOrientation(
403 LPDIRECTSOUND3DBUFFER iface
,
404 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
411 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetConeOutsideVolume(
412 LPDIRECTSOUND3DBUFFER iface
,
413 LONG lConeOutsideVolume
,
420 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetMaxDistance(
421 LPDIRECTSOUND3DBUFFER iface
,
422 D3DVALUE fMaxDistance
,
429 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetMinDistance(
430 LPDIRECTSOUND3DBUFFER iface
,
431 D3DVALUE fMinDistance
,
438 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetMode(
439 LPDIRECTSOUND3DBUFFER iface
,
443 ICOM_THIS(IDirectSound3DBufferImpl
,iface
);
444 TRACE("mode = %lx\n", dwMode
);
445 This
->ds3db
.dwMode
= dwMode
;
449 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetPosition(
450 LPDIRECTSOUND3DBUFFER iface
,
451 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
458 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetVelocity(
459 LPDIRECTSOUND3DBUFFER iface
,
460 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
467 ICOM_VTABLE(IDirectSound3DBuffer
) ds3dbvt
=
469 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
470 /* IUnknown methods */
471 IDirectSound3DBufferImpl_QueryInterface
,
472 IDirectSound3DBufferImpl_AddRef
,
473 IDirectSound3DBufferImpl_Release
,
474 /* IDirectSound3DBuffer methods */
475 IDirectSound3DBufferImpl_GetAllParameters
,
476 IDirectSound3DBufferImpl_GetConeAngles
,
477 IDirectSound3DBufferImpl_GetConeOrientation
,
478 IDirectSound3DBufferImpl_GetConeOutsideVolume
,
479 IDirectSound3DBufferImpl_GetMaxDistance
,
480 IDirectSound3DBufferImpl_GetMinDistance
,
481 IDirectSound3DBufferImpl_GetMode
,
482 IDirectSound3DBufferImpl_GetPosition
,
483 IDirectSound3DBufferImpl_GetVelocity
,
484 IDirectSound3DBufferImpl_SetAllParameters
,
485 IDirectSound3DBufferImpl_SetConeAngles
,
486 IDirectSound3DBufferImpl_SetConeOrientation
,
487 IDirectSound3DBufferImpl_SetConeOutsideVolume
,
488 IDirectSound3DBufferImpl_SetMaxDistance
,
489 IDirectSound3DBufferImpl_SetMinDistance
,
490 IDirectSound3DBufferImpl_SetMode
,
491 IDirectSound3DBufferImpl_SetPosition
,
492 IDirectSound3DBufferImpl_SetVelocity
,
496 static int DSOUND_Create3DBuffer(IDirectSoundBufferImpl
* dsb
)
498 DWORD i
, temp
, iSize
, oSize
, offset
;
499 LPBYTE bIbuf
, bObuf
, bTbuf
= NULL
;
500 LPWORD wIbuf
, wObuf
, wTbuf
= NULL
;
502 /* Inside DirectX says it's stupid but allowed */
503 if (dsb
->wfx
.nChannels
== 2) {
504 /* Convert to mono */
505 if (dsb
->wfx
.wBitsPerSample
== 16) {
506 iSize
= dsb
->buflen
/ 4;
507 wTbuf
= malloc(dsb
->buflen
/ 2);
509 return DSERR_OUTOFMEMORY
;
510 for (i
= 0; i
< iSize
; i
++)
511 wTbuf
[i
] = (dsb
->buffer
[i
] + dsb
->buffer
[(i
* 2) + 1]) / 2;
514 iSize
= dsb
->buflen
/ 2;
515 bTbuf
= malloc(dsb
->buflen
/ 2);
517 return DSERR_OUTOFMEMORY
;
518 for (i
= 0; i
< iSize
; i
++)
519 bTbuf
[i
] = (dsb
->buffer
[i
] + dsb
->buffer
[(i
* 2) + 1]) / 2;
523 if (dsb
->wfx
.wBitsPerSample
== 16) {
524 iSize
= dsb
->buflen
/ 2;
525 wIbuf
= (LPWORD
) dsb
->buffer
;
527 bIbuf
= (LPBYTE
) dsb
->buffer
;
532 if (primarybuf
->wfx
.wBitsPerSample
== 16) {
533 wObuf
= (LPWORD
) dsb
->ds3db
->buffer
;
534 oSize
= dsb
->ds3db
->buflen
/ 2;
536 bObuf
= (LPBYTE
) dsb
->ds3db
->buffer
;
537 oSize
= dsb
->ds3db
->buflen
;
540 offset
= primarybuf
->wfx
.nSamplesPerSec
/ 100; /* 10ms */
541 if (primarybuf
->wfx
.wBitsPerSample
== 16 && dsb
->wfx
.wBitsPerSample
== 16)
542 for (i
= 0; i
< iSize
; i
++) {
545 temp
+= wIbuf
[i
- offset
] >> 9;
547 temp
+= wIbuf
[i
+ iSize
- offset
] >> 9;
549 wObuf
[(i
* 2) + 1] = temp
;
551 else if (primarybuf
->wfx
.wBitsPerSample
== 8 && dsb
->wfx
.wBitsPerSample
== 8)
552 for (i
= 0; i
< iSize
; i
++) {
555 temp
+= bIbuf
[i
- offset
] >> 5;
557 temp
+= bIbuf
[i
+ iSize
- offset
] >> 5;
559 bObuf
[(i
* 2) + 1] = temp
;
570 /*******************************************************************************
571 * IDirectSound3DListener
574 /* IUnknown methods */
575 static HRESULT WINAPI
IDirectSound3DListenerImpl_QueryInterface(
576 LPDIRECTSOUND3DLISTENER iface
, REFIID riid
, LPVOID
*ppobj
)
578 ICOM_THIS(IDirectSound3DListenerImpl
,iface
);
580 TRACE("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
584 static ULONG WINAPI
IDirectSound3DListenerImpl_AddRef(LPDIRECTSOUND3DLISTENER iface
)
586 ICOM_THIS(IDirectSound3DListenerImpl
,iface
);
591 static ULONG WINAPI
IDirectSound3DListenerImpl_Release(LPDIRECTSOUND3DLISTENER iface
)
594 ICOM_THIS(IDirectSound3DListenerImpl
,iface
);
596 ulReturn
= --This
->ref
;
598 /* Free all resources */
599 if( ulReturn
== 0 ) {
601 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)This
->dsb
);
602 HeapFree(GetProcessHeap(),0,This
);
608 /* IDirectSound3DListener methods */
609 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetAllParameter(
610 LPDIRECTSOUND3DLISTENER iface
,
611 LPDS3DLISTENER lpDS3DL
)
617 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetDistanceFactor(
618 LPDIRECTSOUND3DLISTENER iface
,
619 LPD3DVALUE lpfDistanceFactor
)
625 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetDopplerFactor(
626 LPDIRECTSOUND3DLISTENER iface
,
627 LPD3DVALUE lpfDopplerFactor
)
633 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetOrientation(
634 LPDIRECTSOUND3DLISTENER iface
,
635 LPD3DVECTOR lpvOrientFront
,
636 LPD3DVECTOR lpvOrientTop
)
642 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetPosition(
643 LPDIRECTSOUND3DLISTENER iface
,
644 LPD3DVECTOR lpvPosition
)
650 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetRolloffFactor(
651 LPDIRECTSOUND3DLISTENER iface
,
652 LPD3DVALUE lpfRolloffFactor
)
658 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetVelocity(
659 LPDIRECTSOUND3DLISTENER iface
,
660 LPD3DVECTOR lpvVelocity
)
666 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetAllParameters(
667 LPDIRECTSOUND3DLISTENER iface
,
668 LPCDS3DLISTENER lpcDS3DL
,
675 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetDistanceFactor(
676 LPDIRECTSOUND3DLISTENER iface
,
677 D3DVALUE fDistanceFactor
,
684 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetDopplerFactor(
685 LPDIRECTSOUND3DLISTENER iface
,
686 D3DVALUE fDopplerFactor
,
693 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetOrientation(
694 LPDIRECTSOUND3DLISTENER iface
,
695 D3DVALUE xFront
, D3DVALUE yFront
, D3DVALUE zFront
,
696 D3DVALUE xTop
, D3DVALUE yTop
, D3DVALUE zTop
,
703 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetPosition(
704 LPDIRECTSOUND3DLISTENER iface
,
705 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
712 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetRolloffFactor(
713 LPDIRECTSOUND3DLISTENER iface
,
714 D3DVALUE fRolloffFactor
,
721 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetVelocity(
722 LPDIRECTSOUND3DLISTENER iface
,
723 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
730 static HRESULT WINAPI
IDirectSound3DListenerImpl_CommitDeferredSettings(
731 LPDIRECTSOUND3DLISTENER iface
)
738 ICOM_VTABLE(IDirectSound3DListener
) ds3dlvt
=
740 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
741 /* IUnknown methods */
742 IDirectSound3DListenerImpl_QueryInterface
,
743 IDirectSound3DListenerImpl_AddRef
,
744 IDirectSound3DListenerImpl_Release
,
745 /* IDirectSound3DListener methods */
746 IDirectSound3DListenerImpl_GetAllParameter
,
747 IDirectSound3DListenerImpl_GetDistanceFactor
,
748 IDirectSound3DListenerImpl_GetDopplerFactor
,
749 IDirectSound3DListenerImpl_GetOrientation
,
750 IDirectSound3DListenerImpl_GetPosition
,
751 IDirectSound3DListenerImpl_GetRolloffFactor
,
752 IDirectSound3DListenerImpl_GetVelocity
,
753 IDirectSound3DListenerImpl_SetAllParameters
,
754 IDirectSound3DListenerImpl_SetDistanceFactor
,
755 IDirectSound3DListenerImpl_SetDopplerFactor
,
756 IDirectSound3DListenerImpl_SetOrientation
,
757 IDirectSound3DListenerImpl_SetPosition
,
758 IDirectSound3DListenerImpl_SetRolloffFactor
,
759 IDirectSound3DListenerImpl_SetVelocity
,
760 IDirectSound3DListenerImpl_CommitDeferredSettings
,
763 /*******************************************************************************
766 static HRESULT WINAPI
IDirectSoundNotifyImpl_QueryInterface(
767 LPDIRECTSOUNDNOTIFY iface
,REFIID riid
,LPVOID
*ppobj
769 ICOM_THIS(IDirectSoundNotifyImpl
,iface
);
771 TRACE("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
775 static ULONG WINAPI
IDirectSoundNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface
) {
776 ICOM_THIS(IDirectSoundNotifyImpl
,iface
);
777 return ++(This
->ref
);
780 static ULONG WINAPI
IDirectSoundNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface
) {
781 ICOM_THIS(IDirectSoundNotifyImpl
,iface
);
784 IDirectSoundNotify_Release((LPDIRECTSOUNDBUFFER
)This
->dsb
);
785 HeapFree(GetProcessHeap(),0,This
);
791 static HRESULT WINAPI
IDirectSoundNotifyImpl_SetNotificationPositions(
792 LPDIRECTSOUNDNOTIFY iface
,DWORD howmuch
,LPCDSBPOSITIONNOTIFY notify
794 ICOM_THIS(IDirectSoundNotifyImpl
,iface
);
797 if (TRACE_ON(dsound
)) {
798 TRACE("(%p,0x%08lx,%p)\n",This
,howmuch
,notify
);
799 for (i
=0;i
<howmuch
;i
++)
800 TRACE("notify at %ld to 0x%08lx\n",
801 notify
[i
].dwOffset
,(DWORD
)notify
[i
].hEventNotify
);
803 This
->dsb
->notifies
= HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,This
->dsb
->notifies
,(This
->dsb
->nrofnotifies
+howmuch
)*sizeof(DSBPOSITIONNOTIFY
));
804 memcpy( This
->dsb
->notifies
+This
->dsb
->nrofnotifies
,
806 howmuch
*sizeof(DSBPOSITIONNOTIFY
)
808 This
->dsb
->nrofnotifies
+=howmuch
;
813 ICOM_VTABLE(IDirectSoundNotify
) dsnvt
=
815 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
816 IDirectSoundNotifyImpl_QueryInterface
,
817 IDirectSoundNotifyImpl_AddRef
,
818 IDirectSoundNotifyImpl_Release
,
819 IDirectSoundNotifyImpl_SetNotificationPositions
,
822 /*******************************************************************************
826 /* This sets this format for the <em>Primary Buffer Only</em> */
827 /* See file:///cdrom/sdk52/docs/worddoc/dsound.doc page 120 */
828 static HRESULT WINAPI
IDirectSoundBufferImpl_SetFormat(
829 LPDIRECTSOUNDBUFFER iface
,LPWAVEFORMATEX wfex
831 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
832 IDirectSoundBufferImpl
** dsb
;
835 /* Let's be pedantic! */
836 if ((wfex
== NULL
) ||
837 (wfex
->wFormatTag
!= WAVE_FORMAT_PCM
) ||
838 (wfex
->nChannels
< 1) || (wfex
->nChannels
> 2) ||
839 (wfex
->nSamplesPerSec
< 1) ||
840 (wfex
->nBlockAlign
< 1) || (wfex
->nChannels
> 4) ||
841 ((wfex
->wBitsPerSample
!= 8) && (wfex
->wBitsPerSample
!= 16))) {
842 TRACE("failed pedantic check!\n");
843 return DSERR_INVALIDPARAM
;
847 EnterCriticalSection(&(This
->dsound
->lock
));
849 if (primarybuf
->wfx
.nSamplesPerSec
!= wfex
->nSamplesPerSec
) {
850 dsb
= dsound
->buffers
;
851 for (i
= 0; i
< dsound
->nrofbuffers
; i
++, dsb
++) {
853 EnterCriticalSection(&((*dsb
)->lock
));
855 (*dsb
)->freqAdjust
= ((*dsb
)->freq
<< DSOUND_FREQSHIFT
) /
856 wfex
->nSamplesPerSec
;
858 LeaveCriticalSection(&((*dsb
)->lock
));
863 memcpy(&(primarybuf
->wfx
), wfex
, sizeof(primarybuf
->wfx
));
865 TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld"
866 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
867 wfex
->wFormatTag
, wfex
->nChannels
, wfex
->nSamplesPerSec
,
868 wfex
->nAvgBytesPerSec
, wfex
->nBlockAlign
,
869 wfex
->wBitsPerSample
, wfex
->cbSize
);
871 primarybuf
->wfx
.nAvgBytesPerSec
=
872 This
->wfx
.nSamplesPerSec
* This
->wfx
.nBlockAlign
;
875 LeaveCriticalSection(&(This
->dsound
->lock
));
881 static HRESULT WINAPI
IDirectSoundBufferImpl_SetVolume(
882 LPDIRECTSOUNDBUFFER iface
,LONG vol
884 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
887 TRACE("(%p,%ld)\n",This
,vol
);
889 /* I'm not sure if we need this for primary buffer */
890 if (!(This
->dsbd
.dwFlags
& DSBCAPS_CTRLVOLUME
))
891 return DSERR_CONTROLUNAVAIL
;
893 if ((vol
> DSBVOLUME_MAX
) || (vol
< DSBVOLUME_MIN
))
894 return DSERR_INVALIDPARAM
;
896 /* This needs to adjust the soundcard volume when */
897 /* called for the primary buffer */
898 if (This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
899 FIXME("Volume control of primary unimplemented.\n");
905 EnterCriticalSection(&(This
->lock
));
909 temp
= (double) (This
->volume
- (This
->pan
> 0 ? This
->pan
: 0));
910 This
->lVolAdjust
= (ULONG
) (pow(2.0, temp
/ 600.0) * 32768.0);
911 temp
= (double) (This
->volume
+ (This
->pan
< 0 ? This
->pan
: 0));
912 This
->rVolAdjust
= (ULONG
) (pow(2.0, temp
/ 600.0) * 32768.0);
914 LeaveCriticalSection(&(This
->lock
));
917 TRACE("left = %lx, right = %lx\n", This
->lVolAdjust
, This
->rVolAdjust
);
922 static HRESULT WINAPI
IDirectSoundBufferImpl_GetVolume(
923 LPDIRECTSOUNDBUFFER iface
,LPLONG vol
925 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
926 TRACE("(%p,%p)\n",This
,vol
);
929 return DSERR_INVALIDPARAM
;
935 static HRESULT WINAPI
IDirectSoundBufferImpl_SetFrequency(
936 LPDIRECTSOUNDBUFFER iface
,DWORD freq
938 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
939 TRACE("(%p,%ld)\n",This
,freq
);
941 /* You cannot set the frequency of the primary buffer */
942 if (!(This
->dsbd
.dwFlags
& DSBCAPS_CTRLFREQUENCY
) ||
943 (This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
))
944 return DSERR_CONTROLUNAVAIL
;
946 if ((freq
< DSBFREQUENCY_MIN
) || (freq
> DSBFREQUENCY_MAX
))
947 return DSERR_INVALIDPARAM
;
950 EnterCriticalSection(&(This
->lock
));
953 This
->freqAdjust
= (freq
<< DSOUND_FREQSHIFT
) / primarybuf
->wfx
.nSamplesPerSec
;
954 This
->nAvgBytesPerSec
= freq
* This
->wfx
.nBlockAlign
;
956 LeaveCriticalSection(&(This
->lock
));
962 static HRESULT WINAPI
IDirectSoundBufferImpl_Play(
963 LPDIRECTSOUNDBUFFER iface
,DWORD reserved1
,DWORD reserved2
,DWORD flags
965 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
966 TRACE("(%p,%08lx,%08lx,%08lx)\n",
967 This
,reserved1
,reserved2
,flags
969 This
->playflags
= flags
;
974 static HRESULT WINAPI
IDirectSoundBufferImpl_Stop(LPDIRECTSOUNDBUFFER iface
)
976 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
977 TRACE("(%p)\n",This
);
980 EnterCriticalSection(&(This
->lock
));
983 DSOUND_CheckEvent(This
, 0);
985 LeaveCriticalSection(&(This
->lock
));
991 static DWORD WINAPI
IDirectSoundBufferImpl_AddRef(LPDIRECTSOUNDBUFFER iface
) {
992 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
993 /* TRACE("(%p) ref was %ld\n",This, This->ref); */
995 return ++(This
->ref
);
997 static DWORD WINAPI
IDirectSoundBufferImpl_Release(LPDIRECTSOUNDBUFFER iface
) {
998 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1001 /* TRACE("(%p) ref was %ld\n",This, This->ref); */
1006 EnterCriticalSection(&(This
->dsound
->lock
));
1007 for (i
=0;i
<This
->dsound
->nrofbuffers
;i
++)
1008 if (This
->dsound
->buffers
[i
] == This
)
1010 if (i
< This
->dsound
->nrofbuffers
) {
1011 /* Put the last buffer of the list in the (now empty) position */
1012 This
->dsound
->buffers
[i
] = This
->dsound
->buffers
[This
->dsound
->nrofbuffers
- 1];
1013 This
->dsound
->buffers
= HeapReAlloc(GetProcessHeap(),0,This
->dsound
->buffers
,sizeof(LPDIRECTSOUNDBUFFER
)*This
->dsound
->nrofbuffers
);
1014 This
->dsound
->nrofbuffers
--;
1015 IDirectSound_Release((LPDIRECTSOUND
)This
->dsound
);
1017 LeaveCriticalSection(&(This
->dsound
->lock
));
1019 DeleteCriticalSection(&(This
->lock
));
1020 if (This
->ds3db
&& ICOM_VTBL(This
->ds3db
))
1021 IDirectSound3DBuffer_Release((LPDIRECTSOUND3DBUFFER
)This
->ds3db
);
1023 /* this is a duplicate buffer */
1024 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)This
->parent
);
1026 /* this is a toplevel buffer */
1027 HeapFree(GetProcessHeap(),0,This
->buffer
);
1029 HeapFree(GetProcessHeap(),0,This
);
1031 if (This
== primarybuf
)
1037 static HRESULT WINAPI
IDirectSoundBufferImpl_GetCurrentPosition(
1038 LPDIRECTSOUNDBUFFER iface
,LPDWORD playpos
,LPDWORD writepos
1040 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1041 TRACE("(%p,%p,%p)\n",This
,playpos
,writepos
);
1042 if (playpos
) *playpos
= This
->playpos
;
1043 if (writepos
) *writepos
= This
->writepos
;
1044 TRACE("playpos = %ld, writepos = %ld\n", playpos
?*playpos
:0, writepos
?*writepos
:0);
1048 static HRESULT WINAPI
IDirectSoundBufferImpl_GetStatus(
1049 LPDIRECTSOUNDBUFFER iface
,LPDWORD status
1051 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1052 TRACE("(%p,%p)\n",This
,status
);
1055 return DSERR_INVALIDPARAM
;
1059 *status
|= DSBSTATUS_PLAYING
;
1060 if (This
->playflags
& DSBPLAY_LOOPING
)
1061 *status
|= DSBSTATUS_LOOPING
;
1067 static HRESULT WINAPI
IDirectSoundBufferImpl_GetFormat(
1068 LPDIRECTSOUNDBUFFER iface
,LPWAVEFORMATEX lpwf
,DWORD wfsize
,LPDWORD wfwritten
1070 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1071 TRACE("(%p,%p,%ld,%p)\n",This
,lpwf
,wfsize
,wfwritten
);
1073 if (wfsize
>sizeof(This
->wfx
))
1074 wfsize
= sizeof(This
->wfx
);
1075 if (lpwf
) { /* NULL is valid */
1076 memcpy(lpwf
,&(This
->wfx
),wfsize
);
1078 *wfwritten
= wfsize
;
1081 *wfwritten
= sizeof(This
->wfx
);
1083 return DSERR_INVALIDPARAM
;
1088 static HRESULT WINAPI
IDirectSoundBufferImpl_Lock(
1089 LPDIRECTSOUNDBUFFER iface
,DWORD writecursor
,DWORD writebytes
,LPVOID lplpaudioptr1
,LPDWORD audiobytes1
,LPVOID lplpaudioptr2
,LPDWORD audiobytes2
,DWORD flags
1091 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1093 TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx)\n",
1103 if (flags
& DSBLOCK_FROMWRITECURSOR
)
1104 writecursor
+= This
->writepos
;
1105 if (flags
& DSBLOCK_ENTIREBUFFER
)
1106 writebytes
= This
->buflen
;
1107 if (writebytes
> This
->buflen
)
1108 writebytes
= This
->buflen
;
1110 assert(audiobytes1
!=audiobytes2
);
1111 assert(lplpaudioptr1
!=lplpaudioptr2
);
1112 if (writecursor
+writebytes
<= This
->buflen
) {
1113 *(LPBYTE
*)lplpaudioptr1
= This
->buffer
+writecursor
;
1114 *audiobytes1
= writebytes
;
1116 *(LPBYTE
*)lplpaudioptr2
= NULL
;
1119 TRACE("->%ld.0\n",writebytes
);
1121 *(LPBYTE
*)lplpaudioptr1
= This
->buffer
+writecursor
;
1122 *audiobytes1
= This
->buflen
-writecursor
;
1124 *(LPBYTE
*)lplpaudioptr2
= This
->buffer
;
1126 *audiobytes2
= writebytes
-(This
->buflen
-writecursor
);
1127 TRACE("->%ld.%ld\n",*audiobytes1
,audiobytes2
?*audiobytes2
:0);
1129 /* No. See file:///cdrom/sdk52/docs/worddoc/dsound.doc page 21 */
1130 /* This->writepos=(writecursor+writebytes)%This->buflen; */
1134 static HRESULT WINAPI
IDirectSoundBufferImpl_SetCurrentPosition(
1135 LPDIRECTSOUNDBUFFER iface
,DWORD newpos
1137 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1138 TRACE("(%p,%ld)\n",This
,newpos
);
1141 EnterCriticalSection(&(This
->lock
));
1143 This
->playpos
= newpos
;
1145 LeaveCriticalSection(&(This
->lock
));
1151 static HRESULT WINAPI
IDirectSoundBufferImpl_SetPan(
1152 LPDIRECTSOUNDBUFFER iface
,LONG pan
1154 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1157 TRACE("(%p,%ld)\n",This
,pan
);
1159 if ((pan
> DSBPAN_RIGHT
) || (pan
< DSBPAN_LEFT
))
1160 return DSERR_INVALIDPARAM
;
1162 /* You cannot set the pan of the primary buffer */
1163 /* and you cannot use both pan and 3D controls */
1164 if (!(This
->dsbd
.dwFlags
& DSBCAPS_CTRLPAN
) ||
1165 (This
->dsbd
.dwFlags
& DSBCAPS_CTRL3D
) ||
1166 (This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
))
1167 return DSERR_CONTROLUNAVAIL
;
1170 EnterCriticalSection(&(This
->lock
));
1174 temp
= (double) (This
->volume
- (This
->pan
> 0 ? This
->pan
: 0));
1175 This
->lVolAdjust
= (ULONG
) (pow(2.0, temp
/ 600.0) * 32768.0);
1176 temp
= (double) (This
->volume
+ (This
->pan
< 0 ? This
->pan
: 0));
1177 This
->rVolAdjust
= (ULONG
) (pow(2.0, temp
/ 600.0) * 32768.0);
1179 LeaveCriticalSection(&(This
->lock
));
1185 static HRESULT WINAPI
IDirectSoundBufferImpl_GetPan(
1186 LPDIRECTSOUNDBUFFER iface
,LPLONG pan
1188 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1189 TRACE("(%p,%p)\n",This
,pan
);
1192 return DSERR_INVALIDPARAM
;
1199 static HRESULT WINAPI
IDirectSoundBufferImpl_Unlock(
1200 LPDIRECTSOUNDBUFFER iface
,LPVOID p1
,DWORD x1
,LPVOID p2
,DWORD x2
1202 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1203 TRACE("(%p,%p,%ld,%p,%ld):stub\n", This
,p1
,x1
,p2
,x2
);
1205 /* There is really nothing to do here. Should someone */
1206 /* choose to implement static buffers in hardware (by */
1207 /* using a wave table synth, for example) this is where */
1208 /* you'd want to do the loading. For software buffers, */
1209 /* which is what we currently use, we need do nothing. */
1212 /* It's also the place to pre-process 3D buffers... */
1214 /* This is highly experimental and liable to break things */
1215 if (This
->dsbd
.dwFlags
& DSBCAPS_CTRL3D
)
1216 DSOUND_Create3DBuffer(This
);
1222 static HRESULT WINAPI
IDirectSoundBufferImpl_GetFrequency(
1223 LPDIRECTSOUNDBUFFER iface
,LPDWORD freq
1225 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1226 TRACE("(%p,%p)\n",This
,freq
);
1229 return DSERR_INVALIDPARAM
;
1232 TRACE("-> %ld\n", *freq
);
1237 static HRESULT WINAPI
IDirectSoundBufferImpl_Initialize(
1238 LPDIRECTSOUNDBUFFER iface
,LPDIRECTSOUND dsound
,LPDSBUFFERDESC dbsd
1240 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1241 FIXME("(%p,%p,%p):stub\n",This
,dsound
,dbsd
);
1242 DPRINTF("Re-Init!!!\n");
1243 return DSERR_ALREADYINITIALIZED
;
1246 static HRESULT WINAPI
IDirectSoundBufferImpl_GetCaps(
1247 LPDIRECTSOUNDBUFFER iface
,LPDSBCAPS caps
1249 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1250 TRACE("(%p)->(%p)\n",This
,caps
);
1253 return DSERR_INVALIDPARAM
;
1255 /* I think we should check this value, not set it. See */
1256 /* Inside DirectX, p215. That should apply here, too. */
1257 caps
->dwSize
= sizeof(*caps
);
1259 caps
->dwFlags
= This
->dsbd
.dwFlags
| DSBCAPS_LOCSOFTWARE
;
1260 caps
->dwBufferBytes
= This
->dsbd
.dwBufferBytes
;
1261 /* This value represents the speed of the "unlock" command.
1262 As unlock is quite fast (it does not do anything), I put
1263 4096 ko/s = 4 Mo / s */
1264 caps
->dwUnlockTransferRate
= 4096;
1265 caps
->dwPlayCpuOverhead
= 0;
1270 static HRESULT WINAPI
IDirectSoundBufferImpl_QueryInterface(
1271 LPDIRECTSOUNDBUFFER iface
,REFIID riid
,LPVOID
*ppobj
1273 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1275 TRACE("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
1277 if ( IsEqualGUID( &IID_IDirectSoundNotify
, riid
) ) {
1278 IDirectSoundNotifyImpl
*dsn
;
1280 dsn
= (IDirectSoundNotifyImpl
*)HeapAlloc(GetProcessHeap(),0,sizeof(*dsn
));
1283 IDirectSoundBuffer_AddRef(iface
);
1284 ICOM_VTBL(dsn
) = &dsnvt
;
1285 *ppobj
= (LPVOID
)dsn
;
1289 if ( IsEqualGUID( &IID_IDirectSound3DBuffer
, riid
) ) {
1290 *ppobj
= This
->ds3db
;
1292 IDirectSound3DBuffer_AddRef((LPDIRECTSOUND3DBUFFER
)This
->ds3db
);
1297 if ( IsEqualGUID( &IID_IDirectSound3DListener
, riid
) ) {
1298 IDirectSound3DListenerImpl
* dsl
;
1300 if (This
->dsound
->listener
) {
1301 *ppobj
= This
->dsound
->listener
;
1302 IDirectSound3DListener_AddRef((LPDIRECTSOUND3DLISTENER
)This
->dsound
->listener
);
1306 dsl
= (IDirectSound3DListenerImpl
*)HeapAlloc(GetProcessHeap(),0,sizeof(*dsl
));
1308 ICOM_VTBL(dsl
) = &ds3dlvt
;
1309 *ppobj
= (LPVOID
)dsl
;
1312 IDirectSoundBuffer_AddRef(iface
);
1314 This
->dsound
->listener
= dsl
;
1315 IDirectSound3DListener_AddRef((LPDIRECTSOUND3DLISTENER
)dsl
);
1320 FIXME( "Unknown GUID %s\n", debugstr_guid( riid
) );
1325 static ICOM_VTABLE(IDirectSoundBuffer
) dsbvt
=
1327 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1328 IDirectSoundBufferImpl_QueryInterface
,
1329 IDirectSoundBufferImpl_AddRef
,
1330 IDirectSoundBufferImpl_Release
,
1331 IDirectSoundBufferImpl_GetCaps
,
1332 IDirectSoundBufferImpl_GetCurrentPosition
,
1333 IDirectSoundBufferImpl_GetFormat
,
1334 IDirectSoundBufferImpl_GetVolume
,
1335 IDirectSoundBufferImpl_GetPan
,
1336 IDirectSoundBufferImpl_GetFrequency
,
1337 IDirectSoundBufferImpl_GetStatus
,
1338 IDirectSoundBufferImpl_Initialize
,
1339 IDirectSoundBufferImpl_Lock
,
1340 IDirectSoundBufferImpl_Play
,
1341 IDirectSoundBufferImpl_SetCurrentPosition
,
1342 IDirectSoundBufferImpl_SetFormat
,
1343 IDirectSoundBufferImpl_SetVolume
,
1344 IDirectSoundBufferImpl_SetPan
,
1345 IDirectSoundBufferImpl_SetFrequency
,
1346 IDirectSoundBufferImpl_Stop
,
1347 IDirectSoundBufferImpl_Unlock
1350 /*******************************************************************************
1354 static HRESULT WINAPI
IDirectSoundImpl_SetCooperativeLevel(
1355 LPDIRECTSOUND iface
,HWND hwnd
,DWORD level
1357 ICOM_THIS(IDirectSoundImpl
,iface
);
1359 FIXME("(%p,%08lx,%ld):stub\n",This
,(DWORD
)hwnd
,level
);
1361 This
->priolevel
= level
;
1366 static HRESULT WINAPI
IDirectSoundImpl_CreateSoundBuffer(
1367 LPDIRECTSOUND iface
,LPDSBUFFERDESC dsbd
,LPLPDIRECTSOUNDBUFFER ppdsb
,LPUNKNOWN lpunk
1369 ICOM_THIS(IDirectSoundImpl
,iface
);
1370 IDirectSoundBufferImpl
** ippdsb
=(IDirectSoundBufferImpl
**)ppdsb
;
1371 LPWAVEFORMATEX wfex
;
1373 TRACE("(%p,%p,%p,%p)\n",This
,dsbd
,ippdsb
,lpunk
);
1375 if ((This
== NULL
) || (dsbd
== NULL
) || (ippdsb
== NULL
))
1376 return DSERR_INVALIDPARAM
;
1378 if (TRACE_ON(dsound
)) {
1379 TRACE("(structsize=%ld)\n",dsbd
->dwSize
);
1380 TRACE("(flags=0x%08lx:\n",dsbd
->dwFlags
);
1381 _dump_DSBCAPS(dsbd
->dwFlags
);
1383 TRACE("(bufferbytes=%ld)\n",dsbd
->dwBufferBytes
);
1384 TRACE("(lpwfxFormat=%p)\n",dsbd
->lpwfxFormat
);
1387 wfex
= dsbd
->lpwfxFormat
;
1390 TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld,"
1391 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
1392 wfex
->wFormatTag
, wfex
->nChannels
, wfex
->nSamplesPerSec
,
1393 wfex
->nAvgBytesPerSec
, wfex
->nBlockAlign
,
1394 wfex
->wBitsPerSample
, wfex
->cbSize
);
1396 if (dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
1398 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER
)primarybuf
);
1399 *ippdsb
= primarybuf
;
1400 primarybuf
->dsbd
.dwFlags
= dsbd
->dwFlags
;
1402 } /* Else create primarybuf */
1405 *ippdsb
= (IDirectSoundBufferImpl
*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDirectSoundBufferImpl
));
1406 if (*ippdsb
== NULL
)
1407 return DSERR_OUTOFMEMORY
;
1410 TRACE("Created buffer at %p\n", *ippdsb
);
1412 if (dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
1413 (*ippdsb
)->buflen
= dsound
->wfx
.nAvgBytesPerSec
;
1414 (*ippdsb
)->freq
= dsound
->wfx
.nSamplesPerSec
;
1416 (*ippdsb
)->buflen
= dsbd
->dwBufferBytes
;
1417 (*ippdsb
)->freq
= dsbd
->lpwfxFormat
->nSamplesPerSec
;
1419 (*ippdsb
)->buffer
= (LPBYTE
)HeapAlloc(GetProcessHeap(),0,(*ippdsb
)->buflen
);
1420 if ((*ippdsb
)->buffer
== NULL
) {
1421 HeapFree(GetProcessHeap(),0,(*ippdsb
));
1423 return DSERR_OUTOFMEMORY
;
1425 /* It's not necessary to initialize values to zero since */
1426 /* we allocated this structure with HEAP_ZERO_MEMORY... */
1427 (*ippdsb
)->playpos
= 0;
1428 (*ippdsb
)->writepos
= 0;
1429 (*ippdsb
)->parent
= NULL
;
1430 ICOM_VTBL(*ippdsb
) = &dsbvt
;
1431 (*ippdsb
)->dsound
= This
;
1432 (*ippdsb
)->playing
= 0;
1433 (*ippdsb
)->lVolAdjust
= (1 << 15);
1434 (*ippdsb
)->rVolAdjust
= (1 << 15);
1436 if (!(dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
)) {
1437 (*ippdsb
)->freqAdjust
= ((*ippdsb
)->freq
<< DSOUND_FREQSHIFT
) /
1438 primarybuf
->wfx
.nSamplesPerSec
;
1439 (*ippdsb
)->nAvgBytesPerSec
= (*ippdsb
)->freq
*
1440 dsbd
->lpwfxFormat
->nBlockAlign
;
1443 memcpy(&((*ippdsb
)->dsbd
),dsbd
,sizeof(*dsbd
));
1445 EnterCriticalSection(&(This
->lock
));
1446 /* register buffer */
1447 if (!(dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
)) {
1448 This
->buffers
= (IDirectSoundBufferImpl
**)HeapReAlloc(GetProcessHeap(),0,This
->buffers
,sizeof(IDirectSoundBufferImpl
*)*(This
->nrofbuffers
+1));
1449 This
->buffers
[This
->nrofbuffers
] = *ippdsb
;
1450 This
->nrofbuffers
++;
1452 LeaveCriticalSection(&(This
->lock
));
1454 IDirectSound_AddRef(iface
);
1456 if (dsbd
->lpwfxFormat
)
1457 memcpy(&((*ippdsb
)->wfx
), dsbd
->lpwfxFormat
, sizeof((*ippdsb
)->wfx
));
1459 InitializeCriticalSection(&((*ippdsb
)->lock
));
1462 if (dsbd
->dwFlags
& DSBCAPS_CTRL3D
) {
1463 IDirectSound3DBufferImpl
*ds3db
;
1465 ds3db
= (IDirectSound3DBufferImpl
*)HeapAlloc(GetProcessHeap(),
1468 ds3db
->dsb
= (*ippdsb
);
1469 ICOM_VTBL(ds3db
) = &ds3dbvt
;
1470 (*ippdsb
)->ds3db
= ds3db
;
1471 ds3db
->ds3db
.dwSize
= sizeof(DS3DBUFFER
);
1472 ds3db
->ds3db
.vPosition
.x
.x
= 0.0;
1473 ds3db
->ds3db
.vPosition
.y
.y
= 0.0;
1474 ds3db
->ds3db
.vPosition
.z
.z
= 0.0;
1475 ds3db
->ds3db
.vVelocity
.x
.x
= 0.0;
1476 ds3db
->ds3db
.vVelocity
.y
.y
= 0.0;
1477 ds3db
->ds3db
.vVelocity
.z
.z
= 0.0;
1478 ds3db
->ds3db
.dwInsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
1479 ds3db
->ds3db
.dwOutsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
1480 ds3db
->ds3db
.vConeOrientation
.x
.x
= 0.0;
1481 ds3db
->ds3db
.vConeOrientation
.y
.y
= 0.0;
1482 ds3db
->ds3db
.vConeOrientation
.z
.z
= 0.0;
1483 ds3db
->ds3db
.lConeOutsideVolume
= DS3D_DEFAULTCONEOUTSIDEVOLUME
;
1484 ds3db
->ds3db
.flMinDistance
= DS3D_DEFAULTMINDISTANCE
;
1485 ds3db
->ds3db
.flMaxDistance
= DS3D_DEFAULTMAXDISTANCE
;
1486 ds3db
->ds3db
.dwMode
= DS3DMODE_NORMAL
;
1487 ds3db
->buflen
= ((*ippdsb
)->buflen
* primarybuf
->wfx
.nBlockAlign
) /
1488 (*ippdsb
)->wfx
.nBlockAlign
;
1489 ds3db
->buffer
= HeapAlloc(GetProcessHeap(), 0, ds3db
->buflen
);
1490 if (ds3db
->buffer
== NULL
) {
1492 ds3db
->ds3db
.dwMode
= DS3DMODE_DISABLE
;
1499 static HRESULT WINAPI
IDirectSoundImpl_DuplicateSoundBuffer(
1500 LPDIRECTSOUND iface
,LPDIRECTSOUNDBUFFER pdsb
,LPLPDIRECTSOUNDBUFFER ppdsb
1502 ICOM_THIS(IDirectSoundImpl
,iface
);
1503 IDirectSoundBufferImpl
* ipdsb
=(IDirectSoundBufferImpl
*)pdsb
;
1504 IDirectSoundBufferImpl
** ippdsb
=(IDirectSoundBufferImpl
**)ppdsb
;
1505 TRACE("(%p,%p,%p)\n",This
,ipdsb
,ippdsb
);
1507 *ippdsb
= (IDirectSoundBufferImpl
*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDirectSoundBufferImpl
));
1509 IDirectSoundBuffer_AddRef(pdsb
);
1510 memcpy(*ippdsb
, ipdsb
, sizeof(IDirectSoundBufferImpl
));
1512 (*ippdsb
)->playpos
= 0;
1513 (*ippdsb
)->writepos
= 0;
1514 (*ippdsb
)->dsound
= This
;
1515 (*ippdsb
)->parent
= ipdsb
;
1516 memcpy(&((*ippdsb
)->wfx
), &(ipdsb
->wfx
), sizeof((*ippdsb
)->wfx
));
1517 /* register buffer */
1518 EnterCriticalSection(&(This
->lock
));
1519 This
->buffers
= (IDirectSoundBufferImpl
**)HeapReAlloc(GetProcessHeap(),0,This
->buffers
,sizeof(IDirectSoundBufferImpl
**)*(This
->nrofbuffers
+1));
1520 This
->buffers
[This
->nrofbuffers
] = *ippdsb
;
1521 This
->nrofbuffers
++;
1522 IDirectSound_AddRef(iface
);
1523 LeaveCriticalSection(&(This
->lock
));
1528 static HRESULT WINAPI
IDirectSoundImpl_GetCaps(LPDIRECTSOUND iface
,LPDSCAPS caps
) {
1529 ICOM_THIS(IDirectSoundImpl
,iface
);
1530 TRACE("(%p,%p)\n",This
,caps
);
1531 TRACE("(flags=0x%08lx)\n",caps
->dwFlags
);
1534 return DSERR_INVALIDPARAM
;
1536 /* We should check this value, not set it. See Inside DirectX, p215. */
1537 caps
->dwSize
= sizeof(*caps
);
1540 DSCAPS_PRIMARYSTEREO
|
1541 DSCAPS_PRIMARY16BIT
|
1542 DSCAPS_SECONDARYSTEREO
|
1543 DSCAPS_SECONDARY16BIT
|
1544 DSCAPS_CONTINUOUSRATE
;
1545 /* FIXME: query OSS */
1546 caps
->dwMinSecondarySampleRate
= DSBFREQUENCY_MIN
;
1547 caps
->dwMaxSecondarySampleRate
= DSBFREQUENCY_MAX
;
1549 caps
->dwPrimaryBuffers
= 1;
1551 caps
->dwMaxHwMixingAllBuffers
= 0;
1552 caps
->dwMaxHwMixingStaticBuffers
= 0;
1553 caps
->dwMaxHwMixingStreamingBuffers
= 0;
1555 caps
->dwFreeHwMixingAllBuffers
= 0;
1556 caps
->dwFreeHwMixingStaticBuffers
= 0;
1557 caps
->dwFreeHwMixingStreamingBuffers
= 0;
1559 caps
->dwMaxHw3DAllBuffers
= 0;
1560 caps
->dwMaxHw3DStaticBuffers
= 0;
1561 caps
->dwMaxHw3DStreamingBuffers
= 0;
1563 caps
->dwFreeHw3DAllBuffers
= 0;
1564 caps
->dwFreeHw3DStaticBuffers
= 0;
1565 caps
->dwFreeHw3DStreamingBuffers
= 0;
1567 caps
->dwTotalHwMemBytes
= 0;
1569 caps
->dwFreeHwMemBytes
= 0;
1571 caps
->dwMaxContigFreeHwMemBytes
= 0;
1573 caps
->dwUnlockTransferRateHwBuffers
= 4096; /* But we have none... */
1575 caps
->dwPlayCpuOverheadSwBuffers
= 1; /* 1% */
1580 static ULONG WINAPI
IDirectSoundImpl_AddRef(LPDIRECTSOUND iface
) {
1581 ICOM_THIS(IDirectSoundImpl
,iface
);
1582 return ++(This
->ref
);
1585 static ULONG WINAPI
IDirectSoundImpl_Release(LPDIRECTSOUND iface
) {
1586 ICOM_THIS(IDirectSoundImpl
,iface
);
1587 TRACE("(%p), ref was %ld\n",This
,This
->ref
);
1588 if (!--(This
->ref
)) {
1589 DSOUND_CloseAudio();
1590 while(IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)primarybuf
)); /* Deallocate */
1591 FIXME("need to release all buffers!\n");
1592 HeapFree(GetProcessHeap(),0,This
);
1599 static HRESULT WINAPI
IDirectSoundImpl_SetSpeakerConfig(
1600 LPDIRECTSOUND iface
,DWORD config
1602 ICOM_THIS(IDirectSoundImpl
,iface
);
1603 FIXME("(%p,0x%08lx):stub\n",This
,config
);
1607 static HRESULT WINAPI
IDirectSoundImpl_QueryInterface(
1608 LPDIRECTSOUND iface
,REFIID riid
,LPVOID
*ppobj
1610 ICOM_THIS(IDirectSoundImpl
,iface
);
1612 if ( IsEqualGUID( &IID_IDirectSound3DListener
, riid
) ) {
1614 if (This
->listener
) {
1615 *ppobj
= This
->listener
;
1616 IDirectSound3DListener_AddRef((LPDIRECTSOUND3DLISTENER
)This
->listener
);
1619 This
->listener
= (IDirectSound3DListenerImpl
*)HeapAlloc(
1620 GetProcessHeap(), 0, sizeof(*(This
->listener
)));
1621 This
->listener
->ref
= 1;
1622 ICOM_VTBL(This
->listener
) = &ds3dlvt
;
1623 IDirectSound_AddRef(iface
);
1624 This
->listener
->ds3dl
.dwSize
= sizeof(DS3DLISTENER
);
1625 This
->listener
->ds3dl
.vPosition
.x
.x
= 0.0;
1626 This
->listener
->ds3dl
.vPosition
.x
.x
= 0.0;
1627 This
->listener
->ds3dl
.vPosition
.z
.z
= 0.0;
1628 This
->listener
->ds3dl
.vVelocity
.x
.x
= 0.0;
1629 This
->listener
->ds3dl
.vVelocity
.y
.y
= 0.0;
1630 This
->listener
->ds3dl
.vVelocity
.z
.z
= 0.0;
1631 This
->listener
->ds3dl
.vOrientFront
.x
.x
= 0.0;
1632 This
->listener
->ds3dl
.vOrientFront
.y
.y
= 0.0;
1633 This
->listener
->ds3dl
.vOrientFront
.z
.z
= 1.0;
1634 This
->listener
->ds3dl
.vOrientTop
.x
.x
= 0.0;
1635 This
->listener
->ds3dl
.vOrientTop
.y
.y
= 1.0;
1636 This
->listener
->ds3dl
.vOrientTop
.z
.z
= 0.0;
1637 This
->listener
->ds3dl
.flDistanceFactor
= DS3D_DEFAULTDISTANCEFACTOR
;
1638 This
->listener
->ds3dl
.flRolloffFactor
= DS3D_DEFAULTROLLOFFFACTOR
;
1639 This
->listener
->ds3dl
.flDopplerFactor
= DS3D_DEFAULTDOPPLERFACTOR
;
1640 *ppobj
= (LPVOID
)This
->listener
;
1644 TRACE("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
1648 static HRESULT WINAPI
IDirectSoundImpl_Compact(
1649 LPDIRECTSOUND iface
)
1651 ICOM_THIS(IDirectSoundImpl
,iface
);
1652 TRACE("(%p)\n", This
);
1656 static HRESULT WINAPI
IDirectSoundImpl_GetSpeakerConfig(
1657 LPDIRECTSOUND iface
,
1658 LPDWORD lpdwSpeakerConfig
)
1660 ICOM_THIS(IDirectSoundImpl
,iface
);
1661 TRACE("(%p, %p)\n", This
, lpdwSpeakerConfig
);
1662 *lpdwSpeakerConfig
= DSSPEAKER_STEREO
| (DSSPEAKER_GEOMETRY_NARROW
<< 16);
1666 static HRESULT WINAPI
IDirectSoundImpl_Initialize(
1667 LPDIRECTSOUND iface
,
1670 ICOM_THIS(IDirectSoundImpl
,iface
);
1671 TRACE("(%p, %p)\n", This
, lpGuid
);
1675 static ICOM_VTABLE(IDirectSound
) dsvt
=
1677 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1678 IDirectSoundImpl_QueryInterface
,
1679 IDirectSoundImpl_AddRef
,
1680 IDirectSoundImpl_Release
,
1681 IDirectSoundImpl_CreateSoundBuffer
,
1682 IDirectSoundImpl_GetCaps
,
1683 IDirectSoundImpl_DuplicateSoundBuffer
,
1684 IDirectSoundImpl_SetCooperativeLevel
,
1685 IDirectSoundImpl_Compact
,
1686 IDirectSoundImpl_GetSpeakerConfig
,
1687 IDirectSoundImpl_SetSpeakerConfig
,
1688 IDirectSoundImpl_Initialize
1692 /* See http://www.opensound.com/pguide/audio.html for more details */
1695 DSOUND_setformat(LPWAVEFORMATEX wfex
) {
1696 int xx
,channels
,speed
,format
,nformat
;
1699 TRACE("(%p) deferred\n", wfex
);
1702 switch (wfex
->wFormatTag
) {
1704 WARN("unknown WAVE_FORMAT tag %d\n",wfex
->wFormatTag
);
1705 return DSERR_BADFORMAT
;
1706 case WAVE_FORMAT_PCM
:
1709 if (wfex
->wBitsPerSample
==8)
1712 format
= AFMT_S16_LE
;
1714 if (-1==ioctl(audiofd
,SNDCTL_DSP_GETFMTS
,&xx
)) {
1715 perror("ioctl SNDCTL_DSP_GETFMTS");
1718 if ((xx
&format
)!=format
) {/* format unsupported */
1719 FIXME("SNDCTL_DSP_GETFMTS: format not supported\n");
1723 if (-1==ioctl(audiofd
,SNDCTL_DSP_SETFMT
,&nformat
)) {
1724 perror("ioctl SNDCTL_DSP_SETFMT");
1727 if (nformat
!=format
) {/* didn't work */
1728 FIXME("SNDCTL_DSP_GETFMTS: format not set\n");
1732 channels
= wfex
->nChannels
-1;
1733 if (-1==ioctl(audiofd
,SNDCTL_DSP_STEREO
,&channels
)) {
1734 perror("ioctl SNDCTL_DSP_STEREO");
1737 speed
= wfex
->nSamplesPerSec
;
1738 if (-1==ioctl(audiofd
,SNDCTL_DSP_SPEED
,&speed
)) {
1739 perror("ioctl SNDCTL_DSP_SPEED");
1742 TRACE("(freq=%ld,channels=%d,bits=%d)\n",
1743 wfex
->nSamplesPerSec
,wfex
->nChannels
,wfex
->wBitsPerSample
1748 static void DSOUND_CheckEvent(IDirectSoundBufferImpl
*dsb
, int len
)
1752 LPDSBPOSITIONNOTIFY event
;
1754 if (dsb
->nrofnotifies
== 0)
1757 TRACE("(%p) buflen = %ld, playpos = %ld, len = %d\n",
1758 dsb
, dsb
->buflen
, dsb
->playpos
, len
);
1759 for (i
= 0; i
< dsb
->nrofnotifies
; i
++) {
1760 event
= dsb
->notifies
+ i
;
1761 offset
= event
->dwOffset
;
1762 TRACE("checking %d, position %ld, event = %d\n",
1763 i
, offset
, event
->hEventNotify
);
1764 /* DSBPN_OFFSETSTOP has to be the last element. So this is */
1765 /* OK. [Inside DirectX, p274] */
1767 /* This also means we can't sort the entries by offset, */
1768 /* because DSBPN_OFFSETSTOP == -1 */
1769 if (offset
== DSBPN_OFFSETSTOP
) {
1770 if (dsb
->playing
== 0) {
1771 SetEvent(event
->hEventNotify
);
1772 TRACE("signalled event %d (%d)\n", event
->hEventNotify
, i
);
1777 if ((dsb
->playpos
+ len
) >= dsb
->buflen
) {
1778 if ((offset
< ((dsb
->playpos
+ len
) % dsb
->buflen
)) ||
1779 (offset
>= dsb
->playpos
)) {
1780 TRACE("signalled event %d (%d)\n", event
->hEventNotify
, i
);
1781 SetEvent(event
->hEventNotify
);
1784 if ((offset
>= dsb
->playpos
) && (offset
< (dsb
->playpos
+ len
))) {
1785 TRACE("signalled event %d (%d)\n", event
->hEventNotify
, i
);
1786 SetEvent(event
->hEventNotify
);
1792 /* WAV format info can be found at: */
1794 /* http://www.cwi.nl/ftp/audio/AudioFormats.part2 */
1795 /* ftp://ftp.cwi.nl/pub/audio/RIFF-format */
1797 /* Import points to remember: */
1799 /* 8-bit WAV is unsigned */
1800 /* 16-bit WAV is signed */
1802 static inline INT16
cvtU8toS16(BYTE byte
)
1804 INT16 s
= (byte
- 128) << 8;
1809 static inline BYTE
cvtS16toU8(INT16 word
)
1811 BYTE b
= (word
+ 32768) >> 8;
1817 /* We should be able to optimize these two inline functions */
1818 /* so that we aren't doing 8->16->8 conversions when it is */
1819 /* not necessary. But this is still a WIP. Optimize later. */
1820 static inline void get_fields(const IDirectSoundBufferImpl
*dsb
, BYTE
*buf
, INT
*fl
, INT
*fr
)
1822 INT16
*bufs
= (INT16
*) buf
;
1824 /* TRACE("(%p)", buf); */
1825 if ((dsb
->wfx
.wBitsPerSample
== 8) && dsb
->wfx
.nChannels
== 2) {
1826 *fl
= cvtU8toS16(*buf
);
1827 *fr
= cvtU8toS16(*(buf
+ 1));
1831 if ((dsb
->wfx
.wBitsPerSample
== 16) && dsb
->wfx
.nChannels
== 2) {
1837 if ((dsb
->wfx
.wBitsPerSample
== 8) && dsb
->wfx
.nChannels
== 1) {
1838 *fl
= cvtU8toS16(*buf
);
1843 if ((dsb
->wfx
.wBitsPerSample
== 16) && dsb
->wfx
.nChannels
== 1) {
1849 FIXME("get_fields found an unsupported configuration\n");
1853 static inline void set_fields(BYTE
*buf
, INT fl
, INT fr
)
1855 INT16
*bufs
= (INT16
*) buf
;
1857 if ((primarybuf
->wfx
.wBitsPerSample
== 8) && (primarybuf
->wfx
.nChannels
== 2)) {
1858 *buf
= cvtS16toU8(fl
);
1859 *(buf
+ 1) = cvtS16toU8(fr
);
1863 if ((primarybuf
->wfx
.wBitsPerSample
== 16) && (primarybuf
->wfx
.nChannels
== 2)) {
1869 if ((primarybuf
->wfx
.wBitsPerSample
== 8) && (primarybuf
->wfx
.nChannels
== 1)) {
1870 *buf
= cvtS16toU8((fl
+ fr
) >> 1);
1874 if ((primarybuf
->wfx
.wBitsPerSample
== 16) && (primarybuf
->wfx
.nChannels
== 1)) {
1875 *bufs
= (fl
+ fr
) >> 1;
1878 FIXME("set_fields found an unsupported configuration\n");
1882 /* Now with PerfectPitch (tm) technology */
1883 static INT
DSOUND_MixerNorm(IDirectSoundBufferImpl
*dsb
, BYTE
*buf
, INT len
)
1885 INT i
, size
, ipos
, ilen
, fieldL
, fieldR
;
1887 INT iAdvance
= dsb
->wfx
.nBlockAlign
;
1888 INT oAdvance
= primarybuf
->wfx
.nBlockAlign
;
1890 ibp
= dsb
->buffer
+ dsb
->playpos
;
1893 TRACE("(%p, %p, %p), playpos=%8.8lx\n", dsb
, ibp
, obp
, dsb
->playpos
);
1894 /* Check for the best case */
1895 if ((dsb
->freq
== primarybuf
->wfx
.nSamplesPerSec
) &&
1896 (dsb
->wfx
.wBitsPerSample
== primarybuf
->wfx
.wBitsPerSample
) &&
1897 (dsb
->wfx
.nChannels
== primarybuf
->wfx
.nChannels
)) {
1898 DWORD bytesleft
= dsb
->buflen
- dsb
->playpos
;
1899 TRACE("(%p) Best case\n", dsb
);
1900 if (len
<= bytesleft
)
1901 memcpy(obp
, ibp
, len
);
1903 memcpy(obp
, ibp
, bytesleft
);
1904 memcpy(obp
+ bytesleft
, dsb
->buffer
, len
- bytesleft
);
1909 /* Check for same sample rate */
1910 if (dsb
->freq
== primarybuf
->wfx
.nSamplesPerSec
) {
1911 TRACE("(%p) Same sample rate %ld = primary %ld\n", dsb
,
1912 dsb
->freq
, primarybuf
->wfx
.nSamplesPerSec
);
1914 for (i
= 0; i
< len
; i
+= oAdvance
) {
1915 get_fields(dsb
, ibp
, &fieldL
, &fieldR
);
1918 set_fields(obp
, fieldL
, fieldR
);
1920 if (ibp
>= (BYTE
*)(dsb
->buffer
+ dsb
->buflen
))
1921 ibp
= dsb
->buffer
; /* wrap */
1926 /* Mix in different sample rates */
1928 /* New PerfectPitch(tm) Technology (c) 1998 Rob Riggs */
1929 /* Patent Pending :-] */
1931 TRACE("(%p) Adjusting frequency: %ld -> %ld\n",
1932 dsb
, dsb
->freq
, primarybuf
->wfx
.nSamplesPerSec
);
1934 size
= len
/ oAdvance
;
1935 ilen
= ((size
* dsb
->freqAdjust
) >> DSOUND_FREQSHIFT
) * iAdvance
;
1936 for (i
= 0; i
< size
; i
++) {
1938 ipos
= (((i
* dsb
->freqAdjust
) >> DSOUND_FREQSHIFT
) * iAdvance
) + dsb
->playpos
;
1940 if (ipos
>= dsb
->buflen
)
1941 ipos
%= dsb
->buflen
; /* wrap */
1943 get_fields(dsb
, (dsb
->buffer
+ ipos
), &fieldL
, &fieldR
);
1944 set_fields(obp
, fieldL
, fieldR
);
1950 static void DSOUND_MixerVol(IDirectSoundBufferImpl
*dsb
, BYTE
*buf
, INT len
)
1952 INT i
, inc
= primarybuf
->wfx
.wBitsPerSample
>> 3;
1954 INT16
*bps
= (INT16
*) buf
;
1956 TRACE("(%p) left = %lx, right = %lx\n", dsb
,
1957 dsb
->lVolAdjust
, dsb
->rVolAdjust
);
1958 if ((!(dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLPAN
) || (dsb
->pan
== 0)) &&
1959 (!(dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLVOLUME
) || (dsb
->volume
== 0)) &&
1960 !(dsb
->dsbd
.dwFlags
& DSBCAPS_CTRL3D
))
1961 return; /* Nothing to do */
1963 /* If we end up with some bozo coder using panning or 3D sound */
1964 /* with a mono primary buffer, it could sound very weird using */
1965 /* this method. Oh well, tough patooties. */
1967 for (i
= 0; i
< len
; i
+= inc
) {
1973 /* 8-bit WAV is unsigned, but we need to operate */
1974 /* on signed data for this to work properly */
1976 val
= ((val
* (i
& inc
? dsb
->rVolAdjust
: dsb
->lVolAdjust
)) >> 15);
1981 /* 16-bit WAV is signed -- much better */
1983 val
= ((val
* ((i
& inc
) ? dsb
->rVolAdjust
: dsb
->lVolAdjust
)) >> 15);
1989 FIXME("MixerVol had a nasty error\n");
1995 static void DSOUND_Mixer3D(IDirectSoundBufferImpl
*dsb
, BYTE
*buf
, INT len
)
1998 DWORD buflen
, playpos
;
2000 buflen
= dsb
->ds3db
->buflen
;
2001 playpos
= (dsb
->playpos
* primarybuf
->wfx
.nBlockAlign
) / dsb
->wfx
.nBlockAlign
;
2002 ibp
= dsb
->ds3db
->buffer
+ playpos
;
2005 if (playpos
> buflen
) {
2006 FIXME("Major breakage");
2010 if (len
<= (playpos
+ buflen
))
2011 memcpy(obp
, ibp
, len
);
2013 memcpy(obp
, ibp
, buflen
- playpos
);
2014 memcpy(obp
+ (buflen
- playpos
),
2016 len
- (buflen
- playpos
));
2022 static void *tmp_buffer
;
2023 static size_t tmp_buffer_len
= 0;
2025 static void *DSOUND_tmpbuffer(size_t len
)
2027 if (len
>tmp_buffer_len
) {
2028 void *new_buffer
= realloc(tmp_buffer
, len
);
2030 tmp_buffer
= new_buffer
;
2031 tmp_buffer_len
= len
;
2038 static DWORD
DSOUND_MixInBuffer(IDirectSoundBufferImpl
*dsb
)
2040 INT i
, len
, ilen
, temp
, field
;
2041 INT advance
= primarybuf
->wfx
.wBitsPerSample
>> 3;
2042 BYTE
*buf
, *ibuf
, *obuf
;
2043 INT16
*ibufs
, *obufs
;
2045 len
= DSOUND_FRAGLEN
; /* The most we will use */
2046 if (!(dsb
->playflags
& DSBPLAY_LOOPING
)) {
2047 temp
= MulDiv(primarybuf
->wfx
.nAvgBytesPerSec
, dsb
->buflen
,
2048 dsb
->nAvgBytesPerSec
) -
2049 MulDiv(primarybuf
->wfx
.nAvgBytesPerSec
, dsb
->playpos
,
2050 dsb
->nAvgBytesPerSec
);
2051 len
= (len
> temp
) ? temp
: len
;
2053 len
&= ~3; /* 4 byte alignment */
2056 /* This should only happen if we aren't looping and temp < 4 */
2058 /* We skip the remainder, so check for possible events */
2059 DSOUND_CheckEvent(dsb
, dsb
->buflen
- dsb
->playpos
);
2064 /* Check for DSBPN_OFFSETSTOP */
2065 DSOUND_CheckEvent(dsb
, 0);
2069 /* Been seeing segfaults in malloc() for some reason... */
2070 TRACE("allocating buffer (size = %d)\n", len
);
2071 if ((buf
= ibuf
= (BYTE
*) DSOUND_tmpbuffer(len
)) == NULL
)
2074 TRACE("MixInBuffer (%p) len = %d\n", dsb
, len
);
2076 ilen
= DSOUND_MixerNorm(dsb
, ibuf
, len
);
2077 if ((dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLPAN
) ||
2078 (dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLVOLUME
))
2079 DSOUND_MixerVol(dsb
, ibuf
, len
);
2081 obuf
= primarybuf
->buffer
+ primarybuf
->playpos
;
2082 for (i
= 0; i
< len
; i
+= advance
) {
2083 obufs
= (INT16
*) obuf
;
2084 ibufs
= (INT16
*) ibuf
;
2085 if (primarybuf
->wfx
.wBitsPerSample
== 8) {
2086 /* 8-bit WAV is unsigned */
2087 field
= (*ibuf
- 128);
2088 field
+= (*obuf
- 128);
2089 field
= field
> 127 ? 127 : field
;
2090 field
= field
< -128 ? -128 : field
;
2091 *obuf
= field
+ 128;
2093 /* 16-bit WAV is signed */
2096 field
= field
> 32767 ? 32767 : field
;
2097 field
= field
< -32768 ? -32768 : field
;
2102 if (obuf
>= (BYTE
*)(primarybuf
->buffer
+ primarybuf
->buflen
))
2103 obuf
= primarybuf
->buffer
;
2107 if (dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLPOSITIONNOTIFY
)
2108 DSOUND_CheckEvent(dsb
, ilen
);
2110 dsb
->playpos
+= ilen
;
2111 dsb
->writepos
= dsb
->playpos
+ ilen
;
2113 if (dsb
->playpos
>= dsb
->buflen
) {
2114 if (!(dsb
->playflags
& DSBPLAY_LOOPING
)) {
2118 DSOUND_CheckEvent(dsb
, 0); /* For DSBPN_OFFSETSTOP */
2120 dsb
->playpos
%= dsb
->buflen
; /* wrap */
2123 if (dsb
->writepos
>= dsb
->buflen
)
2124 dsb
->writepos
%= dsb
->buflen
;
2129 static DWORD WINAPI
DSOUND_MixPrimary(void)
2131 INT i
, len
, maxlen
= 0;
2132 IDirectSoundBufferImpl
*dsb
;
2134 for (i
= dsound
->nrofbuffers
- 1; i
>= 0; i
--) {
2135 dsb
= dsound
->buffers
[i
];
2137 if (!dsb
|| !(ICOM_VTBL(dsb
)))
2139 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER
)dsb
);
2140 if (dsb
->buflen
&& dsb
->playing
) {
2141 EnterCriticalSection(&(dsb
->lock
));
2142 len
= DSOUND_MixInBuffer(dsb
);
2143 maxlen
= len
> maxlen
? len
: maxlen
;
2144 LeaveCriticalSection(&(dsb
->lock
));
2146 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)dsb
);
2152 static int DSOUND_OpenAudio(void)
2154 int audioFragment
,flags
;
2156 if (primarybuf
== NULL
)
2157 return DSERR_OUTOFMEMORY
;
2159 while (audiofd
>= 0)
2162 /* we will most likely not get one, avoid excessive opens ... */
2163 if (audiofd
== -ENODEV
)
2165 audiofd
= open("/dev/audio",O_WRONLY
|O_NDELAY
);
2167 /* Don't worry if sound is busy at the moment */
2168 if ((errno
!= EBUSY
) && (errno
!= ENODEV
))
2169 perror("open /dev/audio");
2174 /* We should probably do something here if SETFRAGMENT fails... */
2175 audioFragment
=0x0002000c;
2176 if (-1==ioctl(audiofd
,SNDCTL_DSP_SETFRAGMENT
,&audioFragment
))
2177 perror("ioctl SETFRAGMENT");
2179 if ((flags
= fcntl(audiofd
,F_GETFL
,0)) != -1) {
2181 if (-1==fcntl(audiofd
,F_SETFL
,flags
))
2182 perror("clearing the non-blocking flags in DSOUND_OpenAudio");
2184 perror("cannot get flags of audiofd");
2187 DSOUND_setformat(&(primarybuf
->wfx
));
2192 static void DSOUND_CloseAudio(void)
2196 neutral
= primarybuf
->wfx
.wBitsPerSample
== 8 ? 128 : 0;
2197 audioOK
= 0; /* race condition */
2199 /* It's possible we've been called with audio closed */
2200 /* from SetFormat()... this is just to force a call */
2201 /* to OpenAudio() to reset the hardware properly */
2204 primarybuf
->playpos
= 0;
2205 primarybuf
->writepos
= DSOUND_FRAGLEN
;
2206 memset(primarybuf
->buffer
, neutral
, primarybuf
->buflen
);
2208 TRACE("Audio stopped\n");
2211 static int DSOUND_WriteAudio(char *buf
, int len
)
2213 int result
, left
= 0;
2215 while (left
< len
) {
2216 result
= write(audiofd
, buf
+ left
, len
- left
);
2228 static void DSOUND_OutputPrimary(int len
)
2230 int neutral
, flen1
, flen2
;
2231 char *frag1
, *frag2
;
2233 /* This is a bad place for this. We need to clear the */
2234 /* buffer with a neutral value, for unsigned 8-bit WAVE */
2235 /* that's 128, for signed 16-bit it's 0 */
2236 neutral
= primarybuf
->wfx
.wBitsPerSample
== 8 ? 128 : 0;
2239 EnterCriticalSection(&(primarybuf
->lock
));
2242 if ((audioOK
== 1) || (DSOUND_OpenAudio() == 0)) {
2243 if (primarybuf
->playpos
+ len
>= primarybuf
->buflen
) {
2244 frag1
= primarybuf
->buffer
+ primarybuf
->playpos
;
2245 flen1
= primarybuf
->buflen
- primarybuf
->playpos
;
2246 frag2
= primarybuf
->buffer
;
2247 flen2
= len
- (primarybuf
->buflen
- primarybuf
->playpos
);
2248 if (DSOUND_WriteAudio(frag1
, flen1
) != 0) {
2249 perror("DSOUND_WriteAudio");
2250 LeaveCriticalSection(&(primarybuf
->lock
));
2253 memset(frag1
, neutral
, flen1
);
2254 if (DSOUND_WriteAudio(frag2
, flen2
) != 0) {
2255 perror("DSOUND_WriteAudio");
2256 LeaveCriticalSection(&(primarybuf
->lock
));
2259 memset(frag2
, neutral
, flen2
);
2261 frag1
= primarybuf
->buffer
+ primarybuf
->playpos
;
2263 if (DSOUND_WriteAudio(frag1
, flen1
) != 0) {
2264 perror("DSOUND_WriteAudio");
2265 LeaveCriticalSection(&(primarybuf
->lock
));
2268 memset(frag1
, neutral
, flen1
);
2271 /* Can't play audio at the moment -- we need to sleep */
2272 /* to make up for the time we'd be blocked in write() */
2276 primarybuf
->playpos
+= len
;
2277 if (primarybuf
->playpos
>= primarybuf
->buflen
)
2278 primarybuf
->playpos
%= primarybuf
->buflen
;
2279 primarybuf
->writepos
= primarybuf
->playpos
+ DSOUND_FRAGLEN
;
2280 if (primarybuf
->writepos
>= primarybuf
->buflen
)
2281 primarybuf
->writepos
%= primarybuf
->buflen
;
2283 LeaveCriticalSection(&(primarybuf
->lock
));
2287 static DWORD WINAPI
DSOUND_thread(LPVOID arg
)
2291 TRACE("dsound is at pid %d\n",getpid());
2294 WARN("DSOUND thread giving up.\n");
2298 /* EP: since the thread creating this thread can
2299 * die before the end of the DSOUND one, this
2301 * What shall be tested is whether the DSOUND thread
2302 * is the last one in the process
2305 WARN("DSOUND father died? Giving up.\n");
2309 /* RACE: dsound could be deleted */
2310 EnterCriticalSection(&(dsound
->lock
));
2311 if (primarybuf
== NULL
) {
2312 /* Should never happen */
2313 WARN("Lost the primary buffer!\n");
2314 IDirectSound_Release((LPDIRECTSOUND
)dsound
);
2318 EnterCriticalSection(&(primarybuf
->lock
));
2320 len
= DSOUND_MixPrimary();
2322 LeaveCriticalSection(&(primarybuf
->lock
));
2323 LeaveCriticalSection(&(dsound
->lock
));
2325 if (primarybuf
->playing
)
2326 len
= DSOUND_FRAGLEN
> len
? DSOUND_FRAGLEN
: len
;
2328 /* This does all the work */
2329 DSOUND_OutputPrimary(len
);
2331 /* no buffers playing -- close and wait */
2333 DSOUND_CloseAudio();
2340 #endif /* HAVE_OSS */
2342 /*******************************************************************************
2345 HRESULT WINAPI
DirectSoundCreate(REFGUID lpGUID
,LPDIRECTSOUND
*ppDS
,IUnknown
*pUnkOuter
)
2347 IDirectSoundImpl
** ippDS
=(IDirectSoundImpl
**)ppDS
;
2349 TRACE("(%p,%p,%p)\n",lpGUID
,ippDS
,pUnkOuter
);
2351 TRACE("DirectSoundCreate (%p)\n", ippDS
);
2356 return DSERR_INVALIDPARAM
;
2359 IDirectSound_AddRef((LPDIRECTSOUND
)dsound
);
2364 /* Check that we actually have audio capabilities */
2365 /* If we do, whether it's busy or not, we continue */
2366 /* otherwise we return with DSERR_NODRIVER */
2368 audiofd
= open("/dev/audio",O_WRONLY
|O_NDELAY
);
2369 if (audiofd
== -1) {
2371 if (errno
== ENODEV
) {
2372 MESSAGE("No sound hardware found, but continuing anyway.\n");
2373 } else if (errno
== EBUSY
) {
2374 MESSAGE("Sound device busy, will keep trying.\n");
2376 MESSAGE("Unexpected error (%d) while checking for sound support.\n",errno
);
2377 return DSERR_GENERIC
;
2384 *ippDS
= (IDirectSoundImpl
*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundImpl
));
2386 return DSERR_OUTOFMEMORY
;
2388 ICOM_VTBL(*ippDS
) = &dsvt
;
2391 (*ippDS
)->priolevel
= DSSCL_NORMAL
;
2392 (*ippDS
)->nrofbuffers
= 0;
2393 (*ippDS
)->buffers
= NULL
;
2394 (*ippDS
)->primary
= NULL
;
2395 (*ippDS
)->listener
= NULL
;
2397 (*ippDS
)->wfx
.wFormatTag
= 1;
2398 (*ippDS
)->wfx
.nChannels
= 2;
2399 (*ippDS
)->wfx
.nSamplesPerSec
= 22050;
2400 (*ippDS
)->wfx
.nAvgBytesPerSec
= 44100;
2401 (*ippDS
)->wfx
.nBlockAlign
= 2;
2402 (*ippDS
)->wfx
.wBitsPerSample
= 8;
2404 InitializeCriticalSection(&((*ippDS
)->lock
));
2411 if (primarybuf
== NULL
) {
2415 dsbd
.dwSize
= sizeof(DSBUFFERDESC
);
2416 dsbd
.dwFlags
= DSBCAPS_PRIMARYBUFFER
;
2417 dsbd
.dwBufferBytes
= 0;
2418 dsbd
.lpwfxFormat
= &(dsound
->wfx
);
2419 hr
= IDirectSound_CreateSoundBuffer(*ppDS
, &dsbd
, (LPDIRECTSOUNDBUFFER
*)&primarybuf
, NULL
);
2422 dsound
->primary
= primarybuf
;
2424 memset(primarybuf
->buffer
, 128, primarybuf
->buflen
);
2425 hnd
= CreateThread(NULL
,0,DSOUND_thread
,0,0,&xid
);
2429 MessageBoxA(0,"DirectSound needs the Open Sound System Driver, which has not been found by ./configure.","WINE DirectSound",MB_OK
|MB_ICONSTOP
);
2430 return DSERR_NODRIVER
;
2434 /***************************************************************************
2435 * DirectSoundCaptureCreate [DSOUND.6]
2437 * Enumerate all DirectSound drivers installed in the system
2441 * Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
2444 HRESULT WINAPI
DirectSoundCaptureCreate(
2446 LPDIRECTSOUNDCAPTURE
* lplpDSC
,
2447 LPUNKNOWN pUnkOuter
)
2449 FIXME("(%s,%p,%p): stub\n", debugstr_guid(riid
), lplpDSC
, pUnkOuter
);
2452 return DSERR_NOAGGREGATION
;
2457 return DSERR_OUTOFMEMORY
;
2460 /***************************************************************************
2461 * DirectSoundCaptureEnumerateA [DSOUND.7]
2463 * Enumerate all DirectSound drivers installed in the system
2467 * Failure: DSERR_INVALIDPARAM
2469 HRESULT WINAPI
DirectSoundCaptureEnumerateA(
2470 LPDSENUMCALLBACKA lpDSEnumCallback
,
2473 FIXME("(%p,%p):stub\n", lpDSEnumCallback
, lpContext
);
2477 /***************************************************************************
2478 * DirectSoundCaptureEnumerateW [DSOUND.8]
2480 * Enumerate all DirectSound drivers installed in the system
2484 * Failure: DSERR_INVALIDPARAM
2486 HRESULT WINAPI
DirectSoundCaptureEnumerateW(
2487 LPDSENUMCALLBACKW lpDSEnumCallback
,
2490 FIXME("(%p,%p):stub\n", lpDSEnumCallback
, lpContext
);
2498 /*******************************************************************************
2499 * DirectSound ClassFactory
2503 /* IUnknown fields */
2504 ICOM_VFIELD(IClassFactory
);
2506 } IClassFactoryImpl
;
2508 static HRESULT WINAPI
2509 DSCF_QueryInterface(LPCLASSFACTORY iface
,REFIID riid
,LPVOID
*ppobj
) {
2510 ICOM_THIS(IClassFactoryImpl
,iface
);
2512 FIXME("(%p)->(%s,%p),stub!\n",This
,debugstr_guid(riid
),ppobj
);
2513 return E_NOINTERFACE
;
2517 DSCF_AddRef(LPCLASSFACTORY iface
) {
2518 ICOM_THIS(IClassFactoryImpl
,iface
);
2519 return ++(This
->ref
);
2522 static ULONG WINAPI
DSCF_Release(LPCLASSFACTORY iface
) {
2523 ICOM_THIS(IClassFactoryImpl
,iface
);
2524 /* static class, won't be freed */
2525 return --(This
->ref
);
2528 static HRESULT WINAPI
DSCF_CreateInstance(
2529 LPCLASSFACTORY iface
,LPUNKNOWN pOuter
,REFIID riid
,LPVOID
*ppobj
2531 ICOM_THIS(IClassFactoryImpl
,iface
);
2533 TRACE("(%p)->(%p,%s,%p)\n",This
,pOuter
,debugstr_guid(riid
),ppobj
);
2534 if ( IsEqualGUID( &IID_IDirectSound
, riid
) ) {
2535 /* FIXME: reuse already created dsound if present? */
2536 return DirectSoundCreate(riid
,(LPDIRECTSOUND
*)ppobj
,pOuter
);
2538 return E_NOINTERFACE
;
2541 static HRESULT WINAPI
DSCF_LockServer(LPCLASSFACTORY iface
,BOOL dolock
) {
2542 ICOM_THIS(IClassFactoryImpl
,iface
);
2543 FIXME("(%p)->(%d),stub!\n",This
,dolock
);
2547 static ICOM_VTABLE(IClassFactory
) DSCF_Vtbl
= {
2548 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
2549 DSCF_QueryInterface
,
2552 DSCF_CreateInstance
,
2555 static IClassFactoryImpl DSOUND_CF
= {&DSCF_Vtbl
, 1 };
2557 /*******************************************************************************
2558 * DllGetClassObject [DSOUND.4]
2559 * Retrieves class object from a DLL object
2562 * Docs say returns STDAPI
2565 * rclsid [I] CLSID for the class object
2566 * riid [I] Reference to identifier of interface for class object
2567 * ppv [O] Address of variable to receive interface pointer for riid
2571 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
2574 DWORD WINAPI
DSOUND_DllGetClassObject(REFCLSID rclsid
,REFIID riid
,LPVOID
*ppv
)
2576 TRACE("(%p,%p,%p)\n", debugstr_guid(rclsid
), debugstr_guid(riid
), ppv
);
2577 if ( IsEqualCLSID( &IID_IClassFactory
, riid
) ) {
2578 *ppv
= (LPVOID
)&DSOUND_CF
;
2579 IClassFactory_AddRef((IClassFactory
*)*ppv
);
2583 FIXME("(%p,%p,%p): no interface found.\n", debugstr_guid(rclsid
), debugstr_guid(riid
), ppv
);
2584 return CLASS_E_CLASSNOTAVAILABLE
;
2588 /*******************************************************************************
2589 * DllCanUnloadNow [DSOUND.3] Determines whether the DLL is in use.
2595 DWORD WINAPI
DSOUND_DllCanUnloadNow(void)
2597 FIXME("(void): stub\n");