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
208 HRESULT WINAPI
DirectSoundEnumerateA(
209 LPDSENUMCALLBACKA enumcb
,
212 TRACE("enumcb = %p, context = %p\n", enumcb
, context
);
216 enumcb(NULL
,"WINE DirectSound using Open Sound System",
224 static void _dump_DSBCAPS(DWORD xmask
) {
229 #define FE(x) { x, #x },
230 FE(DSBCAPS_PRIMARYBUFFER
)
232 FE(DSBCAPS_LOCHARDWARE
)
233 FE(DSBCAPS_LOCSOFTWARE
)
234 FE(DSBCAPS_CTRLFREQUENCY
)
236 FE(DSBCAPS_CTRLVOLUME
)
237 FE(DSBCAPS_CTRLDEFAULT
)
239 FE(DSBCAPS_STICKYFOCUS
)
240 FE(DSBCAPS_GETCURRENTPOSITION2
)
244 for (i
=0;i
<sizeof(flags
)/sizeof(flags
[0]);i
++)
245 if ((flags
[i
].mask
& xmask
) == flags
[i
].mask
)
246 DPRINTF("%s ",flags
[i
].name
);
249 /*******************************************************************************
250 * IDirectSound3DBuffer
253 /* IUnknown methods */
254 static HRESULT WINAPI
IDirectSound3DBufferImpl_QueryInterface(
255 LPDIRECTSOUND3DBUFFER iface
, REFIID riid
, LPVOID
*ppobj
)
257 ICOM_THIS(IDirectSound3DBufferImpl
,iface
);
259 TRACE("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
263 static ULONG WINAPI
IDirectSound3DBufferImpl_AddRef(LPDIRECTSOUND3DBUFFER iface
)
265 ICOM_THIS(IDirectSound3DBufferImpl
,iface
);
270 static ULONG WINAPI
IDirectSound3DBufferImpl_Release(LPDIRECTSOUND3DBUFFER iface
)
272 ICOM_THIS(IDirectSound3DBufferImpl
,iface
);
276 HeapFree(GetProcessHeap(),0,This
->buffer
);
277 HeapFree(GetProcessHeap(),0,This
);
282 /* IDirectSound3DBuffer methods */
283 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetAllParameters(
284 LPDIRECTSOUND3DBUFFER iface
,
285 LPDS3DBUFFER lpDs3dBuffer
)
291 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetConeAngles(
292 LPDIRECTSOUND3DBUFFER iface
,
293 LPDWORD lpdwInsideConeAngle
,
294 LPDWORD lpdwOutsideConeAngle
)
300 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetConeOrientation(
301 LPDIRECTSOUND3DBUFFER iface
,
302 LPD3DVECTOR lpvConeOrientation
)
308 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetConeOutsideVolume(
309 LPDIRECTSOUND3DBUFFER iface
,
310 LPLONG lplConeOutsideVolume
)
316 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetMaxDistance(
317 LPDIRECTSOUND3DBUFFER iface
,
318 LPD3DVALUE lpfMaxDistance
)
324 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetMinDistance(
325 LPDIRECTSOUND3DBUFFER iface
,
326 LPD3DVALUE lpfMinDistance
)
332 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetMode(
333 LPDIRECTSOUND3DBUFFER iface
,
340 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetPosition(
341 LPDIRECTSOUND3DBUFFER iface
,
342 LPD3DVECTOR lpvPosition
)
348 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetVelocity(
349 LPDIRECTSOUND3DBUFFER iface
,
350 LPD3DVECTOR lpvVelocity
)
356 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetAllParameters(
357 LPDIRECTSOUND3DBUFFER iface
,
358 LPCDS3DBUFFER lpcDs3dBuffer
,
365 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetConeAngles(
366 LPDIRECTSOUND3DBUFFER iface
,
367 DWORD dwInsideConeAngle
,
368 DWORD dwOutsideConeAngle
,
375 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetConeOrientation(
376 LPDIRECTSOUND3DBUFFER iface
,
377 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
384 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetConeOutsideVolume(
385 LPDIRECTSOUND3DBUFFER iface
,
386 LONG lConeOutsideVolume
,
393 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetMaxDistance(
394 LPDIRECTSOUND3DBUFFER iface
,
395 D3DVALUE fMaxDistance
,
402 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetMinDistance(
403 LPDIRECTSOUND3DBUFFER iface
,
404 D3DVALUE fMinDistance
,
411 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetMode(
412 LPDIRECTSOUND3DBUFFER iface
,
416 ICOM_THIS(IDirectSound3DBufferImpl
,iface
);
417 TRACE("mode = %lx\n", dwMode
);
418 This
->ds3db
.dwMode
= dwMode
;
422 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetPosition(
423 LPDIRECTSOUND3DBUFFER iface
,
424 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
431 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetVelocity(
432 LPDIRECTSOUND3DBUFFER iface
,
433 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
440 ICOM_VTABLE(IDirectSound3DBuffer
) ds3dbvt
=
442 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
443 /* IUnknown methods */
444 IDirectSound3DBufferImpl_QueryInterface
,
445 IDirectSound3DBufferImpl_AddRef
,
446 IDirectSound3DBufferImpl_Release
,
447 /* IDirectSound3DBuffer methods */
448 IDirectSound3DBufferImpl_GetAllParameters
,
449 IDirectSound3DBufferImpl_GetConeAngles
,
450 IDirectSound3DBufferImpl_GetConeOrientation
,
451 IDirectSound3DBufferImpl_GetConeOutsideVolume
,
452 IDirectSound3DBufferImpl_GetMaxDistance
,
453 IDirectSound3DBufferImpl_GetMinDistance
,
454 IDirectSound3DBufferImpl_GetMode
,
455 IDirectSound3DBufferImpl_GetPosition
,
456 IDirectSound3DBufferImpl_GetVelocity
,
457 IDirectSound3DBufferImpl_SetAllParameters
,
458 IDirectSound3DBufferImpl_SetConeAngles
,
459 IDirectSound3DBufferImpl_SetConeOrientation
,
460 IDirectSound3DBufferImpl_SetConeOutsideVolume
,
461 IDirectSound3DBufferImpl_SetMaxDistance
,
462 IDirectSound3DBufferImpl_SetMinDistance
,
463 IDirectSound3DBufferImpl_SetMode
,
464 IDirectSound3DBufferImpl_SetPosition
,
465 IDirectSound3DBufferImpl_SetVelocity
,
469 static int DSOUND_Create3DBuffer(IDirectSoundBufferImpl
* dsb
)
471 DWORD i
, temp
, iSize
, oSize
, offset
;
472 LPBYTE bIbuf
, bObuf
, bTbuf
= NULL
;
473 LPWORD wIbuf
, wObuf
, wTbuf
= NULL
;
475 /* Inside DirectX says it's stupid but allowed */
476 if (dsb
->wfx
.nChannels
== 2) {
477 /* Convert to mono */
478 if (dsb
->wfx
.wBitsPerSample
== 16) {
479 iSize
= dsb
->buflen
/ 4;
480 wTbuf
= malloc(dsb
->buflen
/ 2);
482 return DSERR_OUTOFMEMORY
;
483 for (i
= 0; i
< iSize
; i
++)
484 wTbuf
[i
] = (dsb
->buffer
[i
] + dsb
->buffer
[(i
* 2) + 1]) / 2;
487 iSize
= dsb
->buflen
/ 2;
488 bTbuf
= malloc(dsb
->buflen
/ 2);
490 return DSERR_OUTOFMEMORY
;
491 for (i
= 0; i
< iSize
; i
++)
492 bTbuf
[i
] = (dsb
->buffer
[i
] + dsb
->buffer
[(i
* 2) + 1]) / 2;
496 if (dsb
->wfx
.wBitsPerSample
== 16) {
497 iSize
= dsb
->buflen
/ 2;
498 wIbuf
= (LPWORD
) dsb
->buffer
;
500 bIbuf
= (LPBYTE
) dsb
->buffer
;
505 if (primarybuf
->wfx
.wBitsPerSample
== 16) {
506 wObuf
= (LPWORD
) dsb
->ds3db
->buffer
;
507 oSize
= dsb
->ds3db
->buflen
/ 2;
509 bObuf
= (LPBYTE
) dsb
->ds3db
->buffer
;
510 oSize
= dsb
->ds3db
->buflen
;
513 offset
= primarybuf
->wfx
.nSamplesPerSec
/ 100; /* 10ms */
514 if (primarybuf
->wfx
.wBitsPerSample
== 16 && dsb
->wfx
.wBitsPerSample
== 16)
515 for (i
= 0; i
< iSize
; i
++) {
518 temp
+= wIbuf
[i
- offset
] >> 9;
520 temp
+= wIbuf
[i
+ iSize
- offset
] >> 9;
522 wObuf
[(i
* 2) + 1] = temp
;
524 else if (primarybuf
->wfx
.wBitsPerSample
== 8 && dsb
->wfx
.wBitsPerSample
== 8)
525 for (i
= 0; i
< iSize
; i
++) {
528 temp
+= bIbuf
[i
- offset
] >> 5;
530 temp
+= bIbuf
[i
+ iSize
- offset
] >> 5;
532 bObuf
[(i
* 2) + 1] = temp
;
543 /*******************************************************************************
544 * IDirectSound3DListener
547 /* IUnknown methods */
548 static HRESULT WINAPI
IDirectSound3DListenerImpl_QueryInterface(
549 LPDIRECTSOUND3DLISTENER iface
, REFIID riid
, LPVOID
*ppobj
)
551 ICOM_THIS(IDirectSound3DListenerImpl
,iface
);
553 TRACE("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
557 static ULONG WINAPI
IDirectSound3DListenerImpl_AddRef(LPDIRECTSOUND3DLISTENER iface
)
559 ICOM_THIS(IDirectSound3DListenerImpl
,iface
);
564 static ULONG WINAPI
IDirectSound3DListenerImpl_Release(LPDIRECTSOUND3DLISTENER iface
)
566 ICOM_THIS(IDirectSound3DListenerImpl
,iface
);
571 /* IDirectSound3DListener methods */
572 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetAllParameter(
573 LPDIRECTSOUND3DLISTENER iface
,
574 LPDS3DLISTENER lpDS3DL
)
580 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetDistanceFactor(
581 LPDIRECTSOUND3DLISTENER iface
,
582 LPD3DVALUE lpfDistanceFactor
)
588 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetDopplerFactor(
589 LPDIRECTSOUND3DLISTENER iface
,
590 LPD3DVALUE lpfDopplerFactor
)
596 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetOrientation(
597 LPDIRECTSOUND3DLISTENER iface
,
598 LPD3DVECTOR lpvOrientFront
,
599 LPD3DVECTOR lpvOrientTop
)
605 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetPosition(
606 LPDIRECTSOUND3DLISTENER iface
,
607 LPD3DVECTOR lpvPosition
)
613 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetRolloffFactor(
614 LPDIRECTSOUND3DLISTENER iface
,
615 LPD3DVALUE lpfRolloffFactor
)
621 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetVelocity(
622 LPDIRECTSOUND3DLISTENER iface
,
623 LPD3DVECTOR lpvVelocity
)
629 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetAllParameters(
630 LPDIRECTSOUND3DLISTENER iface
,
631 LPCDS3DLISTENER lpcDS3DL
,
638 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetDistanceFactor(
639 LPDIRECTSOUND3DLISTENER iface
,
640 D3DVALUE fDistanceFactor
,
647 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetDopplerFactor(
648 LPDIRECTSOUND3DLISTENER iface
,
649 D3DVALUE fDopplerFactor
,
656 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetOrientation(
657 LPDIRECTSOUND3DLISTENER iface
,
658 D3DVALUE xFront
, D3DVALUE yFront
, D3DVALUE zFront
,
659 D3DVALUE xTop
, D3DVALUE yTop
, D3DVALUE zTop
,
666 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetPosition(
667 LPDIRECTSOUND3DLISTENER iface
,
668 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
675 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetRolloffFactor(
676 LPDIRECTSOUND3DLISTENER iface
,
677 D3DVALUE fRolloffFactor
,
684 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetVelocity(
685 LPDIRECTSOUND3DLISTENER iface
,
686 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
693 static HRESULT WINAPI
IDirectSound3DListenerImpl_CommitDeferredSettings(
694 LPDIRECTSOUND3DLISTENER iface
)
701 ICOM_VTABLE(IDirectSound3DListener
) ds3dlvt
=
703 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
704 /* IUnknown methods */
705 IDirectSound3DListenerImpl_QueryInterface
,
706 IDirectSound3DListenerImpl_AddRef
,
707 IDirectSound3DListenerImpl_Release
,
708 /* IDirectSound3DListener methods */
709 IDirectSound3DListenerImpl_GetAllParameter
,
710 IDirectSound3DListenerImpl_GetDistanceFactor
,
711 IDirectSound3DListenerImpl_GetDopplerFactor
,
712 IDirectSound3DListenerImpl_GetOrientation
,
713 IDirectSound3DListenerImpl_GetPosition
,
714 IDirectSound3DListenerImpl_GetRolloffFactor
,
715 IDirectSound3DListenerImpl_GetVelocity
,
716 IDirectSound3DListenerImpl_SetAllParameters
,
717 IDirectSound3DListenerImpl_SetDistanceFactor
,
718 IDirectSound3DListenerImpl_SetDopplerFactor
,
719 IDirectSound3DListenerImpl_SetOrientation
,
720 IDirectSound3DListenerImpl_SetPosition
,
721 IDirectSound3DListenerImpl_SetRolloffFactor
,
722 IDirectSound3DListenerImpl_SetVelocity
,
723 IDirectSound3DListenerImpl_CommitDeferredSettings
,
726 /*******************************************************************************
729 static HRESULT WINAPI
IDirectSoundNotifyImpl_QueryInterface(
730 LPDIRECTSOUNDNOTIFY iface
,REFIID riid
,LPVOID
*ppobj
732 ICOM_THIS(IDirectSoundNotifyImpl
,iface
);
734 TRACE("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
738 static ULONG WINAPI
IDirectSoundNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface
) {
739 ICOM_THIS(IDirectSoundNotifyImpl
,iface
);
740 return ++(This
->ref
);
743 static ULONG WINAPI
IDirectSoundNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface
) {
744 ICOM_THIS(IDirectSoundNotifyImpl
,iface
);
747 IDirectSoundNotify_Release((LPDIRECTSOUNDBUFFER
)This
->dsb
);
748 HeapFree(GetProcessHeap(),0,This
);
754 static HRESULT WINAPI
IDirectSoundNotifyImpl_SetNotificationPositions(
755 LPDIRECTSOUNDNOTIFY iface
,DWORD howmuch
,LPCDSBPOSITIONNOTIFY notify
757 ICOM_THIS(IDirectSoundNotifyImpl
,iface
);
760 if (TRACE_ON(dsound
)) {
761 TRACE("(%p,0x%08lx,%p)\n",This
,howmuch
,notify
);
762 for (i
=0;i
<howmuch
;i
++)
763 TRACE("notify at %ld to 0x%08lx\n",
764 notify
[i
].dwOffset
,(DWORD
)notify
[i
].hEventNotify
);
766 This
->dsb
->notifies
= HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,This
->dsb
->notifies
,(This
->dsb
->nrofnotifies
+howmuch
)*sizeof(DSBPOSITIONNOTIFY
));
767 memcpy( This
->dsb
->notifies
+This
->dsb
->nrofnotifies
,
769 howmuch
*sizeof(DSBPOSITIONNOTIFY
)
771 This
->dsb
->nrofnotifies
+=howmuch
;
776 ICOM_VTABLE(IDirectSoundNotify
) dsnvt
=
778 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
779 IDirectSoundNotifyImpl_QueryInterface
,
780 IDirectSoundNotifyImpl_AddRef
,
781 IDirectSoundNotifyImpl_Release
,
782 IDirectSoundNotifyImpl_SetNotificationPositions
,
785 /*******************************************************************************
789 /* This sets this format for the <em>Primary Buffer Only</em> */
790 /* See file:///cdrom/sdk52/docs/worddoc/dsound.doc page 120 */
791 static HRESULT WINAPI
IDirectSoundBufferImpl_SetFormat(
792 LPDIRECTSOUNDBUFFER iface
,LPWAVEFORMATEX wfex
794 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
795 IDirectSoundBufferImpl
** dsb
;
798 /* Let's be pedantic! */
799 if ((wfex
== NULL
) ||
800 (wfex
->wFormatTag
!= WAVE_FORMAT_PCM
) ||
801 (wfex
->nChannels
< 1) || (wfex
->nChannels
> 2) ||
802 (wfex
->nSamplesPerSec
< 1) ||
803 (wfex
->nBlockAlign
< 1) || (wfex
->nChannels
> 4) ||
804 ((wfex
->wBitsPerSample
!= 8) && (wfex
->wBitsPerSample
!= 16))) {
805 TRACE("failed pedantic check!\n");
806 return DSERR_INVALIDPARAM
;
810 EnterCriticalSection(&(This
->dsound
->lock
));
812 if (primarybuf
->wfx
.nSamplesPerSec
!= wfex
->nSamplesPerSec
) {
813 dsb
= dsound
->buffers
;
814 for (i
= 0; i
< dsound
->nrofbuffers
; i
++, dsb
++) {
816 EnterCriticalSection(&((*dsb
)->lock
));
818 (*dsb
)->freqAdjust
= ((*dsb
)->freq
<< DSOUND_FREQSHIFT
) /
819 wfex
->nSamplesPerSec
;
821 LeaveCriticalSection(&((*dsb
)->lock
));
826 memcpy(&(primarybuf
->wfx
), wfex
, sizeof(primarybuf
->wfx
));
828 TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld"
829 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
830 wfex
->wFormatTag
, wfex
->nChannels
, wfex
->nSamplesPerSec
,
831 wfex
->nAvgBytesPerSec
, wfex
->nBlockAlign
,
832 wfex
->wBitsPerSample
, wfex
->cbSize
);
834 primarybuf
->wfx
.nAvgBytesPerSec
=
835 This
->wfx
.nSamplesPerSec
* This
->wfx
.nBlockAlign
;
838 LeaveCriticalSection(&(This
->dsound
->lock
));
844 static HRESULT WINAPI
IDirectSoundBufferImpl_SetVolume(
845 LPDIRECTSOUNDBUFFER iface
,LONG vol
847 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
850 TRACE("(%p,%ld)\n",This
,vol
);
852 /* I'm not sure if we need this for primary buffer */
853 if (!(This
->dsbd
.dwFlags
& DSBCAPS_CTRLVOLUME
))
854 return DSERR_CONTROLUNAVAIL
;
856 if ((vol
> DSBVOLUME_MAX
) || (vol
< DSBVOLUME_MIN
))
857 return DSERR_INVALIDPARAM
;
859 /* This needs to adjust the soundcard volume when */
860 /* called for the primary buffer */
861 if (This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
862 FIXME("Volume control of primary unimplemented.\n");
868 EnterCriticalSection(&(This
->lock
));
872 temp
= (double) (This
->volume
- (This
->pan
> 0 ? This
->pan
: 0));
873 This
->lVolAdjust
= (ULONG
) (pow(2.0, temp
/ 600.0) * 32768.0);
874 temp
= (double) (This
->volume
+ (This
->pan
< 0 ? This
->pan
: 0));
875 This
->rVolAdjust
= (ULONG
) (pow(2.0, temp
/ 600.0) * 32768.0);
877 LeaveCriticalSection(&(This
->lock
));
880 TRACE("left = %lx, right = %lx\n", This
->lVolAdjust
, This
->rVolAdjust
);
885 static HRESULT WINAPI
IDirectSoundBufferImpl_GetVolume(
886 LPDIRECTSOUNDBUFFER iface
,LPLONG vol
888 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
889 TRACE("(%p,%p)\n",This
,vol
);
892 return DSERR_INVALIDPARAM
;
898 static HRESULT WINAPI
IDirectSoundBufferImpl_SetFrequency(
899 LPDIRECTSOUNDBUFFER iface
,DWORD freq
901 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
902 TRACE("(%p,%ld)\n",This
,freq
);
904 /* You cannot set the frequency of the primary buffer */
905 if (!(This
->dsbd
.dwFlags
& DSBCAPS_CTRLFREQUENCY
) ||
906 (This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
))
907 return DSERR_CONTROLUNAVAIL
;
909 if ((freq
< DSBFREQUENCY_MIN
) || (freq
> DSBFREQUENCY_MAX
))
910 return DSERR_INVALIDPARAM
;
913 EnterCriticalSection(&(This
->lock
));
916 This
->freqAdjust
= (freq
<< DSOUND_FREQSHIFT
) / primarybuf
->wfx
.nSamplesPerSec
;
917 This
->nAvgBytesPerSec
= freq
* This
->wfx
.nBlockAlign
;
919 LeaveCriticalSection(&(This
->lock
));
925 static HRESULT WINAPI
IDirectSoundBufferImpl_Play(
926 LPDIRECTSOUNDBUFFER iface
,DWORD reserved1
,DWORD reserved2
,DWORD flags
928 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
929 TRACE("(%p,%08lx,%08lx,%08lx)\n",
930 This
,reserved1
,reserved2
,flags
932 This
->playflags
= flags
;
937 static HRESULT WINAPI
IDirectSoundBufferImpl_Stop(LPDIRECTSOUNDBUFFER iface
)
939 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
940 TRACE("(%p)\n",This
);
943 EnterCriticalSection(&(This
->lock
));
946 DSOUND_CheckEvent(This
, 0);
948 LeaveCriticalSection(&(This
->lock
));
954 static DWORD WINAPI
IDirectSoundBufferImpl_AddRef(LPDIRECTSOUNDBUFFER iface
) {
955 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
956 /* TRACE("(%p) ref was %ld\n",This, This->ref); */
958 return ++(This
->ref
);
960 static DWORD WINAPI
IDirectSoundBufferImpl_Release(LPDIRECTSOUNDBUFFER iface
) {
961 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
964 /* TRACE("(%p) ref was %ld\n",This, This->ref); */
969 EnterCriticalSection(&(This
->dsound
->lock
));
970 for (i
=0;i
<This
->dsound
->nrofbuffers
;i
++)
971 if (This
->dsound
->buffers
[i
] == This
)
973 if (i
< This
->dsound
->nrofbuffers
) {
974 /* Put the last buffer of the list in the (now empty) position */
975 This
->dsound
->buffers
[i
] = This
->dsound
->buffers
[This
->dsound
->nrofbuffers
- 1];
976 This
->dsound
->buffers
= HeapReAlloc(GetProcessHeap(),0,This
->dsound
->buffers
,sizeof(LPDIRECTSOUNDBUFFER
)*This
->dsound
->nrofbuffers
);
977 This
->dsound
->nrofbuffers
--;
978 IDirectSound_Release((LPDIRECTSOUND
)This
->dsound
);
980 LeaveCriticalSection(&(This
->dsound
->lock
));
982 DeleteCriticalSection(&(This
->lock
));
983 if (This
->ds3db
&& ICOM_VTBL(This
->ds3db
))
984 IDirectSound3DBuffer_Release((LPDIRECTSOUND3DBUFFER
)This
->ds3db
);
986 /* this is a duplicate buffer */
987 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)This
->parent
);
989 /* this is a toplevel buffer */
990 HeapFree(GetProcessHeap(),0,This
->buffer
);
992 HeapFree(GetProcessHeap(),0,This
);
994 if (This
== primarybuf
)
1000 static HRESULT WINAPI
IDirectSoundBufferImpl_GetCurrentPosition(
1001 LPDIRECTSOUNDBUFFER iface
,LPDWORD playpos
,LPDWORD writepos
1003 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1004 TRACE("(%p,%p,%p)\n",This
,playpos
,writepos
);
1005 if (playpos
) *playpos
= This
->playpos
;
1006 if (writepos
) *writepos
= This
->writepos
;
1007 TRACE("playpos = %ld, writepos = %ld\n", playpos
?*playpos
:0, writepos
?*writepos
:0);
1011 static HRESULT WINAPI
IDirectSoundBufferImpl_GetStatus(
1012 LPDIRECTSOUNDBUFFER iface
,LPDWORD status
1014 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1015 TRACE("(%p,%p)\n",This
,status
);
1018 return DSERR_INVALIDPARAM
;
1022 *status
|= DSBSTATUS_PLAYING
;
1023 if (This
->playflags
& DSBPLAY_LOOPING
)
1024 *status
|= DSBSTATUS_LOOPING
;
1030 static HRESULT WINAPI
IDirectSoundBufferImpl_GetFormat(
1031 LPDIRECTSOUNDBUFFER iface
,LPWAVEFORMATEX lpwf
,DWORD wfsize
,LPDWORD wfwritten
1033 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1034 TRACE("(%p,%p,%ld,%p)\n",This
,lpwf
,wfsize
,wfwritten
);
1036 if (wfsize
>sizeof(This
->wfx
))
1037 wfsize
= sizeof(This
->wfx
);
1038 if (lpwf
) { /* NULL is valid */
1039 memcpy(lpwf
,&(This
->wfx
),wfsize
);
1041 *wfwritten
= wfsize
;
1044 *wfwritten
= sizeof(This
->wfx
);
1046 return DSERR_INVALIDPARAM
;
1051 static HRESULT WINAPI
IDirectSoundBufferImpl_Lock(
1052 LPDIRECTSOUNDBUFFER iface
,DWORD writecursor
,DWORD writebytes
,LPVOID lplpaudioptr1
,LPDWORD audiobytes1
,LPVOID lplpaudioptr2
,LPDWORD audiobytes2
,DWORD flags
1054 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1056 TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx)\n",
1066 if (flags
& DSBLOCK_FROMWRITECURSOR
)
1067 writecursor
+= This
->writepos
;
1068 if (flags
& DSBLOCK_ENTIREBUFFER
)
1069 writebytes
= This
->buflen
;
1070 if (writebytes
> This
->buflen
)
1071 writebytes
= This
->buflen
;
1073 assert(audiobytes1
!=audiobytes2
);
1074 assert(lplpaudioptr1
!=lplpaudioptr2
);
1075 if (writecursor
+writebytes
<= This
->buflen
) {
1076 *(LPBYTE
*)lplpaudioptr1
= This
->buffer
+writecursor
;
1077 *audiobytes1
= writebytes
;
1079 *(LPBYTE
*)lplpaudioptr2
= NULL
;
1082 TRACE("->%ld.0\n",writebytes
);
1084 *(LPBYTE
*)lplpaudioptr1
= This
->buffer
+writecursor
;
1085 *audiobytes1
= This
->buflen
-writecursor
;
1087 *(LPBYTE
*)lplpaudioptr2
= This
->buffer
;
1089 *audiobytes2
= writebytes
-(This
->buflen
-writecursor
);
1090 TRACE("->%ld.%ld\n",*audiobytes1
,audiobytes2
?*audiobytes2
:0);
1092 /* No. See file:///cdrom/sdk52/docs/worddoc/dsound.doc page 21 */
1093 /* This->writepos=(writecursor+writebytes)%This->buflen; */
1097 static HRESULT WINAPI
IDirectSoundBufferImpl_SetCurrentPosition(
1098 LPDIRECTSOUNDBUFFER iface
,DWORD newpos
1100 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1101 TRACE("(%p,%ld)\n",This
,newpos
);
1104 EnterCriticalSection(&(This
->lock
));
1106 This
->playpos
= newpos
;
1108 LeaveCriticalSection(&(This
->lock
));
1114 static HRESULT WINAPI
IDirectSoundBufferImpl_SetPan(
1115 LPDIRECTSOUNDBUFFER iface
,LONG pan
1117 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1120 TRACE("(%p,%ld)\n",This
,pan
);
1122 if ((pan
> DSBPAN_RIGHT
) || (pan
< DSBPAN_LEFT
))
1123 return DSERR_INVALIDPARAM
;
1125 /* You cannot set the pan of the primary buffer */
1126 /* and you cannot use both pan and 3D controls */
1127 if (!(This
->dsbd
.dwFlags
& DSBCAPS_CTRLPAN
) ||
1128 (This
->dsbd
.dwFlags
& DSBCAPS_CTRL3D
) ||
1129 (This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
))
1130 return DSERR_CONTROLUNAVAIL
;
1133 EnterCriticalSection(&(This
->lock
));
1137 temp
= (double) (This
->volume
- (This
->pan
> 0 ? This
->pan
: 0));
1138 This
->lVolAdjust
= (ULONG
) (pow(2.0, temp
/ 600.0) * 32768.0);
1139 temp
= (double) (This
->volume
+ (This
->pan
< 0 ? This
->pan
: 0));
1140 This
->rVolAdjust
= (ULONG
) (pow(2.0, temp
/ 600.0) * 32768.0);
1142 LeaveCriticalSection(&(This
->lock
));
1148 static HRESULT WINAPI
IDirectSoundBufferImpl_GetPan(
1149 LPDIRECTSOUNDBUFFER iface
,LPLONG pan
1151 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1152 TRACE("(%p,%p)\n",This
,pan
);
1155 return DSERR_INVALIDPARAM
;
1162 static HRESULT WINAPI
IDirectSoundBufferImpl_Unlock(
1163 LPDIRECTSOUNDBUFFER iface
,LPVOID p1
,DWORD x1
,LPVOID p2
,DWORD x2
1165 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1166 TRACE("(%p,%p,%ld,%p,%ld):stub\n", This
,p1
,x1
,p2
,x2
);
1168 /* There is really nothing to do here. Should someone */
1169 /* choose to implement static buffers in hardware (by */
1170 /* using a wave table synth, for example) this is where */
1171 /* you'd want to do the loading. For software buffers, */
1172 /* which is what we currently use, we need do nothing. */
1175 /* It's also the place to pre-process 3D buffers... */
1177 /* This is highly experimental and liable to break things */
1178 if (This
->dsbd
.dwFlags
& DSBCAPS_CTRL3D
)
1179 DSOUND_Create3DBuffer(This
);
1185 static HRESULT WINAPI
IDirectSoundBufferImpl_GetFrequency(
1186 LPDIRECTSOUNDBUFFER iface
,LPDWORD freq
1188 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1189 TRACE("(%p,%p)\n",This
,freq
);
1192 return DSERR_INVALIDPARAM
;
1195 TRACE("-> %ld\n", *freq
);
1200 static HRESULT WINAPI
IDirectSoundBufferImpl_Initialize(
1201 LPDIRECTSOUNDBUFFER iface
,LPDIRECTSOUND dsound
,LPDSBUFFERDESC dbsd
1203 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1204 FIXME("(%p,%p,%p):stub\n",This
,dsound
,dbsd
);
1205 DPRINTF("Re-Init!!!\n");
1206 return DSERR_ALREADYINITIALIZED
;
1209 static HRESULT WINAPI
IDirectSoundBufferImpl_GetCaps(
1210 LPDIRECTSOUNDBUFFER iface
,LPDSBCAPS caps
1212 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1213 TRACE("(%p)->(%p)\n",This
,caps
);
1216 return DSERR_INVALIDPARAM
;
1218 /* I think we should check this value, not set it. See */
1219 /* Inside DirectX, p215. That should apply here, too. */
1220 caps
->dwSize
= sizeof(*caps
);
1222 caps
->dwFlags
= This
->dsbd
.dwFlags
| DSBCAPS_LOCSOFTWARE
;
1223 caps
->dwBufferBytes
= This
->dsbd
.dwBufferBytes
;
1224 /* This value represents the speed of the "unlock" command.
1225 As unlock is quite fast (it does not do anything), I put
1226 4096 ko/s = 4 Mo / s */
1227 caps
->dwUnlockTransferRate
= 4096;
1228 caps
->dwPlayCpuOverhead
= 0;
1233 static HRESULT WINAPI
IDirectSoundBufferImpl_QueryInterface(
1234 LPDIRECTSOUNDBUFFER iface
,REFIID riid
,LPVOID
*ppobj
1236 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1238 TRACE("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
1240 if ( IsEqualGUID( &IID_IDirectSoundNotify
, riid
) ) {
1241 IDirectSoundNotifyImpl
*dsn
;
1243 dsn
= (IDirectSoundNotifyImpl
*)HeapAlloc(GetProcessHeap(),0,sizeof(*dsn
));
1246 IDirectSoundBuffer_AddRef(iface
);
1247 ICOM_VTBL(dsn
) = &dsnvt
;
1248 *ppobj
= (LPVOID
)dsn
;
1252 if ( IsEqualGUID( &IID_IDirectSound3DBuffer
, riid
) ) {
1253 *ppobj
= This
->ds3db
;
1261 static ICOM_VTABLE(IDirectSoundBuffer
) dsbvt
=
1263 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1264 IDirectSoundBufferImpl_QueryInterface
,
1265 IDirectSoundBufferImpl_AddRef
,
1266 IDirectSoundBufferImpl_Release
,
1267 IDirectSoundBufferImpl_GetCaps
,
1268 IDirectSoundBufferImpl_GetCurrentPosition
,
1269 IDirectSoundBufferImpl_GetFormat
,
1270 IDirectSoundBufferImpl_GetVolume
,
1271 IDirectSoundBufferImpl_GetPan
,
1272 IDirectSoundBufferImpl_GetFrequency
,
1273 IDirectSoundBufferImpl_GetStatus
,
1274 IDirectSoundBufferImpl_Initialize
,
1275 IDirectSoundBufferImpl_Lock
,
1276 IDirectSoundBufferImpl_Play
,
1277 IDirectSoundBufferImpl_SetCurrentPosition
,
1278 IDirectSoundBufferImpl_SetFormat
,
1279 IDirectSoundBufferImpl_SetVolume
,
1280 IDirectSoundBufferImpl_SetPan
,
1281 IDirectSoundBufferImpl_SetFrequency
,
1282 IDirectSoundBufferImpl_Stop
,
1283 IDirectSoundBufferImpl_Unlock
1286 /*******************************************************************************
1290 static HRESULT WINAPI
IDirectSoundImpl_SetCooperativeLevel(
1291 LPDIRECTSOUND iface
,HWND hwnd
,DWORD level
1293 ICOM_THIS(IDirectSoundImpl
,iface
);
1294 FIXME("(%p,%08lx,%ld):stub\n",This
,(DWORD
)hwnd
,level
);
1298 static HRESULT WINAPI
IDirectSoundImpl_CreateSoundBuffer(
1299 LPDIRECTSOUND iface
,LPDSBUFFERDESC dsbd
,LPLPDIRECTSOUNDBUFFER ppdsb
,LPUNKNOWN lpunk
1301 ICOM_THIS(IDirectSoundImpl
,iface
);
1302 IDirectSoundBufferImpl
** ippdsb
=(IDirectSoundBufferImpl
**)ppdsb
;
1303 LPWAVEFORMATEX wfex
;
1305 TRACE("(%p,%p,%p,%p)\n",This
,dsbd
,ippdsb
,lpunk
);
1307 if ((This
== NULL
) || (dsbd
== NULL
) || (ippdsb
== NULL
))
1308 return DSERR_INVALIDPARAM
;
1310 if (TRACE_ON(dsound
)) {
1311 TRACE("(structsize=%ld)\n",dsbd
->dwSize
);
1312 TRACE("(flags=0x%08lx:\n",dsbd
->dwFlags
);
1313 _dump_DSBCAPS(dsbd
->dwFlags
);
1315 TRACE("(bufferbytes=%ld)\n",dsbd
->dwBufferBytes
);
1316 TRACE("(lpwfxFormat=%p)\n",dsbd
->lpwfxFormat
);
1319 wfex
= dsbd
->lpwfxFormat
;
1322 TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld,"
1323 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
1324 wfex
->wFormatTag
, wfex
->nChannels
, wfex
->nSamplesPerSec
,
1325 wfex
->nAvgBytesPerSec
, wfex
->nBlockAlign
,
1326 wfex
->wBitsPerSample
, wfex
->cbSize
);
1328 if (dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
1330 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER
)primarybuf
);
1331 *ippdsb
= primarybuf
;
1332 primarybuf
->dsbd
.dwFlags
= dsbd
->dwFlags
;
1334 } /* Else create primarybuf */
1337 *ippdsb
= (IDirectSoundBufferImpl
*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDirectSoundBufferImpl
));
1338 if (*ippdsb
== NULL
)
1339 return DSERR_OUTOFMEMORY
;
1342 TRACE("Created buffer at %p\n", *ippdsb
);
1344 if (dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
1345 (*ippdsb
)->buflen
= dsound
->wfx
.nAvgBytesPerSec
;
1346 (*ippdsb
)->freq
= dsound
->wfx
.nSamplesPerSec
;
1348 (*ippdsb
)->buflen
= dsbd
->dwBufferBytes
;
1349 (*ippdsb
)->freq
= dsbd
->lpwfxFormat
->nSamplesPerSec
;
1351 (*ippdsb
)->buffer
= (LPBYTE
)HeapAlloc(GetProcessHeap(),0,(*ippdsb
)->buflen
);
1352 if ((*ippdsb
)->buffer
== NULL
) {
1353 HeapFree(GetProcessHeap(),0,(*ippdsb
));
1355 return DSERR_OUTOFMEMORY
;
1357 /* It's not necessary to initialize values to zero since */
1358 /* we allocated this structure with HEAP_ZERO_MEMORY... */
1359 (*ippdsb
)->playpos
= 0;
1360 (*ippdsb
)->writepos
= 0;
1361 (*ippdsb
)->parent
= NULL
;
1362 ICOM_VTBL(*ippdsb
) = &dsbvt
;
1363 (*ippdsb
)->dsound
= This
;
1364 (*ippdsb
)->playing
= 0;
1365 (*ippdsb
)->lVolAdjust
= (1 << 15);
1366 (*ippdsb
)->rVolAdjust
= (1 << 15);
1368 if (!(dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
)) {
1369 (*ippdsb
)->freqAdjust
= ((*ippdsb
)->freq
<< DSOUND_FREQSHIFT
) /
1370 primarybuf
->wfx
.nSamplesPerSec
;
1371 (*ippdsb
)->nAvgBytesPerSec
= (*ippdsb
)->freq
*
1372 dsbd
->lpwfxFormat
->nBlockAlign
;
1375 memcpy(&((*ippdsb
)->dsbd
),dsbd
,sizeof(*dsbd
));
1377 EnterCriticalSection(&(This
->lock
));
1378 /* register buffer */
1379 if (!(dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
)) {
1380 This
->buffers
= (IDirectSoundBufferImpl
**)HeapReAlloc(GetProcessHeap(),0,This
->buffers
,sizeof(IDirectSoundBufferImpl
*)*(This
->nrofbuffers
+1));
1381 This
->buffers
[This
->nrofbuffers
] = *ippdsb
;
1382 This
->nrofbuffers
++;
1384 LeaveCriticalSection(&(This
->lock
));
1386 IDirectSound_AddRef(iface
);
1388 if (dsbd
->lpwfxFormat
)
1389 memcpy(&((*ippdsb
)->wfx
), dsbd
->lpwfxFormat
, sizeof((*ippdsb
)->wfx
));
1391 InitializeCriticalSection(&((*ippdsb
)->lock
));
1394 if (dsbd
->dwFlags
& DSBCAPS_CTRL3D
) {
1395 IDirectSound3DBufferImpl
*ds3db
;
1397 ds3db
= (IDirectSound3DBufferImpl
*)HeapAlloc(GetProcessHeap(),
1400 ds3db
->dsb
= (*ippdsb
);
1401 ICOM_VTBL(ds3db
) = &ds3dbvt
;
1402 (*ippdsb
)->ds3db
= ds3db
;
1403 ds3db
->ds3db
.dwSize
= sizeof(DS3DBUFFER
);
1404 ds3db
->ds3db
.vPosition
.x
.x
= 0.0;
1405 ds3db
->ds3db
.vPosition
.y
.y
= 0.0;
1406 ds3db
->ds3db
.vPosition
.z
.z
= 0.0;
1407 ds3db
->ds3db
.vVelocity
.x
.x
= 0.0;
1408 ds3db
->ds3db
.vVelocity
.y
.y
= 0.0;
1409 ds3db
->ds3db
.vVelocity
.z
.z
= 0.0;
1410 ds3db
->ds3db
.dwInsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
1411 ds3db
->ds3db
.dwOutsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
1412 ds3db
->ds3db
.vConeOrientation
.x
.x
= 0.0;
1413 ds3db
->ds3db
.vConeOrientation
.y
.y
= 0.0;
1414 ds3db
->ds3db
.vConeOrientation
.z
.z
= 0.0;
1415 ds3db
->ds3db
.lConeOutsideVolume
= DS3D_DEFAULTCONEOUTSIDEVOLUME
;
1416 ds3db
->ds3db
.flMinDistance
= DS3D_DEFAULTMINDISTANCE
;
1417 ds3db
->ds3db
.flMaxDistance
= DS3D_DEFAULTMAXDISTANCE
;
1418 ds3db
->ds3db
.dwMode
= DS3DMODE_NORMAL
;
1419 ds3db
->buflen
= ((*ippdsb
)->buflen
* primarybuf
->wfx
.nBlockAlign
) /
1420 (*ippdsb
)->wfx
.nBlockAlign
;
1421 ds3db
->buffer
= HeapAlloc(GetProcessHeap(), 0, ds3db
->buflen
);
1422 if (ds3db
->buffer
== NULL
) {
1424 ds3db
->ds3db
.dwMode
= DS3DMODE_DISABLE
;
1431 static HRESULT WINAPI
IDirectSoundImpl_DuplicateSoundBuffer(
1432 LPDIRECTSOUND iface
,LPDIRECTSOUNDBUFFER pdsb
,LPLPDIRECTSOUNDBUFFER ppdsb
1434 ICOM_THIS(IDirectSoundImpl
,iface
);
1435 IDirectSoundBufferImpl
* ipdsb
=(IDirectSoundBufferImpl
*)pdsb
;
1436 IDirectSoundBufferImpl
** ippdsb
=(IDirectSoundBufferImpl
**)ppdsb
;
1437 TRACE("(%p,%p,%p)\n",This
,ipdsb
,ippdsb
);
1439 *ippdsb
= (IDirectSoundBufferImpl
*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDirectSoundBufferImpl
));
1441 IDirectSoundBuffer_AddRef(pdsb
);
1442 memcpy(*ippdsb
, ipdsb
, sizeof(IDirectSoundBufferImpl
));
1444 (*ippdsb
)->playpos
= 0;
1445 (*ippdsb
)->writepos
= 0;
1446 (*ippdsb
)->dsound
= This
;
1447 (*ippdsb
)->parent
= ipdsb
;
1448 memcpy(&((*ippdsb
)->wfx
), &(ipdsb
->wfx
), sizeof((*ippdsb
)->wfx
));
1449 /* register buffer */
1450 EnterCriticalSection(&(This
->lock
));
1451 This
->buffers
= (IDirectSoundBufferImpl
**)HeapReAlloc(GetProcessHeap(),0,This
->buffers
,sizeof(IDirectSoundBufferImpl
**)*(This
->nrofbuffers
+1));
1452 This
->buffers
[This
->nrofbuffers
] = *ippdsb
;
1453 This
->nrofbuffers
++;
1454 IDirectSound_AddRef(iface
);
1455 LeaveCriticalSection(&(This
->lock
));
1460 static HRESULT WINAPI
IDirectSoundImpl_GetCaps(LPDIRECTSOUND iface
,LPDSCAPS caps
) {
1461 ICOM_THIS(IDirectSoundImpl
,iface
);
1462 TRACE("(%p,%p)\n",This
,caps
);
1463 TRACE("(flags=0x%08lx)\n",caps
->dwFlags
);
1466 return DSERR_INVALIDPARAM
;
1468 /* We should check this value, not set it. See Inside DirectX, p215. */
1469 caps
->dwSize
= sizeof(*caps
);
1472 DSCAPS_PRIMARYSTEREO
|
1473 DSCAPS_PRIMARY16BIT
|
1474 DSCAPS_SECONDARYSTEREO
|
1475 DSCAPS_SECONDARY16BIT
|
1476 DSCAPS_CONTINUOUSRATE
;
1477 /* FIXME: query OSS */
1478 caps
->dwMinSecondarySampleRate
= DSBFREQUENCY_MIN
;
1479 caps
->dwMaxSecondarySampleRate
= DSBFREQUENCY_MAX
;
1481 caps
->dwPrimaryBuffers
= 1;
1483 caps
->dwMaxHwMixingAllBuffers
= 0;
1484 caps
->dwMaxHwMixingStaticBuffers
= 0;
1485 caps
->dwMaxHwMixingStreamingBuffers
= 0;
1487 caps
->dwFreeHwMixingAllBuffers
= 0;
1488 caps
->dwFreeHwMixingStaticBuffers
= 0;
1489 caps
->dwFreeHwMixingStreamingBuffers
= 0;
1491 caps
->dwMaxHw3DAllBuffers
= 0;
1492 caps
->dwMaxHw3DStaticBuffers
= 0;
1493 caps
->dwMaxHw3DStreamingBuffers
= 0;
1495 caps
->dwFreeHw3DAllBuffers
= 0;
1496 caps
->dwFreeHw3DStaticBuffers
= 0;
1497 caps
->dwFreeHw3DStreamingBuffers
= 0;
1499 caps
->dwTotalHwMemBytes
= 0;
1501 caps
->dwFreeHwMemBytes
= 0;
1503 caps
->dwMaxContigFreeHwMemBytes
= 0;
1505 caps
->dwUnlockTransferRateHwBuffers
= 4096; /* But we have none... */
1507 caps
->dwPlayCpuOverheadSwBuffers
= 1; /* 1% */
1512 static ULONG WINAPI
IDirectSoundImpl_AddRef(LPDIRECTSOUND iface
) {
1513 ICOM_THIS(IDirectSoundImpl
,iface
);
1514 return ++(This
->ref
);
1517 static ULONG WINAPI
IDirectSoundImpl_Release(LPDIRECTSOUND iface
) {
1518 ICOM_THIS(IDirectSoundImpl
,iface
);
1519 TRACE("(%p), ref was %ld\n",This
,This
->ref
);
1520 if (!--(This
->ref
)) {
1521 DSOUND_CloseAudio();
1522 while(IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)primarybuf
)); /* Deallocate */
1523 FIXME("need to release all buffers!\n");
1524 HeapFree(GetProcessHeap(),0,This
);
1531 static HRESULT WINAPI
IDirectSoundImpl_SetSpeakerConfig(
1532 LPDIRECTSOUND iface
,DWORD config
1534 ICOM_THIS(IDirectSoundImpl
,iface
);
1535 FIXME("(%p,0x%08lx):stub\n",This
,config
);
1539 static HRESULT WINAPI
IDirectSoundImpl_QueryInterface(
1540 LPDIRECTSOUND iface
,REFIID riid
,LPVOID
*ppobj
1542 ICOM_THIS(IDirectSoundImpl
,iface
);
1544 if ( IsEqualGUID( &IID_IDirectSound3DListener
, riid
) ) {
1546 if (This
->listener
) {
1547 *ppobj
= This
->listener
;
1550 This
->listener
= (IDirectSound3DListenerImpl
*)HeapAlloc(
1551 GetProcessHeap(), 0, sizeof(*(This
->listener
)));
1552 This
->listener
->ref
= 1;
1553 ICOM_VTBL(This
->listener
) = &ds3dlvt
;
1554 IDirectSound_AddRef(iface
);
1555 This
->listener
->ds3dl
.dwSize
= sizeof(DS3DLISTENER
);
1556 This
->listener
->ds3dl
.vPosition
.x
.x
= 0.0;
1557 This
->listener
->ds3dl
.vPosition
.y
.y
= 0.0;
1558 This
->listener
->ds3dl
.vPosition
.z
.z
= 0.0;
1559 This
->listener
->ds3dl
.vVelocity
.x
.x
= 0.0;
1560 This
->listener
->ds3dl
.vVelocity
.y
.y
= 0.0;
1561 This
->listener
->ds3dl
.vVelocity
.z
.z
= 0.0;
1562 This
->listener
->ds3dl
.vOrientFront
.x
.x
= 0.0;
1563 This
->listener
->ds3dl
.vOrientFront
.y
.y
= 0.0;
1564 This
->listener
->ds3dl
.vOrientFront
.z
.z
= 1.0;
1565 This
->listener
->ds3dl
.vOrientTop
.x
.x
= 0.0;
1566 This
->listener
->ds3dl
.vOrientTop
.y
.y
= 1.0;
1567 This
->listener
->ds3dl
.vOrientTop
.z
.z
= 0.0;
1568 This
->listener
->ds3dl
.flDistanceFactor
= DS3D_DEFAULTDISTANCEFACTOR
;
1569 This
->listener
->ds3dl
.flRolloffFactor
= DS3D_DEFAULTROLLOFFFACTOR
;
1570 This
->listener
->ds3dl
.flDopplerFactor
= DS3D_DEFAULTDOPPLERFACTOR
;
1571 *ppobj
= (LPVOID
)This
->listener
;
1575 TRACE("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
1579 static HRESULT WINAPI
IDirectSoundImpl_Compact(
1580 LPDIRECTSOUND iface
)
1582 ICOM_THIS(IDirectSoundImpl
,iface
);
1583 TRACE("(%p)\n", This
);
1587 static HRESULT WINAPI
IDirectSoundImpl_GetSpeakerConfig(
1588 LPDIRECTSOUND iface
,
1589 LPDWORD lpdwSpeakerConfig
)
1591 ICOM_THIS(IDirectSoundImpl
,iface
);
1592 TRACE("(%p, %p)\n", This
, lpdwSpeakerConfig
);
1593 *lpdwSpeakerConfig
= DSSPEAKER_STEREO
| (DSSPEAKER_GEOMETRY_NARROW
<< 16);
1597 static HRESULT WINAPI
IDirectSoundImpl_Initialize(
1598 LPDIRECTSOUND iface
,
1601 ICOM_THIS(IDirectSoundImpl
,iface
);
1602 TRACE("(%p, %p)\n", This
, lpGuid
);
1606 static ICOM_VTABLE(IDirectSound
) dsvt
=
1608 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1609 IDirectSoundImpl_QueryInterface
,
1610 IDirectSoundImpl_AddRef
,
1611 IDirectSoundImpl_Release
,
1612 IDirectSoundImpl_CreateSoundBuffer
,
1613 IDirectSoundImpl_GetCaps
,
1614 IDirectSoundImpl_DuplicateSoundBuffer
,
1615 IDirectSoundImpl_SetCooperativeLevel
,
1616 IDirectSoundImpl_Compact
,
1617 IDirectSoundImpl_GetSpeakerConfig
,
1618 IDirectSoundImpl_SetSpeakerConfig
,
1619 IDirectSoundImpl_Initialize
1623 /* See http://www.opensound.com/pguide/audio.html for more details */
1626 DSOUND_setformat(LPWAVEFORMATEX wfex
) {
1627 int xx
,channels
,speed
,format
,nformat
;
1630 TRACE("(%p) deferred\n", wfex
);
1633 switch (wfex
->wFormatTag
) {
1635 WARN("unknown WAVE_FORMAT tag %d\n",wfex
->wFormatTag
);
1636 return DSERR_BADFORMAT
;
1637 case WAVE_FORMAT_PCM
:
1640 if (wfex
->wBitsPerSample
==8)
1643 format
= AFMT_S16_LE
;
1645 if (-1==ioctl(audiofd
,SNDCTL_DSP_GETFMTS
,&xx
)) {
1646 perror("ioctl SNDCTL_DSP_GETFMTS");
1649 if ((xx
&format
)!=format
) {/* format unsupported */
1650 FIXME("SNDCTL_DSP_GETFMTS: format not supported\n");
1654 if (-1==ioctl(audiofd
,SNDCTL_DSP_SETFMT
,&nformat
)) {
1655 perror("ioctl SNDCTL_DSP_SETFMT");
1658 if (nformat
!=format
) {/* didn't work */
1659 FIXME("SNDCTL_DSP_GETFMTS: format not set\n");
1663 channels
= wfex
->nChannels
-1;
1664 if (-1==ioctl(audiofd
,SNDCTL_DSP_STEREO
,&channels
)) {
1665 perror("ioctl SNDCTL_DSP_STEREO");
1668 speed
= wfex
->nSamplesPerSec
;
1669 if (-1==ioctl(audiofd
,SNDCTL_DSP_SPEED
,&speed
)) {
1670 perror("ioctl SNDCTL_DSP_SPEED");
1673 TRACE("(freq=%ld,channels=%d,bits=%d)\n",
1674 wfex
->nSamplesPerSec
,wfex
->nChannels
,wfex
->wBitsPerSample
1679 static void DSOUND_CheckEvent(IDirectSoundBufferImpl
*dsb
, int len
)
1683 LPDSBPOSITIONNOTIFY event
;
1685 if (dsb
->nrofnotifies
== 0)
1688 TRACE("(%p) buflen = %ld, playpos = %ld, len = %d\n",
1689 dsb
, dsb
->buflen
, dsb
->playpos
, len
);
1690 for (i
= 0; i
< dsb
->nrofnotifies
; i
++) {
1691 event
= dsb
->notifies
+ i
;
1692 offset
= event
->dwOffset
;
1693 TRACE("checking %d, position %ld, event = %d\n",
1694 i
, offset
, event
->hEventNotify
);
1695 /* DSBPN_OFFSETSTOP has to be the last element. So this is */
1696 /* OK. [Inside DirectX, p274] */
1698 /* This also means we can't sort the entries by offset, */
1699 /* because DSBPN_OFFSETSTOP == -1 */
1700 if (offset
== DSBPN_OFFSETSTOP
) {
1701 if (dsb
->playing
== 0) {
1702 SetEvent(event
->hEventNotify
);
1703 TRACE("signalled event %d (%d)\n", event
->hEventNotify
, i
);
1708 if ((dsb
->playpos
+ len
) >= dsb
->buflen
) {
1709 if ((offset
< ((dsb
->playpos
+ len
) % dsb
->buflen
)) ||
1710 (offset
>= dsb
->playpos
)) {
1711 TRACE("signalled event %d (%d)\n", event
->hEventNotify
, i
);
1712 SetEvent(event
->hEventNotify
);
1715 if ((offset
>= dsb
->playpos
) && (offset
< (dsb
->playpos
+ len
))) {
1716 TRACE("signalled event %d (%d)\n", event
->hEventNotify
, i
);
1717 SetEvent(event
->hEventNotify
);
1723 /* WAV format info can be found at: */
1725 /* http://www.cwi.nl/ftp/audio/AudioFormats.part2 */
1726 /* ftp://ftp.cwi.nl/pub/audio/RIFF-format */
1728 /* Import points to remember: */
1730 /* 8-bit WAV is unsigned */
1731 /* 16-bit WAV is signed */
1733 static inline INT16
cvtU8toS16(BYTE byte
)
1735 INT16 s
= (byte
- 128) << 8;
1740 static inline BYTE
cvtS16toU8(INT16 word
)
1742 BYTE b
= (word
+ 32768) >> 8;
1748 /* We should be able to optimize these two inline functions */
1749 /* so that we aren't doing 8->16->8 conversions when it is */
1750 /* not necessary. But this is still a WIP. Optimize later. */
1751 static inline void get_fields(const IDirectSoundBufferImpl
*dsb
, BYTE
*buf
, INT
*fl
, INT
*fr
)
1753 INT16
*bufs
= (INT16
*) buf
;
1755 /* TRACE("(%p)", buf); */
1756 if ((dsb
->wfx
.wBitsPerSample
== 8) && dsb
->wfx
.nChannels
== 2) {
1757 *fl
= cvtU8toS16(*buf
);
1758 *fr
= cvtU8toS16(*(buf
+ 1));
1762 if ((dsb
->wfx
.wBitsPerSample
== 16) && dsb
->wfx
.nChannels
== 2) {
1768 if ((dsb
->wfx
.wBitsPerSample
== 8) && dsb
->wfx
.nChannels
== 1) {
1769 *fl
= cvtU8toS16(*buf
);
1774 if ((dsb
->wfx
.wBitsPerSample
== 16) && dsb
->wfx
.nChannels
== 1) {
1780 FIXME("get_fields found an unsupported configuration\n");
1784 static inline void set_fields(BYTE
*buf
, INT fl
, INT fr
)
1786 INT16
*bufs
= (INT16
*) buf
;
1788 if ((primarybuf
->wfx
.wBitsPerSample
== 8) && (primarybuf
->wfx
.nChannels
== 2)) {
1789 *buf
= cvtS16toU8(fl
);
1790 *(buf
+ 1) = cvtS16toU8(fr
);
1794 if ((primarybuf
->wfx
.wBitsPerSample
== 16) && (primarybuf
->wfx
.nChannels
== 2)) {
1800 if ((primarybuf
->wfx
.wBitsPerSample
== 8) && (primarybuf
->wfx
.nChannels
== 1)) {
1801 *buf
= cvtS16toU8((fl
+ fr
) >> 1);
1805 if ((primarybuf
->wfx
.wBitsPerSample
== 16) && (primarybuf
->wfx
.nChannels
== 1)) {
1806 *bufs
= (fl
+ fr
) >> 1;
1809 FIXME("set_fields found an unsupported configuration\n");
1813 /* Now with PerfectPitch (tm) technology */
1814 static INT
DSOUND_MixerNorm(IDirectSoundBufferImpl
*dsb
, BYTE
*buf
, INT len
)
1816 INT i
, size
, ipos
, ilen
, fieldL
, fieldR
;
1818 INT iAdvance
= dsb
->wfx
.nBlockAlign
;
1819 INT oAdvance
= primarybuf
->wfx
.nBlockAlign
;
1821 ibp
= dsb
->buffer
+ dsb
->playpos
;
1824 TRACE("(%p, %p, %p), playpos=%8.8lx\n", dsb
, ibp
, obp
, dsb
->playpos
);
1825 /* Check for the best case */
1826 if ((dsb
->freq
== primarybuf
->wfx
.nSamplesPerSec
) &&
1827 (dsb
->wfx
.wBitsPerSample
== primarybuf
->wfx
.wBitsPerSample
) &&
1828 (dsb
->wfx
.nChannels
== primarybuf
->wfx
.nChannels
)) {
1829 DWORD bytesleft
= dsb
->buflen
- dsb
->playpos
;
1830 TRACE("(%p) Best case\n", dsb
);
1831 if (len
<= bytesleft
)
1832 memcpy(obp
, ibp
, len
);
1834 memcpy(obp
, ibp
, bytesleft
);
1835 memcpy(obp
+ bytesleft
, dsb
->buffer
, len
- bytesleft
);
1840 /* Check for same sample rate */
1841 if (dsb
->freq
== primarybuf
->wfx
.nSamplesPerSec
) {
1842 TRACE("(%p) Same sample rate %ld = primary %ld\n", dsb
,
1843 dsb
->freq
, primarybuf
->wfx
.nSamplesPerSec
);
1845 for (i
= 0; i
< len
; i
+= oAdvance
) {
1846 get_fields(dsb
, ibp
, &fieldL
, &fieldR
);
1849 set_fields(obp
, fieldL
, fieldR
);
1851 if (ibp
>= (BYTE
*)(dsb
->buffer
+ dsb
->buflen
))
1852 ibp
= dsb
->buffer
; /* wrap */
1857 /* Mix in different sample rates */
1859 /* New PerfectPitch(tm) Technology (c) 1998 Rob Riggs */
1860 /* Patent Pending :-] */
1862 TRACE("(%p) Adjusting frequency: %ld -> %ld\n",
1863 dsb
, dsb
->freq
, primarybuf
->wfx
.nSamplesPerSec
);
1865 size
= len
/ oAdvance
;
1866 ilen
= ((size
* dsb
->freqAdjust
) >> DSOUND_FREQSHIFT
) * iAdvance
;
1867 for (i
= 0; i
< size
; i
++) {
1869 ipos
= (((i
* dsb
->freqAdjust
) >> DSOUND_FREQSHIFT
) * iAdvance
) + dsb
->playpos
;
1871 if (ipos
>= dsb
->buflen
)
1872 ipos
%= dsb
->buflen
; /* wrap */
1874 get_fields(dsb
, (dsb
->buffer
+ ipos
), &fieldL
, &fieldR
);
1875 set_fields(obp
, fieldL
, fieldR
);
1881 static void DSOUND_MixerVol(IDirectSoundBufferImpl
*dsb
, BYTE
*buf
, INT len
)
1883 INT i
, inc
= primarybuf
->wfx
.wBitsPerSample
>> 3;
1885 INT16
*bps
= (INT16
*) buf
;
1887 TRACE("(%p) left = %lx, right = %lx\n", dsb
,
1888 dsb
->lVolAdjust
, dsb
->rVolAdjust
);
1889 if ((!(dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLPAN
) || (dsb
->pan
== 0)) &&
1890 (!(dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLVOLUME
) || (dsb
->volume
== 0)) &&
1891 !(dsb
->dsbd
.dwFlags
& DSBCAPS_CTRL3D
))
1892 return; /* Nothing to do */
1894 /* If we end up with some bozo coder using panning or 3D sound */
1895 /* with a mono primary buffer, it could sound very weird using */
1896 /* this method. Oh well, tough patooties. */
1898 for (i
= 0; i
< len
; i
+= inc
) {
1904 /* 8-bit WAV is unsigned, but we need to operate */
1905 /* on signed data for this to work properly */
1907 val
= ((val
* (i
& inc
? dsb
->rVolAdjust
: dsb
->lVolAdjust
)) >> 15);
1912 /* 16-bit WAV is signed -- much better */
1914 val
= ((val
* ((i
& inc
) ? dsb
->rVolAdjust
: dsb
->lVolAdjust
)) >> 15);
1920 FIXME("MixerVol had a nasty error\n");
1926 static void DSOUND_Mixer3D(IDirectSoundBufferImpl
*dsb
, BYTE
*buf
, INT len
)
1929 DWORD buflen
, playpos
;
1931 buflen
= dsb
->ds3db
->buflen
;
1932 playpos
= (dsb
->playpos
* primarybuf
->wfx
.nBlockAlign
) / dsb
->wfx
.nBlockAlign
;
1933 ibp
= dsb
->ds3db
->buffer
+ playpos
;
1936 if (playpos
> buflen
) {
1937 FIXME("Major breakage");
1941 if (len
<= (playpos
+ buflen
))
1942 memcpy(obp
, ibp
, len
);
1944 memcpy(obp
, ibp
, buflen
- playpos
);
1945 memcpy(obp
+ (buflen
- playpos
),
1947 len
- (buflen
- playpos
));
1953 static void *tmp_buffer
;
1954 static size_t tmp_buffer_len
= 0;
1956 static void *DSOUND_tmpbuffer(size_t len
)
1958 if (len
>tmp_buffer_len
) {
1959 void *new_buffer
= realloc(tmp_buffer
, len
);
1961 tmp_buffer
= new_buffer
;
1962 tmp_buffer_len
= len
;
1969 static DWORD
DSOUND_MixInBuffer(IDirectSoundBufferImpl
*dsb
)
1971 INT i
, len
, ilen
, temp
, field
;
1972 INT advance
= primarybuf
->wfx
.wBitsPerSample
>> 3;
1973 BYTE
*buf
, *ibuf
, *obuf
;
1974 INT16
*ibufs
, *obufs
;
1976 len
= DSOUND_FRAGLEN
; /* The most we will use */
1977 if (!(dsb
->playflags
& DSBPLAY_LOOPING
)) {
1978 temp
= MulDiv(primarybuf
->wfx
.nAvgBytesPerSec
, dsb
->buflen
,
1979 dsb
->nAvgBytesPerSec
) -
1980 MulDiv(primarybuf
->wfx
.nAvgBytesPerSec
, dsb
->playpos
,
1981 dsb
->nAvgBytesPerSec
);
1982 len
= (len
> temp
) ? temp
: len
;
1984 len
&= ~3; /* 4 byte alignment */
1987 /* This should only happen if we aren't looping and temp < 4 */
1989 /* We skip the remainder, so check for possible events */
1990 DSOUND_CheckEvent(dsb
, dsb
->buflen
- dsb
->playpos
);
1995 /* Check for DSBPN_OFFSETSTOP */
1996 DSOUND_CheckEvent(dsb
, 0);
2000 /* Been seeing segfaults in malloc() for some reason... */
2001 TRACE("allocating buffer (size = %d)\n", len
);
2002 if ((buf
= ibuf
= (BYTE
*) DSOUND_tmpbuffer(len
)) == NULL
)
2005 TRACE("MixInBuffer (%p) len = %d\n", dsb
, len
);
2007 ilen
= DSOUND_MixerNorm(dsb
, ibuf
, len
);
2008 if ((dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLPAN
) ||
2009 (dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLVOLUME
))
2010 DSOUND_MixerVol(dsb
, ibuf
, len
);
2012 obuf
= primarybuf
->buffer
+ primarybuf
->playpos
;
2013 for (i
= 0; i
< len
; i
+= advance
) {
2014 obufs
= (INT16
*) obuf
;
2015 ibufs
= (INT16
*) ibuf
;
2016 if (primarybuf
->wfx
.wBitsPerSample
== 8) {
2017 /* 8-bit WAV is unsigned */
2018 field
= (*ibuf
- 128);
2019 field
+= (*obuf
- 128);
2020 field
= field
> 127 ? 127 : field
;
2021 field
= field
< -128 ? -128 : field
;
2022 *obuf
= field
+ 128;
2024 /* 16-bit WAV is signed */
2027 field
= field
> 32767 ? 32767 : field
;
2028 field
= field
< -32768 ? -32768 : field
;
2033 if (obuf
>= (BYTE
*)(primarybuf
->buffer
+ primarybuf
->buflen
))
2034 obuf
= primarybuf
->buffer
;
2038 if (dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLPOSITIONNOTIFY
)
2039 DSOUND_CheckEvent(dsb
, ilen
);
2041 dsb
->playpos
+= ilen
;
2042 dsb
->writepos
= dsb
->playpos
+ ilen
;
2044 if (dsb
->playpos
>= dsb
->buflen
) {
2045 if (!(dsb
->playflags
& DSBPLAY_LOOPING
)) {
2049 DSOUND_CheckEvent(dsb
, 0); /* For DSBPN_OFFSETSTOP */
2051 dsb
->playpos
%= dsb
->buflen
; /* wrap */
2054 if (dsb
->writepos
>= dsb
->buflen
)
2055 dsb
->writepos
%= dsb
->buflen
;
2060 static DWORD WINAPI
DSOUND_MixPrimary(void)
2062 INT i
, len
, maxlen
= 0;
2063 IDirectSoundBufferImpl
*dsb
;
2065 for (i
= dsound
->nrofbuffers
- 1; i
>= 0; i
--) {
2066 dsb
= dsound
->buffers
[i
];
2068 if (!dsb
|| !(ICOM_VTBL(dsb
)))
2070 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER
)dsb
);
2071 if (dsb
->buflen
&& dsb
->playing
) {
2072 EnterCriticalSection(&(dsb
->lock
));
2073 len
= DSOUND_MixInBuffer(dsb
);
2074 maxlen
= len
> maxlen
? len
: maxlen
;
2075 LeaveCriticalSection(&(dsb
->lock
));
2077 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)dsb
);
2083 static int DSOUND_OpenAudio(void)
2085 int audioFragment
,flags
;
2087 if (primarybuf
== NULL
)
2088 return DSERR_OUTOFMEMORY
;
2090 while (audiofd
>= 0)
2093 /* we will most likely not get one, avoid excessive opens ... */
2094 if (audiofd
== -ENODEV
)
2096 audiofd
= open("/dev/audio",O_WRONLY
|O_NDELAY
);
2098 /* Don't worry if sound is busy at the moment */
2099 if ((errno
!= EBUSY
) && (errno
!= ENODEV
))
2100 perror("open /dev/audio");
2105 /* We should probably do something here if SETFRAGMENT fails... */
2106 audioFragment
=0x0002000c;
2107 if (-1==ioctl(audiofd
,SNDCTL_DSP_SETFRAGMENT
,&audioFragment
))
2108 perror("ioctl SETFRAGMENT");
2110 if ((flags
= fcntl(audiofd
,F_GETFL
,0)) != -1) {
2112 if (-1==fcntl(audiofd
,F_SETFL
,flags
))
2113 perror("clearing the non-blocking flags in DSOUND_OpenAudio");
2115 perror("cannot get flags of audiofd");
2118 DSOUND_setformat(&(primarybuf
->wfx
));
2123 static void DSOUND_CloseAudio(void)
2127 neutral
= primarybuf
->wfx
.wBitsPerSample
== 8 ? 128 : 0;
2128 audioOK
= 0; /* race condition */
2130 /* It's possible we've been called with audio closed */
2131 /* from SetFormat()... this is just to force a call */
2132 /* to OpenAudio() to reset the hardware properly */
2135 primarybuf
->playpos
= 0;
2136 primarybuf
->writepos
= DSOUND_FRAGLEN
;
2137 memset(primarybuf
->buffer
, neutral
, primarybuf
->buflen
);
2139 TRACE("Audio stopped\n");
2142 static int DSOUND_WriteAudio(char *buf
, int len
)
2144 int result
, left
= 0;
2146 while (left
< len
) {
2147 result
= write(audiofd
, buf
+ left
, len
- left
);
2159 static void DSOUND_OutputPrimary(int len
)
2161 int neutral
, flen1
, flen2
;
2162 char *frag1
, *frag2
;
2164 /* This is a bad place for this. We need to clear the */
2165 /* buffer with a neutral value, for unsigned 8-bit WAVE */
2166 /* that's 128, for signed 16-bit it's 0 */
2167 neutral
= primarybuf
->wfx
.wBitsPerSample
== 8 ? 128 : 0;
2170 EnterCriticalSection(&(primarybuf
->lock
));
2173 if ((audioOK
== 1) || (DSOUND_OpenAudio() == 0)) {
2174 if (primarybuf
->playpos
+ len
>= primarybuf
->buflen
) {
2175 frag1
= primarybuf
->buffer
+ primarybuf
->playpos
;
2176 flen1
= primarybuf
->buflen
- primarybuf
->playpos
;
2177 frag2
= primarybuf
->buffer
;
2178 flen2
= len
- (primarybuf
->buflen
- primarybuf
->playpos
);
2179 if (DSOUND_WriteAudio(frag1
, flen1
) != 0) {
2180 perror("DSOUND_WriteAudio");
2181 LeaveCriticalSection(&(primarybuf
->lock
));
2184 memset(frag1
, neutral
, flen1
);
2185 if (DSOUND_WriteAudio(frag2
, flen2
) != 0) {
2186 perror("DSOUND_WriteAudio");
2187 LeaveCriticalSection(&(primarybuf
->lock
));
2190 memset(frag2
, neutral
, flen2
);
2192 frag1
= primarybuf
->buffer
+ primarybuf
->playpos
;
2194 if (DSOUND_WriteAudio(frag1
, flen1
) != 0) {
2195 perror("DSOUND_WriteAudio");
2196 LeaveCriticalSection(&(primarybuf
->lock
));
2199 memset(frag1
, neutral
, flen1
);
2202 /* Can't play audio at the moment -- we need to sleep */
2203 /* to make up for the time we'd be blocked in write() */
2207 primarybuf
->playpos
+= len
;
2208 if (primarybuf
->playpos
>= primarybuf
->buflen
)
2209 primarybuf
->playpos
%= primarybuf
->buflen
;
2210 primarybuf
->writepos
= primarybuf
->playpos
+ DSOUND_FRAGLEN
;
2211 if (primarybuf
->writepos
>= primarybuf
->buflen
)
2212 primarybuf
->writepos
%= primarybuf
->buflen
;
2214 LeaveCriticalSection(&(primarybuf
->lock
));
2218 static DWORD WINAPI
DSOUND_thread(LPVOID arg
)
2222 TRACE("dsound is at pid %d\n",getpid());
2225 WARN("DSOUND thread giving up.\n");
2229 /* EP: since the thread creating this thread can
2230 * die before the end of the DSOUND one, this
2232 * What shall be tested is whether the DSOUND thread
2233 * is the last one in the process
2236 WARN("DSOUND father died? Giving up.\n");
2240 /* RACE: dsound could be deleted */
2241 EnterCriticalSection(&(dsound
->lock
));
2242 if (primarybuf
== NULL
) {
2243 /* Should never happen */
2244 WARN("Lost the primary buffer!\n");
2245 IDirectSound_Release((LPDIRECTSOUND
)dsound
);
2249 EnterCriticalSection(&(primarybuf
->lock
));
2251 len
= DSOUND_MixPrimary();
2253 LeaveCriticalSection(&(primarybuf
->lock
));
2254 LeaveCriticalSection(&(dsound
->lock
));
2256 if (primarybuf
->playing
)
2257 len
= DSOUND_FRAGLEN
> len
? DSOUND_FRAGLEN
: len
;
2259 /* This does all the work */
2260 DSOUND_OutputPrimary(len
);
2262 /* no buffers playing -- close and wait */
2264 DSOUND_CloseAudio();
2271 #endif /* HAVE_OSS */
2273 /*******************************************************************************
2276 HRESULT WINAPI
DirectSoundCreate(REFGUID lpGUID
,LPDIRECTSOUND
*ppDS
,IUnknown
*pUnkOuter
)
2278 IDirectSoundImpl
** ippDS
=(IDirectSoundImpl
**)ppDS
;
2280 TRACE("(%p,%p,%p)\n",lpGUID
,ippDS
,pUnkOuter
);
2282 TRACE("DirectSoundCreate (%p)\n", ippDS
);
2287 return DSERR_INVALIDPARAM
;
2290 IDirectSound_AddRef((LPDIRECTSOUND
)dsound
);
2295 /* Check that we actually have audio capabilities */
2296 /* If we do, whether it's busy or not, we continue */
2297 /* otherwise we return with DSERR_NODRIVER */
2299 audiofd
= open("/dev/audio",O_WRONLY
|O_NDELAY
);
2300 if (audiofd
== -1) {
2302 if (errno
== ENODEV
) {
2303 MESSAGE("No sound hardware found, but continuing anyway.\n");
2304 } else if (errno
== EBUSY
) {
2305 MESSAGE("Sound device busy, will keep trying.\n");
2307 MESSAGE("Unexpected error (%d) while checking for sound support.\n",errno
);
2308 return DSERR_GENERIC
;
2315 *ippDS
= (IDirectSoundImpl
*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundImpl
));
2317 return DSERR_OUTOFMEMORY
;
2320 ICOM_VTBL(*ippDS
) = &dsvt
;
2321 (*ippDS
)->buffers
= NULL
;
2322 (*ippDS
)->nrofbuffers
= 0;
2324 (*ippDS
)->wfx
.wFormatTag
= 1;
2325 (*ippDS
)->wfx
.nChannels
= 2;
2326 (*ippDS
)->wfx
.nSamplesPerSec
= 22050;
2327 (*ippDS
)->wfx
.nAvgBytesPerSec
= 44100;
2328 (*ippDS
)->wfx
.nBlockAlign
= 2;
2329 (*ippDS
)->wfx
.wBitsPerSample
= 8;
2331 InitializeCriticalSection(&((*ippDS
)->lock
));
2338 if (primarybuf
== NULL
) {
2342 dsbd
.dwSize
= sizeof(DSBUFFERDESC
);
2343 dsbd
.dwFlags
= DSBCAPS_PRIMARYBUFFER
;
2344 dsbd
.dwBufferBytes
= 0;
2345 dsbd
.lpwfxFormat
= &(dsound
->wfx
);
2346 hr
= IDirectSound_CreateSoundBuffer(*ppDS
, &dsbd
, (LPDIRECTSOUNDBUFFER
*)&primarybuf
, NULL
);
2349 dsound
->primary
= primarybuf
;
2351 memset(primarybuf
->buffer
, 128, primarybuf
->buflen
);
2352 hnd
= CreateThread(NULL
,0,DSOUND_thread
,0,0,&xid
);
2356 MessageBoxA(0,"DirectSound needs the Open Sound System Driver, which has not been found by ./configure.","WINE DirectSound",MB_OK
|MB_ICONSTOP
);
2357 return DSERR_NODRIVER
;
2361 /*******************************************************************************
2362 * DirectSound ClassFactory
2366 /* IUnknown fields */
2367 ICOM_VFIELD(IClassFactory
);
2369 } IClassFactoryImpl
;
2371 static HRESULT WINAPI
2372 DSCF_QueryInterface(LPCLASSFACTORY iface
,REFIID riid
,LPVOID
*ppobj
) {
2373 ICOM_THIS(IClassFactoryImpl
,iface
);
2375 FIXME("(%p)->(%s,%p),stub!\n",This
,debugstr_guid(riid
),ppobj
);
2376 return E_NOINTERFACE
;
2380 DSCF_AddRef(LPCLASSFACTORY iface
) {
2381 ICOM_THIS(IClassFactoryImpl
,iface
);
2382 return ++(This
->ref
);
2385 static ULONG WINAPI
DSCF_Release(LPCLASSFACTORY iface
) {
2386 ICOM_THIS(IClassFactoryImpl
,iface
);
2387 /* static class, won't be freed */
2388 return --(This
->ref
);
2391 static HRESULT WINAPI
DSCF_CreateInstance(
2392 LPCLASSFACTORY iface
,LPUNKNOWN pOuter
,REFIID riid
,LPVOID
*ppobj
2394 ICOM_THIS(IClassFactoryImpl
,iface
);
2396 TRACE("(%p)->(%p,%s,%p)\n",This
,pOuter
,debugstr_guid(riid
),ppobj
);
2397 if ( IsEqualGUID( &IID_IDirectSound
, riid
) ) {
2398 /* FIXME: reuse already created dsound if present? */
2399 return DirectSoundCreate(riid
,(LPDIRECTSOUND
*)ppobj
,pOuter
);
2401 return E_NOINTERFACE
;
2404 static HRESULT WINAPI
DSCF_LockServer(LPCLASSFACTORY iface
,BOOL dolock
) {
2405 ICOM_THIS(IClassFactoryImpl
,iface
);
2406 FIXME("(%p)->(%d),stub!\n",This
,dolock
);
2410 static ICOM_VTABLE(IClassFactory
) DSCF_Vtbl
= {
2411 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
2412 DSCF_QueryInterface
,
2415 DSCF_CreateInstance
,
2418 static IClassFactoryImpl DSOUND_CF
= {&DSCF_Vtbl
, 1 };
2420 /*******************************************************************************
2421 * DllGetClassObject [DSOUND.4]
2422 * Retrieves class object from a DLL object
2425 * Docs say returns STDAPI
2428 * rclsid [I] CLSID for the class object
2429 * riid [I] Reference to identifier of interface for class object
2430 * ppv [O] Address of variable to receive interface pointer for riid
2434 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
2437 DWORD WINAPI
DSOUND_DllGetClassObject(REFCLSID rclsid
,REFIID riid
,LPVOID
*ppv
)
2439 TRACE("(%p,%p,%p)\n", debugstr_guid(rclsid
), debugstr_guid(riid
), ppv
);
2440 if ( IsEqualCLSID( &IID_IClassFactory
, riid
) ) {
2441 *ppv
= (LPVOID
)&DSOUND_CF
;
2442 IClassFactory_AddRef((IClassFactory
*)*ppv
);
2446 FIXME("(%p,%p,%p): no interface found.\n", debugstr_guid(rclsid
), debugstr_guid(riid
), ppv
);
2447 return CLASS_E_CLASSNOTAVAILABLE
;
2451 /*******************************************************************************
2452 * DllCanUnloadNow [DSOUND.3] Determines whether the DLL is in use.
2458 DWORD WINAPI
DSOUND_DllCanUnloadNow(void)
2460 FIXME("(void): stub\n");