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 "multimedia.h"
68 #include "wine/obj_base.h"
70 #include "debugtools.h"
72 DEFAULT_DEBUG_CHANNEL(dsound
)
75 /*****************************************************************************
76 * Predeclare the interface implementation structures
78 typedef struct IDirectSoundImpl IDirectSoundImpl
;
79 typedef struct IDirectSoundBufferImpl IDirectSoundBufferImpl
;
80 typedef struct IDirectSoundNotifyImpl IDirectSoundNotifyImpl
;
81 typedef struct IDirectSound3DListenerImpl IDirectSound3DListenerImpl
;
82 typedef struct IDirectSound3DBufferImpl IDirectSound3DBufferImpl
;
84 /*****************************************************************************
85 * IDirectSound implementation structure
87 struct IDirectSoundImpl
90 ICOM_VTABLE(IDirectSound
)* lpvtbl
;
92 /* IDirectSoundImpl fields */
95 IDirectSoundBufferImpl
** buffers
;
96 IDirectSoundBufferImpl
* primary
;
97 IDirectSound3DListenerImpl
* listener
;
98 WAVEFORMATEX wfx
; /* current main waveformat */
101 /*****************************************************************************
102 * IDirectSoundBuffer implementation structure
104 struct IDirectSoundBufferImpl
106 /* IUnknown fields */
107 ICOM_VTABLE(IDirectSoundBuffer
)* lpvtbl
;
109 /* IDirectSoundBufferImpl fields */
112 IDirectSound3DBufferImpl
* ds3db
;
113 DWORD playflags
,playing
;
114 DWORD playpos
,writepos
,buflen
;
115 DWORD nAvgBytesPerSec
;
119 LONG lVolAdjust
,rVolAdjust
;
120 IDirectSoundBufferImpl
* parent
; /* for duplicates */
121 IDirectSoundImpl
* dsound
;
123 LPDSBPOSITIONNOTIFY notifies
;
125 CRITICAL_SECTION lock
;
128 /*****************************************************************************
129 * IDirectSoundNotify implementation structure
131 struct IDirectSoundNotifyImpl
133 /* IUnknown fields */
134 ICOM_VTABLE(IDirectSoundNotify
)* lpvtbl
;
136 /* IDirectSoundNotifyImpl fields */
137 IDirectSoundBufferImpl
* dsb
;
140 /*****************************************************************************
141 * IDirectSound3DListener implementation structure
143 struct IDirectSound3DListenerImpl
145 /* IUnknown fields */
146 ICOM_VTABLE(IDirectSound3DListener
)* lpvtbl
;
148 /* IDirectSound3DListenerImpl fields */
149 IDirectSoundBufferImpl
* dsb
;
151 CRITICAL_SECTION lock
;
154 /*****************************************************************************
155 * IDirectSound3DBuffer implementation structure
157 struct IDirectSound3DBufferImpl
159 /* IUnknown fields */
160 ICOM_VTABLE(IDirectSound3DBuffer
)* lpvtbl
;
162 /* IDirectSound3DBufferImpl fields */
163 IDirectSoundBufferImpl
* dsb
;
167 CRITICAL_SECTION lock
;
172 # include <sys/ioctl.h>
173 # ifdef HAVE_MACHINE_SOUNDCARD_H
174 # include <machine/soundcard.h>
176 # ifdef HAVE_SYS_SOUNDCARD_H
177 # include <sys/soundcard.h>
180 /* #define USE_DSOUND3D 1 */
182 #define DSOUND_FRAGLEN (primarybuf->wfx.nAvgBytesPerSec >> 4)
183 #define DSOUND_FREQSHIFT (14)
185 static int audiofd
= -1;
186 static int audioOK
= 0;
188 static IDirectSoundImpl
* dsound
= NULL
;
190 static IDirectSoundBufferImpl
* primarybuf
= NULL
;
192 static int DSOUND_setformat(LPWAVEFORMATEX wfex
);
193 static void DSOUND_CheckEvent(IDirectSoundBufferImpl
*dsb
, int len
);
194 static void DSOUND_CloseAudio(void);
199 HRESULT WINAPI
DirectSoundEnumerateA(
200 LPDSENUMCALLBACKA enumcb
,
203 TRACE("enumcb = %p, context = %p\n", enumcb
, context
);
207 enumcb(NULL
,"WINE DirectSound using Open Sound System",
215 static void _dump_DSBCAPS(DWORD xmask
) {
220 #define FE(x) { x, #x },
221 FE(DSBCAPS_PRIMARYBUFFER
)
223 FE(DSBCAPS_LOCHARDWARE
)
224 FE(DSBCAPS_LOCSOFTWARE
)
225 FE(DSBCAPS_CTRLFREQUENCY
)
227 FE(DSBCAPS_CTRLVOLUME
)
228 FE(DSBCAPS_CTRLDEFAULT
)
230 FE(DSBCAPS_STICKYFOCUS
)
231 FE(DSBCAPS_GETCURRENTPOSITION2
)
235 for (i
=0;i
<sizeof(flags
)/sizeof(flags
[0]);i
++)
236 if (flags
[i
].mask
& xmask
)
237 fprintf(stderr
,"%s ",flags
[i
].name
);
240 /*******************************************************************************
241 * IDirectSound3DBuffer
244 /* IUnknown methods */
245 static HRESULT WINAPI
IDirectSound3DBufferImpl_QueryInterface(
246 LPDIRECTSOUND3DBUFFER iface
, REFIID riid
, LPVOID
*ppobj
)
248 ICOM_THIS(IDirectSound3DBufferImpl
,iface
);
251 WINE_StringFromCLSID(riid
,xbuf
);
252 TRACE("(%p,%s,%p)\n",This
,xbuf
,ppobj
);
256 static ULONG WINAPI
IDirectSound3DBufferImpl_AddRef(LPDIRECTSOUND3DBUFFER iface
)
258 ICOM_THIS(IDirectSound3DBufferImpl
,iface
);
263 static ULONG WINAPI
IDirectSound3DBufferImpl_Release(LPDIRECTSOUND3DBUFFER iface
)
265 ICOM_THIS(IDirectSound3DBufferImpl
,iface
);
269 HeapFree(GetProcessHeap(),0,This
->buffer
);
270 HeapFree(GetProcessHeap(),0,This
);
275 /* IDirectSound3DBuffer methods */
276 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetAllParameters(
277 LPDIRECTSOUND3DBUFFER iface
,
278 LPDS3DBUFFER lpDs3dBuffer
)
284 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetConeAngles(
285 LPDIRECTSOUND3DBUFFER iface
,
286 LPDWORD lpdwInsideConeAngle
,
287 LPDWORD lpdwOutsideConeAngle
)
293 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetConeOrientation(
294 LPDIRECTSOUND3DBUFFER iface
,
295 LPD3DVECTOR lpvConeOrientation
)
301 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetConeOutsideVolume(
302 LPDIRECTSOUND3DBUFFER iface
,
303 LPLONG lplConeOutsideVolume
)
309 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetMaxDistance(
310 LPDIRECTSOUND3DBUFFER iface
,
311 LPD3DVALUE lpfMaxDistance
)
317 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetMinDistance(
318 LPDIRECTSOUND3DBUFFER iface
,
319 LPD3DVALUE lpfMinDistance
)
325 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetMode(
326 LPDIRECTSOUND3DBUFFER iface
,
333 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetPosition(
334 LPDIRECTSOUND3DBUFFER iface
,
335 LPD3DVECTOR lpvPosition
)
341 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetVelocity(
342 LPDIRECTSOUND3DBUFFER iface
,
343 LPD3DVECTOR lpvVelocity
)
349 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetAllParameters(
350 LPDIRECTSOUND3DBUFFER iface
,
351 LPCDS3DBUFFER lpcDs3dBuffer
,
358 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetConeAngles(
359 LPDIRECTSOUND3DBUFFER iface
,
360 DWORD dwInsideConeAngle
,
361 DWORD dwOutsideConeAngle
,
368 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetConeOrientation(
369 LPDIRECTSOUND3DBUFFER iface
,
370 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
377 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetConeOutsideVolume(
378 LPDIRECTSOUND3DBUFFER iface
,
379 LONG lConeOutsideVolume
,
386 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetMaxDistance(
387 LPDIRECTSOUND3DBUFFER iface
,
388 D3DVALUE fMaxDistance
,
395 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetMinDistance(
396 LPDIRECTSOUND3DBUFFER iface
,
397 D3DVALUE fMinDistance
,
404 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetMode(
405 LPDIRECTSOUND3DBUFFER iface
,
409 ICOM_THIS(IDirectSound3DBufferImpl
,iface
);
410 TRACE("mode = %lx\n", dwMode
);
411 This
->ds3db
.dwMode
= dwMode
;
415 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetPosition(
416 LPDIRECTSOUND3DBUFFER iface
,
417 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
424 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetVelocity(
425 LPDIRECTSOUND3DBUFFER iface
,
426 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
433 ICOM_VTABLE(IDirectSound3DBuffer
) ds3dbvt
=
435 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
436 /* IUnknown methods */
437 IDirectSound3DBufferImpl_QueryInterface
,
438 IDirectSound3DBufferImpl_AddRef
,
439 IDirectSound3DBufferImpl_Release
,
440 /* IDirectSound3DBuffer methods */
441 IDirectSound3DBufferImpl_GetAllParameters
,
442 IDirectSound3DBufferImpl_GetConeAngles
,
443 IDirectSound3DBufferImpl_GetConeOrientation
,
444 IDirectSound3DBufferImpl_GetConeOutsideVolume
,
445 IDirectSound3DBufferImpl_GetMaxDistance
,
446 IDirectSound3DBufferImpl_GetMinDistance
,
447 IDirectSound3DBufferImpl_GetMode
,
448 IDirectSound3DBufferImpl_GetPosition
,
449 IDirectSound3DBufferImpl_GetVelocity
,
450 IDirectSound3DBufferImpl_SetAllParameters
,
451 IDirectSound3DBufferImpl_SetConeAngles
,
452 IDirectSound3DBufferImpl_SetConeOrientation
,
453 IDirectSound3DBufferImpl_SetConeOutsideVolume
,
454 IDirectSound3DBufferImpl_SetMaxDistance
,
455 IDirectSound3DBufferImpl_SetMinDistance
,
456 IDirectSound3DBufferImpl_SetMode
,
457 IDirectSound3DBufferImpl_SetPosition
,
458 IDirectSound3DBufferImpl_SetVelocity
,
462 static int DSOUND_Create3DBuffer(IDirectSoundBufferImpl
* dsb
)
464 DWORD i
, temp
, iSize
, oSize
, offset
;
465 LPBYTE bIbuf
, bObuf
, bTbuf
= NULL
;
466 LPWORD wIbuf
, wObuf
, wTbuf
= NULL
;
468 /* Inside DirectX says it's stupid but allowed */
469 if (dsb
->wfx
.nChannels
== 2) {
470 /* Convert to mono */
471 if (dsb
->wfx
.wBitsPerSample
== 16) {
472 iSize
= dsb
->buflen
/ 4;
473 wTbuf
= malloc(dsb
->buflen
/ 2);
475 return DSERR_OUTOFMEMORY
;
476 for (i
= 0; i
< iSize
; i
++)
477 wTbuf
[i
] = (dsb
->buffer
[i
] + dsb
->buffer
[(i
* 2) + 1]) / 2;
480 iSize
= dsb
->buflen
/ 2;
481 bTbuf
= malloc(dsb
->buflen
/ 2);
483 return DSERR_OUTOFMEMORY
;
484 for (i
= 0; i
< iSize
; i
++)
485 bTbuf
[i
] = (dsb
->buffer
[i
] + dsb
->buffer
[(i
* 2) + 1]) / 2;
489 if (dsb
->wfx
.wBitsPerSample
== 16) {
490 iSize
= dsb
->buflen
/ 2;
491 wIbuf
= (LPWORD
) dsb
->buffer
;
493 bIbuf
= (LPBYTE
) dsb
->buffer
;
498 if (primarybuf
->wfx
.wBitsPerSample
== 16) {
499 wObuf
= (LPWORD
) dsb
->ds3db
->buffer
;
500 oSize
= dsb
->ds3db
->buflen
/ 2;
502 bObuf
= (LPBYTE
) dsb
->ds3db
->buffer
;
503 oSize
= dsb
->ds3db
->buflen
;
506 offset
= primarybuf
->wfx
.nSamplesPerSec
/ 100; /* 10ms */
507 if (primarybuf
->wfx
.wBitsPerSample
== 16 && dsb
->wfx
.wBitsPerSample
== 16)
508 for (i
= 0; i
< iSize
; i
++) {
511 temp
+= wIbuf
[i
- offset
] >> 9;
513 temp
+= wIbuf
[i
+ iSize
- offset
] >> 9;
515 wObuf
[(i
* 2) + 1] = temp
;
517 else if (primarybuf
->wfx
.wBitsPerSample
== 8 && dsb
->wfx
.wBitsPerSample
== 8)
518 for (i
= 0; i
< iSize
; i
++) {
521 temp
+= bIbuf
[i
- offset
] >> 5;
523 temp
+= bIbuf
[i
+ iSize
- offset
] >> 5;
525 bObuf
[(i
* 2) + 1] = temp
;
536 /*******************************************************************************
537 * IDirectSound3DListener
540 /* IUnknown methods */
541 static HRESULT WINAPI
IDirectSound3DListenerImpl_QueryInterface(
542 LPDIRECTSOUND3DLISTENER iface
, REFIID riid
, LPVOID
*ppobj
)
544 ICOM_THIS(IDirectSound3DListenerImpl
,iface
);
547 WINE_StringFromCLSID(riid
,xbuf
);
548 TRACE("(%p,%s,%p)\n",This
,xbuf
,ppobj
);
552 static ULONG WINAPI
IDirectSound3DListenerImpl_AddRef(LPDIRECTSOUND3DLISTENER iface
)
554 ICOM_THIS(IDirectSound3DListenerImpl
,iface
);
559 static ULONG WINAPI
IDirectSound3DListenerImpl_Release(LPDIRECTSOUND3DLISTENER iface
)
561 ICOM_THIS(IDirectSound3DListenerImpl
,iface
);
566 /* IDirectSound3DListener methods */
567 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetAllParameter(
568 LPDIRECTSOUND3DLISTENER iface
,
569 LPDS3DLISTENER lpDS3DL
)
575 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetDistanceFactor(
576 LPDIRECTSOUND3DLISTENER iface
,
577 LPD3DVALUE lpfDistanceFactor
)
583 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetDopplerFactor(
584 LPDIRECTSOUND3DLISTENER iface
,
585 LPD3DVALUE lpfDopplerFactor
)
591 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetOrientation(
592 LPDIRECTSOUND3DLISTENER iface
,
593 LPD3DVECTOR lpvOrientFront
,
594 LPD3DVECTOR lpvOrientTop
)
600 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetPosition(
601 LPDIRECTSOUND3DLISTENER iface
,
602 LPD3DVECTOR lpvPosition
)
608 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetRolloffFactor(
609 LPDIRECTSOUND3DLISTENER iface
,
610 LPD3DVALUE lpfRolloffFactor
)
616 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetVelocity(
617 LPDIRECTSOUND3DLISTENER iface
,
618 LPD3DVECTOR lpvVelocity
)
624 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetAllParameters(
625 LPDIRECTSOUND3DLISTENER iface
,
626 LPCDS3DLISTENER lpcDS3DL
,
633 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetDistanceFactor(
634 LPDIRECTSOUND3DLISTENER iface
,
635 D3DVALUE fDistanceFactor
,
642 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetDopplerFactor(
643 LPDIRECTSOUND3DLISTENER iface
,
644 D3DVALUE fDopplerFactor
,
651 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetOrientation(
652 LPDIRECTSOUND3DLISTENER iface
,
653 D3DVALUE xFront
, D3DVALUE yFront
, D3DVALUE zFront
,
654 D3DVALUE xTop
, D3DVALUE yTop
, D3DVALUE zTop
,
661 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetPosition(
662 LPDIRECTSOUND3DLISTENER iface
,
663 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
670 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetRolloffFactor(
671 LPDIRECTSOUND3DLISTENER iface
,
672 D3DVALUE fRolloffFactor
,
679 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetVelocity(
680 LPDIRECTSOUND3DLISTENER iface
,
681 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
688 static HRESULT WINAPI
IDirectSound3DListenerImpl_CommitDeferredSettings(
689 LPDIRECTSOUND3DLISTENER iface
)
696 ICOM_VTABLE(IDirectSound3DListener
) ds3dlvt
=
698 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
699 /* IUnknown methods */
700 IDirectSound3DListenerImpl_QueryInterface
,
701 IDirectSound3DListenerImpl_AddRef
,
702 IDirectSound3DListenerImpl_Release
,
703 /* IDirectSound3DListener methods */
704 IDirectSound3DListenerImpl_GetAllParameter
,
705 IDirectSound3DListenerImpl_GetDistanceFactor
,
706 IDirectSound3DListenerImpl_GetDopplerFactor
,
707 IDirectSound3DListenerImpl_GetOrientation
,
708 IDirectSound3DListenerImpl_GetPosition
,
709 IDirectSound3DListenerImpl_GetRolloffFactor
,
710 IDirectSound3DListenerImpl_GetVelocity
,
711 IDirectSound3DListenerImpl_SetAllParameters
,
712 IDirectSound3DListenerImpl_SetDistanceFactor
,
713 IDirectSound3DListenerImpl_SetDopplerFactor
,
714 IDirectSound3DListenerImpl_SetOrientation
,
715 IDirectSound3DListenerImpl_SetPosition
,
716 IDirectSound3DListenerImpl_SetRolloffFactor
,
717 IDirectSound3DListenerImpl_SetVelocity
,
718 IDirectSound3DListenerImpl_CommitDeferredSettings
,
721 /*******************************************************************************
724 static HRESULT WINAPI
IDirectSoundNotifyImpl_QueryInterface(
725 LPDIRECTSOUNDNOTIFY iface
,REFIID riid
,LPVOID
*ppobj
727 ICOM_THIS(IDirectSoundNotifyImpl
,iface
);
730 WINE_StringFromCLSID(riid
,xbuf
);
731 TRACE("(%p,%s,%p)\n",This
,xbuf
,ppobj
);
735 static ULONG WINAPI
IDirectSoundNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface
) {
736 ICOM_THIS(IDirectSoundNotifyImpl
,iface
);
737 return ++(This
->ref
);
740 static ULONG WINAPI
IDirectSoundNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface
) {
741 ICOM_THIS(IDirectSoundNotifyImpl
,iface
);
744 IDirectSoundNotify_Release((LPDIRECTSOUNDBUFFER
)This
->dsb
);
745 HeapFree(GetProcessHeap(),0,This
);
751 static HRESULT WINAPI
IDirectSoundNotifyImpl_SetNotificationPositions(
752 LPDIRECTSOUNDNOTIFY iface
,DWORD howmuch
,LPCDSBPOSITIONNOTIFY notify
754 ICOM_THIS(IDirectSoundNotifyImpl
,iface
);
757 if (TRACE_ON(dsound
)) {
758 TRACE("(%p,0x%08lx,%p)\n",This
,howmuch
,notify
);
759 for (i
=0;i
<howmuch
;i
++)
760 TRACE("notify at %ld to 0x%08lx\n",
761 notify
[i
].dwOffset
,(DWORD
)notify
[i
].hEventNotify
);
763 This
->dsb
->notifies
= HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,This
->dsb
->notifies
,(This
->dsb
->nrofnotifies
+howmuch
)*sizeof(DSBPOSITIONNOTIFY
));
764 memcpy( This
->dsb
->notifies
+This
->dsb
->nrofnotifies
,
766 howmuch
*sizeof(DSBPOSITIONNOTIFY
)
768 This
->dsb
->nrofnotifies
+=howmuch
;
773 ICOM_VTABLE(IDirectSoundNotify
) dsnvt
=
775 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
776 IDirectSoundNotifyImpl_QueryInterface
,
777 IDirectSoundNotifyImpl_AddRef
,
778 IDirectSoundNotifyImpl_Release
,
779 IDirectSoundNotifyImpl_SetNotificationPositions
,
782 /*******************************************************************************
786 /* This sets this format for the <em>Primary Buffer Only</em> */
787 /* See file:///cdrom/sdk52/docs/worddoc/dsound.doc page 120 */
788 static HRESULT WINAPI
IDirectSoundBufferImpl_SetFormat(
789 LPDIRECTSOUNDBUFFER iface
,LPWAVEFORMATEX wfex
791 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
792 IDirectSoundBufferImpl
** dsb
;
795 /* Let's be pedantic! */
796 if ((wfex
== NULL
) ||
797 (wfex
->wFormatTag
!= WAVE_FORMAT_PCM
) ||
798 (wfex
->nChannels
< 1) || (wfex
->nChannels
> 2) ||
799 (wfex
->nSamplesPerSec
< 1) ||
800 (wfex
->nBlockAlign
< 1) || (wfex
->nChannels
> 4) ||
801 ((wfex
->wBitsPerSample
!= 8) && (wfex
->wBitsPerSample
!= 16))) {
802 TRACE("failed pedantic check!\n");
803 return DSERR_INVALIDPARAM
;
807 EnterCriticalSection(&(primarybuf
->lock
));
809 if (primarybuf
->wfx
.nSamplesPerSec
!= wfex
->nSamplesPerSec
) {
810 dsb
= dsound
->buffers
;
811 for (i
= 0; i
< dsound
->nrofbuffers
; i
++, dsb
++) {
813 EnterCriticalSection(&((*dsb
)->lock
));
815 (*dsb
)->freqAdjust
= ((*dsb
)->freq
<< DSOUND_FREQSHIFT
) /
816 wfex
->nSamplesPerSec
;
818 LeaveCriticalSection(&((*dsb
)->lock
));
823 memcpy(&(primarybuf
->wfx
), wfex
, sizeof(primarybuf
->wfx
));
825 TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld"
826 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
827 wfex
->wFormatTag
, wfex
->nChannels
, wfex
->nSamplesPerSec
,
828 wfex
->nAvgBytesPerSec
, wfex
->nBlockAlign
,
829 wfex
->wBitsPerSample
, wfex
->cbSize
);
831 primarybuf
->wfx
.nAvgBytesPerSec
=
832 This
->wfx
.nSamplesPerSec
* This
->wfx
.nBlockAlign
;
836 LeaveCriticalSection(&(primarybuf
->lock
));
842 static HRESULT WINAPI
IDirectSoundBufferImpl_SetVolume(
843 LPDIRECTSOUNDBUFFER iface
,LONG vol
845 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
848 TRACE("(%p,%ld)\n",This
,vol
);
850 /* I'm not sure if we need this for primary buffer */
851 if (!(This
->dsbd
.dwFlags
& DSBCAPS_CTRLVOLUME
))
852 return DSERR_CONTROLUNAVAIL
;
854 if ((vol
> DSBVOLUME_MAX
) || (vol
< DSBVOLUME_MIN
))
855 return DSERR_INVALIDPARAM
;
857 /* This needs to adjust the soundcard volume when */
858 /* called for the primary buffer */
859 if (This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
860 FIXME("Volume control of primary unimplemented.\n");
866 EnterCriticalSection(&(This
->lock
));
870 temp
= (double) (This
->volume
- (This
->pan
> 0 ? This
->pan
: 0));
871 This
->lVolAdjust
= (ULONG
) (pow(2.0, temp
/ 600.0) * 32768.0);
872 temp
= (double) (This
->volume
+ (This
->pan
< 0 ? This
->pan
: 0));
873 This
->rVolAdjust
= (ULONG
) (pow(2.0, temp
/ 600.0) * 32768.0);
875 LeaveCriticalSection(&(This
->lock
));
878 TRACE("left = %lx, right = %lx\n", This
->lVolAdjust
, This
->rVolAdjust
);
883 static HRESULT WINAPI
IDirectSoundBufferImpl_GetVolume(
884 LPDIRECTSOUNDBUFFER iface
,LPLONG vol
886 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
887 TRACE("(%p,%p)\n",This
,vol
);
890 return DSERR_INVALIDPARAM
;
896 static HRESULT WINAPI
IDirectSoundBufferImpl_SetFrequency(
897 LPDIRECTSOUNDBUFFER iface
,DWORD freq
899 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
900 TRACE("(%p,%ld)\n",This
,freq
);
902 /* You cannot set the frequency of the primary buffer */
903 if (!(This
->dsbd
.dwFlags
& DSBCAPS_CTRLFREQUENCY
) ||
904 (This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
))
905 return DSERR_CONTROLUNAVAIL
;
907 if ((freq
< DSBFREQUENCY_MIN
) || (freq
> DSBFREQUENCY_MAX
))
908 return DSERR_INVALIDPARAM
;
911 EnterCriticalSection(&(This
->lock
));
914 This
->freqAdjust
= (freq
<< DSOUND_FREQSHIFT
) / primarybuf
->wfx
.nSamplesPerSec
;
915 This
->nAvgBytesPerSec
= freq
* This
->wfx
.nBlockAlign
;
917 LeaveCriticalSection(&(This
->lock
));
923 static HRESULT WINAPI
IDirectSoundBufferImpl_Play(
924 LPDIRECTSOUNDBUFFER iface
,DWORD reserved1
,DWORD reserved2
,DWORD flags
926 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
927 TRACE("(%p,%08lx,%08lx,%08lx)\n",
928 This
,reserved1
,reserved2
,flags
930 This
->playflags
= flags
;
935 static HRESULT WINAPI
IDirectSoundBufferImpl_Stop(LPDIRECTSOUNDBUFFER iface
)
937 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
938 TRACE("(%p)\n",This
);
941 EnterCriticalSection(&(This
->lock
));
944 DSOUND_CheckEvent(This
, 0);
946 LeaveCriticalSection(&(This
->lock
));
952 static DWORD WINAPI
IDirectSoundBufferImpl_AddRef(LPDIRECTSOUNDBUFFER iface
) {
953 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
954 /* TRACE(dsound,"(%p) ref was %ld\n",This, This->ref); */
956 return ++(This
->ref
);
958 static DWORD WINAPI
IDirectSoundBufferImpl_Release(LPDIRECTSOUNDBUFFER iface
) {
959 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
962 /* TRACE(dsound,"(%p) ref was %ld\n",This, This->ref); */
967 for (i
=0;i
<This
->dsound
->nrofbuffers
;i
++)
968 if (This
->dsound
->buffers
[i
] == This
)
970 if (i
< This
->dsound
->nrofbuffers
) {
971 /* Put the last buffer of the list in the (now empty) position */
972 This
->dsound
->buffers
[i
] = This
->dsound
->buffers
[This
->dsound
->nrofbuffers
- 1];
973 This
->dsound
->buffers
= HeapReAlloc(GetProcessHeap(),0,This
->dsound
->buffers
,sizeof(LPDIRECTSOUNDBUFFER
)*This
->dsound
->nrofbuffers
);
974 This
->dsound
->nrofbuffers
--;
975 IDirectSound_Release((LPDIRECTSOUND
)This
->dsound
);
978 DeleteCriticalSection(&(This
->lock
));
980 if (This
->ds3db
&& This
->ds3db
->lpvtbl
)
981 IDirectSound3DBuffer_Release((LPDIRECTSOUND3DBUFFER
)This
->ds3db
);
984 /* this is a duplicate buffer */
985 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)This
->parent
);
987 /* this is a toplevel buffer */
988 HeapFree(GetProcessHeap(),0,This
->buffer
);
990 HeapFree(GetProcessHeap(),0,This
);
992 if (This
== primarybuf
)
998 static HRESULT WINAPI
IDirectSoundBufferImpl_GetCurrentPosition(
999 LPDIRECTSOUNDBUFFER iface
,LPDWORD playpos
,LPDWORD writepos
1001 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1002 TRACE("(%p,%p,%p)\n",This
,playpos
,writepos
);
1003 if (playpos
) *playpos
= This
->playpos
;
1004 if (writepos
) *writepos
= This
->writepos
;
1005 TRACE("playpos = %ld, writepos = %ld\n", *playpos
, *writepos
);
1009 static HRESULT WINAPI
IDirectSoundBufferImpl_GetStatus(
1010 LPDIRECTSOUNDBUFFER iface
,LPDWORD status
1012 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1013 TRACE("(%p,%p)\n",This
,status
);
1016 return DSERR_INVALIDPARAM
;
1020 *status
|= DSBSTATUS_PLAYING
;
1021 if (This
->playflags
& DSBPLAY_LOOPING
)
1022 *status
|= DSBSTATUS_LOOPING
;
1028 static HRESULT WINAPI
IDirectSoundBufferImpl_GetFormat(
1029 LPDIRECTSOUNDBUFFER iface
,LPWAVEFORMATEX lpwf
,DWORD wfsize
,LPDWORD wfwritten
1031 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1032 TRACE("(%p,%p,%ld,%p)\n",This
,lpwf
,wfsize
,wfwritten
);
1034 if (wfsize
>sizeof(This
->wfx
))
1035 wfsize
= sizeof(This
->wfx
);
1036 if (lpwf
) { /* NULL is valid */
1037 memcpy(lpwf
,&(This
->wfx
),wfsize
);
1039 *wfwritten
= wfsize
;
1042 *wfwritten
= sizeof(This
->wfx
);
1044 return DSERR_INVALIDPARAM
;
1049 static HRESULT WINAPI
IDirectSoundBufferImpl_Lock(
1050 LPDIRECTSOUNDBUFFER iface
,DWORD writecursor
,DWORD writebytes
,LPVOID lplpaudioptr1
,LPDWORD audiobytes1
,LPVOID lplpaudioptr2
,LPDWORD audiobytes2
,DWORD flags
1052 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1054 TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx)\n",
1064 if (flags
& DSBLOCK_FROMWRITECURSOR
)
1065 writecursor
+= This
->writepos
;
1066 if (flags
& DSBLOCK_ENTIREBUFFER
)
1067 writebytes
= This
->buflen
;
1068 if (writebytes
> This
->buflen
)
1069 writebytes
= This
->buflen
;
1071 assert(audiobytes1
!=audiobytes2
);
1072 assert(lplpaudioptr1
!=lplpaudioptr2
);
1073 if (writecursor
+writebytes
<= This
->buflen
) {
1074 *(LPBYTE
*)lplpaudioptr1
= This
->buffer
+writecursor
;
1075 *audiobytes1
= writebytes
;
1077 *(LPBYTE
*)lplpaudioptr2
= NULL
;
1080 TRACE("->%ld.0\n",writebytes
);
1082 *(LPBYTE
*)lplpaudioptr1
= This
->buffer
+writecursor
;
1083 *audiobytes1
= This
->buflen
-writecursor
;
1085 *(LPBYTE
*)lplpaudioptr2
= This
->buffer
;
1087 *audiobytes2
= writebytes
-(This
->buflen
-writecursor
);
1088 TRACE("->%ld.%ld\n",*audiobytes1
,audiobytes2
?*audiobytes2
:0);
1090 /* No. See file:///cdrom/sdk52/docs/worddoc/dsound.doc page 21 */
1091 /* This->writepos=(writecursor+writebytes)%This->buflen; */
1095 static HRESULT WINAPI
IDirectSoundBufferImpl_SetCurrentPosition(
1096 LPDIRECTSOUNDBUFFER iface
,DWORD newpos
1098 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1099 TRACE("(%p,%ld)\n",This
,newpos
);
1102 EnterCriticalSection(&(This
->lock
));
1104 This
->playpos
= newpos
;
1106 LeaveCriticalSection(&(This
->lock
));
1112 static HRESULT WINAPI
IDirectSoundBufferImpl_SetPan(
1113 LPDIRECTSOUNDBUFFER iface
,LONG pan
1115 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1118 TRACE("(%p,%ld)\n",This
,pan
);
1120 if ((pan
> DSBPAN_RIGHT
) || (pan
< DSBPAN_LEFT
))
1121 return DSERR_INVALIDPARAM
;
1123 /* You cannot set the pan of the primary buffer */
1124 /* and you cannot use both pan and 3D controls */
1125 if (!(This
->dsbd
.dwFlags
& DSBCAPS_CTRLPAN
) ||
1126 (This
->dsbd
.dwFlags
& DSBCAPS_CTRL3D
) ||
1127 (This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
))
1128 return DSERR_CONTROLUNAVAIL
;
1131 EnterCriticalSection(&(This
->lock
));
1135 temp
= (double) (This
->volume
- (This
->pan
> 0 ? This
->pan
: 0));
1136 This
->lVolAdjust
= (ULONG
) (pow(2.0, temp
/ 600.0) * 32768.0);
1137 temp
= (double) (This
->volume
+ (This
->pan
< 0 ? This
->pan
: 0));
1138 This
->rVolAdjust
= (ULONG
) (pow(2.0, temp
/ 600.0) * 32768.0);
1140 LeaveCriticalSection(&(This
->lock
));
1146 static HRESULT WINAPI
IDirectSoundBufferImpl_GetPan(
1147 LPDIRECTSOUNDBUFFER iface
,LPLONG pan
1149 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1150 TRACE("(%p,%p)\n",This
,pan
);
1153 return DSERR_INVALIDPARAM
;
1160 static HRESULT WINAPI
IDirectSoundBufferImpl_Unlock(
1161 LPDIRECTSOUNDBUFFER iface
,LPVOID p1
,DWORD x1
,LPVOID p2
,DWORD x2
1163 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1164 TRACE("(%p,%p,%ld,%p,%ld):stub\n", This
,p1
,x1
,p2
,x2
);
1166 /* There is really nothing to do here. Should someone */
1167 /* choose to implement static buffers in hardware (by */
1168 /* using a wave table synth, for example) this is where */
1169 /* you'd want to do the loading. For software buffers, */
1170 /* which is what we currently use, we need do nothing. */
1173 /* It's also the place to pre-process 3D buffers... */
1175 /* This is highly experimental and liable to break things */
1176 if (This
->dsbd
.dwFlags
& DSBCAPS_CTRL3D
)
1177 DSOUND_Create3DBuffer(This
);
1183 static HRESULT WINAPI
IDirectSoundBufferImpl_GetFrequency(
1184 LPDIRECTSOUNDBUFFER iface
,LPDWORD freq
1186 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1187 TRACE("(%p,%p)\n",This
,freq
);
1190 return DSERR_INVALIDPARAM
;
1197 static HRESULT WINAPI
IDirectSoundBufferImpl_Initialize(
1198 LPDIRECTSOUNDBUFFER iface
,LPDIRECTSOUND dsound
,LPDSBUFFERDESC dbsd
1200 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1201 FIXME("(%p,%p,%p):stub\n",This
,dsound
,dbsd
);
1202 printf("Re-Init!!!\n");
1203 return DSERR_ALREADYINITIALIZED
;
1206 static HRESULT WINAPI
IDirectSoundBufferImpl_GetCaps(
1207 LPDIRECTSOUNDBUFFER iface
,LPDSBCAPS caps
1209 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1210 TRACE("(%p)->(%p)\n",This
,caps
);
1213 return DSERR_INVALIDPARAM
;
1215 /* I think we should check this value, not set it. See */
1216 /* Inside DirectX, p215. That should apply here, too. */
1217 caps
->dwSize
= sizeof(*caps
);
1219 caps
->dwFlags
= This
->dsbd
.dwFlags
| DSBCAPS_LOCSOFTWARE
;
1220 caps
->dwBufferBytes
= This
->dsbd
.dwBufferBytes
;
1221 /* This value represents the speed of the "unlock" command.
1222 As unlock is quite fast (it does not do anything), I put
1223 4096 ko/s = 4 Mo / s */
1224 caps
->dwUnlockTransferRate
= 4096;
1225 caps
->dwPlayCpuOverhead
= 0;
1230 static HRESULT WINAPI
IDirectSoundBufferImpl_QueryInterface(
1231 LPDIRECTSOUNDBUFFER iface
,REFIID riid
,LPVOID
*ppobj
1233 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1236 WINE_StringFromCLSID(riid
,xbuf
);
1237 TRACE("(%p,%s,%p)\n",This
,xbuf
,ppobj
);
1239 if (!memcmp(&IID_IDirectSoundNotify
,riid
,sizeof(*riid
))) {
1240 IDirectSoundNotifyImpl
*dsn
;
1242 dsn
= (IDirectSoundNotifyImpl
*)HeapAlloc(GetProcessHeap(),0,sizeof(*dsn
));
1245 IDirectSoundBuffer_AddRef(iface
);
1246 dsn
->lpvtbl
= &dsnvt
;
1247 *ppobj
= (LPVOID
)dsn
;
1251 if (!memcmp(&IID_IDirectSound3DBuffer
,riid
,sizeof(*riid
))) {
1252 *ppobj
= This
->ds3db
;
1260 static ICOM_VTABLE(IDirectSoundBuffer
) dsbvt
=
1262 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1263 IDirectSoundBufferImpl_QueryInterface
,
1264 IDirectSoundBufferImpl_AddRef
,
1265 IDirectSoundBufferImpl_Release
,
1266 IDirectSoundBufferImpl_GetCaps
,
1267 IDirectSoundBufferImpl_GetCurrentPosition
,
1268 IDirectSoundBufferImpl_GetFormat
,
1269 IDirectSoundBufferImpl_GetVolume
,
1270 IDirectSoundBufferImpl_GetPan
,
1271 IDirectSoundBufferImpl_GetFrequency
,
1272 IDirectSoundBufferImpl_GetStatus
,
1273 IDirectSoundBufferImpl_Initialize
,
1274 IDirectSoundBufferImpl_Lock
,
1275 IDirectSoundBufferImpl_Play
,
1276 IDirectSoundBufferImpl_SetCurrentPosition
,
1277 IDirectSoundBufferImpl_SetFormat
,
1278 IDirectSoundBufferImpl_SetVolume
,
1279 IDirectSoundBufferImpl_SetPan
,
1280 IDirectSoundBufferImpl_SetFrequency
,
1281 IDirectSoundBufferImpl_Stop
,
1282 IDirectSoundBufferImpl_Unlock
1285 /*******************************************************************************
1289 static HRESULT WINAPI
IDirectSoundImpl_SetCooperativeLevel(
1290 LPDIRECTSOUND iface
,HWND hwnd
,DWORD level
1292 ICOM_THIS(IDirectSoundImpl
,iface
);
1293 FIXME("(%p,%08lx,%ld):stub\n",This
,(DWORD
)hwnd
,level
);
1297 static HRESULT WINAPI
IDirectSoundImpl_CreateSoundBuffer(
1298 LPDIRECTSOUND iface
,LPDSBUFFERDESC dsbd
,LPLPDIRECTSOUNDBUFFER ppdsb
,LPUNKNOWN lpunk
1300 ICOM_THIS(IDirectSoundImpl
,iface
);
1301 IDirectSoundBufferImpl
** ippdsb
=(IDirectSoundBufferImpl
**)ppdsb
;
1302 LPWAVEFORMATEX wfex
;
1304 TRACE("(%p,%p,%p,%p)\n",This
,dsbd
,ippdsb
,lpunk
);
1306 if ((This
== NULL
) || (dsbd
== NULL
) || (ippdsb
== NULL
))
1307 return DSERR_INVALIDPARAM
;
1309 if (TRACE_ON(dsound
)) {
1310 TRACE("(size=%ld)\n",dsbd
->dwSize
);
1311 TRACE("(flags=0x%08lx\n",dsbd
->dwFlags
);
1312 _dump_DSBCAPS(dsbd
->dwFlags
);
1313 TRACE("(bufferbytes=%ld)\n",dsbd
->dwBufferBytes
);
1314 TRACE("(lpwfxFormat=%p)\n",dsbd
->lpwfxFormat
);
1317 wfex
= dsbd
->lpwfxFormat
;
1320 TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld"
1321 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
1322 wfex
->wFormatTag
, wfex
->nChannels
, wfex
->nSamplesPerSec
,
1323 wfex
->nAvgBytesPerSec
, wfex
->nBlockAlign
,
1324 wfex
->wBitsPerSample
, wfex
->cbSize
);
1326 if (dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
1328 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER
)primarybuf
);
1329 *ippdsb
= primarybuf
;
1330 primarybuf
->dsbd
.dwFlags
= dsbd
->dwFlags
;
1332 } /* Else create primarybuf */
1335 *ippdsb
= (IDirectSoundBufferImpl
*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDirectSoundBufferImpl
));
1336 if (*ippdsb
== NULL
)
1337 return DSERR_OUTOFMEMORY
;
1340 TRACE("Created buffer at %p\n", *ippdsb
);
1342 if (dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
1343 (*ippdsb
)->buflen
= dsound
->wfx
.nAvgBytesPerSec
;
1344 (*ippdsb
)->freq
= dsound
->wfx
.nSamplesPerSec
;
1346 (*ippdsb
)->buflen
= dsbd
->dwBufferBytes
;
1347 (*ippdsb
)->freq
= dsbd
->lpwfxFormat
->nSamplesPerSec
;
1349 (*ippdsb
)->buffer
= (LPBYTE
)HeapAlloc(GetProcessHeap(),0,(*ippdsb
)->buflen
);
1350 if ((*ippdsb
)->buffer
== NULL
) {
1351 HeapFree(GetProcessHeap(),0,(*ippdsb
));
1353 return DSERR_OUTOFMEMORY
;
1355 /* It's not necessary to initialize values to zero since */
1356 /* we allocated this structure with HEAP_ZERO_MEMORY... */
1357 (*ippdsb
)->playpos
= 0;
1358 (*ippdsb
)->writepos
= 0;
1359 (*ippdsb
)->parent
= NULL
;
1360 (*ippdsb
)->lpvtbl
= &dsbvt
;
1361 (*ippdsb
)->dsound
= This
;
1362 (*ippdsb
)->playing
= 0;
1363 (*ippdsb
)->lVolAdjust
= (1 << 15);
1364 (*ippdsb
)->rVolAdjust
= (1 << 15);
1366 if (!(dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
)) {
1367 (*ippdsb
)->freqAdjust
= ((*ippdsb
)->freq
<< DSOUND_FREQSHIFT
) /
1368 primarybuf
->wfx
.nSamplesPerSec
;
1369 (*ippdsb
)->nAvgBytesPerSec
= (*ippdsb
)->freq
*
1370 dsbd
->lpwfxFormat
->nBlockAlign
;
1373 memcpy(&((*ippdsb
)->dsbd
),dsbd
,sizeof(*dsbd
));
1375 /* register buffer */
1376 if (!(dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
)) {
1377 This
->buffers
= (IDirectSoundBufferImpl
**)HeapReAlloc(GetProcessHeap(),0,This
->buffers
,sizeof(IDirectSoundBufferImpl
*)*(This
->nrofbuffers
+1));
1378 This
->buffers
[This
->nrofbuffers
] = *ippdsb
;
1379 This
->nrofbuffers
++;
1381 IDirectSound_AddRef(iface
);
1383 if (dsbd
->lpwfxFormat
)
1384 memcpy(&((*ippdsb
)->wfx
), dsbd
->lpwfxFormat
, sizeof((*ippdsb
)->wfx
));
1386 InitializeCriticalSection(&((*ippdsb
)->lock
));
1389 if (dsbd
->dwFlags
& DSBCAPS_CTRL3D
) {
1390 IDirectSound3DBufferImpl
*ds3db
;
1392 ds3db
= (IDirectSound3DBufferImpl
*)HeapAlloc(GetProcessHeap(),
1395 ds3db
->dsb
= (*ippdsb
);
1396 ds3db
->lpvtbl
= &ds3dbvt
;
1397 (*ippdsb
)->ds3db
= ds3db
;
1398 ds3db
->ds3db
.dwSize
= sizeof(DS3DBUFFER
);
1399 ds3db
->ds3db
.vPosition
.x
.x
= 0.0;
1400 ds3db
->ds3db
.vPosition
.y
.y
= 0.0;
1401 ds3db
->ds3db
.vPosition
.z
.z
= 0.0;
1402 ds3db
->ds3db
.vVelocity
.x
.x
= 0.0;
1403 ds3db
->ds3db
.vVelocity
.y
.y
= 0.0;
1404 ds3db
->ds3db
.vVelocity
.z
.z
= 0.0;
1405 ds3db
->ds3db
.dwInsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
1406 ds3db
->ds3db
.dwOutsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
1407 ds3db
->ds3db
.vConeOrientation
.x
.x
= 0.0;
1408 ds3db
->ds3db
.vConeOrientation
.y
.y
= 0.0;
1409 ds3db
->ds3db
.vConeOrientation
.z
.z
= 0.0;
1410 ds3db
->ds3db
.lConeOutsideVolume
= DS3D_DEFAULTCONEOUTSIDEVOLUME
;
1411 ds3db
->ds3db
.flMinDistance
= DS3D_DEFAULTMINDISTANCE
;
1412 ds3db
->ds3db
.flMaxDistance
= DS3D_DEFAULTMAXDISTANCE
;
1413 ds3db
->ds3db
.dwMode
= DS3DMODE_NORMAL
;
1414 ds3db
->buflen
= ((*ippdsb
)->buflen
* primarybuf
->wfx
.nBlockAlign
) /
1415 (*ippdsb
)->wfx
.nBlockAlign
;
1416 ds3db
->buffer
= HeapAlloc(GetProcessHeap(), 0, ds3db
->buflen
);
1417 if (ds3db
->buffer
== NULL
) {
1419 ds3db
->ds3db
.dwMode
= DS3DMODE_DISABLE
;
1426 static HRESULT WINAPI
IDirectSoundImpl_DuplicateSoundBuffer(
1427 LPDIRECTSOUND iface
,LPDIRECTSOUNDBUFFER pdsb
,LPLPDIRECTSOUNDBUFFER ppdsb
1429 ICOM_THIS(IDirectSoundImpl
,iface
);
1430 IDirectSoundBufferImpl
* ipdsb
=(IDirectSoundBufferImpl
*)pdsb
;
1431 IDirectSoundBufferImpl
** ippdsb
=(IDirectSoundBufferImpl
**)ppdsb
;
1432 TRACE("(%p,%p,%p)\n",This
,ipdsb
,ippdsb
);
1434 *ippdsb
= (IDirectSoundBufferImpl
*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDirectSoundBufferImpl
));
1436 IDirectSoundBuffer_AddRef(pdsb
);
1437 memcpy(*ippdsb
, ipdsb
, sizeof(IDirectSoundBufferImpl
));
1439 (*ippdsb
)->playpos
= 0;
1440 (*ippdsb
)->writepos
= 0;
1441 (*ippdsb
)->dsound
= This
;
1442 (*ippdsb
)->parent
= ipdsb
;
1443 memcpy(&((*ippdsb
)->wfx
), &(ipdsb
->wfx
), sizeof((*ippdsb
)->wfx
));
1444 /* register buffer */
1445 This
->buffers
= (IDirectSoundBufferImpl
**)HeapReAlloc(GetProcessHeap(),0,This
->buffers
,sizeof(IDirectSoundBufferImpl
**)*(This
->nrofbuffers
+1));
1446 This
->buffers
[This
->nrofbuffers
] = *ippdsb
;
1447 This
->nrofbuffers
++;
1448 IDirectSound_AddRef(iface
);
1453 static HRESULT WINAPI
IDirectSoundImpl_GetCaps(LPDIRECTSOUND iface
,LPDSCAPS caps
) {
1454 ICOM_THIS(IDirectSoundImpl
,iface
);
1455 TRACE("(%p,%p)\n",This
,caps
);
1456 TRACE("(flags=0x%08lx)\n",caps
->dwFlags
);
1459 return DSERR_INVALIDPARAM
;
1461 /* We should check this value, not set it. See Inside DirectX, p215. */
1462 caps
->dwSize
= sizeof(*caps
);
1465 DSCAPS_PRIMARYSTEREO
|
1466 DSCAPS_PRIMARY16BIT
|
1467 DSCAPS_SECONDARYSTEREO
|
1468 DSCAPS_SECONDARY16BIT
|
1469 DSCAPS_CONTINUOUSRATE
;
1470 /* FIXME: query OSS */
1471 caps
->dwMinSecondarySampleRate
= DSBFREQUENCY_MIN
;
1472 caps
->dwMaxSecondarySampleRate
= DSBFREQUENCY_MAX
;
1474 caps
->dwPrimaryBuffers
= 1;
1476 caps
->dwMaxHwMixingAllBuffers
= 0;
1477 caps
->dwMaxHwMixingStaticBuffers
= 0;
1478 caps
->dwMaxHwMixingStreamingBuffers
= 0;
1480 caps
->dwFreeHwMixingAllBuffers
= 0;
1481 caps
->dwFreeHwMixingStaticBuffers
= 0;
1482 caps
->dwFreeHwMixingStreamingBuffers
= 0;
1484 caps
->dwMaxHw3DAllBuffers
= 0;
1485 caps
->dwMaxHw3DStaticBuffers
= 0;
1486 caps
->dwMaxHw3DStreamingBuffers
= 0;
1488 caps
->dwFreeHw3DAllBuffers
= 0;
1489 caps
->dwFreeHw3DStaticBuffers
= 0;
1490 caps
->dwFreeHw3DStreamingBuffers
= 0;
1492 caps
->dwTotalHwMemBytes
= 0;
1494 caps
->dwFreeHwMemBytes
= 0;
1496 caps
->dwMaxContigFreeHwMemBytes
= 0;
1498 caps
->dwUnlockTransferRateHwBuffers
= 4096; /* But we have none... */
1500 caps
->dwPlayCpuOverheadSwBuffers
= 1; /* 1% */
1505 static ULONG WINAPI
IDirectSoundImpl_AddRef(LPDIRECTSOUND iface
) {
1506 ICOM_THIS(IDirectSoundImpl
,iface
);
1507 return ++(This
->ref
);
1510 static ULONG WINAPI
IDirectSoundImpl_Release(LPDIRECTSOUND iface
) {
1511 ICOM_THIS(IDirectSoundImpl
,iface
);
1512 TRACE("(%p), ref was %ld\n",This
,This
->ref
);
1513 if (!--(This
->ref
)) {
1514 DSOUND_CloseAudio();
1515 while(IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)primarybuf
)); /* Deallocate */
1516 FIXME("need to release all buffers!\n");
1517 HeapFree(GetProcessHeap(),0,This
);
1524 static HRESULT WINAPI
IDirectSoundImpl_SetSpeakerConfig(
1525 LPDIRECTSOUND iface
,DWORD config
1527 ICOM_THIS(IDirectSoundImpl
,iface
);
1528 FIXME("(%p,0x%08lx):stub\n",This
,config
);
1532 static HRESULT WINAPI
IDirectSoundImpl_QueryInterface(
1533 LPDIRECTSOUND iface
,REFIID riid
,LPVOID
*ppobj
1535 ICOM_THIS(IDirectSoundImpl
,iface
);
1538 if (!memcmp(&IID_IDirectSound3DListener
,riid
,sizeof(*riid
))) {
1540 if (This
->listener
) {
1541 *ppobj
= This
->listener
;
1544 This
->listener
= (IDirectSound3DListenerImpl
*)HeapAlloc(
1545 GetProcessHeap(), 0, sizeof(*(This
->listener
)));
1546 This
->listener
->ref
= 1;
1547 This
->listener
->lpvtbl
= &ds3dlvt
;
1548 IDirectSound_AddRef(iface
);
1549 This
->listener
->ds3dl
.dwSize
= sizeof(DS3DLISTENER
);
1550 This
->listener
->ds3dl
.vPosition
.x
.x
= 0.0;
1551 This
->listener
->ds3dl
.vPosition
.y
.y
= 0.0;
1552 This
->listener
->ds3dl
.vPosition
.z
.z
= 0.0;
1553 This
->listener
->ds3dl
.vVelocity
.x
.x
= 0.0;
1554 This
->listener
->ds3dl
.vVelocity
.y
.y
= 0.0;
1555 This
->listener
->ds3dl
.vVelocity
.z
.z
= 0.0;
1556 This
->listener
->ds3dl
.vOrientFront
.x
.x
= 0.0;
1557 This
->listener
->ds3dl
.vOrientFront
.y
.y
= 0.0;
1558 This
->listener
->ds3dl
.vOrientFront
.z
.z
= 1.0;
1559 This
->listener
->ds3dl
.vOrientTop
.x
.x
= 0.0;
1560 This
->listener
->ds3dl
.vOrientTop
.y
.y
= 1.0;
1561 This
->listener
->ds3dl
.vOrientTop
.z
.z
= 0.0;
1562 This
->listener
->ds3dl
.flDistanceFactor
= DS3D_DEFAULTDISTANCEFACTOR
;
1563 This
->listener
->ds3dl
.flRolloffFactor
= DS3D_DEFAULTROLLOFFFACTOR
;
1564 This
->listener
->ds3dl
.flDopplerFactor
= DS3D_DEFAULTDOPPLERFACTOR
;
1565 *ppobj
= (LPVOID
)This
->listener
;
1569 WINE_StringFromCLSID(riid
,xbuf
);
1570 TRACE("(%p,%s,%p)\n",This
,xbuf
,ppobj
);
1574 static HRESULT WINAPI
IDirectSoundImpl_Compact(
1575 LPDIRECTSOUND iface
)
1577 ICOM_THIS(IDirectSoundImpl
,iface
);
1578 TRACE("(%p)\n", This
);
1582 static HRESULT WINAPI
IDirectSoundImpl_GetSpeakerConfig(
1583 LPDIRECTSOUND iface
,
1584 LPDWORD lpdwSpeakerConfig
)
1586 ICOM_THIS(IDirectSoundImpl
,iface
);
1587 TRACE("(%p, %p)\n", This
, lpdwSpeakerConfig
);
1588 *lpdwSpeakerConfig
= DSSPEAKER_STEREO
| (DSSPEAKER_GEOMETRY_NARROW
<< 16);
1592 static HRESULT WINAPI
IDirectSoundImpl_Initialize(
1593 LPDIRECTSOUND iface
,
1596 ICOM_THIS(IDirectSoundImpl
,iface
);
1597 TRACE("(%p, %p)\n", This
, lpGuid
);
1601 static ICOM_VTABLE(IDirectSound
) dsvt
=
1603 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1604 IDirectSoundImpl_QueryInterface
,
1605 IDirectSoundImpl_AddRef
,
1606 IDirectSoundImpl_Release
,
1607 IDirectSoundImpl_CreateSoundBuffer
,
1608 IDirectSoundImpl_GetCaps
,
1609 IDirectSoundImpl_DuplicateSoundBuffer
,
1610 IDirectSoundImpl_SetCooperativeLevel
,
1611 IDirectSoundImpl_Compact
,
1612 IDirectSoundImpl_GetSpeakerConfig
,
1613 IDirectSoundImpl_SetSpeakerConfig
,
1614 IDirectSoundImpl_Initialize
1618 /* See http://www.opensound.com/pguide/audio.html for more details */
1621 DSOUND_setformat(LPWAVEFORMATEX wfex
) {
1622 int xx
,channels
,speed
,format
,nformat
;
1625 TRACE("(%p) deferred\n", wfex
);
1628 switch (wfex
->wFormatTag
) {
1630 WARN("unknown WAVE_FORMAT tag %d\n",wfex
->wFormatTag
);
1631 return DSERR_BADFORMAT
;
1632 case WAVE_FORMAT_PCM
:
1635 if (wfex
->wBitsPerSample
==8)
1638 format
= AFMT_S16_LE
;
1640 if (-1==ioctl(audiofd
,SNDCTL_DSP_GETFMTS
,&xx
)) {
1641 perror("ioctl SNDCTL_DSP_GETFMTS");
1644 if ((xx
&format
)!=format
) {/* format unsupported */
1645 FIXME("SNDCTL_DSP_GETFMTS: format not supported\n");
1649 if (-1==ioctl(audiofd
,SNDCTL_DSP_SETFMT
,&nformat
)) {
1650 perror("ioctl SNDCTL_DSP_SETFMT");
1653 if (nformat
!=format
) {/* didn't work */
1654 FIXME("SNDCTL_DSP_GETFMTS: format not set\n");
1658 channels
= wfex
->nChannels
-1;
1659 if (-1==ioctl(audiofd
,SNDCTL_DSP_STEREO
,&channels
)) {
1660 perror("ioctl SNDCTL_DSP_STEREO");
1663 speed
= wfex
->nSamplesPerSec
;
1664 if (-1==ioctl(audiofd
,SNDCTL_DSP_SPEED
,&speed
)) {
1665 perror("ioctl SNDCTL_DSP_SPEED");
1668 TRACE("(freq=%ld,channels=%d,bits=%d)\n",
1669 wfex
->nSamplesPerSec
,wfex
->nChannels
,wfex
->wBitsPerSample
1674 static void DSOUND_CheckEvent(IDirectSoundBufferImpl
*dsb
, int len
)
1678 LPDSBPOSITIONNOTIFY event
;
1680 if (dsb
->nrofnotifies
== 0)
1683 TRACE("(%p) buflen = %ld, playpos = %ld, len = %d\n",
1684 dsb
, dsb
->buflen
, dsb
->playpos
, len
);
1685 for (i
= 0; i
< dsb
->nrofnotifies
; i
++) {
1686 event
= dsb
->notifies
+ i
;
1687 offset
= event
->dwOffset
;
1688 TRACE("checking %d, position %ld, event = %d\n",
1689 i
, offset
, event
->hEventNotify
);
1690 /* DSBPN_OFFSETSTOP has to be the last element. So this is */
1691 /* OK. [Inside DirectX, p274] */
1693 /* This also means we can't sort the entries by offset, */
1694 /* because DSBPN_OFFSETSTOP == -1 */
1695 if (offset
== DSBPN_OFFSETSTOP
) {
1696 if (dsb
->playing
== 0) {
1697 SetEvent(event
->hEventNotify
);
1698 TRACE("signalled event %d (%d)\n", event
->hEventNotify
, i
);
1703 if ((dsb
->playpos
+ len
) >= dsb
->buflen
) {
1704 if ((offset
< ((dsb
->playpos
+ len
) % dsb
->buflen
)) ||
1705 (offset
>= dsb
->playpos
)) {
1706 TRACE("signalled event %d (%d)\n", event
->hEventNotify
, i
);
1707 SetEvent(event
->hEventNotify
);
1710 if ((offset
>= dsb
->playpos
) && (offset
< (dsb
->playpos
+ len
))) {
1711 TRACE("signalled event %d (%d)\n", event
->hEventNotify
, i
);
1712 SetEvent(event
->hEventNotify
);
1718 /* WAV format info can be found at: */
1720 /* http://www.cwi.nl/ftp/audio/AudioFormats.part2 */
1721 /* ftp://ftp.cwi.nl/pub/audio/RIFF-format */
1723 /* Import points to remember: */
1725 /* 8-bit WAV is unsigned */
1726 /* 16-bit WAV is signed */
1728 static inline INT16
cvtU8toS16(BYTE byte
)
1730 INT16 s
= (byte
- 128) << 8;
1735 static inline BYTE
cvtS16toU8(INT16 word
)
1737 BYTE b
= (word
+ 32768) >> 8;
1743 /* We should be able to optimize these two inline functions */
1744 /* so that we aren't doing 8->16->8 conversions when it is */
1745 /* not necessary. But this is still a WIP. Optimize later. */
1746 static inline void get_fields(const IDirectSoundBufferImpl
*dsb
, BYTE
*buf
, INT
*fl
, INT
*fr
)
1748 INT16
*bufs
= (INT16
*) buf
;
1750 /* TRACE(dsound, "(%p)", buf); */
1751 if ((dsb
->wfx
.wBitsPerSample
== 8) && dsb
->wfx
.nChannels
== 2) {
1752 *fl
= cvtU8toS16(*buf
);
1753 *fr
= cvtU8toS16(*(buf
+ 1));
1757 if ((dsb
->wfx
.wBitsPerSample
== 16) && dsb
->wfx
.nChannels
== 2) {
1763 if ((dsb
->wfx
.wBitsPerSample
== 8) && dsb
->wfx
.nChannels
== 1) {
1764 *fl
= cvtU8toS16(*buf
);
1769 if ((dsb
->wfx
.wBitsPerSample
== 16) && dsb
->wfx
.nChannels
== 1) {
1775 FIXME("get_fields found an unsupported configuration\n");
1779 static inline void set_fields(BYTE
*buf
, INT fl
, INT fr
)
1781 INT16
*bufs
= (INT16
*) buf
;
1783 if ((primarybuf
->wfx
.wBitsPerSample
== 8) && (primarybuf
->wfx
.nChannels
== 2)) {
1784 *buf
= cvtS16toU8(fl
);
1785 *(buf
+ 1) = cvtS16toU8(fr
);
1789 if ((primarybuf
->wfx
.wBitsPerSample
== 16) && (primarybuf
->wfx
.nChannels
== 2)) {
1795 if ((primarybuf
->wfx
.wBitsPerSample
== 8) && (primarybuf
->wfx
.nChannels
== 1)) {
1796 *buf
= cvtS16toU8((fl
+ fr
) >> 1);
1800 if ((primarybuf
->wfx
.wBitsPerSample
== 16) && (primarybuf
->wfx
.nChannels
== 1)) {
1801 *bufs
= (fl
+ fr
) >> 1;
1804 FIXME("set_fields found an unsupported configuration\n");
1808 /* Now with PerfectPitch (tm) technology */
1809 static INT
DSOUND_MixerNorm(IDirectSoundBufferImpl
*dsb
, BYTE
*buf
, INT len
)
1811 INT i
, size
, ipos
, ilen
, fieldL
, fieldR
;
1813 INT iAdvance
= dsb
->wfx
.nBlockAlign
;
1814 INT oAdvance
= primarybuf
->wfx
.nBlockAlign
;
1816 ibp
= dsb
->buffer
+ dsb
->playpos
;
1819 TRACE("(%p, %p, %p), playpos=%8.8lx\n", dsb
, ibp
, obp
, dsb
->playpos
);
1820 /* Check for the best case */
1821 if ((dsb
->freq
== primarybuf
->wfx
.nSamplesPerSec
) &&
1822 (dsb
->wfx
.wBitsPerSample
== primarybuf
->wfx
.wBitsPerSample
) &&
1823 (dsb
->wfx
.nChannels
== primarybuf
->wfx
.nChannels
)) {
1824 TRACE("(%p) Best case\n", dsb
);
1825 if ((ibp
+ len
) < (BYTE
*)(dsb
->buffer
+ dsb
->buflen
))
1826 memcpy(obp
, ibp
, len
);
1828 memcpy(obp
, ibp
, dsb
->buflen
- dsb
->playpos
);
1829 memcpy(obp
+ (dsb
->buflen
- dsb
->playpos
),
1831 len
- (dsb
->buflen
- dsb
->playpos
));
1836 /* Check for same sample rate */
1837 if (dsb
->freq
== primarybuf
->wfx
.nSamplesPerSec
) {
1838 TRACE("(%p) Same sample rate %ld = primary %ld\n", dsb
,
1839 dsb
->freq
, primarybuf
->wfx
.nSamplesPerSec
);
1841 for (i
= 0; i
< len
; i
+= oAdvance
) {
1842 get_fields(dsb
, ibp
, &fieldL
, &fieldR
);
1845 set_fields(obp
, fieldL
, fieldR
);
1847 if (ibp
>= (BYTE
*)(dsb
->buffer
+ dsb
->buflen
))
1848 ibp
= dsb
->buffer
; /* wrap */
1853 /* Mix in different sample rates */
1855 /* New PerfectPitch(tm) Technology (c) 1998 Rob Riggs */
1856 /* Patent Pending :-] */
1858 TRACE("(%p) Adjusting frequency: %ld -> %ld\n",
1859 dsb
, dsb
->freq
, primarybuf
->wfx
.nSamplesPerSec
);
1861 size
= len
/ oAdvance
;
1862 ilen
= ((size
* dsb
->freqAdjust
) >> DSOUND_FREQSHIFT
) * iAdvance
;
1863 for (i
= 0; i
< size
; i
++) {
1865 ipos
= (((i
* dsb
->freqAdjust
) >> DSOUND_FREQSHIFT
) * iAdvance
) + dsb
->playpos
;
1867 if (ipos
>= dsb
->buflen
)
1868 ipos
%= dsb
->buflen
; /* wrap */
1870 get_fields(dsb
, (dsb
->buffer
+ ipos
), &fieldL
, &fieldR
);
1871 set_fields(obp
, fieldL
, fieldR
);
1877 static void DSOUND_MixerVol(IDirectSoundBufferImpl
*dsb
, BYTE
*buf
, INT len
)
1879 INT i
, inc
= primarybuf
->wfx
.wBitsPerSample
>> 3;
1881 INT16
*bps
= (INT16
*) buf
;
1883 TRACE("(%p) left = %lx, right = %lx\n", dsb
,
1884 dsb
->lVolAdjust
, dsb
->rVolAdjust
);
1885 if ((!(dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLPAN
) || (dsb
->pan
== 0)) &&
1886 (!(dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLVOLUME
) || (dsb
->volume
== 0)) &&
1887 !(dsb
->dsbd
.dwFlags
& DSBCAPS_CTRL3D
))
1888 return; /* Nothing to do */
1890 /* If we end up with some bozo coder using panning or 3D sound */
1891 /* with a mono primary buffer, it could sound very weird using */
1892 /* this method. Oh well, tough patooties. */
1894 for (i
= 0; i
< len
; i
+= inc
) {
1900 /* 8-bit WAV is unsigned, but we need to operate */
1901 /* on signed data for this to work properly */
1903 val
= ((val
* (i
& inc
? dsb
->rVolAdjust
: dsb
->lVolAdjust
)) >> 15);
1908 /* 16-bit WAV is signed -- much better */
1910 val
= ((val
* ((i
& inc
) ? dsb
->rVolAdjust
: dsb
->lVolAdjust
)) >> 15);
1916 FIXME("MixerVol had a nasty error\n");
1922 static void DSOUND_Mixer3D(IDirectSoundBufferImpl
*dsb
, BYTE
*buf
, INT len
)
1925 DWORD buflen
, playpos
;
1927 buflen
= dsb
->ds3db
->buflen
;
1928 playpos
= (dsb
->playpos
* primarybuf
->wfx
.nBlockAlign
) / dsb
->wfx
.nBlockAlign
;
1929 ibp
= dsb
->ds3db
->buffer
+ playpos
;
1932 if (playpos
> buflen
) {
1933 FIXME("Major breakage");
1937 if (len
<= (playpos
+ buflen
))
1938 memcpy(obp
, ibp
, len
);
1940 memcpy(obp
, ibp
, buflen
- playpos
);
1941 memcpy(obp
+ (buflen
- playpos
),
1943 len
- (buflen
- playpos
));
1949 static void *tmp_buffer
;
1950 static size_t tmp_buffer_len
= 0;
1952 static void *DSOUND_tmpbuffer(size_t len
)
1954 if (len
>tmp_buffer_len
) {
1955 void *new_buffer
= realloc(tmp_buffer
, len
);
1957 tmp_buffer
= new_buffer
;
1958 tmp_buffer_len
= len
;
1965 static DWORD
DSOUND_MixInBuffer(IDirectSoundBufferImpl
*dsb
)
1967 INT i
, len
, ilen
, temp
, field
;
1968 INT advance
= primarybuf
->wfx
.wBitsPerSample
>> 3;
1969 BYTE
*buf
, *ibuf
, *obuf
;
1970 INT16
*ibufs
, *obufs
;
1972 len
= DSOUND_FRAGLEN
; /* The most we will use */
1973 if (!(dsb
->playflags
& DSBPLAY_LOOPING
)) {
1974 temp
= MulDiv(primarybuf
->wfx
.nAvgBytesPerSec
, dsb
->buflen
,
1975 dsb
->nAvgBytesPerSec
) -
1976 MulDiv(primarybuf
->wfx
.nAvgBytesPerSec
, dsb
->playpos
,
1977 dsb
->nAvgBytesPerSec
);
1978 len
= (len
> temp
) ? temp
: len
;
1980 len
&= ~3; /* 4 byte alignment */
1983 /* This should only happen if we aren't looping and temp < 4 */
1985 /* We skip the remainder, so check for possible events */
1986 DSOUND_CheckEvent(dsb
, dsb
->buflen
- dsb
->playpos
);
1991 /* Check for DSBPN_OFFSETSTOP */
1992 DSOUND_CheckEvent(dsb
, 0);
1996 /* Been seeing segfaults in malloc() for some reason... */
1997 TRACE("allocating buffer (size = %d)\n", len
);
1998 if ((buf
= ibuf
= (BYTE
*) DSOUND_tmpbuffer(len
)) == NULL
)
2001 TRACE("MixInBuffer (%p) len = %d\n", dsb
, len
);
2003 ilen
= DSOUND_MixerNorm(dsb
, ibuf
, len
);
2004 if ((dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLPAN
) ||
2005 (dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLVOLUME
))
2006 DSOUND_MixerVol(dsb
, ibuf
, len
);
2008 obuf
= primarybuf
->buffer
+ primarybuf
->playpos
;
2009 for (i
= 0; i
< len
; i
+= advance
) {
2010 obufs
= (INT16
*) obuf
;
2011 ibufs
= (INT16
*) ibuf
;
2012 if (primarybuf
->wfx
.wBitsPerSample
== 8) {
2013 /* 8-bit WAV is unsigned */
2014 field
= (*ibuf
- 128);
2015 field
+= (*obuf
- 128);
2016 field
= field
> 127 ? 127 : field
;
2017 field
= field
< -128 ? -128 : field
;
2018 *obuf
= field
+ 128;
2020 /* 16-bit WAV is signed */
2023 field
= field
> 32767 ? 32767 : field
;
2024 field
= field
< -32768 ? -32768 : field
;
2029 if (obuf
>= (BYTE
*)(primarybuf
->buffer
+ primarybuf
->buflen
))
2030 obuf
= primarybuf
->buffer
;
2034 if (dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLPOSITIONNOTIFY
)
2035 DSOUND_CheckEvent(dsb
, ilen
);
2037 dsb
->playpos
+= ilen
;
2038 dsb
->writepos
= dsb
->playpos
+ ilen
;
2040 if (dsb
->playpos
>= dsb
->buflen
) {
2041 if (!(dsb
->playflags
& DSBPLAY_LOOPING
)) {
2045 DSOUND_CheckEvent(dsb
, 0); /* For DSBPN_OFFSETSTOP */
2047 dsb
->playpos
%= dsb
->buflen
; /* wrap */
2050 if (dsb
->writepos
>= dsb
->buflen
)
2051 dsb
->writepos
%= dsb
->buflen
;
2056 static DWORD WINAPI
DSOUND_MixPrimary(void)
2058 INT i
, len
, maxlen
= 0;
2059 IDirectSoundBufferImpl
*dsb
;
2061 for (i
= dsound
->nrofbuffers
- 1; i
>= 0; i
--) {
2062 dsb
= dsound
->buffers
[i
];
2064 if (!dsb
|| !(dsb
->lpvtbl
))
2066 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER
)dsb
);
2067 if (dsb
->buflen
&& dsb
->playing
) {
2068 EnterCriticalSection(&(dsb
->lock
));
2069 len
= DSOUND_MixInBuffer(dsb
);
2070 maxlen
= len
> maxlen
? len
: maxlen
;
2071 LeaveCriticalSection(&(dsb
->lock
));
2073 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)dsb
);
2079 static int DSOUND_OpenAudio(void)
2083 if (primarybuf
== NULL
)
2084 return DSERR_OUTOFMEMORY
;
2086 while (audiofd
!= -1)
2088 audiofd
= open("/dev/audio",O_WRONLY
);
2090 /* Don't worry if sound is busy at the moment */
2092 perror("open /dev/audio");
2093 return audiofd
; /* -1 */
2096 /* We should probably do something here if SETFRAGMENT fails... */
2097 audioFragment
=0x0002000c;
2098 if (-1==ioctl(audiofd
,SNDCTL_DSP_SETFRAGMENT
,&audioFragment
))
2099 perror("ioctl SETFRAGMENT");
2102 DSOUND_setformat(&(primarybuf
->wfx
));
2107 static void DSOUND_CloseAudio(void)
2111 neutral
= primarybuf
->wfx
.wBitsPerSample
== 8 ? 128 : 0;
2112 audioOK
= 0; /* race condition */
2114 /* It's possible we've been called with audio closed */
2115 /* from SetFormat()... this is just to force a call */
2116 /* to OpenAudio() to reset the hardware properly */
2119 primarybuf
->playpos
= 0;
2120 primarybuf
->writepos
= DSOUND_FRAGLEN
;
2121 memset(primarybuf
->buffer
, neutral
, primarybuf
->buflen
);
2123 TRACE("Audio stopped\n");
2126 static int DSOUND_WriteAudio(char *buf
, int len
)
2128 int result
, left
= 0;
2130 while (left
< len
) {
2131 result
= write(audiofd
, buf
+ left
, len
- left
);
2143 static void DSOUND_OutputPrimary(int len
)
2145 int neutral
, flen1
, flen2
;
2146 char *frag1
, *frag2
;
2148 /* This is a bad place for this. We need to clear the */
2149 /* buffer with a neutral value, for unsigned 8-bit WAVE */
2150 /* that's 128, for signed 16-bit it's 0 */
2151 neutral
= primarybuf
->wfx
.wBitsPerSample
== 8 ? 128 : 0;
2154 EnterCriticalSection(&(primarybuf
->lock
));
2157 if ((audioOK
== 1) || (DSOUND_OpenAudio() == 0)) {
2158 if (primarybuf
->playpos
+ len
>= primarybuf
->buflen
) {
2159 frag1
= primarybuf
->buffer
+ primarybuf
->playpos
;
2160 flen1
= primarybuf
->buflen
- primarybuf
->playpos
;
2161 frag2
= primarybuf
->buffer
;
2162 flen2
= len
- (primarybuf
->buflen
- primarybuf
->playpos
);
2163 if (DSOUND_WriteAudio(frag1
, flen1
) != 0) {
2164 perror("DSOUND_WriteAudio");
2165 LeaveCriticalSection(&(primarybuf
->lock
));
2168 memset(frag1
, neutral
, flen1
);
2169 if (DSOUND_WriteAudio(frag2
, flen2
) != 0) {
2170 perror("DSOUND_WriteAudio");
2171 LeaveCriticalSection(&(primarybuf
->lock
));
2174 memset(frag2
, neutral
, flen2
);
2176 frag1
= primarybuf
->buffer
+ primarybuf
->playpos
;
2178 if (DSOUND_WriteAudio(frag1
, flen1
) != 0) {
2179 perror("DSOUND_WriteAudio");
2180 LeaveCriticalSection(&(primarybuf
->lock
));
2183 memset(frag1
, neutral
, flen1
);
2186 /* Can't play audio at the moment -- we need to sleep */
2187 /* to make up for the time we'd be blocked in write() */
2191 primarybuf
->playpos
+= len
;
2192 if (primarybuf
->playpos
>= primarybuf
->buflen
)
2193 primarybuf
->playpos
%= primarybuf
->buflen
;
2194 primarybuf
->writepos
= primarybuf
->playpos
+ DSOUND_FRAGLEN
;
2195 if (primarybuf
->writepos
>= primarybuf
->buflen
)
2196 primarybuf
->writepos
%= primarybuf
->buflen
;
2198 LeaveCriticalSection(&(primarybuf
->lock
));
2202 static DWORD WINAPI
DSOUND_thread(LPVOID arg
)
2206 TRACE("dsound is at pid %d\n",getpid());
2209 WARN("DSOUND thread giving up.\n");
2213 WARN("DSOUND father died? Giving up.\n");
2216 /* RACE: dsound could be deleted */
2217 IDirectSound_AddRef((LPDIRECTSOUND
)dsound
);
2218 if (primarybuf
== NULL
) {
2219 /* Should never happen */
2220 WARN("Lost the primary buffer!\n");
2221 IDirectSound_Release((LPDIRECTSOUND
)dsound
);
2226 EnterCriticalSection(&(primarybuf
->lock
));
2227 len
= DSOUND_MixPrimary();
2228 LeaveCriticalSection(&(primarybuf
->lock
));
2231 if (primarybuf
->playing
)
2232 len
= DSOUND_FRAGLEN
> len
? DSOUND_FRAGLEN
: len
;
2234 /* This does all the work */
2235 DSOUND_OutputPrimary(len
);
2237 /* no buffers playing -- close and wait */
2239 DSOUND_CloseAudio();
2242 IDirectSound_Release((LPDIRECTSOUND
)dsound
);
2247 #endif /* HAVE_OSS */
2249 HRESULT WINAPI
DirectSoundCreate(REFGUID lpGUID
,LPDIRECTSOUND
*ppDS
,IUnknown
*pUnkOuter
)
2251 IDirectSoundImpl
** ippDS
=(IDirectSoundImpl
**)ppDS
;
2253 TRACE("(%p,%p,%p)\n",lpGUID
,ippDS
,pUnkOuter
);
2255 TRACE("DirectSoundCreate (%p)\n", ippDS
);
2260 return DSERR_INVALIDPARAM
;
2263 IDirectSound_AddRef((LPDIRECTSOUND
)dsound
);
2268 /* Check that we actually have audio capabilities */
2269 /* If we do, whether it's busy or not, we continue */
2270 /* otherwise we return with DSERR_NODRIVER */
2272 audiofd
= open("/dev/audio",O_WRONLY
);
2273 if (audiofd
== -1) {
2274 if (errno
== ENODEV
) {
2275 MESSAGE("No sound hardware found.\n");
2276 return DSERR_NODRIVER
;
2277 } else if (errno
== EBUSY
) {
2278 MESSAGE("Sound device busy, will keep trying.\n");
2280 MESSAGE("Unexpected error (%d) while checking for sound support.\n",errno
);
2281 return DSERR_GENERIC
;
2288 *ippDS
= (IDirectSoundImpl
*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundImpl
));
2290 return DSERR_OUTOFMEMORY
;
2293 (*ippDS
)->lpvtbl
= &dsvt
;
2294 (*ippDS
)->buffers
= NULL
;
2295 (*ippDS
)->nrofbuffers
= 0;
2297 (*ippDS
)->wfx
.wFormatTag
= 1;
2298 (*ippDS
)->wfx
.nChannels
= 2;
2299 (*ippDS
)->wfx
.nSamplesPerSec
= 22050;
2300 (*ippDS
)->wfx
.nAvgBytesPerSec
= 44100;
2301 (*ippDS
)->wfx
.nBlockAlign
= 2;
2302 (*ippDS
)->wfx
.wBitsPerSample
= 8;
2309 if (primarybuf
== NULL
) {
2313 dsbd
.dwSize
= sizeof(DSBUFFERDESC
);
2314 dsbd
.dwFlags
= DSBCAPS_PRIMARYBUFFER
;
2315 dsbd
.dwBufferBytes
= 0;
2316 dsbd
.lpwfxFormat
= &(dsound
->wfx
);
2317 hr
= IDirectSound_CreateSoundBuffer(*ppDS
, &dsbd
, (LPDIRECTSOUNDBUFFER
*)&primarybuf
, NULL
);
2320 dsound
->primary
= primarybuf
;
2322 memset(primarybuf
->buffer
, 128, primarybuf
->buflen
);
2323 hnd
= CreateThread(NULL
,0,DSOUND_thread
,0,0,&xid
);
2327 MessageBoxA(0,"DirectSound needs the Open Sound System Driver, which has not been found by ./configure.","WINE DirectSound",MB_OK
|MB_ICONSTOP
);
2328 return DSERR_NODRIVER
;
2332 /*******************************************************************************
2333 * DirectSound ClassFactory
2337 /* IUnknown fields */
2338 ICOM_VTABLE(IClassFactory
)* lpvtbl
;
2340 } IClassFactoryImpl
;
2342 static HRESULT WINAPI
2343 DSCF_QueryInterface(LPCLASSFACTORY iface
,REFIID riid
,LPVOID
*ppobj
) {
2344 ICOM_THIS(IClassFactoryImpl
,iface
);
2348 WINE_StringFromCLSID(riid
,buf
);
2350 sprintf(buf
,"<guid-0x%04x>",LOWORD(riid
));
2351 FIXME("(%p)->(%s,%p),stub!\n",This
,buf
,ppobj
);
2352 return E_NOINTERFACE
;
2356 DSCF_AddRef(LPCLASSFACTORY iface
) {
2357 ICOM_THIS(IClassFactoryImpl
,iface
);
2358 return ++(This
->ref
);
2361 static ULONG WINAPI
DSCF_Release(LPCLASSFACTORY iface
) {
2362 ICOM_THIS(IClassFactoryImpl
,iface
);
2363 /* static class, won't be freed */
2364 return --(This
->ref
);
2367 static HRESULT WINAPI
DSCF_CreateInstance(
2368 LPCLASSFACTORY iface
,LPUNKNOWN pOuter
,REFIID riid
,LPVOID
*ppobj
2370 ICOM_THIS(IClassFactoryImpl
,iface
);
2373 WINE_StringFromCLSID(riid
,buf
);
2374 TRACE("(%p)->(%p,%s,%p)\n",This
,pOuter
,buf
,ppobj
);
2375 if (!memcmp(riid
,&IID_IDirectSound
,sizeof(IID_IDirectSound
))) {
2376 /* FIXME: reuse already created dsound if present? */
2377 return DirectSoundCreate(riid
,(LPDIRECTSOUND
*)ppobj
,pOuter
);
2379 return E_NOINTERFACE
;
2382 static HRESULT WINAPI
DSCF_LockServer(LPCLASSFACTORY iface
,BOOL dolock
) {
2383 ICOM_THIS(IClassFactoryImpl
,iface
);
2384 FIXME("(%p)->(%d),stub!\n",This
,dolock
);
2388 static ICOM_VTABLE(IClassFactory
) DSCF_Vtbl
= {
2389 DSCF_QueryInterface
,
2392 DSCF_CreateInstance
,
2395 static IClassFactoryImpl DSOUND_CF
= {&DSCF_Vtbl
, 1 };
2397 /*******************************************************************************
2398 * DllGetClassObject [DSOUND.4]
2399 * Retrieves class object from a DLL object
2402 * Docs say returns STDAPI
2405 * rclsid [I] CLSID for the class object
2406 * riid [I] Reference to identifier of interface for class object
2407 * ppv [O] Address of variable to receive interface pointer for riid
2411 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
2414 DWORD WINAPI
DSOUND_DllGetClassObject(REFCLSID rclsid
,REFIID riid
,LPVOID
*ppv
)
2416 char buf
[80],xbuf
[80];
2419 WINE_StringFromCLSID(rclsid
,xbuf
);
2421 sprintf(xbuf
,"<guid-0x%04x>",LOWORD(rclsid
));
2423 WINE_StringFromCLSID(riid
,buf
);
2425 sprintf(buf
,"<guid-0x%04x>",LOWORD(riid
));
2426 WINE_StringFromCLSID(riid
,xbuf
);
2427 TRACE("(%p,%p,%p)\n", xbuf
, buf
, ppv
);
2428 if (!memcmp(riid
,&IID_IClassFactory
,sizeof(IID_IClassFactory
))) {
2429 *ppv
= (LPVOID
)&DSOUND_CF
;
2430 IClassFactory_AddRef((IClassFactory
*)*ppv
);
2433 FIXME("(%p,%p,%p): no interface found.\n", xbuf
, buf
, ppv
);
2434 return E_NOINTERFACE
;
2438 /*******************************************************************************
2439 * DllCanUnloadNow [DSOUND.3] Determines whether the DLL is in use.
2445 DWORD WINAPI
DSOUND_DllCanUnloadNow(void)
2447 FIXME("(void): stub\n");