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 * FIXME: This file is full of race conditions and unlocked variable access
12 * from two threads. But we usually don't need to bother.
14 * Tested with a Soundblaster clone and a Gravis UltraSound Classic.
17 * - Wing Commander 4/W95:
18 * The intromovie plays without problems. Nearly lipsynchron.
20 * The sound works, but noticeable chunks are left out (from the sound and
21 * the animation). Don't know why yet.
23 * Sound works, but slows down the movieplayer.
27 * The background sound of the startscreen works ;)
28 * - WingCommander Prophecy Demo:
29 * Sound works for the intromovie.
35 #include <sys/types.h>
37 #include <sys/fcntl.h>
41 #include <math.h> /* Insomnia - pow() function */
44 #include "multimedia.h"
53 #include <sys/ioctl.h>
55 /* #define USE_DSOUND3D 1 */
57 #define DSOUND_FRAGLEN (primarybuf->wfx.nAvgBytesPerSec >> 4)
58 #define DSOUND_FREQSHIFT (14)
60 static int audiofd
= -1;
61 static int audioOK
= 0;
63 static LPDIRECTSOUND dsound
= NULL
;
65 static LPDIRECTSOUNDBUFFER primarybuf
= NULL
;
67 static int DSOUND_setformat(LPWAVEFORMATEX wfex
);
68 static void DSOUND_CheckEvent(IDirectSoundBuffer
*dsb
, int len
);
69 static void DSOUND_CloseAudio(void);
73 HRESULT WINAPI
DirectSoundEnumerate32A(LPDSENUMCALLBACK32A enumcb
,LPVOID context
) {
75 enumcb(NULL
,"WINE DirectSound using Open Sound System","sound",context
);
81 static void _dump_DSBCAPS(DWORD xmask
) {
86 #define FE(x) { x, #x },
87 FE(DSBCAPS_PRIMARYBUFFER
)
89 FE(DSBCAPS_LOCHARDWARE
)
90 FE(DSBCAPS_LOCSOFTWARE
)
91 FE(DSBCAPS_CTRLFREQUENCY
)
93 FE(DSBCAPS_CTRLVOLUME
)
94 FE(DSBCAPS_CTRLDEFAULT
)
96 FE(DSBCAPS_STICKYFOCUS
)
97 FE(DSBCAPS_GETCURRENTPOSITION2
)
101 for (i
=0;i
<sizeof(flags
)/sizeof(flags
[0]);i
++)
102 if (flags
[i
].mask
& xmask
)
103 fprintf(stderr
,"%s ",flags
[i
].name
);
106 /*******************************************************************************
107 * IDirectSound3DBuffer
110 /* IUnknown methods */
111 static HRESULT WINAPI
IDirectSound3DBuffer_QueryInterface(
112 LPDIRECTSOUND3DBUFFER
this, REFIID riid
, LPVOID
*ppobj
)
116 WINE_StringFromCLSID(riid
,xbuf
);
117 TRACE(dsound
,"(%p,%s,%p)\n",this,xbuf
,ppobj
);
121 static ULONG WINAPI
IDirectSound3DBuffer_AddRef(LPDIRECTSOUND3DBUFFER
this)
127 static ULONG WINAPI
IDirectSound3DBuffer_Release(LPDIRECTSOUND3DBUFFER
this)
132 HeapFree(GetProcessHeap(),0,this->buffer
);
133 HeapFree(GetProcessHeap(),0,this);
138 /* IDirectSound3DBuffer methods */
139 static HRESULT WINAPI
IDirectSound3DBuffer_GetAllParameters(
140 LPDIRECTSOUND3DBUFFER
this,
141 LPDS3DBUFFER lpDs3dBuffer
)
143 FIXME(dsound
,"stub\n");
147 static HRESULT WINAPI
IDirectSound3DBuffer_GetConeAngles(
148 LPDIRECTSOUND3DBUFFER
this,
149 LPDWORD lpdwInsideConeAngle
,
150 LPDWORD lpdwOutsideConeAngle
)
152 FIXME(dsound
,"stub\n");
156 static HRESULT WINAPI
IDirectSound3DBuffer_GetConeOrientation(
157 LPDIRECTSOUND3DBUFFER
this,
158 LPD3DVECTOR lpvConeOrientation
)
160 FIXME(dsound
,"stub\n");
164 static HRESULT WINAPI
IDirectSound3DBuffer_GetConeOutsideVolume(
165 LPDIRECTSOUND3DBUFFER
this,
166 LPLONG lplConeOutsideVolume
)
168 FIXME(dsound
,"stub\n");
172 static HRESULT WINAPI
IDirectSound3DBuffer_GetMaxDistance(
173 LPDIRECTSOUND3DBUFFER
this,
174 LPD3DVALUE lpfMaxDistance
)
176 FIXME(dsound
,"stub\n");
180 static HRESULT WINAPI
IDirectSound3DBuffer_GetMinDistance(
181 LPDIRECTSOUND3DBUFFER
this,
182 LPD3DVALUE lpfMinDistance
)
184 FIXME(dsound
,"stub\n");
188 static HRESULT WINAPI
IDirectSound3DBuffer_GetMode(
189 LPDIRECTSOUND3DBUFFER
this,
192 FIXME(dsound
,"stub\n");
196 static HRESULT WINAPI
IDirectSound3DBuffer_GetPosition(
197 LPDIRECTSOUND3DBUFFER
this,
198 LPD3DVECTOR lpvPosition
)
200 FIXME(dsound
,"stub\n");
204 static HRESULT WINAPI
IDirectSound3DBuffer_GetVelocity(
205 LPDIRECTSOUND3DBUFFER
this,
206 LPD3DVECTOR lpvVelocity
)
208 FIXME(dsound
,"stub\n");
212 static HRESULT WINAPI
IDirectSound3DBuffer_SetAllParameters(
213 LPDIRECTSOUND3DBUFFER
this,
214 LPCDS3DBUFFER lpcDs3dBuffer
,
217 FIXME(dsound
,"stub\n");
221 static HRESULT WINAPI
IDirectSound3DBuffer_SetConeAngles(
222 LPDIRECTSOUND3DBUFFER
this,
223 DWORD dwInsideConeAngle
,
224 DWORD dwOutsideConeAngle
,
227 FIXME(dsound
,"stub\n");
231 static HRESULT WINAPI
IDirectSound3DBuffer_SetConeOrientation(
232 LPDIRECTSOUND3DBUFFER
this,
233 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
236 FIXME(dsound
,"stub\n");
240 static HRESULT WINAPI
IDirectSound3DBuffer_SetConeOutsideVolume(
241 LPDIRECTSOUND3DBUFFER
this,
242 LONG lConeOutsideVolume
,
245 FIXME(dsound
,"stub\n");
249 static HRESULT WINAPI
IDirectSound3DBuffer_SetMaxDistance(
250 LPDIRECTSOUND3DBUFFER
this,
251 D3DVALUE fMaxDistance
,
254 FIXME(dsound
,"stub\n");
258 static HRESULT WINAPI
IDirectSound3DBuffer_SetMinDistance(
259 LPDIRECTSOUND3DBUFFER
this,
260 D3DVALUE fMinDistance
,
263 FIXME(dsound
,"stub\n");
267 static HRESULT WINAPI
IDirectSound3DBuffer_SetMode(
268 LPDIRECTSOUND3DBUFFER
this,
272 TRACE(dsound
, "mode = %lx\n", dwMode
);
273 this->ds3db
.dwMode
= dwMode
;
277 static HRESULT WINAPI
IDirectSound3DBuffer_SetPosition(
278 LPDIRECTSOUND3DBUFFER
this,
279 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
282 FIXME(dsound
,"stub\n");
286 static HRESULT WINAPI
IDirectSound3DBuffer_SetVelocity(
287 LPDIRECTSOUND3DBUFFER
this,
288 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
291 FIXME(dsound
,"stub\n");
295 IDirectSound3DBuffer_VTable ds3dbvt
= {
296 /* IUnknown methods */
297 IDirectSound3DBuffer_QueryInterface
,
298 IDirectSound3DBuffer_AddRef
,
299 IDirectSound3DBuffer_Release
,
300 /* IDirectSound3DBuffer methods */
301 IDirectSound3DBuffer_GetAllParameters
,
302 IDirectSound3DBuffer_GetConeAngles
,
303 IDirectSound3DBuffer_GetConeOrientation
,
304 IDirectSound3DBuffer_GetConeOutsideVolume
,
305 IDirectSound3DBuffer_GetMaxDistance
,
306 IDirectSound3DBuffer_GetMinDistance
,
307 IDirectSound3DBuffer_GetMode
,
308 IDirectSound3DBuffer_GetPosition
,
309 IDirectSound3DBuffer_GetVelocity
,
310 IDirectSound3DBuffer_SetAllParameters
,
311 IDirectSound3DBuffer_SetConeAngles
,
312 IDirectSound3DBuffer_SetConeOrientation
,
313 IDirectSound3DBuffer_SetConeOutsideVolume
,
314 IDirectSound3DBuffer_SetMaxDistance
,
315 IDirectSound3DBuffer_SetMinDistance
,
316 IDirectSound3DBuffer_SetMode
,
317 IDirectSound3DBuffer_SetPosition
,
318 IDirectSound3DBuffer_SetVelocity
,
322 static int DSOUND_Create3DBuffer(LPDIRECTSOUNDBUFFER dsb
)
324 DWORD i
, temp
, iSize
, oSize
, offset
;
325 LPBYTE bIbuf
, bObuf
, bTbuf
= NULL
;
326 LPWORD wIbuf
, wObuf
, wTbuf
= NULL
;
328 /* Inside DirectX says it's stupid but allowed */
329 if (dsb
->wfx
.nChannels
== 2) {
330 /* Convert to mono */
331 if (dsb
->wfx
.wBitsPerSample
== 16) {
332 iSize
= dsb
->buflen
/ 4;
333 wTbuf
= malloc(dsb
->buflen
/ 2);
335 return DSERR_OUTOFMEMORY
;
336 for (i
= 0; i
< iSize
; i
++)
337 wTbuf
[i
] = (dsb
->buffer
[i
] + dsb
->buffer
[(i
* 2) + 1]) / 2;
340 iSize
= dsb
->buflen
/ 2;
341 bTbuf
= malloc(dsb
->buflen
/ 2);
343 return DSERR_OUTOFMEMORY
;
344 for (i
= 0; i
< iSize
; i
++)
345 bTbuf
[i
] = (dsb
->buffer
[i
] + dsb
->buffer
[(i
* 2) + 1]) / 2;
349 if (dsb
->wfx
.wBitsPerSample
== 16) {
350 iSize
= dsb
->buflen
/ 2;
351 wIbuf
= (LPWORD
) dsb
->buffer
;
353 bIbuf
= (LPBYTE
) dsb
->buffer
;
358 if (primarybuf
->wfx
.wBitsPerSample
== 16) {
359 wObuf
= (LPWORD
) dsb
->ds3db
->buffer
;
360 oSize
= dsb
->ds3db
->buflen
/ 2;
362 bObuf
= (LPBYTE
) dsb
->ds3db
->buffer
;
363 oSize
= dsb
->ds3db
->buflen
;
366 offset
= primarybuf
->wfx
.nSamplesPerSec
/ 100; /* 10ms */
367 if (primarybuf
->wfx
.wBitsPerSample
== 16 && dsb
->wfx
.wBitsPerSample
== 16)
368 for (i
= 0; i
< iSize
; i
++) {
371 temp
+= wIbuf
[i
- offset
] >> 9;
373 temp
+= wIbuf
[i
+ iSize
- offset
] >> 9;
375 wObuf
[(i
* 2) + 1] = temp
;
377 else if (primarybuf
->wfx
.wBitsPerSample
== 8 && dsb
->wfx
.wBitsPerSample
== 8)
378 for (i
= 0; i
< iSize
; i
++) {
381 temp
+= bIbuf
[i
- offset
] >> 5;
383 temp
+= bIbuf
[i
+ iSize
- offset
] >> 5;
385 bObuf
[(i
* 2) + 1] = temp
;
396 /*******************************************************************************
397 * IDirectSound3DListener
400 /* IUnknown methods */
401 static HRESULT WINAPI
IDirectSound3DListener_QueryInterface(
402 LPDIRECTSOUND3DLISTENER
this, REFIID riid
, LPVOID
*ppobj
)
406 WINE_StringFromCLSID(riid
,xbuf
);
407 TRACE(dsound
,"(%p,%s,%p)\n",this,xbuf
,ppobj
);
411 static ULONG WINAPI
IDirectSound3DListener_AddRef(LPDIRECTSOUND3DLISTENER
this)
417 static ULONG WINAPI
IDirectSound3DListener_Release(LPDIRECTSOUND3DLISTENER
this)
423 /* IDirectSound3DListener methods */
424 static HRESULT WINAPI
IDirectSound3DListener_GetAllParameter(
425 LPDIRECTSOUND3DLISTENER
this,
426 LPDS3DLISTENER lpDS3DL
)
428 FIXME(dsound
,"stub\n");
432 static HRESULT WINAPI
IDirectSound3DListener_GetDistanceFactor(
433 LPDIRECTSOUND3DLISTENER
this,
434 LPD3DVALUE lpfDistanceFactor
)
436 FIXME(dsound
,"stub\n");
440 static HRESULT WINAPI
IDirectSound3DListener_GetDopplerFactor(
441 LPDIRECTSOUND3DLISTENER
this,
442 LPD3DVALUE lpfDopplerFactor
)
444 FIXME(dsound
,"stub\n");
448 static HRESULT WINAPI
IDirectSound3DListener_GetOrientation(
449 LPDIRECTSOUND3DLISTENER
this,
450 LPD3DVECTOR lpvOrientFront
,
451 LPD3DVECTOR lpvOrientTop
)
453 FIXME(dsound
,"stub\n");
457 static HRESULT WINAPI
IDirectSound3DListener_GetPosition(
458 LPDIRECTSOUND3DLISTENER
this,
459 LPD3DVECTOR lpvPosition
)
461 FIXME(dsound
,"stub\n");
465 static HRESULT WINAPI
IDirectSound3DListener_GetRolloffFactor(
466 LPDIRECTSOUND3DLISTENER
this,
467 LPD3DVALUE lpfRolloffFactor
)
469 FIXME(dsound
,"stub\n");
473 static HRESULT WINAPI
IDirectSound3DListener_GetVelocity(
474 LPDIRECTSOUND3DLISTENER
this,
475 LPD3DVECTOR lpvVelocity
)
477 FIXME(dsound
,"stub\n");
481 static HRESULT WINAPI
IDirectSound3DListener_SetAllParameters(
482 LPDIRECTSOUND3DLISTENER
this,
483 LPCDS3DLISTENER lpcDS3DL
,
486 FIXME(dsound
,"stub\n");
490 static HRESULT WINAPI
IDirectSound3DListener_SetDistanceFactor(
491 LPDIRECTSOUND3DLISTENER
this,
492 D3DVALUE fDistanceFactor
,
495 FIXME(dsound
,"stub\n");
499 static HRESULT WINAPI
IDirectSound3DListener_SetDopplerFactor(
500 LPDIRECTSOUND3DLISTENER
this,
501 D3DVALUE fDopplerFactor
,
504 FIXME(dsound
,"stub\n");
508 static HRESULT WINAPI
IDirectSound3DListener_SetOrientation(
509 LPDIRECTSOUND3DLISTENER
this,
510 D3DVALUE xFront
, D3DVALUE yFront
, D3DVALUE zFront
,
511 D3DVALUE xTop
, D3DVALUE yTop
, D3DVALUE zTop
,
514 FIXME(dsound
,"stub\n");
518 static HRESULT WINAPI
IDirectSound3DListener_SetPosition(
519 LPDIRECTSOUND3DLISTENER
this,
520 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
523 FIXME(dsound
,"stub\n");
527 static HRESULT WINAPI
IDirectSound3DListener_SetRolloffFactor(
528 LPDIRECTSOUND3DLISTENER
this,
529 D3DVALUE fRolloffFactor
,
532 FIXME(dsound
,"stub\n");
536 static HRESULT WINAPI
IDirectSound3DListener_SetVelocity(
537 LPDIRECTSOUND3DLISTENER
this,
538 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
541 FIXME(dsound
,"stub\n");
545 static HRESULT WINAPI
IDirectSound3DListener_CommitDeferredSettings(
546 LPDIRECTSOUND3DLISTENER
this)
549 FIXME(dsound
,"stub\n");
553 IDirectSound3DListener_VTable ds3dlvt
= {
554 /* IUnknown methods */
555 IDirectSound3DListener_QueryInterface
,
556 IDirectSound3DListener_AddRef
,
557 IDirectSound3DListener_Release
,
558 /* IDirectSound3DListener methods */
559 IDirectSound3DListener_GetAllParameter
,
560 IDirectSound3DListener_GetDistanceFactor
,
561 IDirectSound3DListener_GetDopplerFactor
,
562 IDirectSound3DListener_GetOrientation
,
563 IDirectSound3DListener_GetPosition
,
564 IDirectSound3DListener_GetRolloffFactor
,
565 IDirectSound3DListener_GetVelocity
,
566 IDirectSound3DListener_SetAllParameters
,
567 IDirectSound3DListener_SetDistanceFactor
,
568 IDirectSound3DListener_SetDopplerFactor
,
569 IDirectSound3DListener_SetOrientation
,
570 IDirectSound3DListener_SetPosition
,
571 IDirectSound3DListener_SetRolloffFactor
,
572 IDirectSound3DListener_SetVelocity
,
573 IDirectSound3DListener_CommitDeferredSettings
,
576 /*******************************************************************************
579 static HRESULT WINAPI
IDirectSoundNotify_QueryInterface(
580 LPDIRECTSOUNDNOTIFY
this,REFIID riid
,LPVOID
*ppobj
584 WINE_StringFromCLSID(riid
,xbuf
);
585 TRACE(dsound
,"(%p,%s,%p)\n",this,xbuf
,ppobj
);
589 static ULONG WINAPI
IDirectSoundNotify_AddRef(LPDIRECTSOUNDNOTIFY
this) {
590 return ++(this->ref
);
593 static ULONG WINAPI
IDirectSoundNotify_Release(LPDIRECTSOUNDNOTIFY
this) {
596 this->dsb
->lpvtbl
->fnRelease(this->dsb
);
597 HeapFree(GetProcessHeap(),0,this);
603 static HRESULT WINAPI
IDirectSoundNotify_SetNotificationPositions(
604 LPDIRECTSOUNDNOTIFY
this,DWORD howmuch
,LPCDSBPOSITIONNOTIFY notify
608 if (TRACE_ON(dsound
)) {
609 TRACE(dsound
,"(%p,0x%08lx,%p)\n",this,howmuch
,notify
);
610 for (i
=0;i
<howmuch
;i
++)
611 TRACE(dsound
,"notify at %ld to 0x%08lx\n",
612 notify
[i
].dwOffset
,(DWORD
)notify
[i
].hEventNotify
);
614 this->dsb
->notifies
= HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,this->dsb
->notifies
,(this->dsb
->nrofnotifies
+howmuch
)*sizeof(DSBPOSITIONNOTIFY
));
615 memcpy( this->dsb
->notifies
+this->dsb
->nrofnotifies
,
617 howmuch
*sizeof(DSBPOSITIONNOTIFY
)
619 this->dsb
->nrofnotifies
+=howmuch
;
624 IDirectSoundNotify_VTable dsnvt
= {
625 IDirectSoundNotify_QueryInterface
,
626 IDirectSoundNotify_AddRef
,
627 IDirectSoundNotify_Release
,
628 IDirectSoundNotify_SetNotificationPositions
,
631 /*******************************************************************************
635 /* This sets this format for the <em>Primary Buffer Only</em> */
636 /* See file:///cdrom/sdk52/docs/worddoc/dsound.doc page 120 */
637 static HRESULT WINAPI
IDirectSoundBuffer_SetFormat(
638 LPDIRECTSOUNDBUFFER
this,LPWAVEFORMATEX wfex
640 LPDIRECTSOUNDBUFFER
*dsb
;
643 /* Let's be pedantic! */
644 if ((wfex
== NULL
) ||
645 (wfex
->wFormatTag
!= WAVE_FORMAT_PCM
) ||
646 (wfex
->nChannels
< 1) || (wfex
->nChannels
> 2) ||
647 (wfex
->nSamplesPerSec
< 1) ||
648 (wfex
->nBlockAlign
< 1) || (wfex
->nChannels
> 4) ||
649 ((wfex
->wBitsPerSample
!= 8) && (wfex
->wBitsPerSample
!= 16))) {
650 TRACE(dsound
, "failed pedantic check!\n");
651 return DSERR_INVALIDPARAM
;
655 EnterCriticalSection(&(primarybuf
->lock
));
657 if (primarybuf
->wfx
.nSamplesPerSec
!= wfex
->nSamplesPerSec
) {
658 dsb
= dsound
->buffers
;
659 for (i
= 0; i
< dsound
->nrofbuffers
; i
++, dsb
++) {
661 EnterCriticalSection(&((*dsb
)->lock
));
663 (*dsb
)->freqAdjust
= ((*dsb
)->freq
<< DSOUND_FREQSHIFT
) /
664 wfex
->nSamplesPerSec
;
666 LeaveCriticalSection(&((*dsb
)->lock
));
671 memcpy(&(primarybuf
->wfx
), wfex
, sizeof(primarybuf
->wfx
));
673 TRACE(dsound
,"(formattag=0x%04x,chans=%d,samplerate=%ld"
674 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
675 wfex
->wFormatTag
, wfex
->nChannels
, wfex
->nSamplesPerSec
,
676 wfex
->nAvgBytesPerSec
, wfex
->nBlockAlign
,
677 wfex
->wBitsPerSample
, wfex
->cbSize
);
679 primarybuf
->wfx
.nAvgBytesPerSec
=
680 this->wfx
.nSamplesPerSec
* this->wfx
.nBlockAlign
;
684 LeaveCriticalSection(&(primarybuf
->lock
));
690 static HRESULT WINAPI
IDirectSoundBuffer_SetVolume(
691 LPDIRECTSOUNDBUFFER
this,LONG vol
695 TRACE(dsound
,"(%p,%ld)\n",this,vol
);
697 /* I'm not sure if we need this for primary buffer */
698 if (!(this->dsbd
.dwFlags
& DSBCAPS_CTRLVOLUME
))
699 return DSERR_CONTROLUNAVAIL
;
701 if ((vol
> DSBVOLUME_MAX
) || (vol
< DSBVOLUME_MIN
))
702 return DSERR_INVALIDPARAM
;
704 /* This needs to adjust the soundcard volume when */
705 /* called for the primary buffer */
706 if (this->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
707 FIXME(dsound
, "Volume control of primary unimplemented.\n");
713 EnterCriticalSection(&(this->lock
));
717 temp
= (double) (this->volume
- (this->pan
> 0 ? this->pan
: 0));
718 this->lVolAdjust
= (ULONG
) (pow(2.0, temp
/ 600.0) * 32768.0);
719 temp
= (double) (this->volume
+ (this->pan
< 0 ? this->pan
: 0));
720 this->rVolAdjust
= (ULONG
) (pow(2.0, temp
/ 600.0) * 32768.0);
722 LeaveCriticalSection(&(this->lock
));
725 TRACE(dsound
, "left = %lx, right = %lx\n", this->lVolAdjust
, this->rVolAdjust
);
730 static HRESULT WINAPI
IDirectSoundBuffer_GetVolume(
731 LPDIRECTSOUNDBUFFER
this,LPLONG vol
733 TRACE(dsound
,"(%p,%p)\n",this,vol
);
736 return DSERR_INVALIDPARAM
;
742 static HRESULT WINAPI
IDirectSoundBuffer_SetFrequency(
743 LPDIRECTSOUNDBUFFER
this,DWORD freq
745 TRACE(dsound
,"(%p,%ld)\n",this,freq
);
747 /* You cannot set the frequency of the primary buffer */
748 if (!(this->dsbd
.dwFlags
& DSBCAPS_CTRLFREQUENCY
) ||
749 (this->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
))
750 return DSERR_CONTROLUNAVAIL
;
752 if ((freq
< DSBFREQUENCY_MIN
) || (freq
> DSBFREQUENCY_MAX
))
753 return DSERR_INVALIDPARAM
;
756 EnterCriticalSection(&(this->lock
));
759 this->freqAdjust
= (freq
<< DSOUND_FREQSHIFT
) / primarybuf
->wfx
.nSamplesPerSec
;
760 this->nAvgBytesPerSec
= freq
* this->wfx
.nBlockAlign
;
762 LeaveCriticalSection(&(this->lock
));
768 static HRESULT WINAPI
IDirectSoundBuffer_Play(
769 LPDIRECTSOUNDBUFFER
this,DWORD reserved1
,DWORD reserved2
,DWORD flags
771 TRACE(dsound
,"(%p,%08lx,%08lx,%08lx)\n",
772 this,reserved1
,reserved2
,flags
774 this->playflags
= flags
;
779 static HRESULT WINAPI
IDirectSoundBuffer_Stop(LPDIRECTSOUNDBUFFER
this)
781 TRACE(dsound
,"(%p)\n",this);
784 EnterCriticalSection(&(this->lock
));
787 DSOUND_CheckEvent(this, 0);
789 LeaveCriticalSection(&(this->lock
));
795 static DWORD WINAPI
IDirectSoundBuffer_AddRef(LPDIRECTSOUNDBUFFER
this) {
796 /* TRACE(dsound,"(%p) ref was %ld\n",this, this->ref); */
798 return ++(this->ref
);
800 static DWORD WINAPI
IDirectSoundBuffer_Release(LPDIRECTSOUNDBUFFER
this) {
803 /* TRACE(dsound,"(%p) ref was %ld\n",this, this->ref); */
808 for (i
=0;i
<this->dsound
->nrofbuffers
;i
++)
809 if (this->dsound
->buffers
[i
] == this)
811 if (i
< this->dsound
->nrofbuffers
) {
812 /* Put the last buffer of the list in the (now empty) position */
813 this->dsound
->buffers
[i
] = this->dsound
->buffers
[this->dsound
->nrofbuffers
- 1];
814 this->dsound
->buffers
= HeapReAlloc(GetProcessHeap(),0,this->dsound
->buffers
,sizeof(LPDIRECTSOUNDBUFFER
)*this->dsound
->nrofbuffers
);
815 this->dsound
->nrofbuffers
--;
816 this->dsound
->lpvtbl
->fnRelease(this->dsound
);
819 DeleteCriticalSection(&(this->lock
));
821 if (this->ds3db
&& this->ds3db
->lpvtbl
)
822 this->ds3db
->lpvtbl
->fnRelease(this->ds3db
);
824 HeapFree(GetProcessHeap(),0,this->buffer
);
825 HeapFree(GetProcessHeap(),0,this);
827 if (this == primarybuf
)
833 static HRESULT WINAPI
IDirectSoundBuffer_GetCurrentPosition(
834 LPDIRECTSOUNDBUFFER
this,LPDWORD playpos
,LPDWORD writepos
836 TRACE(dsound
,"(%p,%p,%p)\n",this,playpos
,writepos
);
837 if (playpos
) *playpos
= this->playpos
;
838 if (writepos
) *writepos
= this->writepos
;
842 static HRESULT WINAPI
IDirectSoundBuffer_GetStatus(
843 LPDIRECTSOUNDBUFFER
this,LPDWORD status
845 TRACE(dsound
,"(%p,%p)\n",this,status
);
848 return DSERR_INVALIDPARAM
;
852 *status
|= DSBSTATUS_PLAYING
;
853 if (this->playflags
& DSBPLAY_LOOPING
)
854 *status
|= DSBSTATUS_LOOPING
;
860 static HRESULT WINAPI
IDirectSoundBuffer_GetFormat(
861 LPDIRECTSOUNDBUFFER
this,LPWAVEFORMATEX lpwf
,DWORD wfsize
,LPDWORD wfwritten
863 TRACE(dsound
,"(%p,%p,%ld,%p)\n",this,lpwf
,wfsize
,wfwritten
);
865 if (wfsize
>sizeof(this->wfx
))
866 wfsize
= sizeof(this->wfx
);
867 if (lpwf
) { /* NULL is valid */
868 memcpy(lpwf
,&(this->wfx
),wfsize
);
873 *wfwritten
= sizeof(this->wfx
);
875 return DSERR_INVALIDPARAM
;
880 static HRESULT WINAPI
IDirectSoundBuffer_Lock(
881 LPDIRECTSOUNDBUFFER
this,DWORD writecursor
,DWORD writebytes
,LPVOID lplpaudioptr1
,LPDWORD audiobytes1
,LPVOID lplpaudioptr2
,LPDWORD audiobytes2
,DWORD flags
884 TRACE(dsound
,"(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx)\n",
894 if (flags
& DSBLOCK_FROMWRITECURSOR
)
895 writecursor
+= this->writepos
;
896 if (flags
& DSBLOCK_ENTIREBUFFER
)
897 writebytes
= this->buflen
;
898 if (writebytes
> this->buflen
)
899 writebytes
= this->buflen
;
901 assert(audiobytes1
!=audiobytes2
);
902 assert(lplpaudioptr1
!=lplpaudioptr2
);
903 if (writecursor
+writebytes
<= this->buflen
) {
904 *(LPBYTE
*)lplpaudioptr1
= this->buffer
+writecursor
;
905 *audiobytes1
= writebytes
;
907 *(LPBYTE
*)lplpaudioptr2
= NULL
;
910 TRACE(dsound
,"->%ld.0\n",writebytes
);
912 *(LPBYTE
*)lplpaudioptr1
= this->buffer
+writecursor
;
913 *audiobytes1
= this->buflen
-writecursor
;
915 *(LPBYTE
*)lplpaudioptr2
= this->buffer
;
917 *audiobytes2
= writebytes
-(this->buflen
-writecursor
);
918 TRACE(dsound
,"->%ld.%ld\n",*audiobytes1
,audiobytes2
?*audiobytes2
:0);
920 /* No. See file:///cdrom/sdk52/docs/worddoc/dsound.doc page 21 */
921 /* this->writepos=(writecursor+writebytes)%this->buflen; */
925 static HRESULT WINAPI
IDirectSoundBuffer_SetCurrentPosition(
926 LPDIRECTSOUNDBUFFER
this,DWORD newpos
928 TRACE(dsound
,"(%p,%ld)\n",this,newpos
);
931 EnterCriticalSection(&(this->lock
));
933 this->playpos
= newpos
;
935 LeaveCriticalSection(&(this->lock
));
941 static HRESULT WINAPI
IDirectSoundBuffer_SetPan(
942 LPDIRECTSOUNDBUFFER
this,LONG pan
946 TRACE(dsound
,"(%p,%ld)\n",this,pan
);
948 if ((pan
> DSBPAN_RIGHT
) || (pan
< DSBPAN_LEFT
))
949 return DSERR_INVALIDPARAM
;
951 /* You cannot set the pan of the primary buffer */
952 /* and you cannot use both pan and 3D controls */
953 if (!(this->dsbd
.dwFlags
& DSBCAPS_CTRLPAN
) ||
954 (this->dsbd
.dwFlags
& DSBCAPS_CTRL3D
) ||
955 (this->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
))
956 return DSERR_CONTROLUNAVAIL
;
959 EnterCriticalSection(&(this->lock
));
963 temp
= (double) (this->volume
- (this->pan
> 0 ? this->pan
: 0));
964 this->lVolAdjust
= (ULONG
) (pow(2.0, temp
/ 600.0) * 32768.0);
965 temp
= (double) (this->volume
+ (this->pan
< 0 ? this->pan
: 0));
966 this->rVolAdjust
= (ULONG
) (pow(2.0, temp
/ 600.0) * 32768.0);
968 LeaveCriticalSection(&(this->lock
));
974 static HRESULT WINAPI
IDirectSoundBuffer_GetPan(
975 LPDIRECTSOUNDBUFFER
this,LPLONG pan
977 TRACE(dsound
,"(%p,%p)\n",this,pan
);
980 return DSERR_INVALIDPARAM
;
987 static HRESULT WINAPI
IDirectSoundBuffer_Unlock(
988 LPDIRECTSOUNDBUFFER
this,LPVOID p1
,DWORD x1
,LPVOID p2
,DWORD x2
990 TRACE(dsound
,"(%p,%p,%ld,%p,%ld):stub\n", this,p1
,x1
,p2
,x2
);
992 /* There is really nothing to do here. Should someone */
993 /* choose to implement static buffers in hardware (by */
994 /* using a wave table synth, for example) this is where */
995 /* you'd want to do the loading. For software buffers, */
996 /* which is what we currently use, we need do nothing. */
999 /* It's also the place to pre-process 3D buffers... */
1001 /* This is highly experimental and liable to break things */
1002 if (this->dsbd
.dwFlags
& DSBCAPS_CTRL3D
)
1003 DSOUND_Create3DBuffer(this);
1009 static HRESULT WINAPI
IDirectSoundBuffer_GetFrequency(
1010 LPDIRECTSOUNDBUFFER
this,LPDWORD freq
1012 TRACE(dsound
,"(%p,%p)\n",this,freq
);
1015 return DSERR_INVALIDPARAM
;
1022 static HRESULT WINAPI
IDirectSoundBuffer_Initialize(
1023 LPDIRECTSOUNDBUFFER
this,LPDIRECTSOUND dsound
,LPDSBUFFERDESC dbsd
1025 FIXME(dsound
,"(%p,%p,%p):stub\n",this,dsound
,dbsd
);
1026 printf("Re-Init!!!\n");
1027 return DSERR_ALREADYINITIALIZED
;
1030 static HRESULT WINAPI
IDirectSoundBuffer_GetCaps(
1031 LPDIRECTSOUNDBUFFER
this,LPDSBCAPS caps
1033 TRACE(dsound
,"(%p)->(%p)\n",this,caps
);
1036 return DSERR_INVALIDPARAM
;
1038 /* I think we should check this value, not set it. See */
1039 /* Inside DirectX, p215. That should apply here, too. */
1040 caps
->dwSize
= sizeof(*caps
);
1042 caps
->dwFlags
= this->dsbd
.dwFlags
| DSBCAPS_LOCSOFTWARE
;
1043 caps
->dwBufferBytes
= this->dsbd
.dwBufferBytes
;
1044 /* This value represents the speed of the "unlock" command.
1045 As unlock is quite fast (it does not do anything), I put
1046 4096 ko/s = 4 Mo / s */
1047 caps
->dwUnlockTransferRate
= 4096;
1048 caps
->dwPlayCpuOverhead
= 0;
1053 static HRESULT WINAPI
IDirectSoundBuffer_QueryInterface(
1054 LPDIRECTSOUNDBUFFER
this,REFIID riid
,LPVOID
*ppobj
1058 WINE_StringFromCLSID(riid
,xbuf
);
1059 TRACE(dsound
,"(%p,%s,%p)\n",this,xbuf
,ppobj
);
1061 if (!memcmp(&IID_IDirectSoundNotify
,riid
,sizeof(*riid
))) {
1062 IDirectSoundNotify
*dsn
;
1064 dsn
= (LPDIRECTSOUNDNOTIFY
)HeapAlloc(GetProcessHeap(),0,sizeof(*dsn
));
1067 this->lpvtbl
->fnAddRef(this);
1068 dsn
->lpvtbl
= &dsnvt
;
1069 *ppobj
= (LPVOID
)dsn
;
1073 if (!memcmp(&IID_IDirectSound3DBuffer
,riid
,sizeof(*riid
))) {
1074 *ppobj
= this->ds3db
;
1082 static struct tagLPDIRECTSOUNDBUFFER_VTABLE dsbvt
= {
1083 IDirectSoundBuffer_QueryInterface
,
1084 IDirectSoundBuffer_AddRef
,
1085 IDirectSoundBuffer_Release
,
1086 IDirectSoundBuffer_GetCaps
,
1087 IDirectSoundBuffer_GetCurrentPosition
,
1088 IDirectSoundBuffer_GetFormat
,
1089 IDirectSoundBuffer_GetVolume
,
1090 IDirectSoundBuffer_GetPan
,
1091 IDirectSoundBuffer_GetFrequency
,
1092 IDirectSoundBuffer_GetStatus
,
1093 IDirectSoundBuffer_Initialize
,
1094 IDirectSoundBuffer_Lock
,
1095 IDirectSoundBuffer_Play
,
1096 IDirectSoundBuffer_SetCurrentPosition
,
1097 IDirectSoundBuffer_SetFormat
,
1098 IDirectSoundBuffer_SetVolume
,
1099 IDirectSoundBuffer_SetPan
,
1100 IDirectSoundBuffer_SetFrequency
,
1101 IDirectSoundBuffer_Stop
,
1102 IDirectSoundBuffer_Unlock
1105 /*******************************************************************************
1109 static HRESULT WINAPI
IDirectSound_SetCooperativeLevel(
1110 LPDIRECTSOUND
this,HWND32 hwnd
,DWORD level
1112 FIXME(dsound
,"(%p,%08lx,%ld):stub\n",this,(DWORD
)hwnd
,level
);
1116 static HRESULT WINAPI
IDirectSound_CreateSoundBuffer(
1117 LPDIRECTSOUND
this,LPDSBUFFERDESC dsbd
,LPLPDIRECTSOUNDBUFFER ppdsb
,LPUNKNOWN lpunk
1119 LPWAVEFORMATEX wfex
;
1121 TRACE(dsound
,"(%p,%p,%p,%p)\n",this,dsbd
,ppdsb
,lpunk
);
1123 if ((this == NULL
) || (dsbd
== NULL
) || (ppdsb
== NULL
))
1124 return DSERR_INVALIDPARAM
;
1126 if (TRACE_ON(dsound
)) {
1127 TRACE(dsound
,"(size=%ld)\n",dsbd
->dwSize
);
1128 TRACE(dsound
,"(flags=0x%08lx\n",dsbd
->dwFlags
);
1129 _dump_DSBCAPS(dsbd
->dwFlags
);
1130 TRACE(dsound
,"(bufferbytes=%ld)\n",dsbd
->dwBufferBytes
);
1131 TRACE(dsound
,"(lpwfxFormat=%p)\n",dsbd
->lpwfxFormat
);
1134 wfex
= dsbd
->lpwfxFormat
;
1137 TRACE(dsound
,"(formattag=0x%04x,chans=%d,samplerate=%ld"
1138 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
1139 wfex
->wFormatTag
, wfex
->nChannels
, wfex
->nSamplesPerSec
,
1140 wfex
->nAvgBytesPerSec
, wfex
->nBlockAlign
,
1141 wfex
->wBitsPerSample
, wfex
->cbSize
);
1143 if (dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
1145 primarybuf
->lpvtbl
->fnAddRef(primarybuf
);
1146 *ppdsb
= primarybuf
;
1148 } /* Else create primarybuf */
1151 *ppdsb
= (LPDIRECTSOUNDBUFFER
)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDirectSoundBuffer
));
1153 return DSERR_OUTOFMEMORY
;
1156 TRACE(dsound
, "Created buffer at %p\n", *ppdsb
);
1158 if (dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
1159 (*ppdsb
)->buflen
= dsound
->wfx
.nAvgBytesPerSec
;
1160 (*ppdsb
)->freq
= dsound
->wfx
.nSamplesPerSec
;
1162 (*ppdsb
)->buflen
= dsbd
->dwBufferBytes
;
1163 (*ppdsb
)->freq
= dsbd
->lpwfxFormat
->nSamplesPerSec
;
1165 (*ppdsb
)->buffer
= (LPBYTE
)HeapAlloc(GetProcessHeap(),0,(*ppdsb
)->buflen
);
1166 if ((*ppdsb
)->buffer
== NULL
) {
1167 HeapFree(GetProcessHeap(),0,(*ppdsb
));
1169 return DSERR_OUTOFMEMORY
;
1171 /* It's not necessary to initialize values to zero since */
1172 /* we allocated this structure with HEAP_ZERO_MEMORY... */
1173 (*ppdsb
)->playpos
= 0;
1174 (*ppdsb
)->writepos
= 0;
1175 (*ppdsb
)->lpvtbl
= &dsbvt
;
1176 (*ppdsb
)->dsound
= this;
1177 (*ppdsb
)->playing
= 0;
1178 (*ppdsb
)->lVolAdjust
= (1 << 15);
1179 (*ppdsb
)->rVolAdjust
= (1 << 15);
1181 if (!(dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
)) {
1182 (*ppdsb
)->freqAdjust
= ((*ppdsb
)->freq
<< DSOUND_FREQSHIFT
) /
1183 primarybuf
->wfx
.nSamplesPerSec
;
1184 (*ppdsb
)->nAvgBytesPerSec
= (*ppdsb
)->freq
*
1185 dsbd
->lpwfxFormat
->nBlockAlign
;
1188 memcpy(&((*ppdsb
)->dsbd
),dsbd
,sizeof(*dsbd
));
1190 /* register buffer */
1191 if (!(dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
)) {
1192 this->buffers
= (LPDIRECTSOUNDBUFFER
*)HeapReAlloc(GetProcessHeap(),0,this->buffers
,sizeof(LPDIRECTSOUNDBUFFER
)*(this->nrofbuffers
+1));
1193 this->buffers
[this->nrofbuffers
] = *ppdsb
;
1194 this->nrofbuffers
++;
1196 this->lpvtbl
->fnAddRef(this);
1198 if (dsbd
->lpwfxFormat
)
1199 memcpy(&((*ppdsb
)->wfx
), dsbd
->lpwfxFormat
, sizeof((*ppdsb
)->wfx
));
1201 InitializeCriticalSection(&((*ppdsb
)->lock
));
1204 if (dsbd
->dwFlags
& DSBCAPS_CTRL3D
) {
1205 IDirectSound3DBuffer
*ds3db
;
1207 ds3db
= (LPDIRECTSOUND3DBUFFER
)HeapAlloc(GetProcessHeap(),
1210 ds3db
->dsb
= (*ppdsb
);
1211 ds3db
->lpvtbl
= &ds3dbvt
;
1212 (*ppdsb
)->ds3db
= ds3db
;
1213 ds3db
->ds3db
.dwSize
= sizeof(DS3DBUFFER
);
1214 ds3db
->ds3db
.vPosition
.x
.x
= 0.0;
1215 ds3db
->ds3db
.vPosition
.y
.y
= 0.0;
1216 ds3db
->ds3db
.vPosition
.z
.z
= 0.0;
1217 ds3db
->ds3db
.vVelocity
.x
.x
= 0.0;
1218 ds3db
->ds3db
.vVelocity
.y
.y
= 0.0;
1219 ds3db
->ds3db
.vVelocity
.z
.z
= 0.0;
1220 ds3db
->ds3db
.dwInsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
1221 ds3db
->ds3db
.dwOutsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
1222 ds3db
->ds3db
.vConeOrientation
.x
.x
= 0.0;
1223 ds3db
->ds3db
.vConeOrientation
.y
.y
= 0.0;
1224 ds3db
->ds3db
.vConeOrientation
.z
.z
= 0.0;
1225 ds3db
->ds3db
.lConeOutsideVolume
= DS3D_DEFAULTCONEOUTSIDEVOLUME
;
1226 ds3db
->ds3db
.flMinDistance
= DS3D_DEFAULTMINDISTANCE
;
1227 ds3db
->ds3db
.flMaxDistance
= DS3D_DEFAULTMAXDISTANCE
;
1228 ds3db
->ds3db
.dwMode
= DS3DMODE_NORMAL
;
1229 ds3db
->buflen
= ((*ppdsb
)->buflen
* primarybuf
->wfx
.nBlockAlign
) /
1230 (*ppdsb
)->wfx
.nBlockAlign
;
1231 ds3db
->buffer
= HeapAlloc(GetProcessHeap(), 0, ds3db
->buflen
);
1232 if (ds3db
->buffer
== NULL
) {
1234 ds3db
->ds3db
.dwMode
= DS3DMODE_DISABLE
;
1241 static HRESULT WINAPI
IDirectSound_DuplicateSoundBuffer(
1242 LPDIRECTSOUND
this,LPDIRECTSOUNDBUFFER pdsb
,LPLPDIRECTSOUNDBUFFER ppdsb
1244 TRACE(dsound
,"(%p,%p,%p)\n",this,pdsb
,ppdsb
);
1246 *ppdsb
= (LPDIRECTSOUNDBUFFER
)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDirectSoundBuffer
));
1249 (*ppdsb
)->buffer
= (LPBYTE
)HeapAlloc(GetProcessHeap(),0,pdsb
->buflen
);
1250 memcpy((*ppdsb
)->buffer
,pdsb
->buffer
,pdsb
->buflen
);
1251 (*ppdsb
)->buflen
= pdsb
->buflen
;
1252 (*ppdsb
)->playpos
= 0;
1253 (*ppdsb
)->writepos
= 0;
1254 (*ppdsb
)->lpvtbl
= &dsbvt
;
1255 (*ppdsb
)->dsound
= this;
1256 memcpy(&((*ppdsb
)->wfx
), &(pdsb
->wfx
), sizeof((*ppdsb
)->wfx
));
1257 /* register buffer */
1258 this->buffers
= (LPDIRECTSOUNDBUFFER
*)HeapReAlloc(GetProcessHeap(),0,this->buffers
,sizeof(LPDIRECTSOUNDBUFFER
)*(this->nrofbuffers
+1));
1259 this->buffers
[this->nrofbuffers
] = *ppdsb
;
1260 this->nrofbuffers
++;
1261 this->lpvtbl
->fnAddRef(this);
1266 static HRESULT WINAPI
IDirectSound_GetCaps(LPDIRECTSOUND
this,LPDSCAPS caps
) {
1267 TRACE(dsound
,"(%p,%p)\n",this,caps
);
1268 TRACE(dsound
,"(flags=0x%08lx)\n",caps
->dwFlags
);
1271 return DSERR_INVALIDPARAM
;
1273 /* We should check this value, not set it. See Inside DirectX, p215. */
1274 caps
->dwSize
= sizeof(*caps
);
1277 DSCAPS_PRIMARYSTEREO
|
1278 DSCAPS_PRIMARY16BIT
|
1279 DSCAPS_SECONDARYSTEREO
|
1280 DSCAPS_SECONDARY16BIT
|
1281 DSCAPS_CONTINUOUSRATE
;
1282 /* FIXME: query OSS */
1283 caps
->dwMinSecondarySampleRate
= DSBFREQUENCY_MIN
;
1284 caps
->dwMaxSecondarySampleRate
= DSBFREQUENCY_MAX
;
1286 caps
->dwPrimaryBuffers
= 1;
1288 caps
->dwMaxHwMixingAllBuffers
= 0;
1289 caps
->dwMaxHwMixingStaticBuffers
= 0;
1290 caps
->dwMaxHwMixingStreamingBuffers
= 0;
1292 caps
->dwFreeHwMixingAllBuffers
= 0;
1293 caps
->dwFreeHwMixingStaticBuffers
= 0;
1294 caps
->dwFreeHwMixingStreamingBuffers
= 0;
1296 caps
->dwMaxHw3DAllBuffers
= 0;
1297 caps
->dwMaxHw3DStaticBuffers
= 0;
1298 caps
->dwMaxHw3DStreamingBuffers
= 0;
1300 caps
->dwFreeHw3DAllBuffers
= 0;
1301 caps
->dwFreeHw3DStaticBuffers
= 0;
1302 caps
->dwFreeHw3DStreamingBuffers
= 0;
1304 caps
->dwTotalHwMemBytes
= 0;
1306 caps
->dwFreeHwMemBytes
= 0;
1308 caps
->dwMaxContigFreeHwMemBytes
= 0;
1310 caps
->dwUnlockTransferRateHwBuffers
= 4096; /* But we have none... */
1312 caps
->dwPlayCpuOverheadSwBuffers
= 1; /* 1% */
1317 static ULONG WINAPI
IDirectSound_AddRef(LPDIRECTSOUND
this) {
1318 return ++(this->ref
);
1321 static ULONG WINAPI
IDirectSound_Release(LPDIRECTSOUND
this) {
1322 TRACE(dsound
,"(%p), ref was %ld\n",this,this->ref
);
1323 if (!--(this->ref
)) {
1324 DSOUND_CloseAudio();
1325 while(IDirectSoundBuffer_Release(primarybuf
)); /* Deallocate */
1326 FIXME(dsound
, "need to release all buffers!\n");
1327 HeapFree(GetProcessHeap(),0,this);
1334 static HRESULT WINAPI
IDirectSound_SetSpeakerConfig(
1335 LPDIRECTSOUND
this,DWORD config
1337 FIXME(dsound
,"(%p,0x%08lx):stub\n",this,config
);
1341 static HRESULT WINAPI
IDirectSound_QueryInterface(
1342 LPDIRECTSOUND
this,REFIID riid
,LPVOID
*ppobj
1346 if (!memcmp(&IID_IDirectSound3DListener
,riid
,sizeof(*riid
))) {
1348 if (this->listener
) {
1349 *ppobj
= this->listener
;
1352 this->listener
= (LPDIRECTSOUND3DLISTENER
)HeapAlloc(
1353 GetProcessHeap(), 0, sizeof(*(this->listener
)));
1354 this->listener
->ref
= 1;
1355 this->listener
->lpvtbl
= &ds3dlvt
;
1356 this->lpvtbl
->fnAddRef(this);
1357 this->listener
->ds3dl
.dwSize
= sizeof(DS3DLISTENER
);
1358 this->listener
->ds3dl
.vPosition
.x
.x
= 0.0;
1359 this->listener
->ds3dl
.vPosition
.y
.y
= 0.0;
1360 this->listener
->ds3dl
.vPosition
.z
.z
= 0.0;
1361 this->listener
->ds3dl
.vVelocity
.x
.x
= 0.0;
1362 this->listener
->ds3dl
.vVelocity
.y
.y
= 0.0;
1363 this->listener
->ds3dl
.vVelocity
.z
.z
= 0.0;
1364 this->listener
->ds3dl
.vOrientFront
.x
.x
= 0.0;
1365 this->listener
->ds3dl
.vOrientFront
.y
.y
= 0.0;
1366 this->listener
->ds3dl
.vOrientFront
.z
.z
= 1.0;
1367 this->listener
->ds3dl
.vOrientTop
.x
.x
= 0.0;
1368 this->listener
->ds3dl
.vOrientTop
.y
.y
= 1.0;
1369 this->listener
->ds3dl
.vOrientTop
.z
.z
= 0.0;
1370 this->listener
->ds3dl
.flDistanceFactor
= DS3D_DEFAULTDISTANCEFACTOR
;
1371 this->listener
->ds3dl
.flRolloffFactor
= DS3D_DEFAULTROLLOFFFACTOR
;
1372 this->listener
->ds3dl
.flDopplerFactor
= DS3D_DEFAULTDOPPLERFACTOR
;
1373 *ppobj
= (LPVOID
)this->listener
;
1377 WINE_StringFromCLSID(riid
,xbuf
);
1378 TRACE(dsound
,"(%p,%s,%p)\n",this,xbuf
,ppobj
);
1382 static HRESULT WINAPI
IDirectSound_Compact(
1385 TRACE(dsound
, "(%p)\n", this);
1389 static HRESULT WINAPI
IDirectSound_GetSpeakerConfig(
1391 LPDWORD lpdwSpeakerConfig
)
1393 TRACE(dsound
, "(%p, %p)\n", this, lpdwSpeakerConfig
);
1394 *lpdwSpeakerConfig
= DSSPEAKER_STEREO
| (DSSPEAKER_GEOMETRY_NARROW
<< 16);
1398 static HRESULT WINAPI
IDirectSound_Initialize(
1402 TRACE(dsound
, "(%p, %p)\n", this, lpGuid
);
1406 static struct tagLPDIRECTSOUND_VTABLE dsvt
= {
1407 IDirectSound_QueryInterface
,
1408 IDirectSound_AddRef
,
1409 IDirectSound_Release
,
1410 IDirectSound_CreateSoundBuffer
,
1411 IDirectSound_GetCaps
,
1412 IDirectSound_DuplicateSoundBuffer
,
1413 IDirectSound_SetCooperativeLevel
,
1414 IDirectSound_Compact
,
1415 IDirectSound_GetSpeakerConfig
,
1416 IDirectSound_SetSpeakerConfig
,
1417 IDirectSound_Initialize
1421 DSOUND_setformat(LPWAVEFORMATEX wfex
) {
1422 int xx
,channels
,speed
,format
,nformat
;
1425 TRACE(dsound
, "(%p) deferred\n", wfex
);
1428 switch (wfex
->wFormatTag
) {
1430 WARN(dsound
,"unknown WAVE_FORMAT tag %d\n",wfex
->wFormatTag
);
1431 return DSERR_BADFORMAT
;
1432 case WAVE_FORMAT_PCM
:
1435 if (wfex
->wBitsPerSample
==8)
1438 format
= AFMT_S16_LE
;
1440 if (-1==ioctl(audiofd
,SNDCTL_DSP_GETFMTS
,&xx
)) {
1441 perror("ioctl SNDCTL_DSP_GETFMTS");
1444 if ((xx
&format
)!=format
) {/* format unsupported */
1445 FIXME(dsound
,"SNDCTL_DSP_GETFMTS: format not supported\n");
1449 if (-1==ioctl(audiofd
,SNDCTL_DSP_SETFMT
,&nformat
)) {
1450 perror("ioctl SNDCTL_DSP_SETFMT");
1453 if (nformat
!=format
) {/* didn't work */
1454 FIXME(dsound
,"SNDCTL_DSP_GETFMTS: format not set\n");
1458 channels
= wfex
->nChannels
-1;
1459 if (-1==ioctl(audiofd
,SNDCTL_DSP_STEREO
,&channels
)) {
1460 perror("ioctl SNDCTL_DSP_STEREO");
1463 speed
= wfex
->nSamplesPerSec
;
1464 if (-1==ioctl(audiofd
,SNDCTL_DSP_SPEED
,&speed
)) {
1465 perror("ioctl SNDCTL_DSP_SPEED");
1468 TRACE(dsound
,"(freq=%ld,channels=%d,bits=%d)\n",
1469 wfex
->nSamplesPerSec
,wfex
->nChannels
,wfex
->wBitsPerSample
1474 static void DSOUND_CheckEvent(IDirectSoundBuffer
*dsb
, int len
)
1478 LPDSBPOSITIONNOTIFY event
;
1480 if (dsb
->nrofnotifies
== 0)
1483 TRACE(dsound
,"(%p) buflen = %ld, playpos = %ld, len = %d\n",
1484 dsb
, dsb
->buflen
, dsb
->playpos
, len
);
1485 for (i
= 0; i
< dsb
->nrofnotifies
; i
++) {
1486 event
= dsb
->notifies
+ i
;
1487 offset
= event
->dwOffset
;
1488 TRACE(dsound
, "checking %d, position %ld, event = %d\n",
1489 i
, offset
, event
->hEventNotify
);
1490 /* DSBPN_OFFSETSTOP has to be the last element. So this is */
1491 /* OK. [Inside DirectX, p274] */
1493 /* This also means we can't sort the entries by offset, */
1494 /* because DSBPN_OFFSETSTOP == -1 */
1495 if (offset
== DSBPN_OFFSETSTOP
) {
1496 if (dsb
->playing
== 0) {
1497 SetEvent(event
->hEventNotify
);
1498 TRACE(dsound
,"signalled event %d (%d)\n", event
->hEventNotify
, i
);
1503 if ((dsb
->playpos
+ len
) >= dsb
->buflen
) {
1504 if ((offset
< ((dsb
->playpos
+ len
) % dsb
->buflen
)) ||
1505 (offset
>= dsb
->playpos
)) {
1506 TRACE(dsound
,"signalled event %d (%d)\n", event
->hEventNotify
, i
);
1507 SetEvent(event
->hEventNotify
);
1510 if ((offset
>= dsb
->playpos
) && (offset
< (dsb
->playpos
+ len
))) {
1511 TRACE(dsound
,"signalled event %d (%d)\n", event
->hEventNotify
, i
);
1512 SetEvent(event
->hEventNotify
);
1518 /* WAV format info can be found at: */
1520 /* http://www.cwi.nl/ftp/audio/AudioFormats.part2 */
1521 /* ftp://ftp.cwi.nl/pub/audio/RIFF-format */
1523 /* Import points to remember: */
1525 /* 8-bit WAV is unsigned */
1526 /* 16-bit WAV is signed */
1528 static inline INT16
cvtU8toS16(BYTE byte
)
1530 INT16 s
= (byte
- 128) << 8;
1535 static inline BYTE
cvtS16toU8(INT16 word
)
1537 BYTE b
= (word
+ 32768) >> 8;
1543 /* We should be able to optimize these two inline functions */
1544 /* so that we aren't doing 8->16->8 conversions when it is */
1545 /* not necessary. But this is still a WIP. Optimize later. */
1546 static inline void get_fields(const IDirectSoundBuffer
*dsb
, BYTE
*buf
, INT32
*fl
, INT32
*fr
)
1548 INT16
*bufs
= (INT16
*) buf
;
1550 /* TRACE(dsound, "(%p)", buf); */
1551 if ((dsb
->wfx
.wBitsPerSample
== 8) && dsb
->wfx
.nChannels
== 2) {
1552 *fl
= cvtU8toS16(*buf
);
1553 *fr
= cvtU8toS16(*(buf
+ 1));
1557 if ((dsb
->wfx
.wBitsPerSample
== 16) && dsb
->wfx
.nChannels
== 2) {
1563 if ((dsb
->wfx
.wBitsPerSample
== 8) && dsb
->wfx
.nChannels
== 1) {
1564 *fl
= cvtU8toS16(*buf
);
1569 if ((dsb
->wfx
.wBitsPerSample
== 16) && dsb
->wfx
.nChannels
== 1) {
1575 FIXME(dsound
, "get_fields found an unsupported configuration\n");
1579 static inline void set_fields(BYTE
*buf
, INT32 fl
, INT32 fr
)
1581 INT16
*bufs
= (INT16
*) buf
;
1583 if ((primarybuf
->wfx
.wBitsPerSample
== 8) && (primarybuf
->wfx
.nChannels
== 2)) {
1584 *buf
= cvtS16toU8(fl
);
1585 *(buf
+ 1) = cvtS16toU8(fr
);
1589 if ((primarybuf
->wfx
.wBitsPerSample
== 16) && (primarybuf
->wfx
.nChannels
== 2)) {
1595 if ((primarybuf
->wfx
.wBitsPerSample
== 8) && (primarybuf
->wfx
.nChannels
== 1)) {
1596 *buf
= cvtS16toU8((fl
+ fr
) >> 1);
1600 if ((primarybuf
->wfx
.wBitsPerSample
== 16) && (primarybuf
->wfx
.nChannels
== 1)) {
1601 *bufs
= (fl
+ fr
) >> 1;
1604 FIXME(dsound
, "set_fields found an unsupported configuration\n");
1608 /* Now with PerfectPitch (tm) technology */
1609 static INT32
DSOUND_MixerNorm(IDirectSoundBuffer
*dsb
, BYTE
*buf
, INT32 len
)
1611 INT32 i
, size
, ipos
, ilen
, fieldL
, fieldR
;
1613 INT32 iAdvance
= dsb
->wfx
.nBlockAlign
;
1614 INT32 oAdvance
= primarybuf
->wfx
.nBlockAlign
;
1616 ibp
= dsb
->buffer
+ dsb
->playpos
;
1619 TRACE(dsound
, "(%p, %p, %p), playpos=%8.8lx\n", dsb
, ibp
, obp
, dsb
->playpos
);
1620 /* Check for the best case */
1621 if ((dsb
->freq
== primarybuf
->wfx
.nSamplesPerSec
) &&
1622 (dsb
->wfx
.wBitsPerSample
== primarybuf
->wfx
.wBitsPerSample
) &&
1623 (dsb
->wfx
.nChannels
== primarybuf
->wfx
.nChannels
)) {
1624 TRACE(dsound
, "(%p) Best case\n", dsb
);
1625 if ((ibp
+ len
) < (BYTE
*)(dsb
->buffer
+ dsb
->buflen
))
1626 memcpy(obp
, ibp
, len
);
1628 memcpy(obp
, ibp
, dsb
->buflen
- dsb
->playpos
);
1629 memcpy(obp
+ (dsb
->buflen
- dsb
->playpos
),
1631 len
- (dsb
->buflen
- dsb
->playpos
));
1636 /* Check for same sample rate */
1637 if (dsb
->freq
== primarybuf
->wfx
.nSamplesPerSec
) {
1638 TRACE(dsound
, "(%p) Same sample rate %ld = primary %ld\n", dsb
,
1639 dsb
->freq
, primarybuf
->wfx
.nSamplesPerSec
);
1641 for (i
= 0; i
< len
; i
+= oAdvance
) {
1642 get_fields(dsb
, ibp
, &fieldL
, &fieldR
);
1645 set_fields(obp
, fieldL
, fieldR
);
1647 if (ibp
>= (BYTE
*)(dsb
->buffer
+ dsb
->buflen
))
1648 ibp
= dsb
->buffer
; /* wrap */
1653 /* Mix in different sample rates */
1655 /* New PerfectPitch(tm) Technology (c) 1998 Rob Riggs */
1656 /* Patent Pending :-] */
1658 TRACE(dsound
, "(%p) Adjusting frequency: %ld -> %ld\n",
1659 dsb
, dsb
->freq
, primarybuf
->wfx
.nSamplesPerSec
);
1661 size
= len
/ oAdvance
;
1662 ilen
= ((size
* dsb
->freqAdjust
) >> DSOUND_FREQSHIFT
) * iAdvance
;
1663 for (i
= 0; i
< size
; i
++) {
1665 ipos
= (((i
* dsb
->freqAdjust
) >> DSOUND_FREQSHIFT
) * iAdvance
) + dsb
->playpos
;
1667 if (ipos
>= dsb
->buflen
)
1668 ipos
%= dsb
->buflen
; /* wrap */
1670 get_fields(dsb
, (dsb
->buffer
+ ipos
), &fieldL
, &fieldR
);
1671 set_fields(obp
, fieldL
, fieldR
);
1677 static void DSOUND_MixerVol(IDirectSoundBuffer
*dsb
, BYTE
*buf
, INT32 len
)
1679 INT32 i
, inc
= primarybuf
->wfx
.wBitsPerSample
>> 3;
1681 INT16
*bps
= (INT16
*) buf
;
1683 TRACE(dsound
, "(%p) left = %lx, right = %lx\n", dsb
,
1684 dsb
->lVolAdjust
, dsb
->rVolAdjust
);
1685 if ((!(dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLPAN
) || (dsb
->pan
== 0)) &&
1686 (!(dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLVOLUME
) || (dsb
->volume
== 0)) &&
1687 !(dsb
->dsbd
.dwFlags
& DSBCAPS_CTRL3D
))
1688 return; /* Nothing to do */
1690 /* If we end up with some bozo coder using panning or 3D sound */
1691 /* with a mono primary buffer, it could sound very weird using */
1692 /* this method. Oh well, tough patooties. */
1694 for (i
= 0; i
< len
; i
+= inc
) {
1700 /* 8-bit WAV is unsigned, but we need to operate */
1701 /* on signed data for this to work properly */
1703 val
= ((val
* (i
& inc
? dsb
->rVolAdjust
: dsb
->lVolAdjust
)) >> 15);
1708 /* 16-bit WAV is signed -- much better */
1710 val
= ((val
* ((i
& inc
) ? dsb
->rVolAdjust
: dsb
->lVolAdjust
)) >> 15);
1716 FIXME(dsound
, "MixerVol had a nasty error\n");
1722 static void DSOUND_Mixer3D(IDirectSoundBuffer
*dsb
, BYTE
*buf
, INT32 len
)
1725 DWORD buflen
, playpos
;
1727 buflen
= dsb
->ds3db
->buflen
;
1728 playpos
= (dsb
->playpos
* primarybuf
->wfx
.nBlockAlign
) / dsb
->wfx
.nBlockAlign
;
1729 ibp
= dsb
->ds3db
->buffer
+ playpos
;
1732 if (playpos
> buflen
) {
1733 FIXME(dsound
, "Major breakage");
1737 if (len
<= (playpos
+ buflen
))
1738 memcpy(obp
, ibp
, len
);
1740 memcpy(obp
, ibp
, buflen
- playpos
);
1741 memcpy(obp
+ (buflen
- playpos
),
1743 len
- (buflen
- playpos
));
1749 static DWORD
DSOUND_MixInBuffer(IDirectSoundBuffer
*dsb
)
1751 INT32 i
, len
, ilen
, temp
, field
;
1752 INT32 advance
= primarybuf
->wfx
.wBitsPerSample
>> 3;
1753 BYTE
*buf
, *ibuf
, *obuf
;
1754 INT16
*ibufs
, *obufs
;
1756 len
= DSOUND_FRAGLEN
; /* The most we will use */
1757 if (!(dsb
->playflags
& DSBPLAY_LOOPING
)) {
1758 temp
= ((primarybuf
->wfx
.nAvgBytesPerSec
* dsb
->buflen
) /
1759 dsb
->nAvgBytesPerSec
) -
1760 ((primarybuf
->wfx
.nAvgBytesPerSec
* dsb
->playpos
) /
1761 dsb
->nAvgBytesPerSec
);
1762 len
= (len
> temp
) ? temp
: len
;
1764 len
&= ~3; /* 4 byte alignment */
1767 /* This should only happen if we aren't looping and temp < 4 */
1769 /* We skip the remainder, so check for possible events */
1770 DSOUND_CheckEvent(dsb
, dsb
->buflen
- dsb
->playpos
);
1775 /* Check for DSBPN_OFFSETSTOP */
1776 DSOUND_CheckEvent(dsb
, 0);
1780 /* Been seeing segfaults in malloc() for some reason... */
1781 TRACE(dsound
, "allocating buffer (size = %d)\n", len
);
1782 if ((buf
= ibuf
= (BYTE
*) malloc(len
)) == NULL
)
1785 TRACE(dsound
, "MixInBuffer (%p) len = %d\n", dsb
, len
);
1787 ilen
= DSOUND_MixerNorm(dsb
, ibuf
, len
);
1788 if ((dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLPAN
) ||
1789 (dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLVOLUME
))
1790 DSOUND_MixerVol(dsb
, ibuf
, len
);
1792 obuf
= primarybuf
->buffer
+ primarybuf
->playpos
;
1793 for (i
= 0; i
< len
; i
+= advance
) {
1794 obufs
= (INT16
*) obuf
;
1795 ibufs
= (INT16
*) ibuf
;
1796 if (primarybuf
->wfx
.wBitsPerSample
== 8) {
1797 /* 8-bit WAV is unsigned */
1798 field
= (*ibuf
- 128);
1799 field
+= (*obuf
- 128);
1800 field
= field
> 127 ? 127 : field
;
1801 field
= field
< -128 ? -128 : field
;
1802 *obuf
= field
+ 128;
1804 /* 16-bit WAV is signed */
1807 field
= field
> 32767 ? 32767 : field
;
1808 field
= field
< -32768 ? -32768 : field
;
1813 if (obuf
>= (BYTE
*)(primarybuf
->buffer
+ primarybuf
->buflen
))
1814 obuf
= primarybuf
->buffer
;
1818 if (dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLPOSITIONNOTIFY
)
1819 DSOUND_CheckEvent(dsb
, ilen
);
1821 dsb
->playpos
+= ilen
;
1822 dsb
->writepos
= dsb
->playpos
+ ilen
;
1824 if (dsb
->playpos
>= dsb
->buflen
) {
1825 if (!(dsb
->playflags
& DSBPLAY_LOOPING
)) {
1829 DSOUND_CheckEvent(dsb
, 0); /* For DSBPN_OFFSETSTOP */
1831 dsb
->playpos
%= dsb
->buflen
; /* wrap */
1834 if (dsb
->writepos
>= dsb
->buflen
)
1835 dsb
->writepos
%= dsb
->buflen
;
1840 static DWORD WINAPI
DSOUND_MixPrimary(void)
1842 INT32 i
, len
, maxlen
= 0;
1843 IDirectSoundBuffer
*dsb
;
1845 for (i
= dsound
->nrofbuffers
- 1; i
>= 0; i
--) {
1846 dsb
= dsound
->buffers
[i
];
1848 if (!dsb
|| !(dsb
->lpvtbl
))
1850 dsb
->lpvtbl
->fnAddRef(dsb
);
1851 if (dsb
->buflen
&& dsb
->playing
) {
1852 EnterCriticalSection(&(dsb
->lock
));
1853 len
= DSOUND_MixInBuffer(dsb
);
1854 maxlen
= len
> maxlen
? len
: maxlen
;
1855 LeaveCriticalSection(&(dsb
->lock
));
1857 dsb
->lpvtbl
->fnRelease(dsb
);
1863 static int DSOUND_OpenAudio(void)
1867 if (primarybuf
== NULL
)
1868 return DSERR_OUTOFMEMORY
;
1870 while (audiofd
!= -1)
1872 audiofd
= open("/dev/audio",O_WRONLY
);
1874 /* Don't worry if sound is busy at the moment */
1876 perror("open /dev/audio");
1877 return audiofd
; /* -1 */
1880 /* We should probably do something here if SETFRAGMENT fails... */
1881 audioFragment
=0x0002000c;
1882 if (-1==ioctl(audiofd
,SNDCTL_DSP_SETFRAGMENT
,&audioFragment
))
1883 perror("ioctl SETFRAGMENT");
1886 DSOUND_setformat(&(primarybuf
->wfx
));
1891 static void DSOUND_CloseAudio(void)
1895 neutral
= primarybuf
->wfx
.wBitsPerSample
== 8 ? 128 : 0;
1896 audioOK
= 0; /* race condition */
1898 /* It's possible we've been called with audio closed */
1899 /* from SetFormat()... this is just to force a call */
1900 /* to OpenAudio() to reset the hardware properly */
1903 primarybuf
->playpos
= 0;
1904 primarybuf
->writepos
= DSOUND_FRAGLEN
;
1905 memset(primarybuf
->buffer
, neutral
, primarybuf
->buflen
);
1907 TRACE(dsound
, "Audio stopped\n");
1910 static int DSOUND_WriteAudio(char *buf
, int len
)
1912 int result
, left
= 0;
1914 while (left
< len
) {
1915 result
= write(audiofd
, buf
+ left
, len
- left
);
1926 static void DSOUND_OutputPrimary(int len
)
1928 int neutral
, flen1
, flen2
;
1929 char *frag1
, *frag2
;
1931 /* This is a bad place for this. We need to clear the */
1932 /* buffer with a neutral value, for unsigned 8-bit WAVE */
1933 /* that's 128, for signed 16-bit it's 0 */
1934 neutral
= primarybuf
->wfx
.wBitsPerSample
== 8 ? 128 : 0;
1937 EnterCriticalSection(&(primarybuf
->lock
));
1940 if ((audioOK
== 1) || (DSOUND_OpenAudio() == 0)) {
1941 if (primarybuf
->playpos
+ len
>= primarybuf
->buflen
) {
1942 frag1
= primarybuf
->buffer
+ primarybuf
->playpos
;
1943 flen1
= primarybuf
->buflen
- primarybuf
->playpos
;
1944 frag2
= primarybuf
->buffer
;
1945 flen2
= len
- (primarybuf
->buflen
- primarybuf
->playpos
);
1946 if (DSOUND_WriteAudio(frag1
, flen1
) != 0) {
1947 perror("DSOUND_WriteAudio");
1948 LeaveCriticalSection(&(primarybuf
->lock
));
1951 memset(frag1
, neutral
, flen1
);
1952 if (DSOUND_WriteAudio(frag2
, flen2
) != 0) {
1953 perror("DSOUND_WriteAudio");
1954 LeaveCriticalSection(&(primarybuf
->lock
));
1957 memset(frag2
, neutral
, flen2
);
1959 frag1
= primarybuf
->buffer
+ primarybuf
->playpos
;
1961 if (DSOUND_WriteAudio(frag1
, flen1
) != 0) {
1962 perror("DSOUND_WriteAudio");
1963 LeaveCriticalSection(&(primarybuf
->lock
));
1966 memset(frag1
, neutral
, flen1
);
1969 /* Can't play audio at the moment -- we need to sleep */
1970 /* to make up for the time we'd be blocked in write() */
1974 primarybuf
->playpos
+= len
;
1975 if (primarybuf
->playpos
>= primarybuf
->buflen
)
1976 primarybuf
->playpos
%= primarybuf
->buflen
;
1977 primarybuf
->writepos
= primarybuf
->playpos
+ DSOUND_FRAGLEN
;
1978 if (primarybuf
->writepos
>= primarybuf
->buflen
)
1979 primarybuf
->writepos
%= primarybuf
->buflen
;
1981 LeaveCriticalSection(&(primarybuf
->lock
));
1985 static DWORD WINAPI
DSOUND_thread(LPVOID arg
)
1989 TRACE(dsound
,"dsound is at pid %d\n",getpid());
1992 WARN(dsound
,"DSOUND thread giving up.\n");
1996 WARN(dsound
,"DSOUND father died? Giving up.\n");
1999 /* RACE: dsound could be deleted */
2000 dsound
->lpvtbl
->fnAddRef(dsound
);
2001 if (primarybuf
== NULL
) {
2002 /* Should never happen */
2003 WARN(dsound
, "Lost the primary buffer!\n");
2004 dsound
->lpvtbl
->fnRelease(dsound
);
2009 EnterCriticalSection(&(primarybuf
->lock
));
2010 len
= DSOUND_MixPrimary();
2011 LeaveCriticalSection(&(primarybuf
->lock
));
2014 if (primarybuf
->playing
)
2015 len
= DSOUND_FRAGLEN
> len
? DSOUND_FRAGLEN
: len
;
2017 /* This does all the work */
2018 DSOUND_OutputPrimary(len
);
2020 /* no buffers playing -- close and wait */
2022 DSOUND_CloseAudio();
2025 dsound
->lpvtbl
->fnRelease(dsound
);
2030 #endif /* HAVE_OSS */
2032 HRESULT WINAPI
DirectSoundCreate(LPGUID lpGUID
,LPDIRECTSOUND
*ppDS
,IUnknown
*pUnkOuter
)
2035 TRACE(dsound
,"(%p,%p,%p)\n",lpGUID
,ppDS
,pUnkOuter
);
2037 TRACE(dsound
,"DirectSoundCreate (%p)\n", ppDS
);
2042 return DSERR_INVALIDPARAM
;
2045 dsound
->lpvtbl
->fnAddRef(dsound
);
2050 /* Check that we actually have audio capabilities */
2051 /* If we do, whether it's busy or not, we continue */
2052 /* otherwise we return with DSERR_NODRIVER */
2054 audiofd
= open("/dev/audio",O_WRONLY
);
2055 if (audiofd
== -1) {
2056 if (errno
== ENODEV
) {
2057 TRACE(dsound
, "No sound hardware\n");
2058 return DSERR_NODRIVER
;
2059 } else if (errno
== EBUSY
) {
2060 TRACE(dsound
, "Sound device busy, will keep trying\n");
2062 TRACE(dsound
, "Unexpected error while checking for sound support\n");
2063 return DSERR_GENERIC
;
2070 *ppDS
= (LPDIRECTSOUND
)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSound
));
2072 return DSERR_OUTOFMEMORY
;
2075 (*ppDS
)->lpvtbl
= &dsvt
;
2076 (*ppDS
)->buffers
= NULL
;
2077 (*ppDS
)->nrofbuffers
= 0;
2079 (*ppDS
)->wfx
.wFormatTag
= 1;
2080 (*ppDS
)->wfx
.nChannels
= 2;
2081 (*ppDS
)->wfx
.nSamplesPerSec
= 22050;
2082 (*ppDS
)->wfx
.nAvgBytesPerSec
= 44100;
2083 (*ppDS
)->wfx
.nBlockAlign
= 2;
2084 (*ppDS
)->wfx
.wBitsPerSample
= 8;
2091 if (primarybuf
== NULL
) {
2095 dsbd
.dwSize
= sizeof(DSBUFFERDESC
);
2096 dsbd
.dwFlags
= DSBCAPS_PRIMARYBUFFER
;
2097 dsbd
.dwBufferBytes
= 0;
2098 dsbd
.lpwfxFormat
= &(dsound
->wfx
);
2099 hr
= IDirectSound_CreateSoundBuffer(*ppDS
, &dsbd
, &primarybuf
, NULL
);
2102 dsound
->primary
= primarybuf
;
2104 memset(primarybuf
->buffer
, 128, primarybuf
->buflen
);
2105 hnd
= CreateThread(NULL
,0,DSOUND_thread
,0,0,&xid
);
2109 MessageBox32A(0,"DirectSound needs the Open Sound System Driver, which has not been found by ./configure.","WINE DirectSound",MB_OK
|MB_ICONSTOP
);
2110 return DSERR_NODRIVER
;
2114 /*******************************************************************************
2115 * DirectSound ClassFactory
2117 static HRESULT WINAPI
2118 DSCF_QueryInterface(LPUNKNOWN iface
,REFIID riid
,LPVOID
*ppobj
) {
2119 ICOM_THIS(IClassFactory
,iface
);
2123 WINE_StringFromCLSID(riid
,buf
);
2125 sprintf(buf
,"<guid-0x%04x>",LOWORD(riid
));
2126 FIXME(dsound
,"(%p)->(%s,%p),stub!\n",this,buf
,ppobj
);
2127 return E_NOINTERFACE
;
2131 DSCF_AddRef(LPUNKNOWN iface
) {
2132 ICOM_THIS(IClassFactory
,iface
);
2133 return ++(this->ref
);
2136 static ULONG WINAPI
DSCF_Release(LPUNKNOWN iface
) {
2137 ICOM_THIS(IClassFactory
,iface
);
2138 /* static class, won't be freed */
2139 return --(this->ref
);
2142 static HRESULT WINAPI
DSCF_CreateInstance(
2143 LPCLASSFACTORY iface
,LPUNKNOWN pOuter
,REFIID riid
,LPVOID
*ppobj
2145 ICOM_THIS(IClassFactory
,iface
);
2148 WINE_StringFromCLSID(riid
,buf
);
2149 TRACE(dsound
,"(%p)->(%p,%s,%p)\n",this,pOuter
,buf
,ppobj
);
2150 if (!memcmp(riid
,&IID_IDirectSound
,sizeof(IID_IDirectSound
))) {
2151 /* FIXME: reuse already created dsound if present? */
2152 return DirectSoundCreate(riid
,(LPDIRECTSOUND
*)ppobj
,pOuter
);
2154 return E_NOINTERFACE
;
2157 static HRESULT WINAPI
DSCF_LockServer(LPCLASSFACTORY iface
,BOOL32 dolock
) {
2158 ICOM_THIS(IClassFactory
,iface
);
2159 FIXME(dsound
,"(%p)->(%d),stub!\n",this,dolock
);
2163 static ICOM_VTABLE(IClassFactory
) DSCF_VTable
= {
2165 DSCF_QueryInterface
,
2169 DSCF_CreateInstance
,
2172 static _IClassFactory DSOUND_CF
= {&DSCF_VTable
, 1 };
2174 /*******************************************************************************
2175 * DllGetClassObject [DSOUND.4]
2176 * Retrieves class object from a DLL object
2179 * Docs say returns STDAPI
2182 * rclsid [I] CLSID for the class object
2183 * riid [I] Reference to identifier of interface for class object
2184 * ppv [O] Address of variable to receive interface pointer for riid
2188 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
2191 DWORD WINAPI
DSOUND_DllGetClassObject(REFCLSID rclsid
,REFIID riid
,LPVOID
*ppv
)
2193 char buf
[80],xbuf
[80];
2196 WINE_StringFromCLSID(rclsid
,xbuf
);
2198 sprintf(xbuf
,"<guid-0x%04x>",LOWORD(rclsid
));
2200 WINE_StringFromCLSID(riid
,buf
);
2202 sprintf(buf
,"<guid-0x%04x>",LOWORD(riid
));
2203 WINE_StringFromCLSID(riid
,xbuf
);
2204 TRACE(dsound
, "(%p,%p,%p)\n", xbuf
, buf
, ppv
);
2205 if (!memcmp(riid
,&IID_IClassFactory
,sizeof(IID_IClassFactory
))) {
2206 *ppv
= (LPVOID
)&DSOUND_CF
;
2207 IClassFactory_AddRef(&DSOUND_CF
);
2210 FIXME(dsound
, "(%p,%p,%p): no interface found.\n", xbuf
, buf
, ppv
);
2211 return E_NOINTERFACE
;
2215 /*******************************************************************************
2216 * DllCanUnloadNow [DSOUND.3] Determines whether the DLL is in use.
2222 DWORD WINAPI
DSOUND_DllCanUnloadNow(void)
2224 FIXME(dsound
, "(void): stub\n");