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
=
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(dsound
,"(%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
)
571 FIXME(dsound
,"stub\n");
575 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetDistanceFactor(
576 LPDIRECTSOUND3DLISTENER iface
,
577 LPD3DVALUE lpfDistanceFactor
)
579 FIXME(dsound
,"stub\n");
583 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetDopplerFactor(
584 LPDIRECTSOUND3DLISTENER iface
,
585 LPD3DVALUE lpfDopplerFactor
)
587 FIXME(dsound
,"stub\n");
591 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetOrientation(
592 LPDIRECTSOUND3DLISTENER iface
,
593 LPD3DVECTOR lpvOrientFront
,
594 LPD3DVECTOR lpvOrientTop
)
596 FIXME(dsound
,"stub\n");
600 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetPosition(
601 LPDIRECTSOUND3DLISTENER iface
,
602 LPD3DVECTOR lpvPosition
)
604 FIXME(dsound
,"stub\n");
608 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetRolloffFactor(
609 LPDIRECTSOUND3DLISTENER iface
,
610 LPD3DVALUE lpfRolloffFactor
)
612 FIXME(dsound
,"stub\n");
616 static HRESULT WINAPI
IDirectSound3DListenerImpl_GetVelocity(
617 LPDIRECTSOUND3DLISTENER iface
,
618 LPD3DVECTOR lpvVelocity
)
620 FIXME(dsound
,"stub\n");
624 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetAllParameters(
625 LPDIRECTSOUND3DLISTENER iface
,
626 LPCDS3DLISTENER lpcDS3DL
,
629 FIXME(dsound
,"stub\n");
633 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetDistanceFactor(
634 LPDIRECTSOUND3DLISTENER iface
,
635 D3DVALUE fDistanceFactor
,
638 FIXME(dsound
,"stub\n");
642 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetDopplerFactor(
643 LPDIRECTSOUND3DLISTENER iface
,
644 D3DVALUE fDopplerFactor
,
647 FIXME(dsound
,"stub\n");
651 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetOrientation(
652 LPDIRECTSOUND3DLISTENER iface
,
653 D3DVALUE xFront
, D3DVALUE yFront
, D3DVALUE zFront
,
654 D3DVALUE xTop
, D3DVALUE yTop
, D3DVALUE zTop
,
657 FIXME(dsound
,"stub\n");
661 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetPosition(
662 LPDIRECTSOUND3DLISTENER iface
,
663 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
666 FIXME(dsound
,"stub\n");
670 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetRolloffFactor(
671 LPDIRECTSOUND3DLISTENER iface
,
672 D3DVALUE fRolloffFactor
,
675 FIXME(dsound
,"stub\n");
679 static HRESULT WINAPI
IDirectSound3DListenerImpl_SetVelocity(
680 LPDIRECTSOUND3DLISTENER iface
,
681 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
684 FIXME(dsound
,"stub\n");
688 static HRESULT WINAPI
IDirectSound3DListenerImpl_CommitDeferredSettings(
689 LPDIRECTSOUND3DLISTENER iface
)
692 FIXME(dsound
,"stub\n");
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(dsound
,"(%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(dsound
,"(%p,0x%08lx,%p)\n",This
,howmuch
,notify
);
759 for (i
=0;i
<howmuch
;i
++)
760 TRACE(dsound
,"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(dsound
, "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(dsound
,"(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(dsound
,"(%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(dsound
, "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(dsound
, "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(dsound
,"(%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(dsound
,"(%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(dsound
,"(%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(dsound
,"(%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(dsound
,"(%p,%p,%p)\n",This
,playpos
,writepos
);
1003 if (playpos
) *playpos
= This
->playpos
;
1004 if (writepos
) *writepos
= This
->writepos
;
1005 TRACE(dsound
, "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(dsound
,"(%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(dsound
,"(%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(dsound
,"(%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(dsound
,"->%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(dsound
,"->%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(dsound
,"(%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(dsound
,"(%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(dsound
,"(%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(dsound
,"(%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(dsound
,"(%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(dsound
,"(%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(dsound
,"(%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(dsound
,"(%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(dsound
,"(%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(dsound
,"(%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(dsound
,"(size=%ld)\n",dsbd
->dwSize
);
1311 TRACE(dsound
,"(flags=0x%08lx\n",dsbd
->dwFlags
);
1312 _dump_DSBCAPS(dsbd
->dwFlags
);
1313 TRACE(dsound
,"(bufferbytes=%ld)\n",dsbd
->dwBufferBytes
);
1314 TRACE(dsound
,"(lpwfxFormat=%p)\n",dsbd
->lpwfxFormat
);
1317 wfex
= dsbd
->lpwfxFormat
;
1320 TRACE(dsound
,"(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
;
1331 } /* Else create primarybuf */
1334 *ippdsb
= (IDirectSoundBufferImpl
*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDirectSoundBufferImpl
));
1335 if (*ippdsb
== NULL
)
1336 return DSERR_OUTOFMEMORY
;
1339 TRACE(dsound
, "Created buffer at %p\n", *ippdsb
);
1341 if (dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
1342 (*ippdsb
)->buflen
= dsound
->wfx
.nAvgBytesPerSec
;
1343 (*ippdsb
)->freq
= dsound
->wfx
.nSamplesPerSec
;
1345 (*ippdsb
)->buflen
= dsbd
->dwBufferBytes
;
1346 (*ippdsb
)->freq
= dsbd
->lpwfxFormat
->nSamplesPerSec
;
1348 (*ippdsb
)->buffer
= (LPBYTE
)HeapAlloc(GetProcessHeap(),0,(*ippdsb
)->buflen
);
1349 if ((*ippdsb
)->buffer
== NULL
) {
1350 HeapFree(GetProcessHeap(),0,(*ippdsb
));
1352 return DSERR_OUTOFMEMORY
;
1354 /* It's not necessary to initialize values to zero since */
1355 /* we allocated this structure with HEAP_ZERO_MEMORY... */
1356 (*ippdsb
)->playpos
= 0;
1357 (*ippdsb
)->writepos
= 0;
1358 (*ippdsb
)->parent
= NULL
;
1359 (*ippdsb
)->lpvtbl
= &dsbvt
;
1360 (*ippdsb
)->dsound
= This
;
1361 (*ippdsb
)->playing
= 0;
1362 (*ippdsb
)->lVolAdjust
= (1 << 15);
1363 (*ippdsb
)->rVolAdjust
= (1 << 15);
1365 if (!(dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
)) {
1366 (*ippdsb
)->freqAdjust
= ((*ippdsb
)->freq
<< DSOUND_FREQSHIFT
) /
1367 primarybuf
->wfx
.nSamplesPerSec
;
1368 (*ippdsb
)->nAvgBytesPerSec
= (*ippdsb
)->freq
*
1369 dsbd
->lpwfxFormat
->nBlockAlign
;
1372 memcpy(&((*ippdsb
)->dsbd
),dsbd
,sizeof(*dsbd
));
1374 /* register buffer */
1375 if (!(dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
)) {
1376 This
->buffers
= (IDirectSoundBufferImpl
**)HeapReAlloc(GetProcessHeap(),0,This
->buffers
,sizeof(IDirectSoundBufferImpl
*)*(This
->nrofbuffers
+1));
1377 This
->buffers
[This
->nrofbuffers
] = *ippdsb
;
1378 This
->nrofbuffers
++;
1380 IDirectSound_AddRef(iface
);
1382 if (dsbd
->lpwfxFormat
)
1383 memcpy(&((*ippdsb
)->wfx
), dsbd
->lpwfxFormat
, sizeof((*ippdsb
)->wfx
));
1385 InitializeCriticalSection(&((*ippdsb
)->lock
));
1388 if (dsbd
->dwFlags
& DSBCAPS_CTRL3D
) {
1389 IDirectSound3DBufferImpl
*ds3db
;
1391 ds3db
= (IDirectSound3DBufferImpl
*)HeapAlloc(GetProcessHeap(),
1394 ds3db
->dsb
= (*ippdsb
);
1395 ds3db
->lpvtbl
= &ds3dbvt
;
1396 (*ippdsb
)->ds3db
= ds3db
;
1397 ds3db
->ds3db
.dwSize
= sizeof(DS3DBUFFER
);
1398 ds3db
->ds3db
.vPosition
.x
.x
= 0.0;
1399 ds3db
->ds3db
.vPosition
.y
.y
= 0.0;
1400 ds3db
->ds3db
.vPosition
.z
.z
= 0.0;
1401 ds3db
->ds3db
.vVelocity
.x
.x
= 0.0;
1402 ds3db
->ds3db
.vVelocity
.y
.y
= 0.0;
1403 ds3db
->ds3db
.vVelocity
.z
.z
= 0.0;
1404 ds3db
->ds3db
.dwInsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
1405 ds3db
->ds3db
.dwOutsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
1406 ds3db
->ds3db
.vConeOrientation
.x
.x
= 0.0;
1407 ds3db
->ds3db
.vConeOrientation
.y
.y
= 0.0;
1408 ds3db
->ds3db
.vConeOrientation
.z
.z
= 0.0;
1409 ds3db
->ds3db
.lConeOutsideVolume
= DS3D_DEFAULTCONEOUTSIDEVOLUME
;
1410 ds3db
->ds3db
.flMinDistance
= DS3D_DEFAULTMINDISTANCE
;
1411 ds3db
->ds3db
.flMaxDistance
= DS3D_DEFAULTMAXDISTANCE
;
1412 ds3db
->ds3db
.dwMode
= DS3DMODE_NORMAL
;
1413 ds3db
->buflen
= ((*ippdsb
)->buflen
* primarybuf
->wfx
.nBlockAlign
) /
1414 (*ippdsb
)->wfx
.nBlockAlign
;
1415 ds3db
->buffer
= HeapAlloc(GetProcessHeap(), 0, ds3db
->buflen
);
1416 if (ds3db
->buffer
== NULL
) {
1418 ds3db
->ds3db
.dwMode
= DS3DMODE_DISABLE
;
1425 static HRESULT WINAPI
IDirectSoundImpl_DuplicateSoundBuffer(
1426 LPDIRECTSOUND iface
,LPDIRECTSOUNDBUFFER pdsb
,LPLPDIRECTSOUNDBUFFER ppdsb
1428 ICOM_THIS(IDirectSoundImpl
,iface
);
1429 IDirectSoundBufferImpl
* ipdsb
=(IDirectSoundBufferImpl
*)pdsb
;
1430 IDirectSoundBufferImpl
** ippdsb
=(IDirectSoundBufferImpl
**)ppdsb
;
1431 TRACE(dsound
,"(%p,%p,%p)\n",This
,ipdsb
,ippdsb
);
1433 *ippdsb
= (IDirectSoundBufferImpl
*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDirectSoundBufferImpl
));
1435 IDirectSoundBuffer_AddRef(pdsb
);
1436 memcpy(*ippdsb
, ipdsb
, sizeof(IDirectSoundBufferImpl
));
1438 (*ippdsb
)->playpos
= 0;
1439 (*ippdsb
)->writepos
= 0;
1440 (*ippdsb
)->dsound
= This
;
1441 (*ippdsb
)->parent
= ipdsb
;
1442 memcpy(&((*ippdsb
)->wfx
), &(ipdsb
->wfx
), sizeof((*ippdsb
)->wfx
));
1443 /* register buffer */
1444 This
->buffers
= (IDirectSoundBufferImpl
**)HeapReAlloc(GetProcessHeap(),0,This
->buffers
,sizeof(IDirectSoundBufferImpl
**)*(This
->nrofbuffers
+1));
1445 This
->buffers
[This
->nrofbuffers
] = *ippdsb
;
1446 This
->nrofbuffers
++;
1447 IDirectSound_AddRef(iface
);
1452 static HRESULT WINAPI
IDirectSoundImpl_GetCaps(LPDIRECTSOUND iface
,LPDSCAPS caps
) {
1453 ICOM_THIS(IDirectSoundImpl
,iface
);
1454 TRACE(dsound
,"(%p,%p)\n",This
,caps
);
1455 TRACE(dsound
,"(flags=0x%08lx)\n",caps
->dwFlags
);
1458 return DSERR_INVALIDPARAM
;
1460 /* We should check this value, not set it. See Inside DirectX, p215. */
1461 caps
->dwSize
= sizeof(*caps
);
1464 DSCAPS_PRIMARYSTEREO
|
1465 DSCAPS_PRIMARY16BIT
|
1466 DSCAPS_SECONDARYSTEREO
|
1467 DSCAPS_SECONDARY16BIT
|
1468 DSCAPS_CONTINUOUSRATE
;
1469 /* FIXME: query OSS */
1470 caps
->dwMinSecondarySampleRate
= DSBFREQUENCY_MIN
;
1471 caps
->dwMaxSecondarySampleRate
= DSBFREQUENCY_MAX
;
1473 caps
->dwPrimaryBuffers
= 1;
1475 caps
->dwMaxHwMixingAllBuffers
= 0;
1476 caps
->dwMaxHwMixingStaticBuffers
= 0;
1477 caps
->dwMaxHwMixingStreamingBuffers
= 0;
1479 caps
->dwFreeHwMixingAllBuffers
= 0;
1480 caps
->dwFreeHwMixingStaticBuffers
= 0;
1481 caps
->dwFreeHwMixingStreamingBuffers
= 0;
1483 caps
->dwMaxHw3DAllBuffers
= 0;
1484 caps
->dwMaxHw3DStaticBuffers
= 0;
1485 caps
->dwMaxHw3DStreamingBuffers
= 0;
1487 caps
->dwFreeHw3DAllBuffers
= 0;
1488 caps
->dwFreeHw3DStaticBuffers
= 0;
1489 caps
->dwFreeHw3DStreamingBuffers
= 0;
1491 caps
->dwTotalHwMemBytes
= 0;
1493 caps
->dwFreeHwMemBytes
= 0;
1495 caps
->dwMaxContigFreeHwMemBytes
= 0;
1497 caps
->dwUnlockTransferRateHwBuffers
= 4096; /* But we have none... */
1499 caps
->dwPlayCpuOverheadSwBuffers
= 1; /* 1% */
1504 static ULONG WINAPI
IDirectSoundImpl_AddRef(LPDIRECTSOUND iface
) {
1505 ICOM_THIS(IDirectSoundImpl
,iface
);
1506 return ++(This
->ref
);
1509 static ULONG WINAPI
IDirectSoundImpl_Release(LPDIRECTSOUND iface
) {
1510 ICOM_THIS(IDirectSoundImpl
,iface
);
1511 TRACE(dsound
,"(%p), ref was %ld\n",This
,This
->ref
);
1512 if (!--(This
->ref
)) {
1513 DSOUND_CloseAudio();
1514 while(IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)primarybuf
)); /* Deallocate */
1515 FIXME(dsound
, "need to release all buffers!\n");
1516 HeapFree(GetProcessHeap(),0,This
);
1523 static HRESULT WINAPI
IDirectSoundImpl_SetSpeakerConfig(
1524 LPDIRECTSOUND iface
,DWORD config
1526 ICOM_THIS(IDirectSoundImpl
,iface
);
1527 FIXME(dsound
,"(%p,0x%08lx):stub\n",This
,config
);
1531 static HRESULT WINAPI
IDirectSoundImpl_QueryInterface(
1532 LPDIRECTSOUND iface
,REFIID riid
,LPVOID
*ppobj
1534 ICOM_THIS(IDirectSoundImpl
,iface
);
1537 if (!memcmp(&IID_IDirectSound3DListener
,riid
,sizeof(*riid
))) {
1539 if (This
->listener
) {
1540 *ppobj
= This
->listener
;
1543 This
->listener
= (IDirectSound3DListenerImpl
*)HeapAlloc(
1544 GetProcessHeap(), 0, sizeof(*(This
->listener
)));
1545 This
->listener
->ref
= 1;
1546 This
->listener
->lpvtbl
= &ds3dlvt
;
1547 IDirectSound_AddRef(iface
);
1548 This
->listener
->ds3dl
.dwSize
= sizeof(DS3DLISTENER
);
1549 This
->listener
->ds3dl
.vPosition
.x
.x
= 0.0;
1550 This
->listener
->ds3dl
.vPosition
.y
.y
= 0.0;
1551 This
->listener
->ds3dl
.vPosition
.z
.z
= 0.0;
1552 This
->listener
->ds3dl
.vVelocity
.x
.x
= 0.0;
1553 This
->listener
->ds3dl
.vVelocity
.y
.y
= 0.0;
1554 This
->listener
->ds3dl
.vVelocity
.z
.z
= 0.0;
1555 This
->listener
->ds3dl
.vOrientFront
.x
.x
= 0.0;
1556 This
->listener
->ds3dl
.vOrientFront
.y
.y
= 0.0;
1557 This
->listener
->ds3dl
.vOrientFront
.z
.z
= 1.0;
1558 This
->listener
->ds3dl
.vOrientTop
.x
.x
= 0.0;
1559 This
->listener
->ds3dl
.vOrientTop
.y
.y
= 1.0;
1560 This
->listener
->ds3dl
.vOrientTop
.z
.z
= 0.0;
1561 This
->listener
->ds3dl
.flDistanceFactor
= DS3D_DEFAULTDISTANCEFACTOR
;
1562 This
->listener
->ds3dl
.flRolloffFactor
= DS3D_DEFAULTROLLOFFFACTOR
;
1563 This
->listener
->ds3dl
.flDopplerFactor
= DS3D_DEFAULTDOPPLERFACTOR
;
1564 *ppobj
= (LPVOID
)This
->listener
;
1568 WINE_StringFromCLSID(riid
,xbuf
);
1569 TRACE(dsound
,"(%p,%s,%p)\n",This
,xbuf
,ppobj
);
1573 static HRESULT WINAPI
IDirectSoundImpl_Compact(
1574 LPDIRECTSOUND iface
)
1576 ICOM_THIS(IDirectSoundImpl
,iface
);
1577 TRACE(dsound
, "(%p)\n", This
);
1581 static HRESULT WINAPI
IDirectSoundImpl_GetSpeakerConfig(
1582 LPDIRECTSOUND iface
,
1583 LPDWORD lpdwSpeakerConfig
)
1585 ICOM_THIS(IDirectSoundImpl
,iface
);
1586 TRACE(dsound
, "(%p, %p)\n", This
, lpdwSpeakerConfig
);
1587 *lpdwSpeakerConfig
= DSSPEAKER_STEREO
| (DSSPEAKER_GEOMETRY_NARROW
<< 16);
1591 static HRESULT WINAPI
IDirectSoundImpl_Initialize(
1592 LPDIRECTSOUND iface
,
1595 ICOM_THIS(IDirectSoundImpl
,iface
);
1596 TRACE(dsound
, "(%p, %p)\n", This
, lpGuid
);
1600 static ICOM_VTABLE(IDirectSound
) dsvt
=
1602 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1603 IDirectSoundImpl_QueryInterface
,
1604 IDirectSoundImpl_AddRef
,
1605 IDirectSoundImpl_Release
,
1606 IDirectSoundImpl_CreateSoundBuffer
,
1607 IDirectSoundImpl_GetCaps
,
1608 IDirectSoundImpl_DuplicateSoundBuffer
,
1609 IDirectSoundImpl_SetCooperativeLevel
,
1610 IDirectSoundImpl_Compact
,
1611 IDirectSoundImpl_GetSpeakerConfig
,
1612 IDirectSoundImpl_SetSpeakerConfig
,
1613 IDirectSoundImpl_Initialize
1617 /* See http://www.opensound.com/pguide/audio.html for more details */
1620 DSOUND_setformat(LPWAVEFORMATEX wfex
) {
1621 int xx
,channels
,speed
,format
,nformat
;
1624 TRACE(dsound
, "(%p) deferred\n", wfex
);
1627 switch (wfex
->wFormatTag
) {
1629 WARN(dsound
,"unknown WAVE_FORMAT tag %d\n",wfex
->wFormatTag
);
1630 return DSERR_BADFORMAT
;
1631 case WAVE_FORMAT_PCM
:
1634 if (wfex
->wBitsPerSample
==8)
1637 format
= AFMT_S16_LE
;
1639 if (-1==ioctl(audiofd
,SNDCTL_DSP_GETFMTS
,&xx
)) {
1640 perror("ioctl SNDCTL_DSP_GETFMTS");
1643 if ((xx
&format
)!=format
) {/* format unsupported */
1644 FIXME(dsound
,"SNDCTL_DSP_GETFMTS: format not supported\n");
1648 if (-1==ioctl(audiofd
,SNDCTL_DSP_SETFMT
,&nformat
)) {
1649 perror("ioctl SNDCTL_DSP_SETFMT");
1652 if (nformat
!=format
) {/* didn't work */
1653 FIXME(dsound
,"SNDCTL_DSP_GETFMTS: format not set\n");
1657 channels
= wfex
->nChannels
-1;
1658 if (-1==ioctl(audiofd
,SNDCTL_DSP_STEREO
,&channels
)) {
1659 perror("ioctl SNDCTL_DSP_STEREO");
1662 speed
= wfex
->nSamplesPerSec
;
1663 if (-1==ioctl(audiofd
,SNDCTL_DSP_SPEED
,&speed
)) {
1664 perror("ioctl SNDCTL_DSP_SPEED");
1667 TRACE(dsound
,"(freq=%ld,channels=%d,bits=%d)\n",
1668 wfex
->nSamplesPerSec
,wfex
->nChannels
,wfex
->wBitsPerSample
1673 static void DSOUND_CheckEvent(IDirectSoundBufferImpl
*dsb
, int len
)
1677 LPDSBPOSITIONNOTIFY event
;
1679 if (dsb
->nrofnotifies
== 0)
1682 TRACE(dsound
,"(%p) buflen = %ld, playpos = %ld, len = %d\n",
1683 dsb
, dsb
->buflen
, dsb
->playpos
, len
);
1684 for (i
= 0; i
< dsb
->nrofnotifies
; i
++) {
1685 event
= dsb
->notifies
+ i
;
1686 offset
= event
->dwOffset
;
1687 TRACE(dsound
, "checking %d, position %ld, event = %d\n",
1688 i
, offset
, event
->hEventNotify
);
1689 /* DSBPN_OFFSETSTOP has to be the last element. So this is */
1690 /* OK. [Inside DirectX, p274] */
1692 /* This also means we can't sort the entries by offset, */
1693 /* because DSBPN_OFFSETSTOP == -1 */
1694 if (offset
== DSBPN_OFFSETSTOP
) {
1695 if (dsb
->playing
== 0) {
1696 SetEvent(event
->hEventNotify
);
1697 TRACE(dsound
,"signalled event %d (%d)\n", event
->hEventNotify
, i
);
1702 if ((dsb
->playpos
+ len
) >= dsb
->buflen
) {
1703 if ((offset
< ((dsb
->playpos
+ len
) % dsb
->buflen
)) ||
1704 (offset
>= dsb
->playpos
)) {
1705 TRACE(dsound
,"signalled event %d (%d)\n", event
->hEventNotify
, i
);
1706 SetEvent(event
->hEventNotify
);
1709 if ((offset
>= dsb
->playpos
) && (offset
< (dsb
->playpos
+ len
))) {
1710 TRACE(dsound
,"signalled event %d (%d)\n", event
->hEventNotify
, i
);
1711 SetEvent(event
->hEventNotify
);
1717 /* WAV format info can be found at: */
1719 /* http://www.cwi.nl/ftp/audio/AudioFormats.part2 */
1720 /* ftp://ftp.cwi.nl/pub/audio/RIFF-format */
1722 /* Import points to remember: */
1724 /* 8-bit WAV is unsigned */
1725 /* 16-bit WAV is signed */
1727 static inline INT16
cvtU8toS16(BYTE byte
)
1729 INT16 s
= (byte
- 128) << 8;
1734 static inline BYTE
cvtS16toU8(INT16 word
)
1736 BYTE b
= (word
+ 32768) >> 8;
1742 /* We should be able to optimize these two inline functions */
1743 /* so that we aren't doing 8->16->8 conversions when it is */
1744 /* not necessary. But this is still a WIP. Optimize later. */
1745 static inline void get_fields(const IDirectSoundBufferImpl
*dsb
, BYTE
*buf
, INT
*fl
, INT
*fr
)
1747 INT16
*bufs
= (INT16
*) buf
;
1749 /* TRACE(dsound, "(%p)", buf); */
1750 if ((dsb
->wfx
.wBitsPerSample
== 8) && dsb
->wfx
.nChannels
== 2) {
1751 *fl
= cvtU8toS16(*buf
);
1752 *fr
= cvtU8toS16(*(buf
+ 1));
1756 if ((dsb
->wfx
.wBitsPerSample
== 16) && dsb
->wfx
.nChannels
== 2) {
1762 if ((dsb
->wfx
.wBitsPerSample
== 8) && dsb
->wfx
.nChannels
== 1) {
1763 *fl
= cvtU8toS16(*buf
);
1768 if ((dsb
->wfx
.wBitsPerSample
== 16) && dsb
->wfx
.nChannels
== 1) {
1774 FIXME(dsound
, "get_fields found an unsupported configuration\n");
1778 static inline void set_fields(BYTE
*buf
, INT fl
, INT fr
)
1780 INT16
*bufs
= (INT16
*) buf
;
1782 if ((primarybuf
->wfx
.wBitsPerSample
== 8) && (primarybuf
->wfx
.nChannels
== 2)) {
1783 *buf
= cvtS16toU8(fl
);
1784 *(buf
+ 1) = cvtS16toU8(fr
);
1788 if ((primarybuf
->wfx
.wBitsPerSample
== 16) && (primarybuf
->wfx
.nChannels
== 2)) {
1794 if ((primarybuf
->wfx
.wBitsPerSample
== 8) && (primarybuf
->wfx
.nChannels
== 1)) {
1795 *buf
= cvtS16toU8((fl
+ fr
) >> 1);
1799 if ((primarybuf
->wfx
.wBitsPerSample
== 16) && (primarybuf
->wfx
.nChannels
== 1)) {
1800 *bufs
= (fl
+ fr
) >> 1;
1803 FIXME(dsound
, "set_fields found an unsupported configuration\n");
1807 /* Now with PerfectPitch (tm) technology */
1808 static INT
DSOUND_MixerNorm(IDirectSoundBufferImpl
*dsb
, BYTE
*buf
, INT len
)
1810 INT i
, size
, ipos
, ilen
, fieldL
, fieldR
;
1812 INT iAdvance
= dsb
->wfx
.nBlockAlign
;
1813 INT oAdvance
= primarybuf
->wfx
.nBlockAlign
;
1815 ibp
= dsb
->buffer
+ dsb
->playpos
;
1818 TRACE(dsound
, "(%p, %p, %p), playpos=%8.8lx\n", dsb
, ibp
, obp
, dsb
->playpos
);
1819 /* Check for the best case */
1820 if ((dsb
->freq
== primarybuf
->wfx
.nSamplesPerSec
) &&
1821 (dsb
->wfx
.wBitsPerSample
== primarybuf
->wfx
.wBitsPerSample
) &&
1822 (dsb
->wfx
.nChannels
== primarybuf
->wfx
.nChannels
)) {
1823 TRACE(dsound
, "(%p) Best case\n", dsb
);
1824 if ((ibp
+ len
) < (BYTE
*)(dsb
->buffer
+ dsb
->buflen
))
1825 memcpy(obp
, ibp
, len
);
1827 memcpy(obp
, ibp
, dsb
->buflen
- dsb
->playpos
);
1828 memcpy(obp
+ (dsb
->buflen
- dsb
->playpos
),
1830 len
- (dsb
->buflen
- dsb
->playpos
));
1835 /* Check for same sample rate */
1836 if (dsb
->freq
== primarybuf
->wfx
.nSamplesPerSec
) {
1837 TRACE(dsound
, "(%p) Same sample rate %ld = primary %ld\n", dsb
,
1838 dsb
->freq
, primarybuf
->wfx
.nSamplesPerSec
);
1840 for (i
= 0; i
< len
; i
+= oAdvance
) {
1841 get_fields(dsb
, ibp
, &fieldL
, &fieldR
);
1844 set_fields(obp
, fieldL
, fieldR
);
1846 if (ibp
>= (BYTE
*)(dsb
->buffer
+ dsb
->buflen
))
1847 ibp
= dsb
->buffer
; /* wrap */
1852 /* Mix in different sample rates */
1854 /* New PerfectPitch(tm) Technology (c) 1998 Rob Riggs */
1855 /* Patent Pending :-] */
1857 TRACE(dsound
, "(%p) Adjusting frequency: %ld -> %ld\n",
1858 dsb
, dsb
->freq
, primarybuf
->wfx
.nSamplesPerSec
);
1860 size
= len
/ oAdvance
;
1861 ilen
= ((size
* dsb
->freqAdjust
) >> DSOUND_FREQSHIFT
) * iAdvance
;
1862 for (i
= 0; i
< size
; i
++) {
1864 ipos
= (((i
* dsb
->freqAdjust
) >> DSOUND_FREQSHIFT
) * iAdvance
) + dsb
->playpos
;
1866 if (ipos
>= dsb
->buflen
)
1867 ipos
%= dsb
->buflen
; /* wrap */
1869 get_fields(dsb
, (dsb
->buffer
+ ipos
), &fieldL
, &fieldR
);
1870 set_fields(obp
, fieldL
, fieldR
);
1876 static void DSOUND_MixerVol(IDirectSoundBufferImpl
*dsb
, BYTE
*buf
, INT len
)
1878 INT i
, inc
= primarybuf
->wfx
.wBitsPerSample
>> 3;
1880 INT16
*bps
= (INT16
*) buf
;
1882 TRACE(dsound
, "(%p) left = %lx, right = %lx\n", dsb
,
1883 dsb
->lVolAdjust
, dsb
->rVolAdjust
);
1884 if ((!(dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLPAN
) || (dsb
->pan
== 0)) &&
1885 (!(dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLVOLUME
) || (dsb
->volume
== 0)) &&
1886 !(dsb
->dsbd
.dwFlags
& DSBCAPS_CTRL3D
))
1887 return; /* Nothing to do */
1889 /* If we end up with some bozo coder using panning or 3D sound */
1890 /* with a mono primary buffer, it could sound very weird using */
1891 /* this method. Oh well, tough patooties. */
1893 for (i
= 0; i
< len
; i
+= inc
) {
1899 /* 8-bit WAV is unsigned, but we need to operate */
1900 /* on signed data for this to work properly */
1902 val
= ((val
* (i
& inc
? dsb
->rVolAdjust
: dsb
->lVolAdjust
)) >> 15);
1907 /* 16-bit WAV is signed -- much better */
1909 val
= ((val
* ((i
& inc
) ? dsb
->rVolAdjust
: dsb
->lVolAdjust
)) >> 15);
1915 FIXME(dsound
, "MixerVol had a nasty error\n");
1921 static void DSOUND_Mixer3D(IDirectSoundBufferImpl
*dsb
, BYTE
*buf
, INT len
)
1924 DWORD buflen
, playpos
;
1926 buflen
= dsb
->ds3db
->buflen
;
1927 playpos
= (dsb
->playpos
* primarybuf
->wfx
.nBlockAlign
) / dsb
->wfx
.nBlockAlign
;
1928 ibp
= dsb
->ds3db
->buffer
+ playpos
;
1931 if (playpos
> buflen
) {
1932 FIXME(dsound
, "Major breakage");
1936 if (len
<= (playpos
+ buflen
))
1937 memcpy(obp
, ibp
, len
);
1939 memcpy(obp
, ibp
, buflen
- playpos
);
1940 memcpy(obp
+ (buflen
- playpos
),
1942 len
- (buflen
- playpos
));
1948 static void *tmp_buffer
;
1949 static size_t tmp_buffer_len
= 0;
1951 static void *DSOUND_tmpbuffer(size_t len
)
1953 if (len
>tmp_buffer_len
) {
1954 void *new_buffer
= realloc(tmp_buffer
, len
);
1956 tmp_buffer
= new_buffer
;
1957 tmp_buffer_len
= len
;
1964 static DWORD
DSOUND_MixInBuffer(IDirectSoundBufferImpl
*dsb
)
1966 INT i
, len
, ilen
, temp
, field
;
1967 INT advance
= primarybuf
->wfx
.wBitsPerSample
>> 3;
1968 BYTE
*buf
, *ibuf
, *obuf
;
1969 INT16
*ibufs
, *obufs
;
1971 len
= DSOUND_FRAGLEN
; /* The most we will use */
1972 if (!(dsb
->playflags
& DSBPLAY_LOOPING
)) {
1973 temp
= MulDiv(primarybuf
->wfx
.nAvgBytesPerSec
, dsb
->buflen
,
1974 dsb
->nAvgBytesPerSec
) -
1975 MulDiv(primarybuf
->wfx
.nAvgBytesPerSec
, dsb
->playpos
,
1976 dsb
->nAvgBytesPerSec
);
1977 len
= (len
> temp
) ? temp
: len
;
1979 len
&= ~3; /* 4 byte alignment */
1982 /* This should only happen if we aren't looping and temp < 4 */
1984 /* We skip the remainder, so check for possible events */
1985 DSOUND_CheckEvent(dsb
, dsb
->buflen
- dsb
->playpos
);
1990 /* Check for DSBPN_OFFSETSTOP */
1991 DSOUND_CheckEvent(dsb
, 0);
1995 /* Been seeing segfaults in malloc() for some reason... */
1996 TRACE(dsound
, "allocating buffer (size = %d)\n", len
);
1997 if ((buf
= ibuf
= (BYTE
*) DSOUND_tmpbuffer(len
)) == NULL
)
2000 TRACE(dsound
, "MixInBuffer (%p) len = %d\n", dsb
, len
);
2002 ilen
= DSOUND_MixerNorm(dsb
, ibuf
, len
);
2003 if ((dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLPAN
) ||
2004 (dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLVOLUME
))
2005 DSOUND_MixerVol(dsb
, ibuf
, len
);
2007 obuf
= primarybuf
->buffer
+ primarybuf
->playpos
;
2008 for (i
= 0; i
< len
; i
+= advance
) {
2009 obufs
= (INT16
*) obuf
;
2010 ibufs
= (INT16
*) ibuf
;
2011 if (primarybuf
->wfx
.wBitsPerSample
== 8) {
2012 /* 8-bit WAV is unsigned */
2013 field
= (*ibuf
- 128);
2014 field
+= (*obuf
- 128);
2015 field
= field
> 127 ? 127 : field
;
2016 field
= field
< -128 ? -128 : field
;
2017 *obuf
= field
+ 128;
2019 /* 16-bit WAV is signed */
2022 field
= field
> 32767 ? 32767 : field
;
2023 field
= field
< -32768 ? -32768 : field
;
2028 if (obuf
>= (BYTE
*)(primarybuf
->buffer
+ primarybuf
->buflen
))
2029 obuf
= primarybuf
->buffer
;
2033 if (dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLPOSITIONNOTIFY
)
2034 DSOUND_CheckEvent(dsb
, ilen
);
2036 dsb
->playpos
+= ilen
;
2037 dsb
->writepos
= dsb
->playpos
+ ilen
;
2039 if (dsb
->playpos
>= dsb
->buflen
) {
2040 if (!(dsb
->playflags
& DSBPLAY_LOOPING
)) {
2044 DSOUND_CheckEvent(dsb
, 0); /* For DSBPN_OFFSETSTOP */
2046 dsb
->playpos
%= dsb
->buflen
; /* wrap */
2049 if (dsb
->writepos
>= dsb
->buflen
)
2050 dsb
->writepos
%= dsb
->buflen
;
2055 static DWORD WINAPI
DSOUND_MixPrimary(void)
2057 INT i
, len
, maxlen
= 0;
2058 IDirectSoundBufferImpl
*dsb
;
2060 for (i
= dsound
->nrofbuffers
- 1; i
>= 0; i
--) {
2061 dsb
= dsound
->buffers
[i
];
2063 if (!dsb
|| !(dsb
->lpvtbl
))
2065 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER
)dsb
);
2066 if (dsb
->buflen
&& dsb
->playing
) {
2067 EnterCriticalSection(&(dsb
->lock
));
2068 len
= DSOUND_MixInBuffer(dsb
);
2069 maxlen
= len
> maxlen
? len
: maxlen
;
2070 LeaveCriticalSection(&(dsb
->lock
));
2072 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER
)dsb
);
2078 static int DSOUND_OpenAudio(void)
2082 if (primarybuf
== NULL
)
2083 return DSERR_OUTOFMEMORY
;
2085 while (audiofd
!= -1)
2087 audiofd
= open("/dev/audio",O_WRONLY
);
2089 /* Don't worry if sound is busy at the moment */
2091 perror("open /dev/audio");
2092 return audiofd
; /* -1 */
2095 /* We should probably do something here if SETFRAGMENT fails... */
2096 audioFragment
=0x0002000c;
2097 if (-1==ioctl(audiofd
,SNDCTL_DSP_SETFRAGMENT
,&audioFragment
))
2098 perror("ioctl SETFRAGMENT");
2101 DSOUND_setformat(&(primarybuf
->wfx
));
2106 static void DSOUND_CloseAudio(void)
2110 neutral
= primarybuf
->wfx
.wBitsPerSample
== 8 ? 128 : 0;
2111 audioOK
= 0; /* race condition */
2113 /* It's possible we've been called with audio closed */
2114 /* from SetFormat()... this is just to force a call */
2115 /* to OpenAudio() to reset the hardware properly */
2118 primarybuf
->playpos
= 0;
2119 primarybuf
->writepos
= DSOUND_FRAGLEN
;
2120 memset(primarybuf
->buffer
, neutral
, primarybuf
->buflen
);
2122 TRACE(dsound
, "Audio stopped\n");
2125 static int DSOUND_WriteAudio(char *buf
, int len
)
2127 int result
, left
= 0;
2129 while (left
< len
) {
2130 result
= write(audiofd
, buf
+ left
, len
- left
);
2142 static void DSOUND_OutputPrimary(int len
)
2144 int neutral
, flen1
, flen2
;
2145 char *frag1
, *frag2
;
2147 /* This is a bad place for this. We need to clear the */
2148 /* buffer with a neutral value, for unsigned 8-bit WAVE */
2149 /* that's 128, for signed 16-bit it's 0 */
2150 neutral
= primarybuf
->wfx
.wBitsPerSample
== 8 ? 128 : 0;
2153 EnterCriticalSection(&(primarybuf
->lock
));
2156 if ((audioOK
== 1) || (DSOUND_OpenAudio() == 0)) {
2157 if (primarybuf
->playpos
+ len
>= primarybuf
->buflen
) {
2158 frag1
= primarybuf
->buffer
+ primarybuf
->playpos
;
2159 flen1
= primarybuf
->buflen
- primarybuf
->playpos
;
2160 frag2
= primarybuf
->buffer
;
2161 flen2
= len
- (primarybuf
->buflen
- primarybuf
->playpos
);
2162 if (DSOUND_WriteAudio(frag1
, flen1
) != 0) {
2163 perror("DSOUND_WriteAudio");
2164 LeaveCriticalSection(&(primarybuf
->lock
));
2167 memset(frag1
, neutral
, flen1
);
2168 if (DSOUND_WriteAudio(frag2
, flen2
) != 0) {
2169 perror("DSOUND_WriteAudio");
2170 LeaveCriticalSection(&(primarybuf
->lock
));
2173 memset(frag2
, neutral
, flen2
);
2175 frag1
= primarybuf
->buffer
+ primarybuf
->playpos
;
2177 if (DSOUND_WriteAudio(frag1
, flen1
) != 0) {
2178 perror("DSOUND_WriteAudio");
2179 LeaveCriticalSection(&(primarybuf
->lock
));
2182 memset(frag1
, neutral
, flen1
);
2185 /* Can't play audio at the moment -- we need to sleep */
2186 /* to make up for the time we'd be blocked in write() */
2190 primarybuf
->playpos
+= len
;
2191 if (primarybuf
->playpos
>= primarybuf
->buflen
)
2192 primarybuf
->playpos
%= primarybuf
->buflen
;
2193 primarybuf
->writepos
= primarybuf
->playpos
+ DSOUND_FRAGLEN
;
2194 if (primarybuf
->writepos
>= primarybuf
->buflen
)
2195 primarybuf
->writepos
%= primarybuf
->buflen
;
2197 LeaveCriticalSection(&(primarybuf
->lock
));
2201 static DWORD WINAPI
DSOUND_thread(LPVOID arg
)
2205 TRACE(dsound
,"dsound is at pid %d\n",getpid());
2208 WARN(dsound
,"DSOUND thread giving up.\n");
2212 WARN(dsound
,"DSOUND father died? Giving up.\n");
2215 /* RACE: dsound could be deleted */
2216 IDirectSound_AddRef((LPDIRECTSOUND
)dsound
);
2217 if (primarybuf
== NULL
) {
2218 /* Should never happen */
2219 WARN(dsound
, "Lost the primary buffer!\n");
2220 IDirectSound_Release((LPDIRECTSOUND
)dsound
);
2225 EnterCriticalSection(&(primarybuf
->lock
));
2226 len
= DSOUND_MixPrimary();
2227 LeaveCriticalSection(&(primarybuf
->lock
));
2230 if (primarybuf
->playing
)
2231 len
= DSOUND_FRAGLEN
> len
? DSOUND_FRAGLEN
: len
;
2233 /* This does all the work */
2234 DSOUND_OutputPrimary(len
);
2236 /* no buffers playing -- close and wait */
2238 DSOUND_CloseAudio();
2241 IDirectSound_Release((LPDIRECTSOUND
)dsound
);
2246 #endif /* HAVE_OSS */
2248 HRESULT WINAPI
DirectSoundCreate(REFGUID lpGUID
,LPDIRECTSOUND
*ppDS
,IUnknown
*pUnkOuter
)
2250 IDirectSoundImpl
** ippDS
=(IDirectSoundImpl
**)ppDS
;
2252 TRACE(dsound
,"(%p,%p,%p)\n",lpGUID
,ippDS
,pUnkOuter
);
2254 TRACE(dsound
,"DirectSoundCreate (%p)\n", ippDS
);
2259 return DSERR_INVALIDPARAM
;
2262 IDirectSound_AddRef((LPDIRECTSOUND
)dsound
);
2267 /* Check that we actually have audio capabilities */
2268 /* If we do, whether it's busy or not, we continue */
2269 /* otherwise we return with DSERR_NODRIVER */
2271 audiofd
= open("/dev/audio",O_WRONLY
);
2272 if (audiofd
== -1) {
2273 if (errno
== ENODEV
) {
2274 MSG("No sound hardware found.\n");
2275 return DSERR_NODRIVER
;
2276 } else if (errno
== EBUSY
) {
2277 MSG("Sound device busy, will keep trying.\n");
2279 MSG("Unexpected error while checking for sound support.\n");
2280 return DSERR_GENERIC
;
2287 *ippDS
= (IDirectSoundImpl
*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundImpl
));
2289 return DSERR_OUTOFMEMORY
;
2292 (*ippDS
)->lpvtbl
= &dsvt
;
2293 (*ippDS
)->buffers
= NULL
;
2294 (*ippDS
)->nrofbuffers
= 0;
2296 (*ippDS
)->wfx
.wFormatTag
= 1;
2297 (*ippDS
)->wfx
.nChannels
= 2;
2298 (*ippDS
)->wfx
.nSamplesPerSec
= 22050;
2299 (*ippDS
)->wfx
.nAvgBytesPerSec
= 44100;
2300 (*ippDS
)->wfx
.nBlockAlign
= 2;
2301 (*ippDS
)->wfx
.wBitsPerSample
= 8;
2308 if (primarybuf
== NULL
) {
2312 dsbd
.dwSize
= sizeof(DSBUFFERDESC
);
2313 dsbd
.dwFlags
= DSBCAPS_PRIMARYBUFFER
;
2314 dsbd
.dwBufferBytes
= 0;
2315 dsbd
.lpwfxFormat
= &(dsound
->wfx
);
2316 hr
= IDirectSound_CreateSoundBuffer(*ppDS
, &dsbd
, (LPDIRECTSOUNDBUFFER
*)&primarybuf
, NULL
);
2319 dsound
->primary
= primarybuf
;
2321 memset(primarybuf
->buffer
, 128, primarybuf
->buflen
);
2322 hnd
= CreateThread(NULL
,0,DSOUND_thread
,0,0,&xid
);
2326 MessageBoxA(0,"DirectSound needs the Open Sound System Driver, which has not been found by ./configure.","WINE DirectSound",MB_OK
|MB_ICONSTOP
);
2327 return DSERR_NODRIVER
;
2331 /*******************************************************************************
2332 * DirectSound ClassFactory
2336 /* IUnknown fields */
2337 ICOM_VTABLE(IClassFactory
)* lpvtbl
;
2339 } IClassFactoryImpl
;
2341 static HRESULT WINAPI
2342 DSCF_QueryInterface(LPCLASSFACTORY iface
,REFIID riid
,LPVOID
*ppobj
) {
2343 ICOM_THIS(IClassFactoryImpl
,iface
);
2347 WINE_StringFromCLSID(riid
,buf
);
2349 sprintf(buf
,"<guid-0x%04x>",LOWORD(riid
));
2350 FIXME(dsound
,"(%p)->(%s,%p),stub!\n",This
,buf
,ppobj
);
2351 return E_NOINTERFACE
;
2355 DSCF_AddRef(LPCLASSFACTORY iface
) {
2356 ICOM_THIS(IClassFactoryImpl
,iface
);
2357 return ++(This
->ref
);
2360 static ULONG WINAPI
DSCF_Release(LPCLASSFACTORY iface
) {
2361 ICOM_THIS(IClassFactoryImpl
,iface
);
2362 /* static class, won't be freed */
2363 return --(This
->ref
);
2366 static HRESULT WINAPI
DSCF_CreateInstance(
2367 LPCLASSFACTORY iface
,LPUNKNOWN pOuter
,REFIID riid
,LPVOID
*ppobj
2369 ICOM_THIS(IClassFactoryImpl
,iface
);
2372 WINE_StringFromCLSID(riid
,buf
);
2373 TRACE(dsound
,"(%p)->(%p,%s,%p)\n",This
,pOuter
,buf
,ppobj
);
2374 if (!memcmp(riid
,&IID_IDirectSound
,sizeof(IID_IDirectSound
))) {
2375 /* FIXME: reuse already created dsound if present? */
2376 return DirectSoundCreate(riid
,(LPDIRECTSOUND
*)ppobj
,pOuter
);
2378 return E_NOINTERFACE
;
2381 static HRESULT WINAPI
DSCF_LockServer(LPCLASSFACTORY iface
,BOOL dolock
) {
2382 ICOM_THIS(IClassFactoryImpl
,iface
);
2383 FIXME(dsound
,"(%p)->(%d),stub!\n",This
,dolock
);
2387 static ICOM_VTABLE(IClassFactory
) DSCF_Vtbl
= {
2388 DSCF_QueryInterface
,
2391 DSCF_CreateInstance
,
2394 static IClassFactoryImpl DSOUND_CF
= {&DSCF_Vtbl
, 1 };
2396 /*******************************************************************************
2397 * DllGetClassObject [DSOUND.4]
2398 * Retrieves class object from a DLL object
2401 * Docs say returns STDAPI
2404 * rclsid [I] CLSID for the class object
2405 * riid [I] Reference to identifier of interface for class object
2406 * ppv [O] Address of variable to receive interface pointer for riid
2410 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
2413 DWORD WINAPI
DSOUND_DllGetClassObject(REFCLSID rclsid
,REFIID riid
,LPVOID
*ppv
)
2415 char buf
[80],xbuf
[80];
2418 WINE_StringFromCLSID(rclsid
,xbuf
);
2420 sprintf(xbuf
,"<guid-0x%04x>",LOWORD(rclsid
));
2422 WINE_StringFromCLSID(riid
,buf
);
2424 sprintf(buf
,"<guid-0x%04x>",LOWORD(riid
));
2425 WINE_StringFromCLSID(riid
,xbuf
);
2426 TRACE(dsound
, "(%p,%p,%p)\n", xbuf
, buf
, ppv
);
2427 if (!memcmp(riid
,&IID_IClassFactory
,sizeof(IID_IClassFactory
))) {
2428 *ppv
= (LPVOID
)&DSOUND_CF
;
2429 IClassFactory_AddRef((IClassFactory
*)*ppv
);
2432 FIXME(dsound
, "(%p,%p,%p): no interface found.\n", xbuf
, buf
, ppv
);
2433 return E_NOINTERFACE
;
2437 /*******************************************************************************
2438 * DllCanUnloadNow [DSOUND.3] Determines whether the DLL is in use.
2444 DWORD WINAPI
DSOUND_DllCanUnloadNow(void)
2446 FIXME(dsound
, "(void): stub\n");