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 "interfaces.h"
52 # include <sys/ioctl.h>
53 # ifdef HAVE_MACHINE_SOUNDCARD_H
54 # include <machine/soundcard.h>
56 # ifdef HAVE_SYS_SOUNDCARD_H
57 # include <sys/soundcard.h>
60 /* #define USE_DSOUND3D 1 */
62 #define DSOUND_FRAGLEN (primarybuf->wfx.nAvgBytesPerSec >> 4)
63 #define DSOUND_FREQSHIFT (14)
65 static int audiofd
= -1;
66 static int audioOK
= 0;
68 static LPDIRECTSOUND dsound
= NULL
;
70 static LPDIRECTSOUNDBUFFER primarybuf
= NULL
;
72 static int DSOUND_setformat(LPWAVEFORMATEX wfex
);
73 static void DSOUND_CheckEvent(IDirectSoundBuffer
*dsb
, int len
);
74 static void DSOUND_CloseAudio(void);
78 HRESULT WINAPI
DirectSoundEnumerate32A(LPDSENUMCALLBACK32A enumcb
,LPVOID context
) {
80 enumcb(NULL
,"WINE DirectSound using Open Sound System","sound",context
);
86 static void _dump_DSBCAPS(DWORD xmask
) {
91 #define FE(x) { x, #x },
92 FE(DSBCAPS_PRIMARYBUFFER
)
94 FE(DSBCAPS_LOCHARDWARE
)
95 FE(DSBCAPS_LOCSOFTWARE
)
96 FE(DSBCAPS_CTRLFREQUENCY
)
98 FE(DSBCAPS_CTRLVOLUME
)
99 FE(DSBCAPS_CTRLDEFAULT
)
101 FE(DSBCAPS_STICKYFOCUS
)
102 FE(DSBCAPS_GETCURRENTPOSITION2
)
106 for (i
=0;i
<sizeof(flags
)/sizeof(flags
[0]);i
++)
107 if (flags
[i
].mask
& xmask
)
108 fprintf(stderr
,"%s ",flags
[i
].name
);
111 /*******************************************************************************
112 * IDirectSound3DBuffer
116 static HRESULT WINAPI
IDirectSound3DBuffer_QueryInterface(
117 LPDIRECTSOUND3DBUFFER
this, REFIID riid
, LPVOID
*ppobj
)
121 WINE_StringFromCLSID(riid
,xbuf
);
122 TRACE(dsound
,"(%p,%s,%p)\n",this,xbuf
,ppobj
);
126 static ULONG WINAPI
IDirectSound3DBuffer_AddRef(LPDIRECTSOUND3DBUFFER
this)
132 static ULONG WINAPI
IDirectSound3DBuffer_Release(LPDIRECTSOUND3DBUFFER
this)
137 HeapFree(GetProcessHeap(),0,this->buffer
);
138 HeapFree(GetProcessHeap(),0,this);
143 // IDirectSound3DBuffer methods
144 static HRESULT WINAPI
IDirectSound3DBuffer_GetAllParameters(
145 LPDIRECTSOUND3DBUFFER
this,
146 LPDS3DBUFFER lpDs3dBuffer
)
148 FIXME(dsound
,"stub\n");
152 static HRESULT WINAPI
IDirectSound3DBuffer_GetConeAngles(
153 LPDIRECTSOUND3DBUFFER
this,
154 LPDWORD lpdwInsideConeAngle
,
155 LPDWORD lpdwOutsideConeAngle
)
157 FIXME(dsound
,"stub\n");
161 static HRESULT WINAPI
IDirectSound3DBuffer_GetConeOrientation(
162 LPDIRECTSOUND3DBUFFER
this,
163 LPD3DVECTOR lpvConeOrientation
)
165 FIXME(dsound
,"stub\n");
169 static HRESULT WINAPI
IDirectSound3DBuffer_GetConeOutsideVolume(
170 LPDIRECTSOUND3DBUFFER
this,
171 LPLONG lplConeOutsideVolume
)
173 FIXME(dsound
,"stub\n");
177 static HRESULT WINAPI
IDirectSound3DBuffer_GetMaxDistance(
178 LPDIRECTSOUND3DBUFFER
this,
179 LPD3DVALUE lpfMaxDistance
)
181 FIXME(dsound
,"stub\n");
185 static HRESULT WINAPI
IDirectSound3DBuffer_GetMinDistance(
186 LPDIRECTSOUND3DBUFFER
this,
187 LPD3DVALUE lpfMinDistance
)
189 FIXME(dsound
,"stub\n");
193 static HRESULT WINAPI
IDirectSound3DBuffer_GetMode(
194 LPDIRECTSOUND3DBUFFER
this,
197 FIXME(dsound
,"stub\n");
201 static HRESULT WINAPI
IDirectSound3DBuffer_GetPosition(
202 LPDIRECTSOUND3DBUFFER
this,
203 LPD3DVECTOR lpvPosition
)
205 FIXME(dsound
,"stub\n");
209 static HRESULT WINAPI
IDirectSound3DBuffer_GetVelocity(
210 LPDIRECTSOUND3DBUFFER
this,
211 LPD3DVECTOR lpvVelocity
)
213 FIXME(dsound
,"stub\n");
217 static HRESULT WINAPI
IDirectSound3DBuffer_SetAllParameters(
218 LPDIRECTSOUND3DBUFFER
this,
219 LPCDS3DBUFFER lpcDs3dBuffer
,
222 FIXME(dsound
,"stub\n");
226 static HRESULT WINAPI
IDirectSound3DBuffer_SetConeAngles(
227 LPDIRECTSOUND3DBUFFER
this,
228 DWORD dwInsideConeAngle
,
229 DWORD dwOutsideConeAngle
,
232 FIXME(dsound
,"stub\n");
236 static HRESULT WINAPI
IDirectSound3DBuffer_SetConeOrientation(
237 LPDIRECTSOUND3DBUFFER
this,
238 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
241 FIXME(dsound
,"stub\n");
245 static HRESULT WINAPI
IDirectSound3DBuffer_SetConeOutsideVolume(
246 LPDIRECTSOUND3DBUFFER
this,
247 LONG lConeOutsideVolume
,
250 FIXME(dsound
,"stub\n");
254 static HRESULT WINAPI
IDirectSound3DBuffer_SetMaxDistance(
255 LPDIRECTSOUND3DBUFFER
this,
256 D3DVALUE fMaxDistance
,
259 FIXME(dsound
,"stub\n");
263 static HRESULT WINAPI
IDirectSound3DBuffer_SetMinDistance(
264 LPDIRECTSOUND3DBUFFER
this,
265 D3DVALUE fMinDistance
,
268 FIXME(dsound
,"stub\n");
272 static HRESULT WINAPI
IDirectSound3DBuffer_SetMode(
273 LPDIRECTSOUND3DBUFFER
this,
277 TRACE(dsound
, "mode = %lx\n", dwMode
);
278 this->ds3db
.dwMode
= dwMode
;
282 static HRESULT WINAPI
IDirectSound3DBuffer_SetPosition(
283 LPDIRECTSOUND3DBUFFER
this,
284 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
287 FIXME(dsound
,"stub\n");
291 static HRESULT WINAPI
IDirectSound3DBuffer_SetVelocity(
292 LPDIRECTSOUND3DBUFFER
this,
293 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
296 FIXME(dsound
,"stub\n");
300 IDirectSound3DBuffer_VTable ds3dbvt
= {
302 IDirectSound3DBuffer_QueryInterface
,
303 IDirectSound3DBuffer_AddRef
,
304 IDirectSound3DBuffer_Release
,
305 // IDirectSound3DBuffer methods
306 IDirectSound3DBuffer_GetAllParameters
,
307 IDirectSound3DBuffer_GetConeAngles
,
308 IDirectSound3DBuffer_GetConeOrientation
,
309 IDirectSound3DBuffer_GetConeOutsideVolume
,
310 IDirectSound3DBuffer_GetMaxDistance
,
311 IDirectSound3DBuffer_GetMinDistance
,
312 IDirectSound3DBuffer_GetMode
,
313 IDirectSound3DBuffer_GetPosition
,
314 IDirectSound3DBuffer_GetVelocity
,
315 IDirectSound3DBuffer_SetAllParameters
,
316 IDirectSound3DBuffer_SetConeAngles
,
317 IDirectSound3DBuffer_SetConeOrientation
,
318 IDirectSound3DBuffer_SetConeOutsideVolume
,
319 IDirectSound3DBuffer_SetMaxDistance
,
320 IDirectSound3DBuffer_SetMinDistance
,
321 IDirectSound3DBuffer_SetMode
,
322 IDirectSound3DBuffer_SetPosition
,
323 IDirectSound3DBuffer_SetVelocity
,
327 static int DSOUND_Create3DBuffer(LPDIRECTSOUNDBUFFER dsb
)
329 DWORD i
, temp
, iSize
, oSize
, offset
;
330 LPBYTE bIbuf
, bObuf
, bTbuf
= NULL
;
331 LPWORD wIbuf
, wObuf
, wTbuf
= NULL
;
333 // Inside DirectX says it's stupid but allowed
334 if (dsb
->wfx
.nChannels
== 2) {
336 if (dsb
->wfx
.wBitsPerSample
== 16) {
337 iSize
= dsb
->buflen
/ 4;
338 wTbuf
= malloc(dsb
->buflen
/ 2);
340 return DSERR_OUTOFMEMORY
;
341 for (i
= 0; i
< iSize
; i
++)
342 wTbuf
[i
] = (dsb
->buffer
[i
] + dsb
->buffer
[(i
* 2) + 1]) / 2;
345 iSize
= dsb
->buflen
/ 2;
346 bTbuf
= malloc(dsb
->buflen
/ 2);
348 return DSERR_OUTOFMEMORY
;
349 for (i
= 0; i
< iSize
; i
++)
350 bTbuf
[i
] = (dsb
->buffer
[i
] + dsb
->buffer
[(i
* 2) + 1]) / 2;
354 if (dsb
->wfx
.wBitsPerSample
== 16) {
355 iSize
= dsb
->buflen
/ 2;
356 wIbuf
= (LPWORD
) dsb
->buffer
;
358 bIbuf
= (LPBYTE
) dsb
->buffer
;
363 if (primarybuf
->wfx
.wBitsPerSample
== 16) {
364 wObuf
= (LPWORD
) dsb
->ds3db
->buffer
;
365 oSize
= dsb
->ds3db
->buflen
/ 2;
367 bObuf
= (LPBYTE
) dsb
->ds3db
->buffer
;
368 oSize
= dsb
->ds3db
->buflen
;
371 offset
= primarybuf
->wfx
.nSamplesPerSec
/ 100; // 10ms
372 if (primarybuf
->wfx
.wBitsPerSample
== 16 && dsb
->wfx
.wBitsPerSample
== 16)
373 for (i
= 0; i
< iSize
; i
++) {
376 temp
+= wIbuf
[i
- offset
] >> 9;
378 temp
+= wIbuf
[i
+ iSize
- offset
] >> 9;
380 wObuf
[(i
* 2) + 1] = temp
;
382 else if (primarybuf
->wfx
.wBitsPerSample
== 8 && dsb
->wfx
.wBitsPerSample
== 8)
383 for (i
= 0; i
< iSize
; i
++) {
386 temp
+= bIbuf
[i
- offset
] >> 5;
388 temp
+= bIbuf
[i
+ iSize
- offset
] >> 5;
390 bObuf
[(i
* 2) + 1] = temp
;
401 /*******************************************************************************
402 * IDirectSound3DListener
406 static HRESULT WINAPI
IDirectSound3DListener_QueryInterface(
407 LPDIRECTSOUND3DLISTENER
this, REFIID riid
, LPVOID
*ppobj
)
411 WINE_StringFromCLSID(riid
,xbuf
);
412 TRACE(dsound
,"(%p,%s,%p)\n",this,xbuf
,ppobj
);
416 static ULONG WINAPI
IDirectSound3DListener_AddRef(LPDIRECTSOUND3DLISTENER
this)
422 static ULONG WINAPI
IDirectSound3DListener_Release(LPDIRECTSOUND3DLISTENER
this)
428 // IDirectSound3DListener methods
429 static HRESULT WINAPI
IDirectSound3DListener_GetAllParameter(
430 LPDIRECTSOUND3DLISTENER
this,
431 LPDS3DLISTENER lpDS3DL
)
433 FIXME(dsound
,"stub\n");
437 static HRESULT WINAPI
IDirectSound3DListener_GetDistanceFactor(
438 LPDIRECTSOUND3DLISTENER
this,
439 LPD3DVALUE lpfDistanceFactor
)
441 FIXME(dsound
,"stub\n");
445 static HRESULT WINAPI
IDirectSound3DListener_GetDopplerFactor(
446 LPDIRECTSOUND3DLISTENER
this,
447 LPD3DVALUE lpfDopplerFactor
)
449 FIXME(dsound
,"stub\n");
453 static HRESULT WINAPI
IDirectSound3DListener_GetOrientation(
454 LPDIRECTSOUND3DLISTENER
this,
455 LPD3DVECTOR lpvOrientFront
,
456 LPD3DVECTOR lpvOrientTop
)
458 FIXME(dsound
,"stub\n");
462 static HRESULT WINAPI
IDirectSound3DListener_GetPosition(
463 LPDIRECTSOUND3DLISTENER
this,
464 LPD3DVECTOR lpvPosition
)
466 FIXME(dsound
,"stub\n");
470 static HRESULT WINAPI
IDirectSound3DListener_GetRolloffFactor(
471 LPDIRECTSOUND3DLISTENER
this,
472 LPD3DVALUE lpfRolloffFactor
)
474 FIXME(dsound
,"stub\n");
478 static HRESULT WINAPI
IDirectSound3DListener_GetVelocity(
479 LPDIRECTSOUND3DLISTENER
this,
480 LPD3DVECTOR lpvVelocity
)
482 FIXME(dsound
,"stub\n");
486 static HRESULT WINAPI
IDirectSound3DListener_SetAllParameters(
487 LPDIRECTSOUND3DLISTENER
this,
488 LPCDS3DLISTENER lpcDS3DL
,
491 FIXME(dsound
,"stub\n");
495 static HRESULT WINAPI
IDirectSound3DListener_SetDistanceFactor(
496 LPDIRECTSOUND3DLISTENER
this,
497 D3DVALUE fDistanceFactor
,
500 FIXME(dsound
,"stub\n");
504 static HRESULT WINAPI
IDirectSound3DListener_SetDopplerFactor(
505 LPDIRECTSOUND3DLISTENER
this,
506 D3DVALUE fDopplerFactor
,
509 FIXME(dsound
,"stub\n");
513 static HRESULT WINAPI
IDirectSound3DListener_SetOrientation(
514 LPDIRECTSOUND3DLISTENER
this,
515 D3DVALUE xFront
, D3DVALUE yFront
, D3DVALUE zFront
,
516 D3DVALUE xTop
, D3DVALUE yTop
, D3DVALUE zTop
,
519 FIXME(dsound
,"stub\n");
523 static HRESULT WINAPI
IDirectSound3DListener_SetPosition(
524 LPDIRECTSOUND3DLISTENER
this,
525 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
528 FIXME(dsound
,"stub\n");
532 static HRESULT WINAPI
IDirectSound3DListener_SetRolloffFactor(
533 LPDIRECTSOUND3DLISTENER
this,
534 D3DVALUE fRolloffFactor
,
537 FIXME(dsound
,"stub\n");
541 static HRESULT WINAPI
IDirectSound3DListener_SetVelocity(
542 LPDIRECTSOUND3DLISTENER
this,
543 D3DVALUE x
, D3DVALUE y
, D3DVALUE z
,
546 FIXME(dsound
,"stub\n");
550 static HRESULT WINAPI
IDirectSound3DListener_CommitDeferredSettings(
551 LPDIRECTSOUND3DLISTENER
this)
554 FIXME(dsound
,"stub\n");
558 IDirectSound3DListener_VTable ds3dlvt
= {
560 IDirectSound3DListener_QueryInterface
,
561 IDirectSound3DListener_AddRef
,
562 IDirectSound3DListener_Release
,
563 // IDirectSound3DListener methods
564 IDirectSound3DListener_GetAllParameter
,
565 IDirectSound3DListener_GetDistanceFactor
,
566 IDirectSound3DListener_GetDopplerFactor
,
567 IDirectSound3DListener_GetOrientation
,
568 IDirectSound3DListener_GetPosition
,
569 IDirectSound3DListener_GetRolloffFactor
,
570 IDirectSound3DListener_GetVelocity
,
571 IDirectSound3DListener_SetAllParameters
,
572 IDirectSound3DListener_SetDistanceFactor
,
573 IDirectSound3DListener_SetDopplerFactor
,
574 IDirectSound3DListener_SetOrientation
,
575 IDirectSound3DListener_SetPosition
,
576 IDirectSound3DListener_SetRolloffFactor
,
577 IDirectSound3DListener_SetVelocity
,
578 IDirectSound3DListener_CommitDeferredSettings
,
581 /*******************************************************************************
584 static HRESULT WINAPI
IDirectSoundNotify_QueryInterface(
585 LPDIRECTSOUNDNOTIFY
this,REFIID riid
,LPVOID
*ppobj
589 WINE_StringFromCLSID(riid
,xbuf
);
590 TRACE(dsound
,"(%p,%s,%p)\n",this,xbuf
,ppobj
);
594 static ULONG WINAPI
IDirectSoundNotify_AddRef(LPDIRECTSOUNDNOTIFY
this) {
595 return ++(this->ref
);
598 static ULONG WINAPI
IDirectSoundNotify_Release(LPDIRECTSOUNDNOTIFY
this) {
601 this->dsb
->lpvtbl
->fnRelease(this->dsb
);
602 HeapFree(GetProcessHeap(),0,this);
608 static HRESULT WINAPI
IDirectSoundNotify_SetNotificationPositions(
609 LPDIRECTSOUNDNOTIFY
this,DWORD howmuch
,LPCDSBPOSITIONNOTIFY notify
613 if (TRACE_ON(dsound
)) {
614 TRACE(dsound
,"(%p,0x%08lx,%p)\n",this,howmuch
,notify
);
615 for (i
=0;i
<howmuch
;i
++)
616 TRACE(dsound
,"notify at %ld to 0x%08lx\n",
617 notify
[i
].dwOffset
,(DWORD
)notify
[i
].hEventNotify
);
619 this->dsb
->notifies
= HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,this->dsb
->notifies
,(this->dsb
->nrofnotifies
+howmuch
)*sizeof(DSBPOSITIONNOTIFY
));
620 memcpy( this->dsb
->notifies
+this->dsb
->nrofnotifies
,
622 howmuch
*sizeof(DSBPOSITIONNOTIFY
)
624 this->dsb
->nrofnotifies
+=howmuch
;
629 IDirectSoundNotify_VTable dsnvt
= {
630 IDirectSoundNotify_QueryInterface
,
631 IDirectSoundNotify_AddRef
,
632 IDirectSoundNotify_Release
,
633 IDirectSoundNotify_SetNotificationPositions
,
636 /*******************************************************************************
640 // This sets this format for the <em>Primary Buffer Only</em>
641 // See file:///cdrom/sdk52/docs/worddoc/dsound.doc page 120
642 static HRESULT WINAPI
IDirectSoundBuffer_SetFormat(
643 LPDIRECTSOUNDBUFFER
this,LPWAVEFORMATEX wfex
645 LPDIRECTSOUNDBUFFER
*dsb
;
648 // Let's be pedantic!
649 if ((wfex
== NULL
) ||
650 (wfex
->wFormatTag
!= WAVE_FORMAT_PCM
) ||
651 (wfex
->nChannels
< 1) || (wfex
->nChannels
> 2) ||
652 (wfex
->nSamplesPerSec
< 1) ||
653 (wfex
->nBlockAlign
< 1) || (wfex
->nChannels
> 4) ||
654 ((wfex
->wBitsPerSample
!= 8) && (wfex
->wBitsPerSample
!= 16))) {
655 TRACE(dsound
, "failed pedantic check!\n");
656 return DSERR_INVALIDPARAM
;
660 EnterCriticalSection(&(primarybuf
->lock
));
662 if (primarybuf
->wfx
.nSamplesPerSec
!= wfex
->nSamplesPerSec
) {
663 dsb
= dsound
->buffers
;
664 for (i
= 0; i
< dsound
->nrofbuffers
; i
++, dsb
++) {
666 EnterCriticalSection(&((*dsb
)->lock
));
668 (*dsb
)->freqAdjust
= ((*dsb
)->freq
<< DSOUND_FREQSHIFT
) /
669 wfex
->nSamplesPerSec
;
671 LeaveCriticalSection(&((*dsb
)->lock
));
676 memcpy(&(primarybuf
->wfx
), wfex
, sizeof(primarybuf
->wfx
));
678 TRACE(dsound
,"(formattag=0x%04x,chans=%d,samplerate=%ld"
679 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
680 wfex
->wFormatTag
, wfex
->nChannels
, wfex
->nSamplesPerSec
,
681 wfex
->nAvgBytesPerSec
, wfex
->nBlockAlign
,
682 wfex
->wBitsPerSample
, wfex
->cbSize
);
684 primarybuf
->wfx
.nAvgBytesPerSec
=
685 this->wfx
.nSamplesPerSec
* this->wfx
.nBlockAlign
;
689 LeaveCriticalSection(&(primarybuf
->lock
));
695 static HRESULT WINAPI
IDirectSoundBuffer_SetVolume(
696 LPDIRECTSOUNDBUFFER
this,LONG vol
700 TRACE(dsound
,"(%p,%ld)\n",this,vol
);
702 // I'm not sure if we need this for primary buffer
703 if (!(this->dsbd
.dwFlags
& DSBCAPS_CTRLVOLUME
))
704 return DSERR_CONTROLUNAVAIL
;
706 if ((vol
> DSBVOLUME_MAX
) || (vol
< DSBVOLUME_MIN
))
707 return DSERR_INVALIDPARAM
;
709 // This needs to adjust the soundcard volume when
710 // called for the primary buffer
711 if (this->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
712 FIXME(dsound
, "Volume control of primary unimplemented.\n");
718 EnterCriticalSection(&(this->lock
));
722 temp
= (double) (this->volume
- (this->pan
> 0 ? this->pan
: 0));
723 this->lVolAdjust
= (ULONG
) (pow(2.0, temp
/ 600.0) * 32768.0);
724 temp
= (double) (this->volume
+ (this->pan
< 0 ? this->pan
: 0));
725 this->rVolAdjust
= (ULONG
) (pow(2.0, temp
/ 600.0) * 32768.0);
727 LeaveCriticalSection(&(this->lock
));
730 TRACE(dsound
, "left = %lx, right = %lx\n", this->lVolAdjust
, this->rVolAdjust
);
735 static HRESULT WINAPI
IDirectSoundBuffer_GetVolume(
736 LPDIRECTSOUNDBUFFER
this,LPLONG vol
738 TRACE(dsound
,"(%p,%p)\n",this,vol
);
741 return DSERR_INVALIDPARAM
;
747 static HRESULT WINAPI
IDirectSoundBuffer_SetFrequency(
748 LPDIRECTSOUNDBUFFER
this,DWORD freq
750 TRACE(dsound
,"(%p,%ld)\n",this,freq
);
752 // You cannot set the frequency of the primary buffer
753 if (!(this->dsbd
.dwFlags
& DSBCAPS_CTRLFREQUENCY
) ||
754 (this->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
))
755 return DSERR_CONTROLUNAVAIL
;
757 if ((freq
< DSBFREQUENCY_MIN
) || (freq
> DSBFREQUENCY_MAX
))
758 return DSERR_INVALIDPARAM
;
761 EnterCriticalSection(&(this->lock
));
764 this->freqAdjust
= (freq
<< DSOUND_FREQSHIFT
) / primarybuf
->wfx
.nSamplesPerSec
;
765 this->nAvgBytesPerSec
= freq
* this->wfx
.nBlockAlign
;
767 LeaveCriticalSection(&(this->lock
));
773 static HRESULT WINAPI
IDirectSoundBuffer_Play(
774 LPDIRECTSOUNDBUFFER
this,DWORD reserved1
,DWORD reserved2
,DWORD flags
776 TRACE(dsound
,"(%p,%08lx,%08lx,%08lx)\n",
777 this,reserved1
,reserved2
,flags
779 this->playflags
= flags
;
784 static HRESULT WINAPI
IDirectSoundBuffer_Stop(LPDIRECTSOUNDBUFFER
this)
786 TRACE(dsound
,"(%p)\n",this);
789 EnterCriticalSection(&(this->lock
));
792 DSOUND_CheckEvent(this, 0);
794 LeaveCriticalSection(&(this->lock
));
800 static DWORD WINAPI
IDirectSoundBuffer_AddRef(LPDIRECTSOUNDBUFFER
this) {
801 // TRACE(dsound,"(%p) ref was %ld\n",this, this->ref);
803 return ++(this->ref
);
805 static DWORD WINAPI
IDirectSoundBuffer_Release(LPDIRECTSOUNDBUFFER
this) {
808 // TRACE(dsound,"(%p) ref was %ld\n",this, this->ref);
813 for (i
=0;i
<this->dsound
->nrofbuffers
;i
++)
814 if (this->dsound
->buffers
[i
] == this)
816 if (i
< this->dsound
->nrofbuffers
) {
817 /* Put the last buffer of the list in the (now empty) position */
818 this->dsound
->buffers
[i
] = this->dsound
->buffers
[this->dsound
->nrofbuffers
- 1];
819 this->dsound
->buffers
= HeapReAlloc(GetProcessHeap(),0,this->dsound
->buffers
,sizeof(LPDIRECTSOUNDBUFFER
)*this->dsound
->nrofbuffers
);
820 this->dsound
->nrofbuffers
--;
821 this->dsound
->lpvtbl
->fnRelease(this->dsound
);
824 DeleteCriticalSection(&(this->lock
));
826 if (this->ds3db
&& this->ds3db
->lpvtbl
)
827 this->ds3db
->lpvtbl
->fnRelease(this->ds3db
);
829 HeapFree(GetProcessHeap(),0,this->buffer
);
830 HeapFree(GetProcessHeap(),0,this);
832 if (this == primarybuf
)
838 static HRESULT WINAPI
IDirectSoundBuffer_GetCurrentPosition(
839 LPDIRECTSOUNDBUFFER
this,LPDWORD playpos
,LPDWORD writepos
841 TRACE(dsound
,"(%p,%p,%p)\n",this,playpos
,writepos
);
842 if (playpos
) *playpos
= this->playpos
;
843 if (writepos
) *writepos
= this->writepos
;
847 static HRESULT WINAPI
IDirectSoundBuffer_GetStatus(
848 LPDIRECTSOUNDBUFFER
this,LPDWORD status
850 TRACE(dsound
,"(%p,%p)\n",this,status
);
853 return DSERR_INVALIDPARAM
;
857 *status
|= DSBSTATUS_PLAYING
;
858 if (this->playflags
& DSBPLAY_LOOPING
)
859 *status
|= DSBSTATUS_LOOPING
;
865 static HRESULT WINAPI
IDirectSoundBuffer_GetFormat(
866 LPDIRECTSOUNDBUFFER
this,LPWAVEFORMATEX lpwf
,DWORD wfsize
,LPDWORD wfwritten
868 TRACE(dsound
,"(%p,%p,%ld,%p)\n",this,lpwf
,wfsize
,wfwritten
);
870 if (wfsize
>sizeof(this->wfx
))
871 wfsize
= sizeof(this->wfx
);
872 if (lpwf
) { // NULL is valid
873 memcpy(lpwf
,&(this->wfx
),wfsize
);
878 *wfwritten
= sizeof(this->wfx
);
880 return DSERR_INVALIDPARAM
;
885 static HRESULT WINAPI
IDirectSoundBuffer_Lock(
886 LPDIRECTSOUNDBUFFER
this,DWORD writecursor
,DWORD writebytes
,LPVOID lplpaudioptr1
,LPDWORD audiobytes1
,LPVOID lplpaudioptr2
,LPDWORD audiobytes2
,DWORD flags
889 TRACE(dsound
,"(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx)\n",
899 if (flags
& DSBLOCK_FROMWRITECURSOR
)
900 writecursor
+= this->writepos
;
901 if (flags
& DSBLOCK_ENTIREBUFFER
)
902 writebytes
= this->buflen
;
903 if (writebytes
> this->buflen
)
904 writebytes
= this->buflen
;
906 assert(audiobytes1
!=audiobytes2
);
907 assert(lplpaudioptr1
!=lplpaudioptr2
);
908 if (writecursor
+writebytes
<= this->buflen
) {
909 *(LPBYTE
*)lplpaudioptr1
= this->buffer
+writecursor
;
910 *audiobytes1
= writebytes
;
912 *(LPBYTE
*)lplpaudioptr2
= NULL
;
915 TRACE(dsound
,"->%ld.0\n",writebytes
);
917 *(LPBYTE
*)lplpaudioptr1
= this->buffer
+writecursor
;
918 *audiobytes1
= this->buflen
-writecursor
;
920 *(LPBYTE
*)lplpaudioptr2
= this->buffer
;
922 *audiobytes2
= writebytes
-(this->buflen
-writecursor
);
923 TRACE(dsound
,"->%ld.%ld\n",*audiobytes1
,audiobytes2
?*audiobytes2
:0);
925 // No. See file:///cdrom/sdk52/docs/worddoc/dsound.doc page 21
926 // this->writepos=(writecursor+writebytes)%this->buflen;
930 static HRESULT WINAPI
IDirectSoundBuffer_SetCurrentPosition(
931 LPDIRECTSOUNDBUFFER
this,DWORD newpos
933 TRACE(dsound
,"(%p,%ld)\n",this,newpos
);
936 EnterCriticalSection(&(this->lock
));
938 this->playpos
= newpos
;
940 LeaveCriticalSection(&(this->lock
));
946 static HRESULT WINAPI
IDirectSoundBuffer_SetPan(
947 LPDIRECTSOUNDBUFFER
this,LONG pan
951 TRACE(dsound
,"(%p,%ld)\n",this,pan
);
953 if ((pan
> DSBPAN_RIGHT
) || (pan
< DSBPAN_LEFT
))
954 return DSERR_INVALIDPARAM
;
956 // You cannot set the pan of the primary buffer
957 // and you cannot use both pan and 3D controls
958 if (!(this->dsbd
.dwFlags
& DSBCAPS_CTRLPAN
) ||
959 (this->dsbd
.dwFlags
& DSBCAPS_CTRL3D
) ||
960 (this->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
))
961 return DSERR_CONTROLUNAVAIL
;
964 EnterCriticalSection(&(this->lock
));
968 temp
= (double) (this->volume
- (this->pan
> 0 ? this->pan
: 0));
969 this->lVolAdjust
= (ULONG
) (pow(2.0, temp
/ 600.0) * 32768.0);
970 temp
= (double) (this->volume
+ (this->pan
< 0 ? this->pan
: 0));
971 this->rVolAdjust
= (ULONG
) (pow(2.0, temp
/ 600.0) * 32768.0);
973 LeaveCriticalSection(&(this->lock
));
979 static HRESULT WINAPI
IDirectSoundBuffer_GetPan(
980 LPDIRECTSOUNDBUFFER
this,LPLONG pan
982 TRACE(dsound
,"(%p,%p)\n",this,pan
);
985 return DSERR_INVALIDPARAM
;
992 static HRESULT WINAPI
IDirectSoundBuffer_Unlock(
993 LPDIRECTSOUNDBUFFER
this,LPVOID p1
,DWORD x1
,LPVOID p2
,DWORD x2
995 TRACE(dsound
,"(%p,%p,%ld,%p,%ld):stub\n", this,p1
,x1
,p2
,x2
);
997 // There is really nothing to do here. Should someone
998 // choose to implement static buffers in hardware (by
999 // using a wave table synth, for example) this is where
1000 // you'd want to do the loading. For software buffers,
1001 // which is what we currently use, we need do nothing.
1004 // It's also the place to pre-process 3D buffers...
1006 // This is highly experimental and liable to break things
1007 if (this->dsbd
.dwFlags
& DSBCAPS_CTRL3D
)
1008 DSOUND_Create3DBuffer(this);
1014 static HRESULT WINAPI
IDirectSoundBuffer_GetFrequency(
1015 LPDIRECTSOUNDBUFFER
this,LPDWORD freq
1017 TRACE(dsound
,"(%p,%p)\n",this,freq
);
1020 return DSERR_INVALIDPARAM
;
1027 static HRESULT WINAPI
IDirectSoundBuffer_Initialize(
1028 LPDIRECTSOUNDBUFFER
this,LPDIRECTSOUND dsound
,LPDSBUFFERDESC dbsd
1030 FIXME(dsound
,"(%p,%p,%p):stub\n",this,dsound
,dbsd
);
1031 printf("Re-Init!!!\n");
1032 return DSERR_ALREADYINITIALIZED
;
1035 static HRESULT WINAPI
IDirectSoundBuffer_GetCaps(
1036 LPDIRECTSOUNDBUFFER
this,LPDSBCAPS caps
1038 TRACE(dsound
,"(%p)->(%p)\n",this,caps
);
1041 return DSERR_INVALIDPARAM
;
1043 // I think we should check this value, not set it. See
1044 // Inside DirectX, p215. That should apply here, too.
1045 caps
->dwSize
= sizeof(*caps
);
1047 caps
->dwFlags
= this->dsbd
.dwFlags
| DSBCAPS_LOCSOFTWARE
;
1048 caps
->dwBufferBytes
= this->dsbd
.dwBufferBytes
;
1049 /* This value represents the speed of the "unlock" command.
1050 As unlock is quite fast (it does not do anything), I put
1051 4096 ko/s = 4 Mo / s */
1052 caps
->dwUnlockTransferRate
= 4096;
1053 caps
->dwPlayCpuOverhead
= 0;
1058 static HRESULT WINAPI
IDirectSoundBuffer_QueryInterface(
1059 LPDIRECTSOUNDBUFFER
this,REFIID riid
,LPVOID
*ppobj
1063 WINE_StringFromCLSID(riid
,xbuf
);
1064 TRACE(dsound
,"(%p,%s,%p)\n",this,xbuf
,ppobj
);
1066 if (!memcmp(&IID_IDirectSoundNotify
,riid
,sizeof(*riid
))) {
1067 IDirectSoundNotify
*dsn
;
1069 dsn
= (LPDIRECTSOUNDNOTIFY
)HeapAlloc(GetProcessHeap(),0,sizeof(*dsn
));
1072 this->lpvtbl
->fnAddRef(this);
1073 dsn
->lpvtbl
= &dsnvt
;
1074 *ppobj
= (LPVOID
)dsn
;
1078 if (!memcmp(&IID_IDirectSound3DBuffer
,riid
,sizeof(*riid
))) {
1079 *ppobj
= this->ds3db
;
1087 static struct tagLPDIRECTSOUNDBUFFER_VTABLE dsbvt
= {
1088 IDirectSoundBuffer_QueryInterface
,
1089 IDirectSoundBuffer_AddRef
,
1090 IDirectSoundBuffer_Release
,
1091 IDirectSoundBuffer_GetCaps
,
1092 IDirectSoundBuffer_GetCurrentPosition
,
1093 IDirectSoundBuffer_GetFormat
,
1094 IDirectSoundBuffer_GetVolume
,
1095 IDirectSoundBuffer_GetPan
,
1096 IDirectSoundBuffer_GetFrequency
,
1097 IDirectSoundBuffer_GetStatus
,
1098 IDirectSoundBuffer_Initialize
,
1099 IDirectSoundBuffer_Lock
,
1100 IDirectSoundBuffer_Play
,
1101 IDirectSoundBuffer_SetCurrentPosition
,
1102 IDirectSoundBuffer_SetFormat
,
1103 IDirectSoundBuffer_SetVolume
,
1104 IDirectSoundBuffer_SetPan
,
1105 IDirectSoundBuffer_SetFrequency
,
1106 IDirectSoundBuffer_Stop
,
1107 IDirectSoundBuffer_Unlock
1110 /*******************************************************************************
1114 static HRESULT WINAPI
IDirectSound_SetCooperativeLevel(
1115 LPDIRECTSOUND
this,HWND32 hwnd
,DWORD level
1117 FIXME(dsound
,"(%p,%08lx,%ld):stub\n",this,(DWORD
)hwnd
,level
);
1121 static HRESULT WINAPI
IDirectSound_CreateSoundBuffer(
1122 LPDIRECTSOUND
this,LPDSBUFFERDESC dsbd
,LPLPDIRECTSOUNDBUFFER ppdsb
,LPUNKNOWN lpunk
1124 LPWAVEFORMATEX wfex
;
1126 TRACE(dsound
,"(%p,%p,%p,%p)\n",this,dsbd
,ppdsb
,lpunk
);
1128 if ((this == NULL
) || (dsbd
== NULL
) || (ppdsb
== NULL
))
1129 return DSERR_INVALIDPARAM
;
1131 if (TRACE_ON(dsound
)) {
1132 TRACE(dsound
,"(size=%ld)\n",dsbd
->dwSize
);
1133 TRACE(dsound
,"(flags=0x%08lx\n",dsbd
->dwFlags
);
1134 _dump_DSBCAPS(dsbd
->dwFlags
);
1135 TRACE(dsound
,"(bufferbytes=%ld)\n",dsbd
->dwBufferBytes
);
1136 TRACE(dsound
,"(lpwfxFormat=%p)\n",dsbd
->lpwfxFormat
);
1139 wfex
= dsbd
->lpwfxFormat
;
1142 TRACE(dsound
,"(formattag=0x%04x,chans=%d,samplerate=%ld"
1143 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
1144 wfex
->wFormatTag
, wfex
->nChannels
, wfex
->nSamplesPerSec
,
1145 wfex
->nAvgBytesPerSec
, wfex
->nBlockAlign
,
1146 wfex
->wBitsPerSample
, wfex
->cbSize
);
1148 if (dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
1150 primarybuf
->lpvtbl
->fnAddRef(primarybuf
);
1151 *ppdsb
= primarybuf
;
1153 } // Else create primarybuf
1156 *ppdsb
= (LPDIRECTSOUNDBUFFER
)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDirectSoundBuffer
));
1158 return DSERR_OUTOFMEMORY
;
1161 TRACE(dsound
, "Created buffer at %p\n", *ppdsb
);
1163 if (dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
1164 (*ppdsb
)->buflen
= dsound
->wfx
.nAvgBytesPerSec
;
1165 (*ppdsb
)->freq
= dsound
->wfx
.nSamplesPerSec
;
1167 (*ppdsb
)->buflen
= dsbd
->dwBufferBytes
;
1168 (*ppdsb
)->freq
= dsbd
->lpwfxFormat
->nSamplesPerSec
;
1170 (*ppdsb
)->buffer
= (LPBYTE
)HeapAlloc(GetProcessHeap(),0,(*ppdsb
)->buflen
);
1171 if ((*ppdsb
)->buffer
== NULL
) {
1172 HeapFree(GetProcessHeap(),0,(*ppdsb
));
1174 return DSERR_OUTOFMEMORY
;
1176 // It's not necessary to initialize values to zero since
1177 // we allocated this structure with HEAP_ZERO_MEMORY...
1178 (*ppdsb
)->playpos
= 0;
1179 (*ppdsb
)->writepos
= 0;
1180 (*ppdsb
)->lpvtbl
= &dsbvt
;
1181 (*ppdsb
)->dsound
= this;
1182 (*ppdsb
)->playing
= 0;
1183 (*ppdsb
)->lVolAdjust
= (1 << 15);
1184 (*ppdsb
)->rVolAdjust
= (1 << 15);
1186 if (!(dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
)) {
1187 (*ppdsb
)->freqAdjust
= ((*ppdsb
)->freq
<< DSOUND_FREQSHIFT
) /
1188 primarybuf
->wfx
.nSamplesPerSec
;
1189 (*ppdsb
)->nAvgBytesPerSec
= (*ppdsb
)->freq
*
1190 dsbd
->lpwfxFormat
->nBlockAlign
;
1193 memcpy(&((*ppdsb
)->dsbd
),dsbd
,sizeof(*dsbd
));
1195 /* register buffer */
1196 if (!(dsbd
->dwFlags
& DSBCAPS_PRIMARYBUFFER
)) {
1197 this->buffers
= (LPDIRECTSOUNDBUFFER
*)HeapReAlloc(GetProcessHeap(),0,this->buffers
,sizeof(LPDIRECTSOUNDBUFFER
)*(this->nrofbuffers
+1));
1198 this->buffers
[this->nrofbuffers
] = *ppdsb
;
1199 this->nrofbuffers
++;
1201 this->lpvtbl
->fnAddRef(this);
1203 if (dsbd
->lpwfxFormat
)
1204 memcpy(&((*ppdsb
)->wfx
), dsbd
->lpwfxFormat
, sizeof((*ppdsb
)->wfx
));
1206 InitializeCriticalSection(&((*ppdsb
)->lock
));
1209 if (dsbd
->dwFlags
& DSBCAPS_CTRL3D
) {
1210 IDirectSound3DBuffer
*ds3db
;
1212 ds3db
= (LPDIRECTSOUND3DBUFFER
)HeapAlloc(GetProcessHeap(),
1215 ds3db
->dsb
= (*ppdsb
);
1216 ds3db
->lpvtbl
= &ds3dbvt
;
1217 (*ppdsb
)->ds3db
= ds3db
;
1218 ds3db
->ds3db
.dwSize
= sizeof(DS3DBUFFER
);
1219 ds3db
->ds3db
.vPosition
.x
= 0.0;
1220 ds3db
->ds3db
.vPosition
.y
= 0.0;
1221 ds3db
->ds3db
.vPosition
.z
= 0.0;
1222 ds3db
->ds3db
.vVelocity
.x
= 0.0;
1223 ds3db
->ds3db
.vVelocity
.y
= 0.0;
1224 ds3db
->ds3db
.vVelocity
.z
= 0.0;
1225 ds3db
->ds3db
.dwInsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
1226 ds3db
->ds3db
.dwOutsideConeAngle
= DS3D_DEFAULTCONEANGLE
;
1227 ds3db
->ds3db
.vConeOrientation
.x
= 0.0;
1228 ds3db
->ds3db
.vConeOrientation
.y
= 0.0;
1229 ds3db
->ds3db
.vConeOrientation
.z
= 0.0;
1230 ds3db
->ds3db
.lConeOutsideVolume
= DS3D_DEFAULTCONEOUTSIDEVOLUME
;
1231 ds3db
->ds3db
.flMinDistance
= DS3D_DEFAULTMINDISTANCE
;
1232 ds3db
->ds3db
.flMaxDistance
= DS3D_DEFAULTMAXDISTANCE
;
1233 ds3db
->ds3db
.dwMode
= DS3DMODE_NORMAL
;
1234 ds3db
->buflen
= ((*ppdsb
)->buflen
* primarybuf
->wfx
.nBlockAlign
) /
1235 (*ppdsb
)->wfx
.nBlockAlign
;
1236 ds3db
->buffer
= HeapAlloc(GetProcessHeap(), 0, ds3db
->buflen
);
1237 if (ds3db
->buffer
== NULL
) {
1239 ds3db
->ds3db
.dwMode
= DS3DMODE_DISABLE
;
1246 static HRESULT WINAPI
IDirectSound_DuplicateSoundBuffer(
1247 LPDIRECTSOUND
this,LPDIRECTSOUNDBUFFER pdsb
,LPLPDIRECTSOUNDBUFFER ppdsb
1249 TRACE(dsound
,"(%p,%p,%p)\n",this,pdsb
,ppdsb
);
1251 *ppdsb
= (LPDIRECTSOUNDBUFFER
)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDirectSoundBuffer
));
1254 (*ppdsb
)->buffer
= (LPBYTE
)HeapAlloc(GetProcessHeap(),0,pdsb
->buflen
);
1255 memcpy((*ppdsb
)->buffer
,pdsb
->buffer
,pdsb
->buflen
);
1256 (*ppdsb
)->buflen
= pdsb
->buflen
;
1257 (*ppdsb
)->playpos
= 0;
1258 (*ppdsb
)->writepos
= 0;
1259 (*ppdsb
)->lpvtbl
= &dsbvt
;
1260 (*ppdsb
)->dsound
= this;
1261 memcpy(&((*ppdsb
)->wfx
), &(pdsb
->wfx
), sizeof((*ppdsb
)->wfx
));
1262 /* register buffer */
1263 this->buffers
= (LPDIRECTSOUNDBUFFER
*)HeapReAlloc(GetProcessHeap(),0,this->buffers
,sizeof(LPDIRECTSOUNDBUFFER
)*(this->nrofbuffers
+1));
1264 this->buffers
[this->nrofbuffers
] = *ppdsb
;
1265 this->nrofbuffers
++;
1266 this->lpvtbl
->fnAddRef(this);
1271 static HRESULT WINAPI
IDirectSound_GetCaps(LPDIRECTSOUND
this,LPDSCAPS caps
) {
1272 TRACE(dsound
,"(%p,%p)\n",this,caps
);
1273 TRACE(dsound
,"(flags=0x%08lx)\n",caps
->dwFlags
);
1276 return DSERR_INVALIDPARAM
;
1278 // We should check this value, not set it. See Inside DirectX, p215.
1279 caps
->dwSize
= sizeof(*caps
);
1282 DSCAPS_PRIMARYSTEREO
|
1283 DSCAPS_PRIMARY16BIT
|
1284 DSCAPS_SECONDARYSTEREO
|
1285 DSCAPS_SECONDARY16BIT
|
1286 DSCAPS_CONTINUOUSRATE
;
1287 /* FIXME: query OSS */
1288 caps
->dwMinSecondarySampleRate
= DSBFREQUENCY_MIN
;
1289 caps
->dwMaxSecondarySampleRate
= DSBFREQUENCY_MAX
;
1291 caps
->dwPrimaryBuffers
= 1;
1293 caps
->dwMaxHwMixingAllBuffers
= 0;
1294 caps
->dwMaxHwMixingStaticBuffers
= 0;
1295 caps
->dwMaxHwMixingStreamingBuffers
= 0;
1297 caps
->dwFreeHwMixingAllBuffers
= 0;
1298 caps
->dwFreeHwMixingStaticBuffers
= 0;
1299 caps
->dwFreeHwMixingStreamingBuffers
= 0;
1301 caps
->dwMaxHw3DAllBuffers
= 0;
1302 caps
->dwMaxHw3DStaticBuffers
= 0;
1303 caps
->dwMaxHw3DStreamingBuffers
= 0;
1305 caps
->dwFreeHw3DAllBuffers
= 0;
1306 caps
->dwFreeHw3DStaticBuffers
= 0;
1307 caps
->dwFreeHw3DStreamingBuffers
= 0;
1309 caps
->dwTotalHwMemBytes
= 0;
1311 caps
->dwFreeHwMemBytes
= 0;
1313 caps
->dwMaxContigFreeHwMemBytes
= 0;
1315 caps
->dwUnlockTransferRateHwBuffers
= 4096; // But we have none...
1317 caps
->dwPlayCpuOverheadSwBuffers
= 1; // 1%
1322 static ULONG WINAPI
IDirectSound_AddRef(LPDIRECTSOUND
this) {
1323 return ++(this->ref
);
1326 static ULONG WINAPI
IDirectSound_Release(LPDIRECTSOUND
this) {
1327 TRACE(dsound
,"(%p), ref was %ld\n",this,this->ref
);
1328 if (!--(this->ref
)) {
1329 DSOUND_CloseAudio();
1330 while(IDirectSoundBuffer_Release(primarybuf
)); // Deallocate
1331 FIXME(dsound
, "need to release all buffers!\n");
1332 HeapFree(GetProcessHeap(),0,this);
1339 static HRESULT WINAPI
IDirectSound_SetSpeakerConfig(
1340 LPDIRECTSOUND
this,DWORD config
1342 FIXME(dsound
,"(%p,0x%08lx):stub\n",this,config
);
1346 static HRESULT WINAPI
IDirectSound_QueryInterface(
1347 LPDIRECTSOUND
this,REFIID riid
,LPVOID
*ppobj
1351 if (!memcmp(&IID_IDirectSound3DListener
,riid
,sizeof(*riid
))) {
1353 if (this->listener
) {
1354 *ppobj
= this->listener
;
1357 this->listener
= (LPDIRECTSOUND3DLISTENER
)HeapAlloc(
1358 GetProcessHeap(), 0, sizeof(*(this->listener
)));
1359 this->listener
->ref
= 1;
1360 this->listener
->lpvtbl
= &ds3dlvt
;
1361 this->lpvtbl
->fnAddRef(this);
1362 this->listener
->ds3dl
.dwSize
= sizeof(DS3DLISTENER
);
1363 this->listener
->ds3dl
.vPosition
.x
= 0.0;
1364 this->listener
->ds3dl
.vPosition
.y
= 0.0;
1365 this->listener
->ds3dl
.vPosition
.z
= 0.0;
1366 this->listener
->ds3dl
.vVelocity
.x
= 0.0;
1367 this->listener
->ds3dl
.vVelocity
.y
= 0.0;
1368 this->listener
->ds3dl
.vVelocity
.z
= 0.0;
1369 this->listener
->ds3dl
.vOrientFront
.x
= 0.0;
1370 this->listener
->ds3dl
.vOrientFront
.y
= 0.0;
1371 this->listener
->ds3dl
.vOrientFront
.z
= 1.0;
1372 this->listener
->ds3dl
.vOrientTop
.x
= 0.0;
1373 this->listener
->ds3dl
.vOrientTop
.y
= 1.0;
1374 this->listener
->ds3dl
.vOrientTop
.z
= 0.0;
1375 this->listener
->ds3dl
.flDistanceFactor
= DS3D_DEFAULTDISTANCEFACTOR
;
1376 this->listener
->ds3dl
.flRolloffFactor
= DS3D_DEFAULTROLLOFFFACTOR
;
1377 this->listener
->ds3dl
.flDopplerFactor
= DS3D_DEFAULTDOPPLERFACTOR
;
1378 *ppobj
= (LPVOID
)this->listener
;
1382 WINE_StringFromCLSID(riid
,xbuf
);
1383 TRACE(dsound
,"(%p,%s,%p)\n",this,xbuf
,ppobj
);
1387 static HRESULT WINAPI
IDirectSound_Compact(
1390 TRACE(dsound
, "(%p)\n", this);
1394 static HRESULT WINAPI
IDirectSound_GetSpeakerConfig(
1396 LPDWORD lpdwSpeakerConfig
)
1398 TRACE(dsound
, "(%p, %p)\n", this, lpdwSpeakerConfig
);
1399 *lpdwSpeakerConfig
= DSSPEAKER_STEREO
| (DSSPEAKER_GEOMETRY_NARROW
<< 16);
1403 static HRESULT WINAPI
IDirectSound_Initialize(
1407 TRACE(dsound
, "(%p, %p)\n", this, lpGuid
);
1411 static struct tagLPDIRECTSOUND_VTABLE dsvt
= {
1412 IDirectSound_QueryInterface
,
1413 IDirectSound_AddRef
,
1414 IDirectSound_Release
,
1415 IDirectSound_CreateSoundBuffer
,
1416 IDirectSound_GetCaps
,
1417 IDirectSound_DuplicateSoundBuffer
,
1418 IDirectSound_SetCooperativeLevel
,
1419 IDirectSound_Compact
,
1420 IDirectSound_GetSpeakerConfig
,
1421 IDirectSound_SetSpeakerConfig
,
1422 IDirectSound_Initialize
1426 DSOUND_setformat(LPWAVEFORMATEX wfex
) {
1427 int xx
,channels
,speed
,format
,nformat
;
1430 TRACE(dsound
, "(%p) deferred\n", wfex
);
1433 switch (wfex
->wFormatTag
) {
1435 WARN(dsound
,"unknown WAVE_FORMAT tag %d\n",wfex
->wFormatTag
);
1436 return DSERR_BADFORMAT
;
1437 case WAVE_FORMAT_PCM
:
1440 if (wfex
->wBitsPerSample
==8)
1443 format
= AFMT_S16_LE
;
1445 if (-1==ioctl(audiofd
,SNDCTL_DSP_GETFMTS
,&xx
)) {
1446 perror("ioctl SNDCTL_DSP_GETFMTS");
1449 if ((xx
&format
)!=format
) {/* format unsupported */
1450 FIXME(dsound
,"SNDCTL_DSP_GETFMTS: format not supported\n");
1454 if (-1==ioctl(audiofd
,SNDCTL_DSP_SETFMT
,&nformat
)) {
1455 perror("ioctl SNDCTL_DSP_SETFMT");
1458 if (nformat
!=format
) {/* didn't work */
1459 FIXME(dsound
,"SNDCTL_DSP_GETFMTS: format not set\n");
1463 channels
= wfex
->nChannels
-1;
1464 if (-1==ioctl(audiofd
,SNDCTL_DSP_STEREO
,&channels
)) {
1465 perror("ioctl SNDCTL_DSP_STEREO");
1468 speed
= wfex
->nSamplesPerSec
;
1469 if (-1==ioctl(audiofd
,SNDCTL_DSP_SPEED
,&speed
)) {
1470 perror("ioctl SNDCTL_DSP_SPEED");
1473 TRACE(dsound
,"(freq=%ld,channels=%d,bits=%d)\n",
1474 wfex
->nSamplesPerSec
,wfex
->nChannels
,wfex
->wBitsPerSample
1479 static void DSOUND_CheckEvent(IDirectSoundBuffer
*dsb
, int len
)
1483 LPDSBPOSITIONNOTIFY event
;
1485 if (dsb
->nrofnotifies
== 0)
1488 TRACE(dsound
,"(%p) buflen = %ld, playpos = %ld, len = %d\n",
1489 dsb
, dsb
->buflen
, dsb
->playpos
, len
);
1490 for (i
= 0; i
< dsb
->nrofnotifies
; i
++) {
1491 event
= dsb
->notifies
+ i
;
1492 offset
= event
->dwOffset
;
1493 TRACE(dsound
, "checking %d, position %ld, event = %d\n",
1494 i
, offset
, event
->hEventNotify
);
1495 // DSBPN_OFFSETSTOP has to be the last element. So this is
1496 // OK. [Inside DirectX, p274]
1498 // This also means we can't sort the entries by offset,
1499 // because DSBPN_OFFSETSTOP == -1
1500 if (offset
== DSBPN_OFFSETSTOP
) {
1501 if (dsb
->playing
== 0) {
1502 SetEvent(event
->hEventNotify
);
1503 TRACE(dsound
,"signalled event %d (%d)\n", event
->hEventNotify
, i
);
1508 if ((dsb
->playpos
+ len
) >= dsb
->buflen
) {
1509 if ((offset
< ((dsb
->playpos
+ len
) % dsb
->buflen
)) ||
1510 (offset
>= dsb
->playpos
)) {
1511 TRACE(dsound
,"signalled event %d (%d)\n", event
->hEventNotify
, i
);
1512 SetEvent(event
->hEventNotify
);
1515 if ((offset
>= dsb
->playpos
) && (offset
< (dsb
->playpos
+ len
))) {
1516 TRACE(dsound
,"signalled event %d (%d)\n", event
->hEventNotify
, i
);
1517 SetEvent(event
->hEventNotify
);
1523 // WAV format info can be found at:
1525 // http://www.cwi.nl/ftp/audio/AudioFormats.part2
1526 // ftp://ftp.cwi.nl/pub/audio/RIFF-format
1528 // Import points to remember:
1530 // 8-bit WAV is unsigned
1531 // 16-bit WAV is signed
1533 static inline INT16
cvtU8toS16(BYTE byte
)
1535 INT16 s
= (byte
- 128) << 8;
1540 static inline BYTE
cvtS16toU8(INT16 word
)
1542 BYTE b
= (word
+ 32768) >> 8;
1548 // We should be able to optimize these two inline functions
1549 // so that we aren't doing 8->16->8 conversions when it is
1550 // not necessary. But this is still a WIP. Optimize later.
1551 static inline void get_fields(const IDirectSoundBuffer
*dsb
, BYTE
*buf
, INT32
*fl
, INT32
*fr
)
1553 INT16
*bufs
= (INT16
*) buf
;
1555 // TRACE(dsound, "(%p)", buf);
1556 if ((dsb
->wfx
.wBitsPerSample
== 8) && dsb
->wfx
.nChannels
== 2) {
1557 *fl
= cvtU8toS16(*buf
);
1558 *fr
= cvtU8toS16(*(buf
+ 1));
1562 if ((dsb
->wfx
.wBitsPerSample
== 16) && dsb
->wfx
.nChannels
== 2) {
1568 if ((dsb
->wfx
.wBitsPerSample
== 8) && dsb
->wfx
.nChannels
== 1) {
1569 *fl
= cvtU8toS16(*buf
);
1574 if ((dsb
->wfx
.wBitsPerSample
== 16) && dsb
->wfx
.nChannels
== 1) {
1580 FIXME(dsound
, "get_fields found an unsupported configuration\n");
1584 static inline void set_fields(BYTE
*buf
, INT32 fl
, INT32 fr
)
1586 INT16
*bufs
= (INT16
*) buf
;
1588 if ((primarybuf
->wfx
.wBitsPerSample
== 8) && (primarybuf
->wfx
.nChannels
== 2)) {
1589 *buf
= cvtS16toU8(fl
);
1590 *(buf
+ 1) = cvtS16toU8(fr
);
1594 if ((primarybuf
->wfx
.wBitsPerSample
== 16) && (primarybuf
->wfx
.nChannels
== 2)) {
1600 if ((primarybuf
->wfx
.wBitsPerSample
== 8) && (primarybuf
->wfx
.nChannels
== 1)) {
1601 *buf
= cvtS16toU8((fl
+ fr
) >> 1);
1605 if ((primarybuf
->wfx
.wBitsPerSample
== 16) && (primarybuf
->wfx
.nChannels
== 1)) {
1606 *bufs
= (fl
+ fr
) >> 1;
1609 FIXME(dsound
, "set_fields found an unsupported configuration\n");
1613 // Now with PerfectPitch (tm) technology
1614 static INT32
DSOUND_MixerNorm(IDirectSoundBuffer
*dsb
, BYTE
*buf
, INT32 len
)
1616 INT32 i
, size
, ipos
, ilen
, fieldL
, fieldR
;
1618 INT32 iAdvance
= dsb
->wfx
.nBlockAlign
;
1619 INT32 oAdvance
= primarybuf
->wfx
.nBlockAlign
;
1621 ibp
= dsb
->buffer
+ dsb
->playpos
;
1624 TRACE(dsound
, "(%p, %p, %p), playpos=%8.8lx\n", dsb
, ibp
, obp
, dsb
->playpos
);
1625 // Check for the best case
1626 if ((dsb
->freq
== primarybuf
->wfx
.nSamplesPerSec
) &&
1627 (dsb
->wfx
.wBitsPerSample
== primarybuf
->wfx
.wBitsPerSample
) &&
1628 (dsb
->wfx
.nChannels
== primarybuf
->wfx
.nChannels
)) {
1629 TRACE(dsound
, "(%p) Best case\n", dsb
);
1630 if ((ibp
+ len
) < (BYTE
*)(dsb
->buffer
+ dsb
->buflen
))
1631 memcpy(obp
, ibp
, len
);
1633 memcpy(obp
, ibp
, dsb
->buflen
- dsb
->playpos
);
1634 memcpy(obp
+ (dsb
->buflen
- dsb
->playpos
),
1636 len
- (dsb
->buflen
- dsb
->playpos
));
1641 // Check for same sample rate
1642 if (dsb
->freq
== primarybuf
->wfx
.nSamplesPerSec
) {
1643 TRACE(dsound
, "(%p) Same sample rate %ld = primary %ld\n", dsb
,
1644 dsb
->freq
, primarybuf
->wfx
.nSamplesPerSec
);
1646 for (i
= 0; i
< len
; i
+= oAdvance
) {
1647 get_fields(dsb
, ibp
, &fieldL
, &fieldR
);
1650 set_fields(obp
, fieldL
, fieldR
);
1652 if (ibp
>= (BYTE
*)(dsb
->buffer
+ dsb
->buflen
))
1653 ibp
= dsb
->buffer
; // wrap
1658 // Mix in different sample rates
1660 // New PerfectPitch(tm) Technology (c) 1998 Rob Riggs
1661 // Patent Pending :-]
1663 TRACE(dsound
, "(%p) Adjusting frequency: %ld -> %ld\n",
1664 dsb
, dsb
->freq
, primarybuf
->wfx
.nSamplesPerSec
);
1666 size
= len
/ oAdvance
;
1667 ilen
= ((size
* dsb
->freqAdjust
) >> DSOUND_FREQSHIFT
) * iAdvance
;
1668 for (i
= 0; i
< size
; i
++) {
1670 ipos
= (((i
* dsb
->freqAdjust
) >> DSOUND_FREQSHIFT
) * iAdvance
) + dsb
->playpos
;
1672 if (ipos
>= dsb
->buflen
)
1673 ipos
%= dsb
->buflen
; // wrap
1675 get_fields(dsb
, (dsb
->buffer
+ ipos
), &fieldL
, &fieldR
);
1676 set_fields(obp
, fieldL
, fieldR
);
1682 static void DSOUND_MixerVol(IDirectSoundBuffer
*dsb
, BYTE
*buf
, INT32 len
)
1684 INT32 i
, inc
= primarybuf
->wfx
.wBitsPerSample
>> 3;
1686 INT16
*bps
= (INT16
*) buf
;
1688 TRACE(dsound
, "(%p) left = %lx, right = %lx\n", dsb
,
1689 dsb
->lVolAdjust
, dsb
->rVolAdjust
);
1690 if ((!(dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLPAN
) || (dsb
->pan
== 0)) &&
1691 (!(dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLVOLUME
) || (dsb
->volume
== 0)) &&
1692 !(dsb
->dsbd
.dwFlags
& DSBCAPS_CTRL3D
))
1693 return; // Nothing to do
1695 // If we end up with some bozo coder using panning or 3D sound
1696 // with a mono primary buffer, it could sound very weird using
1697 // this method. Oh well, tough patooties.
1699 for (i
= 0; i
< len
; i
+= inc
) {
1705 // 8-bit WAV is unsigned, but we need to operate
1706 // on signed data for this to work properly
1708 val
= ((val
* (i
& inc
? dsb
->rVolAdjust
: dsb
->lVolAdjust
)) >> 15);
1713 // 16-bit WAV is signed -- much better
1715 val
= ((val
* ((i
& inc
) ? dsb
->rVolAdjust
: dsb
->lVolAdjust
)) >> 15);
1721 FIXME(dsound
, "MixerVol had a nasty error\n");
1727 static void DSOUND_Mixer3D(IDirectSoundBuffer
*dsb
, BYTE
*buf
, INT32 len
)
1730 DWORD buflen
, playpos
;
1732 buflen
= dsb
->ds3db
->buflen
;
1733 playpos
= (dsb
->playpos
* primarybuf
->wfx
.nBlockAlign
) / dsb
->wfx
.nBlockAlign
;
1734 ibp
= dsb
->ds3db
->buffer
+ playpos
;
1737 if (playpos
> buflen
) {
1738 FIXME(dsound
, "Major breakage");
1742 if (len
<= (playpos
+ buflen
))
1743 memcpy(obp
, ibp
, len
);
1745 memcpy(obp
, ibp
, buflen
- playpos
);
1746 memcpy(obp
+ (buflen
- playpos
),
1748 len
- (buflen
- playpos
));
1754 static DWORD
DSOUND_MixInBuffer(IDirectSoundBuffer
*dsb
)
1756 INT32 i
, len
, ilen
, temp
, field
;
1757 INT32 advance
= primarybuf
->wfx
.wBitsPerSample
>> 3;
1758 BYTE
*buf
, *ibuf
, *obuf
;
1759 INT16
*ibufs
, *obufs
;
1761 len
= DSOUND_FRAGLEN
; // The most we will use
1762 if (!(dsb
->playflags
& DSBPLAY_LOOPING
)) {
1763 temp
= ((primarybuf
->wfx
.nAvgBytesPerSec
* dsb
->buflen
) /
1764 dsb
->nAvgBytesPerSec
) -
1765 ((primarybuf
->wfx
.nAvgBytesPerSec
* dsb
->playpos
) /
1766 dsb
->nAvgBytesPerSec
);
1767 len
= (len
> temp
) ? temp
: len
;
1769 len
&= ~3; // 4 byte alignment
1772 // This should only happen if we aren't looping and temp < 4
1774 // We skip the remainder, so check for possible events
1775 DSOUND_CheckEvent(dsb
, dsb
->buflen
- dsb
->playpos
);
1780 // Check for DSBPN_OFFSETSTOP
1781 DSOUND_CheckEvent(dsb
, 0);
1785 // Been seeing segfaults in malloc() for some reason...
1786 TRACE(dsound
, "allocating buffer (size = %d)\n", len
);
1787 if ((buf
= ibuf
= (BYTE
*) malloc(len
)) == NULL
)
1790 TRACE(dsound
, "MixInBuffer (%p) len = %d\n", dsb
, len
);
1792 ilen
= DSOUND_MixerNorm(dsb
, ibuf
, len
);
1793 if ((dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLPAN
) ||
1794 (dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLVOLUME
))
1795 DSOUND_MixerVol(dsb
, ibuf
, len
);
1797 obuf
= primarybuf
->buffer
+ primarybuf
->playpos
;
1798 for (i
= 0; i
< len
; i
+= advance
) {
1799 obufs
= (INT16
*) obuf
;
1800 ibufs
= (INT16
*) ibuf
;
1801 if (primarybuf
->wfx
.wBitsPerSample
== 8) {
1802 // 8-bit WAV is unsigned
1803 field
= (*ibuf
- 128);
1804 field
+= (*obuf
- 128);
1805 field
= field
> 127 ? 127 : field
;
1806 field
= field
< -128 ? -128 : field
;
1807 *obuf
= field
+ 128;
1809 // 16-bit WAV is signed
1812 field
= field
> 32767 ? 32767 : field
;
1813 field
= field
< -32768 ? -32768 : field
;
1818 if (obuf
>= (BYTE
*)(primarybuf
->buffer
+ primarybuf
->buflen
))
1819 obuf
= primarybuf
->buffer
;
1823 if (dsb
->dsbd
.dwFlags
& DSBCAPS_CTRLPOSITIONNOTIFY
)
1824 DSOUND_CheckEvent(dsb
, ilen
);
1826 dsb
->playpos
+= ilen
;
1827 dsb
->writepos
= dsb
->playpos
+ ilen
;
1829 if (dsb
->playpos
>= dsb
->buflen
) {
1830 if (!(dsb
->playflags
& DSBPLAY_LOOPING
)) {
1834 DSOUND_CheckEvent(dsb
, 0); // For DSBPN_OFFSETSTOP
1836 dsb
->playpos
%= dsb
->buflen
; // wrap
1839 if (dsb
->writepos
>= dsb
->buflen
)
1840 dsb
->writepos
%= dsb
->buflen
;
1845 static DWORD WINAPI
DSOUND_MixPrimary(void)
1847 INT32 i
, len
, maxlen
= 0;
1848 IDirectSoundBuffer
*dsb
;
1850 for (i
= dsound
->nrofbuffers
- 1; i
>= 0; i
--) {
1851 dsb
= dsound
->buffers
[i
];
1853 if (!dsb
|| !(dsb
->lpvtbl
))
1855 dsb
->lpvtbl
->fnAddRef(dsb
);
1856 if (dsb
->buflen
&& dsb
->playing
) {
1857 EnterCriticalSection(&(dsb
->lock
));
1858 len
= DSOUND_MixInBuffer(dsb
);
1859 maxlen
= len
> maxlen
? len
: maxlen
;
1860 LeaveCriticalSection(&(dsb
->lock
));
1862 dsb
->lpvtbl
->fnRelease(dsb
);
1868 static int DSOUND_OpenAudio(void)
1872 if (primarybuf
== NULL
)
1873 return DSERR_OUTOFMEMORY
;
1875 while (audiofd
!= -1)
1877 audiofd
= open("/dev/audio",O_WRONLY
);
1879 // Don't worry if sound is busy at the moment
1881 perror("open /dev/audio");
1882 return audiofd
; // -1
1885 // We should probably do something here if SETFRAGMENT fails...
1886 audioFragment
=0x0002000c;
1887 if (-1==ioctl(audiofd
,SNDCTL_DSP_SETFRAGMENT
,&audioFragment
))
1888 perror("ioctl SETFRAGMENT");
1891 DSOUND_setformat(&(primarybuf
->wfx
));
1896 static void DSOUND_CloseAudio(void)
1900 neutral
= primarybuf
->wfx
.wBitsPerSample
== 8 ? 128 : 0;
1901 audioOK
= 0; // race condition
1903 // It's possible we've been called with audio closed
1904 // from SetFormat()... this is just to force a call
1905 // to OpenAudio() to reset the hardware properly
1908 primarybuf
->playpos
= 0;
1909 primarybuf
->writepos
= DSOUND_FRAGLEN
;
1910 memset(primarybuf
->buffer
, neutral
, primarybuf
->buflen
);
1912 TRACE(dsound
, "Audio stopped\n");
1915 static int DSOUND_WriteAudio(char *buf
, int len
)
1917 int result
, left
= 0;
1919 while (left
< len
) {
1920 result
= write(audiofd
, buf
+ left
, len
- left
);
1931 static void DSOUND_OutputPrimary(int len
)
1933 int neutral
, flen1
, flen2
;
1934 char *frag1
, *frag2
;
1936 // This is a bad place for this. We need to clear the
1937 // buffer with a neutral value, for unsigned 8-bit WAVE
1938 // that's 128, for signed 16-bit it's 0
1939 neutral
= primarybuf
->wfx
.wBitsPerSample
== 8 ? 128 : 0;
1942 EnterCriticalSection(&(primarybuf
->lock
));
1945 if ((audioOK
== 1) || (DSOUND_OpenAudio() == 0)) {
1946 if (primarybuf
->playpos
+ len
>= primarybuf
->buflen
) {
1947 frag1
= primarybuf
->buffer
+ primarybuf
->playpos
;
1948 flen1
= primarybuf
->buflen
- primarybuf
->playpos
;
1949 frag2
= primarybuf
->buffer
;
1950 flen2
= len
- (primarybuf
->buflen
- primarybuf
->playpos
);
1951 if (DSOUND_WriteAudio(frag1
, flen1
) != 0) {
1952 perror("DSOUND_WriteAudio");
1953 LeaveCriticalSection(&(primarybuf
->lock
));
1956 memset(frag1
, neutral
, flen1
);
1957 if (DSOUND_WriteAudio(frag2
, flen2
) != 0) {
1958 perror("DSOUND_WriteAudio");
1959 LeaveCriticalSection(&(primarybuf
->lock
));
1962 memset(frag2
, neutral
, flen2
);
1964 frag1
= primarybuf
->buffer
+ primarybuf
->playpos
;
1966 if (DSOUND_WriteAudio(frag1
, flen1
) != 0) {
1967 perror("DSOUND_WriteAudio");
1968 LeaveCriticalSection(&(primarybuf
->lock
));
1971 memset(frag1
, neutral
, flen1
);
1974 // Can't play audio at the moment -- we need to sleep
1975 // to make up for the time we'd be blocked in write()
1979 primarybuf
->playpos
+= len
;
1980 if (primarybuf
->playpos
>= primarybuf
->buflen
)
1981 primarybuf
->playpos
%= primarybuf
->buflen
;
1982 primarybuf
->writepos
= primarybuf
->playpos
+ DSOUND_FRAGLEN
;
1983 if (primarybuf
->writepos
>= primarybuf
->buflen
)
1984 primarybuf
->writepos
%= primarybuf
->buflen
;
1986 LeaveCriticalSection(&(primarybuf
->lock
));
1990 static DWORD WINAPI
DSOUND_thread(LPVOID arg
)
1994 TRACE(dsound
,"dsound is at pid %d\n",getpid());
1997 WARN(dsound
,"DSOUND thread giving up.\n");
2001 WARN(dsound
,"DSOUND father died? Giving up.\n");
2004 /* RACE: dsound could be deleted */
2005 dsound
->lpvtbl
->fnAddRef(dsound
);
2006 if (primarybuf
== NULL
) {
2007 // Should never happen
2008 WARN(dsound
, "Lost the primary buffer!\n");
2009 dsound
->lpvtbl
->fnRelease(dsound
);
2014 EnterCriticalSection(&(primarybuf
->lock
));
2015 len
= DSOUND_MixPrimary();
2016 LeaveCriticalSection(&(primarybuf
->lock
));
2019 if (primarybuf
->playing
)
2020 len
= DSOUND_FRAGLEN
> len
? DSOUND_FRAGLEN
: len
;
2022 // This does all the work
2023 DSOUND_OutputPrimary(len
);
2025 // no buffers playing -- close and wait
2027 DSOUND_CloseAudio();
2030 dsound
->lpvtbl
->fnRelease(dsound
);
2035 #endif /* HAVE_OSS */
2037 HRESULT WINAPI
DirectSoundCreate(LPGUID lpGUID
,LPDIRECTSOUND
*ppDS
,IUnknown
*pUnkOuter
)
2040 TRACE(dsound
,"(%p,%p,%p)\n",lpGUID
,ppDS
,pUnkOuter
);
2042 TRACE(dsound
,"DirectSoundCreate (%p)\n", ppDS
);
2047 return DSERR_INVALIDPARAM
;
2050 dsound
->lpvtbl
->fnAddRef(dsound
);
2055 // Check that we actually have audio capabilities
2056 // If we do, whether it's busy or not, we continue
2057 // otherwise we return with DSERR_NODRIVER
2059 audiofd
= open("/dev/audio",O_WRONLY
);
2060 if (audiofd
== -1) {
2061 if (errno
== ENODEV
) {
2062 TRACE(dsound
, "No sound hardware\n");
2063 return DSERR_NODRIVER
;
2064 } else if (errno
== EBUSY
) {
2065 TRACE(dsound
, "Sound device busy, will keep trying\n");
2067 TRACE(dsound
, "Unexpected error while checking for sound support\n");
2068 return DSERR_GENERIC
;
2075 *ppDS
= (LPDIRECTSOUND
)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSound
));
2077 return DSERR_OUTOFMEMORY
;
2080 (*ppDS
)->lpvtbl
= &dsvt
;
2081 (*ppDS
)->buffers
= NULL
;
2082 (*ppDS
)->nrofbuffers
= 0;
2084 (*ppDS
)->wfx
.wFormatTag
= 1;
2085 (*ppDS
)->wfx
.nChannels
= 2;
2086 (*ppDS
)->wfx
.nSamplesPerSec
= 22050;
2087 (*ppDS
)->wfx
.nAvgBytesPerSec
= 44100;
2088 (*ppDS
)->wfx
.nBlockAlign
= 2;
2089 (*ppDS
)->wfx
.wBitsPerSample
= 8;
2096 if (primarybuf
== NULL
) {
2100 dsbd
.dwSize
= sizeof(DSBUFFERDESC
);
2101 dsbd
.dwFlags
= DSBCAPS_PRIMARYBUFFER
;
2102 dsbd
.dwBufferBytes
= 0;
2103 dsbd
.lpwfxFormat
= &(dsound
->wfx
);
2104 hr
= IDirectSound_CreateSoundBuffer(*ppDS
, &dsbd
, &primarybuf
, NULL
);
2107 dsound
->primary
= primarybuf
;
2109 memset(primarybuf
->buffer
, 128, primarybuf
->buflen
);
2110 hnd
= CreateThread(NULL
,0,DSOUND_thread
,0,0,&xid
);
2114 MessageBox32A(0,"DirectSound needs the Open Sound System Driver, which has not been found by ./configure.","WINE DirectSound",MB_OK
|MB_ICONSTOP
);
2115 return DSERR_NODRIVER
;
2119 /*******************************************************************************
2120 * DirectSound ClassFactory
2122 static HRESULT WINAPI
2123 DSCF_QueryInterface(LPCLASSFACTORY
this,REFIID riid
,LPVOID
*ppobj
) {
2127 WINE_StringFromCLSID(riid
,buf
);
2129 sprintf(buf
,"<guid-0x%04x>",LOWORD(riid
));
2130 FIXME(dsound
,"(%p)->(%s,%p),stub!\n",this,buf
,ppobj
);
2131 return E_NOINTERFACE
;
2135 DSCF_AddRef(LPCLASSFACTORY
this) {
2136 return ++(this->ref
);
2139 static ULONG WINAPI
DSCF_Release(LPCLASSFACTORY
this) {
2140 /* static class, won't be freed */
2141 return --(this->ref
);
2144 static HRESULT WINAPI
DSCF_CreateInstance(
2145 LPCLASSFACTORY
this,LPUNKNOWN pOuter
,REFIID riid
,LPVOID
*ppobj
2149 WINE_StringFromCLSID(riid
,buf
);
2150 TRACE(dsound
,"(%p)->(%p,%s,%p)\n",this,pOuter
,buf
,ppobj
);
2151 if (!memcmp(riid
,&IID_IDirectSound
,sizeof(IID_IDirectSound
))) {
2152 /* FIXME: reuse already created dsound if present? */
2153 return DirectSoundCreate(riid
,(LPDIRECTSOUND
*)ppobj
,pOuter
);
2155 return E_NOINTERFACE
;
2158 static HRESULT WINAPI
DSCF_LockServer(LPCLASSFACTORY
this,BOOL32 dolock
) {
2159 FIXME(dsound
,"(%p)->(%d),stub!\n",this,dolock
);
2163 static IClassFactory_VTable DSCF_VTable
= {
2164 DSCF_QueryInterface
,
2167 DSCF_CreateInstance
,
2170 static IClassFactory DSOUND_CF
= {&DSCF_VTable
, 1 };
2172 /*******************************************************************************
2173 * DllGetClassObject [DSOUND.4]
2174 * Retrieves class object from a DLL object
2177 * Docs say returns STDAPI
2180 * rclsid [I] CLSID for the class object
2181 * riid [I] Reference to identifier of interface for class object
2182 * ppv [O] Address of variable to receive interface pointer for riid
2186 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
2189 DWORD WINAPI
DSOUND_DllGetClassObject(REFCLSID rclsid
,REFIID riid
,LPVOID
*ppv
)
2191 char buf
[80],xbuf
[80];
2194 WINE_StringFromCLSID(rclsid
,xbuf
);
2196 sprintf(xbuf
,"<guid-0x%04x>",LOWORD(rclsid
));
2198 WINE_StringFromCLSID(riid
,buf
);
2200 sprintf(buf
,"<guid-0x%04x>",LOWORD(riid
));
2201 WINE_StringFromCLSID(riid
,xbuf
);
2202 TRACE(dsound
, "(%p,%p,%p)\n", xbuf
, buf
, ppv
);
2203 if (!memcmp(riid
,&IID_IClassFactory
,sizeof(IID_IClassFactory
))) {
2204 *ppv
= (LPVOID
)&DSOUND_CF
;
2205 DSOUND_CF
.lpvtbl
->fnAddRef(&DSOUND_CF
);
2208 FIXME(dsound
, "(%p,%p,%p): no interface found.\n", xbuf
, buf
, ppv
);
2209 return E_NOINTERFACE
;
2213 /*******************************************************************************
2214 * DllCanUnloadNow [DSOUND.3] Determines whether the DLL is in use.
2220 DWORD WINAPI
DSOUND_DllCanUnloadNow(void)
2222 FIXME(dsound
, "(void): stub\n");