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
57 #include <sys/types.h>
59 #include <sys/fcntl.h>
63 #include <math.h> /* Insomnia - pow() function */
67 #include "wine/obj_base.h"
69 #include "debugtools.h"
71 DEFAULT_DEBUG_CHANNEL(dsound
)
74 /*****************************************************************************
75 * Predeclare the interface implementation structures
77 typedef struct IDirectSoundImpl IDirectSoundImpl
;
78 typedef struct IDirectSoundBufferImpl IDirectSoundBufferImpl
;
79 typedef struct IDirectSoundNotifyImpl IDirectSoundNotifyImpl
;
80 typedef struct IDirectSound3DListenerImpl IDirectSound3DListenerImpl
;
81 typedef struct IDirectSound3DBufferImpl IDirectSound3DBufferImpl
;
83 /*****************************************************************************
84 * IDirectSound implementation structure
86 struct IDirectSoundImpl
89 ICOM_VTABLE(IDirectSound
)* lpvtbl
;
91 /* IDirectSoundImpl fields */
94 IDirectSoundBufferImpl
** buffers
;
95 IDirectSoundBufferImpl
* primary
;
96 IDirectSound3DListenerImpl
* listener
;
97 WAVEFORMATEX wfx
; /* current main waveformat */
100 /*****************************************************************************
101 * IDirectSoundBuffer implementation structure
103 struct IDirectSoundBufferImpl
105 /* IUnknown fields */
106 ICOM_VTABLE(IDirectSoundBuffer
)* lpvtbl
;
108 /* IDirectSoundBufferImpl fields */
111 IDirectSound3DBufferImpl
* ds3db
;
112 DWORD playflags
,playing
;
113 DWORD playpos
,writepos
,buflen
;
114 DWORD nAvgBytesPerSec
;
118 LONG lVolAdjust
,rVolAdjust
;
119 IDirectSoundBufferImpl
* parent
; /* for duplicates */
120 IDirectSoundImpl
* dsound
;
122 LPDSBPOSITIONNOTIFY notifies
;
124 CRITICAL_SECTION lock
;
127 /*****************************************************************************
128 * IDirectSoundNotify implementation structure
130 struct IDirectSoundNotifyImpl
132 /* IUnknown fields */
133 ICOM_VTABLE(IDirectSoundNotify
)* lpvtbl
;
135 /* IDirectSoundNotifyImpl fields */
136 IDirectSoundBufferImpl
* dsb
;
139 /*****************************************************************************
140 * IDirectSound3DListener implementation structure
142 struct IDirectSound3DListenerImpl
144 /* IUnknown fields */
145 ICOM_VTABLE(IDirectSound3DListener
)* lpvtbl
;
147 /* IDirectSound3DListenerImpl fields */
148 IDirectSoundBufferImpl
* dsb
;
150 CRITICAL_SECTION lock
;
153 /*****************************************************************************
154 * IDirectSound3DBuffer implementation structure
156 struct IDirectSound3DBufferImpl
158 /* IUnknown fields */
159 ICOM_VTABLE(IDirectSound3DBuffer
)* lpvtbl
;
161 /* IDirectSound3DBufferImpl fields */
162 IDirectSoundBufferImpl
* dsb
;
166 CRITICAL_SECTION lock
;
171 # include <sys/ioctl.h>
172 # ifdef HAVE_MACHINE_SOUNDCARD_H
173 # include <machine/soundcard.h>
175 # ifdef HAVE_SYS_SOUNDCARD_H
176 # include <sys/soundcard.h>
179 /* #define USE_DSOUND3D 1 */
181 #define DSOUND_FRAGLEN (primarybuf->wfx.nAvgBytesPerSec >> 4)
182 #define DSOUND_FREQSHIFT (14)
184 static int audiofd
= -1;
185 static int audioOK
= 0;
187 static IDirectSoundImpl
* dsound
= NULL
;
189 static IDirectSoundBufferImpl
* primarybuf
= NULL
;
191 static int DSOUND_setformat(LPWAVEFORMATEX wfex
);
192 static void DSOUND_CheckEvent(IDirectSoundBufferImpl
*dsb
, int len
);
193 static void DSOUND_CloseAudio(void);
198 HRESULT WINAPI
DirectSoundEnumerateA(
199 LPDSENUMCALLBACKA enumcb
,
202 TRACE("enumcb = %p, context = %p\n", enumcb
, context
);
206 enumcb(NULL
,"WINE DirectSound using Open Sound System",
214 static void _dump_DSBCAPS(DWORD xmask
) {
219 #define FE(x) { x, #x },
220 FE(DSBCAPS_PRIMARYBUFFER
)
222 FE(DSBCAPS_LOCHARDWARE
)
223 FE(DSBCAPS_LOCSOFTWARE
)
224 FE(DSBCAPS_CTRLFREQUENCY
)
226 FE(DSBCAPS_CTRLVOLUME
)
227 FE(DSBCAPS_CTRLDEFAULT
)
229 FE(DSBCAPS_STICKYFOCUS
)
230 FE(DSBCAPS_GETCURRENTPOSITION2
)
234 for (i
=0;i
<sizeof(flags
)/sizeof(flags
[0]);i
++)
235 if (flags
[i
].mask
& xmask
)
236 fprintf(stderr
,"%s ",flags
[i
].name
);
239 /*******************************************************************************
240 * IDirectSound3DBuffer
243 /* IUnknown methods */
244 static HRESULT WINAPI
IDirectSound3DBufferImpl_QueryInterface(
245 LPDIRECTSOUND3DBUFFER iface
, REFIID riid
, LPVOID
*ppobj
)
247 ICOM_THIS(IDirectSound3DBufferImpl
,iface
);
250 WINE_StringFromCLSID(riid
,xbuf
);
251 TRACE("(%p,%s,%p)\n",This
,xbuf
,ppobj
);
255 static ULONG WINAPI
IDirectSound3DBufferImpl_AddRef(LPDIRECTSOUND3DBUFFER iface
)
257 ICOM_THIS(IDirectSound3DBufferImpl
,iface
);
262 static ULONG WINAPI
IDirectSound3DBufferImpl_Release(LPDIRECTSOUND3DBUFFER iface
)
264 ICOM_THIS(IDirectSound3DBufferImpl
,iface
);
268 HeapFree(GetProcessHeap(),0,This
->buffer
);
269 HeapFree(GetProcessHeap(),0,This
);
274 /* IDirectSound3DBuffer methods */
275 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetAllParameters(
276 LPDIRECTSOUND3DBUFFER iface
,
277 LPDS3DBUFFER lpDs3dBuffer
)
283 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetConeAngles(
284 LPDIRECTSOUND3DBUFFER iface
,
285 LPDWORD lpdwInsideConeAngle
,
286 LPDWORD lpdwOutsideConeAngle
)
292 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetConeOrientation(
293 LPDIRECTSOUND3DBUFFER iface
,
294 LPD3DVECTOR lpvConeOrientation
)
300 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetConeOutsideVolume(
301 LPDIRECTSOUND3DBUFFER iface
,
302 LPLONG lplConeOutsideVolume
)
308 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetMaxDistance(
309 LPDIRECTSOUND3DBUFFER iface
,
310 LPD3DVALUE lpfMaxDistance
)
316 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetMinDistance(
317 LPDIRECTSOUND3DBUFFER iface
,
318 LPD3DVALUE lpfMinDistance
)
324 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetMode(
325 LPDIRECTSOUND3DBUFFER iface
,
332 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetPosition(
333 LPDIRECTSOUND3DBUFFER iface
,
334 LPD3DVECTOR lpvPosition
)
340 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetVelocity(
341 LPDIRECTSOUND3DBUFFER iface
,
342 LPD3DVECTOR lpvVelocity
)
348 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetAllParameters(
349 LPDIRECTSOUND3DBUFFER iface
,
350 LPCDS3DBUFFER lpcDs3dBuffer
,
357 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetConeAngles(
358 LPDIRECTSOUND3DBUFFER iface
,
359 DWORD dwInsideConeAngle
,
360 DWORD dwOutsideConeAngle
,
367 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetConeOrientation(
368 LPDIRECTSOUND3DBUFFER iface
,
369 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
376 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetConeOutsideVolume(
377 LPDIRECTSOUND3DBUFFER iface
,
378 LONG lConeOutsideVolume
,
385 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetMaxDistance(
386 LPDIRECTSOUND3DBUFFER iface
,
387 D3DVALUE fMaxDistance
,
394 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetMinDistance(
395 LPDIRECTSOUND3DBUFFER iface
,
396 D3DVALUE fMinDistance
,
403 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetMode(
404 LPDIRECTSOUND3DBUFFER iface
,
408 ICOM_THIS(IDirectSound3DBufferImpl
,iface
);
409 TRACE("mode = %lx\n", dwMode
);
410 This
->ds3db
.dwMode
= dwMode
;
414 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetPosition(
415 LPDIRECTSOUND3DBUFFER iface
,
416 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
423 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetVelocity(
424 LPDIRECTSOUND3DBUFFER iface
,
425 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
432 ICOM_VTABLE(IDirectSound3DBuffer
) ds3dbvt
=
434 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
435 /* IUnknown methods */
436 IDirectSound3DBufferImpl_QueryInterface
,
437 IDirectSound3DBufferImpl_AddRef
,
438 IDirectSound3DBufferImpl_Release
,
439 /* IDirectSound3DBuffer methods */
440 IDirectSound3DBufferImpl_GetAllParameters
,
441 IDirectSound3DBufferImpl_GetConeAngles
,
442 IDirectSound3DBufferImpl_GetConeOrientation
,
443 IDirectSound3DBufferImpl_GetConeOutsideVolume
,
444 IDirectSound3DBufferImpl_GetMaxDistance
,
445 IDirectSound3DBufferImpl_GetMinDistance
,
446 IDirectSound3DBufferImpl_GetMode
,
447 IDirectSound3DBufferImpl_GetPosition
,
448 IDirectSound3DBufferImpl_GetVelocity
,
449 IDirectSound3DBufferImpl_SetAllParameters
,
450 IDirectSound3DBufferImpl_SetConeAngles
,
451 IDirectSound3DBufferImpl_SetConeOrientation
,
452 IDirectSound3DBufferImpl_SetConeOutsideVolume
,
453 IDirectSound3DBufferImpl_SetMaxDistance
,
454 IDirectSound3DBufferImpl_SetMinDistance
,
455 IDirectSound3DBufferImpl_SetMode
,
456 IDirectSound3DBufferImpl_SetPosition
,
457 IDirectSound3DBufferImpl_SetVelocity
,
461 static int DSOUND_Create3DBuffer(IDirectSoundBufferImpl
* dsb
)
463 DWORD i
, temp
, iSize
, oSize
, offset
;
464 LPBYTE bIbuf
, bObuf
, bTbuf
= NULL
;
465 LPWORD wIbuf
, wObuf
, wTbuf
= NULL
;
467 /* Inside DirectX says it's stupid but allowed */
468 if (dsb
->wfx
.nChannels
== 2) {
469 /* Convert to mono */
470 if (dsb
->wfx
.wBitsPerSample
== 16) {
471 iSize
= dsb
->buflen
/ 4;
472 wTbuf
= malloc(dsb
->buflen
/ 2);
474 return DSERR_OUTOFMEMORY
;
475 for (i
= 0; i
< iSize
; i
++)
476 wTbuf
[i
] = (dsb
->buffer
[i
] + dsb
->buffer
[(i
* 2) + 1]) / 2;
479 iSize
= dsb
->buflen
/ 2;
480 bTbuf
= malloc(dsb
->buflen
/ 2);
482 return DSERR_OUTOFMEMORY
;
483 for (i
= 0; i
< iSize
; i
++)
484 bTbuf
[i
] = (dsb
->buffer
[i
] + dsb
->buffer
[(i
* 2) + 1]) / 2;
488 if (dsb
->wfx
.wBitsPerSample
== 16) {
489 iSize
= dsb
->buflen
/ 2;
490 wIbuf
= (LPWORD
) dsb
->buffer
;
492 bIbuf
= (LPBYTE
) dsb
->buffer
;
497 if (primarybuf
->wfx
.wBitsPerSample
== 16) {
498 wObuf
= (LPWORD
) dsb
->ds3db
->buffer
;
499 oSize
= dsb
->ds3db
->buflen
/ 2;
501 bObuf
= (LPBYTE
) dsb
->ds3db
->buffer
;
502 oSize
= dsb
->ds3db
->buflen
;
505 offset
= primarybuf
->wfx
.nSamplesPerSec
/ 100; /* 10ms */
506 if (primarybuf
->wfx
.wBitsPerSample
== 16 && dsb
->wfx
.wBitsPerSample
== 16)
507 for (i
= 0; i
< iSize
; i
++) {
510 temp
+= wIbuf
[i
- offset
] >> 9;
512 temp
+= wIbuf
[i
+ iSize
- offset
] >> 9;
514 wObuf
[(i
* 2) + 1] = temp
;
516 else if (primarybuf
->wfx
.wBitsPerSample
== 8 && dsb
->wfx
.wBitsPerSample
== 8)
517 for (i
= 0; i
< iSize
; i
++) {
520 temp
+= bIbuf
[i
- offset
] >> 5;
522 temp
+= bIbuf
[i
+ iSize
- offset
] >> 5;
524 bObuf
[(i
* 2) + 1] = temp
;
535 /*******************************************************************************
536 * IDirectSound3DListener
539 /* IUnknown methods */
540 static HRESULT WINAPI
IDirectSound3DListenerImpl_QueryInterface(
541 LPDIRECTSOUND3DLISTENER iface
, REFIID riid
, LPVOID
*ppobj
)
543 ICOM_THIS(IDirectSound3DListenerImpl
,iface
);
546 WINE_StringFromCLSID(riid
,xbuf
);
547 TRACE("(%p,%s,%p)\n",This
,xbuf
,ppobj
);
551 static ULONG WINAPI
IDirectSound3DListenerImpl_AddRef(LPDIRECTSOUND3DLISTENER iface
)
553 ICOM_THIS(IDirectSound3DListenerImpl
,iface
);
558 static ULONG WINAPI
IDirectSound3DListenerImpl_Release(LPDIRECTSOUND3DLISTENER iface
)
560 ICOM_THIS(IDirectSound3DListenerImpl
,iface
);
565 /* IDirectSound3DListener methods */
566 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetAllParameter(
567 LPDIRECTSOUND3DLISTENER iface
,
568 LPDS3DLISTENER lpDS3DL
)
574 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetDistanceFactor(
575 LPDIRECTSOUND3DLISTENER iface
,
576 LPD3DVALUE lpfDistanceFactor
)
582 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetDopplerFactor(
583 LPDIRECTSOUND3DLISTENER iface
,
584 LPD3DVALUE lpfDopplerFactor
)
590 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetOrientation(
591 LPDIRECTSOUND3DLISTENER iface
,
592 LPD3DVECTOR lpvOrientFront
,
593 LPD3DVECTOR lpvOrientTop
)
599 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetPosition(
600 LPDIRECTSOUND3DLISTENER iface
,
601 LPD3DVECTOR lpvPosition
)
607 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetRolloffFactor(
608 LPDIRECTSOUND3DLISTENER iface
,
609 LPD3DVALUE lpfRolloffFactor
)
615 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetVelocity(
616 LPDIRECTSOUND3DLISTENER iface
,
617 LPD3DVECTOR lpvVelocity
)
623 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetAllParameters(
624 LPDIRECTSOUND3DLISTENER iface
,
625 LPCDS3DLISTENER lpcDS3DL
,
632 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetDistanceFactor(
633 LPDIRECTSOUND3DLISTENER iface
,
634 D3DVALUE fDistanceFactor
,
641 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetDopplerFactor(
642 LPDIRECTSOUND3DLISTENER iface
,
643 D3DVALUE fDopplerFactor
,
650 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetOrientation(
651 LPDIRECTSOUND3DLISTENER iface
,
652 D3DVALUE xFront
, D3DVALUE yFront
, D3DVALUE zFront
,
653 D3DVALUE xTop
, D3DVALUE yTop
, D3DVALUE zTop
,
660 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetPosition(
661 LPDIRECTSOUND3DLISTENER iface
,
662 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
669 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetRolloffFactor(
670 LPDIRECTSOUND3DLISTENER iface
,
671 D3DVALUE fRolloffFactor
,
678 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetVelocity(
679 LPDIRECTSOUND3DLISTENER iface
,
680 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
687 static HRESULT WINAPI
IDirectSound3DListenerImpl_CommitDeferredSettings(
688 LPDIRECTSOUND3DLISTENER iface
)
695 ICOM_VTABLE(IDirectSound3DListener
) ds3dlvt
=
697 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
698 /* IUnknown methods */
699 IDirectSound3DListenerImpl_QueryInterface
,
700 IDirectSound3DListenerImpl_AddRef
,
701 IDirectSound3DListenerImpl_Release
,
702 /* IDirectSound3DListener methods */
703 IDirectSound3DListenerImpl_GetAllParameter
,
704 IDirectSound3DListenerImpl_GetDistanceFactor
,
705 IDirectSound3DListenerImpl_GetDopplerFactor
,
706 IDirectSound3DListenerImpl_GetOrientation
,
707 IDirectSound3DListenerImpl_GetPosition
,
708 IDirectSound3DListenerImpl_GetRolloffFactor
,
709 IDirectSound3DListenerImpl_GetVelocity
,
710 IDirectSound3DListenerImpl_SetAllParameters
,
711 IDirectSound3DListenerImpl_SetDistanceFactor
,
712 IDirectSound3DListenerImpl_SetDopplerFactor
,
713 IDirectSound3DListenerImpl_SetOrientation
,
714 IDirectSound3DListenerImpl_SetPosition
,
715 IDirectSound3DListenerImpl_SetRolloffFactor
,
716 IDirectSound3DListenerImpl_SetVelocity
,
717 IDirectSound3DListenerImpl_CommitDeferredSettings
,
720 /*******************************************************************************
723 static HRESULT WINAPI
IDirectSoundNotifyImpl_QueryInterface(
724 LPDIRECTSOUNDNOTIFY iface
,REFIID riid
,LPVOID
*ppobj
726 ICOM_THIS(IDirectSoundNotifyImpl
,iface
);
729 WINE_StringFromCLSID(riid
,xbuf
);
730 TRACE("(%p,%s,%p)\n",This
,xbuf
,ppobj
);
734 static ULONG WINAPI
IDirectSoundNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface
) {
735 ICOM_THIS(IDirectSoundNotifyImpl
,iface
);
736 return ++(This
->ref
);
739 static ULONG WINAPI
IDirectSoundNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface
) {
740 ICOM_THIS(IDirectSoundNotifyImpl
,iface
);
743 IDirectSoundNotify_Release((LPDIRECTSOUNDBUFFER
)This
->dsb
);
744 HeapFree(GetProcessHeap(),0,This
);
750 static HRESULT WINAPI
IDirectSoundNotifyImpl_SetNotificationPositions(
751 LPDIRECTSOUNDNOTIFY iface
,DWORD howmuch
,LPCDSBPOSITIONNOTIFY notify
753 ICOM_THIS(IDirectSoundNotifyImpl
,iface
);
756 if (TRACE_ON(dsound
)) {
757 TRACE("(%p,0x%08lx,%p)\n",This
,howmuch
,notify
);
758 for (i
=0;i
<howmuch
;i
++)
759 TRACE("notify at %ld to 0x%08lx\n",
760 notify
[i
].dwOffset
,(DWORD
)notify
[i
].hEventNotify
);
762 This
->dsb
->notifies
= HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,This
->dsb
->notifies
,(This
->dsb
->nrofnotifies
+howmuch
)*sizeof(DSBPOSITIONNOTIFY
));
763 memcpy( This
->dsb
->notifies
+This
->dsb
->nrofnotifies
,
765 howmuch
*sizeof(DSBPOSITIONNOTIFY
)
767 This
->dsb
->nrofnotifies
+=howmuch
;
772 ICOM_VTABLE(IDirectSoundNotify
) dsnvt
=
774 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
775 IDirectSoundNotifyImpl_QueryInterface
,
776 IDirectSoundNotifyImpl_AddRef
,
777 IDirectSoundNotifyImpl_Release
,
778 IDirectSoundNotifyImpl_SetNotificationPositions
,
781 /*******************************************************************************
785 /* This sets this format for the <em>Primary Buffer Only</em> */
786 /* See file:///cdrom/sdk52/docs/worddoc/dsound.doc page 120 */
787 static HRESULT WINAPI
IDirectSoundBufferImpl_SetFormat(
788 LPDIRECTSOUNDBUFFER iface
,LPWAVEFORMATEX wfex
790 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
791 IDirectSoundBufferImpl
** dsb
;
794 /* Let's be pedantic! */
795 if ((wfex
== NULL
) ||
796 (wfex
->wFormatTag
!= WAVE_FORMAT_PCM
) ||
797 (wfex
->nChannels
< 1) || (wfex
->nChannels
> 2) ||
798 (wfex
->nSamplesPerSec
< 1) ||
799 (wfex
->nBlockAlign
< 1) || (wfex
->nChannels
> 4) ||
800 ((wfex
->wBitsPerSample
!= 8) && (wfex
->wBitsPerSample
!= 16))) {
801 TRACE("failed pedantic check!\n");
802 return DSERR_INVALIDPARAM
;
806 EnterCriticalSection(&(primarybuf
->lock
));
808 if (primarybuf
->wfx
.nSamplesPerSec
!= wfex
->nSamplesPerSec
) {
809 dsb
= dsound
->buffers
;
810 for (i
= 0; i
< dsound
->nrofbuffers
; i
++, dsb
++) {
812 EnterCriticalSection(&((*dsb
)->lock
));
814 (*dsb
)->freqAdjust
= ((*dsb
)->freq
<< DSOUND_FREQSHIFT
) /
815 wfex
->nSamplesPerSec
;
817 LeaveCriticalSection(&((*dsb
)->lock
));
822 memcpy(&(primarybuf
->wfx
), wfex
, sizeof(primarybuf
->wfx
));
824 TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld"
825 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
826 wfex
->wFormatTag
, wfex
->nChannels
, wfex
->nSamplesPerSec
,
827 wfex
->nAvgBytesPerSec
, wfex
->nBlockAlign
,
828 wfex
->wBitsPerSample
, wfex
->cbSize
);
830 primarybuf
->wfx
.nAvgBytesPerSec
=
831 This
->wfx
.nSamplesPerSec
* This
->wfx
.nBlockAlign
;
835 LeaveCriticalSection(&(primarybuf
->lock
));
841 static HRESULT WINAPI
IDirectSoundBufferImpl_SetVolume(
842 LPDIRECTSOUNDBUFFER iface
,LONG vol
844 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
847 TRACE("(%p,%ld)\n",This
,vol
);
849 /* I'm not sure if we need this for primary buffer */
850 if (!(This
->dsbd
.dwFlags
& DSBCAPS_CTRLVOLUME
))
851 return DSERR_CONTROLUNAVAIL
;
853 if ((vol
> DSBVOLUME_MAX
) || (vol
< DSBVOLUME_MIN
))
854 return DSERR_INVALIDPARAM
;
856 /* This needs to adjust the soundcard volume when */
857 /* called for the primary buffer */
858 if (This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
859 FIXME("Volume control of primary unimplemented.\n");
865 EnterCriticalSection(&(This
->lock
));
869 temp
= (double) (This
->volume
- (This
->pan
> 0 ? This
->pan
: 0));
870 This
->lVolAdjust
= (ULONG
) (pow(2.0, temp
/ 600.0) * 32768.0);
871 temp
= (double) (This
->volume
+ (This
->pan
< 0 ? This
->pan
: 0));
872 This
->rVolAdjust
= (ULONG
) (pow(2.0, temp
/ 600.0) * 32768.0);
874 LeaveCriticalSection(&(This
->lock
));
877 TRACE("left = %lx, right = %lx\n", This
->lVolAdjust
, This
->rVolAdjust
);
882 static HRESULT WINAPI
IDirectSoundBufferImpl_GetVolume(
883 LPDIRECTSOUNDBUFFER iface
,LPLONG vol
885 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
886 TRACE("(%p,%p)\n",This
,vol
);
889 return DSERR_INVALIDPARAM
;
895 static HRESULT WINAPI
IDirectSoundBufferImpl_SetFrequency(
896 LPDIRECTSOUNDBUFFER iface
,DWORD freq
898 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
899 TRACE("(%p,%ld)\n",This
,freq
);
901 /* You cannot set the frequency of the primary buffer */
902 if (!(This
->dsbd
.dwFlags
& DSBCAPS_CTRLFREQUENCY
) ||
903 (This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
))
904 return DSERR_CONTROLUNAVAIL
;
906 if ((freq
< DSBFREQUENCY_MIN
) || (freq
> DSBFREQUENCY_MAX
))
907 return DSERR_INVALIDPARAM
;
910 EnterCriticalSection(&(This
->lock
));
913 This
->freqAdjust
= (freq
<< DSOUND_FREQSHIFT
) / primarybuf
->wfx
.nSamplesPerSec
;
914 This
->nAvgBytesPerSec
= freq
* This
->wfx
.nBlockAlign
;
916 LeaveCriticalSection(&(This
->lock
));
922 static HRESULT WINAPI
IDirectSoundBufferImpl_Play(
923 LPDIRECTSOUNDBUFFER iface
,DWORD reserved1
,DWORD reserved2
,DWORD flags
925 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
926 TRACE("(%p,%08lx,%08lx,%08lx)\n",
927 This
,reserved1
,reserved2
,flags
929 This
->playflags
= flags
;
934 static HRESULT WINAPI
IDirectSoundBufferImpl_Stop(LPDIRECTSOUNDBUFFER iface
)
936 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
937 TRACE("(%p)\n",This
);
940 EnterCriticalSection(&(This
->lock
));
943 DSOUND_CheckEvent(This
, 0);
945 LeaveCriticalSection(&(This
->lock
));
951 static DWORD WINAPI
IDirectSoundBufferImpl_AddRef(LPDIRECTSOUNDBUFFER iface
) {
952 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
953 /* TRACE(dsound,"(%p) ref was %ld\n",This, This->ref); */
955 return ++(This
->ref
);
957 static DWORD WINAPI
IDirectSoundBufferImpl_Release(LPDIRECTSOUNDBUFFER iface
) {
958 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
961 /* TRACE(dsound,"(%p) ref was %ld\n",This, This->ref); */
966 for (i
=0;i
<This
->dsound
->nrofbuffers
;i
++)
967 if (This
->dsound
->buffers
[i
] == This
)
969 if (i
< This
->dsound
->nrofbuffers
) {
970 /* Put the last buffer of the list in the (now empty) position */
971 This
->dsound
->buffers
[i
] = This
->dsound
->buffers
[This
->dsound
->nrofbuffers
- 1];
972 This
->dsound
->buffers
= HeapReAlloc(GetProcessHeap(),0,This
->dsound
->buffers
,sizeof(LPDIRECTSOUNDBUFFER
)*This
->dsound
->nrofbuffers
);
973 This
->dsound
->nrofbuffers
--;
974 IDirectSound_Release((LPDIRECTSOUND
)This
->dsound
);
977 DeleteCriticalSection(&(This
->lock
));
979 if (This
->ds3db
&& This
->ds3db
->lpvtbl
)
980 IDirectSound3DBuffer_Release((LPDIRECTSOUND3DBUFFER
)This
->ds3db
);
983 /* this is a duplicate buffer */
984 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)This
->parent
);
986 /* this is a toplevel buffer */
987 HeapFree(GetProcessHeap(),0,This
->buffer
);
989 HeapFree(GetProcessHeap(),0,This
);
991 if (This
== primarybuf
)
997 static HRESULT WINAPI
IDirectSoundBufferImpl_GetCurrentPosition(
998 LPDIRECTSOUNDBUFFER iface
,LPDWORD playpos
,LPDWORD writepos
1000 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1001 TRACE("(%p,%p,%p)\n",This
,playpos
,writepos
);
1002 if (playpos
) *playpos
= This
->playpos
;
1003 if (writepos
) *writepos
= This
->writepos
;
1004 TRACE("playpos = %ld, writepos = %ld\n", *playpos
, *writepos
);
1008 static HRESULT WINAPI
IDirectSoundBufferImpl_GetStatus(
1009 LPDIRECTSOUNDBUFFER iface
,LPDWORD status
1011 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1012 TRACE("(%p,%p)\n",This
,status
);
1015 return DSERR_INVALIDPARAM
;
1019 *status
|= DSBSTATUS_PLAYING
;
1020 if (This
->playflags
& DSBPLAY_LOOPING
)
1021 *status
|= DSBSTATUS_LOOPING
;
1027 static HRESULT WINAPI
IDirectSoundBufferImpl_GetFormat(
1028 LPDIRECTSOUNDBUFFER iface
,LPWAVEFORMATEX lpwf
,DWORD wfsize
,LPDWORD wfwritten
1030 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1031 TRACE("(%p,%p,%ld,%p)\n",This
,lpwf
,wfsize
,wfwritten
);
1033 if (wfsize
>sizeof(This
->wfx
))
1034 wfsize
= sizeof(This
->wfx
);
1035 if (lpwf
) { /* NULL is valid */
1036 memcpy(lpwf
,&(This
->wfx
),wfsize
);
1038 *wfwritten
= wfsize
;
1041 *wfwritten
= sizeof(This
->wfx
);
1043 return DSERR_INVALIDPARAM
;
1048 static HRESULT WINAPI
IDirectSoundBufferImpl_Lock(
1049 LPDIRECTSOUNDBUFFER iface
,DWORD writecursor
,DWORD writebytes
,LPVOID lplpaudioptr1
,LPDWORD audiobytes1
,LPVOID lplpaudioptr2
,LPDWORD audiobytes2
,DWORD flags
1051 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1053 TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx)\n",
1063 if (flags
& DSBLOCK_FROMWRITECURSOR
)
1064 writecursor
+= This
->writepos
;
1065 if (flags
& DSBLOCK_ENTIREBUFFER
)
1066 writebytes
= This
->buflen
;
1067 if (writebytes
> This
->buflen
)
1068 writebytes
= This
->buflen
;
1070 assert(audiobytes1
!=audiobytes2
);
1071 assert(lplpaudioptr1
!=lplpaudioptr2
);
1072 if (writecursor
+writebytes
<= This
->buflen
) {
1073 *(LPBYTE
*)lplpaudioptr1
= This
->buffer
+writecursor
;
1074 *audiobytes1
= writebytes
;
1076 *(LPBYTE
*)lplpaudioptr2
= NULL
;
1079 TRACE("->%ld.0\n",writebytes
);
1081 *(LPBYTE
*)lplpaudioptr1
= This
->buffer
+writecursor
;
1082 *audiobytes1
= This
->buflen
-writecursor
;
1084 *(LPBYTE
*)lplpaudioptr2
= This
->buffer
;
1086 *audiobytes2
= writebytes
-(This
->buflen
-writecursor
);
1087 TRACE("->%ld.%ld\n",*audiobytes1
,audiobytes2
?*audiobytes2
:0);
1089 /* No. See file:///cdrom/sdk52/docs/worddoc/dsound.doc page 21 */
1090 /* This->writepos=(writecursor+writebytes)%This->buflen; */
1094 static HRESULT WINAPI
IDirectSoundBufferImpl_SetCurrentPosition(
1095 LPDIRECTSOUNDBUFFER iface
,DWORD newpos
1097 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1098 TRACE("(%p,%ld)\n",This
,newpos
);
1101 EnterCriticalSection(&(This
->lock
));
1103 This
->playpos
= newpos
;
1105 LeaveCriticalSection(&(This
->lock
));
1111 static HRESULT WINAPI
IDirectSoundBufferImpl_SetPan(
1112 LPDIRECTSOUNDBUFFER iface
,LONG pan
1114 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1117 TRACE("(%p,%ld)\n",This
,pan
);
1119 if ((pan
> DSBPAN_RIGHT
) || (pan
< DSBPAN_LEFT
))
1120 return DSERR_INVALIDPARAM
;
1122 /* You cannot set the pan of the primary buffer */
1123 /* and you cannot use both pan and 3D controls */
1124 if (!(This
->dsbd
.dwFlags
& DSBCAPS_CTRLPAN
) ||
1125 (This
->dsbd
.dwFlags
& DSBCAPS_CTRL3D
) ||
1126 (This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
))
1127 return DSERR_CONTROLUNAVAIL
;
1130 EnterCriticalSection(&(This
->lock
));
1134 temp
= (double) (This
->volume
- (This
->pan
> 0 ? This
->pan
: 0));
1135 This
->lVolAdjust
= (ULONG
) (pow(2.0, temp
/ 600.0) * 32768.0);
1136 temp
= (double) (This
->volume
+ (This
->pan
< 0 ? This
->pan
: 0));
1137 This
->rVolAdjust
= (ULONG
) (pow(2.0, temp
/ 600.0) * 32768.0);
1139 LeaveCriticalSection(&(This
->lock
));
1145 static HRESULT WINAPI
IDirectSoundBufferImpl_GetPan(
1146 LPDIRECTSOUNDBUFFER iface
,LPLONG pan
1148 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1149 TRACE("(%p,%p)\n",This
,pan
);
1152 return DSERR_INVALIDPARAM
;
1159 static HRESULT WINAPI
IDirectSoundBufferImpl_Unlock(
1160 LPDIRECTSOUNDBUFFER iface
,LPVOID p1
,DWORD x1
,LPVOID p2
,DWORD x2
1162 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1163 TRACE("(%p,%p,%ld,%p,%ld):stub\n", This
,p1
,x1
,p2
,x2
);
1165 /* There is really nothing to do here. Should someone */
1166 /* choose to implement static buffers in hardware (by */
1167 /* using a wave table synth, for example) this is where */
1168 /* you'd want to do the loading. For software buffers, */
1169 /* which is what we currently use, we need do nothing. */
1172 /* It's also the place to pre-process 3D buffers... */
1174 /* This is highly experimental and liable to break things */
1175 if (This
->dsbd
.dwFlags
& DSBCAPS_CTRL3D
)
1176 DSOUND_Create3DBuffer(This
);
1182 static HRESULT WINAPI
IDirectSoundBufferImpl_GetFrequency(
1183 LPDIRECTSOUNDBUFFER iface
,LPDWORD freq
1185 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1186 TRACE("(%p,%p)\n",This
,freq
);
1189 return DSERR_INVALIDPARAM
;
1196 static HRESULT WINAPI
IDirectSoundBufferImpl_Initialize(
1197 LPDIRECTSOUNDBUFFER iface
,LPDIRECTSOUND dsound
,LPDSBUFFERDESC dbsd
1199 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1200 FIXME("(%p,%p,%p):stub\n",This
,dsound
,dbsd
);
1201 printf("Re-Init!!!\n");
1202 return DSERR_ALREADYINITIALIZED
;
1205 static HRESULT WINAPI
IDirectSoundBufferImpl_GetCaps(
1206 LPDIRECTSOUNDBUFFER iface
,LPDSBCAPS caps
1208 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1209 TRACE("(%p)->(%p)\n",This
,caps
);
1212 return DSERR_INVALIDPARAM
;
1214 /* I think we should check this value, not set it. See */
1215 /* Inside DirectX, p215. That should apply here, too. */
1216 caps
->dwSize
= sizeof(*caps
);
1218 caps
->dwFlags
= This
->dsbd
.dwFlags
| DSBCAPS_LOCSOFTWARE
;
1219 caps
->dwBufferBytes
= This
->dsbd
.dwBufferBytes
;
1220 /* This value represents the speed of the "unlock" command.
1221 As unlock is quite fast (it does not do anything), I put
1222 4096 ko/s = 4 Mo / s */
1223 caps
->dwUnlockTransferRate
= 4096;
1224 caps
->dwPlayCpuOverhead
= 0;
1229 static HRESULT WINAPI
IDirectSoundBufferImpl_QueryInterface(
1230 LPDIRECTSOUNDBUFFER iface
,REFIID riid
,LPVOID
*ppobj
1232 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1235 WINE_StringFromCLSID(riid
,xbuf
);
1236 TRACE("(%p,%s,%p)\n",This
,xbuf
,ppobj
);
1238 if ( IsEqualGUID( &IID_IDirectSoundNotify
, riid
) ) {
1239 IDirectSoundNotifyImpl
*dsn
;
1241 dsn
= (IDirectSoundNotifyImpl
*)HeapAlloc(GetProcessHeap(),0,sizeof(*dsn
));
1244 IDirectSoundBuffer_AddRef(iface
);
1245 dsn
->lpvtbl
= &dsnvt
;
1246 *ppobj
= (LPVOID
)dsn
;
1250 if ( IsEqualGUID( &IID_IDirectSound3DBuffer
, riid
) ) {
1251 *ppobj
= This
->ds3db
;
1259 static ICOM_VTABLE(IDirectSoundBuffer
) dsbvt
=
1261 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1262 IDirectSoundBufferImpl_QueryInterface
,
1263 IDirectSoundBufferImpl_AddRef
,
1264 IDirectSoundBufferImpl_Release
,
1265 IDirectSoundBufferImpl_GetCaps
,
1266 IDirectSoundBufferImpl_GetCurrentPosition
,
1267 IDirectSoundBufferImpl_GetFormat
,
1268 IDirectSoundBufferImpl_GetVolume
,
1269 IDirectSoundBufferImpl_GetPan
,
1270 IDirectSoundBufferImpl_GetFrequency
,
1271 IDirectSoundBufferImpl_GetStatus
,
1272 IDirectSoundBufferImpl_Initialize
,
1273 IDirectSoundBufferImpl_Lock
,
1274 IDirectSoundBufferImpl_Play
,
1275 IDirectSoundBufferImpl_SetCurrentPosition
,
1276 IDirectSoundBufferImpl_SetFormat
,
1277 IDirectSoundBufferImpl_SetVolume
,
1278 IDirectSoundBufferImpl_SetPan
,
1279 IDirectSoundBufferImpl_SetFrequency
,
1280 IDirectSoundBufferImpl_Stop
,
1281 IDirectSoundBufferImpl_Unlock
1284 /*******************************************************************************
1288 static HRESULT WINAPI
IDirectSoundImpl_SetCooperativeLevel(
1289 LPDIRECTSOUND iface
,HWND hwnd
,DWORD level
1291 ICOM_THIS(IDirectSoundImpl
,iface
);
1292 FIXME("(%p,%08lx,%ld):stub\n",This
,(DWORD
)hwnd
,level
);
1296 static HRESULT WINAPI
IDirectSoundImpl_CreateSoundBuffer(
1297 LPDIRECTSOUND iface
,LPDSBUFFERDESC dsbd
,LPLPDIRECTSOUNDBUFFER ppdsb
,LPUNKNOWN lpunk
1299 ICOM_THIS(IDirectSoundImpl
,iface
);
1300 IDirectSoundBufferImpl
** ippdsb
=(IDirectSoundBufferImpl
**)ppdsb
;
1301 LPWAVEFORMATEX wfex
;
1303 TRACE("(%p,%p,%p,%p)\n",This
,dsbd
,ippdsb
,lpunk
);
1305 if ((This
== NULL
) || (dsbd
== NULL
) || (ippdsb
== NULL
))
1306 return DSERR_INVALIDPARAM
;
1308 if (TRACE_ON(dsound
)) {
1309 TRACE("(size=%ld)\n",dsbd
->dwSize
);
1310 TRACE("(flags=0x%08lx\n",dsbd
->dwFlags
);
1311 _dump_DSBCAPS(dsbd
->dwFlags
);
1312 TRACE("(bufferbytes=%ld)\n",dsbd
->dwBufferBytes
);
1313 TRACE("(lpwfxFormat=%p)\n",dsbd
->lpwfxFormat
);
1316 wfex
= dsbd
->lpwfxFormat
;
1319 TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld"
1320 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
1321 wfex
->wFormatTag
, wfex
->nChannels
, wfex
->nSamplesPerSec
,
1322 wfex
->nAvgBytesPerSec
, wfex
->nBlockAlign
,
1323 wfex
->wBitsPerSample
, wfex
->cbSize
);
1325 if (dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
1327 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER
)primarybuf
);
1328 *ippdsb
= primarybuf
;
1329 primarybuf
->dsbd
.dwFlags
= dsbd
->dwFlags
;
1331 } /* Else create primarybuf */
1334 *ippdsb
= (IDirectSoundBufferImpl
*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDirectSoundBufferImpl
));
1335 if (*ippdsb
== NULL
)
1336 return DSERR_OUTOFMEMORY
;
1339 TRACE("Created buffer at %p\n", *ippdsb
);
1341 if (dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
1342 (*ippdsb
)->buflen
= dsound
->wfx
.nAvgBytesPerSec
;
1343 (*ippdsb
)->freq
= dsound
->wfx
.nSamplesPerSec
;
1345 (*ippdsb
)->buflen
= dsbd
->dwBufferBytes
;
1346 (*ippdsb
)->freq
= dsbd
->lpwfxFormat
->nSamplesPerSec
;
1348 (*ippdsb
)->buffer
= (LPBYTE
)HeapAlloc(GetProcessHeap(),0,(*ippdsb
)->buflen
);
1349 if ((*ippdsb
)->buffer
== NULL
) {
1350 HeapFree(GetProcessHeap(),0,(*ippdsb
));
1352 return DSERR_OUTOFMEMORY
;
1354 /* It's not necessary to initialize values to zero since */
1355 /* we allocated this structure with HEAP_ZERO_MEMORY... */
1356 (*ippdsb
)->playpos
= 0;
1357 (*ippdsb
)->writepos
= 0;
1358 (*ippdsb
)->parent
= NULL
;
1359 (*ippdsb
)->lpvtbl
= &dsbvt
;
1360 (*ippdsb
)->dsound
= This
;
1361 (*ippdsb
)->playing
= 0;
1362 (*ippdsb
)->lVolAdjust
= (1 << 15);
1363 (*ippdsb
)->rVolAdjust
= (1 << 15);
1365 if (!(dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
)) {
1366 (*ippdsb
)->freqAdjust
= ((*ippdsb
)->freq
<< DSOUND_FREQSHIFT
) /
1367 primarybuf
->wfx
.nSamplesPerSec
;
1368 (*ippdsb
)->nAvgBytesPerSec
= (*ippdsb
)->freq
*
1369 dsbd
->lpwfxFormat
->nBlockAlign
;
1372 memcpy(&((*ippdsb
)->dsbd
),dsbd
,sizeof(*dsbd
));
1374 /* register buffer */
1375 if (!(dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
)) {
1376 This
->buffers
= (IDirectSoundBufferImpl
**)HeapReAlloc(GetProcessHeap(),0,This
->buffers
,sizeof(IDirectSoundBufferImpl
*)*(This
->nrofbuffers
+1));
1377 This
->buffers
[This
->nrofbuffers
] = *ippdsb
;
1378 This
->nrofbuffers
++;
1380 IDirectSound_AddRef(iface
);
1382 if (dsbd
->lpwfxFormat
)
1383 memcpy(&((*ippdsb
)->wfx
), dsbd
->lpwfxFormat
, sizeof((*ippdsb
)->wfx
));
1385 InitializeCriticalSection(&((*ippdsb
)->lock
));
1388 if (dsbd
->dwFlags
& DSBCAPS_CTRL3D
) {
1389 IDirectSound3DBufferImpl
*ds3db
;
1391 ds3db
= (IDirectSound3DBufferImpl
*)HeapAlloc(GetProcessHeap(),
1394 ds3db
->dsb
= (*ippdsb
);
1395 ds3db
->lpvtbl
= &ds3dbvt
;
1396 (*ippdsb
)->ds3db
= ds3db
;
1397 ds3db
->ds3db
.dwSize
= sizeof(DS3DBUFFER
);
1398 ds3db
->ds3db
.vPosition
.x
.x
= 0.0;
1399 ds3db
->ds3db
.vPosition
.y
.y
= 0.0;
1400 ds3db
->ds3db
.vPosition
.z
.z
= 0.0;
1401 ds3db
->ds3db
.vVelocity
.x
.x
= 0.0;
1402 ds3db
->ds3db
.vVelocity
.y
.y
= 0.0;
1403 ds3db
->ds3db
.vVelocity
.z
.z
= 0.0;
1404 ds3db
->ds3db
.dwInsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
1405 ds3db
->ds3db
.dwOutsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
1406 ds3db
->ds3db
.vConeOrientation
.x
.x
= 0.0;
1407 ds3db
->ds3db
.vConeOrientation
.y
.y
= 0.0;
1408 ds3db
->ds3db
.vConeOrientation
.z
.z
= 0.0;
1409 ds3db
->ds3db
.lConeOutsideVolume
= DS3D_DEFAULTCONEOUTSIDEVOLUME
;
1410 ds3db
->ds3db
.flMinDistance
= DS3D_DEFAULTMINDISTANCE
;
1411 ds3db
->ds3db
.flMaxDistance
= DS3D_DEFAULTMAXDISTANCE
;
1412 ds3db
->ds3db
.dwMode
= DS3DMODE_NORMAL
;
1413 ds3db
->buflen
= ((*ippdsb
)->buflen
* primarybuf
->wfx
.nBlockAlign
) /
1414 (*ippdsb
)->wfx
.nBlockAlign
;
1415 ds3db
->buffer
= HeapAlloc(GetProcessHeap(), 0, ds3db
->buflen
);
1416 if (ds3db
->buffer
== NULL
) {
1418 ds3db
->ds3db
.dwMode
= DS3DMODE_DISABLE
;
1425 static HRESULT WINAPI
IDirectSoundImpl_DuplicateSoundBuffer(
1426 LPDIRECTSOUND iface
,LPDIRECTSOUNDBUFFER pdsb
,LPLPDIRECTSOUNDBUFFER ppdsb
1428 ICOM_THIS(IDirectSoundImpl
,iface
);
1429 IDirectSoundBufferImpl
* ipdsb
=(IDirectSoundBufferImpl
*)pdsb
;
1430 IDirectSoundBufferImpl
** ippdsb
=(IDirectSoundBufferImpl
**)ppdsb
;
1431 TRACE("(%p,%p,%p)\n",This
,ipdsb
,ippdsb
);
1433 *ippdsb
= (IDirectSoundBufferImpl
*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDirectSoundBufferImpl
));
1435 IDirectSoundBuffer_AddRef(pdsb
);
1436 memcpy(*ippdsb
, ipdsb
, sizeof(IDirectSoundBufferImpl
));
1438 (*ippdsb
)->playpos
= 0;
1439 (*ippdsb
)->writepos
= 0;
1440 (*ippdsb
)->dsound
= This
;
1441 (*ippdsb
)->parent
= ipdsb
;
1442 memcpy(&((*ippdsb
)->wfx
), &(ipdsb
->wfx
), sizeof((*ippdsb
)->wfx
));
1443 /* register buffer */
1444 This
->buffers
= (IDirectSoundBufferImpl
**)HeapReAlloc(GetProcessHeap(),0,This
->buffers
,sizeof(IDirectSoundBufferImpl
**)*(This
->nrofbuffers
+1));
1445 This
->buffers
[This
->nrofbuffers
] = *ippdsb
;
1446 This
->nrofbuffers
++;
1447 IDirectSound_AddRef(iface
);
1452 static HRESULT WINAPI
IDirectSoundImpl_GetCaps(LPDIRECTSOUND iface
,LPDSCAPS caps
) {
1453 ICOM_THIS(IDirectSoundImpl
,iface
);
1454 TRACE("(%p,%p)\n",This
,caps
);
1455 TRACE("(flags=0x%08lx)\n",caps
->dwFlags
);
1458 return DSERR_INVALIDPARAM
;
1460 /* We should check this value, not set it. See Inside DirectX, p215. */
1461 caps
->dwSize
= sizeof(*caps
);
1464 DSCAPS_PRIMARYSTEREO
|
1465 DSCAPS_PRIMARY16BIT
|
1466 DSCAPS_SECONDARYSTEREO
|
1467 DSCAPS_SECONDARY16BIT
|
1468 DSCAPS_CONTINUOUSRATE
;
1469 /* FIXME: query OSS */
1470 caps
->dwMinSecondarySampleRate
= DSBFREQUENCY_MIN
;
1471 caps
->dwMaxSecondarySampleRate
= DSBFREQUENCY_MAX
;
1473 caps
->dwPrimaryBuffers
= 1;
1475 caps
->dwMaxHwMixingAllBuffers
= 0;
1476 caps
->dwMaxHwMixingStaticBuffers
= 0;
1477 caps
->dwMaxHwMixingStreamingBuffers
= 0;
1479 caps
->dwFreeHwMixingAllBuffers
= 0;
1480 caps
->dwFreeHwMixingStaticBuffers
= 0;
1481 caps
->dwFreeHwMixingStreamingBuffers
= 0;
1483 caps
->dwMaxHw3DAllBuffers
= 0;
1484 caps
->dwMaxHw3DStaticBuffers
= 0;
1485 caps
->dwMaxHw3DStreamingBuffers
= 0;
1487 caps
->dwFreeHw3DAllBuffers
= 0;
1488 caps
->dwFreeHw3DStaticBuffers
= 0;
1489 caps
->dwFreeHw3DStreamingBuffers
= 0;
1491 caps
->dwTotalHwMemBytes
= 0;
1493 caps
->dwFreeHwMemBytes
= 0;
1495 caps
->dwMaxContigFreeHwMemBytes
= 0;
1497 caps
->dwUnlockTransferRateHwBuffers
= 4096; /* But we have none... */
1499 caps
->dwPlayCpuOverheadSwBuffers
= 1; /* 1% */
1504 static ULONG WINAPI
IDirectSoundImpl_AddRef(LPDIRECTSOUND iface
) {
1505 ICOM_THIS(IDirectSoundImpl
,iface
);
1506 return ++(This
->ref
);
1509 static ULONG WINAPI
IDirectSoundImpl_Release(LPDIRECTSOUND iface
) {
1510 ICOM_THIS(IDirectSoundImpl
,iface
);
1511 TRACE("(%p), ref was %ld\n",This
,This
->ref
);
1512 if (!--(This
->ref
)) {
1513 DSOUND_CloseAudio();
1514 while(IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)primarybuf
)); /* Deallocate */
1515 FIXME("need to release all buffers!\n");
1516 HeapFree(GetProcessHeap(),0,This
);
1523 static HRESULT WINAPI
IDirectSoundImpl_SetSpeakerConfig(
1524 LPDIRECTSOUND iface
,DWORD config
1526 ICOM_THIS(IDirectSoundImpl
,iface
);
1527 FIXME("(%p,0x%08lx):stub\n",This
,config
);
1531 static HRESULT WINAPI
IDirectSoundImpl_QueryInterface(
1532 LPDIRECTSOUND iface
,REFIID riid
,LPVOID
*ppobj
1534 ICOM_THIS(IDirectSoundImpl
,iface
);
1537 if ( IsEqualGUID( &IID_IDirectSound3DListener
, riid
) ) {
1539 if (This
->listener
) {
1540 *ppobj
= This
->listener
;
1543 This
->listener
= (IDirectSound3DListenerImpl
*)HeapAlloc(
1544 GetProcessHeap(), 0, sizeof(*(This
->listener
)));
1545 This
->listener
->ref
= 1;
1546 This
->listener
->lpvtbl
= &ds3dlvt
;
1547 IDirectSound_AddRef(iface
);
1548 This
->listener
->ds3dl
.dwSize
= sizeof(DS3DLISTENER
);
1549 This
->listener
->ds3dl
.vPosition
.x
.x
= 0.0;
1550 This
->listener
->ds3dl
.vPosition
.y
.y
= 0.0;
1551 This
->listener
->ds3dl
.vPosition
.z
.z
= 0.0;
1552 This
->listener
->ds3dl
.vVelocity
.x
.x
= 0.0;
1553 This
->listener
->ds3dl
.vVelocity
.y
.y
= 0.0;
1554 This
->listener
->ds3dl
.vVelocity
.z
.z
= 0.0;
1555 This
->listener
->ds3dl
.vOrientFront
.x
.x
= 0.0;
1556 This
->listener
->ds3dl
.vOrientFront
.y
.y
= 0.0;
1557 This
->listener
->ds3dl
.vOrientFront
.z
.z
= 1.0;
1558 This
->listener
->ds3dl
.vOrientTop
.x
.x
= 0.0;
1559 This
->listener
->ds3dl
.vOrientTop
.y
.y
= 1.0;
1560 This
->listener
->ds3dl
.vOrientTop
.z
.z
= 0.0;
1561 This
->listener
->ds3dl
.flDistanceFactor
= DS3D_DEFAULTDISTANCEFACTOR
;
1562 This
->listener
->ds3dl
.flRolloffFactor
= DS3D_DEFAULTROLLOFFFACTOR
;
1563 This
->listener
->ds3dl
.flDopplerFactor
= DS3D_DEFAULTDOPPLERFACTOR
;
1564 *ppobj
= (LPVOID
)This
->listener
;
1568 WINE_StringFromCLSID(riid
,xbuf
);
1569 TRACE("(%p,%s,%p)\n",This
,xbuf
,ppobj
);
1573 static HRESULT WINAPI
IDirectSoundImpl_Compact(
1574 LPDIRECTSOUND iface
)
1576 ICOM_THIS(IDirectSoundImpl
,iface
);
1577 TRACE("(%p)\n", This
);
1581 static HRESULT WINAPI
IDirectSoundImpl_GetSpeakerConfig(
1582 LPDIRECTSOUND iface
,
1583 LPDWORD lpdwSpeakerConfig
)
1585 ICOM_THIS(IDirectSoundImpl
,iface
);
1586 TRACE("(%p, %p)\n", This
, lpdwSpeakerConfig
);
1587 *lpdwSpeakerConfig
= DSSPEAKER_STEREO
| (DSSPEAKER_GEOMETRY_NARROW
<< 16);
1591 static HRESULT WINAPI
IDirectSoundImpl_Initialize(
1592 LPDIRECTSOUND iface
,
1595 ICOM_THIS(IDirectSoundImpl
,iface
);
1596 TRACE("(%p, %p)\n", This
, lpGuid
);
1600 static ICOM_VTABLE(IDirectSound
) dsvt
=
1602 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1603 IDirectSoundImpl_QueryInterface
,
1604 IDirectSoundImpl_AddRef
,
1605 IDirectSoundImpl_Release
,
1606 IDirectSoundImpl_CreateSoundBuffer
,
1607 IDirectSoundImpl_GetCaps
,
1608 IDirectSoundImpl_DuplicateSoundBuffer
,
1609 IDirectSoundImpl_SetCooperativeLevel
,
1610 IDirectSoundImpl_Compact
,
1611 IDirectSoundImpl_GetSpeakerConfig
,
1612 IDirectSoundImpl_SetSpeakerConfig
,
1613 IDirectSoundImpl_Initialize
1617 /* See http://www.opensound.com/pguide/audio.html for more details */
1620 DSOUND_setformat(LPWAVEFORMATEX wfex
) {
1621 int xx
,channels
,speed
,format
,nformat
;
1624 TRACE("(%p) deferred\n", wfex
);
1627 switch (wfex
->wFormatTag
) {
1629 WARN("unknown WAVE_FORMAT tag %d\n",wfex
->wFormatTag
);
1630 return DSERR_BADFORMAT
;
1631 case WAVE_FORMAT_PCM
:
1634 if (wfex
->wBitsPerSample
==8)
1637 format
= AFMT_S16_LE
;
1639 if (-1==ioctl(audiofd
,SNDCTL_DSP_GETFMTS
,&xx
)) {
1640 perror("ioctl SNDCTL_DSP_GETFMTS");
1643 if ((xx
&format
)!=format
) {/* format unsupported */
1644 FIXME("SNDCTL_DSP_GETFMTS: format not supported\n");
1648 if (-1==ioctl(audiofd
,SNDCTL_DSP_SETFMT
,&nformat
)) {
1649 perror("ioctl SNDCTL_DSP_SETFMT");
1652 if (nformat
!=format
) {/* didn't work */
1653 FIXME("SNDCTL_DSP_GETFMTS: format not set\n");
1657 channels
= wfex
->nChannels
-1;
1658 if (-1==ioctl(audiofd
,SNDCTL_DSP_STEREO
,&channels
)) {
1659 perror("ioctl SNDCTL_DSP_STEREO");
1662 speed
= wfex
->nSamplesPerSec
;
1663 if (-1==ioctl(audiofd
,SNDCTL_DSP_SPEED
,&speed
)) {
1664 perror("ioctl SNDCTL_DSP_SPEED");
1667 TRACE("(freq=%ld,channels=%d,bits=%d)\n",
1668 wfex
->nSamplesPerSec
,wfex
->nChannels
,wfex
->wBitsPerSample
1673 static void DSOUND_CheckEvent(IDirectSoundBufferImpl
*dsb
, int len
)
1677 LPDSBPOSITIONNOTIFY event
;
1679 if (dsb
->nrofnotifies
== 0)
1682 TRACE("(%p) buflen = %ld, playpos = %ld, len = %d\n",
1683 dsb
, dsb
->buflen
, dsb
->playpos
, len
);
1684 for (i
= 0; i
< dsb
->nrofnotifies
; i
++) {
1685 event
= dsb
->notifies
+ i
;
1686 offset
= event
->dwOffset
;
1687 TRACE("checking %d, position %ld, event = %d\n",
1688 i
, offset
, event
->hEventNotify
);
1689 /* DSBPN_OFFSETSTOP has to be the last element. So this is */
1690 /* OK. [Inside DirectX, p274] */
1692 /* This also means we can't sort the entries by offset, */
1693 /* because DSBPN_OFFSETSTOP == -1 */
1694 if (offset
== DSBPN_OFFSETSTOP
) {
1695 if (dsb
->playing
== 0) {
1696 SetEvent(event
->hEventNotify
);
1697 TRACE("signalled event %d (%d)\n", event
->hEventNotify
, i
);
1702 if ((dsb
->playpos
+ len
) >= dsb
->buflen
) {
1703 if ((offset
< ((dsb
->playpos
+ len
) % dsb
->buflen
)) ||
1704 (offset
>= dsb
->playpos
)) {
1705 TRACE("signalled event %d (%d)\n", event
->hEventNotify
, i
);
1706 SetEvent(event
->hEventNotify
);
1709 if ((offset
>= dsb
->playpos
) && (offset
< (dsb
->playpos
+ len
))) {
1710 TRACE("signalled event %d (%d)\n", event
->hEventNotify
, i
);
1711 SetEvent(event
->hEventNotify
);
1717 /* WAV format info can be found at: */
1719 /* http://www.cwi.nl/ftp/audio/AudioFormats.part2 */
1720 /* ftp://ftp.cwi.nl/pub/audio/RIFF-format */
1722 /* Import points to remember: */
1724 /* 8-bit WAV is unsigned */
1725 /* 16-bit WAV is signed */
1727 static inline INT16
cvtU8toS16(BYTE byte
)
1729 INT16 s
= (byte
- 128) << 8;
1734 static inline BYTE
cvtS16toU8(INT16 word
)
1736 BYTE b
= (word
+ 32768) >> 8;
1742 /* We should be able to optimize these two inline functions */
1743 /* so that we aren't doing 8->16->8 conversions when it is */
1744 /* not necessary. But this is still a WIP. Optimize later. */
1745 static inline void get_fields(const IDirectSoundBufferImpl
*dsb
, BYTE
*buf
, INT
*fl
, INT
*fr
)
1747 INT16
*bufs
= (INT16
*) buf
;
1749 /* TRACE(dsound, "(%p)", buf); */
1750 if ((dsb
->wfx
.wBitsPerSample
== 8) && dsb
->wfx
.nChannels
== 2) {
1751 *fl
= cvtU8toS16(*buf
);
1752 *fr
= cvtU8toS16(*(buf
+ 1));
1756 if ((dsb
->wfx
.wBitsPerSample
== 16) && dsb
->wfx
.nChannels
== 2) {
1762 if ((dsb
->wfx
.wBitsPerSample
== 8) && dsb
->wfx
.nChannels
== 1) {
1763 *fl
= cvtU8toS16(*buf
);
1768 if ((dsb
->wfx
.wBitsPerSample
== 16) && dsb
->wfx
.nChannels
== 1) {
1774 FIXME("get_fields found an unsupported configuration\n");
1778 static inline void set_fields(BYTE
*buf
, INT fl
, INT fr
)
1780 INT16
*bufs
= (INT16
*) buf
;
1782 if ((primarybuf
->wfx
.wBitsPerSample
== 8) && (primarybuf
->wfx
.nChannels
== 2)) {
1783 *buf
= cvtS16toU8(fl
);
1784 *(buf
+ 1) = cvtS16toU8(fr
);
1788 if ((primarybuf
->wfx
.wBitsPerSample
== 16) && (primarybuf
->wfx
.nChannels
== 2)) {
1794 if ((primarybuf
->wfx
.wBitsPerSample
== 8) && (primarybuf
->wfx
.nChannels
== 1)) {
1795 *buf
= cvtS16toU8((fl
+ fr
) >> 1);
1799 if ((primarybuf
->wfx
.wBitsPerSample
== 16) && (primarybuf
->wfx
.nChannels
== 1)) {
1800 *bufs
= (fl
+ fr
) >> 1;
1803 FIXME("set_fields found an unsupported configuration\n");
1807 /* Now with PerfectPitch (tm) technology */
1808 static INT
DSOUND_MixerNorm(IDirectSoundBufferImpl
*dsb
, BYTE
*buf
, INT len
)
1810 INT i
, size
, ipos
, ilen
, fieldL
, fieldR
;
1812 INT iAdvance
= dsb
->wfx
.nBlockAlign
;
1813 INT oAdvance
= primarybuf
->wfx
.nBlockAlign
;
1815 ibp
= dsb
->buffer
+ dsb
->playpos
;
1818 TRACE("(%p, %p, %p), playpos=%8.8lx\n", dsb
, ibp
, obp
, dsb
->playpos
);
1819 /* Check for the best case */
1820 if ((dsb
->freq
== primarybuf
->wfx
.nSamplesPerSec
) &&
1821 (dsb
->wfx
.wBitsPerSample
== primarybuf
->wfx
.wBitsPerSample
) &&
1822 (dsb
->wfx
.nChannels
== primarybuf
->wfx
.nChannels
)) {
1823 TRACE("(%p) Best case\n", dsb
);
1824 if ((ibp
+ len
) < (BYTE
*)(dsb
->buffer
+ dsb
->buflen
))
1825 memcpy(obp
, ibp
, len
);
1827 memcpy(obp
, ibp
, dsb
->buflen
- dsb
->playpos
);
1828 memcpy(obp
+ (dsb
->buflen
- dsb
->playpos
),
1830 len
- (dsb
->buflen
- dsb
->playpos
));
1835 /* Check for same sample rate */
1836 if (dsb
->freq
== primarybuf
->wfx
.nSamplesPerSec
) {
1837 TRACE("(%p) Same sample rate %ld = primary %ld\n", dsb
,
1838 dsb
->freq
, primarybuf
->wfx
.nSamplesPerSec
);
1840 for (i
= 0; i
< len
; i
+= oAdvance
) {
1841 get_fields(dsb
, ibp
, &fieldL
, &fieldR
);
1844 set_fields(obp
, fieldL
, fieldR
);
1846 if (ibp
>= (BYTE
*)(dsb
->buffer
+ dsb
->buflen
))
1847 ibp
= dsb
->buffer
; /* wrap */
1852 /* Mix in different sample rates */
1854 /* New PerfectPitch(tm) Technology (c) 1998 Rob Riggs */
1855 /* Patent Pending :-] */
1857 TRACE("(%p) Adjusting frequency: %ld -> %ld\n",
1858 dsb
, dsb
->freq
, primarybuf
->wfx
.nSamplesPerSec
);
1860 size
= len
/ oAdvance
;
1861 ilen
= ((size
* dsb
->freqAdjust
) >> DSOUND_FREQSHIFT
) * iAdvance
;
1862 for (i
= 0; i
< size
; i
++) {
1864 ipos
= (((i
* dsb
->freqAdjust
) >> DSOUND_FREQSHIFT
) * iAdvance
) + dsb
->playpos
;
1866 if (ipos
>= dsb
->buflen
)
1867 ipos
%= dsb
->buflen
; /* wrap */
1869 get_fields(dsb
, (dsb
->buffer
+ ipos
), &fieldL
, &fieldR
);
1870 set_fields(obp
, fieldL
, fieldR
);
1876 static void DSOUND_MixerVol(IDirectSoundBufferImpl
*dsb
, BYTE
*buf
, INT len
)
1878 INT i
, inc
= primarybuf
->wfx
.wBitsPerSample
>> 3;
1880 INT16
*bps
= (INT16
*) buf
;
1882 TRACE("(%p) left = %lx, right = %lx\n", dsb
,
1883 dsb
->lVolAdjust
, dsb
->rVolAdjust
);
1884 if ((!(dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLPAN
) || (dsb
->pan
== 0)) &&
1885 (!(dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLVOLUME
) || (dsb
->volume
== 0)) &&
1886 !(dsb
->dsbd
.dwFlags
& DSBCAPS_CTRL3D
))
1887 return; /* Nothing to do */
1889 /* If we end up with some bozo coder using panning or 3D sound */
1890 /* with a mono primary buffer, it could sound very weird using */
1891 /* this method. Oh well, tough patooties. */
1893 for (i
= 0; i
< len
; i
+= inc
) {
1899 /* 8-bit WAV is unsigned, but we need to operate */
1900 /* on signed data for this to work properly */
1902 val
= ((val
* (i
& inc
? dsb
->rVolAdjust
: dsb
->lVolAdjust
)) >> 15);
1907 /* 16-bit WAV is signed -- much better */
1909 val
= ((val
* ((i
& inc
) ? dsb
->rVolAdjust
: dsb
->lVolAdjust
)) >> 15);
1915 FIXME("MixerVol had a nasty error\n");
1921 static void DSOUND_Mixer3D(IDirectSoundBufferImpl
*dsb
, BYTE
*buf
, INT len
)
1924 DWORD buflen
, playpos
;
1926 buflen
= dsb
->ds3db
->buflen
;
1927 playpos
= (dsb
->playpos
* primarybuf
->wfx
.nBlockAlign
) / dsb
->wfx
.nBlockAlign
;
1928 ibp
= dsb
->ds3db
->buffer
+ playpos
;
1931 if (playpos
> buflen
) {
1932 FIXME("Major breakage");
1936 if (len
<= (playpos
+ buflen
))
1937 memcpy(obp
, ibp
, len
);
1939 memcpy(obp
, ibp
, buflen
- playpos
);
1940 memcpy(obp
+ (buflen
- playpos
),
1942 len
- (buflen
- playpos
));
1948 static void *tmp_buffer
;
1949 static size_t tmp_buffer_len
= 0;
1951 static void *DSOUND_tmpbuffer(size_t len
)
1953 if (len
>tmp_buffer_len
) {
1954 void *new_buffer
= realloc(tmp_buffer
, len
);
1956 tmp_buffer
= new_buffer
;
1957 tmp_buffer_len
= len
;
1964 static DWORD
DSOUND_MixInBuffer(IDirectSoundBufferImpl
*dsb
)
1966 INT i
, len
, ilen
, temp
, field
;
1967 INT advance
= primarybuf
->wfx
.wBitsPerSample
>> 3;
1968 BYTE
*buf
, *ibuf
, *obuf
;
1969 INT16
*ibufs
, *obufs
;
1971 len
= DSOUND_FRAGLEN
; /* The most we will use */
1972 if (!(dsb
->playflags
& DSBPLAY_LOOPING
)) {
1973 temp
= MulDiv(primarybuf
->wfx
.nAvgBytesPerSec
, dsb
->buflen
,
1974 dsb
->nAvgBytesPerSec
) -
1975 MulDiv(primarybuf
->wfx
.nAvgBytesPerSec
, dsb
->playpos
,
1976 dsb
->nAvgBytesPerSec
);
1977 len
= (len
> temp
) ? temp
: len
;
1979 len
&= ~3; /* 4 byte alignment */
1982 /* This should only happen if we aren't looping and temp < 4 */
1984 /* We skip the remainder, so check for possible events */
1985 DSOUND_CheckEvent(dsb
, dsb
->buflen
- dsb
->playpos
);
1990 /* Check for DSBPN_OFFSETSTOP */
1991 DSOUND_CheckEvent(dsb
, 0);
1995 /* Been seeing segfaults in malloc() for some reason... */
1996 TRACE("allocating buffer (size = %d)\n", len
);
1997 if ((buf
= ibuf
= (BYTE
*) DSOUND_tmpbuffer(len
)) == NULL
)
2000 TRACE("MixInBuffer (%p) len = %d\n", dsb
, len
);
2002 ilen
= DSOUND_MixerNorm(dsb
, ibuf
, len
);
2003 if ((dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLPAN
) ||
2004 (dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLVOLUME
))
2005 DSOUND_MixerVol(dsb
, ibuf
, len
);
2007 obuf
= primarybuf
->buffer
+ primarybuf
->playpos
;
2008 for (i
= 0; i
< len
; i
+= advance
) {
2009 obufs
= (INT16
*) obuf
;
2010 ibufs
= (INT16
*) ibuf
;
2011 if (primarybuf
->wfx
.wBitsPerSample
== 8) {
2012 /* 8-bit WAV is unsigned */
2013 field
= (*ibuf
- 128);
2014 field
+= (*obuf
- 128);
2015 field
= field
> 127 ? 127 : field
;
2016 field
= field
< -128 ? -128 : field
;
2017 *obuf
= field
+ 128;
2019 /* 16-bit WAV is signed */
2022 field
= field
> 32767 ? 32767 : field
;
2023 field
= field
< -32768 ? -32768 : field
;
2028 if (obuf
>= (BYTE
*)(primarybuf
->buffer
+ primarybuf
->buflen
))
2029 obuf
= primarybuf
->buffer
;
2033 if (dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLPOSITIONNOTIFY
)
2034 DSOUND_CheckEvent(dsb
, ilen
);
2036 dsb
->playpos
+= ilen
;
2037 dsb
->writepos
= dsb
->playpos
+ ilen
;
2039 if (dsb
->playpos
>= dsb
->buflen
) {
2040 if (!(dsb
->playflags
& DSBPLAY_LOOPING
)) {
2044 DSOUND_CheckEvent(dsb
, 0); /* For DSBPN_OFFSETSTOP */
2046 dsb
->playpos
%= dsb
->buflen
; /* wrap */
2049 if (dsb
->writepos
>= dsb
->buflen
)
2050 dsb
->writepos
%= dsb
->buflen
;
2055 static DWORD WINAPI
DSOUND_MixPrimary(void)
2057 INT i
, len
, maxlen
= 0;
2058 IDirectSoundBufferImpl
*dsb
;
2060 for (i
= dsound
->nrofbuffers
- 1; i
>= 0; i
--) {
2061 dsb
= dsound
->buffers
[i
];
2063 if (!dsb
|| !(dsb
->lpvtbl
))
2065 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER
)dsb
);
2066 if (dsb
->buflen
&& dsb
->playing
) {
2067 EnterCriticalSection(&(dsb
->lock
));
2068 len
= DSOUND_MixInBuffer(dsb
);
2069 maxlen
= len
> maxlen
? len
: maxlen
;
2070 LeaveCriticalSection(&(dsb
->lock
));
2072 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)dsb
);
2078 static int DSOUND_OpenAudio(void)
2082 if (primarybuf
== NULL
)
2083 return DSERR_OUTOFMEMORY
;
2085 while (audiofd
>= 0)
2088 /* we will most likely not get one, avoid excessive opens ... */
2089 if (audiofd
== -ENODEV
)
2091 audiofd
= open("/dev/audio",O_WRONLY
);
2093 /* Don't worry if sound is busy at the moment */
2094 if ((errno
!= EBUSY
) && (errno
!= ENODEV
))
2095 perror("open /dev/audio");
2100 /* We should probably do something here if SETFRAGMENT fails... */
2101 audioFragment
=0x0002000c;
2102 if (-1==ioctl(audiofd
,SNDCTL_DSP_SETFRAGMENT
,&audioFragment
))
2103 perror("ioctl SETFRAGMENT");
2106 DSOUND_setformat(&(primarybuf
->wfx
));
2111 static void DSOUND_CloseAudio(void)
2115 neutral
= primarybuf
->wfx
.wBitsPerSample
== 8 ? 128 : 0;
2116 audioOK
= 0; /* race condition */
2118 /* It's possible we've been called with audio closed */
2119 /* from SetFormat()... this is just to force a call */
2120 /* to OpenAudio() to reset the hardware properly */
2123 primarybuf
->playpos
= 0;
2124 primarybuf
->writepos
= DSOUND_FRAGLEN
;
2125 memset(primarybuf
->buffer
, neutral
, primarybuf
->buflen
);
2127 TRACE("Audio stopped\n");
2130 static int DSOUND_WriteAudio(char *buf
, int len
)
2132 int result
, left
= 0;
2134 while (left
< len
) {
2135 result
= write(audiofd
, buf
+ left
, len
- left
);
2147 static void DSOUND_OutputPrimary(int len
)
2149 int neutral
, flen1
, flen2
;
2150 char *frag1
, *frag2
;
2152 /* This is a bad place for this. We need to clear the */
2153 /* buffer with a neutral value, for unsigned 8-bit WAVE */
2154 /* that's 128, for signed 16-bit it's 0 */
2155 neutral
= primarybuf
->wfx
.wBitsPerSample
== 8 ? 128 : 0;
2158 EnterCriticalSection(&(primarybuf
->lock
));
2161 if ((audioOK
== 1) || (DSOUND_OpenAudio() == 0)) {
2162 if (primarybuf
->playpos
+ len
>= primarybuf
->buflen
) {
2163 frag1
= primarybuf
->buffer
+ primarybuf
->playpos
;
2164 flen1
= primarybuf
->buflen
- primarybuf
->playpos
;
2165 frag2
= primarybuf
->buffer
;
2166 flen2
= len
- (primarybuf
->buflen
- primarybuf
->playpos
);
2167 if (DSOUND_WriteAudio(frag1
, flen1
) != 0) {
2168 perror("DSOUND_WriteAudio");
2169 LeaveCriticalSection(&(primarybuf
->lock
));
2172 memset(frag1
, neutral
, flen1
);
2173 if (DSOUND_WriteAudio(frag2
, flen2
) != 0) {
2174 perror("DSOUND_WriteAudio");
2175 LeaveCriticalSection(&(primarybuf
->lock
));
2178 memset(frag2
, neutral
, flen2
);
2180 frag1
= primarybuf
->buffer
+ primarybuf
->playpos
;
2182 if (DSOUND_WriteAudio(frag1
, flen1
) != 0) {
2183 perror("DSOUND_WriteAudio");
2184 LeaveCriticalSection(&(primarybuf
->lock
));
2187 memset(frag1
, neutral
, flen1
);
2190 /* Can't play audio at the moment -- we need to sleep */
2191 /* to make up for the time we'd be blocked in write() */
2195 primarybuf
->playpos
+= len
;
2196 if (primarybuf
->playpos
>= primarybuf
->buflen
)
2197 primarybuf
->playpos
%= primarybuf
->buflen
;
2198 primarybuf
->writepos
= primarybuf
->playpos
+ DSOUND_FRAGLEN
;
2199 if (primarybuf
->writepos
>= primarybuf
->buflen
)
2200 primarybuf
->writepos
%= primarybuf
->buflen
;
2202 LeaveCriticalSection(&(primarybuf
->lock
));
2206 static DWORD WINAPI
DSOUND_thread(LPVOID arg
)
2210 TRACE("dsound is at pid %d\n",getpid());
2213 WARN("DSOUND thread giving up.\n");
2217 WARN("DSOUND father died? Giving up.\n");
2220 /* RACE: dsound could be deleted */
2221 IDirectSound_AddRef((LPDIRECTSOUND
)dsound
);
2222 if (primarybuf
== NULL
) {
2223 /* Should never happen */
2224 WARN("Lost the primary buffer!\n");
2225 IDirectSound_Release((LPDIRECTSOUND
)dsound
);
2230 EnterCriticalSection(&(primarybuf
->lock
));
2231 len
= DSOUND_MixPrimary();
2232 LeaveCriticalSection(&(primarybuf
->lock
));
2235 if (primarybuf
->playing
)
2236 len
= DSOUND_FRAGLEN
> len
? DSOUND_FRAGLEN
: len
;
2238 /* This does all the work */
2239 DSOUND_OutputPrimary(len
);
2241 /* no buffers playing -- close and wait */
2243 DSOUND_CloseAudio();
2246 IDirectSound_Release((LPDIRECTSOUND
)dsound
);
2251 #endif /* HAVE_OSS */
2253 HRESULT WINAPI
DirectSoundCreate(REFGUID lpGUID
,LPDIRECTSOUND
*ppDS
,IUnknown
*pUnkOuter
)
2255 IDirectSoundImpl
** ippDS
=(IDirectSoundImpl
**)ppDS
;
2257 TRACE("(%p,%p,%p)\n",lpGUID
,ippDS
,pUnkOuter
);
2259 TRACE("DirectSoundCreate (%p)\n", ippDS
);
2264 return DSERR_INVALIDPARAM
;
2267 IDirectSound_AddRef((LPDIRECTSOUND
)dsound
);
2272 /* Check that we actually have audio capabilities */
2273 /* If we do, whether it's busy or not, we continue */
2274 /* otherwise we return with DSERR_NODRIVER */
2276 audiofd
= open("/dev/audio",O_WRONLY
);
2277 if (audiofd
== -1) {
2279 if (errno
== ENODEV
) {
2280 MESSAGE("No sound hardware found, but continuing anyway.\n");
2281 } else if (errno
== EBUSY
) {
2282 MESSAGE("Sound device busy, will keep trying.\n");
2284 MESSAGE("Unexpected error (%d) while checking for sound support.\n",errno
);
2285 return DSERR_GENERIC
;
2292 *ippDS
= (IDirectSoundImpl
*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundImpl
));
2294 return DSERR_OUTOFMEMORY
;
2297 (*ippDS
)->lpvtbl
= &dsvt
;
2298 (*ippDS
)->buffers
= NULL
;
2299 (*ippDS
)->nrofbuffers
= 0;
2301 (*ippDS
)->wfx
.wFormatTag
= 1;
2302 (*ippDS
)->wfx
.nChannels
= 2;
2303 (*ippDS
)->wfx
.nSamplesPerSec
= 22050;
2304 (*ippDS
)->wfx
.nAvgBytesPerSec
= 44100;
2305 (*ippDS
)->wfx
.nBlockAlign
= 2;
2306 (*ippDS
)->wfx
.wBitsPerSample
= 8;
2313 if (primarybuf
== NULL
) {
2317 dsbd
.dwSize
= sizeof(DSBUFFERDESC
);
2318 dsbd
.dwFlags
= DSBCAPS_PRIMARYBUFFER
;
2319 dsbd
.dwBufferBytes
= 0;
2320 dsbd
.lpwfxFormat
= &(dsound
->wfx
);
2321 hr
= IDirectSound_CreateSoundBuffer(*ppDS
, &dsbd
, (LPDIRECTSOUNDBUFFER
*)&primarybuf
, NULL
);
2324 dsound
->primary
= primarybuf
;
2326 memset(primarybuf
->buffer
, 128, primarybuf
->buflen
);
2327 hnd
= CreateThread(NULL
,0,DSOUND_thread
,0,0,&xid
);
2331 MessageBoxA(0,"DirectSound needs the Open Sound System Driver, which has not been found by ./configure.","WINE DirectSound",MB_OK
|MB_ICONSTOP
);
2332 return DSERR_NODRIVER
;
2336 /*******************************************************************************
2337 * DirectSound ClassFactory
2341 /* IUnknown fields */
2342 ICOM_VTABLE(IClassFactory
)* lpvtbl
;
2344 } IClassFactoryImpl
;
2346 static HRESULT WINAPI
2347 DSCF_QueryInterface(LPCLASSFACTORY iface
,REFIID riid
,LPVOID
*ppobj
) {
2348 ICOM_THIS(IClassFactoryImpl
,iface
);
2352 WINE_StringFromCLSID(riid
,buf
);
2354 sprintf(buf
,"<guid-0x%04x>",LOWORD(riid
));
2355 FIXME("(%p)->(%s,%p),stub!\n",This
,buf
,ppobj
);
2356 return E_NOINTERFACE
;
2360 DSCF_AddRef(LPCLASSFACTORY iface
) {
2361 ICOM_THIS(IClassFactoryImpl
,iface
);
2362 return ++(This
->ref
);
2365 static ULONG WINAPI
DSCF_Release(LPCLASSFACTORY iface
) {
2366 ICOM_THIS(IClassFactoryImpl
,iface
);
2367 /* static class, won't be freed */
2368 return --(This
->ref
);
2371 static HRESULT WINAPI
DSCF_CreateInstance(
2372 LPCLASSFACTORY iface
,LPUNKNOWN pOuter
,REFIID riid
,LPVOID
*ppobj
2374 ICOM_THIS(IClassFactoryImpl
,iface
);
2377 WINE_StringFromCLSID(riid
,buf
);
2378 TRACE("(%p)->(%p,%s,%p)\n",This
,pOuter
,buf
,ppobj
);
2379 if ( IsEqualGUID( &IID_IDirectSound
, riid
) ) {
2380 /* FIXME: reuse already created dsound if present? */
2381 return DirectSoundCreate(riid
,(LPDIRECTSOUND
*)ppobj
,pOuter
);
2383 return E_NOINTERFACE
;
2386 static HRESULT WINAPI
DSCF_LockServer(LPCLASSFACTORY iface
,BOOL dolock
) {
2387 ICOM_THIS(IClassFactoryImpl
,iface
);
2388 FIXME("(%p)->(%d),stub!\n",This
,dolock
);
2392 static ICOM_VTABLE(IClassFactory
) DSCF_Vtbl
= {
2393 DSCF_QueryInterface
,
2396 DSCF_CreateInstance
,
2399 static IClassFactoryImpl DSOUND_CF
= {&DSCF_Vtbl
, 1 };
2401 /*******************************************************************************
2402 * DllGetClassObject [DSOUND.4]
2403 * Retrieves class object from a DLL object
2406 * Docs say returns STDAPI
2409 * rclsid [I] CLSID for the class object
2410 * riid [I] Reference to identifier of interface for class object
2411 * ppv [O] Address of variable to receive interface pointer for riid
2415 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
2418 DWORD WINAPI
DSOUND_DllGetClassObject(REFCLSID rclsid
,REFIID riid
,LPVOID
*ppv
)
2420 char buf
[80],xbuf
[80];
2423 WINE_StringFromCLSID(rclsid
,xbuf
);
2425 sprintf(xbuf
,"<guid-0x%04x>",LOWORD(rclsid
));
2427 WINE_StringFromCLSID(riid
,buf
);
2429 sprintf(buf
,"<guid-0x%04x>",LOWORD(riid
));
2430 WINE_StringFromCLSID(riid
,xbuf
);
2431 TRACE("(%p,%p,%p)\n", xbuf
, buf
, ppv
);
2432 if ( IsEqualCLSID( &IID_IClassFactory
, riid
) ) {
2433 *ppv
= (LPVOID
)&DSOUND_CF
;
2434 IClassFactory_AddRef((IClassFactory
*)*ppv
);
2438 FIXME("(%p,%p,%p): no interface found.\n", xbuf
, buf
, ppv
);
2439 return CLASS_E_CLASSNOTAVAILABLE
;
2443 /*******************************************************************************
2444 * DllCanUnloadNow [DSOUND.3] Determines whether the DLL is in use.
2450 DWORD WINAPI
DSOUND_DllCanUnloadNow(void)
2452 FIXME("(void): stub\n");