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"
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(dsound
, "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(dsound
,"(%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
)
280 FIXME(dsound
,"stub\n");
284 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetConeAngles(
285 LPDIRECTSOUND3DBUFFER iface
,
286 LPDWORD lpdwInsideConeAngle
,
287 LPDWORD lpdwOutsideConeAngle
)
289 FIXME(dsound
,"stub\n");
293 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetConeOrientation(
294 LPDIRECTSOUND3DBUFFER iface
,
295 LPD3DVECTOR lpvConeOrientation
)
297 FIXME(dsound
,"stub\n");
301 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetConeOutsideVolume(
302 LPDIRECTSOUND3DBUFFER iface
,
303 LPLONG lplConeOutsideVolume
)
305 FIXME(dsound
,"stub\n");
309 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetMaxDistance(
310 LPDIRECTSOUND3DBUFFER iface
,
311 LPD3DVALUE lpfMaxDistance
)
313 FIXME(dsound
,"stub\n");
317 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetMinDistance(
318 LPDIRECTSOUND3DBUFFER iface
,
319 LPD3DVALUE lpfMinDistance
)
321 FIXME(dsound
,"stub\n");
325 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetMode(
326 LPDIRECTSOUND3DBUFFER iface
,
329 FIXME(dsound
,"stub\n");
333 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetPosition(
334 LPDIRECTSOUND3DBUFFER iface
,
335 LPD3DVECTOR lpvPosition
)
337 FIXME(dsound
,"stub\n");
341 static HRESULT WINAPI
IDirectSound3DBufferImpl_GetVelocity(
342 LPDIRECTSOUND3DBUFFER iface
,
343 LPD3DVECTOR lpvVelocity
)
345 FIXME(dsound
,"stub\n");
349 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetAllParameters(
350 LPDIRECTSOUND3DBUFFER iface
,
351 LPCDS3DBUFFER lpcDs3dBuffer
,
354 FIXME(dsound
,"stub\n");
358 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetConeAngles(
359 LPDIRECTSOUND3DBUFFER iface
,
360 DWORD dwInsideConeAngle
,
361 DWORD dwOutsideConeAngle
,
364 FIXME(dsound
,"stub\n");
368 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetConeOrientation(
369 LPDIRECTSOUND3DBUFFER iface
,
370 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
373 FIXME(dsound
,"stub\n");
377 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetConeOutsideVolume(
378 LPDIRECTSOUND3DBUFFER iface
,
379 LONG lConeOutsideVolume
,
382 FIXME(dsound
,"stub\n");
386 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetMaxDistance(
387 LPDIRECTSOUND3DBUFFER iface
,
388 D3DVALUE fMaxDistance
,
391 FIXME(dsound
,"stub\n");
395 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetMinDistance(
396 LPDIRECTSOUND3DBUFFER iface
,
397 D3DVALUE fMinDistance
,
400 FIXME(dsound
,"stub\n");
404 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetMode(
405 LPDIRECTSOUND3DBUFFER iface
,
409 ICOM_THIS(IDirectSound3DBufferImpl
,iface
);
410 TRACE(dsound
, "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
,
420 FIXME(dsound
,"stub\n");
424 static HRESULT WINAPI
IDirectSound3DBufferImpl_SetVelocity(
425 LPDIRECTSOUND3DBUFFER iface
,
426 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
429 FIXME(dsound
,"stub\n");
433 ICOM_VTABLE(IDirectSound3DBuffer
) ds3dbvt
= {
434 /* IUnknown methods */
435 IDirectSound3DBufferImpl_QueryInterface
,
436 IDirectSound3DBufferImpl_AddRef
,
437 IDirectSound3DBufferImpl_Release
,
438 /* IDirectSound3DBuffer methods */
439 IDirectSound3DBufferImpl_GetAllParameters
,
440 IDirectSound3DBufferImpl_GetConeAngles
,
441 IDirectSound3DBufferImpl_GetConeOrientation
,
442 IDirectSound3DBufferImpl_GetConeOutsideVolume
,
443 IDirectSound3DBufferImpl_GetMaxDistance
,
444 IDirectSound3DBufferImpl_GetMinDistance
,
445 IDirectSound3DBufferImpl_GetMode
,
446 IDirectSound3DBufferImpl_GetPosition
,
447 IDirectSound3DBufferImpl_GetVelocity
,
448 IDirectSound3DBufferImpl_SetAllParameters
,
449 IDirectSound3DBufferImpl_SetConeAngles
,
450 IDirectSound3DBufferImpl_SetConeOrientation
,
451 IDirectSound3DBufferImpl_SetConeOutsideVolume
,
452 IDirectSound3DBufferImpl_SetMaxDistance
,
453 IDirectSound3DBufferImpl_SetMinDistance
,
454 IDirectSound3DBufferImpl_SetMode
,
455 IDirectSound3DBufferImpl_SetPosition
,
456 IDirectSound3DBufferImpl_SetVelocity
,
460 static int DSOUND_Create3DBuffer(IDirectSoundBufferImpl
* dsb
)
462 DWORD i
, temp
, iSize
, oSize
, offset
;
463 LPBYTE bIbuf
, bObuf
, bTbuf
= NULL
;
464 LPWORD wIbuf
, wObuf
, wTbuf
= NULL
;
466 /* Inside DirectX says it's stupid but allowed */
467 if (dsb
->wfx
.nChannels
== 2) {
468 /* Convert to mono */
469 if (dsb
->wfx
.wBitsPerSample
== 16) {
470 iSize
= dsb
->buflen
/ 4;
471 wTbuf
= malloc(dsb
->buflen
/ 2);
473 return DSERR_OUTOFMEMORY
;
474 for (i
= 0; i
< iSize
; i
++)
475 wTbuf
[i
] = (dsb
->buffer
[i
] + dsb
->buffer
[(i
* 2) + 1]) / 2;
478 iSize
= dsb
->buflen
/ 2;
479 bTbuf
= malloc(dsb
->buflen
/ 2);
481 return DSERR_OUTOFMEMORY
;
482 for (i
= 0; i
< iSize
; i
++)
483 bTbuf
[i
] = (dsb
->buffer
[i
] + dsb
->buffer
[(i
* 2) + 1]) / 2;
487 if (dsb
->wfx
.wBitsPerSample
== 16) {
488 iSize
= dsb
->buflen
/ 2;
489 wIbuf
= (LPWORD
) dsb
->buffer
;
491 bIbuf
= (LPBYTE
) dsb
->buffer
;
496 if (primarybuf
->wfx
.wBitsPerSample
== 16) {
497 wObuf
= (LPWORD
) dsb
->ds3db
->buffer
;
498 oSize
= dsb
->ds3db
->buflen
/ 2;
500 bObuf
= (LPBYTE
) dsb
->ds3db
->buffer
;
501 oSize
= dsb
->ds3db
->buflen
;
504 offset
= primarybuf
->wfx
.nSamplesPerSec
/ 100; /* 10ms */
505 if (primarybuf
->wfx
.wBitsPerSample
== 16 && dsb
->wfx
.wBitsPerSample
== 16)
506 for (i
= 0; i
< iSize
; i
++) {
509 temp
+= wIbuf
[i
- offset
] >> 9;
511 temp
+= wIbuf
[i
+ iSize
- offset
] >> 9;
513 wObuf
[(i
* 2) + 1] = temp
;
515 else if (primarybuf
->wfx
.wBitsPerSample
== 8 && dsb
->wfx
.wBitsPerSample
== 8)
516 for (i
= 0; i
< iSize
; i
++) {
519 temp
+= bIbuf
[i
- offset
] >> 5;
521 temp
+= bIbuf
[i
+ iSize
- offset
] >> 5;
523 bObuf
[(i
* 2) + 1] = temp
;
534 /*******************************************************************************
535 * IDirectSound3DListener
538 /* IUnknown methods */
539 static HRESULT WINAPI
IDirectSound3DListenerImpl_QueryInterface(
540 LPDIRECTSOUND3DLISTENER iface
, REFIID riid
, LPVOID
*ppobj
)
542 ICOM_THIS(IDirectSound3DListenerImpl
,iface
);
545 WINE_StringFromCLSID(riid
,xbuf
);
546 TRACE(dsound
,"(%p,%s,%p)\n",This
,xbuf
,ppobj
);
550 static ULONG WINAPI
IDirectSound3DListenerImpl_AddRef(LPDIRECTSOUND3DLISTENER iface
)
552 ICOM_THIS(IDirectSound3DListenerImpl
,iface
);
557 static ULONG WINAPI
IDirectSound3DListenerImpl_Release(LPDIRECTSOUND3DLISTENER iface
)
559 ICOM_THIS(IDirectSound3DListenerImpl
,iface
);
564 /* IDirectSound3DListener methods */
565 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetAllParameter(
566 LPDIRECTSOUND3DLISTENER iface
,
567 LPDS3DLISTENER lpDS3DL
)
569 FIXME(dsound
,"stub\n");
573 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetDistanceFactor(
574 LPDIRECTSOUND3DLISTENER iface
,
575 LPD3DVALUE lpfDistanceFactor
)
577 FIXME(dsound
,"stub\n");
581 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetDopplerFactor(
582 LPDIRECTSOUND3DLISTENER iface
,
583 LPD3DVALUE lpfDopplerFactor
)
585 FIXME(dsound
,"stub\n");
589 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetOrientation(
590 LPDIRECTSOUND3DLISTENER iface
,
591 LPD3DVECTOR lpvOrientFront
,
592 LPD3DVECTOR lpvOrientTop
)
594 FIXME(dsound
,"stub\n");
598 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetPosition(
599 LPDIRECTSOUND3DLISTENER iface
,
600 LPD3DVECTOR lpvPosition
)
602 FIXME(dsound
,"stub\n");
606 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetRolloffFactor(
607 LPDIRECTSOUND3DLISTENER iface
,
608 LPD3DVALUE lpfRolloffFactor
)
610 FIXME(dsound
,"stub\n");
614 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetVelocity(
615 LPDIRECTSOUND3DLISTENER iface
,
616 LPD3DVECTOR lpvVelocity
)
618 FIXME(dsound
,"stub\n");
622 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetAllParameters(
623 LPDIRECTSOUND3DLISTENER iface
,
624 LPCDS3DLISTENER lpcDS3DL
,
627 FIXME(dsound
,"stub\n");
631 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetDistanceFactor(
632 LPDIRECTSOUND3DLISTENER iface
,
633 D3DVALUE fDistanceFactor
,
636 FIXME(dsound
,"stub\n");
640 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetDopplerFactor(
641 LPDIRECTSOUND3DLISTENER iface
,
642 D3DVALUE fDopplerFactor
,
645 FIXME(dsound
,"stub\n");
649 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetOrientation(
650 LPDIRECTSOUND3DLISTENER iface
,
651 D3DVALUE xFront
, D3DVALUE yFront
, D3DVALUE zFront
,
652 D3DVALUE xTop
, D3DVALUE yTop
, D3DVALUE zTop
,
655 FIXME(dsound
,"stub\n");
659 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetPosition(
660 LPDIRECTSOUND3DLISTENER iface
,
661 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
664 FIXME(dsound
,"stub\n");
668 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetRolloffFactor(
669 LPDIRECTSOUND3DLISTENER iface
,
670 D3DVALUE fRolloffFactor
,
673 FIXME(dsound
,"stub\n");
677 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetVelocity(
678 LPDIRECTSOUND3DLISTENER iface
,
679 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
682 FIXME(dsound
,"stub\n");
686 static HRESULT WINAPI
IDirectSound3DListenerImpl_CommitDeferredSettings(
687 LPDIRECTSOUND3DLISTENER iface
)
690 FIXME(dsound
,"stub\n");
694 ICOM_VTABLE(IDirectSound3DListener
) ds3dlvt
= {
695 /* IUnknown methods */
696 IDirectSound3DListenerImpl_QueryInterface
,
697 IDirectSound3DListenerImpl_AddRef
,
698 IDirectSound3DListenerImpl_Release
,
699 /* IDirectSound3DListener methods */
700 IDirectSound3DListenerImpl_GetAllParameter
,
701 IDirectSound3DListenerImpl_GetDistanceFactor
,
702 IDirectSound3DListenerImpl_GetDopplerFactor
,
703 IDirectSound3DListenerImpl_GetOrientation
,
704 IDirectSound3DListenerImpl_GetPosition
,
705 IDirectSound3DListenerImpl_GetRolloffFactor
,
706 IDirectSound3DListenerImpl_GetVelocity
,
707 IDirectSound3DListenerImpl_SetAllParameters
,
708 IDirectSound3DListenerImpl_SetDistanceFactor
,
709 IDirectSound3DListenerImpl_SetDopplerFactor
,
710 IDirectSound3DListenerImpl_SetOrientation
,
711 IDirectSound3DListenerImpl_SetPosition
,
712 IDirectSound3DListenerImpl_SetRolloffFactor
,
713 IDirectSound3DListenerImpl_SetVelocity
,
714 IDirectSound3DListenerImpl_CommitDeferredSettings
,
717 /*******************************************************************************
720 static HRESULT WINAPI
IDirectSoundNotifyImpl_QueryInterface(
721 LPDIRECTSOUNDNOTIFY iface
,REFIID riid
,LPVOID
*ppobj
723 ICOM_THIS(IDirectSoundNotifyImpl
,iface
);
726 WINE_StringFromCLSID(riid
,xbuf
);
727 TRACE(dsound
,"(%p,%s,%p)\n",This
,xbuf
,ppobj
);
731 static ULONG WINAPI
IDirectSoundNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface
) {
732 ICOM_THIS(IDirectSoundNotifyImpl
,iface
);
733 return ++(This
->ref
);
736 static ULONG WINAPI
IDirectSoundNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface
) {
737 ICOM_THIS(IDirectSoundNotifyImpl
,iface
);
740 IDirectSoundNotify_Release((LPDIRECTSOUNDBUFFER
)This
->dsb
);
741 HeapFree(GetProcessHeap(),0,This
);
747 static HRESULT WINAPI
IDirectSoundNotifyImpl_SetNotificationPositions(
748 LPDIRECTSOUNDNOTIFY iface
,DWORD howmuch
,LPCDSBPOSITIONNOTIFY notify
750 ICOM_THIS(IDirectSoundNotifyImpl
,iface
);
753 if (TRACE_ON(dsound
)) {
754 TRACE(dsound
,"(%p,0x%08lx,%p)\n",This
,howmuch
,notify
);
755 for (i
=0;i
<howmuch
;i
++)
756 TRACE(dsound
,"notify at %ld to 0x%08lx\n",
757 notify
[i
].dwOffset
,(DWORD
)notify
[i
].hEventNotify
);
759 This
->dsb
->notifies
= HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,This
->dsb
->notifies
,(This
->dsb
->nrofnotifies
+howmuch
)*sizeof(DSBPOSITIONNOTIFY
));
760 memcpy( This
->dsb
->notifies
+This
->dsb
->nrofnotifies
,
762 howmuch
*sizeof(DSBPOSITIONNOTIFY
)
764 This
->dsb
->nrofnotifies
+=howmuch
;
769 ICOM_VTABLE(IDirectSoundNotify
) dsnvt
= {
770 IDirectSoundNotifyImpl_QueryInterface
,
771 IDirectSoundNotifyImpl_AddRef
,
772 IDirectSoundNotifyImpl_Release
,
773 IDirectSoundNotifyImpl_SetNotificationPositions
,
776 /*******************************************************************************
780 /* This sets this format for the <em>Primary Buffer Only</em> */
781 /* See file:///cdrom/sdk52/docs/worddoc/dsound.doc page 120 */
782 static HRESULT WINAPI
IDirectSoundBufferImpl_SetFormat(
783 LPDIRECTSOUNDBUFFER iface
,LPWAVEFORMATEX wfex
785 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
786 IDirectSoundBufferImpl
** dsb
;
789 /* Let's be pedantic! */
790 if ((wfex
== NULL
) ||
791 (wfex
->wFormatTag
!= WAVE_FORMAT_PCM
) ||
792 (wfex
->nChannels
< 1) || (wfex
->nChannels
> 2) ||
793 (wfex
->nSamplesPerSec
< 1) ||
794 (wfex
->nBlockAlign
< 1) || (wfex
->nChannels
> 4) ||
795 ((wfex
->wBitsPerSample
!= 8) && (wfex
->wBitsPerSample
!= 16))) {
796 TRACE(dsound
, "failed pedantic check!\n");
797 return DSERR_INVALIDPARAM
;
801 EnterCriticalSection(&(primarybuf
->lock
));
803 if (primarybuf
->wfx
.nSamplesPerSec
!= wfex
->nSamplesPerSec
) {
804 dsb
= dsound
->buffers
;
805 for (i
= 0; i
< dsound
->nrofbuffers
; i
++, dsb
++) {
807 EnterCriticalSection(&((*dsb
)->lock
));
809 (*dsb
)->freqAdjust
= ((*dsb
)->freq
<< DSOUND_FREQSHIFT
) /
810 wfex
->nSamplesPerSec
;
812 LeaveCriticalSection(&((*dsb
)->lock
));
817 memcpy(&(primarybuf
->wfx
), wfex
, sizeof(primarybuf
->wfx
));
819 TRACE(dsound
,"(formattag=0x%04x,chans=%d,samplerate=%ld"
820 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
821 wfex
->wFormatTag
, wfex
->nChannels
, wfex
->nSamplesPerSec
,
822 wfex
->nAvgBytesPerSec
, wfex
->nBlockAlign
,
823 wfex
->wBitsPerSample
, wfex
->cbSize
);
825 primarybuf
->wfx
.nAvgBytesPerSec
=
826 This
->wfx
.nSamplesPerSec
* This
->wfx
.nBlockAlign
;
830 LeaveCriticalSection(&(primarybuf
->lock
));
836 static HRESULT WINAPI
IDirectSoundBufferImpl_SetVolume(
837 LPDIRECTSOUNDBUFFER iface
,LONG vol
839 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
842 TRACE(dsound
,"(%p,%ld)\n",This
,vol
);
844 /* I'm not sure if we need this for primary buffer */
845 if (!(This
->dsbd
.dwFlags
& DSBCAPS_CTRLVOLUME
))
846 return DSERR_CONTROLUNAVAIL
;
848 if ((vol
> DSBVOLUME_MAX
) || (vol
< DSBVOLUME_MIN
))
849 return DSERR_INVALIDPARAM
;
851 /* This needs to adjust the soundcard volume when */
852 /* called for the primary buffer */
853 if (This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
854 FIXME(dsound
, "Volume control of primary unimplemented.\n");
860 EnterCriticalSection(&(This
->lock
));
864 temp
= (double) (This
->volume
- (This
->pan
> 0 ? This
->pan
: 0));
865 This
->lVolAdjust
= (ULONG
) (pow(2.0, temp
/ 600.0) * 32768.0);
866 temp
= (double) (This
->volume
+ (This
->pan
< 0 ? This
->pan
: 0));
867 This
->rVolAdjust
= (ULONG
) (pow(2.0, temp
/ 600.0) * 32768.0);
869 LeaveCriticalSection(&(This
->lock
));
872 TRACE(dsound
, "left = %lx, right = %lx\n", This
->lVolAdjust
, This
->rVolAdjust
);
877 static HRESULT WINAPI
IDirectSoundBufferImpl_GetVolume(
878 LPDIRECTSOUNDBUFFER iface
,LPLONG vol
880 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
881 TRACE(dsound
,"(%p,%p)\n",This
,vol
);
884 return DSERR_INVALIDPARAM
;
890 static HRESULT WINAPI
IDirectSoundBufferImpl_SetFrequency(
891 LPDIRECTSOUNDBUFFER iface
,DWORD freq
893 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
894 TRACE(dsound
,"(%p,%ld)\n",This
,freq
);
896 /* You cannot set the frequency of the primary buffer */
897 if (!(This
->dsbd
.dwFlags
& DSBCAPS_CTRLFREQUENCY
) ||
898 (This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
))
899 return DSERR_CONTROLUNAVAIL
;
901 if ((freq
< DSBFREQUENCY_MIN
) || (freq
> DSBFREQUENCY_MAX
))
902 return DSERR_INVALIDPARAM
;
905 EnterCriticalSection(&(This
->lock
));
908 This
->freqAdjust
= (freq
<< DSOUND_FREQSHIFT
) / primarybuf
->wfx
.nSamplesPerSec
;
909 This
->nAvgBytesPerSec
= freq
* This
->wfx
.nBlockAlign
;
911 LeaveCriticalSection(&(This
->lock
));
917 static HRESULT WINAPI
IDirectSoundBufferImpl_Play(
918 LPDIRECTSOUNDBUFFER iface
,DWORD reserved1
,DWORD reserved2
,DWORD flags
920 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
921 TRACE(dsound
,"(%p,%08lx,%08lx,%08lx)\n",
922 This
,reserved1
,reserved2
,flags
924 This
->playflags
= flags
;
929 static HRESULT WINAPI
IDirectSoundBufferImpl_Stop(LPDIRECTSOUNDBUFFER iface
)
931 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
932 TRACE(dsound
,"(%p)\n",This
);
935 EnterCriticalSection(&(This
->lock
));
938 DSOUND_CheckEvent(This
, 0);
940 LeaveCriticalSection(&(This
->lock
));
946 static DWORD WINAPI
IDirectSoundBufferImpl_AddRef(LPDIRECTSOUNDBUFFER iface
) {
947 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
948 /* TRACE(dsound,"(%p) ref was %ld\n",This, This->ref); */
950 return ++(This
->ref
);
952 static DWORD WINAPI
IDirectSoundBufferImpl_Release(LPDIRECTSOUNDBUFFER iface
) {
953 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
956 /* TRACE(dsound,"(%p) ref was %ld\n",This, This->ref); */
961 for (i
=0;i
<This
->dsound
->nrofbuffers
;i
++)
962 if (This
->dsound
->buffers
[i
] == This
)
964 if (i
< This
->dsound
->nrofbuffers
) {
965 /* Put the last buffer of the list in the (now empty) position */
966 This
->dsound
->buffers
[i
] = This
->dsound
->buffers
[This
->dsound
->nrofbuffers
- 1];
967 This
->dsound
->buffers
= HeapReAlloc(GetProcessHeap(),0,This
->dsound
->buffers
,sizeof(LPDIRECTSOUNDBUFFER
)*This
->dsound
->nrofbuffers
);
968 This
->dsound
->nrofbuffers
--;
969 IDirectSound_Release((LPDIRECTSOUND
)This
->dsound
);
972 DeleteCriticalSection(&(This
->lock
));
974 if (This
->ds3db
&& This
->ds3db
->lpvtbl
)
975 IDirectSound3DBuffer_Release((LPDIRECTSOUND3DBUFFER
)This
->ds3db
);
978 /* this is a duplicate buffer */
979 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)This
->parent
);
981 /* this is a toplevel buffer */
982 HeapFree(GetProcessHeap(),0,This
->buffer
);
984 HeapFree(GetProcessHeap(),0,This
);
986 if (This
== primarybuf
)
992 static HRESULT WINAPI
IDirectSoundBufferImpl_GetCurrentPosition(
993 LPDIRECTSOUNDBUFFER iface
,LPDWORD playpos
,LPDWORD writepos
995 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
996 TRACE(dsound
,"(%p,%p,%p)\n",This
,playpos
,writepos
);
997 if (playpos
) *playpos
= This
->playpos
;
998 if (writepos
) *writepos
= This
->writepos
;
999 TRACE(dsound
, "playpos = %ld, writepos = %ld\n", *playpos
, *writepos
);
1003 static HRESULT WINAPI
IDirectSoundBufferImpl_GetStatus(
1004 LPDIRECTSOUNDBUFFER iface
,LPDWORD status
1006 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1007 TRACE(dsound
,"(%p,%p)\n",This
,status
);
1010 return DSERR_INVALIDPARAM
;
1014 *status
|= DSBSTATUS_PLAYING
;
1015 if (This
->playflags
& DSBPLAY_LOOPING
)
1016 *status
|= DSBSTATUS_LOOPING
;
1022 static HRESULT WINAPI
IDirectSoundBufferImpl_GetFormat(
1023 LPDIRECTSOUNDBUFFER iface
,LPWAVEFORMATEX lpwf
,DWORD wfsize
,LPDWORD wfwritten
1025 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1026 TRACE(dsound
,"(%p,%p,%ld,%p)\n",This
,lpwf
,wfsize
,wfwritten
);
1028 if (wfsize
>sizeof(This
->wfx
))
1029 wfsize
= sizeof(This
->wfx
);
1030 if (lpwf
) { /* NULL is valid */
1031 memcpy(lpwf
,&(This
->wfx
),wfsize
);
1033 *wfwritten
= wfsize
;
1036 *wfwritten
= sizeof(This
->wfx
);
1038 return DSERR_INVALIDPARAM
;
1043 static HRESULT WINAPI
IDirectSoundBufferImpl_Lock(
1044 LPDIRECTSOUNDBUFFER iface
,DWORD writecursor
,DWORD writebytes
,LPVOID lplpaudioptr1
,LPDWORD audiobytes1
,LPVOID lplpaudioptr2
,LPDWORD audiobytes2
,DWORD flags
1046 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1048 TRACE(dsound
,"(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx)\n",
1058 if (flags
& DSBLOCK_FROMWRITECURSOR
)
1059 writecursor
+= This
->writepos
;
1060 if (flags
& DSBLOCK_ENTIREBUFFER
)
1061 writebytes
= This
->buflen
;
1062 if (writebytes
> This
->buflen
)
1063 writebytes
= This
->buflen
;
1065 assert(audiobytes1
!=audiobytes2
);
1066 assert(lplpaudioptr1
!=lplpaudioptr2
);
1067 if (writecursor
+writebytes
<= This
->buflen
) {
1068 *(LPBYTE
*)lplpaudioptr1
= This
->buffer
+writecursor
;
1069 *audiobytes1
= writebytes
;
1071 *(LPBYTE
*)lplpaudioptr2
= NULL
;
1074 TRACE(dsound
,"->%ld.0\n",writebytes
);
1076 *(LPBYTE
*)lplpaudioptr1
= This
->buffer
+writecursor
;
1077 *audiobytes1
= This
->buflen
-writecursor
;
1079 *(LPBYTE
*)lplpaudioptr2
= This
->buffer
;
1081 *audiobytes2
= writebytes
-(This
->buflen
-writecursor
);
1082 TRACE(dsound
,"->%ld.%ld\n",*audiobytes1
,audiobytes2
?*audiobytes2
:0);
1084 /* No. See file:///cdrom/sdk52/docs/worddoc/dsound.doc page 21 */
1085 /* This->writepos=(writecursor+writebytes)%This->buflen; */
1089 static HRESULT WINAPI
IDirectSoundBufferImpl_SetCurrentPosition(
1090 LPDIRECTSOUNDBUFFER iface
,DWORD newpos
1092 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1093 TRACE(dsound
,"(%p,%ld)\n",This
,newpos
);
1096 EnterCriticalSection(&(This
->lock
));
1098 This
->playpos
= newpos
;
1100 LeaveCriticalSection(&(This
->lock
));
1106 static HRESULT WINAPI
IDirectSoundBufferImpl_SetPan(
1107 LPDIRECTSOUNDBUFFER iface
,LONG pan
1109 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1112 TRACE(dsound
,"(%p,%ld)\n",This
,pan
);
1114 if ((pan
> DSBPAN_RIGHT
) || (pan
< DSBPAN_LEFT
))
1115 return DSERR_INVALIDPARAM
;
1117 /* You cannot set the pan of the primary buffer */
1118 /* and you cannot use both pan and 3D controls */
1119 if (!(This
->dsbd
.dwFlags
& DSBCAPS_CTRLPAN
) ||
1120 (This
->dsbd
.dwFlags
& DSBCAPS_CTRL3D
) ||
1121 (This
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
))
1122 return DSERR_CONTROLUNAVAIL
;
1125 EnterCriticalSection(&(This
->lock
));
1129 temp
= (double) (This
->volume
- (This
->pan
> 0 ? This
->pan
: 0));
1130 This
->lVolAdjust
= (ULONG
) (pow(2.0, temp
/ 600.0) * 32768.0);
1131 temp
= (double) (This
->volume
+ (This
->pan
< 0 ? This
->pan
: 0));
1132 This
->rVolAdjust
= (ULONG
) (pow(2.0, temp
/ 600.0) * 32768.0);
1134 LeaveCriticalSection(&(This
->lock
));
1140 static HRESULT WINAPI
IDirectSoundBufferImpl_GetPan(
1141 LPDIRECTSOUNDBUFFER iface
,LPLONG pan
1143 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1144 TRACE(dsound
,"(%p,%p)\n",This
,pan
);
1147 return DSERR_INVALIDPARAM
;
1154 static HRESULT WINAPI
IDirectSoundBufferImpl_Unlock(
1155 LPDIRECTSOUNDBUFFER iface
,LPVOID p1
,DWORD x1
,LPVOID p2
,DWORD x2
1157 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1158 TRACE(dsound
,"(%p,%p,%ld,%p,%ld):stub\n", This
,p1
,x1
,p2
,x2
);
1160 /* There is really nothing to do here. Should someone */
1161 /* choose to implement static buffers in hardware (by */
1162 /* using a wave table synth, for example) this is where */
1163 /* you'd want to do the loading. For software buffers, */
1164 /* which is what we currently use, we need do nothing. */
1167 /* It's also the place to pre-process 3D buffers... */
1169 /* This is highly experimental and liable to break things */
1170 if (This
->dsbd
.dwFlags
& DSBCAPS_CTRL3D
)
1171 DSOUND_Create3DBuffer(This
);
1177 static HRESULT WINAPI
IDirectSoundBufferImpl_GetFrequency(
1178 LPDIRECTSOUNDBUFFER iface
,LPDWORD freq
1180 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1181 TRACE(dsound
,"(%p,%p)\n",This
,freq
);
1184 return DSERR_INVALIDPARAM
;
1191 static HRESULT WINAPI
IDirectSoundBufferImpl_Initialize(
1192 LPDIRECTSOUNDBUFFER iface
,LPDIRECTSOUND dsound
,LPDSBUFFERDESC dbsd
1194 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1195 FIXME(dsound
,"(%p,%p,%p):stub\n",This
,dsound
,dbsd
);
1196 printf("Re-Init!!!\n");
1197 return DSERR_ALREADYINITIALIZED
;
1200 static HRESULT WINAPI
IDirectSoundBufferImpl_GetCaps(
1201 LPDIRECTSOUNDBUFFER iface
,LPDSBCAPS caps
1203 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1204 TRACE(dsound
,"(%p)->(%p)\n",This
,caps
);
1207 return DSERR_INVALIDPARAM
;
1209 /* I think we should check this value, not set it. See */
1210 /* Inside DirectX, p215. That should apply here, too. */
1211 caps
->dwSize
= sizeof(*caps
);
1213 caps
->dwFlags
= This
->dsbd
.dwFlags
| DSBCAPS_LOCSOFTWARE
;
1214 caps
->dwBufferBytes
= This
->dsbd
.dwBufferBytes
;
1215 /* This value represents the speed of the "unlock" command.
1216 As unlock is quite fast (it does not do anything), I put
1217 4096 ko/s = 4 Mo / s */
1218 caps
->dwUnlockTransferRate
= 4096;
1219 caps
->dwPlayCpuOverhead
= 0;
1224 static HRESULT WINAPI
IDirectSoundBufferImpl_QueryInterface(
1225 LPDIRECTSOUNDBUFFER iface
,REFIID riid
,LPVOID
*ppobj
1227 ICOM_THIS(IDirectSoundBufferImpl
,iface
);
1230 WINE_StringFromCLSID(riid
,xbuf
);
1231 TRACE(dsound
,"(%p,%s,%p)\n",This
,xbuf
,ppobj
);
1233 if (!memcmp(&IID_IDirectSoundNotify
,riid
,sizeof(*riid
))) {
1234 IDirectSoundNotifyImpl
*dsn
;
1236 dsn
= (IDirectSoundNotifyImpl
*)HeapAlloc(GetProcessHeap(),0,sizeof(*dsn
));
1239 IDirectSoundBuffer_AddRef(iface
);
1240 dsn
->lpvtbl
= &dsnvt
;
1241 *ppobj
= (LPVOID
)dsn
;
1245 if (!memcmp(&IID_IDirectSound3DBuffer
,riid
,sizeof(*riid
))) {
1246 *ppobj
= This
->ds3db
;
1254 static ICOM_VTABLE(IDirectSoundBuffer
) dsbvt
= {
1255 IDirectSoundBufferImpl_QueryInterface
,
1256 IDirectSoundBufferImpl_AddRef
,
1257 IDirectSoundBufferImpl_Release
,
1258 IDirectSoundBufferImpl_GetCaps
,
1259 IDirectSoundBufferImpl_GetCurrentPosition
,
1260 IDirectSoundBufferImpl_GetFormat
,
1261 IDirectSoundBufferImpl_GetVolume
,
1262 IDirectSoundBufferImpl_GetPan
,
1263 IDirectSoundBufferImpl_GetFrequency
,
1264 IDirectSoundBufferImpl_GetStatus
,
1265 IDirectSoundBufferImpl_Initialize
,
1266 IDirectSoundBufferImpl_Lock
,
1267 IDirectSoundBufferImpl_Play
,
1268 IDirectSoundBufferImpl_SetCurrentPosition
,
1269 IDirectSoundBufferImpl_SetFormat
,
1270 IDirectSoundBufferImpl_SetVolume
,
1271 IDirectSoundBufferImpl_SetPan
,
1272 IDirectSoundBufferImpl_SetFrequency
,
1273 IDirectSoundBufferImpl_Stop
,
1274 IDirectSoundBufferImpl_Unlock
1277 /*******************************************************************************
1281 static HRESULT WINAPI
IDirectSoundImpl_SetCooperativeLevel(
1282 LPDIRECTSOUND iface
,HWND hwnd
,DWORD level
1284 ICOM_THIS(IDirectSoundImpl
,iface
);
1285 FIXME(dsound
,"(%p,%08lx,%ld):stub\n",This
,(DWORD
)hwnd
,level
);
1289 static HRESULT WINAPI
IDirectSoundImpl_CreateSoundBuffer(
1290 LPDIRECTSOUND iface
,LPDSBUFFERDESC dsbd
,LPLPDIRECTSOUNDBUFFER ppdsb
,LPUNKNOWN lpunk
1292 ICOM_THIS(IDirectSoundImpl
,iface
);
1293 IDirectSoundBufferImpl
** ippdsb
=(IDirectSoundBufferImpl
**)ppdsb
;
1294 LPWAVEFORMATEX wfex
;
1296 TRACE(dsound
,"(%p,%p,%p,%p)\n",This
,dsbd
,ippdsb
,lpunk
);
1298 if ((This
== NULL
) || (dsbd
== NULL
) || (ippdsb
== NULL
))
1299 return DSERR_INVALIDPARAM
;
1301 if (TRACE_ON(dsound
)) {
1302 TRACE(dsound
,"(size=%ld)\n",dsbd
->dwSize
);
1303 TRACE(dsound
,"(flags=0x%08lx\n",dsbd
->dwFlags
);
1304 _dump_DSBCAPS(dsbd
->dwFlags
);
1305 TRACE(dsound
,"(bufferbytes=%ld)\n",dsbd
->dwBufferBytes
);
1306 TRACE(dsound
,"(lpwfxFormat=%p)\n",dsbd
->lpwfxFormat
);
1309 wfex
= dsbd
->lpwfxFormat
;
1312 TRACE(dsound
,"(formattag=0x%04x,chans=%d,samplerate=%ld"
1313 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
1314 wfex
->wFormatTag
, wfex
->nChannels
, wfex
->nSamplesPerSec
,
1315 wfex
->nAvgBytesPerSec
, wfex
->nBlockAlign
,
1316 wfex
->wBitsPerSample
, wfex
->cbSize
);
1318 if (dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
1320 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER
)primarybuf
);
1321 *ippdsb
= primarybuf
;
1323 } /* Else create primarybuf */
1326 *ippdsb
= (IDirectSoundBufferImpl
*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDirectSoundBufferImpl
));
1327 if (*ippdsb
== NULL
)
1328 return DSERR_OUTOFMEMORY
;
1331 TRACE(dsound
, "Created buffer at %p\n", *ippdsb
);
1333 if (dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
1334 (*ippdsb
)->buflen
= dsound
->wfx
.nAvgBytesPerSec
;
1335 (*ippdsb
)->freq
= dsound
->wfx
.nSamplesPerSec
;
1337 (*ippdsb
)->buflen
= dsbd
->dwBufferBytes
;
1338 (*ippdsb
)->freq
= dsbd
->lpwfxFormat
->nSamplesPerSec
;
1340 (*ippdsb
)->buffer
= (LPBYTE
)HeapAlloc(GetProcessHeap(),0,(*ippdsb
)->buflen
);
1341 if ((*ippdsb
)->buffer
== NULL
) {
1342 HeapFree(GetProcessHeap(),0,(*ippdsb
));
1344 return DSERR_OUTOFMEMORY
;
1346 /* It's not necessary to initialize values to zero since */
1347 /* we allocated this structure with HEAP_ZERO_MEMORY... */
1348 (*ippdsb
)->playpos
= 0;
1349 (*ippdsb
)->writepos
= 0;
1350 (*ippdsb
)->parent
= NULL
;
1351 (*ippdsb
)->lpvtbl
= &dsbvt
;
1352 (*ippdsb
)->dsound
= This
;
1353 (*ippdsb
)->playing
= 0;
1354 (*ippdsb
)->lVolAdjust
= (1 << 15);
1355 (*ippdsb
)->rVolAdjust
= (1 << 15);
1357 if (!(dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
)) {
1358 (*ippdsb
)->freqAdjust
= ((*ippdsb
)->freq
<< DSOUND_FREQSHIFT
) /
1359 primarybuf
->wfx
.nSamplesPerSec
;
1360 (*ippdsb
)->nAvgBytesPerSec
= (*ippdsb
)->freq
*
1361 dsbd
->lpwfxFormat
->nBlockAlign
;
1364 memcpy(&((*ippdsb
)->dsbd
),dsbd
,sizeof(*dsbd
));
1366 /* register buffer */
1367 if (!(dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
)) {
1368 This
->buffers
= (IDirectSoundBufferImpl
**)HeapReAlloc(GetProcessHeap(),0,This
->buffers
,sizeof(IDirectSoundBufferImpl
*)*(This
->nrofbuffers
+1));
1369 This
->buffers
[This
->nrofbuffers
] = *ippdsb
;
1370 This
->nrofbuffers
++;
1372 IDirectSound_AddRef(iface
);
1374 if (dsbd
->lpwfxFormat
)
1375 memcpy(&((*ippdsb
)->wfx
), dsbd
->lpwfxFormat
, sizeof((*ippdsb
)->wfx
));
1377 InitializeCriticalSection(&((*ippdsb
)->lock
));
1380 if (dsbd
->dwFlags
& DSBCAPS_CTRL3D
) {
1381 IDirectSound3DBufferImpl
*ds3db
;
1383 ds3db
= (IDirectSound3DBufferImpl
*)HeapAlloc(GetProcessHeap(),
1386 ds3db
->dsb
= (*ippdsb
);
1387 ds3db
->lpvtbl
= &ds3dbvt
;
1388 (*ippdsb
)->ds3db
= ds3db
;
1389 ds3db
->ds3db
.dwSize
= sizeof(DS3DBUFFER
);
1390 ds3db
->ds3db
.vPosition
.x
.x
= 0.0;
1391 ds3db
->ds3db
.vPosition
.y
.y
= 0.0;
1392 ds3db
->ds3db
.vPosition
.z
.z
= 0.0;
1393 ds3db
->ds3db
.vVelocity
.x
.x
= 0.0;
1394 ds3db
->ds3db
.vVelocity
.y
.y
= 0.0;
1395 ds3db
->ds3db
.vVelocity
.z
.z
= 0.0;
1396 ds3db
->ds3db
.dwInsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
1397 ds3db
->ds3db
.dwOutsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
1398 ds3db
->ds3db
.vConeOrientation
.x
.x
= 0.0;
1399 ds3db
->ds3db
.vConeOrientation
.y
.y
= 0.0;
1400 ds3db
->ds3db
.vConeOrientation
.z
.z
= 0.0;
1401 ds3db
->ds3db
.lConeOutsideVolume
= DS3D_DEFAULTCONEOUTSIDEVOLUME
;
1402 ds3db
->ds3db
.flMinDistance
= DS3D_DEFAULTMINDISTANCE
;
1403 ds3db
->ds3db
.flMaxDistance
= DS3D_DEFAULTMAXDISTANCE
;
1404 ds3db
->ds3db
.dwMode
= DS3DMODE_NORMAL
;
1405 ds3db
->buflen
= ((*ippdsb
)->buflen
* primarybuf
->wfx
.nBlockAlign
) /
1406 (*ippdsb
)->wfx
.nBlockAlign
;
1407 ds3db
->buffer
= HeapAlloc(GetProcessHeap(), 0, ds3db
->buflen
);
1408 if (ds3db
->buffer
== NULL
) {
1410 ds3db
->ds3db
.dwMode
= DS3DMODE_DISABLE
;
1417 static HRESULT WINAPI
IDirectSoundImpl_DuplicateSoundBuffer(
1418 LPDIRECTSOUND iface
,LPDIRECTSOUNDBUFFER pdsb
,LPLPDIRECTSOUNDBUFFER ppdsb
1420 ICOM_THIS(IDirectSoundImpl
,iface
);
1421 IDirectSoundBufferImpl
* ipdsb
=(IDirectSoundBufferImpl
*)pdsb
;
1422 IDirectSoundBufferImpl
** ippdsb
=(IDirectSoundBufferImpl
**)ppdsb
;
1423 TRACE(dsound
,"(%p,%p,%p)\n",This
,ipdsb
,ippdsb
);
1425 *ippdsb
= (IDirectSoundBufferImpl
*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDirectSoundBufferImpl
));
1427 IDirectSoundBuffer_AddRef(pdsb
);
1428 memcpy(*ippdsb
, ipdsb
, sizeof(IDirectSoundBufferImpl
));
1430 (*ippdsb
)->playpos
= 0;
1431 (*ippdsb
)->writepos
= 0;
1432 (*ippdsb
)->dsound
= This
;
1433 (*ippdsb
)->parent
= ipdsb
;
1434 memcpy(&((*ippdsb
)->wfx
), &(ipdsb
->wfx
), sizeof((*ippdsb
)->wfx
));
1435 /* register buffer */
1436 This
->buffers
= (IDirectSoundBufferImpl
**)HeapReAlloc(GetProcessHeap(),0,This
->buffers
,sizeof(IDirectSoundBufferImpl
**)*(This
->nrofbuffers
+1));
1437 This
->buffers
[This
->nrofbuffers
] = *ippdsb
;
1438 This
->nrofbuffers
++;
1439 IDirectSound_AddRef(iface
);
1444 static HRESULT WINAPI
IDirectSoundImpl_GetCaps(LPDIRECTSOUND iface
,LPDSCAPS caps
) {
1445 ICOM_THIS(IDirectSoundImpl
,iface
);
1446 TRACE(dsound
,"(%p,%p)\n",This
,caps
);
1447 TRACE(dsound
,"(flags=0x%08lx)\n",caps
->dwFlags
);
1450 return DSERR_INVALIDPARAM
;
1452 /* We should check this value, not set it. See Inside DirectX, p215. */
1453 caps
->dwSize
= sizeof(*caps
);
1456 DSCAPS_PRIMARYSTEREO
|
1457 DSCAPS_PRIMARY16BIT
|
1458 DSCAPS_SECONDARYSTEREO
|
1459 DSCAPS_SECONDARY16BIT
|
1460 DSCAPS_CONTINUOUSRATE
;
1461 /* FIXME: query OSS */
1462 caps
->dwMinSecondarySampleRate
= DSBFREQUENCY_MIN
;
1463 caps
->dwMaxSecondarySampleRate
= DSBFREQUENCY_MAX
;
1465 caps
->dwPrimaryBuffers
= 1;
1467 caps
->dwMaxHwMixingAllBuffers
= 0;
1468 caps
->dwMaxHwMixingStaticBuffers
= 0;
1469 caps
->dwMaxHwMixingStreamingBuffers
= 0;
1471 caps
->dwFreeHwMixingAllBuffers
= 0;
1472 caps
->dwFreeHwMixingStaticBuffers
= 0;
1473 caps
->dwFreeHwMixingStreamingBuffers
= 0;
1475 caps
->dwMaxHw3DAllBuffers
= 0;
1476 caps
->dwMaxHw3DStaticBuffers
= 0;
1477 caps
->dwMaxHw3DStreamingBuffers
= 0;
1479 caps
->dwFreeHw3DAllBuffers
= 0;
1480 caps
->dwFreeHw3DStaticBuffers
= 0;
1481 caps
->dwFreeHw3DStreamingBuffers
= 0;
1483 caps
->dwTotalHwMemBytes
= 0;
1485 caps
->dwFreeHwMemBytes
= 0;
1487 caps
->dwMaxContigFreeHwMemBytes
= 0;
1489 caps
->dwUnlockTransferRateHwBuffers
= 4096; /* But we have none... */
1491 caps
->dwPlayCpuOverheadSwBuffers
= 1; /* 1% */
1496 static ULONG WINAPI
IDirectSoundImpl_AddRef(LPDIRECTSOUND iface
) {
1497 ICOM_THIS(IDirectSoundImpl
,iface
);
1498 return ++(This
->ref
);
1501 static ULONG WINAPI
IDirectSoundImpl_Release(LPDIRECTSOUND iface
) {
1502 ICOM_THIS(IDirectSoundImpl
,iface
);
1503 TRACE(dsound
,"(%p), ref was %ld\n",This
,This
->ref
);
1504 if (!--(This
->ref
)) {
1505 DSOUND_CloseAudio();
1506 while(IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)primarybuf
)); /* Deallocate */
1507 FIXME(dsound
, "need to release all buffers!\n");
1508 HeapFree(GetProcessHeap(),0,This
);
1515 static HRESULT WINAPI
IDirectSoundImpl_SetSpeakerConfig(
1516 LPDIRECTSOUND iface
,DWORD config
1518 ICOM_THIS(IDirectSoundImpl
,iface
);
1519 FIXME(dsound
,"(%p,0x%08lx):stub\n",This
,config
);
1523 static HRESULT WINAPI
IDirectSoundImpl_QueryInterface(
1524 LPDIRECTSOUND iface
,REFIID riid
,LPVOID
*ppobj
1526 ICOM_THIS(IDirectSoundImpl
,iface
);
1529 if (!memcmp(&IID_IDirectSound3DListener
,riid
,sizeof(*riid
))) {
1531 if (This
->listener
) {
1532 *ppobj
= This
->listener
;
1535 This
->listener
= (IDirectSound3DListenerImpl
*)HeapAlloc(
1536 GetProcessHeap(), 0, sizeof(*(This
->listener
)));
1537 This
->listener
->ref
= 1;
1538 This
->listener
->lpvtbl
= &ds3dlvt
;
1539 IDirectSound_AddRef(iface
);
1540 This
->listener
->ds3dl
.dwSize
= sizeof(DS3DLISTENER
);
1541 This
->listener
->ds3dl
.vPosition
.x
.x
= 0.0;
1542 This
->listener
->ds3dl
.vPosition
.y
.y
= 0.0;
1543 This
->listener
->ds3dl
.vPosition
.z
.z
= 0.0;
1544 This
->listener
->ds3dl
.vVelocity
.x
.x
= 0.0;
1545 This
->listener
->ds3dl
.vVelocity
.y
.y
= 0.0;
1546 This
->listener
->ds3dl
.vVelocity
.z
.z
= 0.0;
1547 This
->listener
->ds3dl
.vOrientFront
.x
.x
= 0.0;
1548 This
->listener
->ds3dl
.vOrientFront
.y
.y
= 0.0;
1549 This
->listener
->ds3dl
.vOrientFront
.z
.z
= 1.0;
1550 This
->listener
->ds3dl
.vOrientTop
.x
.x
= 0.0;
1551 This
->listener
->ds3dl
.vOrientTop
.y
.y
= 1.0;
1552 This
->listener
->ds3dl
.vOrientTop
.z
.z
= 0.0;
1553 This
->listener
->ds3dl
.flDistanceFactor
= DS3D_DEFAULTDISTANCEFACTOR
;
1554 This
->listener
->ds3dl
.flRolloffFactor
= DS3D_DEFAULTROLLOFFFACTOR
;
1555 This
->listener
->ds3dl
.flDopplerFactor
= DS3D_DEFAULTDOPPLERFACTOR
;
1556 *ppobj
= (LPVOID
)This
->listener
;
1560 WINE_StringFromCLSID(riid
,xbuf
);
1561 TRACE(dsound
,"(%p,%s,%p)\n",This
,xbuf
,ppobj
);
1565 static HRESULT WINAPI
IDirectSoundImpl_Compact(
1566 LPDIRECTSOUND iface
)
1568 ICOM_THIS(IDirectSoundImpl
,iface
);
1569 TRACE(dsound
, "(%p)\n", This
);
1573 static HRESULT WINAPI
IDirectSoundImpl_GetSpeakerConfig(
1574 LPDIRECTSOUND iface
,
1575 LPDWORD lpdwSpeakerConfig
)
1577 ICOM_THIS(IDirectSoundImpl
,iface
);
1578 TRACE(dsound
, "(%p, %p)\n", This
, lpdwSpeakerConfig
);
1579 *lpdwSpeakerConfig
= DSSPEAKER_STEREO
| (DSSPEAKER_GEOMETRY_NARROW
<< 16);
1583 static HRESULT WINAPI
IDirectSoundImpl_Initialize(
1584 LPDIRECTSOUND iface
,
1587 ICOM_THIS(IDirectSoundImpl
,iface
);
1588 TRACE(dsound
, "(%p, %p)\n", This
, lpGuid
);
1592 static ICOM_VTABLE(IDirectSound
) dsvt
= {
1593 IDirectSoundImpl_QueryInterface
,
1594 IDirectSoundImpl_AddRef
,
1595 IDirectSoundImpl_Release
,
1596 IDirectSoundImpl_CreateSoundBuffer
,
1597 IDirectSoundImpl_GetCaps
,
1598 IDirectSoundImpl_DuplicateSoundBuffer
,
1599 IDirectSoundImpl_SetCooperativeLevel
,
1600 IDirectSoundImpl_Compact
,
1601 IDirectSoundImpl_GetSpeakerConfig
,
1602 IDirectSoundImpl_SetSpeakerConfig
,
1603 IDirectSoundImpl_Initialize
1607 /* See http://www.opensound.com/pguide/audio.html for more details */
1610 DSOUND_setformat(LPWAVEFORMATEX wfex
) {
1611 int xx
,channels
,speed
,format
,nformat
;
1614 TRACE(dsound
, "(%p) deferred\n", wfex
);
1617 switch (wfex
->wFormatTag
) {
1619 WARN(dsound
,"unknown WAVE_FORMAT tag %d\n",wfex
->wFormatTag
);
1620 return DSERR_BADFORMAT
;
1621 case WAVE_FORMAT_PCM
:
1624 if (wfex
->wBitsPerSample
==8)
1627 format
= AFMT_S16_LE
;
1629 if (-1==ioctl(audiofd
,SNDCTL_DSP_GETFMTS
,&xx
)) {
1630 perror("ioctl SNDCTL_DSP_GETFMTS");
1633 if ((xx
&format
)!=format
) {/* format unsupported */
1634 FIXME(dsound
,"SNDCTL_DSP_GETFMTS: format not supported\n");
1638 if (-1==ioctl(audiofd
,SNDCTL_DSP_SETFMT
,&nformat
)) {
1639 perror("ioctl SNDCTL_DSP_SETFMT");
1642 if (nformat
!=format
) {/* didn't work */
1643 FIXME(dsound
,"SNDCTL_DSP_GETFMTS: format not set\n");
1647 channels
= wfex
->nChannels
-1;
1648 if (-1==ioctl(audiofd
,SNDCTL_DSP_STEREO
,&channels
)) {
1649 perror("ioctl SNDCTL_DSP_STEREO");
1652 speed
= wfex
->nSamplesPerSec
;
1653 if (-1==ioctl(audiofd
,SNDCTL_DSP_SPEED
,&speed
)) {
1654 perror("ioctl SNDCTL_DSP_SPEED");
1657 TRACE(dsound
,"(freq=%ld,channels=%d,bits=%d)\n",
1658 wfex
->nSamplesPerSec
,wfex
->nChannels
,wfex
->wBitsPerSample
1663 static void DSOUND_CheckEvent(IDirectSoundBufferImpl
*dsb
, int len
)
1667 LPDSBPOSITIONNOTIFY event
;
1669 if (dsb
->nrofnotifies
== 0)
1672 TRACE(dsound
,"(%p) buflen = %ld, playpos = %ld, len = %d\n",
1673 dsb
, dsb
->buflen
, dsb
->playpos
, len
);
1674 for (i
= 0; i
< dsb
->nrofnotifies
; i
++) {
1675 event
= dsb
->notifies
+ i
;
1676 offset
= event
->dwOffset
;
1677 TRACE(dsound
, "checking %d, position %ld, event = %d\n",
1678 i
, offset
, event
->hEventNotify
);
1679 /* DSBPN_OFFSETSTOP has to be the last element. So this is */
1680 /* OK. [Inside DirectX, p274] */
1682 /* This also means we can't sort the entries by offset, */
1683 /* because DSBPN_OFFSETSTOP == -1 */
1684 if (offset
== DSBPN_OFFSETSTOP
) {
1685 if (dsb
->playing
== 0) {
1686 SetEvent(event
->hEventNotify
);
1687 TRACE(dsound
,"signalled event %d (%d)\n", event
->hEventNotify
, i
);
1692 if ((dsb
->playpos
+ len
) >= dsb
->buflen
) {
1693 if ((offset
< ((dsb
->playpos
+ len
) % dsb
->buflen
)) ||
1694 (offset
>= dsb
->playpos
)) {
1695 TRACE(dsound
,"signalled event %d (%d)\n", event
->hEventNotify
, i
);
1696 SetEvent(event
->hEventNotify
);
1699 if ((offset
>= dsb
->playpos
) && (offset
< (dsb
->playpos
+ len
))) {
1700 TRACE(dsound
,"signalled event %d (%d)\n", event
->hEventNotify
, i
);
1701 SetEvent(event
->hEventNotify
);
1707 /* WAV format info can be found at: */
1709 /* http://www.cwi.nl/ftp/audio/AudioFormats.part2 */
1710 /* ftp://ftp.cwi.nl/pub/audio/RIFF-format */
1712 /* Import points to remember: */
1714 /* 8-bit WAV is unsigned */
1715 /* 16-bit WAV is signed */
1717 static __inline__ INT16
cvtU8toS16(BYTE byte
)
1719 INT16 s
= (byte
- 128) << 8;
1724 static __inline__ BYTE
cvtS16toU8(INT16 word
)
1726 BYTE b
= (word
+ 32768) >> 8;
1732 /* We should be able to optimize these two inline functions */
1733 /* so that we aren't doing 8->16->8 conversions when it is */
1734 /* not necessary. But this is still a WIP. Optimize later. */
1735 static __inline__
void get_fields(const IDirectSoundBufferImpl
*dsb
, BYTE
*buf
, INT
*fl
, INT
*fr
)
1737 INT16
*bufs
= (INT16
*) buf
;
1739 /* TRACE(dsound, "(%p)", buf); */
1740 if ((dsb
->wfx
.wBitsPerSample
== 8) && dsb
->wfx
.nChannels
== 2) {
1741 *fl
= cvtU8toS16(*buf
);
1742 *fr
= cvtU8toS16(*(buf
+ 1));
1746 if ((dsb
->wfx
.wBitsPerSample
== 16) && dsb
->wfx
.nChannels
== 2) {
1752 if ((dsb
->wfx
.wBitsPerSample
== 8) && dsb
->wfx
.nChannels
== 1) {
1753 *fl
= cvtU8toS16(*buf
);
1758 if ((dsb
->wfx
.wBitsPerSample
== 16) && dsb
->wfx
.nChannels
== 1) {
1764 FIXME(dsound
, "get_fields found an unsupported configuration\n");
1768 static __inline__
void set_fields(BYTE
*buf
, INT fl
, INT fr
)
1770 INT16
*bufs
= (INT16
*) buf
;
1772 if ((primarybuf
->wfx
.wBitsPerSample
== 8) && (primarybuf
->wfx
.nChannels
== 2)) {
1773 *buf
= cvtS16toU8(fl
);
1774 *(buf
+ 1) = cvtS16toU8(fr
);
1778 if ((primarybuf
->wfx
.wBitsPerSample
== 16) && (primarybuf
->wfx
.nChannels
== 2)) {
1784 if ((primarybuf
->wfx
.wBitsPerSample
== 8) && (primarybuf
->wfx
.nChannels
== 1)) {
1785 *buf
= cvtS16toU8((fl
+ fr
) >> 1);
1789 if ((primarybuf
->wfx
.wBitsPerSample
== 16) && (primarybuf
->wfx
.nChannels
== 1)) {
1790 *bufs
= (fl
+ fr
) >> 1;
1793 FIXME(dsound
, "set_fields found an unsupported configuration\n");
1797 /* Now with PerfectPitch (tm) technology */
1798 static INT
DSOUND_MixerNorm(IDirectSoundBufferImpl
*dsb
, BYTE
*buf
, INT len
)
1800 INT i
, size
, ipos
, ilen
, fieldL
, fieldR
;
1802 INT iAdvance
= dsb
->wfx
.nBlockAlign
;
1803 INT oAdvance
= primarybuf
->wfx
.nBlockAlign
;
1805 ibp
= dsb
->buffer
+ dsb
->playpos
;
1808 TRACE(dsound
, "(%p, %p, %p), playpos=%8.8lx\n", dsb
, ibp
, obp
, dsb
->playpos
);
1809 /* Check for the best case */
1810 if ((dsb
->freq
== primarybuf
->wfx
.nSamplesPerSec
) &&
1811 (dsb
->wfx
.wBitsPerSample
== primarybuf
->wfx
.wBitsPerSample
) &&
1812 (dsb
->wfx
.nChannels
== primarybuf
->wfx
.nChannels
)) {
1813 TRACE(dsound
, "(%p) Best case\n", dsb
);
1814 if ((ibp
+ len
) < (BYTE
*)(dsb
->buffer
+ dsb
->buflen
))
1815 memcpy(obp
, ibp
, len
);
1817 memcpy(obp
, ibp
, dsb
->buflen
- dsb
->playpos
);
1818 memcpy(obp
+ (dsb
->buflen
- dsb
->playpos
),
1820 len
- (dsb
->buflen
- dsb
->playpos
));
1825 /* Check for same sample rate */
1826 if (dsb
->freq
== primarybuf
->wfx
.nSamplesPerSec
) {
1827 TRACE(dsound
, "(%p) Same sample rate %ld = primary %ld\n", dsb
,
1828 dsb
->freq
, primarybuf
->wfx
.nSamplesPerSec
);
1830 for (i
= 0; i
< len
; i
+= oAdvance
) {
1831 get_fields(dsb
, ibp
, &fieldL
, &fieldR
);
1834 set_fields(obp
, fieldL
, fieldR
);
1836 if (ibp
>= (BYTE
*)(dsb
->buffer
+ dsb
->buflen
))
1837 ibp
= dsb
->buffer
; /* wrap */
1842 /* Mix in different sample rates */
1844 /* New PerfectPitch(tm) Technology (c) 1998 Rob Riggs */
1845 /* Patent Pending :-] */
1847 TRACE(dsound
, "(%p) Adjusting frequency: %ld -> %ld\n",
1848 dsb
, dsb
->freq
, primarybuf
->wfx
.nSamplesPerSec
);
1850 size
= len
/ oAdvance
;
1851 ilen
= ((size
* dsb
->freqAdjust
) >> DSOUND_FREQSHIFT
) * iAdvance
;
1852 for (i
= 0; i
< size
; i
++) {
1854 ipos
= (((i
* dsb
->freqAdjust
) >> DSOUND_FREQSHIFT
) * iAdvance
) + dsb
->playpos
;
1856 if (ipos
>= dsb
->buflen
)
1857 ipos
%= dsb
->buflen
; /* wrap */
1859 get_fields(dsb
, (dsb
->buffer
+ ipos
), &fieldL
, &fieldR
);
1860 set_fields(obp
, fieldL
, fieldR
);
1866 static void DSOUND_MixerVol(IDirectSoundBufferImpl
*dsb
, BYTE
*buf
, INT len
)
1868 INT i
, inc
= primarybuf
->wfx
.wBitsPerSample
>> 3;
1870 INT16
*bps
= (INT16
*) buf
;
1872 TRACE(dsound
, "(%p) left = %lx, right = %lx\n", dsb
,
1873 dsb
->lVolAdjust
, dsb
->rVolAdjust
);
1874 if ((!(dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLPAN
) || (dsb
->pan
== 0)) &&
1875 (!(dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLVOLUME
) || (dsb
->volume
== 0)) &&
1876 !(dsb
->dsbd
.dwFlags
& DSBCAPS_CTRL3D
))
1877 return; /* Nothing to do */
1879 /* If we end up with some bozo coder using panning or 3D sound */
1880 /* with a mono primary buffer, it could sound very weird using */
1881 /* this method. Oh well, tough patooties. */
1883 for (i
= 0; i
< len
; i
+= inc
) {
1889 /* 8-bit WAV is unsigned, but we need to operate */
1890 /* on signed data for this to work properly */
1892 val
= ((val
* (i
& inc
? dsb
->rVolAdjust
: dsb
->lVolAdjust
)) >> 15);
1897 /* 16-bit WAV is signed -- much better */
1899 val
= ((val
* ((i
& inc
) ? dsb
->rVolAdjust
: dsb
->lVolAdjust
)) >> 15);
1905 FIXME(dsound
, "MixerVol had a nasty error\n");
1911 static void DSOUND_Mixer3D(IDirectSoundBufferImpl
*dsb
, BYTE
*buf
, INT len
)
1914 DWORD buflen
, playpos
;
1916 buflen
= dsb
->ds3db
->buflen
;
1917 playpos
= (dsb
->playpos
* primarybuf
->wfx
.nBlockAlign
) / dsb
->wfx
.nBlockAlign
;
1918 ibp
= dsb
->ds3db
->buffer
+ playpos
;
1921 if (playpos
> buflen
) {
1922 FIXME(dsound
, "Major breakage");
1926 if (len
<= (playpos
+ buflen
))
1927 memcpy(obp
, ibp
, len
);
1929 memcpy(obp
, ibp
, buflen
- playpos
);
1930 memcpy(obp
+ (buflen
- playpos
),
1932 len
- (buflen
- playpos
));
1938 static void *tmp_buffer
;
1939 static size_t tmp_buffer_len
= 0;
1941 static void *DSOUND_tmpbuffer(size_t len
)
1943 if (len
>tmp_buffer_len
) {
1944 void *new_buffer
= realloc(tmp_buffer
, len
);
1946 tmp_buffer
= new_buffer
;
1947 tmp_buffer_len
= len
;
1954 static DWORD
DSOUND_MixInBuffer(IDirectSoundBufferImpl
*dsb
)
1956 INT i
, len
, ilen
, temp
, field
;
1957 INT advance
= primarybuf
->wfx
.wBitsPerSample
>> 3;
1958 BYTE
*buf
, *ibuf
, *obuf
;
1959 INT16
*ibufs
, *obufs
;
1961 len
= DSOUND_FRAGLEN
; /* The most we will use */
1962 if (!(dsb
->playflags
& DSBPLAY_LOOPING
)) {
1963 temp
= MulDiv(primarybuf
->wfx
.nAvgBytesPerSec
, dsb
->buflen
,
1964 dsb
->nAvgBytesPerSec
) -
1965 MulDiv(primarybuf
->wfx
.nAvgBytesPerSec
, dsb
->playpos
,
1966 dsb
->nAvgBytesPerSec
);
1967 len
= (len
> temp
) ? temp
: len
;
1969 len
&= ~3; /* 4 byte alignment */
1972 /* This should only happen if we aren't looping and temp < 4 */
1974 /* We skip the remainder, so check for possible events */
1975 DSOUND_CheckEvent(dsb
, dsb
->buflen
- dsb
->playpos
);
1980 /* Check for DSBPN_OFFSETSTOP */
1981 DSOUND_CheckEvent(dsb
, 0);
1985 /* Been seeing segfaults in malloc() for some reason... */
1986 TRACE(dsound
, "allocating buffer (size = %d)\n", len
);
1987 if ((buf
= ibuf
= (BYTE
*) DSOUND_tmpbuffer(len
)) == NULL
)
1990 TRACE(dsound
, "MixInBuffer (%p) len = %d\n", dsb
, len
);
1992 ilen
= DSOUND_MixerNorm(dsb
, ibuf
, len
);
1993 if ((dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLPAN
) ||
1994 (dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLVOLUME
))
1995 DSOUND_MixerVol(dsb
, ibuf
, len
);
1997 obuf
= primarybuf
->buffer
+ primarybuf
->playpos
;
1998 for (i
= 0; i
< len
; i
+= advance
) {
1999 obufs
= (INT16
*) obuf
;
2000 ibufs
= (INT16
*) ibuf
;
2001 if (primarybuf
->wfx
.wBitsPerSample
== 8) {
2002 /* 8-bit WAV is unsigned */
2003 field
= (*ibuf
- 128);
2004 field
+= (*obuf
- 128);
2005 field
= field
> 127 ? 127 : field
;
2006 field
= field
< -128 ? -128 : field
;
2007 *obuf
= field
+ 128;
2009 /* 16-bit WAV is signed */
2012 field
= field
> 32767 ? 32767 : field
;
2013 field
= field
< -32768 ? -32768 : field
;
2018 if (obuf
>= (BYTE
*)(primarybuf
->buffer
+ primarybuf
->buflen
))
2019 obuf
= primarybuf
->buffer
;
2023 if (dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLPOSITIONNOTIFY
)
2024 DSOUND_CheckEvent(dsb
, ilen
);
2026 dsb
->playpos
+= ilen
;
2027 dsb
->writepos
= dsb
->playpos
+ ilen
;
2029 if (dsb
->playpos
>= dsb
->buflen
) {
2030 if (!(dsb
->playflags
& DSBPLAY_LOOPING
)) {
2034 DSOUND_CheckEvent(dsb
, 0); /* For DSBPN_OFFSETSTOP */
2036 dsb
->playpos
%= dsb
->buflen
; /* wrap */
2039 if (dsb
->writepos
>= dsb
->buflen
)
2040 dsb
->writepos
%= dsb
->buflen
;
2045 static DWORD WINAPI
DSOUND_MixPrimary(void)
2047 INT i
, len
, maxlen
= 0;
2048 IDirectSoundBufferImpl
*dsb
;
2050 for (i
= dsound
->nrofbuffers
- 1; i
>= 0; i
--) {
2051 dsb
= dsound
->buffers
[i
];
2053 if (!dsb
|| !(dsb
->lpvtbl
))
2055 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER
)dsb
);
2056 if (dsb
->buflen
&& dsb
->playing
) {
2057 EnterCriticalSection(&(dsb
->lock
));
2058 len
= DSOUND_MixInBuffer(dsb
);
2059 maxlen
= len
> maxlen
? len
: maxlen
;
2060 LeaveCriticalSection(&(dsb
->lock
));
2062 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)dsb
);
2068 static int DSOUND_OpenAudio(void)
2072 if (primarybuf
== NULL
)
2073 return DSERR_OUTOFMEMORY
;
2075 while (audiofd
!= -1)
2077 audiofd
= open("/dev/audio",O_WRONLY
);
2079 /* Don't worry if sound is busy at the moment */
2081 perror("open /dev/audio");
2082 return audiofd
; /* -1 */
2085 /* We should probably do something here if SETFRAGMENT fails... */
2086 audioFragment
=0x0002000c;
2087 if (-1==ioctl(audiofd
,SNDCTL_DSP_SETFRAGMENT
,&audioFragment
))
2088 perror("ioctl SETFRAGMENT");
2091 DSOUND_setformat(&(primarybuf
->wfx
));
2096 static void DSOUND_CloseAudio(void)
2100 neutral
= primarybuf
->wfx
.wBitsPerSample
== 8 ? 128 : 0;
2101 audioOK
= 0; /* race condition */
2103 /* It's possible we've been called with audio closed */
2104 /* from SetFormat()... this is just to force a call */
2105 /* to OpenAudio() to reset the hardware properly */
2108 primarybuf
->playpos
= 0;
2109 primarybuf
->writepos
= DSOUND_FRAGLEN
;
2110 memset(primarybuf
->buffer
, neutral
, primarybuf
->buflen
);
2112 TRACE(dsound
, "Audio stopped\n");
2115 static int DSOUND_WriteAudio(char *buf
, int len
)
2117 int result
, left
= 0;
2119 while (left
< len
) {
2120 result
= write(audiofd
, buf
+ left
, len
- left
);
2132 static void DSOUND_OutputPrimary(int len
)
2134 int neutral
, flen1
, flen2
;
2135 char *frag1
, *frag2
;
2137 /* This is a bad place for this. We need to clear the */
2138 /* buffer with a neutral value, for unsigned 8-bit WAVE */
2139 /* that's 128, for signed 16-bit it's 0 */
2140 neutral
= primarybuf
->wfx
.wBitsPerSample
== 8 ? 128 : 0;
2143 EnterCriticalSection(&(primarybuf
->lock
));
2146 if ((audioOK
== 1) || (DSOUND_OpenAudio() == 0)) {
2147 if (primarybuf
->playpos
+ len
>= primarybuf
->buflen
) {
2148 frag1
= primarybuf
->buffer
+ primarybuf
->playpos
;
2149 flen1
= primarybuf
->buflen
- primarybuf
->playpos
;
2150 frag2
= primarybuf
->buffer
;
2151 flen2
= len
- (primarybuf
->buflen
- primarybuf
->playpos
);
2152 if (DSOUND_WriteAudio(frag1
, flen1
) != 0) {
2153 perror("DSOUND_WriteAudio");
2154 LeaveCriticalSection(&(primarybuf
->lock
));
2157 memset(frag1
, neutral
, flen1
);
2158 if (DSOUND_WriteAudio(frag2
, flen2
) != 0) {
2159 perror("DSOUND_WriteAudio");
2160 LeaveCriticalSection(&(primarybuf
->lock
));
2163 memset(frag2
, neutral
, flen2
);
2165 frag1
= primarybuf
->buffer
+ primarybuf
->playpos
;
2167 if (DSOUND_WriteAudio(frag1
, flen1
) != 0) {
2168 perror("DSOUND_WriteAudio");
2169 LeaveCriticalSection(&(primarybuf
->lock
));
2172 memset(frag1
, neutral
, flen1
);
2175 /* Can't play audio at the moment -- we need to sleep */
2176 /* to make up for the time we'd be blocked in write() */
2180 primarybuf
->playpos
+= len
;
2181 if (primarybuf
->playpos
>= primarybuf
->buflen
)
2182 primarybuf
->playpos
%= primarybuf
->buflen
;
2183 primarybuf
->writepos
= primarybuf
->playpos
+ DSOUND_FRAGLEN
;
2184 if (primarybuf
->writepos
>= primarybuf
->buflen
)
2185 primarybuf
->writepos
%= primarybuf
->buflen
;
2187 LeaveCriticalSection(&(primarybuf
->lock
));
2191 static DWORD WINAPI
DSOUND_thread(LPVOID arg
)
2195 TRACE(dsound
,"dsound is at pid %d\n",getpid());
2198 WARN(dsound
,"DSOUND thread giving up.\n");
2202 WARN(dsound
,"DSOUND father died? Giving up.\n");
2205 /* RACE: dsound could be deleted */
2206 IDirectSound_AddRef((LPDIRECTSOUND
)dsound
);
2207 if (primarybuf
== NULL
) {
2208 /* Should never happen */
2209 WARN(dsound
, "Lost the primary buffer!\n");
2210 IDirectSound_Release((LPDIRECTSOUND
)dsound
);
2215 EnterCriticalSection(&(primarybuf
->lock
));
2216 len
= DSOUND_MixPrimary();
2217 LeaveCriticalSection(&(primarybuf
->lock
));
2220 if (primarybuf
->playing
)
2221 len
= DSOUND_FRAGLEN
> len
? DSOUND_FRAGLEN
: len
;
2223 /* This does all the work */
2224 DSOUND_OutputPrimary(len
);
2226 /* no buffers playing -- close and wait */
2228 DSOUND_CloseAudio();
2231 IDirectSound_Release((LPDIRECTSOUND
)dsound
);
2236 #endif /* HAVE_OSS */
2238 HRESULT WINAPI
DirectSoundCreate(REFGUID lpGUID
,LPDIRECTSOUND
*ppDS
,IUnknown
*pUnkOuter
)
2240 IDirectSoundImpl
** ippDS
=(IDirectSoundImpl
**)ppDS
;
2242 TRACE(dsound
,"(%p,%p,%p)\n",lpGUID
,ippDS
,pUnkOuter
);
2244 TRACE(dsound
,"DirectSoundCreate (%p)\n", ippDS
);
2249 return DSERR_INVALIDPARAM
;
2252 IDirectSound_AddRef((LPDIRECTSOUND
)dsound
);
2257 /* Check that we actually have audio capabilities */
2258 /* If we do, whether it's busy or not, we continue */
2259 /* otherwise we return with DSERR_NODRIVER */
2261 audiofd
= open("/dev/audio",O_WRONLY
);
2262 if (audiofd
== -1) {
2263 if (errno
== ENODEV
) {
2264 MSG("No sound hardware found.\n");
2265 return DSERR_NODRIVER
;
2266 } else if (errno
== EBUSY
) {
2267 MSG("Sound device busy, will keep trying.\n");
2269 MSG("Unexpected error while checking for sound support.\n");
2270 return DSERR_GENERIC
;
2277 *ippDS
= (IDirectSoundImpl
*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundImpl
));
2279 return DSERR_OUTOFMEMORY
;
2282 (*ippDS
)->lpvtbl
= &dsvt
;
2283 (*ippDS
)->buffers
= NULL
;
2284 (*ippDS
)->nrofbuffers
= 0;
2286 (*ippDS
)->wfx
.wFormatTag
= 1;
2287 (*ippDS
)->wfx
.nChannels
= 2;
2288 (*ippDS
)->wfx
.nSamplesPerSec
= 22050;
2289 (*ippDS
)->wfx
.nAvgBytesPerSec
= 44100;
2290 (*ippDS
)->wfx
.nBlockAlign
= 2;
2291 (*ippDS
)->wfx
.wBitsPerSample
= 8;
2298 if (primarybuf
== NULL
) {
2302 dsbd
.dwSize
= sizeof(DSBUFFERDESC
);
2303 dsbd
.dwFlags
= DSBCAPS_PRIMARYBUFFER
;
2304 dsbd
.dwBufferBytes
= 0;
2305 dsbd
.lpwfxFormat
= &(dsound
->wfx
);
2306 hr
= IDirectSound_CreateSoundBuffer(*ppDS
, &dsbd
, (LPDIRECTSOUNDBUFFER
*)&primarybuf
, NULL
);
2309 dsound
->primary
= primarybuf
;
2311 memset(primarybuf
->buffer
, 128, primarybuf
->buflen
);
2312 hnd
= CreateThread(NULL
,0,DSOUND_thread
,0,0,&xid
);
2316 MessageBoxA(0,"DirectSound needs the Open Sound System Driver, which has not been found by ./configure.","WINE DirectSound",MB_OK
|MB_ICONSTOP
);
2317 return DSERR_NODRIVER
;
2321 /*******************************************************************************
2322 * DirectSound ClassFactory
2326 /* IUnknown fields */
2327 ICOM_VTABLE(IClassFactory
)* lpvtbl
;
2329 } IClassFactoryImpl
;
2331 static HRESULT WINAPI
2332 DSCF_QueryInterface(LPCLASSFACTORY iface
,REFIID riid
,LPVOID
*ppobj
) {
2333 ICOM_THIS(IClassFactoryImpl
,iface
);
2337 WINE_StringFromCLSID(riid
,buf
);
2339 sprintf(buf
,"<guid-0x%04x>",LOWORD(riid
));
2340 FIXME(dsound
,"(%p)->(%s,%p),stub!\n",This
,buf
,ppobj
);
2341 return E_NOINTERFACE
;
2345 DSCF_AddRef(LPCLASSFACTORY iface
) {
2346 ICOM_THIS(IClassFactoryImpl
,iface
);
2347 return ++(This
->ref
);
2350 static ULONG WINAPI
DSCF_Release(LPCLASSFACTORY iface
) {
2351 ICOM_THIS(IClassFactoryImpl
,iface
);
2352 /* static class, won't be freed */
2353 return --(This
->ref
);
2356 static HRESULT WINAPI
DSCF_CreateInstance(
2357 LPCLASSFACTORY iface
,LPUNKNOWN pOuter
,REFIID riid
,LPVOID
*ppobj
2359 ICOM_THIS(IClassFactoryImpl
,iface
);
2362 WINE_StringFromCLSID(riid
,buf
);
2363 TRACE(dsound
,"(%p)->(%p,%s,%p)\n",This
,pOuter
,buf
,ppobj
);
2364 if (!memcmp(riid
,&IID_IDirectSound
,sizeof(IID_IDirectSound
))) {
2365 /* FIXME: reuse already created dsound if present? */
2366 return DirectSoundCreate(riid
,(LPDIRECTSOUND
*)ppobj
,pOuter
);
2368 return E_NOINTERFACE
;
2371 static HRESULT WINAPI
DSCF_LockServer(LPCLASSFACTORY iface
,BOOL dolock
) {
2372 ICOM_THIS(IClassFactoryImpl
,iface
);
2373 FIXME(dsound
,"(%p)->(%d),stub!\n",This
,dolock
);
2377 static ICOM_VTABLE(IClassFactory
) DSCF_Vtbl
= {
2378 DSCF_QueryInterface
,
2381 DSCF_CreateInstance
,
2384 static IClassFactoryImpl DSOUND_CF
= {&DSCF_Vtbl
, 1 };
2386 /*******************************************************************************
2387 * DllGetClassObject [DSOUND.4]
2388 * Retrieves class object from a DLL object
2391 * Docs say returns STDAPI
2394 * rclsid [I] CLSID for the class object
2395 * riid [I] Reference to identifier of interface for class object
2396 * ppv [O] Address of variable to receive interface pointer for riid
2400 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
2403 DWORD WINAPI
DSOUND_DllGetClassObject(REFCLSID rclsid
,REFIID riid
,LPVOID
*ppv
)
2405 char buf
[80],xbuf
[80];
2408 WINE_StringFromCLSID(rclsid
,xbuf
);
2410 sprintf(xbuf
,"<guid-0x%04x>",LOWORD(rclsid
));
2412 WINE_StringFromCLSID(riid
,buf
);
2414 sprintf(buf
,"<guid-0x%04x>",LOWORD(riid
));
2415 WINE_StringFromCLSID(riid
,xbuf
);
2416 TRACE(dsound
, "(%p,%p,%p)\n", xbuf
, buf
, ppv
);
2417 if (!memcmp(riid
,&IID_IClassFactory
,sizeof(IID_IClassFactory
))) {
2418 *ppv
= (LPVOID
)&DSOUND_CF
;
2419 IClassFactory_AddRef((IClassFactory
*)*ppv
);
2422 FIXME(dsound
, "(%p,%p,%p): no interface found.\n", xbuf
, buf
, ppv
);
2423 return E_NOINTERFACE
;
2427 /*******************************************************************************
2428 * DllCanUnloadNow [DSOUND.3] Determines whether the DLL is in use.
2434 DWORD WINAPI
DSOUND_DllCanUnloadNow(void)
2436 FIXME(dsound
, "(void): stub\n");