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 */
66 #include "multimedia.h"
67 #include "wine/obj_base.h"
72 # include <sys/ioctl.h>
73 # ifdef HAVE_MACHINE_SOUNDCARD_H
74 # include <machine/soundcard.h>
76 # ifdef HAVE_SYS_SOUNDCARD_H
77 # include <sys/soundcard.h>
80 /* #define USE_DSOUND3D 1 */
82 #define DSOUND_FRAGLEN (primarybuf->wfx.nAvgBytesPerSec >> 4)
83 #define DSOUND_FREQSHIFT (14)
85 static int audiofd
= -1;
86 static int audioOK
= 0;
88 static LPDIRECTSOUND dsound
= NULL
;
90 static LPDIRECTSOUNDBUFFER primarybuf
= NULL
;
92 static int DSOUND_setformat(LPWAVEFORMATEX wfex
);
93 static void DSOUND_CheckEvent(IDirectSoundBuffer
*dsb
, int len
);
94 static void DSOUND_CloseAudio(void);
98 HRESULT WINAPI
DirectSoundEnumerate32A(
99 LPDSENUMCALLBACK32A enumcb
,
102 TRACE(dsound
, "enumcb = %p, context = %p\n", enumcb
, context
);
106 enumcb(NULL
,"WINE DirectSound using Open Sound System",
114 static void _dump_DSBCAPS(DWORD xmask
) {
119 #define FE(x) { x, #x },
120 FE(DSBCAPS_PRIMARYBUFFER
)
122 FE(DSBCAPS_LOCHARDWARE
)
123 FE(DSBCAPS_LOCSOFTWARE
)
124 FE(DSBCAPS_CTRLFREQUENCY
)
126 FE(DSBCAPS_CTRLVOLUME
)
127 FE(DSBCAPS_CTRLDEFAULT
)
129 FE(DSBCAPS_STICKYFOCUS
)
130 FE(DSBCAPS_GETCURRENTPOSITION2
)
134 for (i
=0;i
<sizeof(flags
)/sizeof(flags
[0]);i
++)
135 if (flags
[i
].mask
& xmask
)
136 fprintf(stderr
,"%s ",flags
[i
].name
);
139 /*******************************************************************************
140 * IDirectSound3DBuffer
143 /* IUnknown methods */
144 static HRESULT WINAPI
IDirectSound3DBuffer_QueryInterface(
145 LPDIRECTSOUND3DBUFFER
this, REFIID riid
, LPVOID
*ppobj
)
149 WINE_StringFromCLSID(riid
,xbuf
);
150 TRACE(dsound
,"(%p,%s,%p)\n",this,xbuf
,ppobj
);
154 static ULONG WINAPI
IDirectSound3DBuffer_AddRef(LPDIRECTSOUND3DBUFFER
this)
160 static ULONG WINAPI
IDirectSound3DBuffer_Release(LPDIRECTSOUND3DBUFFER
this)
165 HeapFree(GetProcessHeap(),0,this->buffer
);
166 HeapFree(GetProcessHeap(),0,this);
171 /* IDirectSound3DBuffer methods */
172 static HRESULT WINAPI
IDirectSound3DBuffer_GetAllParameters(
173 LPDIRECTSOUND3DBUFFER
this,
174 LPDS3DBUFFER lpDs3dBuffer
)
176 FIXME(dsound
,"stub\n");
180 static HRESULT WINAPI
IDirectSound3DBuffer_GetConeAngles(
181 LPDIRECTSOUND3DBUFFER
this,
182 LPDWORD lpdwInsideConeAngle
,
183 LPDWORD lpdwOutsideConeAngle
)
185 FIXME(dsound
,"stub\n");
189 static HRESULT WINAPI
IDirectSound3DBuffer_GetConeOrientation(
190 LPDIRECTSOUND3DBUFFER
this,
191 LPD3DVECTOR lpvConeOrientation
)
193 FIXME(dsound
,"stub\n");
197 static HRESULT WINAPI
IDirectSound3DBuffer_GetConeOutsideVolume(
198 LPDIRECTSOUND3DBUFFER
this,
199 LPLONG lplConeOutsideVolume
)
201 FIXME(dsound
,"stub\n");
205 static HRESULT WINAPI
IDirectSound3DBuffer_GetMaxDistance(
206 LPDIRECTSOUND3DBUFFER
this,
207 LPD3DVALUE lpfMaxDistance
)
209 FIXME(dsound
,"stub\n");
213 static HRESULT WINAPI
IDirectSound3DBuffer_GetMinDistance(
214 LPDIRECTSOUND3DBUFFER
this,
215 LPD3DVALUE lpfMinDistance
)
217 FIXME(dsound
,"stub\n");
221 static HRESULT WINAPI
IDirectSound3DBuffer_GetMode(
222 LPDIRECTSOUND3DBUFFER
this,
225 FIXME(dsound
,"stub\n");
229 static HRESULT WINAPI
IDirectSound3DBuffer_GetPosition(
230 LPDIRECTSOUND3DBUFFER
this,
231 LPD3DVECTOR lpvPosition
)
233 FIXME(dsound
,"stub\n");
237 static HRESULT WINAPI
IDirectSound3DBuffer_GetVelocity(
238 LPDIRECTSOUND3DBUFFER
this,
239 LPD3DVECTOR lpvVelocity
)
241 FIXME(dsound
,"stub\n");
245 static HRESULT WINAPI
IDirectSound3DBuffer_SetAllParameters(
246 LPDIRECTSOUND3DBUFFER
this,
247 LPCDS3DBUFFER lpcDs3dBuffer
,
250 FIXME(dsound
,"stub\n");
254 static HRESULT WINAPI
IDirectSound3DBuffer_SetConeAngles(
255 LPDIRECTSOUND3DBUFFER
this,
256 DWORD dwInsideConeAngle
,
257 DWORD dwOutsideConeAngle
,
260 FIXME(dsound
,"stub\n");
264 static HRESULT WINAPI
IDirectSound3DBuffer_SetConeOrientation(
265 LPDIRECTSOUND3DBUFFER
this,
266 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
269 FIXME(dsound
,"stub\n");
273 static HRESULT WINAPI
IDirectSound3DBuffer_SetConeOutsideVolume(
274 LPDIRECTSOUND3DBUFFER
this,
275 LONG lConeOutsideVolume
,
278 FIXME(dsound
,"stub\n");
282 static HRESULT WINAPI
IDirectSound3DBuffer_SetMaxDistance(
283 LPDIRECTSOUND3DBUFFER
this,
284 D3DVALUE fMaxDistance
,
287 FIXME(dsound
,"stub\n");
291 static HRESULT WINAPI
IDirectSound3DBuffer_SetMinDistance(
292 LPDIRECTSOUND3DBUFFER
this,
293 D3DVALUE fMinDistance
,
296 FIXME(dsound
,"stub\n");
300 static HRESULT WINAPI
IDirectSound3DBuffer_SetMode(
301 LPDIRECTSOUND3DBUFFER
this,
305 TRACE(dsound
, "mode = %lx\n", dwMode
);
306 this->ds3db
.dwMode
= dwMode
;
310 static HRESULT WINAPI
IDirectSound3DBuffer_SetPosition(
311 LPDIRECTSOUND3DBUFFER
this,
312 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
315 FIXME(dsound
,"stub\n");
319 static HRESULT WINAPI
IDirectSound3DBuffer_SetVelocity(
320 LPDIRECTSOUND3DBUFFER
this,
321 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
324 FIXME(dsound
,"stub\n");
328 IDirectSound3DBuffer_VTable ds3dbvt
= {
329 /* IUnknown methods */
330 IDirectSound3DBuffer_QueryInterface
,
331 IDirectSound3DBuffer_AddRef
,
332 IDirectSound3DBuffer_Release
,
333 /* IDirectSound3DBuffer methods */
334 IDirectSound3DBuffer_GetAllParameters
,
335 IDirectSound3DBuffer_GetConeAngles
,
336 IDirectSound3DBuffer_GetConeOrientation
,
337 IDirectSound3DBuffer_GetConeOutsideVolume
,
338 IDirectSound3DBuffer_GetMaxDistance
,
339 IDirectSound3DBuffer_GetMinDistance
,
340 IDirectSound3DBuffer_GetMode
,
341 IDirectSound3DBuffer_GetPosition
,
342 IDirectSound3DBuffer_GetVelocity
,
343 IDirectSound3DBuffer_SetAllParameters
,
344 IDirectSound3DBuffer_SetConeAngles
,
345 IDirectSound3DBuffer_SetConeOrientation
,
346 IDirectSound3DBuffer_SetConeOutsideVolume
,
347 IDirectSound3DBuffer_SetMaxDistance
,
348 IDirectSound3DBuffer_SetMinDistance
,
349 IDirectSound3DBuffer_SetMode
,
350 IDirectSound3DBuffer_SetPosition
,
351 IDirectSound3DBuffer_SetVelocity
,
355 static int DSOUND_Create3DBuffer(LPDIRECTSOUNDBUFFER dsb
)
357 DWORD i
, temp
, iSize
, oSize
, offset
;
358 LPBYTE bIbuf
, bObuf
, bTbuf
= NULL
;
359 LPWORD wIbuf
, wObuf
, wTbuf
= NULL
;
361 /* Inside DirectX says it's stupid but allowed */
362 if (dsb
->wfx
.nChannels
== 2) {
363 /* Convert to mono */
364 if (dsb
->wfx
.wBitsPerSample
== 16) {
365 iSize
= dsb
->buflen
/ 4;
366 wTbuf
= malloc(dsb
->buflen
/ 2);
368 return DSERR_OUTOFMEMORY
;
369 for (i
= 0; i
< iSize
; i
++)
370 wTbuf
[i
] = (dsb
->buffer
[i
] + dsb
->buffer
[(i
* 2) + 1]) / 2;
373 iSize
= dsb
->buflen
/ 2;
374 bTbuf
= malloc(dsb
->buflen
/ 2);
376 return DSERR_OUTOFMEMORY
;
377 for (i
= 0; i
< iSize
; i
++)
378 bTbuf
[i
] = (dsb
->buffer
[i
] + dsb
->buffer
[(i
* 2) + 1]) / 2;
382 if (dsb
->wfx
.wBitsPerSample
== 16) {
383 iSize
= dsb
->buflen
/ 2;
384 wIbuf
= (LPWORD
) dsb
->buffer
;
386 bIbuf
= (LPBYTE
) dsb
->buffer
;
391 if (primarybuf
->wfx
.wBitsPerSample
== 16) {
392 wObuf
= (LPWORD
) dsb
->ds3db
->buffer
;
393 oSize
= dsb
->ds3db
->buflen
/ 2;
395 bObuf
= (LPBYTE
) dsb
->ds3db
->buffer
;
396 oSize
= dsb
->ds3db
->buflen
;
399 offset
= primarybuf
->wfx
.nSamplesPerSec
/ 100; /* 10ms */
400 if (primarybuf
->wfx
.wBitsPerSample
== 16 && dsb
->wfx
.wBitsPerSample
== 16)
401 for (i
= 0; i
< iSize
; i
++) {
404 temp
+= wIbuf
[i
- offset
] >> 9;
406 temp
+= wIbuf
[i
+ iSize
- offset
] >> 9;
408 wObuf
[(i
* 2) + 1] = temp
;
410 else if (primarybuf
->wfx
.wBitsPerSample
== 8 && dsb
->wfx
.wBitsPerSample
== 8)
411 for (i
= 0; i
< iSize
; i
++) {
414 temp
+= bIbuf
[i
- offset
] >> 5;
416 temp
+= bIbuf
[i
+ iSize
- offset
] >> 5;
418 bObuf
[(i
* 2) + 1] = temp
;
429 /*******************************************************************************
430 * IDirectSound3DListener
433 /* IUnknown methods */
434 static HRESULT WINAPI
IDirectSound3DListener_QueryInterface(
435 LPDIRECTSOUND3DLISTENER
this, REFIID riid
, LPVOID
*ppobj
)
439 WINE_StringFromCLSID(riid
,xbuf
);
440 TRACE(dsound
,"(%p,%s,%p)\n",this,xbuf
,ppobj
);
444 static ULONG WINAPI
IDirectSound3DListener_AddRef(LPDIRECTSOUND3DLISTENER
this)
450 static ULONG WINAPI
IDirectSound3DListener_Release(LPDIRECTSOUND3DLISTENER
this)
456 /* IDirectSound3DListener methods */
457 static HRESULT WINAPI
IDirectSound3DListener_GetAllParameter(
458 LPDIRECTSOUND3DLISTENER
this,
459 LPDS3DLISTENER lpDS3DL
)
461 FIXME(dsound
,"stub\n");
465 static HRESULT WINAPI
IDirectSound3DListener_GetDistanceFactor(
466 LPDIRECTSOUND3DLISTENER
this,
467 LPD3DVALUE lpfDistanceFactor
)
469 FIXME(dsound
,"stub\n");
473 static HRESULT WINAPI
IDirectSound3DListener_GetDopplerFactor(
474 LPDIRECTSOUND3DLISTENER
this,
475 LPD3DVALUE lpfDopplerFactor
)
477 FIXME(dsound
,"stub\n");
481 static HRESULT WINAPI
IDirectSound3DListener_GetOrientation(
482 LPDIRECTSOUND3DLISTENER
this,
483 LPD3DVECTOR lpvOrientFront
,
484 LPD3DVECTOR lpvOrientTop
)
486 FIXME(dsound
,"stub\n");
490 static HRESULT WINAPI
IDirectSound3DListener_GetPosition(
491 LPDIRECTSOUND3DLISTENER
this,
492 LPD3DVECTOR lpvPosition
)
494 FIXME(dsound
,"stub\n");
498 static HRESULT WINAPI
IDirectSound3DListener_GetRolloffFactor(
499 LPDIRECTSOUND3DLISTENER
this,
500 LPD3DVALUE lpfRolloffFactor
)
502 FIXME(dsound
,"stub\n");
506 static HRESULT WINAPI
IDirectSound3DListener_GetVelocity(
507 LPDIRECTSOUND3DLISTENER
this,
508 LPD3DVECTOR lpvVelocity
)
510 FIXME(dsound
,"stub\n");
514 static HRESULT WINAPI
IDirectSound3DListener_SetAllParameters(
515 LPDIRECTSOUND3DLISTENER
this,
516 LPCDS3DLISTENER lpcDS3DL
,
519 FIXME(dsound
,"stub\n");
523 static HRESULT WINAPI
IDirectSound3DListener_SetDistanceFactor(
524 LPDIRECTSOUND3DLISTENER
this,
525 D3DVALUE fDistanceFactor
,
528 FIXME(dsound
,"stub\n");
532 static HRESULT WINAPI
IDirectSound3DListener_SetDopplerFactor(
533 LPDIRECTSOUND3DLISTENER
this,
534 D3DVALUE fDopplerFactor
,
537 FIXME(dsound
,"stub\n");
541 static HRESULT WINAPI
IDirectSound3DListener_SetOrientation(
542 LPDIRECTSOUND3DLISTENER
this,
543 D3DVALUE xFront
, D3DVALUE yFront
, D3DVALUE zFront
,
544 D3DVALUE xTop
, D3DVALUE yTop
, D3DVALUE zTop
,
547 FIXME(dsound
,"stub\n");
551 static HRESULT WINAPI
IDirectSound3DListener_SetPosition(
552 LPDIRECTSOUND3DLISTENER
this,
553 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
556 FIXME(dsound
,"stub\n");
560 static HRESULT WINAPI
IDirectSound3DListener_SetRolloffFactor(
561 LPDIRECTSOUND3DLISTENER
this,
562 D3DVALUE fRolloffFactor
,
565 FIXME(dsound
,"stub\n");
569 static HRESULT WINAPI
IDirectSound3DListener_SetVelocity(
570 LPDIRECTSOUND3DLISTENER
this,
571 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
574 FIXME(dsound
,"stub\n");
578 static HRESULT WINAPI
IDirectSound3DListener_CommitDeferredSettings(
579 LPDIRECTSOUND3DLISTENER
this)
582 FIXME(dsound
,"stub\n");
586 IDirectSound3DListener_VTable ds3dlvt
= {
587 /* IUnknown methods */
588 IDirectSound3DListener_QueryInterface
,
589 IDirectSound3DListener_AddRef
,
590 IDirectSound3DListener_Release
,
591 /* IDirectSound3DListener methods */
592 IDirectSound3DListener_GetAllParameter
,
593 IDirectSound3DListener_GetDistanceFactor
,
594 IDirectSound3DListener_GetDopplerFactor
,
595 IDirectSound3DListener_GetOrientation
,
596 IDirectSound3DListener_GetPosition
,
597 IDirectSound3DListener_GetRolloffFactor
,
598 IDirectSound3DListener_GetVelocity
,
599 IDirectSound3DListener_SetAllParameters
,
600 IDirectSound3DListener_SetDistanceFactor
,
601 IDirectSound3DListener_SetDopplerFactor
,
602 IDirectSound3DListener_SetOrientation
,
603 IDirectSound3DListener_SetPosition
,
604 IDirectSound3DListener_SetRolloffFactor
,
605 IDirectSound3DListener_SetVelocity
,
606 IDirectSound3DListener_CommitDeferredSettings
,
609 /*******************************************************************************
612 static HRESULT WINAPI
IDirectSoundNotify_QueryInterface(
613 LPDIRECTSOUNDNOTIFY
this,REFIID riid
,LPVOID
*ppobj
617 WINE_StringFromCLSID(riid
,xbuf
);
618 TRACE(dsound
,"(%p,%s,%p)\n",this,xbuf
,ppobj
);
622 static ULONG WINAPI
IDirectSoundNotify_AddRef(LPDIRECTSOUNDNOTIFY
this) {
623 return ++(this->ref
);
626 static ULONG WINAPI
IDirectSoundNotify_Release(LPDIRECTSOUNDNOTIFY
this) {
629 this->dsb
->lpvtbl
->fnRelease(this->dsb
);
630 HeapFree(GetProcessHeap(),0,this);
636 static HRESULT WINAPI
IDirectSoundNotify_SetNotificationPositions(
637 LPDIRECTSOUNDNOTIFY
this,DWORD howmuch
,LPCDSBPOSITIONNOTIFY notify
641 if (TRACE_ON(dsound
)) {
642 TRACE(dsound
,"(%p,0x%08lx,%p)\n",this,howmuch
,notify
);
643 for (i
=0;i
<howmuch
;i
++)
644 TRACE(dsound
,"notify at %ld to 0x%08lx\n",
645 notify
[i
].dwOffset
,(DWORD
)notify
[i
].hEventNotify
);
647 this->dsb
->notifies
= HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,this->dsb
->notifies
,(this->dsb
->nrofnotifies
+howmuch
)*sizeof(DSBPOSITIONNOTIFY
));
648 memcpy( this->dsb
->notifies
+this->dsb
->nrofnotifies
,
650 howmuch
*sizeof(DSBPOSITIONNOTIFY
)
652 this->dsb
->nrofnotifies
+=howmuch
;
657 IDirectSoundNotify_VTable dsnvt
= {
658 IDirectSoundNotify_QueryInterface
,
659 IDirectSoundNotify_AddRef
,
660 IDirectSoundNotify_Release
,
661 IDirectSoundNotify_SetNotificationPositions
,
664 /*******************************************************************************
668 /* This sets this format for the <em>Primary Buffer Only</em> */
669 /* See file:///cdrom/sdk52/docs/worddoc/dsound.doc page 120 */
670 static HRESULT WINAPI
IDirectSoundBuffer_SetFormat(
671 LPDIRECTSOUNDBUFFER
this,LPWAVEFORMATEX wfex
673 LPDIRECTSOUNDBUFFER
*dsb
;
676 /* Let's be pedantic! */
677 if ((wfex
== NULL
) ||
678 (wfex
->wFormatTag
!= WAVE_FORMAT_PCM
) ||
679 (wfex
->nChannels
< 1) || (wfex
->nChannels
> 2) ||
680 (wfex
->nSamplesPerSec
< 1) ||
681 (wfex
->nBlockAlign
< 1) || (wfex
->nChannels
> 4) ||
682 ((wfex
->wBitsPerSample
!= 8) && (wfex
->wBitsPerSample
!= 16))) {
683 TRACE(dsound
, "failed pedantic check!\n");
684 return DSERR_INVALIDPARAM
;
688 EnterCriticalSection(&(primarybuf
->lock
));
690 if (primarybuf
->wfx
.nSamplesPerSec
!= wfex
->nSamplesPerSec
) {
691 dsb
= dsound
->buffers
;
692 for (i
= 0; i
< dsound
->nrofbuffers
; i
++, dsb
++) {
694 EnterCriticalSection(&((*dsb
)->lock
));
696 (*dsb
)->freqAdjust
= ((*dsb
)->freq
<< DSOUND_FREQSHIFT
) /
697 wfex
->nSamplesPerSec
;
699 LeaveCriticalSection(&((*dsb
)->lock
));
704 memcpy(&(primarybuf
->wfx
), wfex
, sizeof(primarybuf
->wfx
));
706 TRACE(dsound
,"(formattag=0x%04x,chans=%d,samplerate=%ld"
707 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
708 wfex
->wFormatTag
, wfex
->nChannels
, wfex
->nSamplesPerSec
,
709 wfex
->nAvgBytesPerSec
, wfex
->nBlockAlign
,
710 wfex
->wBitsPerSample
, wfex
->cbSize
);
712 primarybuf
->wfx
.nAvgBytesPerSec
=
713 this->wfx
.nSamplesPerSec
* this->wfx
.nBlockAlign
;
717 LeaveCriticalSection(&(primarybuf
->lock
));
723 static HRESULT WINAPI
IDirectSoundBuffer_SetVolume(
724 LPDIRECTSOUNDBUFFER
this,LONG vol
728 TRACE(dsound
,"(%p,%ld)\n",this,vol
);
730 /* I'm not sure if we need this for primary buffer */
731 if (!(this->dsbd
.dwFlags
& DSBCAPS_CTRLVOLUME
))
732 return DSERR_CONTROLUNAVAIL
;
734 if ((vol
> DSBVOLUME_MAX
) || (vol
< DSBVOLUME_MIN
))
735 return DSERR_INVALIDPARAM
;
737 /* This needs to adjust the soundcard volume when */
738 /* called for the primary buffer */
739 if (this->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
740 FIXME(dsound
, "Volume control of primary unimplemented.\n");
746 EnterCriticalSection(&(this->lock
));
750 temp
= (double) (this->volume
- (this->pan
> 0 ? this->pan
: 0));
751 this->lVolAdjust
= (ULONG
) (pow(2.0, temp
/ 600.0) * 32768.0);
752 temp
= (double) (this->volume
+ (this->pan
< 0 ? this->pan
: 0));
753 this->rVolAdjust
= (ULONG
) (pow(2.0, temp
/ 600.0) * 32768.0);
755 LeaveCriticalSection(&(this->lock
));
758 TRACE(dsound
, "left = %lx, right = %lx\n", this->lVolAdjust
, this->rVolAdjust
);
763 static HRESULT WINAPI
IDirectSoundBuffer_GetVolume(
764 LPDIRECTSOUNDBUFFER
this,LPLONG vol
766 TRACE(dsound
,"(%p,%p)\n",this,vol
);
769 return DSERR_INVALIDPARAM
;
775 static HRESULT WINAPI
IDirectSoundBuffer_SetFrequency(
776 LPDIRECTSOUNDBUFFER
this,DWORD freq
778 TRACE(dsound
,"(%p,%ld)\n",this,freq
);
780 /* You cannot set the frequency of the primary buffer */
781 if (!(this->dsbd
.dwFlags
& DSBCAPS_CTRLFREQUENCY
) ||
782 (this->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
))
783 return DSERR_CONTROLUNAVAIL
;
785 if ((freq
< DSBFREQUENCY_MIN
) || (freq
> DSBFREQUENCY_MAX
))
786 return DSERR_INVALIDPARAM
;
789 EnterCriticalSection(&(this->lock
));
792 this->freqAdjust
= (freq
<< DSOUND_FREQSHIFT
) / primarybuf
->wfx
.nSamplesPerSec
;
793 this->nAvgBytesPerSec
= freq
* this->wfx
.nBlockAlign
;
795 LeaveCriticalSection(&(this->lock
));
801 static HRESULT WINAPI
IDirectSoundBuffer_Play(
802 LPDIRECTSOUNDBUFFER
this,DWORD reserved1
,DWORD reserved2
,DWORD flags
804 TRACE(dsound
,"(%p,%08lx,%08lx,%08lx)\n",
805 this,reserved1
,reserved2
,flags
807 this->playflags
= flags
;
812 static HRESULT WINAPI
IDirectSoundBuffer_Stop(LPDIRECTSOUNDBUFFER
this)
814 TRACE(dsound
,"(%p)\n",this);
817 EnterCriticalSection(&(this->lock
));
820 DSOUND_CheckEvent(this, 0);
822 LeaveCriticalSection(&(this->lock
));
828 static DWORD WINAPI
IDirectSoundBuffer_AddRef(LPDIRECTSOUNDBUFFER
this) {
829 /* TRACE(dsound,"(%p) ref was %ld\n",this, this->ref); */
831 return ++(this->ref
);
833 static DWORD WINAPI
IDirectSoundBuffer_Release(LPDIRECTSOUNDBUFFER
this) {
836 /* TRACE(dsound,"(%p) ref was %ld\n",this, this->ref); */
841 for (i
=0;i
<this->dsound
->nrofbuffers
;i
++)
842 if (this->dsound
->buffers
[i
] == this)
844 if (i
< this->dsound
->nrofbuffers
) {
845 /* Put the last buffer of the list in the (now empty) position */
846 this->dsound
->buffers
[i
] = this->dsound
->buffers
[this->dsound
->nrofbuffers
- 1];
847 this->dsound
->buffers
= HeapReAlloc(GetProcessHeap(),0,this->dsound
->buffers
,sizeof(LPDIRECTSOUNDBUFFER
)*this->dsound
->nrofbuffers
);
848 this->dsound
->nrofbuffers
--;
849 this->dsound
->lpvtbl
->fnRelease(this->dsound
);
852 DeleteCriticalSection(&(this->lock
));
854 if (this->ds3db
&& this->ds3db
->lpvtbl
)
855 this->ds3db
->lpvtbl
->fnRelease(this->ds3db
);
858 /* this is a duplicate buffer */
859 this->parent
->lpvtbl
->fnRelease(this->parent
);
861 /* this is a toplevel buffer */
862 HeapFree(GetProcessHeap(),0,this->buffer
);
864 HeapFree(GetProcessHeap(),0,this);
866 if (this == primarybuf
)
872 static HRESULT WINAPI
IDirectSoundBuffer_GetCurrentPosition(
873 LPDIRECTSOUNDBUFFER
this,LPDWORD playpos
,LPDWORD writepos
875 TRACE(dsound
,"(%p,%p,%p)\n",this,playpos
,writepos
);
876 if (playpos
) *playpos
= this->playpos
;
877 if (writepos
) *writepos
= this->writepos
;
878 TRACE(dsound
, "playpos = %ld, writepos = %ld\n", *playpos
, *writepos
);
882 static HRESULT WINAPI
IDirectSoundBuffer_GetStatus(
883 LPDIRECTSOUNDBUFFER
this,LPDWORD status
885 TRACE(dsound
,"(%p,%p)\n",this,status
);
888 return DSERR_INVALIDPARAM
;
892 *status
|= DSBSTATUS_PLAYING
;
893 if (this->playflags
& DSBPLAY_LOOPING
)
894 *status
|= DSBSTATUS_LOOPING
;
900 static HRESULT WINAPI
IDirectSoundBuffer_GetFormat(
901 LPDIRECTSOUNDBUFFER
this,LPWAVEFORMATEX lpwf
,DWORD wfsize
,LPDWORD wfwritten
903 TRACE(dsound
,"(%p,%p,%ld,%p)\n",this,lpwf
,wfsize
,wfwritten
);
905 if (wfsize
>sizeof(this->wfx
))
906 wfsize
= sizeof(this->wfx
);
907 if (lpwf
) { /* NULL is valid */
908 memcpy(lpwf
,&(this->wfx
),wfsize
);
913 *wfwritten
= sizeof(this->wfx
);
915 return DSERR_INVALIDPARAM
;
920 static HRESULT WINAPI
IDirectSoundBuffer_Lock(
921 LPDIRECTSOUNDBUFFER
this,DWORD writecursor
,DWORD writebytes
,LPVOID lplpaudioptr1
,LPDWORD audiobytes1
,LPVOID lplpaudioptr2
,LPDWORD audiobytes2
,DWORD flags
924 TRACE(dsound
,"(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx)\n",
934 if (flags
& DSBLOCK_FROMWRITECURSOR
)
935 writecursor
+= this->writepos
;
936 if (flags
& DSBLOCK_ENTIREBUFFER
)
937 writebytes
= this->buflen
;
938 if (writebytes
> this->buflen
)
939 writebytes
= this->buflen
;
941 assert(audiobytes1
!=audiobytes2
);
942 assert(lplpaudioptr1
!=lplpaudioptr2
);
943 if (writecursor
+writebytes
<= this->buflen
) {
944 *(LPBYTE
*)lplpaudioptr1
= this->buffer
+writecursor
;
945 *audiobytes1
= writebytes
;
947 *(LPBYTE
*)lplpaudioptr2
= NULL
;
950 TRACE(dsound
,"->%ld.0\n",writebytes
);
952 *(LPBYTE
*)lplpaudioptr1
= this->buffer
+writecursor
;
953 *audiobytes1
= this->buflen
-writecursor
;
955 *(LPBYTE
*)lplpaudioptr2
= this->buffer
;
957 *audiobytes2
= writebytes
-(this->buflen
-writecursor
);
958 TRACE(dsound
,"->%ld.%ld\n",*audiobytes1
,audiobytes2
?*audiobytes2
:0);
960 /* No. See file:///cdrom/sdk52/docs/worddoc/dsound.doc page 21 */
961 /* this->writepos=(writecursor+writebytes)%this->buflen; */
965 static HRESULT WINAPI
IDirectSoundBuffer_SetCurrentPosition(
966 LPDIRECTSOUNDBUFFER
this,DWORD newpos
968 TRACE(dsound
,"(%p,%ld)\n",this,newpos
);
971 EnterCriticalSection(&(this->lock
));
973 this->playpos
= newpos
;
975 LeaveCriticalSection(&(this->lock
));
981 static HRESULT WINAPI
IDirectSoundBuffer_SetPan(
982 LPDIRECTSOUNDBUFFER
this,LONG pan
986 TRACE(dsound
,"(%p,%ld)\n",this,pan
);
988 if ((pan
> DSBPAN_RIGHT
) || (pan
< DSBPAN_LEFT
))
989 return DSERR_INVALIDPARAM
;
991 /* You cannot set the pan of the primary buffer */
992 /* and you cannot use both pan and 3D controls */
993 if (!(this->dsbd
.dwFlags
& DSBCAPS_CTRLPAN
) ||
994 (this->dsbd
.dwFlags
& DSBCAPS_CTRL3D
) ||
995 (this->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
))
996 return DSERR_CONTROLUNAVAIL
;
999 EnterCriticalSection(&(this->lock
));
1003 temp
= (double) (this->volume
- (this->pan
> 0 ? this->pan
: 0));
1004 this->lVolAdjust
= (ULONG
) (pow(2.0, temp
/ 600.0) * 32768.0);
1005 temp
= (double) (this->volume
+ (this->pan
< 0 ? this->pan
: 0));
1006 this->rVolAdjust
= (ULONG
) (pow(2.0, temp
/ 600.0) * 32768.0);
1008 LeaveCriticalSection(&(this->lock
));
1014 static HRESULT WINAPI
IDirectSoundBuffer_GetPan(
1015 LPDIRECTSOUNDBUFFER
this,LPLONG pan
1017 TRACE(dsound
,"(%p,%p)\n",this,pan
);
1020 return DSERR_INVALIDPARAM
;
1027 static HRESULT WINAPI
IDirectSoundBuffer_Unlock(
1028 LPDIRECTSOUNDBUFFER
this,LPVOID p1
,DWORD x1
,LPVOID p2
,DWORD x2
1030 TRACE(dsound
,"(%p,%p,%ld,%p,%ld):stub\n", this,p1
,x1
,p2
,x2
);
1032 /* There is really nothing to do here. Should someone */
1033 /* choose to implement static buffers in hardware (by */
1034 /* using a wave table synth, for example) this is where */
1035 /* you'd want to do the loading. For software buffers, */
1036 /* which is what we currently use, we need do nothing. */
1039 /* It's also the place to pre-process 3D buffers... */
1041 /* This is highly experimental and liable to break things */
1042 if (this->dsbd
.dwFlags
& DSBCAPS_CTRL3D
)
1043 DSOUND_Create3DBuffer(this);
1049 static HRESULT WINAPI
IDirectSoundBuffer_GetFrequency(
1050 LPDIRECTSOUNDBUFFER
this,LPDWORD freq
1052 TRACE(dsound
,"(%p,%p)\n",this,freq
);
1055 return DSERR_INVALIDPARAM
;
1062 static HRESULT WINAPI
IDirectSoundBuffer_Initialize(
1063 LPDIRECTSOUNDBUFFER
this,LPDIRECTSOUND dsound
,LPDSBUFFERDESC dbsd
1065 FIXME(dsound
,"(%p,%p,%p):stub\n",this,dsound
,dbsd
);
1066 printf("Re-Init!!!\n");
1067 return DSERR_ALREADYINITIALIZED
;
1070 static HRESULT WINAPI
IDirectSoundBuffer_GetCaps(
1071 LPDIRECTSOUNDBUFFER
this,LPDSBCAPS caps
1073 TRACE(dsound
,"(%p)->(%p)\n",this,caps
);
1076 return DSERR_INVALIDPARAM
;
1078 /* I think we should check this value, not set it. See */
1079 /* Inside DirectX, p215. That should apply here, too. */
1080 caps
->dwSize
= sizeof(*caps
);
1082 caps
->dwFlags
= this->dsbd
.dwFlags
| DSBCAPS_LOCSOFTWARE
;
1083 caps
->dwBufferBytes
= this->dsbd
.dwBufferBytes
;
1084 /* This value represents the speed of the "unlock" command.
1085 As unlock is quite fast (it does not do anything), I put
1086 4096 ko/s = 4 Mo / s */
1087 caps
->dwUnlockTransferRate
= 4096;
1088 caps
->dwPlayCpuOverhead
= 0;
1093 static HRESULT WINAPI
IDirectSoundBuffer_QueryInterface(
1094 LPDIRECTSOUNDBUFFER
this,REFIID riid
,LPVOID
*ppobj
1098 WINE_StringFromCLSID(riid
,xbuf
);
1099 TRACE(dsound
,"(%p,%s,%p)\n",this,xbuf
,ppobj
);
1101 if (!memcmp(&IID_IDirectSoundNotify
,riid
,sizeof(*riid
))) {
1102 IDirectSoundNotify
*dsn
;
1104 dsn
= (LPDIRECTSOUNDNOTIFY
)HeapAlloc(GetProcessHeap(),0,sizeof(*dsn
));
1107 this->lpvtbl
->fnAddRef(this);
1108 dsn
->lpvtbl
= &dsnvt
;
1109 *ppobj
= (LPVOID
)dsn
;
1113 if (!memcmp(&IID_IDirectSound3DBuffer
,riid
,sizeof(*riid
))) {
1114 *ppobj
= this->ds3db
;
1122 static struct tagLPDIRECTSOUNDBUFFER_VTABLE dsbvt
= {
1123 IDirectSoundBuffer_QueryInterface
,
1124 IDirectSoundBuffer_AddRef
,
1125 IDirectSoundBuffer_Release
,
1126 IDirectSoundBuffer_GetCaps
,
1127 IDirectSoundBuffer_GetCurrentPosition
,
1128 IDirectSoundBuffer_GetFormat
,
1129 IDirectSoundBuffer_GetVolume
,
1130 IDirectSoundBuffer_GetPan
,
1131 IDirectSoundBuffer_GetFrequency
,
1132 IDirectSoundBuffer_GetStatus
,
1133 IDirectSoundBuffer_Initialize
,
1134 IDirectSoundBuffer_Lock
,
1135 IDirectSoundBuffer_Play
,
1136 IDirectSoundBuffer_SetCurrentPosition
,
1137 IDirectSoundBuffer_SetFormat
,
1138 IDirectSoundBuffer_SetVolume
,
1139 IDirectSoundBuffer_SetPan
,
1140 IDirectSoundBuffer_SetFrequency
,
1141 IDirectSoundBuffer_Stop
,
1142 IDirectSoundBuffer_Unlock
1145 /*******************************************************************************
1149 static HRESULT WINAPI
IDirectSound_SetCooperativeLevel(
1150 LPDIRECTSOUND
this,HWND32 hwnd
,DWORD level
1152 FIXME(dsound
,"(%p,%08lx,%ld):stub\n",this,(DWORD
)hwnd
,level
);
1156 static HRESULT WINAPI
IDirectSound_CreateSoundBuffer(
1157 LPDIRECTSOUND
this,LPDSBUFFERDESC dsbd
,LPLPDIRECTSOUNDBUFFER ppdsb
,LPUNKNOWN lpunk
1159 LPWAVEFORMATEX wfex
;
1161 TRACE(dsound
,"(%p,%p,%p,%p)\n",this,dsbd
,ppdsb
,lpunk
);
1163 if ((this == NULL
) || (dsbd
== NULL
) || (ppdsb
== NULL
))
1164 return DSERR_INVALIDPARAM
;
1166 if (TRACE_ON(dsound
)) {
1167 TRACE(dsound
,"(size=%ld)\n",dsbd
->dwSize
);
1168 TRACE(dsound
,"(flags=0x%08lx\n",dsbd
->dwFlags
);
1169 _dump_DSBCAPS(dsbd
->dwFlags
);
1170 TRACE(dsound
,"(bufferbytes=%ld)\n",dsbd
->dwBufferBytes
);
1171 TRACE(dsound
,"(lpwfxFormat=%p)\n",dsbd
->lpwfxFormat
);
1174 wfex
= dsbd
->lpwfxFormat
;
1177 TRACE(dsound
,"(formattag=0x%04x,chans=%d,samplerate=%ld"
1178 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
1179 wfex
->wFormatTag
, wfex
->nChannels
, wfex
->nSamplesPerSec
,
1180 wfex
->nAvgBytesPerSec
, wfex
->nBlockAlign
,
1181 wfex
->wBitsPerSample
, wfex
->cbSize
);
1183 if (dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
1185 primarybuf
->lpvtbl
->fnAddRef(primarybuf
);
1186 *ppdsb
= primarybuf
;
1188 } /* Else create primarybuf */
1191 *ppdsb
= (LPDIRECTSOUNDBUFFER
)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDirectSoundBuffer
));
1193 return DSERR_OUTOFMEMORY
;
1196 TRACE(dsound
, "Created buffer at %p\n", *ppdsb
);
1198 if (dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
1199 (*ppdsb
)->buflen
= dsound
->wfx
.nAvgBytesPerSec
;
1200 (*ppdsb
)->freq
= dsound
->wfx
.nSamplesPerSec
;
1202 (*ppdsb
)->buflen
= dsbd
->dwBufferBytes
;
1203 (*ppdsb
)->freq
= dsbd
->lpwfxFormat
->nSamplesPerSec
;
1205 (*ppdsb
)->buffer
= (LPBYTE
)HeapAlloc(GetProcessHeap(),0,(*ppdsb
)->buflen
);
1206 if ((*ppdsb
)->buffer
== NULL
) {
1207 HeapFree(GetProcessHeap(),0,(*ppdsb
));
1209 return DSERR_OUTOFMEMORY
;
1211 /* It's not necessary to initialize values to zero since */
1212 /* we allocated this structure with HEAP_ZERO_MEMORY... */
1213 (*ppdsb
)->playpos
= 0;
1214 (*ppdsb
)->writepos
= 0;
1215 (*ppdsb
)->parent
= NULL
;
1216 (*ppdsb
)->lpvtbl
= &dsbvt
;
1217 (*ppdsb
)->dsound
= this;
1218 (*ppdsb
)->playing
= 0;
1219 (*ppdsb
)->lVolAdjust
= (1 << 15);
1220 (*ppdsb
)->rVolAdjust
= (1 << 15);
1222 if (!(dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
)) {
1223 (*ppdsb
)->freqAdjust
= ((*ppdsb
)->freq
<< DSOUND_FREQSHIFT
) /
1224 primarybuf
->wfx
.nSamplesPerSec
;
1225 (*ppdsb
)->nAvgBytesPerSec
= (*ppdsb
)->freq
*
1226 dsbd
->lpwfxFormat
->nBlockAlign
;
1229 memcpy(&((*ppdsb
)->dsbd
),dsbd
,sizeof(*dsbd
));
1231 /* register buffer */
1232 if (!(dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
)) {
1233 this->buffers
= (LPDIRECTSOUNDBUFFER
*)HeapReAlloc(GetProcessHeap(),0,this->buffers
,sizeof(LPDIRECTSOUNDBUFFER
)*(this->nrofbuffers
+1));
1234 this->buffers
[this->nrofbuffers
] = *ppdsb
;
1235 this->nrofbuffers
++;
1237 this->lpvtbl
->fnAddRef(this);
1239 if (dsbd
->lpwfxFormat
)
1240 memcpy(&((*ppdsb
)->wfx
), dsbd
->lpwfxFormat
, sizeof((*ppdsb
)->wfx
));
1242 InitializeCriticalSection(&((*ppdsb
)->lock
));
1245 if (dsbd
->dwFlags
& DSBCAPS_CTRL3D
) {
1246 IDirectSound3DBuffer
*ds3db
;
1248 ds3db
= (LPDIRECTSOUND3DBUFFER
)HeapAlloc(GetProcessHeap(),
1251 ds3db
->dsb
= (*ppdsb
);
1252 ds3db
->lpvtbl
= &ds3dbvt
;
1253 (*ppdsb
)->ds3db
= ds3db
;
1254 ds3db
->ds3db
.dwSize
= sizeof(DS3DBUFFER
);
1255 ds3db
->ds3db
.vPosition
.x
.x
= 0.0;
1256 ds3db
->ds3db
.vPosition
.y
.y
= 0.0;
1257 ds3db
->ds3db
.vPosition
.z
.z
= 0.0;
1258 ds3db
->ds3db
.vVelocity
.x
.x
= 0.0;
1259 ds3db
->ds3db
.vVelocity
.y
.y
= 0.0;
1260 ds3db
->ds3db
.vVelocity
.z
.z
= 0.0;
1261 ds3db
->ds3db
.dwInsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
1262 ds3db
->ds3db
.dwOutsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
1263 ds3db
->ds3db
.vConeOrientation
.x
.x
= 0.0;
1264 ds3db
->ds3db
.vConeOrientation
.y
.y
= 0.0;
1265 ds3db
->ds3db
.vConeOrientation
.z
.z
= 0.0;
1266 ds3db
->ds3db
.lConeOutsideVolume
= DS3D_DEFAULTCONEOUTSIDEVOLUME
;
1267 ds3db
->ds3db
.flMinDistance
= DS3D_DEFAULTMINDISTANCE
;
1268 ds3db
->ds3db
.flMaxDistance
= DS3D_DEFAULTMAXDISTANCE
;
1269 ds3db
->ds3db
.dwMode
= DS3DMODE_NORMAL
;
1270 ds3db
->buflen
= ((*ppdsb
)->buflen
* primarybuf
->wfx
.nBlockAlign
) /
1271 (*ppdsb
)->wfx
.nBlockAlign
;
1272 ds3db
->buffer
= HeapAlloc(GetProcessHeap(), 0, ds3db
->buflen
);
1273 if (ds3db
->buffer
== NULL
) {
1275 ds3db
->ds3db
.dwMode
= DS3DMODE_DISABLE
;
1282 static HRESULT WINAPI
IDirectSound_DuplicateSoundBuffer(
1283 LPDIRECTSOUND
this,LPDIRECTSOUNDBUFFER pdsb
,LPLPDIRECTSOUNDBUFFER ppdsb
1285 TRACE(dsound
,"(%p,%p,%p)\n",this,pdsb
,ppdsb
);
1287 *ppdsb
= (LPDIRECTSOUNDBUFFER
)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDirectSoundBuffer
));
1289 pdsb
->lpvtbl
->fnAddRef(pdsb
);
1290 memcpy(*ppdsb
, pdsb
, sizeof(IDirectSoundBuffer
));
1292 (*ppdsb
)->playpos
= 0;
1293 (*ppdsb
)->writepos
= 0;
1294 (*ppdsb
)->dsound
= this;
1295 (*ppdsb
)->parent
= pdsb
;
1296 memcpy(&((*ppdsb
)->wfx
), &(pdsb
->wfx
), sizeof((*ppdsb
)->wfx
));
1297 /* register buffer */
1298 this->buffers
= (LPDIRECTSOUNDBUFFER
*)HeapReAlloc(GetProcessHeap(),0,this->buffers
,sizeof(LPDIRECTSOUNDBUFFER
)*(this->nrofbuffers
+1));
1299 this->buffers
[this->nrofbuffers
] = *ppdsb
;
1300 this->nrofbuffers
++;
1301 this->lpvtbl
->fnAddRef(this);
1306 static HRESULT WINAPI
IDirectSound_GetCaps(LPDIRECTSOUND
this,LPDSCAPS caps
) {
1307 TRACE(dsound
,"(%p,%p)\n",this,caps
);
1308 TRACE(dsound
,"(flags=0x%08lx)\n",caps
->dwFlags
);
1311 return DSERR_INVALIDPARAM
;
1313 /* We should check this value, not set it. See Inside DirectX, p215. */
1314 caps
->dwSize
= sizeof(*caps
);
1317 DSCAPS_PRIMARYSTEREO
|
1318 DSCAPS_PRIMARY16BIT
|
1319 DSCAPS_SECONDARYSTEREO
|
1320 DSCAPS_SECONDARY16BIT
|
1321 DSCAPS_CONTINUOUSRATE
;
1322 /* FIXME: query OSS */
1323 caps
->dwMinSecondarySampleRate
= DSBFREQUENCY_MIN
;
1324 caps
->dwMaxSecondarySampleRate
= DSBFREQUENCY_MAX
;
1326 caps
->dwPrimaryBuffers
= 1;
1328 caps
->dwMaxHwMixingAllBuffers
= 0;
1329 caps
->dwMaxHwMixingStaticBuffers
= 0;
1330 caps
->dwMaxHwMixingStreamingBuffers
= 0;
1332 caps
->dwFreeHwMixingAllBuffers
= 0;
1333 caps
->dwFreeHwMixingStaticBuffers
= 0;
1334 caps
->dwFreeHwMixingStreamingBuffers
= 0;
1336 caps
->dwMaxHw3DAllBuffers
= 0;
1337 caps
->dwMaxHw3DStaticBuffers
= 0;
1338 caps
->dwMaxHw3DStreamingBuffers
= 0;
1340 caps
->dwFreeHw3DAllBuffers
= 0;
1341 caps
->dwFreeHw3DStaticBuffers
= 0;
1342 caps
->dwFreeHw3DStreamingBuffers
= 0;
1344 caps
->dwTotalHwMemBytes
= 0;
1346 caps
->dwFreeHwMemBytes
= 0;
1348 caps
->dwMaxContigFreeHwMemBytes
= 0;
1350 caps
->dwUnlockTransferRateHwBuffers
= 4096; /* But we have none... */
1352 caps
->dwPlayCpuOverheadSwBuffers
= 1; /* 1% */
1357 static ULONG WINAPI
IDirectSound_AddRef(LPDIRECTSOUND
this) {
1358 return ++(this->ref
);
1361 static ULONG WINAPI
IDirectSound_Release(LPDIRECTSOUND
this) {
1362 TRACE(dsound
,"(%p), ref was %ld\n",this,this->ref
);
1363 if (!--(this->ref
)) {
1364 DSOUND_CloseAudio();
1365 while(IDirectSoundBuffer_Release(primarybuf
)); /* Deallocate */
1366 FIXME(dsound
, "need to release all buffers!\n");
1367 HeapFree(GetProcessHeap(),0,this);
1374 static HRESULT WINAPI
IDirectSound_SetSpeakerConfig(
1375 LPDIRECTSOUND
this,DWORD config
1377 FIXME(dsound
,"(%p,0x%08lx):stub\n",this,config
);
1381 static HRESULT WINAPI
IDirectSound_QueryInterface(
1382 LPDIRECTSOUND
this,REFIID riid
,LPVOID
*ppobj
1386 if (!memcmp(&IID_IDirectSound3DListener
,riid
,sizeof(*riid
))) {
1388 if (this->listener
) {
1389 *ppobj
= this->listener
;
1392 this->listener
= (LPDIRECTSOUND3DLISTENER
)HeapAlloc(
1393 GetProcessHeap(), 0, sizeof(*(this->listener
)));
1394 this->listener
->ref
= 1;
1395 this->listener
->lpvtbl
= &ds3dlvt
;
1396 this->lpvtbl
->fnAddRef(this);
1397 this->listener
->ds3dl
.dwSize
= sizeof(DS3DLISTENER
);
1398 this->listener
->ds3dl
.vPosition
.x
.x
= 0.0;
1399 this->listener
->ds3dl
.vPosition
.y
.y
= 0.0;
1400 this->listener
->ds3dl
.vPosition
.z
.z
= 0.0;
1401 this->listener
->ds3dl
.vVelocity
.x
.x
= 0.0;
1402 this->listener
->ds3dl
.vVelocity
.y
.y
= 0.0;
1403 this->listener
->ds3dl
.vVelocity
.z
.z
= 0.0;
1404 this->listener
->ds3dl
.vOrientFront
.x
.x
= 0.0;
1405 this->listener
->ds3dl
.vOrientFront
.y
.y
= 0.0;
1406 this->listener
->ds3dl
.vOrientFront
.z
.z
= 1.0;
1407 this->listener
->ds3dl
.vOrientTop
.x
.x
= 0.0;
1408 this->listener
->ds3dl
.vOrientTop
.y
.y
= 1.0;
1409 this->listener
->ds3dl
.vOrientTop
.z
.z
= 0.0;
1410 this->listener
->ds3dl
.flDistanceFactor
= DS3D_DEFAULTDISTANCEFACTOR
;
1411 this->listener
->ds3dl
.flRolloffFactor
= DS3D_DEFAULTROLLOFFFACTOR
;
1412 this->listener
->ds3dl
.flDopplerFactor
= DS3D_DEFAULTDOPPLERFACTOR
;
1413 *ppobj
= (LPVOID
)this->listener
;
1417 WINE_StringFromCLSID(riid
,xbuf
);
1418 TRACE(dsound
,"(%p,%s,%p)\n",this,xbuf
,ppobj
);
1422 static HRESULT WINAPI
IDirectSound_Compact(
1425 TRACE(dsound
, "(%p)\n", this);
1429 static HRESULT WINAPI
IDirectSound_GetSpeakerConfig(
1431 LPDWORD lpdwSpeakerConfig
)
1433 TRACE(dsound
, "(%p, %p)\n", this, lpdwSpeakerConfig
);
1434 *lpdwSpeakerConfig
= DSSPEAKER_STEREO
| (DSSPEAKER_GEOMETRY_NARROW
<< 16);
1438 static HRESULT WINAPI
IDirectSound_Initialize(
1442 TRACE(dsound
, "(%p, %p)\n", this, lpGuid
);
1446 static struct tagLPDIRECTSOUND_VTABLE dsvt
= {
1447 IDirectSound_QueryInterface
,
1448 IDirectSound_AddRef
,
1449 IDirectSound_Release
,
1450 IDirectSound_CreateSoundBuffer
,
1451 IDirectSound_GetCaps
,
1452 IDirectSound_DuplicateSoundBuffer
,
1453 IDirectSound_SetCooperativeLevel
,
1454 IDirectSound_Compact
,
1455 IDirectSound_GetSpeakerConfig
,
1456 IDirectSound_SetSpeakerConfig
,
1457 IDirectSound_Initialize
1461 /* See http://www.opensound.com/pguide/audio.html for more details */
1464 DSOUND_setformat(LPWAVEFORMATEX wfex
) {
1465 int xx
,channels
,speed
,format
,nformat
;
1468 TRACE(dsound
, "(%p) deferred\n", wfex
);
1471 switch (wfex
->wFormatTag
) {
1473 WARN(dsound
,"unknown WAVE_FORMAT tag %d\n",wfex
->wFormatTag
);
1474 return DSERR_BADFORMAT
;
1475 case WAVE_FORMAT_PCM
:
1478 if (wfex
->wBitsPerSample
==8)
1481 format
= AFMT_S16_LE
;
1483 if (-1==ioctl(audiofd
,SNDCTL_DSP_GETFMTS
,&xx
)) {
1484 perror("ioctl SNDCTL_DSP_GETFMTS");
1487 if ((xx
&format
)!=format
) {/* format unsupported */
1488 FIXME(dsound
,"SNDCTL_DSP_GETFMTS: format not supported\n");
1492 if (-1==ioctl(audiofd
,SNDCTL_DSP_SETFMT
,&nformat
)) {
1493 perror("ioctl SNDCTL_DSP_SETFMT");
1496 if (nformat
!=format
) {/* didn't work */
1497 FIXME(dsound
,"SNDCTL_DSP_GETFMTS: format not set\n");
1501 channels
= wfex
->nChannels
-1;
1502 if (-1==ioctl(audiofd
,SNDCTL_DSP_STEREO
,&channels
)) {
1503 perror("ioctl SNDCTL_DSP_STEREO");
1506 speed
= wfex
->nSamplesPerSec
;
1507 if (-1==ioctl(audiofd
,SNDCTL_DSP_SPEED
,&speed
)) {
1508 perror("ioctl SNDCTL_DSP_SPEED");
1511 TRACE(dsound
,"(freq=%ld,channels=%d,bits=%d)\n",
1512 wfex
->nSamplesPerSec
,wfex
->nChannels
,wfex
->wBitsPerSample
1517 static void DSOUND_CheckEvent(IDirectSoundBuffer
*dsb
, int len
)
1521 LPDSBPOSITIONNOTIFY event
;
1523 if (dsb
->nrofnotifies
== 0)
1526 TRACE(dsound
,"(%p) buflen = %ld, playpos = %ld, len = %d\n",
1527 dsb
, dsb
->buflen
, dsb
->playpos
, len
);
1528 for (i
= 0; i
< dsb
->nrofnotifies
; i
++) {
1529 event
= dsb
->notifies
+ i
;
1530 offset
= event
->dwOffset
;
1531 TRACE(dsound
, "checking %d, position %ld, event = %d\n",
1532 i
, offset
, event
->hEventNotify
);
1533 /* DSBPN_OFFSETSTOP has to be the last element. So this is */
1534 /* OK. [Inside DirectX, p274] */
1536 /* This also means we can't sort the entries by offset, */
1537 /* because DSBPN_OFFSETSTOP == -1 */
1538 if (offset
== DSBPN_OFFSETSTOP
) {
1539 if (dsb
->playing
== 0) {
1540 SetEvent(event
->hEventNotify
);
1541 TRACE(dsound
,"signalled event %d (%d)\n", event
->hEventNotify
, i
);
1546 if ((dsb
->playpos
+ len
) >= dsb
->buflen
) {
1547 if ((offset
< ((dsb
->playpos
+ len
) % dsb
->buflen
)) ||
1548 (offset
>= dsb
->playpos
)) {
1549 TRACE(dsound
,"signalled event %d (%d)\n", event
->hEventNotify
, i
);
1550 SetEvent(event
->hEventNotify
);
1553 if ((offset
>= dsb
->playpos
) && (offset
< (dsb
->playpos
+ len
))) {
1554 TRACE(dsound
,"signalled event %d (%d)\n", event
->hEventNotify
, i
);
1555 SetEvent(event
->hEventNotify
);
1561 /* WAV format info can be found at: */
1563 /* http://www.cwi.nl/ftp/audio/AudioFormats.part2 */
1564 /* ftp://ftp.cwi.nl/pub/audio/RIFF-format */
1566 /* Import points to remember: */
1568 /* 8-bit WAV is unsigned */
1569 /* 16-bit WAV is signed */
1571 static inline INT16
cvtU8toS16(BYTE byte
)
1573 INT16 s
= (byte
- 128) << 8;
1578 static inline BYTE
cvtS16toU8(INT16 word
)
1580 BYTE b
= (word
+ 32768) >> 8;
1586 /* We should be able to optimize these two inline functions */
1587 /* so that we aren't doing 8->16->8 conversions when it is */
1588 /* not necessary. But this is still a WIP. Optimize later. */
1589 static inline void get_fields(const IDirectSoundBuffer
*dsb
, BYTE
*buf
, INT32
*fl
, INT32
*fr
)
1591 INT16
*bufs
= (INT16
*) buf
;
1593 /* TRACE(dsound, "(%p)", buf); */
1594 if ((dsb
->wfx
.wBitsPerSample
== 8) && dsb
->wfx
.nChannels
== 2) {
1595 *fl
= cvtU8toS16(*buf
);
1596 *fr
= cvtU8toS16(*(buf
+ 1));
1600 if ((dsb
->wfx
.wBitsPerSample
== 16) && dsb
->wfx
.nChannels
== 2) {
1606 if ((dsb
->wfx
.wBitsPerSample
== 8) && dsb
->wfx
.nChannels
== 1) {
1607 *fl
= cvtU8toS16(*buf
);
1612 if ((dsb
->wfx
.wBitsPerSample
== 16) && dsb
->wfx
.nChannels
== 1) {
1618 FIXME(dsound
, "get_fields found an unsupported configuration\n");
1622 static inline void set_fields(BYTE
*buf
, INT32 fl
, INT32 fr
)
1624 INT16
*bufs
= (INT16
*) buf
;
1626 if ((primarybuf
->wfx
.wBitsPerSample
== 8) && (primarybuf
->wfx
.nChannels
== 2)) {
1627 *buf
= cvtS16toU8(fl
);
1628 *(buf
+ 1) = cvtS16toU8(fr
);
1632 if ((primarybuf
->wfx
.wBitsPerSample
== 16) && (primarybuf
->wfx
.nChannels
== 2)) {
1638 if ((primarybuf
->wfx
.wBitsPerSample
== 8) && (primarybuf
->wfx
.nChannels
== 1)) {
1639 *buf
= cvtS16toU8((fl
+ fr
) >> 1);
1643 if ((primarybuf
->wfx
.wBitsPerSample
== 16) && (primarybuf
->wfx
.nChannels
== 1)) {
1644 *bufs
= (fl
+ fr
) >> 1;
1647 FIXME(dsound
, "set_fields found an unsupported configuration\n");
1651 /* Now with PerfectPitch (tm) technology */
1652 static INT32
DSOUND_MixerNorm(IDirectSoundBuffer
*dsb
, BYTE
*buf
, INT32 len
)
1654 INT32 i
, size
, ipos
, ilen
, fieldL
, fieldR
;
1656 INT32 iAdvance
= dsb
->wfx
.nBlockAlign
;
1657 INT32 oAdvance
= primarybuf
->wfx
.nBlockAlign
;
1659 ibp
= dsb
->buffer
+ dsb
->playpos
;
1662 TRACE(dsound
, "(%p, %p, %p), playpos=%8.8lx\n", dsb
, ibp
, obp
, dsb
->playpos
);
1663 /* Check for the best case */
1664 if ((dsb
->freq
== primarybuf
->wfx
.nSamplesPerSec
) &&
1665 (dsb
->wfx
.wBitsPerSample
== primarybuf
->wfx
.wBitsPerSample
) &&
1666 (dsb
->wfx
.nChannels
== primarybuf
->wfx
.nChannels
)) {
1667 TRACE(dsound
, "(%p) Best case\n", dsb
);
1668 if ((ibp
+ len
) < (BYTE
*)(dsb
->buffer
+ dsb
->buflen
))
1669 memcpy(obp
, ibp
, len
);
1671 memcpy(obp
, ibp
, dsb
->buflen
- dsb
->playpos
);
1672 memcpy(obp
+ (dsb
->buflen
- dsb
->playpos
),
1674 len
- (dsb
->buflen
- dsb
->playpos
));
1679 /* Check for same sample rate */
1680 if (dsb
->freq
== primarybuf
->wfx
.nSamplesPerSec
) {
1681 TRACE(dsound
, "(%p) Same sample rate %ld = primary %ld\n", dsb
,
1682 dsb
->freq
, primarybuf
->wfx
.nSamplesPerSec
);
1684 for (i
= 0; i
< len
; i
+= oAdvance
) {
1685 get_fields(dsb
, ibp
, &fieldL
, &fieldR
);
1688 set_fields(obp
, fieldL
, fieldR
);
1690 if (ibp
>= (BYTE
*)(dsb
->buffer
+ dsb
->buflen
))
1691 ibp
= dsb
->buffer
; /* wrap */
1696 /* Mix in different sample rates */
1698 /* New PerfectPitch(tm) Technology (c) 1998 Rob Riggs */
1699 /* Patent Pending :-] */
1701 TRACE(dsound
, "(%p) Adjusting frequency: %ld -> %ld\n",
1702 dsb
, dsb
->freq
, primarybuf
->wfx
.nSamplesPerSec
);
1704 size
= len
/ oAdvance
;
1705 ilen
= ((size
* dsb
->freqAdjust
) >> DSOUND_FREQSHIFT
) * iAdvance
;
1706 for (i
= 0; i
< size
; i
++) {
1708 ipos
= (((i
* dsb
->freqAdjust
) >> DSOUND_FREQSHIFT
) * iAdvance
) + dsb
->playpos
;
1710 if (ipos
>= dsb
->buflen
)
1711 ipos
%= dsb
->buflen
; /* wrap */
1713 get_fields(dsb
, (dsb
->buffer
+ ipos
), &fieldL
, &fieldR
);
1714 set_fields(obp
, fieldL
, fieldR
);
1720 static void DSOUND_MixerVol(IDirectSoundBuffer
*dsb
, BYTE
*buf
, INT32 len
)
1722 INT32 i
, inc
= primarybuf
->wfx
.wBitsPerSample
>> 3;
1724 INT16
*bps
= (INT16
*) buf
;
1726 TRACE(dsound
, "(%p) left = %lx, right = %lx\n", dsb
,
1727 dsb
->lVolAdjust
, dsb
->rVolAdjust
);
1728 if ((!(dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLPAN
) || (dsb
->pan
== 0)) &&
1729 (!(dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLVOLUME
) || (dsb
->volume
== 0)) &&
1730 !(dsb
->dsbd
.dwFlags
& DSBCAPS_CTRL3D
))
1731 return; /* Nothing to do */
1733 /* If we end up with some bozo coder using panning or 3D sound */
1734 /* with a mono primary buffer, it could sound very weird using */
1735 /* this method. Oh well, tough patooties. */
1737 for (i
= 0; i
< len
; i
+= inc
) {
1743 /* 8-bit WAV is unsigned, but we need to operate */
1744 /* on signed data for this to work properly */
1746 val
= ((val
* (i
& inc
? dsb
->rVolAdjust
: dsb
->lVolAdjust
)) >> 15);
1751 /* 16-bit WAV is signed -- much better */
1753 val
= ((val
* ((i
& inc
) ? dsb
->rVolAdjust
: dsb
->lVolAdjust
)) >> 15);
1759 FIXME(dsound
, "MixerVol had a nasty error\n");
1765 static void DSOUND_Mixer3D(IDirectSoundBuffer
*dsb
, BYTE
*buf
, INT32 len
)
1768 DWORD buflen
, playpos
;
1770 buflen
= dsb
->ds3db
->buflen
;
1771 playpos
= (dsb
->playpos
* primarybuf
->wfx
.nBlockAlign
) / dsb
->wfx
.nBlockAlign
;
1772 ibp
= dsb
->ds3db
->buffer
+ playpos
;
1775 if (playpos
> buflen
) {
1776 FIXME(dsound
, "Major breakage");
1780 if (len
<= (playpos
+ buflen
))
1781 memcpy(obp
, ibp
, len
);
1783 memcpy(obp
, ibp
, buflen
- playpos
);
1784 memcpy(obp
+ (buflen
- playpos
),
1786 len
- (buflen
- playpos
));
1792 static DWORD
DSOUND_MixInBuffer(IDirectSoundBuffer
*dsb
)
1794 INT32 i
, len
, ilen
, temp
, field
;
1795 INT32 advance
= primarybuf
->wfx
.wBitsPerSample
>> 3;
1796 BYTE
*buf
, *ibuf
, *obuf
;
1797 INT16
*ibufs
, *obufs
;
1799 len
= DSOUND_FRAGLEN
; /* The most we will use */
1800 if (!(dsb
->playflags
& DSBPLAY_LOOPING
)) {
1801 temp
= MulDiv32(primarybuf
->wfx
.nAvgBytesPerSec
, dsb
->buflen
,
1802 dsb
->nAvgBytesPerSec
) -
1803 MulDiv32(primarybuf
->wfx
.nAvgBytesPerSec
, dsb
->playpos
,
1804 dsb
->nAvgBytesPerSec
);
1805 len
= (len
> temp
) ? temp
: len
;
1807 len
&= ~3; /* 4 byte alignment */
1810 /* This should only happen if we aren't looping and temp < 4 */
1812 /* We skip the remainder, so check for possible events */
1813 DSOUND_CheckEvent(dsb
, dsb
->buflen
- dsb
->playpos
);
1818 /* Check for DSBPN_OFFSETSTOP */
1819 DSOUND_CheckEvent(dsb
, 0);
1823 /* Been seeing segfaults in malloc() for some reason... */
1824 TRACE(dsound
, "allocating buffer (size = %d)\n", len
);
1825 if ((buf
= ibuf
= (BYTE
*) malloc(len
)) == NULL
)
1828 TRACE(dsound
, "MixInBuffer (%p) len = %d\n", dsb
, len
);
1830 ilen
= DSOUND_MixerNorm(dsb
, ibuf
, len
);
1831 if ((dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLPAN
) ||
1832 (dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLVOLUME
))
1833 DSOUND_MixerVol(dsb
, ibuf
, len
);
1835 obuf
= primarybuf
->buffer
+ primarybuf
->playpos
;
1836 for (i
= 0; i
< len
; i
+= advance
) {
1837 obufs
= (INT16
*) obuf
;
1838 ibufs
= (INT16
*) ibuf
;
1839 if (primarybuf
->wfx
.wBitsPerSample
== 8) {
1840 /* 8-bit WAV is unsigned */
1841 field
= (*ibuf
- 128);
1842 field
+= (*obuf
- 128);
1843 field
= field
> 127 ? 127 : field
;
1844 field
= field
< -128 ? -128 : field
;
1845 *obuf
= field
+ 128;
1847 /* 16-bit WAV is signed */
1850 field
= field
> 32767 ? 32767 : field
;
1851 field
= field
< -32768 ? -32768 : field
;
1856 if (obuf
>= (BYTE
*)(primarybuf
->buffer
+ primarybuf
->buflen
))
1857 obuf
= primarybuf
->buffer
;
1861 if (dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLPOSITIONNOTIFY
)
1862 DSOUND_CheckEvent(dsb
, ilen
);
1864 dsb
->playpos
+= ilen
;
1865 dsb
->writepos
= dsb
->playpos
+ ilen
;
1867 if (dsb
->playpos
>= dsb
->buflen
) {
1868 if (!(dsb
->playflags
& DSBPLAY_LOOPING
)) {
1872 DSOUND_CheckEvent(dsb
, 0); /* For DSBPN_OFFSETSTOP */
1874 dsb
->playpos
%= dsb
->buflen
; /* wrap */
1877 if (dsb
->writepos
>= dsb
->buflen
)
1878 dsb
->writepos
%= dsb
->buflen
;
1883 static DWORD WINAPI
DSOUND_MixPrimary(void)
1885 INT32 i
, len
, maxlen
= 0;
1886 IDirectSoundBuffer
*dsb
;
1888 for (i
= dsound
->nrofbuffers
- 1; i
>= 0; i
--) {
1889 dsb
= dsound
->buffers
[i
];
1891 if (!dsb
|| !(dsb
->lpvtbl
))
1893 dsb
->lpvtbl
->fnAddRef(dsb
);
1894 if (dsb
->buflen
&& dsb
->playing
) {
1895 EnterCriticalSection(&(dsb
->lock
));
1896 len
= DSOUND_MixInBuffer(dsb
);
1897 maxlen
= len
> maxlen
? len
: maxlen
;
1898 LeaveCriticalSection(&(dsb
->lock
));
1900 dsb
->lpvtbl
->fnRelease(dsb
);
1906 static int DSOUND_OpenAudio(void)
1910 if (primarybuf
== NULL
)
1911 return DSERR_OUTOFMEMORY
;
1913 while (audiofd
!= -1)
1915 audiofd
= open("/dev/audio",O_WRONLY
);
1917 /* Don't worry if sound is busy at the moment */
1919 perror("open /dev/audio");
1920 return audiofd
; /* -1 */
1923 /* We should probably do something here if SETFRAGMENT fails... */
1924 audioFragment
=0x0002000c;
1925 if (-1==ioctl(audiofd
,SNDCTL_DSP_SETFRAGMENT
,&audioFragment
))
1926 perror("ioctl SETFRAGMENT");
1929 DSOUND_setformat(&(primarybuf
->wfx
));
1934 static void DSOUND_CloseAudio(void)
1938 neutral
= primarybuf
->wfx
.wBitsPerSample
== 8 ? 128 : 0;
1939 audioOK
= 0; /* race condition */
1941 /* It's possible we've been called with audio closed */
1942 /* from SetFormat()... this is just to force a call */
1943 /* to OpenAudio() to reset the hardware properly */
1946 primarybuf
->playpos
= 0;
1947 primarybuf
->writepos
= DSOUND_FRAGLEN
;
1948 memset(primarybuf
->buffer
, neutral
, primarybuf
->buflen
);
1950 TRACE(dsound
, "Audio stopped\n");
1953 static int DSOUND_WriteAudio(char *buf
, int len
)
1955 int result
, left
= 0;
1957 while (left
< len
) {
1958 result
= write(audiofd
, buf
+ left
, len
- left
);
1970 static void DSOUND_OutputPrimary(int len
)
1972 int neutral
, flen1
, flen2
;
1973 char *frag1
, *frag2
;
1975 /* This is a bad place for this. We need to clear the */
1976 /* buffer with a neutral value, for unsigned 8-bit WAVE */
1977 /* that's 128, for signed 16-bit it's 0 */
1978 neutral
= primarybuf
->wfx
.wBitsPerSample
== 8 ? 128 : 0;
1981 EnterCriticalSection(&(primarybuf
->lock
));
1984 if ((audioOK
== 1) || (DSOUND_OpenAudio() == 0)) {
1985 if (primarybuf
->playpos
+ len
>= primarybuf
->buflen
) {
1986 frag1
= primarybuf
->buffer
+ primarybuf
->playpos
;
1987 flen1
= primarybuf
->buflen
- primarybuf
->playpos
;
1988 frag2
= primarybuf
->buffer
;
1989 flen2
= len
- (primarybuf
->buflen
- primarybuf
->playpos
);
1990 if (DSOUND_WriteAudio(frag1
, flen1
) != 0) {
1991 perror("DSOUND_WriteAudio");
1992 LeaveCriticalSection(&(primarybuf
->lock
));
1995 memset(frag1
, neutral
, flen1
);
1996 if (DSOUND_WriteAudio(frag2
, flen2
) != 0) {
1997 perror("DSOUND_WriteAudio");
1998 LeaveCriticalSection(&(primarybuf
->lock
));
2001 memset(frag2
, neutral
, flen2
);
2003 frag1
= primarybuf
->buffer
+ primarybuf
->playpos
;
2005 if (DSOUND_WriteAudio(frag1
, flen1
) != 0) {
2006 perror("DSOUND_WriteAudio");
2007 LeaveCriticalSection(&(primarybuf
->lock
));
2010 memset(frag1
, neutral
, flen1
);
2013 /* Can't play audio at the moment -- we need to sleep */
2014 /* to make up for the time we'd be blocked in write() */
2018 primarybuf
->playpos
+= len
;
2019 if (primarybuf
->playpos
>= primarybuf
->buflen
)
2020 primarybuf
->playpos
%= primarybuf
->buflen
;
2021 primarybuf
->writepos
= primarybuf
->playpos
+ DSOUND_FRAGLEN
;
2022 if (primarybuf
->writepos
>= primarybuf
->buflen
)
2023 primarybuf
->writepos
%= primarybuf
->buflen
;
2025 LeaveCriticalSection(&(primarybuf
->lock
));
2029 static DWORD WINAPI
DSOUND_thread(LPVOID arg
)
2033 TRACE(dsound
,"dsound is at pid %d\n",getpid());
2036 WARN(dsound
,"DSOUND thread giving up.\n");
2040 WARN(dsound
,"DSOUND father died? Giving up.\n");
2043 /* RACE: dsound could be deleted */
2044 dsound
->lpvtbl
->fnAddRef(dsound
);
2045 if (primarybuf
== NULL
) {
2046 /* Should never happen */
2047 WARN(dsound
, "Lost the primary buffer!\n");
2048 dsound
->lpvtbl
->fnRelease(dsound
);
2053 EnterCriticalSection(&(primarybuf
->lock
));
2054 len
= DSOUND_MixPrimary();
2055 LeaveCriticalSection(&(primarybuf
->lock
));
2058 if (primarybuf
->playing
)
2059 len
= DSOUND_FRAGLEN
> len
? DSOUND_FRAGLEN
: len
;
2061 /* This does all the work */
2062 DSOUND_OutputPrimary(len
);
2064 /* no buffers playing -- close and wait */
2066 DSOUND_CloseAudio();
2069 dsound
->lpvtbl
->fnRelease(dsound
);
2074 #endif /* HAVE_OSS */
2076 HRESULT WINAPI
DirectSoundCreate(REFGUID lpGUID
,LPDIRECTSOUND
*ppDS
,IUnknown
*pUnkOuter
)
2079 TRACE(dsound
,"(%p,%p,%p)\n",lpGUID
,ppDS
,pUnkOuter
);
2081 TRACE(dsound
,"DirectSoundCreate (%p)\n", ppDS
);
2086 return DSERR_INVALIDPARAM
;
2089 dsound
->lpvtbl
->fnAddRef(dsound
);
2094 /* Check that we actually have audio capabilities */
2095 /* If we do, whether it's busy or not, we continue */
2096 /* otherwise we return with DSERR_NODRIVER */
2098 audiofd
= open("/dev/audio",O_WRONLY
);
2099 if (audiofd
== -1) {
2100 if (errno
== ENODEV
) {
2101 MSG("No sound hardware found.\n");
2102 return DSERR_NODRIVER
;
2103 } else if (errno
== EBUSY
) {
2104 MSG("Sound device busy, will keep trying.\n");
2106 MSG("Unexpected error while checking for sound support.\n");
2107 return DSERR_GENERIC
;
2114 *ppDS
= (LPDIRECTSOUND
)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSound
));
2116 return DSERR_OUTOFMEMORY
;
2119 (*ppDS
)->lpvtbl
= &dsvt
;
2120 (*ppDS
)->buffers
= NULL
;
2121 (*ppDS
)->nrofbuffers
= 0;
2123 (*ppDS
)->wfx
.wFormatTag
= 1;
2124 (*ppDS
)->wfx
.nChannels
= 2;
2125 (*ppDS
)->wfx
.nSamplesPerSec
= 22050;
2126 (*ppDS
)->wfx
.nAvgBytesPerSec
= 44100;
2127 (*ppDS
)->wfx
.nBlockAlign
= 2;
2128 (*ppDS
)->wfx
.wBitsPerSample
= 8;
2135 if (primarybuf
== NULL
) {
2139 dsbd
.dwSize
= sizeof(DSBUFFERDESC
);
2140 dsbd
.dwFlags
= DSBCAPS_PRIMARYBUFFER
;
2141 dsbd
.dwBufferBytes
= 0;
2142 dsbd
.lpwfxFormat
= &(dsound
->wfx
);
2143 hr
= IDirectSound_CreateSoundBuffer(*ppDS
, &dsbd
, &primarybuf
, NULL
);
2146 dsound
->primary
= primarybuf
;
2148 memset(primarybuf
->buffer
, 128, primarybuf
->buflen
);
2149 hnd
= CreateThread(NULL
,0,DSOUND_thread
,0,0,&xid
);
2153 MessageBox32A(0,"DirectSound needs the Open Sound System Driver, which has not been found by ./configure.","WINE DirectSound",MB_OK
|MB_ICONSTOP
);
2154 return DSERR_NODRIVER
;
2158 /*******************************************************************************
2159 * DirectSound ClassFactory
2163 /* IUnknown fields */
2164 ICOM_VTABLE(IClassFactory
)* lpvtbl
;
2166 } IClassFactoryImpl
;
2168 static HRESULT WINAPI
2169 DSCF_QueryInterface(LPCLASSFACTORY iface
,REFIID riid
,LPVOID
*ppobj
) {
2170 ICOM_THIS(IClassFactoryImpl
,iface
);
2174 WINE_StringFromCLSID(riid
,buf
);
2176 sprintf(buf
,"<guid-0x%04x>",LOWORD(riid
));
2177 FIXME(dsound
,"(%p)->(%s,%p),stub!\n",This
,buf
,ppobj
);
2178 return E_NOINTERFACE
;
2182 DSCF_AddRef(LPCLASSFACTORY iface
) {
2183 ICOM_THIS(IClassFactoryImpl
,iface
);
2184 return ++(This
->ref
);
2187 static ULONG WINAPI
DSCF_Release(LPCLASSFACTORY iface
) {
2188 ICOM_THIS(IClassFactoryImpl
,iface
);
2189 /* static class, won't be freed */
2190 return --(This
->ref
);
2193 static HRESULT WINAPI
DSCF_CreateInstance(
2194 LPCLASSFACTORY iface
,LPUNKNOWN pOuter
,REFIID riid
,LPVOID
*ppobj
2196 ICOM_THIS(IClassFactoryImpl
,iface
);
2199 WINE_StringFromCLSID(riid
,buf
);
2200 TRACE(dsound
,"(%p)->(%p,%s,%p)\n",This
,pOuter
,buf
,ppobj
);
2201 if (!memcmp(riid
,&IID_IDirectSound
,sizeof(IID_IDirectSound
))) {
2202 /* FIXME: reuse already created dsound if present? */
2203 return DirectSoundCreate(riid
,(LPDIRECTSOUND
*)ppobj
,pOuter
);
2205 return E_NOINTERFACE
;
2208 static HRESULT WINAPI
DSCF_LockServer(LPCLASSFACTORY iface
,BOOL32 dolock
) {
2209 ICOM_THIS(IClassFactoryImpl
,iface
);
2210 FIXME(dsound
,"(%p)->(%d),stub!\n",This
,dolock
);
2214 static ICOM_VTABLE(IClassFactory
) DSCF_Vtbl
= {
2215 DSCF_QueryInterface
,
2218 DSCF_CreateInstance
,
2221 static IClassFactoryImpl DSOUND_CF
= {&DSCF_Vtbl
, 1 };
2223 /*******************************************************************************
2224 * DllGetClassObject [DSOUND.4]
2225 * Retrieves class object from a DLL object
2228 * Docs say returns STDAPI
2231 * rclsid [I] CLSID for the class object
2232 * riid [I] Reference to identifier of interface for class object
2233 * ppv [O] Address of variable to receive interface pointer for riid
2237 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
2240 DWORD WINAPI
DSOUND_DllGetClassObject(REFCLSID rclsid
,REFIID riid
,LPVOID
*ppv
)
2242 char buf
[80],xbuf
[80];
2245 WINE_StringFromCLSID(rclsid
,xbuf
);
2247 sprintf(xbuf
,"<guid-0x%04x>",LOWORD(rclsid
));
2249 WINE_StringFromCLSID(riid
,buf
);
2251 sprintf(buf
,"<guid-0x%04x>",LOWORD(riid
));
2252 WINE_StringFromCLSID(riid
,xbuf
);
2253 TRACE(dsound
, "(%p,%p,%p)\n", xbuf
, buf
, ppv
);
2254 if (!memcmp(riid
,&IID_IClassFactory
,sizeof(IID_IClassFactory
))) {
2255 *ppv
= (LPVOID
)&DSOUND_CF
;
2256 IClassFactory_AddRef((IClassFactory
*)*ppv
);
2259 FIXME(dsound
, "(%p,%p,%p): no interface found.\n", xbuf
, buf
, ppv
);
2260 return E_NOINTERFACE
;
2264 /*******************************************************************************
2265 * DllCanUnloadNow [DSOUND.3] Determines whether the DLL is in use.
2271 DWORD WINAPI
DSOUND_DllCanUnloadNow(void)
2273 FIXME(dsound
, "(void): stub\n");