3 * Copyright 1998 Marcus Meissner
6 * Note: This file requires multithread ability. It is not possible to
7 * implement the stuff in a single thread anyway. And most DirectX apps
8 * require threading themselves.
10 * FIXME: This file is full of race conditions and unlocked variable access
11 * from two threads. But we usually don't need to bother.
13 * Tested with a Soundblaster clone and a Gravis UltraSound Classic.
16 * - Wing Commander 4/W95:
17 * The intromovie plays without problems. Nearly lipsynchron.
19 * The sound works, but noticeable chunks are left out (from the sound and
20 * the animation). Don't know why yet.
22 * Sound works, but slows down the movieplayer.
26 * The background sound of the startscreen works ;)
27 * - WingCommander Prophecy Demo:
28 * Sound works for the intromovie.
34 #include <sys/types.h>
36 #include <sys/fcntl.h>
40 #include <math.h> /* Insomnia - pow() function */
43 #include "interfaces.h"
50 # include <sys/ioctl.h>
51 # ifdef HAVE_MACHINE_SOUNDCARD_H
52 # include <machine/soundcard.h>
54 # ifdef HAVE_SYS_SOUNDCARD_H
55 # include <sys/soundcard.h>
58 static int audiofd
= -1;
59 static LPDIRECTSOUND dsound
= NULL
;
61 static short playbuf
[2048];
65 HRESULT WINAPI
DirectSoundEnumerate32A(LPDSENUMCALLBACK32A enumcb
,LPVOID context
) {
67 enumcb(NULL
,"WINE DirectSound using Open Sound System","sound",context
);
73 static void _dump_DSBCAPS(DWORD xmask
) {
78 #define FE(x) { x, #x },
79 FE(DSBCAPS_PRIMARYBUFFER
)
81 FE(DSBCAPS_LOCHARDWARE
)
82 FE(DSBCAPS_LOCSOFTWARE
)
83 FE(DSBCAPS_CTRLFREQUENCY
)
85 FE(DSBCAPS_CTRLVOLUME
)
86 FE(DSBCAPS_CTRLDEFAULT
)
88 FE(DSBCAPS_STICKYFOCUS
)
89 FE(DSBCAPS_GETCURRENTPOSITION2
)
93 for (i
=0;i
<sizeof(flags
)/sizeof(flags
[0]);i
++)
94 if (flags
[i
].mask
& xmask
)
95 fprintf(stderr
,"%s ",flags
[i
].name
);
98 /*******************************************************************************
101 static HRESULT WINAPI
IDirectSoundNotify_QueryInterface(
102 LPDIRECTSOUNDNOTIFY
this,REFIID riid
,LPVOID
*ppobj
106 WINE_StringFromCLSID(riid
,xbuf
);
107 TRACE(dsound
,"(%p,%s,%p)\n",this,xbuf
,ppobj
);
111 static ULONG WINAPI
IDirectSoundNotify_AddRef(LPDIRECTSOUNDNOTIFY
this) {
112 return ++(this->ref
);
115 static ULONG WINAPI
IDirectSoundNotify_Release(LPDIRECTSOUNDNOTIFY
this) {
118 this->dsb
->lpvtbl
->fnRelease(this->dsb
);
119 HeapFree(GetProcessHeap(),0,this);
125 static int _sort_notifies(const void *a
,const void *b
) {
126 LPDSBPOSITIONNOTIFY na
= (LPDSBPOSITIONNOTIFY
)a
;
127 LPDSBPOSITIONNOTIFY nb
= (LPDSBPOSITIONNOTIFY
)b
;
129 return na
->dwOffset
-nb
->dwOffset
;
132 static HRESULT WINAPI
IDirectSoundNotify_SetNotificationPositions(
133 LPDIRECTSOUNDNOTIFY
this,DWORD howmuch
,LPCDSBPOSITIONNOTIFY notify
137 if (TRACE_ON(dsound
)) {
138 TRACE(dsound
,"(%p,0x%08lx,%p)\n",this,howmuch
,notify
);
139 for (i
=0;i
<howmuch
;i
++)
140 TRACE(dsound
,"notify at %ld to 0x%08lx\n",
141 notify
[i
].dwOffset
,(DWORD
)notify
[i
].hEventNotify
);
143 this->dsb
->notifies
= HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,this->dsb
->notifies
,(this->dsb
->nrofnotifies
+howmuch
)*sizeof(DSBPOSITIONNOTIFY
));
144 memcpy( this->dsb
->notifies
+this->dsb
->nrofnotifies
,
146 howmuch
*sizeof(DSBPOSITIONNOTIFY
)
148 this->dsb
->nrofnotifies
+=howmuch
;
149 qsort(this->dsb
->notifies
,this->dsb
->nrofnotifies
,sizeof(DSBPOSITIONNOTIFY
),_sort_notifies
);
153 IDirectSoundNotify_VTable dsnvt
= {
154 IDirectSoundNotify_QueryInterface
,
155 IDirectSoundNotify_AddRef
,
156 IDirectSoundNotify_Release
,
157 IDirectSoundNotify_SetNotificationPositions
,
160 /*******************************************************************************
163 static HRESULT WINAPI
IDirectSoundBuffer_SetFormat(
164 LPDIRECTSOUNDBUFFER
this,LPWAVEFORMATEX wfex
167 memcpy(&(this->wfx
),wfex
,sizeof(this->wfx
));
168 TRACE(dsound
,"(%p,%p)\n", this,wfex
);
169 TRACE(dsound
,"(formattag=0x%04x,chans=%d,samplerate=%ld"
170 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
171 wfex
->wFormatTag
, wfex
->nChannels
, wfex
->nSamplesPerSec
,
172 wfex
->nAvgBytesPerSec
, wfex
->nBlockAlign
,
173 wfex
->wBitsPerSample
, wfex
->cbSize
);
178 static HRESULT WINAPI
IDirectSoundBuffer_SetVolume(
179 LPDIRECTSOUNDBUFFER
this,LONG vol
181 TRACE(dsound
,"(%p,%ld)\n",this,vol
);
183 this->volfac
= ((double)vol
+10000.0)/10000.0;
188 static HRESULT WINAPI
IDirectSoundBuffer_GetVolume(
189 LPDIRECTSOUNDBUFFER
this,LPLONG vol
191 TRACE(dsound
,"(%p,%p)\n",this,vol
);
196 static HRESULT WINAPI
IDirectSoundBuffer_SetFrequency(
197 LPDIRECTSOUNDBUFFER
this,DWORD freq
199 TRACE(dsound
,"(%p,%ld)\n",this,freq
);
200 this->wfx
.nSamplesPerSec
= freq
;
201 this->wfx
.nAvgBytesPerSec
= freq
*this->wfx
.nChannels
*(this->wfx
.wBitsPerSample
/8);
205 static HRESULT WINAPI
IDirectSoundBuffer_Play(
206 LPDIRECTSOUNDBUFFER
this,DWORD reserved1
,DWORD reserved2
,DWORD flags
208 TRACE(dsound
,"(%p,%08lx,%08lx,%08lx)\n",
209 this,reserved1
,reserved2
,flags
212 this->playflags
= flags
;
217 static HRESULT WINAPI
IDirectSoundBuffer_Stop(LPDIRECTSOUNDBUFFER
this) {
218 TRACE(dsound
,"(%p)\n",this);
220 this->writepos
= 0; /* hmm */
224 static DWORD WINAPI
IDirectSoundBuffer_AddRef(LPDIRECTSOUNDBUFFER
this) {
225 return ++(this->ref
);
227 static DWORD WINAPI
IDirectSoundBuffer_Release(LPDIRECTSOUNDBUFFER
this) {
232 for (i
=0;i
<this->dsound
->nrofbuffers
;i
++)
233 if (this->dsound
->buffers
[i
] == this)
235 if (i
< this->dsound
->nrofbuffers
) {
237 this->dsound
->buffers
+i
,
238 this->dsound
->buffers
+i
+1,
239 sizeof(LPDIRECTSOUNDBUFFER
)*(this->dsound
->nrofbuffers
-i
-1)
241 this->dsound
->buffers
= HeapReAlloc(GetProcessHeap(),0,this->dsound
->buffers
,sizeof(LPDIRECTSOUNDBUFFER
)*this->dsound
->nrofbuffers
);
242 this->dsound
->nrofbuffers
--;
243 this->dsound
->lpvtbl
->fnRelease(this->dsound
);
245 HeapFree(GetProcessHeap(),0,this->buffer
);
246 HeapFree(GetProcessHeap(),0,this);
250 static HRESULT WINAPI
IDirectSoundBuffer_GetCurrentPosition(
251 LPDIRECTSOUNDBUFFER
this,LPDWORD playpos
,LPDWORD writepos
253 TRACE(dsound
,"(%p,%p,%p)\n",this,playpos
,writepos
);
254 if (playpos
) *playpos
= this->playpos
;
255 if (writepos
) *writepos
= this->writepos
;
259 static HRESULT WINAPI
IDirectSoundBuffer_GetStatus(
260 LPDIRECTSOUNDBUFFER
this,LPDWORD status
262 TRACE(dsound
,"(%p,%p)\n",this,status
);
265 *status
|= DSBSTATUS_PLAYING
;
266 if (this->playflags
& DSBPLAY_LOOPING
)
267 *status
|= DSBSTATUS_LOOPING
;
271 static HRESULT WINAPI
IDirectSoundBuffer_GetFormat(
272 LPDIRECTSOUNDBUFFER
this,LPWAVEFORMATEX lpwf
,DWORD wfsize
,LPDWORD wfwritten
274 TRACE(dsound
,"(%p,%p,%ld,%p)\n",this,lpwf
,wfsize
,wfwritten
);
275 if (wfsize
>sizeof(this->wfx
)) wfsize
= sizeof(this->wfx
);
276 memcpy(lpwf
,&(this->wfx
),wfsize
);
277 if (wfwritten
) *wfwritten
= wfsize
;
281 static HRESULT WINAPI
IDirectSoundBuffer_Lock(
282 LPDIRECTSOUNDBUFFER
this,DWORD writecursor
,DWORD writebytes
,LPVOID lplpaudioptr1
,LPDWORD audiobytes1
,LPVOID lplpaudioptr2
,LPDWORD audiobytes2
,DWORD flags
285 TRACE(dsound
,"(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx)\n",
295 if (flags
& DSBLOCK_FROMWRITECURSOR
)
296 writecursor
= this->writepos
;
297 assert(audiobytes1
!=audiobytes2
);
298 assert(lplpaudioptr1
!=lplpaudioptr2
);
299 if (writecursor
+writebytes
<= this->buflen
) {
300 *(LPBYTE
*)lplpaudioptr1
= this->buffer
+writecursor
;
301 *audiobytes1
= writebytes
;
303 *(LPBYTE
*)lplpaudioptr2
= NULL
;
306 TRACE(dsound
,"->%ld.0\n",writebytes
);
308 *(LPBYTE
*)lplpaudioptr1
= this->buffer
+writecursor
;
309 *audiobytes1
= this->buflen
-writecursor
;
311 *(LPBYTE
*)lplpaudioptr2
= this->buffer
;
313 *audiobytes2
= writebytes
-(this->buflen
-writecursor
);
314 TRACE(dsound
,"->%ld.%ld\n",*audiobytes1
,audiobytes2
?*audiobytes2
:0);
316 this->writepos
=(writecursor
+writebytes
)%this->buflen
;
320 static HRESULT WINAPI
IDirectSoundBuffer_SetCurrentPosition(
321 LPDIRECTSOUNDBUFFER
this,DWORD newpos
323 TRACE(dsound
,"(%p,%ld)\n",this,newpos
);
324 this->playpos
= newpos
;
328 static HRESULT WINAPI
IDirectSoundBuffer_SetPan(
329 LPDIRECTSOUNDBUFFER
this,LONG newpan
331 TRACE(dsound
,"(%p,%ld)\n",this,newpan
);
336 static HRESULT WINAPI
IDirectSoundBuffer_GetPan(
337 LPDIRECTSOUNDBUFFER
this,LPLONG pan
339 TRACE(dsound
,"(%p,%p)\n",this,pan
);
344 static HRESULT WINAPI
IDirectSoundBuffer_Unlock(
345 LPDIRECTSOUNDBUFFER
this,LPVOID p1
,DWORD x1
,LPVOID p2
,DWORD x2
347 /* FIXME(dsound,"(%p,%p,%ld,%p,%ld):stub\n", this,p1,x1,p2,x2); */
351 static HRESULT WINAPI
IDirectSoundBuffer_GetFrequency(
352 LPDIRECTSOUNDBUFFER
this,LPDWORD freq
354 TRACE(dsound
,"(%p,%p)\n",this,freq
);
355 *freq
= this->wfx
.nSamplesPerSec
;
359 static HRESULT WINAPI
IDirectSoundBuffer_Initialize(
360 LPDIRECTSOUNDBUFFER
this,LPDIRECTSOUND dsound
,LPDSBUFFERDESC dbsd
362 FIXME(dsound
,"(%p,%p,%p):stub\n",this,dsound
,dbsd
);
363 printf("Re-Init!!!\n");
364 return DSERR_ALREADYINITIALIZED
;
367 static HRESULT WINAPI
IDirectSoundBuffer_GetCaps(
368 LPDIRECTSOUNDBUFFER
this,LPDSBCAPS caps
370 caps
->dwSize
= sizeof(*caps
);
371 caps
->dwFlags
= DSBCAPS_PRIMARYBUFFER
|DSBCAPS_STATIC
|DSBCAPS_CTRLALL
|DSBCAPS_LOCSOFTWARE
;
372 caps
->dwBufferBytes
= 65536;
373 caps
->dwUnlockTransferRate
= 0;
374 caps
->dwPlayCpuOverhead
= 0;
378 static HRESULT WINAPI
IDirectSoundBuffer_QueryInterface(
379 LPDIRECTSOUNDBUFFER
this,REFIID riid
,LPVOID
*ppobj
383 if (!memcmp(&IID_IDirectSoundNotify
,riid
,sizeof(*riid
))) {
384 IDirectSoundNotify
*dsn
;
386 dsn
= (LPDIRECTSOUNDNOTIFY
)HeapAlloc(GetProcessHeap(),0,sizeof(*dsn
));
389 this->lpvtbl
->fnAddRef(this);
390 dsn
->lpvtbl
= &dsnvt
;
391 *ppobj
= (LPVOID
)dsn
;
394 WINE_StringFromCLSID(riid
,xbuf
);
395 TRACE(dsound
,"(%p,%s,%p)\n",this,xbuf
,ppobj
);
399 static struct tagLPDIRECTSOUNDBUFFER_VTABLE dsbvt
= {
400 IDirectSoundBuffer_QueryInterface
,
401 IDirectSoundBuffer_AddRef
,
402 IDirectSoundBuffer_Release
,
403 IDirectSoundBuffer_GetCaps
,
404 IDirectSoundBuffer_GetCurrentPosition
,
405 IDirectSoundBuffer_GetFormat
,
406 IDirectSoundBuffer_GetVolume
,
407 IDirectSoundBuffer_GetPan
,
408 IDirectSoundBuffer_GetFrequency
,
409 IDirectSoundBuffer_GetStatus
,
410 IDirectSoundBuffer_Initialize
,
411 IDirectSoundBuffer_Lock
,
412 IDirectSoundBuffer_Play
,
413 IDirectSoundBuffer_SetCurrentPosition
,
414 IDirectSoundBuffer_SetFormat
,
415 IDirectSoundBuffer_SetVolume
,
416 IDirectSoundBuffer_SetPan
,
417 IDirectSoundBuffer_SetFrequency
,
418 IDirectSoundBuffer_Stop
,
419 IDirectSoundBuffer_Unlock
422 /*******************************************************************************
426 static HRESULT WINAPI
IDirectSound_SetCooperativeLevel(
427 LPDIRECTSOUND
this,HWND32 hwnd
,DWORD level
429 FIXME(dsound
,"(%p,%08lx,%ld):stub\n",this,(DWORD
)hwnd
,level
);
434 static HRESULT WINAPI
IDirectSound_CreateSoundBuffer(
435 LPDIRECTSOUND
this,LPDSBUFFERDESC dsbd
,LPLPDIRECTSOUNDBUFFER ppdsb
,LPUNKNOWN lpunk
437 if (TRACE_ON(dsound
)) {
438 TRACE(dsound
,"(%p,%p,%p,%p)\n",this,dsbd
,ppdsb
,lpunk
);
439 TRACE(dsound
,"(size=%ld)\n",dsbd
->dwSize
);
440 TRACE(dsound
,"(flags=0x%08lx\n",dsbd
->dwFlags
);
441 _dump_DSBCAPS(dsbd
->dwFlags
);
442 TRACE(dsound
,"(bufferbytes=%ld)\n",dsbd
->dwBufferBytes
);
443 TRACE(dsound
,"(lpwfxFormat=%p)\n",dsbd
->lpwfxFormat
);
445 *ppdsb
= (LPDIRECTSOUNDBUFFER
)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDirectSoundBuffer
));
447 (*ppdsb
)->buffer
= (LPBYTE
)HeapAlloc(GetProcessHeap(),0,dsbd
->dwBufferBytes
);
448 (*ppdsb
)->buflen
= dsbd
->dwBufferBytes
;
449 (*ppdsb
)->playpos
= 0;
450 (*ppdsb
)->writepos
= 0;
451 (*ppdsb
)->lpvtbl
= &dsbvt
;
452 (*ppdsb
)->dsound
= this;
453 (*ppdsb
)->playing
= 0;
454 (*ppdsb
)->volfac
= 1.0;
455 memcpy(&((*ppdsb
)->dsbd
),dsbd
,sizeof(*dsbd
));
457 /* register buffer */
458 this->buffers
= (LPDIRECTSOUNDBUFFER
*)HeapReAlloc(GetProcessHeap(),0,this->buffers
,sizeof(LPDIRECTSOUNDBUFFER
)*(this->nrofbuffers
+1));
459 this->buffers
[this->nrofbuffers
] = *ppdsb
;
461 this->lpvtbl
->fnAddRef(this);
463 if (dsbd
->lpwfxFormat
) dsbvt
.fnSetFormat(*ppdsb
,dsbd
->lpwfxFormat
);
467 static HRESULT WINAPI
IDirectSound_DuplicateSoundBuffer(
468 LPDIRECTSOUND
this,LPDIRECTSOUNDBUFFER pdsb
,LPLPDIRECTSOUNDBUFFER ppdsb
470 TRACE(dsound
,"(%p,%p,%p)\n",this,pdsb
,ppdsb
);
472 *ppdsb
= (LPDIRECTSOUNDBUFFER
)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(IDirectSoundBuffer
));
474 (*ppdsb
)->buffer
= (LPBYTE
)HeapAlloc(GetProcessHeap(),0,pdsb
->buflen
);
475 memcpy((*ppdsb
)->buffer
,pdsb
->buffer
,pdsb
->buflen
);
476 (*ppdsb
)->buflen
= pdsb
->buflen
;
477 (*ppdsb
)->playpos
= 0;
478 (*ppdsb
)->writepos
= 0;
479 (*ppdsb
)->lpvtbl
= &dsbvt
;
480 (*ppdsb
)->dsound
= this;
481 dsbvt
.fnSetFormat(*ppdsb
,&(pdsb
->wfx
));
482 /* register buffer */
483 this->buffers
= (LPDIRECTSOUNDBUFFER
*)HeapReAlloc(GetProcessHeap(),0,this->buffers
,sizeof(LPDIRECTSOUNDBUFFER
)*(this->nrofbuffers
+1));
484 this->buffers
[this->nrofbuffers
] = *ppdsb
;
486 this->lpvtbl
->fnAddRef(this);
491 static HRESULT WINAPI
IDirectSound_GetCaps(LPDIRECTSOUND
this,LPDSCAPS caps
) {
492 TRACE(dsound
,"(%p,%p)\n",this,caps
);
493 TRACE(dsound
,"(flags=0x%08lx)\n",caps
->dwFlags
);
495 caps
->dwSize
= sizeof(*caps
);
496 caps
->dwFlags
= DSCAPS_PRIMARYSTEREO
|DSCAPS_PRIMARY16BIT
|DSCAPS_SECONDARYSTEREO
|DSCAPS_SECONDARY16BIT
;
497 /* FIXME: query OSS */
498 caps
->dwMinSecondarySampleRate
= 22050;
499 caps
->dwMaxSecondarySampleRate
= 48000;
500 caps
->dwPrimaryBuffers
= 1;
501 /* FIXME: set the rest... hmm */
505 static ULONG WINAPI
IDirectSound_AddRef(LPDIRECTSOUND
this) {
506 TRACE(dsound
,"(%p), ref was %d\n",this,this->ref
);
507 return ++(this->ref
);
510 static ULONG WINAPI
IDirectSound_Release(LPDIRECTSOUND
this) {
511 TRACE(dsound
,"(%p), ref was %d\n",this,this->ref
);
512 if (!--(this->ref
)) {
513 HeapFree(GetProcessHeap(),0,this);
515 close(audiofd
);audiofd
= -1;
521 static HRESULT WINAPI
IDirectSound_SetSpeakerConfig(
522 LPDIRECTSOUND
this,DWORD config
524 FIXME(dsound
,"(%p,0x%08lx):stub\n",this,config
);
528 static HRESULT WINAPI
IDirectSound_QueryInterface(
529 LPDIRECTSOUND
this,REFIID riid
,LPVOID
*ppobj
533 WINE_StringFromCLSID(riid
,xbuf
);
534 TRACE(dsound
,"(%p,%s,%p)\n",this,xbuf
,ppobj
);
538 static struct tagLPDIRECTSOUND_VTABLE dsvt
= {
539 IDirectSound_QueryInterface
,
541 IDirectSound_Release
,
542 IDirectSound_CreateSoundBuffer
,
543 IDirectSound_GetCaps
,
544 IDirectSound_DuplicateSoundBuffer
,
545 IDirectSound_SetCooperativeLevel
,
548 IDirectSound_SetSpeakerConfig
,
553 DSOUND_setformat(LPWAVEFORMATEX wfex
) {
554 int xx
,channels
,speed
,format
,nformat
;
557 switch (wfex
->wFormatTag
) {
559 WARN(dsound
,"unknown WAVE_FORMAT tag %d\n",wfex
->wFormatTag
);
560 return DSERR_BADFORMAT
;
561 case WAVE_FORMAT_PCM
:
564 if (wfex
->wBitsPerSample
==8)
567 format
= AFMT_S16_LE
;
569 if (-1==ioctl(audiofd
,SNDCTL_DSP_GETFMTS
,&xx
)) {
570 perror("ioctl SNDCTL_DSP_GETFMTS");
573 if ((xx
&format
)!=format
) {/* format unsupported */
574 WARN(dsound
,"SNDCTL_DSP_GETFMTS: format not supported\n");
578 if (-1==ioctl(audiofd
,SNDCTL_DSP_SETFMT
,&nformat
)) {
579 perror("ioctl SNDCTL_DSP_SETFMT");
582 if (nformat
!=format
) {/* didn't work */
583 WARN(dsound
,"SNDCTL_DSP_GETFMTS: format not set\n");
587 channels
= wfex
->nChannels
-1;
588 if (-1==ioctl(audiofd
,SNDCTL_DSP_STEREO
,&channels
)) {
589 perror("ioctl SNDCTL_DSP_STEREO");
592 speed
= wfex
->nSamplesPerSec
;
593 if (-1==ioctl(audiofd
,SNDCTL_DSP_SPEED
,&speed
)) {
594 perror("ioctl SNDCTL_DSP_SPEED");
597 TRACE(dsound
,"(freq=%ld,channels=%d,bits=%d)\n",
598 wfex
->nSamplesPerSec
,wfex
->nChannels
,wfex
->wBitsPerSample
603 static LPDSBPOSITIONNOTIFY
604 DSOUND_nextevent(IDirectSoundBuffer
*dsb
) {
607 if (dsb
->nrofnotifies
) {
608 for (i
=0;i
<dsb
->nrofnotifies
;i
++) {
609 if (dsb
->playpos
<dsb
->notifies
[i
].dwOffset
)
612 if (i
==dsb
->nrofnotifies
)
614 return dsb
->notifies
+i
;
619 #define CHECK_EVENT \
620 if (nextevent && (dsb->playpos == nextevent->dwOffset)) { \
621 SetEvent(nextevent->hEventNotify); \
622 TRACE(dsound,"signalled event %d\n",nextevent->hEventNotify);\
623 nextevent = DSOUND_nextevent(dsb); \
628 DSOUND_MixInBuffer(IDirectSoundBuffer
*dsb
) {
629 int j
,buflen
= dsb
->buflen
;
630 LPDSBPOSITIONNOTIFY nextevent
;
631 int xdiff
= dsb
->wfx
.nSamplesPerSec
-dsound
->wfx
.nSamplesPerSec
;
633 /* Insomnia - Going along with REAL author's style */
634 long Rvoldec
, Lvoldec
;
636 long samp
; /* temporary sample workspace */
639 double tmpr
=dsb
->volume
-500;
641 if(pan
>0) tmpl
-= (double)pan
;
642 else tmpr
+= (double)pan
;
645 tmpl
= pow(2.0, tmpl
);
646 tmpr
= pow(2.0, tmpr
);
647 tmpl
*= 65536; /* Set to the correct multiple times */
648 tmpr
*= 65536; /* 65536 to be convenient for bit shifting */
649 tmpl
+= 0.5; /* Add .5 for rounding accuracy */
651 Lvoldec
= (long)tmpl
;
652 Rvoldec
= (long)tmpr
;
654 /* End Insomnia's mod */
656 if (xdiff
<0) xdiff
=-xdiff
;
658 WARN(dsound
,"mixing in buffer of different frequency (%ld vs %ld), argh!\n",
659 dsb
->wfx
.nSamplesPerSec
,dsound
->wfx
.nSamplesPerSec
);
661 nextevent
= DSOUND_nextevent(dsb
);
662 /* TRACE(dsound,"(%d.%d.%d.%d)\n",dsound->wfx.wBitsPerSample,dsb->wfx.wBitsPerSample,dsound->wfx.nChannels,dsb->wfx.nChannels);*/
664 if (dsound
->wfx
.wBitsPerSample
== 8) {
665 char *playbuf8
= (char*)playbuf
;
667 if (dsb
->wfx
.wBitsPerSample
== 8) {
668 unsigned char *xbuf
= (unsigned char*)(dsb
->buffer
);
669 if (dsb
->wfx
.nChannels
== 1) {
670 for (j
=0;j
<sizeof(playbuf
)/2;j
++) {
672 dsb
->playpos
=(dsb
->playpos
+1)%buflen
;
673 if (!dsb
->playpos
&& !(dsb
->playflags
&DSBPLAY_LOOPING
)) {
675 dsb
->playpos
= buflen
;
678 /* Insomnia- volume, panning, and correcting against wrap */
680 samp
= xbuf
[dsb
->playpos
>>1];
683 samp
+= playbuf8
[(j
<<1)];
684 if(samp
> 127L) samp
= 127L;
685 else if(samp
< -128L) samp
= -128L;
686 playbuf8
[(j
<<1)] = (short)samp
;
689 samp
= xbuf
[dsb
->playpos
>>1];
692 samp
+= playbuf8
[(j
<<1)+1];
693 if(samp
> 127L) samp
= 127L;
694 else if(samp
< -128L) samp
= -128L;
695 playbuf8
[(j
<<1)+1] = (short)samp
;
696 /* End Insomnia's mod */
701 for (j
=0;j
<sizeof(playbuf
);j
++) {
702 dsb
->playpos
=(dsb
->playpos
+1)%buflen
;
703 if (!dsb
->playpos
&& !(dsb
->playflags
&DSBPLAY_LOOPING
)) {
705 dsb
->playpos
= buflen
;
708 /* Insomnia- volume, panning, and correcting against wrap */
709 samp
= xbuf
[dsb
->playpos
>>1];
712 if(j
&1) samp
*= Rvoldec
;
714 else samp
*= Lvoldec
;
718 if(samp
> 127L) samp
= 127L;
719 else if(samp
< -128L) samp
= -128L;
720 playbuf8
[j
] = (short)samp
;
721 /* End Insomnia's mod */
727 short *xbuf
= (short*)(dsb
->buffer
);
728 if (dsb
->wfx
.nChannels
== 1) {
729 for (j
=0;j
<sizeof(playbuf
)/2;j
++) {
730 dsb
->playpos
=(dsb
->playpos
+2)%buflen
;
731 if (!dsb
->playpos
&& !(dsb
->playflags
&DSBPLAY_LOOPING
)) {
733 dsb
->playpos
= buflen
;
736 /* Insomnia- volume, panning, and correcting against wrap */
738 samp
= xbuf
[dsb
->playpos
>>1];
741 samp
+= playbuf8
[(j
<<1)];
742 if(samp
> 127L) samp
= 127L;
743 else if(samp
< -128L) samp
= -128L;
744 playbuf8
[(j
<<1)] = (short)samp
;
747 samp
= xbuf
[dsb
->playpos
>>1];
750 samp
+= playbuf8
[(j
<<1)+1];
751 if(samp
> 127L) samp
= 127L;
752 else if(samp
< -128L) samp
= -128L;
753 playbuf8
[(j
<<1)+1] = (short)samp
;
754 /* End Insomnia's mod */
759 for (j
=0;j
<sizeof(playbuf
);j
++) {
760 dsb
->playpos
=(dsb
->playpos
+2)%buflen
;
761 if (!dsb
->playpos
&& !(dsb
->playflags
&DSBPLAY_LOOPING
)) {
763 dsb
->playpos
= buflen
;
766 /* Insomnia- volume, panning, and correcting against wrap */
767 samp
= xbuf
[dsb
->playpos
>>1];
770 if(j
&1) samp
*= Rvoldec
;
772 else samp
*= Lvoldec
;
776 if(samp
> 127L) samp
= 127L;
777 else if(samp
< -128L) samp
= -128L;
778 playbuf8
[j
] = (short)samp
;
779 /* End Insomnia's mod */
785 } else { /* 16 bit */
786 if (dsb
->wfx
.wBitsPerSample
== 8) {
787 /* unsigned char *xbuf = (unsigned char*)(dsb->buffer); */
788 char *xbuf
= dsb
->buffer
;
789 if (dsb
->wfx
.nChannels
== 1) {
790 WARN(dsound
,"Mixing 8-bit stereo into 16!!\n");
791 for (j
=0;j
<sizeof(playbuf
)/sizeof(playbuf
[0])/2;j
++) {
792 dsb
->playpos
=(dsb
->playpos
+1)%buflen
;
793 if (!dsb
->playpos
&& !(dsb
->playflags
&DSBPLAY_LOOPING
)) {
795 dsb
->playpos
= buflen
;
798 /* Insomnia- volume, panning, and correcting against wrap */
800 samp
= xbuf
[dsb
->playpos
>>1];
803 samp
+= playbuf
[(j
<<1)];
804 if(samp
> 32767L) samp
= 32767L;
805 else if(samp
< -32768L) samp
= -32768L;
806 playbuf
[(j
<<1)] = (short)samp
;
809 samp
= xbuf
[dsb
->playpos
>>1];
812 samp
+= playbuf
[(j
<<1)+1];
813 if(samp
> 32767L) samp
= 32767L;
814 else if(samp
< -32768L) samp
= -32768L;
815 playbuf
[(j
<<1)+1] = (short)samp
;
816 /* End Insomnia's mod */
821 for (j
=0;j
<sizeof(playbuf
)/sizeof(playbuf
[0]);j
++) {
822 dsb
->playpos
=(dsb
->playpos
+1)%buflen
;
823 if (!dsb
->playpos
&& !(dsb
->playflags
&DSBPLAY_LOOPING
)) {
825 dsb
->playpos
= buflen
;
828 /* Insomnia- volume, panning, and correcting against wrap */
829 samp
= xbuf
[dsb
->playpos
>>1];
832 if(j
&1) samp
*= Rvoldec
;
834 else samp
*= Lvoldec
;
838 if(samp
> 32767L) samp
= 32767L;
839 else if(samp
< -32768L) samp
= -32768L;
840 playbuf
[j
] = (short)samp
;
841 /* End Insomnia's mod */
847 short *xbuf
= (short*)(dsb
->buffer
);
848 if (dsb
->wfx
.nChannels
== 1) {
849 for (j
=0;j
<sizeof(playbuf
)/sizeof(playbuf
[0])/2;j
++) {
850 dsb
->playpos
=(dsb
->playpos
+2)%buflen
;
851 if (!dsb
->playpos
&& !(dsb
->playflags
&DSBPLAY_LOOPING
)) {
853 dsb
->playpos
= buflen
;
856 /* Insomnia- volume, panning, and correcting against wrap */
858 samp
= xbuf
[dsb
->playpos
>>1];
861 samp
+= playbuf
[(j
<<1)];
862 if(samp
> 32767L) samp
= 32767L;
863 else if(samp
< -32768L) samp
= -32768L;
864 playbuf
[(j
<<1)] = (short)samp
;
867 samp
= xbuf
[dsb
->playpos
>>1];
870 samp
+= playbuf
[(j
<<1)+1];
871 if(samp
> 32767L) samp
= 32767L;
872 else if(samp
< -32768L) samp
= -32768L;
873 playbuf
[(j
<<1)+1] = (short)samp
;
874 /* End Insomnia's mod */
879 for (j
=0;j
<sizeof(playbuf
)/sizeof(playbuf
[0]);j
++) {
880 dsb
->playpos
=(dsb
->playpos
+2)%buflen
;
881 if (!dsb
->playpos
&& !(dsb
->playflags
&DSBPLAY_LOOPING
)) {
883 dsb
->playpos
= buflen
;
886 /* Insomnia- volume, panning, and correcting against wrap */
887 samp
= xbuf
[dsb
->playpos
>>1];
890 if(j
&1) samp
*= Rvoldec
;
892 else samp
*= Lvoldec
;
896 if(samp
> 32767L) samp
= 32767L;
897 else if(samp
< -32768L) samp
= -32768L;
898 playbuf
[j
] = (short)samp
;
899 /* End Insomnia's mod */
909 DSOUND_thread(LPVOID arg
) {
910 int res
,i
,curleft
,playing
,haveprimary
= 0;
912 TRACE(dsound
,"dsound is at pid %d\n",getpid());
915 WARN(dsound
,"DSOUND thread giving up.\n");
919 WARN(dsound
,"DSOUND father died? Giving up.\n");
922 /* RACE: dsound could be deleted */
923 dsound
->lpvtbl
->fnAddRef(dsound
);
924 if (!dsound
->nrofbuffers
) {
925 /* no soundbuffer yet... wait. */
927 dsound
->lpvtbl
->fnRelease(dsound
);
930 memset(playbuf
,0,sizeof(playbuf
));
933 for (i
=dsound
->nrofbuffers
;i
--;) {
934 IDirectSoundBuffer
*dsb
= dsound
->buffers
[i
];
936 if (!dsb
|| !dsb
->lpvtbl
)
938 dsb
->lpvtbl
->fnAddRef(dsb
);
939 if (dsb
->playing
&& dsb
->buflen
)
941 if (dsb
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
943 if (memcmp(&dsound
->wfx
,&(dsb
->wfx
),sizeof(dsound
->wfx
))) {
944 DSOUND_setformat(&(dsb
->wfx
));
945 memcpy(&dsound
->wfx
,&(dsb
->wfx
),sizeof(dsb
->wfx
));
948 dsb
->lpvtbl
->fnRelease(dsb
);
950 /* We have just one playbuffer, so use its format */
951 if ((playing
==1) && !haveprimary
) {
952 for (i
=dsound
->nrofbuffers
;i
--;) {
953 IDirectSoundBuffer
*dsb
= dsound
->buffers
[i
];
955 dsb
->lpvtbl
->fnAddRef(dsb
);
956 if (dsb
->playing
&& dsb
->buflen
) {
957 if (memcmp(&dsound
->wfx
,&(dsb
->wfx
),sizeof(dsound
->wfx
))) {
958 DSOUND_setformat(&(dsb
->wfx
));
959 memcpy(&dsound
->wfx
,&(dsb
->wfx
),sizeof(dsb
->wfx
));
962 dsb
->lpvtbl
->fnRelease(dsb
);
965 for (i
=dsound
->nrofbuffers
;i
--;) {
966 IDirectSoundBuffer
*dsb
= dsound
->buffers
[i
];
968 if (!dsb
|| !dsb
->lpvtbl
)
970 dsb
->lpvtbl
->fnAddRef(dsb
);
971 if (dsb
->buflen
&& dsb
->playing
) {
973 DSOUND_MixInBuffer(dsb
);
975 dsb
->lpvtbl
->fnRelease(dsb
);
977 dsound
->lpvtbl
->fnRelease(dsound
);
979 /*fputc('0'+playing,stderr);*/
981 while (curleft
< sizeof(playbuf
)) {
982 res
= write(audiofd
,(LPBYTE
)playbuf
+curleft
,sizeof(playbuf
)-curleft
);
986 perror("write audiofd");
996 #endif /* HAVE_OSS */
998 HRESULT WINAPI
DirectSoundCreate(LPGUID lpGUID
,LPDIRECTSOUND
*ppDS
,IUnknown
*pUnkOuter
) {
1001 TRACE(dsound
,"(%p,%p,%p)\n",lpGUID
,ppDS
,pUnkOuter
);
1004 return DSERR_ALLOCATED
;
1005 audiofd
= open("/dev/audio",O_WRONLY
);
1007 perror("open /dev/audio");
1009 return DSERR_NODRIVER
;
1012 if (-1==ioctl(audiofd
,SNDCTL_DSP_SETFRAGMENT
,&xx
))
1013 perror("ioctl SETFRAGMENT");
1015 TRACE(dsound,"SETFRAGMENT. count is now %d, fragsize is %d\n",
1016 (xx>>16)+1,xx&0xffff
1020 *ppDS
= (LPDIRECTSOUND
)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSound
));
1022 (*ppDS
)->lpvtbl
= &dsvt
;
1023 (*ppDS
)->buffers
= NULL
;
1024 (*ppDS
)->nrofbuffers
= 0;
1026 (*ppDS
)->wfx
.wFormatTag
= 1;
1027 (*ppDS
)->wfx
.nChannels
= 2;
1028 (*ppDS
)->wfx
.nSamplesPerSec
= 22050;
1029 (*ppDS
)->wfx
.nAvgBytesPerSec
= 44100;
1030 (*ppDS
)->wfx
.nBlockAlign
= 2;
1031 (*ppDS
)->wfx
.wBitsPerSample
= 8;
1033 DSOUND_setformat(&((*ppDS
)->wfx
));
1040 hnd
= CreateThread(NULL
,0,DSOUND_thread
,0,0,&xid
);
1044 MessageBox32A(0,"DirectSound needs the Open Sound System Driver, which has not been found by ./configure.","WINE DirectSound",MB_OK
|MB_ICONSTOP
);
1045 return DSERR_NODRIVER
;
1050 /*******************************************************************************
1051 * DllGetClassObject [DSOUND.4]
1052 * Retrieves class object from a DLL object
1055 * Docs say returns STDAPI
1058 * rclsid [I] CLSID for the class object
1059 * riid [I] Reference to identifier of interface for class object
1060 * ppv [O] Address of variable to receive interface pointer for riid
1064 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
1067 DWORD WINAPI
DllGetClassObject( REFCLSID rclsid
, REFIID riid
, LPVOID
*ppv
)
1069 FIXME(dsound
, "(%p,%p,%p): stub\n", rclsid
, riid
, ppv
);
1074 /*******************************************************************************
1075 * DllCanUnloadNow [DSOUND.3] Determines whether the DLL is in use.
1081 DWORD WINAPI
DllCanUnloadNow(void)
1083 FIXME(dsound
, "(void): stub\n");