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"
73 # include <sys/ioctl.h>
74 # ifdef HAVE_MACHINE_SOUNDCARD_H
75 # include <machine/soundcard.h>
77 # ifdef HAVE_SYS_SOUNDCARD_H
78 # include <sys/soundcard.h>
81 /* #define USE_DSOUND3D 1 */
83 #define DSOUND_FRAGLEN (primarybuf->wfx.nAvgBytesPerSec >> 4)
84 #define DSOUND_FREQSHIFT (14)
86 static int audiofd
= -1;
87 static int audioOK
= 0;
89 static LPDIRECTSOUND dsound
= NULL
;
91 static LPDIRECTSOUNDBUFFER primarybuf
= NULL
;
93 static int DSOUND_setformat(LPWAVEFORMATEX wfex
);
94 static void DSOUND_CheckEvent(IDirectSoundBuffer
*dsb
, int len
);
95 static void DSOUND_CloseAudio(void);
99 HRESULT WINAPI
DirectSoundEnumerateA(
100 LPDSENUMCALLBACKA enumcb
,
103 TRACE(dsound
, "enumcb = %p, context = %p\n", enumcb
, context
);
107 enumcb(NULL
,"WINE DirectSound using Open Sound System",
115 static void _dump_DSBCAPS(DWORD xmask
) {
120 #define FE(x) { x, #x },
121 FE(DSBCAPS_PRIMARYBUFFER
)
123 FE(DSBCAPS_LOCHARDWARE
)
124 FE(DSBCAPS_LOCSOFTWARE
)
125 FE(DSBCAPS_CTRLFREQUENCY
)
127 FE(DSBCAPS_CTRLVOLUME
)
128 FE(DSBCAPS_CTRLDEFAULT
)
130 FE(DSBCAPS_STICKYFOCUS
)
131 FE(DSBCAPS_GETCURRENTPOSITION2
)
135 for (i
=0;i
<sizeof(flags
)/sizeof(flags
[0]);i
++)
136 if (flags
[i
].mask
& xmask
)
137 fprintf(stderr
,"%s ",flags
[i
].name
);
140 /*******************************************************************************
141 * IDirectSound3DBuffer
144 /* IUnknown methods */
145 static HRESULT WINAPI
IDirectSound3DBuffer_QueryInterface(
146 LPDIRECTSOUND3DBUFFER
this, REFIID riid
, LPVOID
*ppobj
)
150 WINE_StringFromCLSID(riid
,xbuf
);
151 TRACE(dsound
,"(%p,%s,%p)\n",this,xbuf
,ppobj
);
155 static ULONG WINAPI
IDirectSound3DBuffer_AddRef(LPDIRECTSOUND3DBUFFER
this)
161 static ULONG WINAPI
IDirectSound3DBuffer_Release(LPDIRECTSOUND3DBUFFER
this)
166 HeapFree(GetProcessHeap(),0,this->buffer
);
167 HeapFree(GetProcessHeap(),0,this);
172 /* IDirectSound3DBuffer methods */
173 static HRESULT WINAPI
IDirectSound3DBuffer_GetAllParameters(
174 LPDIRECTSOUND3DBUFFER
this,
175 LPDS3DBUFFER lpDs3dBuffer
)
177 FIXME(dsound
,"stub\n");
181 static HRESULT WINAPI
IDirectSound3DBuffer_GetConeAngles(
182 LPDIRECTSOUND3DBUFFER
this,
183 LPDWORD lpdwInsideConeAngle
,
184 LPDWORD lpdwOutsideConeAngle
)
186 FIXME(dsound
,"stub\n");
190 static HRESULT WINAPI
IDirectSound3DBuffer_GetConeOrientation(
191 LPDIRECTSOUND3DBUFFER
this,
192 LPD3DVECTOR lpvConeOrientation
)
194 FIXME(dsound
,"stub\n");
198 static HRESULT WINAPI
IDirectSound3DBuffer_GetConeOutsideVolume(
199 LPDIRECTSOUND3DBUFFER
this,
200 LPLONG lplConeOutsideVolume
)
202 FIXME(dsound
,"stub\n");
206 static HRESULT WINAPI
IDirectSound3DBuffer_GetMaxDistance(
207 LPDIRECTSOUND3DBUFFER
this,
208 LPD3DVALUE lpfMaxDistance
)
210 FIXME(dsound
,"stub\n");
214 static HRESULT WINAPI
IDirectSound3DBuffer_GetMinDistance(
215 LPDIRECTSOUND3DBUFFER
this,
216 LPD3DVALUE lpfMinDistance
)
218 FIXME(dsound
,"stub\n");
222 static HRESULT WINAPI
IDirectSound3DBuffer_GetMode(
223 LPDIRECTSOUND3DBUFFER
this,
226 FIXME(dsound
,"stub\n");
230 static HRESULT WINAPI
IDirectSound3DBuffer_GetPosition(
231 LPDIRECTSOUND3DBUFFER
this,
232 LPD3DVECTOR lpvPosition
)
234 FIXME(dsound
,"stub\n");
238 static HRESULT WINAPI
IDirectSound3DBuffer_GetVelocity(
239 LPDIRECTSOUND3DBUFFER
this,
240 LPD3DVECTOR lpvVelocity
)
242 FIXME(dsound
,"stub\n");
246 static HRESULT WINAPI
IDirectSound3DBuffer_SetAllParameters(
247 LPDIRECTSOUND3DBUFFER
this,
248 LPCDS3DBUFFER lpcDs3dBuffer
,
251 FIXME(dsound
,"stub\n");
255 static HRESULT WINAPI
IDirectSound3DBuffer_SetConeAngles(
256 LPDIRECTSOUND3DBUFFER
this,
257 DWORD dwInsideConeAngle
,
258 DWORD dwOutsideConeAngle
,
261 FIXME(dsound
,"stub\n");
265 static HRESULT WINAPI
IDirectSound3DBuffer_SetConeOrientation(
266 LPDIRECTSOUND3DBUFFER
this,
267 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
270 FIXME(dsound
,"stub\n");
274 static HRESULT WINAPI
IDirectSound3DBuffer_SetConeOutsideVolume(
275 LPDIRECTSOUND3DBUFFER
this,
276 LONG lConeOutsideVolume
,
279 FIXME(dsound
,"stub\n");
283 static HRESULT WINAPI
IDirectSound3DBuffer_SetMaxDistance(
284 LPDIRECTSOUND3DBUFFER
this,
285 D3DVALUE fMaxDistance
,
288 FIXME(dsound
,"stub\n");
292 static HRESULT WINAPI
IDirectSound3DBuffer_SetMinDistance(
293 LPDIRECTSOUND3DBUFFER
this,
294 D3DVALUE fMinDistance
,
297 FIXME(dsound
,"stub\n");
301 static HRESULT WINAPI
IDirectSound3DBuffer_SetMode(
302 LPDIRECTSOUND3DBUFFER
this,
306 TRACE(dsound
, "mode = %lx\n", dwMode
);
307 this->ds3db
.dwMode
= dwMode
;
311 static HRESULT WINAPI
IDirectSound3DBuffer_SetPosition(
312 LPDIRECTSOUND3DBUFFER
this,
313 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
316 FIXME(dsound
,"stub\n");
320 static HRESULT WINAPI
IDirectSound3DBuffer_SetVelocity(
321 LPDIRECTSOUND3DBUFFER
this,
322 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
325 FIXME(dsound
,"stub\n");
329 IDirectSound3DBuffer_VTable ds3dbvt
= {
330 /* IUnknown methods */
331 IDirectSound3DBuffer_QueryInterface
,
332 IDirectSound3DBuffer_AddRef
,
333 IDirectSound3DBuffer_Release
,
334 /* IDirectSound3DBuffer methods */
335 IDirectSound3DBuffer_GetAllParameters
,
336 IDirectSound3DBuffer_GetConeAngles
,
337 IDirectSound3DBuffer_GetConeOrientation
,
338 IDirectSound3DBuffer_GetConeOutsideVolume
,
339 IDirectSound3DBuffer_GetMaxDistance
,
340 IDirectSound3DBuffer_GetMinDistance
,
341 IDirectSound3DBuffer_GetMode
,
342 IDirectSound3DBuffer_GetPosition
,
343 IDirectSound3DBuffer_GetVelocity
,
344 IDirectSound3DBuffer_SetAllParameters
,
345 IDirectSound3DBuffer_SetConeAngles
,
346 IDirectSound3DBuffer_SetConeOrientation
,
347 IDirectSound3DBuffer_SetConeOutsideVolume
,
348 IDirectSound3DBuffer_SetMaxDistance
,
349 IDirectSound3DBuffer_SetMinDistance
,
350 IDirectSound3DBuffer_SetMode
,
351 IDirectSound3DBuffer_SetPosition
,
352 IDirectSound3DBuffer_SetVelocity
,
356 static int DSOUND_Create3DBuffer(LPDIRECTSOUNDBUFFER dsb
)
358 DWORD i
, temp
, iSize
, oSize
, offset
;
359 LPBYTE bIbuf
, bObuf
, bTbuf
= NULL
;
360 LPWORD wIbuf
, wObuf
, wTbuf
= NULL
;
362 /* Inside DirectX says it's stupid but allowed */
363 if (dsb
->wfx
.nChannels
== 2) {
364 /* Convert to mono */
365 if (dsb
->wfx
.wBitsPerSample
== 16) {
366 iSize
= dsb
->buflen
/ 4;
367 wTbuf
= malloc(dsb
->buflen
/ 2);
369 return DSERR_OUTOFMEMORY
;
370 for (i
= 0; i
< iSize
; i
++)
371 wTbuf
[i
] = (dsb
->buffer
[i
] + dsb
->buffer
[(i
* 2) + 1]) / 2;
374 iSize
= dsb
->buflen
/ 2;
375 bTbuf
= malloc(dsb
->buflen
/ 2);
377 return DSERR_OUTOFMEMORY
;
378 for (i
= 0; i
< iSize
; i
++)
379 bTbuf
[i
] = (dsb
->buffer
[i
] + dsb
->buffer
[(i
* 2) + 1]) / 2;
383 if (dsb
->wfx
.wBitsPerSample
== 16) {
384 iSize
= dsb
->buflen
/ 2;
385 wIbuf
= (LPWORD
) dsb
->buffer
;
387 bIbuf
= (LPBYTE
) dsb
->buffer
;
392 if (primarybuf
->wfx
.wBitsPerSample
== 16) {
393 wObuf
= (LPWORD
) dsb
->ds3db
->buffer
;
394 oSize
= dsb
->ds3db
->buflen
/ 2;
396 bObuf
= (LPBYTE
) dsb
->ds3db
->buffer
;
397 oSize
= dsb
->ds3db
->buflen
;
400 offset
= primarybuf
->wfx
.nSamplesPerSec
/ 100; /* 10ms */
401 if (primarybuf
->wfx
.wBitsPerSample
== 16 && dsb
->wfx
.wBitsPerSample
== 16)
402 for (i
= 0; i
< iSize
; i
++) {
405 temp
+= wIbuf
[i
- offset
] >> 9;
407 temp
+= wIbuf
[i
+ iSize
- offset
] >> 9;
409 wObuf
[(i
* 2) + 1] = temp
;
411 else if (primarybuf
->wfx
.wBitsPerSample
== 8 && dsb
->wfx
.wBitsPerSample
== 8)
412 for (i
= 0; i
< iSize
; i
++) {
415 temp
+= bIbuf
[i
- offset
] >> 5;
417 temp
+= bIbuf
[i
+ iSize
- offset
] >> 5;
419 bObuf
[(i
* 2) + 1] = temp
;
430 /*******************************************************************************
431 * IDirectSound3DListener
434 /* IUnknown methods */
435 static HRESULT WINAPI
IDirectSound3DListener_QueryInterface(
436 LPDIRECTSOUND3DLISTENER
this, REFIID riid
, LPVOID
*ppobj
)
440 WINE_StringFromCLSID(riid
,xbuf
);
441 TRACE(dsound
,"(%p,%s,%p)\n",this,xbuf
,ppobj
);
445 static ULONG WINAPI
IDirectSound3DListener_AddRef(LPDIRECTSOUND3DLISTENER
this)
451 static ULONG WINAPI
IDirectSound3DListener_Release(LPDIRECTSOUND3DLISTENER
this)
457 /* IDirectSound3DListener methods */
458 static HRESULT WINAPI
IDirectSound3DListener_GetAllParameter(
459 LPDIRECTSOUND3DLISTENER
this,
460 LPDS3DLISTENER lpDS3DL
)
462 FIXME(dsound
,"stub\n");
466 static HRESULT WINAPI
IDirectSound3DListener_GetDistanceFactor(
467 LPDIRECTSOUND3DLISTENER
this,
468 LPD3DVALUE lpfDistanceFactor
)
470 FIXME(dsound
,"stub\n");
474 static HRESULT WINAPI
IDirectSound3DListener_GetDopplerFactor(
475 LPDIRECTSOUND3DLISTENER
this,
476 LPD3DVALUE lpfDopplerFactor
)
478 FIXME(dsound
,"stub\n");
482 static HRESULT WINAPI
IDirectSound3DListener_GetOrientation(
483 LPDIRECTSOUND3DLISTENER
this,
484 LPD3DVECTOR lpvOrientFront
,
485 LPD3DVECTOR lpvOrientTop
)
487 FIXME(dsound
,"stub\n");
491 static HRESULT WINAPI
IDirectSound3DListener_GetPosition(
492 LPDIRECTSOUND3DLISTENER
this,
493 LPD3DVECTOR lpvPosition
)
495 FIXME(dsound
,"stub\n");
499 static HRESULT WINAPI
IDirectSound3DListener_GetRolloffFactor(
500 LPDIRECTSOUND3DLISTENER
this,
501 LPD3DVALUE lpfRolloffFactor
)
503 FIXME(dsound
,"stub\n");
507 static HRESULT WINAPI
IDirectSound3DListener_GetVelocity(
508 LPDIRECTSOUND3DLISTENER
this,
509 LPD3DVECTOR lpvVelocity
)
511 FIXME(dsound
,"stub\n");
515 static HRESULT WINAPI
IDirectSound3DListener_SetAllParameters(
516 LPDIRECTSOUND3DLISTENER
this,
517 LPCDS3DLISTENER lpcDS3DL
,
520 FIXME(dsound
,"stub\n");
524 static HRESULT WINAPI
IDirectSound3DListener_SetDistanceFactor(
525 LPDIRECTSOUND3DLISTENER
this,
526 D3DVALUE fDistanceFactor
,
529 FIXME(dsound
,"stub\n");
533 static HRESULT WINAPI
IDirectSound3DListener_SetDopplerFactor(
534 LPDIRECTSOUND3DLISTENER
this,
535 D3DVALUE fDopplerFactor
,
538 FIXME(dsound
,"stub\n");
542 static HRESULT WINAPI
IDirectSound3DListener_SetOrientation(
543 LPDIRECTSOUND3DLISTENER
this,
544 D3DVALUE xFront
, D3DVALUE yFront
, D3DVALUE zFront
,
545 D3DVALUE xTop
, D3DVALUE yTop
, D3DVALUE zTop
,
548 FIXME(dsound
,"stub\n");
552 static HRESULT WINAPI
IDirectSound3DListener_SetPosition(
553 LPDIRECTSOUND3DLISTENER
this,
554 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
557 FIXME(dsound
,"stub\n");
561 static HRESULT WINAPI
IDirectSound3DListener_SetRolloffFactor(
562 LPDIRECTSOUND3DLISTENER
this,
563 D3DVALUE fRolloffFactor
,
566 FIXME(dsound
,"stub\n");
570 static HRESULT WINAPI
IDirectSound3DListener_SetVelocity(
571 LPDIRECTSOUND3DLISTENER
this,
572 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
575 FIXME(dsound
,"stub\n");
579 static HRESULT WINAPI
IDirectSound3DListener_CommitDeferredSettings(
580 LPDIRECTSOUND3DLISTENER
this)
583 FIXME(dsound
,"stub\n");
587 IDirectSound3DListener_VTable ds3dlvt
= {
588 /* IUnknown methods */
589 IDirectSound3DListener_QueryInterface
,
590 IDirectSound3DListener_AddRef
,
591 IDirectSound3DListener_Release
,
592 /* IDirectSound3DListener methods */
593 IDirectSound3DListener_GetAllParameter
,
594 IDirectSound3DListener_GetDistanceFactor
,
595 IDirectSound3DListener_GetDopplerFactor
,
596 IDirectSound3DListener_GetOrientation
,
597 IDirectSound3DListener_GetPosition
,
598 IDirectSound3DListener_GetRolloffFactor
,
599 IDirectSound3DListener_GetVelocity
,
600 IDirectSound3DListener_SetAllParameters
,
601 IDirectSound3DListener_SetDistanceFactor
,
602 IDirectSound3DListener_SetDopplerFactor
,
603 IDirectSound3DListener_SetOrientation
,
604 IDirectSound3DListener_SetPosition
,
605 IDirectSound3DListener_SetRolloffFactor
,
606 IDirectSound3DListener_SetVelocity
,
607 IDirectSound3DListener_CommitDeferredSettings
,
610 /*******************************************************************************
613 static HRESULT WINAPI
IDirectSoundNotify_QueryInterface(
614 LPDIRECTSOUNDNOTIFY
this,REFIID riid
,LPVOID
*ppobj
618 WINE_StringFromCLSID(riid
,xbuf
);
619 TRACE(dsound
,"(%p,%s,%p)\n",this,xbuf
,ppobj
);
623 static ULONG WINAPI
IDirectSoundNotify_AddRef(LPDIRECTSOUNDNOTIFY
this) {
624 return ++(this->ref
);
627 static ULONG WINAPI
IDirectSoundNotify_Release(LPDIRECTSOUNDNOTIFY
this) {
630 this->dsb
->lpvtbl
->fnRelease(this->dsb
);
631 HeapFree(GetProcessHeap(),0,this);
637 static HRESULT WINAPI
IDirectSoundNotify_SetNotificationPositions(
638 LPDIRECTSOUNDNOTIFY
this,DWORD howmuch
,LPCDSBPOSITIONNOTIFY notify
642 if (TRACE_ON(dsound
)) {
643 TRACE(dsound
,"(%p,0x%08lx,%p)\n",this,howmuch
,notify
);
644 for (i
=0;i
<howmuch
;i
++)
645 TRACE(dsound
,"notify at %ld to 0x%08lx\n",
646 notify
[i
].dwOffset
,(DWORD
)notify
[i
].hEventNotify
);
648 this->dsb
->notifies
= HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,this->dsb
->notifies
,(this->dsb
->nrofnotifies
+howmuch
)*sizeof(DSBPOSITIONNOTIFY
));
649 memcpy( this->dsb
->notifies
+this->dsb
->nrofnotifies
,
651 howmuch
*sizeof(DSBPOSITIONNOTIFY
)
653 this->dsb
->nrofnotifies
+=howmuch
;
658 IDirectSoundNotify_VTable dsnvt
= {
659 IDirectSoundNotify_QueryInterface
,
660 IDirectSoundNotify_AddRef
,
661 IDirectSoundNotify_Release
,
662 IDirectSoundNotify_SetNotificationPositions
,
665 /*******************************************************************************
669 /* This sets this format for the <em>Primary Buffer Only</em> */
670 /* See file:///cdrom/sdk52/docs/worddoc/dsound.doc page 120 */
671 static HRESULT WINAPI
IDirectSoundBuffer_SetFormat(
672 LPDIRECTSOUNDBUFFER
this,LPWAVEFORMATEX wfex
674 LPDIRECTSOUNDBUFFER
*dsb
;
677 /* Let's be pedantic! */
678 if ((wfex
== NULL
) ||
679 (wfex
->wFormatTag
!= WAVE_FORMAT_PCM
) ||
680 (wfex
->nChannels
< 1) || (wfex
->nChannels
> 2) ||
681 (wfex
->nSamplesPerSec
< 1) ||
682 (wfex
->nBlockAlign
< 1) || (wfex
->nChannels
> 4) ||
683 ((wfex
->wBitsPerSample
!= 8) && (wfex
->wBitsPerSample
!= 16))) {
684 TRACE(dsound
, "failed pedantic check!\n");
685 return DSERR_INVALIDPARAM
;
689 EnterCriticalSection(&(primarybuf
->lock
));
691 if (primarybuf
->wfx
.nSamplesPerSec
!= wfex
->nSamplesPerSec
) {
692 dsb
= dsound
->buffers
;
693 for (i
= 0; i
< dsound
->nrofbuffers
; i
++, dsb
++) {
695 EnterCriticalSection(&((*dsb
)->lock
));
697 (*dsb
)->freqAdjust
= ((*dsb
)->freq
<< DSOUND_FREQSHIFT
) /
698 wfex
->nSamplesPerSec
;
700 LeaveCriticalSection(&((*dsb
)->lock
));
705 memcpy(&(primarybuf
->wfx
), wfex
, sizeof(primarybuf
->wfx
));
707 TRACE(dsound
,"(formattag=0x%04x,chans=%d,samplerate=%ld"
708 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
709 wfex
->wFormatTag
, wfex
->nChannels
, wfex
->nSamplesPerSec
,
710 wfex
->nAvgBytesPerSec
, wfex
->nBlockAlign
,
711 wfex
->wBitsPerSample
, wfex
->cbSize
);
713 primarybuf
->wfx
.nAvgBytesPerSec
=
714 this->wfx
.nSamplesPerSec
* this->wfx
.nBlockAlign
;
718 LeaveCriticalSection(&(primarybuf
->lock
));
724 static HRESULT WINAPI
IDirectSoundBuffer_SetVolume(
725 LPDIRECTSOUNDBUFFER
this,LONG vol
729 TRACE(dsound
,"(%p,%ld)\n",this,vol
);
731 /* I'm not sure if we need this for primary buffer */
732 if (!(this->dsbd
.dwFlags
& DSBCAPS_CTRLVOLUME
))
733 return DSERR_CONTROLUNAVAIL
;
735 if ((vol
> DSBVOLUME_MAX
) || (vol
< DSBVOLUME_MIN
))
736 return DSERR_INVALIDPARAM
;
738 /* This needs to adjust the soundcard volume when */
739 /* called for the primary buffer */
740 if (this->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
741 FIXME(dsound
, "Volume control of primary unimplemented.\n");
747 EnterCriticalSection(&(this->lock
));
751 temp
= (double) (this->volume
- (this->pan
> 0 ? this->pan
: 0));
752 this->lVolAdjust
= (ULONG
) (pow(2.0, temp
/ 600.0) * 32768.0);
753 temp
= (double) (this->volume
+ (this->pan
< 0 ? this->pan
: 0));
754 this->rVolAdjust
= (ULONG
) (pow(2.0, temp
/ 600.0) * 32768.0);
756 LeaveCriticalSection(&(this->lock
));
759 TRACE(dsound
, "left = %lx, right = %lx\n", this->lVolAdjust
, this->rVolAdjust
);
764 static HRESULT WINAPI
IDirectSoundBuffer_GetVolume(
765 LPDIRECTSOUNDBUFFER
this,LPLONG vol
767 TRACE(dsound
,"(%p,%p)\n",this,vol
);
770 return DSERR_INVALIDPARAM
;
776 static HRESULT WINAPI
IDirectSoundBuffer_SetFrequency(
777 LPDIRECTSOUNDBUFFER
this,DWORD freq
779 TRACE(dsound
,"(%p,%ld)\n",this,freq
);
781 /* You cannot set the frequency of the primary buffer */
782 if (!(this->dsbd
.dwFlags
& DSBCAPS_CTRLFREQUENCY
) ||
783 (this->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
))
784 return DSERR_CONTROLUNAVAIL
;
786 if ((freq
< DSBFREQUENCY_MIN
) || (freq
> DSBFREQUENCY_MAX
))
787 return DSERR_INVALIDPARAM
;
790 EnterCriticalSection(&(this->lock
));
793 this->freqAdjust
= (freq
<< DSOUND_FREQSHIFT
) / primarybuf
->wfx
.nSamplesPerSec
;
794 this->nAvgBytesPerSec
= freq
* this->wfx
.nBlockAlign
;
796 LeaveCriticalSection(&(this->lock
));
802 static HRESULT WINAPI
IDirectSoundBuffer_Play(
803 LPDIRECTSOUNDBUFFER
this,DWORD reserved1
,DWORD reserved2
,DWORD flags
805 TRACE(dsound
,"(%p,%08lx,%08lx,%08lx)\n",
806 this,reserved1
,reserved2
,flags
808 this->playflags
= flags
;
813 static HRESULT WINAPI
IDirectSoundBuffer_Stop(LPDIRECTSOUNDBUFFER
this)
815 TRACE(dsound
,"(%p)\n",this);
818 EnterCriticalSection(&(this->lock
));
821 DSOUND_CheckEvent(this, 0);
823 LeaveCriticalSection(&(this->lock
));
829 static DWORD WINAPI
IDirectSoundBuffer_AddRef(LPDIRECTSOUNDBUFFER
this) {
830 /* TRACE(dsound,"(%p) ref was %ld\n",this, this->ref); */
832 return ++(this->ref
);
834 static DWORD WINAPI
IDirectSoundBuffer_Release(LPDIRECTSOUNDBUFFER
this) {
837 /* TRACE(dsound,"(%p) ref was %ld\n",this, this->ref); */
842 for (i
=0;i
<this->dsound
->nrofbuffers
;i
++)
843 if (this->dsound
->buffers
[i
] == this)
845 if (i
< this->dsound
->nrofbuffers
) {
846 /* Put the last buffer of the list in the (now empty) position */
847 this->dsound
->buffers
[i
] = this->dsound
->buffers
[this->dsound
->nrofbuffers
- 1];
848 this->dsound
->buffers
= HeapReAlloc(GetProcessHeap(),0,this->dsound
->buffers
,sizeof(LPDIRECTSOUNDBUFFER
)*this->dsound
->nrofbuffers
);
849 this->dsound
->nrofbuffers
--;
850 this->dsound
->lpvtbl
->fnRelease(this->dsound
);
853 DeleteCriticalSection(&(this->lock
));
855 if (this->ds3db
&& this->ds3db
->lpvtbl
)
856 this->ds3db
->lpvtbl
->fnRelease(this->ds3db
);
859 /* this is a duplicate buffer */
860 this->parent
->lpvtbl
->fnRelease(this->parent
);
862 /* this is a toplevel buffer */
863 HeapFree(GetProcessHeap(),0,this->buffer
);
865 HeapFree(GetProcessHeap(),0,this);
867 if (this == primarybuf
)
873 static HRESULT WINAPI
IDirectSoundBuffer_GetCurrentPosition(
874 LPDIRECTSOUNDBUFFER
this,LPDWORD playpos
,LPDWORD writepos
876 TRACE(dsound
,"(%p,%p,%p)\n",this,playpos
,writepos
);
877 if (playpos
) *playpos
= this->playpos
;
878 if (writepos
) *writepos
= this->writepos
;
879 TRACE(dsound
, "playpos = %ld, writepos = %ld\n", *playpos
, *writepos
);
883 static HRESULT WINAPI
IDirectSoundBuffer_GetStatus(
884 LPDIRECTSOUNDBUFFER
this,LPDWORD status
886 TRACE(dsound
,"(%p,%p)\n",this,status
);
889 return DSERR_INVALIDPARAM
;
893 *status
|= DSBSTATUS_PLAYING
;
894 if (this->playflags
& DSBPLAY_LOOPING
)
895 *status
|= DSBSTATUS_LOOPING
;
901 static HRESULT WINAPI
IDirectSoundBuffer_GetFormat(
902 LPDIRECTSOUNDBUFFER
this,LPWAVEFORMATEX lpwf
,DWORD wfsize
,LPDWORD wfwritten
904 TRACE(dsound
,"(%p,%p,%ld,%p)\n",this,lpwf
,wfsize
,wfwritten
);
906 if (wfsize
>sizeof(this->wfx
))
907 wfsize
= sizeof(this->wfx
);
908 if (lpwf
) { /* NULL is valid */
909 memcpy(lpwf
,&(this->wfx
),wfsize
);
914 *wfwritten
= sizeof(this->wfx
);
916 return DSERR_INVALIDPARAM
;
921 static HRESULT WINAPI
IDirectSoundBuffer_Lock(
922 LPDIRECTSOUNDBUFFER
this,DWORD writecursor
,DWORD writebytes
,LPVOID lplpaudioptr1
,LPDWORD audiobytes1
,LPVOID lplpaudioptr2
,LPDWORD audiobytes2
,DWORD flags
925 TRACE(dsound
,"(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx)\n",
935 if (flags
& DSBLOCK_FROMWRITECURSOR
)
936 writecursor
+= this->writepos
;
937 if (flags
& DSBLOCK_ENTIREBUFFER
)
938 writebytes
= this->buflen
;
939 if (writebytes
> this->buflen
)
940 writebytes
= this->buflen
;
942 assert(audiobytes1
!=audiobytes2
);
943 assert(lplpaudioptr1
!=lplpaudioptr2
);
944 if (writecursor
+writebytes
<= this->buflen
) {
945 *(LPBYTE
*)lplpaudioptr1
= this->buffer
+writecursor
;
946 *audiobytes1
= writebytes
;
948 *(LPBYTE
*)lplpaudioptr2
= NULL
;
951 TRACE(dsound
,"->%ld.0\n",writebytes
);
953 *(LPBYTE
*)lplpaudioptr1
= this->buffer
+writecursor
;
954 *audiobytes1
= this->buflen
-writecursor
;
956 *(LPBYTE
*)lplpaudioptr2
= this->buffer
;
958 *audiobytes2
= writebytes
-(this->buflen
-writecursor
);
959 TRACE(dsound
,"->%ld.%ld\n",*audiobytes1
,audiobytes2
?*audiobytes2
:0);
961 /* No. See file:///cdrom/sdk52/docs/worddoc/dsound.doc page 21 */
962 /* this->writepos=(writecursor+writebytes)%this->buflen; */
966 static HRESULT WINAPI
IDirectSoundBuffer_SetCurrentPosition(
967 LPDIRECTSOUNDBUFFER
this,DWORD newpos
969 TRACE(dsound
,"(%p,%ld)\n",this,newpos
);
972 EnterCriticalSection(&(this->lock
));
974 this->playpos
= newpos
;
976 LeaveCriticalSection(&(this->lock
));
982 static HRESULT WINAPI
IDirectSoundBuffer_SetPan(
983 LPDIRECTSOUNDBUFFER
this,LONG pan
987 TRACE(dsound
,"(%p,%ld)\n",this,pan
);
989 if ((pan
> DSBPAN_RIGHT
) || (pan
< DSBPAN_LEFT
))
990 return DSERR_INVALIDPARAM
;
992 /* You cannot set the pan of the primary buffer */
993 /* and you cannot use both pan and 3D controls */
994 if (!(this->dsbd
.dwFlags
& DSBCAPS_CTRLPAN
) ||
995 (this->dsbd
.dwFlags
& DSBCAPS_CTRL3D
) ||
996 (this->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
))
997 return DSERR_CONTROLUNAVAIL
;
1000 EnterCriticalSection(&(this->lock
));
1004 temp
= (double) (this->volume
- (this->pan
> 0 ? this->pan
: 0));
1005 this->lVolAdjust
= (ULONG
) (pow(2.0, temp
/ 600.0) * 32768.0);
1006 temp
= (double) (this->volume
+ (this->pan
< 0 ? this->pan
: 0));
1007 this->rVolAdjust
= (ULONG
) (pow(2.0, temp
/ 600.0) * 32768.0);
1009 LeaveCriticalSection(&(this->lock
));
1015 static HRESULT WINAPI
IDirectSoundBuffer_GetPan(
1016 LPDIRECTSOUNDBUFFER
this,LPLONG pan
1018 TRACE(dsound
,"(%p,%p)\n",this,pan
);
1021 return DSERR_INVALIDPARAM
;
1028 static HRESULT WINAPI
IDirectSoundBuffer_Unlock(
1029 LPDIRECTSOUNDBUFFER
this,LPVOID p1
,DWORD x1
,LPVOID p2
,DWORD x2
1031 TRACE(dsound
,"(%p,%p,%ld,%p,%ld):stub\n", this,p1
,x1
,p2
,x2
);
1033 /* There is really nothing to do here. Should someone */
1034 /* choose to implement static buffers in hardware (by */
1035 /* using a wave table synth, for example) this is where */
1036 /* you'd want to do the loading. For software buffers, */
1037 /* which is what we currently use, we need do nothing. */
1040 /* It's also the place to pre-process 3D buffers... */
1042 /* This is highly experimental and liable to break things */
1043 if (this->dsbd
.dwFlags
& DSBCAPS_CTRL3D
)
1044 DSOUND_Create3DBuffer(this);
1050 static HRESULT WINAPI
IDirectSoundBuffer_GetFrequency(
1051 LPDIRECTSOUNDBUFFER
this,LPDWORD freq
1053 TRACE(dsound
,"(%p,%p)\n",this,freq
);
1056 return DSERR_INVALIDPARAM
;
1063 static HRESULT WINAPI
IDirectSoundBuffer_Initialize(
1064 LPDIRECTSOUNDBUFFER
this,LPDIRECTSOUND dsound
,LPDSBUFFERDESC dbsd
1066 FIXME(dsound
,"(%p,%p,%p):stub\n",this,dsound
,dbsd
);
1067 printf("Re-Init!!!\n");
1068 return DSERR_ALREADYINITIALIZED
;
1071 static HRESULT WINAPI
IDirectSoundBuffer_GetCaps(
1072 LPDIRECTSOUNDBUFFER
this,LPDSBCAPS caps
1074 TRACE(dsound
,"(%p)->(%p)\n",this,caps
);
1077 return DSERR_INVALIDPARAM
;
1079 /* I think we should check this value, not set it. See */
1080 /* Inside DirectX, p215. That should apply here, too. */
1081 caps
->dwSize
= sizeof(*caps
);
1083 caps
->dwFlags
= this->dsbd
.dwFlags
| DSBCAPS_LOCSOFTWARE
;
1084 caps
->dwBufferBytes
= this->dsbd
.dwBufferBytes
;
1085 /* This value represents the speed of the "unlock" command.
1086 As unlock is quite fast (it does not do anything), I put
1087 4096 ko/s = 4 Mo / s */
1088 caps
->dwUnlockTransferRate
= 4096;
1089 caps
->dwPlayCpuOverhead
= 0;
1094 static HRESULT WINAPI
IDirectSoundBuffer_QueryInterface(
1095 LPDIRECTSOUNDBUFFER
this,REFIID riid
,LPVOID
*ppobj
1099 WINE_StringFromCLSID(riid
,xbuf
);
1100 TRACE(dsound
,"(%p,%s,%p)\n",this,xbuf
,ppobj
);
1102 if (!memcmp(&IID_IDirectSoundNotify
,riid
,sizeof(*riid
))) {
1103 IDirectSoundNotify
*dsn
;
1105 dsn
= (LPDIRECTSOUNDNOTIFY
)HeapAlloc(GetProcessHeap(),0,sizeof(*dsn
));
1108 this->lpvtbl
->fnAddRef(this);
1109 dsn
->lpvtbl
= &dsnvt
;
1110 *ppobj
= (LPVOID
)dsn
;
1114 if (!memcmp(&IID_IDirectSound3DBuffer
,riid
,sizeof(*riid
))) {
1115 *ppobj
= this->ds3db
;
1123 static struct tagLPDIRECTSOUNDBUFFER_VTABLE dsbvt
= {
1124 IDirectSoundBuffer_QueryInterface
,
1125 IDirectSoundBuffer_AddRef
,
1126 IDirectSoundBuffer_Release
,
1127 IDirectSoundBuffer_GetCaps
,
1128 IDirectSoundBuffer_GetCurrentPosition
,
1129 IDirectSoundBuffer_GetFormat
,
1130 IDirectSoundBuffer_GetVolume
,
1131 IDirectSoundBuffer_GetPan
,
1132 IDirectSoundBuffer_GetFrequency
,
1133 IDirectSoundBuffer_GetStatus
,
1134 IDirectSoundBuffer_Initialize
,
1135 IDirectSoundBuffer_Lock
,
1136 IDirectSoundBuffer_Play
,
1137 IDirectSoundBuffer_SetCurrentPosition
,
1138 IDirectSoundBuffer_SetFormat
,
1139 IDirectSoundBuffer_SetVolume
,
1140 IDirectSoundBuffer_SetPan
,
1141 IDirectSoundBuffer_SetFrequency
,
1142 IDirectSoundBuffer_Stop
,
1143 IDirectSoundBuffer_Unlock
1146 /*******************************************************************************
1150 static HRESULT WINAPI
IDirectSound_SetCooperativeLevel(
1151 LPDIRECTSOUND
this,HWND hwnd
,DWORD level
1153 FIXME(dsound
,"(%p,%08lx,%ld):stub\n",this,(DWORD
)hwnd
,level
);
1157 static HRESULT WINAPI
IDirectSound_CreateSoundBuffer(
1158 LPDIRECTSOUND
this,LPDSBUFFERDESC dsbd
,LPLPDIRECTSOUNDBUFFER ppdsb
,LPUNKNOWN lpunk
1160 LPWAVEFORMATEX wfex
;
1162 TRACE(dsound
,"(%p,%p,%p,%p)\n",this,dsbd
,ppdsb
,lpunk
);
1164 if ((this == NULL
) || (dsbd
== NULL
) || (ppdsb
== NULL
))
1165 return DSERR_INVALIDPARAM
;
1167 if (TRACE_ON(dsound
)) {
1168 TRACE(dsound
,"(size=%ld)\n",dsbd
->dwSize
);
1169 TRACE(dsound
,"(flags=0x%08lx\n",dsbd
->dwFlags
);
1170 _dump_DSBCAPS(dsbd
->dwFlags
);
1171 TRACE(dsound
,"(bufferbytes=%ld)\n",dsbd
->dwBufferBytes
);
1172 TRACE(dsound
,"(lpwfxFormat=%p)\n",dsbd
->lpwfxFormat
);
1175 wfex
= dsbd
->lpwfxFormat
;
1178 TRACE(dsound
,"(formattag=0x%04x,chans=%d,samplerate=%ld"
1179 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
1180 wfex
->wFormatTag
, wfex
->nChannels
, wfex
->nSamplesPerSec
,
1181 wfex
->nAvgBytesPerSec
, wfex
->nBlockAlign
,
1182 wfex
->wBitsPerSample
, wfex
->cbSize
);
1184 if (dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
1186 primarybuf
->lpvtbl
->fnAddRef(primarybuf
);
1187 *ppdsb
= primarybuf
;
1189 } /* Else create primarybuf */
1192 *ppdsb
= (LPDIRECTSOUNDBUFFER
)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDirectSoundBuffer
));
1194 return DSERR_OUTOFMEMORY
;
1197 TRACE(dsound
, "Created buffer at %p\n", *ppdsb
);
1199 if (dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
1200 (*ppdsb
)->buflen
= dsound
->wfx
.nAvgBytesPerSec
;
1201 (*ppdsb
)->freq
= dsound
->wfx
.nSamplesPerSec
;
1203 (*ppdsb
)->buflen
= dsbd
->dwBufferBytes
;
1204 (*ppdsb
)->freq
= dsbd
->lpwfxFormat
->nSamplesPerSec
;
1206 (*ppdsb
)->buffer
= (LPBYTE
)HeapAlloc(GetProcessHeap(),0,(*ppdsb
)->buflen
);
1207 if ((*ppdsb
)->buffer
== NULL
) {
1208 HeapFree(GetProcessHeap(),0,(*ppdsb
));
1210 return DSERR_OUTOFMEMORY
;
1212 /* It's not necessary to initialize values to zero since */
1213 /* we allocated this structure with HEAP_ZERO_MEMORY... */
1214 (*ppdsb
)->playpos
= 0;
1215 (*ppdsb
)->writepos
= 0;
1216 (*ppdsb
)->parent
= NULL
;
1217 (*ppdsb
)->lpvtbl
= &dsbvt
;
1218 (*ppdsb
)->dsound
= this;
1219 (*ppdsb
)->playing
= 0;
1220 (*ppdsb
)->lVolAdjust
= (1 << 15);
1221 (*ppdsb
)->rVolAdjust
= (1 << 15);
1223 if (!(dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
)) {
1224 (*ppdsb
)->freqAdjust
= ((*ppdsb
)->freq
<< DSOUND_FREQSHIFT
) /
1225 primarybuf
->wfx
.nSamplesPerSec
;
1226 (*ppdsb
)->nAvgBytesPerSec
= (*ppdsb
)->freq
*
1227 dsbd
->lpwfxFormat
->nBlockAlign
;
1230 memcpy(&((*ppdsb
)->dsbd
),dsbd
,sizeof(*dsbd
));
1232 /* register buffer */
1233 if (!(dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
)) {
1234 this->buffers
= (LPDIRECTSOUNDBUFFER
*)HeapReAlloc(GetProcessHeap(),0,this->buffers
,sizeof(LPDIRECTSOUNDBUFFER
)*(this->nrofbuffers
+1));
1235 this->buffers
[this->nrofbuffers
] = *ppdsb
;
1236 this->nrofbuffers
++;
1238 this->lpvtbl
->fnAddRef(this);
1240 if (dsbd
->lpwfxFormat
)
1241 memcpy(&((*ppdsb
)->wfx
), dsbd
->lpwfxFormat
, sizeof((*ppdsb
)->wfx
));
1243 InitializeCriticalSection(&((*ppdsb
)->lock
));
1246 if (dsbd
->dwFlags
& DSBCAPS_CTRL3D
) {
1247 IDirectSound3DBuffer
*ds3db
;
1249 ds3db
= (LPDIRECTSOUND3DBUFFER
)HeapAlloc(GetProcessHeap(),
1252 ds3db
->dsb
= (*ppdsb
);
1253 ds3db
->lpvtbl
= &ds3dbvt
;
1254 (*ppdsb
)->ds3db
= ds3db
;
1255 ds3db
->ds3db
.dwSize
= sizeof(DS3DBUFFER
);
1256 ds3db
->ds3db
.vPosition
.x
.x
= 0.0;
1257 ds3db
->ds3db
.vPosition
.y
.y
= 0.0;
1258 ds3db
->ds3db
.vPosition
.z
.z
= 0.0;
1259 ds3db
->ds3db
.vVelocity
.x
.x
= 0.0;
1260 ds3db
->ds3db
.vVelocity
.y
.y
= 0.0;
1261 ds3db
->ds3db
.vVelocity
.z
.z
= 0.0;
1262 ds3db
->ds3db
.dwInsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
1263 ds3db
->ds3db
.dwOutsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
1264 ds3db
->ds3db
.vConeOrientation
.x
.x
= 0.0;
1265 ds3db
->ds3db
.vConeOrientation
.y
.y
= 0.0;
1266 ds3db
->ds3db
.vConeOrientation
.z
.z
= 0.0;
1267 ds3db
->ds3db
.lConeOutsideVolume
= DS3D_DEFAULTCONEOUTSIDEVOLUME
;
1268 ds3db
->ds3db
.flMinDistance
= DS3D_DEFAULTMINDISTANCE
;
1269 ds3db
->ds3db
.flMaxDistance
= DS3D_DEFAULTMAXDISTANCE
;
1270 ds3db
->ds3db
.dwMode
= DS3DMODE_NORMAL
;
1271 ds3db
->buflen
= ((*ppdsb
)->buflen
* primarybuf
->wfx
.nBlockAlign
) /
1272 (*ppdsb
)->wfx
.nBlockAlign
;
1273 ds3db
->buffer
= HeapAlloc(GetProcessHeap(), 0, ds3db
->buflen
);
1274 if (ds3db
->buffer
== NULL
) {
1276 ds3db
->ds3db
.dwMode
= DS3DMODE_DISABLE
;
1283 static HRESULT WINAPI
IDirectSound_DuplicateSoundBuffer(
1284 LPDIRECTSOUND
this,LPDIRECTSOUNDBUFFER pdsb
,LPLPDIRECTSOUNDBUFFER ppdsb
1286 TRACE(dsound
,"(%p,%p,%p)\n",this,pdsb
,ppdsb
);
1288 *ppdsb
= (LPDIRECTSOUNDBUFFER
)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDirectSoundBuffer
));
1290 pdsb
->lpvtbl
->fnAddRef(pdsb
);
1291 memcpy(*ppdsb
, pdsb
, sizeof(IDirectSoundBuffer
));
1293 (*ppdsb
)->playpos
= 0;
1294 (*ppdsb
)->writepos
= 0;
1295 (*ppdsb
)->dsound
= this;
1296 (*ppdsb
)->parent
= pdsb
;
1297 memcpy(&((*ppdsb
)->wfx
), &(pdsb
->wfx
), sizeof((*ppdsb
)->wfx
));
1298 /* register buffer */
1299 this->buffers
= (LPDIRECTSOUNDBUFFER
*)HeapReAlloc(GetProcessHeap(),0,this->buffers
,sizeof(LPDIRECTSOUNDBUFFER
)*(this->nrofbuffers
+1));
1300 this->buffers
[this->nrofbuffers
] = *ppdsb
;
1301 this->nrofbuffers
++;
1302 this->lpvtbl
->fnAddRef(this);
1307 static HRESULT WINAPI
IDirectSound_GetCaps(LPDIRECTSOUND
this,LPDSCAPS caps
) {
1308 TRACE(dsound
,"(%p,%p)\n",this,caps
);
1309 TRACE(dsound
,"(flags=0x%08lx)\n",caps
->dwFlags
);
1312 return DSERR_INVALIDPARAM
;
1314 /* We should check this value, not set it. See Inside DirectX, p215. */
1315 caps
->dwSize
= sizeof(*caps
);
1318 DSCAPS_PRIMARYSTEREO
|
1319 DSCAPS_PRIMARY16BIT
|
1320 DSCAPS_SECONDARYSTEREO
|
1321 DSCAPS_SECONDARY16BIT
|
1322 DSCAPS_CONTINUOUSRATE
;
1323 /* FIXME: query OSS */
1324 caps
->dwMinSecondarySampleRate
= DSBFREQUENCY_MIN
;
1325 caps
->dwMaxSecondarySampleRate
= DSBFREQUENCY_MAX
;
1327 caps
->dwPrimaryBuffers
= 1;
1329 caps
->dwMaxHwMixingAllBuffers
= 0;
1330 caps
->dwMaxHwMixingStaticBuffers
= 0;
1331 caps
->dwMaxHwMixingStreamingBuffers
= 0;
1333 caps
->dwFreeHwMixingAllBuffers
= 0;
1334 caps
->dwFreeHwMixingStaticBuffers
= 0;
1335 caps
->dwFreeHwMixingStreamingBuffers
= 0;
1337 caps
->dwMaxHw3DAllBuffers
= 0;
1338 caps
->dwMaxHw3DStaticBuffers
= 0;
1339 caps
->dwMaxHw3DStreamingBuffers
= 0;
1341 caps
->dwFreeHw3DAllBuffers
= 0;
1342 caps
->dwFreeHw3DStaticBuffers
= 0;
1343 caps
->dwFreeHw3DStreamingBuffers
= 0;
1345 caps
->dwTotalHwMemBytes
= 0;
1347 caps
->dwFreeHwMemBytes
= 0;
1349 caps
->dwMaxContigFreeHwMemBytes
= 0;
1351 caps
->dwUnlockTransferRateHwBuffers
= 4096; /* But we have none... */
1353 caps
->dwPlayCpuOverheadSwBuffers
= 1; /* 1% */
1358 static ULONG WINAPI
IDirectSound_AddRef(LPDIRECTSOUND
this) {
1359 return ++(this->ref
);
1362 static ULONG WINAPI
IDirectSound_Release(LPDIRECTSOUND
this) {
1363 TRACE(dsound
,"(%p), ref was %ld\n",this,this->ref
);
1364 if (!--(this->ref
)) {
1365 DSOUND_CloseAudio();
1366 while(IDirectSoundBuffer_Release(primarybuf
)); /* Deallocate */
1367 FIXME(dsound
, "need to release all buffers!\n");
1368 HeapFree(GetProcessHeap(),0,this);
1375 static HRESULT WINAPI
IDirectSound_SetSpeakerConfig(
1376 LPDIRECTSOUND
this,DWORD config
1378 FIXME(dsound
,"(%p,0x%08lx):stub\n",this,config
);
1382 static HRESULT WINAPI
IDirectSound_QueryInterface(
1383 LPDIRECTSOUND
this,REFIID riid
,LPVOID
*ppobj
1387 if (!memcmp(&IID_IDirectSound3DListener
,riid
,sizeof(*riid
))) {
1389 if (this->listener
) {
1390 *ppobj
= this->listener
;
1393 this->listener
= (LPDIRECTSOUND3DLISTENER
)HeapAlloc(
1394 GetProcessHeap(), 0, sizeof(*(this->listener
)));
1395 this->listener
->ref
= 1;
1396 this->listener
->lpvtbl
= &ds3dlvt
;
1397 this->lpvtbl
->fnAddRef(this);
1398 this->listener
->ds3dl
.dwSize
= sizeof(DS3DLISTENER
);
1399 this->listener
->ds3dl
.vPosition
.x
.x
= 0.0;
1400 this->listener
->ds3dl
.vPosition
.y
.y
= 0.0;
1401 this->listener
->ds3dl
.vPosition
.z
.z
= 0.0;
1402 this->listener
->ds3dl
.vVelocity
.x
.x
= 0.0;
1403 this->listener
->ds3dl
.vVelocity
.y
.y
= 0.0;
1404 this->listener
->ds3dl
.vVelocity
.z
.z
= 0.0;
1405 this->listener
->ds3dl
.vOrientFront
.x
.x
= 0.0;
1406 this->listener
->ds3dl
.vOrientFront
.y
.y
= 0.0;
1407 this->listener
->ds3dl
.vOrientFront
.z
.z
= 1.0;
1408 this->listener
->ds3dl
.vOrientTop
.x
.x
= 0.0;
1409 this->listener
->ds3dl
.vOrientTop
.y
.y
= 1.0;
1410 this->listener
->ds3dl
.vOrientTop
.z
.z
= 0.0;
1411 this->listener
->ds3dl
.flDistanceFactor
= DS3D_DEFAULTDISTANCEFACTOR
;
1412 this->listener
->ds3dl
.flRolloffFactor
= DS3D_DEFAULTROLLOFFFACTOR
;
1413 this->listener
->ds3dl
.flDopplerFactor
= DS3D_DEFAULTDOPPLERFACTOR
;
1414 *ppobj
= (LPVOID
)this->listener
;
1418 WINE_StringFromCLSID(riid
,xbuf
);
1419 TRACE(dsound
,"(%p,%s,%p)\n",this,xbuf
,ppobj
);
1423 static HRESULT WINAPI
IDirectSound_Compact(
1426 TRACE(dsound
, "(%p)\n", this);
1430 static HRESULT WINAPI
IDirectSound_GetSpeakerConfig(
1432 LPDWORD lpdwSpeakerConfig
)
1434 TRACE(dsound
, "(%p, %p)\n", this, lpdwSpeakerConfig
);
1435 *lpdwSpeakerConfig
= DSSPEAKER_STEREO
| (DSSPEAKER_GEOMETRY_NARROW
<< 16);
1439 static HRESULT WINAPI
IDirectSound_Initialize(
1443 TRACE(dsound
, "(%p, %p)\n", this, lpGuid
);
1447 static struct tagLPDIRECTSOUND_VTABLE dsvt
= {
1448 IDirectSound_QueryInterface
,
1449 IDirectSound_AddRef
,
1450 IDirectSound_Release
,
1451 IDirectSound_CreateSoundBuffer
,
1452 IDirectSound_GetCaps
,
1453 IDirectSound_DuplicateSoundBuffer
,
1454 IDirectSound_SetCooperativeLevel
,
1455 IDirectSound_Compact
,
1456 IDirectSound_GetSpeakerConfig
,
1457 IDirectSound_SetSpeakerConfig
,
1458 IDirectSound_Initialize
1462 /* See http://www.opensound.com/pguide/audio.html for more details */
1465 DSOUND_setformat(LPWAVEFORMATEX wfex
) {
1466 int xx
,channels
,speed
,format
,nformat
;
1469 TRACE(dsound
, "(%p) deferred\n", wfex
);
1472 switch (wfex
->wFormatTag
) {
1474 WARN(dsound
,"unknown WAVE_FORMAT tag %d\n",wfex
->wFormatTag
);
1475 return DSERR_BADFORMAT
;
1476 case WAVE_FORMAT_PCM
:
1479 if (wfex
->wBitsPerSample
==8)
1482 format
= AFMT_S16_LE
;
1484 if (-1==ioctl(audiofd
,SNDCTL_DSP_GETFMTS
,&xx
)) {
1485 perror("ioctl SNDCTL_DSP_GETFMTS");
1488 if ((xx
&format
)!=format
) {/* format unsupported */
1489 FIXME(dsound
,"SNDCTL_DSP_GETFMTS: format not supported\n");
1493 if (-1==ioctl(audiofd
,SNDCTL_DSP_SETFMT
,&nformat
)) {
1494 perror("ioctl SNDCTL_DSP_SETFMT");
1497 if (nformat
!=format
) {/* didn't work */
1498 FIXME(dsound
,"SNDCTL_DSP_GETFMTS: format not set\n");
1502 channels
= wfex
->nChannels
-1;
1503 if (-1==ioctl(audiofd
,SNDCTL_DSP_STEREO
,&channels
)) {
1504 perror("ioctl SNDCTL_DSP_STEREO");
1507 speed
= wfex
->nSamplesPerSec
;
1508 if (-1==ioctl(audiofd
,SNDCTL_DSP_SPEED
,&speed
)) {
1509 perror("ioctl SNDCTL_DSP_SPEED");
1512 TRACE(dsound
,"(freq=%ld,channels=%d,bits=%d)\n",
1513 wfex
->nSamplesPerSec
,wfex
->nChannels
,wfex
->wBitsPerSample
1518 static void DSOUND_CheckEvent(IDirectSoundBuffer
*dsb
, int len
)
1522 LPDSBPOSITIONNOTIFY event
;
1524 if (dsb
->nrofnotifies
== 0)
1527 TRACE(dsound
,"(%p) buflen = %ld, playpos = %ld, len = %d\n",
1528 dsb
, dsb
->buflen
, dsb
->playpos
, len
);
1529 for (i
= 0; i
< dsb
->nrofnotifies
; i
++) {
1530 event
= dsb
->notifies
+ i
;
1531 offset
= event
->dwOffset
;
1532 TRACE(dsound
, "checking %d, position %ld, event = %d\n",
1533 i
, offset
, event
->hEventNotify
);
1534 /* DSBPN_OFFSETSTOP has to be the last element. So this is */
1535 /* OK. [Inside DirectX, p274] */
1537 /* This also means we can't sort the entries by offset, */
1538 /* because DSBPN_OFFSETSTOP == -1 */
1539 if (offset
== DSBPN_OFFSETSTOP
) {
1540 if (dsb
->playing
== 0) {
1541 SetEvent(event
->hEventNotify
);
1542 TRACE(dsound
,"signalled event %d (%d)\n", event
->hEventNotify
, i
);
1547 if ((dsb
->playpos
+ len
) >= dsb
->buflen
) {
1548 if ((offset
< ((dsb
->playpos
+ len
) % dsb
->buflen
)) ||
1549 (offset
>= dsb
->playpos
)) {
1550 TRACE(dsound
,"signalled event %d (%d)\n", event
->hEventNotify
, i
);
1551 SetEvent(event
->hEventNotify
);
1554 if ((offset
>= dsb
->playpos
) && (offset
< (dsb
->playpos
+ len
))) {
1555 TRACE(dsound
,"signalled event %d (%d)\n", event
->hEventNotify
, i
);
1556 SetEvent(event
->hEventNotify
);
1562 /* WAV format info can be found at: */
1564 /* http://www.cwi.nl/ftp/audio/AudioFormats.part2 */
1565 /* ftp://ftp.cwi.nl/pub/audio/RIFF-format */
1567 /* Import points to remember: */
1569 /* 8-bit WAV is unsigned */
1570 /* 16-bit WAV is signed */
1572 static inline INT16
cvtU8toS16(BYTE byte
)
1574 INT16 s
= (byte
- 128) << 8;
1579 static inline BYTE
cvtS16toU8(INT16 word
)
1581 BYTE b
= (word
+ 32768) >> 8;
1587 /* We should be able to optimize these two inline functions */
1588 /* so that we aren't doing 8->16->8 conversions when it is */
1589 /* not necessary. But this is still a WIP. Optimize later. */
1590 static inline void get_fields(const IDirectSoundBuffer
*dsb
, BYTE
*buf
, INT
*fl
, INT
*fr
)
1592 INT16
*bufs
= (INT16
*) buf
;
1594 /* TRACE(dsound, "(%p)", buf); */
1595 if ((dsb
->wfx
.wBitsPerSample
== 8) && dsb
->wfx
.nChannels
== 2) {
1596 *fl
= cvtU8toS16(*buf
);
1597 *fr
= cvtU8toS16(*(buf
+ 1));
1601 if ((dsb
->wfx
.wBitsPerSample
== 16) && dsb
->wfx
.nChannels
== 2) {
1607 if ((dsb
->wfx
.wBitsPerSample
== 8) && dsb
->wfx
.nChannels
== 1) {
1608 *fl
= cvtU8toS16(*buf
);
1613 if ((dsb
->wfx
.wBitsPerSample
== 16) && dsb
->wfx
.nChannels
== 1) {
1619 FIXME(dsound
, "get_fields found an unsupported configuration\n");
1623 static inline void set_fields(BYTE
*buf
, INT fl
, INT fr
)
1625 INT16
*bufs
= (INT16
*) buf
;
1627 if ((primarybuf
->wfx
.wBitsPerSample
== 8) && (primarybuf
->wfx
.nChannels
== 2)) {
1628 *buf
= cvtS16toU8(fl
);
1629 *(buf
+ 1) = cvtS16toU8(fr
);
1633 if ((primarybuf
->wfx
.wBitsPerSample
== 16) && (primarybuf
->wfx
.nChannels
== 2)) {
1639 if ((primarybuf
->wfx
.wBitsPerSample
== 8) && (primarybuf
->wfx
.nChannels
== 1)) {
1640 *buf
= cvtS16toU8((fl
+ fr
) >> 1);
1644 if ((primarybuf
->wfx
.wBitsPerSample
== 16) && (primarybuf
->wfx
.nChannels
== 1)) {
1645 *bufs
= (fl
+ fr
) >> 1;
1648 FIXME(dsound
, "set_fields found an unsupported configuration\n");
1652 /* Now with PerfectPitch (tm) technology */
1653 static INT
DSOUND_MixerNorm(IDirectSoundBuffer
*dsb
, BYTE
*buf
, INT len
)
1655 INT i
, size
, ipos
, ilen
, fieldL
, fieldR
;
1657 INT iAdvance
= dsb
->wfx
.nBlockAlign
;
1658 INT oAdvance
= primarybuf
->wfx
.nBlockAlign
;
1660 ibp
= dsb
->buffer
+ dsb
->playpos
;
1663 TRACE(dsound
, "(%p, %p, %p), playpos=%8.8lx\n", dsb
, ibp
, obp
, dsb
->playpos
);
1664 /* Check for the best case */
1665 if ((dsb
->freq
== primarybuf
->wfx
.nSamplesPerSec
) &&
1666 (dsb
->wfx
.wBitsPerSample
== primarybuf
->wfx
.wBitsPerSample
) &&
1667 (dsb
->wfx
.nChannels
== primarybuf
->wfx
.nChannels
)) {
1668 TRACE(dsound
, "(%p) Best case\n", dsb
);
1669 if ((ibp
+ len
) < (BYTE
*)(dsb
->buffer
+ dsb
->buflen
))
1670 memcpy(obp
, ibp
, len
);
1672 memcpy(obp
, ibp
, dsb
->buflen
- dsb
->playpos
);
1673 memcpy(obp
+ (dsb
->buflen
- dsb
->playpos
),
1675 len
- (dsb
->buflen
- dsb
->playpos
));
1680 /* Check for same sample rate */
1681 if (dsb
->freq
== primarybuf
->wfx
.nSamplesPerSec
) {
1682 TRACE(dsound
, "(%p) Same sample rate %ld = primary %ld\n", dsb
,
1683 dsb
->freq
, primarybuf
->wfx
.nSamplesPerSec
);
1685 for (i
= 0; i
< len
; i
+= oAdvance
) {
1686 get_fields(dsb
, ibp
, &fieldL
, &fieldR
);
1689 set_fields(obp
, fieldL
, fieldR
);
1691 if (ibp
>= (BYTE
*)(dsb
->buffer
+ dsb
->buflen
))
1692 ibp
= dsb
->buffer
; /* wrap */
1697 /* Mix in different sample rates */
1699 /* New PerfectPitch(tm) Technology (c) 1998 Rob Riggs */
1700 /* Patent Pending :-] */
1702 TRACE(dsound
, "(%p) Adjusting frequency: %ld -> %ld\n",
1703 dsb
, dsb
->freq
, primarybuf
->wfx
.nSamplesPerSec
);
1705 size
= len
/ oAdvance
;
1706 ilen
= ((size
* dsb
->freqAdjust
) >> DSOUND_FREQSHIFT
) * iAdvance
;
1707 for (i
= 0; i
< size
; i
++) {
1709 ipos
= (((i
* dsb
->freqAdjust
) >> DSOUND_FREQSHIFT
) * iAdvance
) + dsb
->playpos
;
1711 if (ipos
>= dsb
->buflen
)
1712 ipos
%= dsb
->buflen
; /* wrap */
1714 get_fields(dsb
, (dsb
->buffer
+ ipos
), &fieldL
, &fieldR
);
1715 set_fields(obp
, fieldL
, fieldR
);
1721 static void DSOUND_MixerVol(IDirectSoundBuffer
*dsb
, BYTE
*buf
, INT len
)
1723 INT i
, inc
= primarybuf
->wfx
.wBitsPerSample
>> 3;
1725 INT16
*bps
= (INT16
*) buf
;
1727 TRACE(dsound
, "(%p) left = %lx, right = %lx\n", dsb
,
1728 dsb
->lVolAdjust
, dsb
->rVolAdjust
);
1729 if ((!(dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLPAN
) || (dsb
->pan
== 0)) &&
1730 (!(dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLVOLUME
) || (dsb
->volume
== 0)) &&
1731 !(dsb
->dsbd
.dwFlags
& DSBCAPS_CTRL3D
))
1732 return; /* Nothing to do */
1734 /* If we end up with some bozo coder using panning or 3D sound */
1735 /* with a mono primary buffer, it could sound very weird using */
1736 /* this method. Oh well, tough patooties. */
1738 for (i
= 0; i
< len
; i
+= inc
) {
1744 /* 8-bit WAV is unsigned, but we need to operate */
1745 /* on signed data for this to work properly */
1747 val
= ((val
* (i
& inc
? dsb
->rVolAdjust
: dsb
->lVolAdjust
)) >> 15);
1752 /* 16-bit WAV is signed -- much better */
1754 val
= ((val
* ((i
& inc
) ? dsb
->rVolAdjust
: dsb
->lVolAdjust
)) >> 15);
1760 FIXME(dsound
, "MixerVol had a nasty error\n");
1766 static void DSOUND_Mixer3D(IDirectSoundBuffer
*dsb
, BYTE
*buf
, INT len
)
1769 DWORD buflen
, playpos
;
1771 buflen
= dsb
->ds3db
->buflen
;
1772 playpos
= (dsb
->playpos
* primarybuf
->wfx
.nBlockAlign
) / dsb
->wfx
.nBlockAlign
;
1773 ibp
= dsb
->ds3db
->buffer
+ playpos
;
1776 if (playpos
> buflen
) {
1777 FIXME(dsound
, "Major breakage");
1781 if (len
<= (playpos
+ buflen
))
1782 memcpy(obp
, ibp
, len
);
1784 memcpy(obp
, ibp
, buflen
- playpos
);
1785 memcpy(obp
+ (buflen
- playpos
),
1787 len
- (buflen
- playpos
));
1793 static DWORD
DSOUND_MixInBuffer(IDirectSoundBuffer
*dsb
)
1795 INT i
, len
, ilen
, temp
, field
;
1796 INT advance
= primarybuf
->wfx
.wBitsPerSample
>> 3;
1797 BYTE
*buf
, *ibuf
, *obuf
;
1798 INT16
*ibufs
, *obufs
;
1800 len
= DSOUND_FRAGLEN
; /* The most we will use */
1801 if (!(dsb
->playflags
& DSBPLAY_LOOPING
)) {
1802 temp
= MulDiv(primarybuf
->wfx
.nAvgBytesPerSec
, dsb
->buflen
,
1803 dsb
->nAvgBytesPerSec
) -
1804 MulDiv(primarybuf
->wfx
.nAvgBytesPerSec
, dsb
->playpos
,
1805 dsb
->nAvgBytesPerSec
);
1806 len
= (len
> temp
) ? temp
: len
;
1808 len
&= ~3; /* 4 byte alignment */
1811 /* This should only happen if we aren't looping and temp < 4 */
1813 /* We skip the remainder, so check for possible events */
1814 DSOUND_CheckEvent(dsb
, dsb
->buflen
- dsb
->playpos
);
1819 /* Check for DSBPN_OFFSETSTOP */
1820 DSOUND_CheckEvent(dsb
, 0);
1824 /* Been seeing segfaults in malloc() for some reason... */
1825 TRACE(dsound
, "allocating buffer (size = %d)\n", len
);
1826 if ((buf
= ibuf
= (BYTE
*) malloc(len
)) == NULL
)
1829 TRACE(dsound
, "MixInBuffer (%p) len = %d\n", dsb
, len
);
1831 ilen
= DSOUND_MixerNorm(dsb
, ibuf
, len
);
1832 if ((dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLPAN
) ||
1833 (dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLVOLUME
))
1834 DSOUND_MixerVol(dsb
, ibuf
, len
);
1836 obuf
= primarybuf
->buffer
+ primarybuf
->playpos
;
1837 for (i
= 0; i
< len
; i
+= advance
) {
1838 obufs
= (INT16
*) obuf
;
1839 ibufs
= (INT16
*) ibuf
;
1840 if (primarybuf
->wfx
.wBitsPerSample
== 8) {
1841 /* 8-bit WAV is unsigned */
1842 field
= (*ibuf
- 128);
1843 field
+= (*obuf
- 128);
1844 field
= field
> 127 ? 127 : field
;
1845 field
= field
< -128 ? -128 : field
;
1846 *obuf
= field
+ 128;
1848 /* 16-bit WAV is signed */
1851 field
= field
> 32767 ? 32767 : field
;
1852 field
= field
< -32768 ? -32768 : field
;
1857 if (obuf
>= (BYTE
*)(primarybuf
->buffer
+ primarybuf
->buflen
))
1858 obuf
= primarybuf
->buffer
;
1862 if (dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLPOSITIONNOTIFY
)
1863 DSOUND_CheckEvent(dsb
, ilen
);
1865 dsb
->playpos
+= ilen
;
1866 dsb
->writepos
= dsb
->playpos
+ ilen
;
1868 if (dsb
->playpos
>= dsb
->buflen
) {
1869 if (!(dsb
->playflags
& DSBPLAY_LOOPING
)) {
1873 DSOUND_CheckEvent(dsb
, 0); /* For DSBPN_OFFSETSTOP */
1875 dsb
->playpos
%= dsb
->buflen
; /* wrap */
1878 if (dsb
->writepos
>= dsb
->buflen
)
1879 dsb
->writepos
%= dsb
->buflen
;
1884 static DWORD WINAPI
DSOUND_MixPrimary(void)
1886 INT i
, len
, maxlen
= 0;
1887 IDirectSoundBuffer
*dsb
;
1889 for (i
= dsound
->nrofbuffers
- 1; i
>= 0; i
--) {
1890 dsb
= dsound
->buffers
[i
];
1892 if (!dsb
|| !(dsb
->lpvtbl
))
1894 dsb
->lpvtbl
->fnAddRef(dsb
);
1895 if (dsb
->buflen
&& dsb
->playing
) {
1896 EnterCriticalSection(&(dsb
->lock
));
1897 len
= DSOUND_MixInBuffer(dsb
);
1898 maxlen
= len
> maxlen
? len
: maxlen
;
1899 LeaveCriticalSection(&(dsb
->lock
));
1901 dsb
->lpvtbl
->fnRelease(dsb
);
1907 static int DSOUND_OpenAudio(void)
1911 if (primarybuf
== NULL
)
1912 return DSERR_OUTOFMEMORY
;
1914 while (audiofd
!= -1)
1916 audiofd
= open("/dev/audio",O_WRONLY
);
1918 /* Don't worry if sound is busy at the moment */
1920 perror("open /dev/audio");
1921 return audiofd
; /* -1 */
1924 /* We should probably do something here if SETFRAGMENT fails... */
1925 audioFragment
=0x0002000c;
1926 if (-1==ioctl(audiofd
,SNDCTL_DSP_SETFRAGMENT
,&audioFragment
))
1927 perror("ioctl SETFRAGMENT");
1930 DSOUND_setformat(&(primarybuf
->wfx
));
1935 static void DSOUND_CloseAudio(void)
1939 neutral
= primarybuf
->wfx
.wBitsPerSample
== 8 ? 128 : 0;
1940 audioOK
= 0; /* race condition */
1942 /* It's possible we've been called with audio closed */
1943 /* from SetFormat()... this is just to force a call */
1944 /* to OpenAudio() to reset the hardware properly */
1947 primarybuf
->playpos
= 0;
1948 primarybuf
->writepos
= DSOUND_FRAGLEN
;
1949 memset(primarybuf
->buffer
, neutral
, primarybuf
->buflen
);
1951 TRACE(dsound
, "Audio stopped\n");
1954 static int DSOUND_WriteAudio(char *buf
, int len
)
1956 int result
, left
= 0;
1958 while (left
< len
) {
1959 result
= write(audiofd
, buf
+ left
, len
- left
);
1971 static void DSOUND_OutputPrimary(int len
)
1973 int neutral
, flen1
, flen2
;
1974 char *frag1
, *frag2
;
1976 /* This is a bad place for this. We need to clear the */
1977 /* buffer with a neutral value, for unsigned 8-bit WAVE */
1978 /* that's 128, for signed 16-bit it's 0 */
1979 neutral
= primarybuf
->wfx
.wBitsPerSample
== 8 ? 128 : 0;
1982 EnterCriticalSection(&(primarybuf
->lock
));
1985 if ((audioOK
== 1) || (DSOUND_OpenAudio() == 0)) {
1986 if (primarybuf
->playpos
+ len
>= primarybuf
->buflen
) {
1987 frag1
= primarybuf
->buffer
+ primarybuf
->playpos
;
1988 flen1
= primarybuf
->buflen
- primarybuf
->playpos
;
1989 frag2
= primarybuf
->buffer
;
1990 flen2
= len
- (primarybuf
->buflen
- primarybuf
->playpos
);
1991 if (DSOUND_WriteAudio(frag1
, flen1
) != 0) {
1992 perror("DSOUND_WriteAudio");
1993 LeaveCriticalSection(&(primarybuf
->lock
));
1996 memset(frag1
, neutral
, flen1
);
1997 if (DSOUND_WriteAudio(frag2
, flen2
) != 0) {
1998 perror("DSOUND_WriteAudio");
1999 LeaveCriticalSection(&(primarybuf
->lock
));
2002 memset(frag2
, neutral
, flen2
);
2004 frag1
= primarybuf
->buffer
+ primarybuf
->playpos
;
2006 if (DSOUND_WriteAudio(frag1
, flen1
) != 0) {
2007 perror("DSOUND_WriteAudio");
2008 LeaveCriticalSection(&(primarybuf
->lock
));
2011 memset(frag1
, neutral
, flen1
);
2014 /* Can't play audio at the moment -- we need to sleep */
2015 /* to make up for the time we'd be blocked in write() */
2019 primarybuf
->playpos
+= len
;
2020 if (primarybuf
->playpos
>= primarybuf
->buflen
)
2021 primarybuf
->playpos
%= primarybuf
->buflen
;
2022 primarybuf
->writepos
= primarybuf
->playpos
+ DSOUND_FRAGLEN
;
2023 if (primarybuf
->writepos
>= primarybuf
->buflen
)
2024 primarybuf
->writepos
%= primarybuf
->buflen
;
2026 LeaveCriticalSection(&(primarybuf
->lock
));
2030 static DWORD WINAPI
DSOUND_thread(LPVOID arg
)
2034 TRACE(dsound
,"dsound is at pid %d\n",getpid());
2037 WARN(dsound
,"DSOUND thread giving up.\n");
2041 WARN(dsound
,"DSOUND father died? Giving up.\n");
2044 /* RACE: dsound could be deleted */
2045 dsound
->lpvtbl
->fnAddRef(dsound
);
2046 if (primarybuf
== NULL
) {
2047 /* Should never happen */
2048 WARN(dsound
, "Lost the primary buffer!\n");
2049 dsound
->lpvtbl
->fnRelease(dsound
);
2054 EnterCriticalSection(&(primarybuf
->lock
));
2055 len
= DSOUND_MixPrimary();
2056 LeaveCriticalSection(&(primarybuf
->lock
));
2059 if (primarybuf
->playing
)
2060 len
= DSOUND_FRAGLEN
> len
? DSOUND_FRAGLEN
: len
;
2062 /* This does all the work */
2063 DSOUND_OutputPrimary(len
);
2065 /* no buffers playing -- close and wait */
2067 DSOUND_CloseAudio();
2070 dsound
->lpvtbl
->fnRelease(dsound
);
2075 #endif /* HAVE_OSS */
2077 HRESULT WINAPI
DirectSoundCreate(REFGUID lpGUID
,LPDIRECTSOUND
*ppDS
,IUnknown
*pUnkOuter
)
2080 TRACE(dsound
,"(%p,%p,%p)\n",lpGUID
,ppDS
,pUnkOuter
);
2082 TRACE(dsound
,"DirectSoundCreate (%p)\n", ppDS
);
2087 return DSERR_INVALIDPARAM
;
2090 dsound
->lpvtbl
->fnAddRef(dsound
);
2095 /* Check that we actually have audio capabilities */
2096 /* If we do, whether it's busy or not, we continue */
2097 /* otherwise we return with DSERR_NODRIVER */
2099 audiofd
= open("/dev/audio",O_WRONLY
);
2100 if (audiofd
== -1) {
2101 if (errno
== ENODEV
) {
2102 MSG("No sound hardware found.\n");
2103 return DSERR_NODRIVER
;
2104 } else if (errno
== EBUSY
) {
2105 MSG("Sound device busy, will keep trying.\n");
2107 MSG("Unexpected error while checking for sound support.\n");
2108 return DSERR_GENERIC
;
2115 *ppDS
= (LPDIRECTSOUND
)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSound
));
2117 return DSERR_OUTOFMEMORY
;
2120 (*ppDS
)->lpvtbl
= &dsvt
;
2121 (*ppDS
)->buffers
= NULL
;
2122 (*ppDS
)->nrofbuffers
= 0;
2124 (*ppDS
)->wfx
.wFormatTag
= 1;
2125 (*ppDS
)->wfx
.nChannels
= 2;
2126 (*ppDS
)->wfx
.nSamplesPerSec
= 22050;
2127 (*ppDS
)->wfx
.nAvgBytesPerSec
= 44100;
2128 (*ppDS
)->wfx
.nBlockAlign
= 2;
2129 (*ppDS
)->wfx
.wBitsPerSample
= 8;
2136 if (primarybuf
== NULL
) {
2140 dsbd
.dwSize
= sizeof(DSBUFFERDESC
);
2141 dsbd
.dwFlags
= DSBCAPS_PRIMARYBUFFER
;
2142 dsbd
.dwBufferBytes
= 0;
2143 dsbd
.lpwfxFormat
= &(dsound
->wfx
);
2144 hr
= IDirectSound_CreateSoundBuffer(*ppDS
, &dsbd
, &primarybuf
, NULL
);
2147 dsound
->primary
= primarybuf
;
2149 memset(primarybuf
->buffer
, 128, primarybuf
->buflen
);
2150 hnd
= CreateThread(NULL
,0,DSOUND_thread
,0,0,&xid
);
2154 MessageBoxA(0,"DirectSound needs the Open Sound System Driver, which has not been found by ./configure.","WINE DirectSound",MB_OK
|MB_ICONSTOP
);
2155 return DSERR_NODRIVER
;
2159 /*******************************************************************************
2160 * DirectSound ClassFactory
2164 /* IUnknown fields */
2165 ICOM_VTABLE(IClassFactory
)* lpvtbl
;
2167 } IClassFactoryImpl
;
2169 static HRESULT WINAPI
2170 DSCF_QueryInterface(LPCLASSFACTORY iface
,REFIID riid
,LPVOID
*ppobj
) {
2171 ICOM_THIS(IClassFactoryImpl
,iface
);
2175 WINE_StringFromCLSID(riid
,buf
);
2177 sprintf(buf
,"<guid-0x%04x>",LOWORD(riid
));
2178 FIXME(dsound
,"(%p)->(%s,%p),stub!\n",This
,buf
,ppobj
);
2179 return E_NOINTERFACE
;
2183 DSCF_AddRef(LPCLASSFACTORY iface
) {
2184 ICOM_THIS(IClassFactoryImpl
,iface
);
2185 return ++(This
->ref
);
2188 static ULONG WINAPI
DSCF_Release(LPCLASSFACTORY iface
) {
2189 ICOM_THIS(IClassFactoryImpl
,iface
);
2190 /* static class, won't be freed */
2191 return --(This
->ref
);
2194 static HRESULT WINAPI
DSCF_CreateInstance(
2195 LPCLASSFACTORY iface
,LPUNKNOWN pOuter
,REFIID riid
,LPVOID
*ppobj
2197 ICOM_THIS(IClassFactoryImpl
,iface
);
2200 WINE_StringFromCLSID(riid
,buf
);
2201 TRACE(dsound
,"(%p)->(%p,%s,%p)\n",This
,pOuter
,buf
,ppobj
);
2202 if (!memcmp(riid
,&IID_IDirectSound
,sizeof(IID_IDirectSound
))) {
2203 /* FIXME: reuse already created dsound if present? */
2204 return DirectSoundCreate(riid
,(LPDIRECTSOUND
*)ppobj
,pOuter
);
2206 return E_NOINTERFACE
;
2209 static HRESULT WINAPI
DSCF_LockServer(LPCLASSFACTORY iface
,BOOL dolock
) {
2210 ICOM_THIS(IClassFactoryImpl
,iface
);
2211 FIXME(dsound
,"(%p)->(%d),stub!\n",This
,dolock
);
2215 static ICOM_VTABLE(IClassFactory
) DSCF_Vtbl
= {
2216 DSCF_QueryInterface
,
2219 DSCF_CreateInstance
,
2222 static IClassFactoryImpl DSOUND_CF
= {&DSCF_Vtbl
, 1 };
2224 /*******************************************************************************
2225 * DllGetClassObject [DSOUND.4]
2226 * Retrieves class object from a DLL object
2229 * Docs say returns STDAPI
2232 * rclsid [I] CLSID for the class object
2233 * riid [I] Reference to identifier of interface for class object
2234 * ppv [O] Address of variable to receive interface pointer for riid
2238 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
2241 DWORD WINAPI
DSOUND_DllGetClassObject(REFCLSID rclsid
,REFIID riid
,LPVOID
*ppv
)
2243 char buf
[80],xbuf
[80];
2246 WINE_StringFromCLSID(rclsid
,xbuf
);
2248 sprintf(xbuf
,"<guid-0x%04x>",LOWORD(rclsid
));
2250 WINE_StringFromCLSID(riid
,buf
);
2252 sprintf(buf
,"<guid-0x%04x>",LOWORD(riid
));
2253 WINE_StringFromCLSID(riid
,xbuf
);
2254 TRACE(dsound
, "(%p,%p,%p)\n", xbuf
, buf
, ppv
);
2255 if (!memcmp(riid
,&IID_IClassFactory
,sizeof(IID_IClassFactory
))) {
2256 *ppv
= (LPVOID
)&DSOUND_CF
;
2257 IClassFactory_AddRef((IClassFactory
*)*ppv
);
2260 FIXME(dsound
, "(%p,%p,%p): no interface found.\n", xbuf
, buf
, ppv
);
2261 return E_NOINTERFACE
;
2265 /*******************************************************************************
2266 * DllCanUnloadNow [DSOUND.3] Determines whether the DLL is in use.
2272 DWORD WINAPI
DSOUND_DllCanUnloadNow(void)
2274 FIXME(dsound
, "(void): stub\n");