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
= 0;
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_EMULDRIVER
|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 return ++(this->ref
);
509 static ULONG WINAPI
IDirectSound_Release(LPDIRECTSOUND
this) {
510 if (!--(this->ref
)) {
511 HeapFree(GetProcessHeap(),0,this);
513 close(audiofd
);audiofd
= -1;
519 static HRESULT WINAPI
IDirectSound_SetSpeakerConfig(
520 LPDIRECTSOUND
this,DWORD config
522 FIXME(dsound
,"(%p,0x%08lx):stub\n",this,config
);
526 static HRESULT WINAPI
IDirectSound_QueryInterface(
527 LPDIRECTSOUND
this,REFIID riid
,LPVOID
*ppobj
531 WINE_StringFromCLSID(riid
,xbuf
);
532 TRACE(dsound
,"(%p,%s,%p)\n",this,xbuf
,ppobj
);
536 static struct tagLPDIRECTSOUND_VTABLE dsvt
= {
537 IDirectSound_QueryInterface
,
539 IDirectSound_Release
,
540 IDirectSound_CreateSoundBuffer
,
541 IDirectSound_GetCaps
,
542 IDirectSound_DuplicateSoundBuffer
,
543 IDirectSound_SetCooperativeLevel
,
546 IDirectSound_SetSpeakerConfig
,
551 DSOUND_setformat(LPWAVEFORMATEX wfex
) {
552 int xx
,channels
,speed
,format
,nformat
;
555 switch (wfex
->wFormatTag
) {
557 WARN(dsound
,"unknown WAVE_FORMAT tag %d\n",wfex
->wFormatTag
);
558 return DSERR_BADFORMAT
;
559 case WAVE_FORMAT_PCM
:
562 if (wfex
->wBitsPerSample
==8)
565 format
= AFMT_S16_LE
;
567 if (-1==ioctl(audiofd
,SNDCTL_DSP_GETFMTS
,&xx
)) {
568 perror("ioctl SNDCTL_DSP_GETFMTS");
571 if ((xx
&format
)!=format
) {/* format unsupported */
572 WARN(dsound
,"SNDCTL_DSP_GETFMTS: format not supported\n");
576 if (-1==ioctl(audiofd
,SNDCTL_DSP_SETFMT
,&nformat
)) {
577 perror("ioctl SNDCTL_DSP_SETFMT");
580 if (nformat
!=format
) {/* didn't work */
581 WARN(dsound
,"SNDCTL_DSP_GETFMTS: format not set\n");
585 channels
= wfex
->nChannels
-1;
586 if (-1==ioctl(audiofd
,SNDCTL_DSP_STEREO
,&channels
)) {
587 perror("ioctl SNDCTL_DSP_STEREO");
590 speed
= wfex
->nSamplesPerSec
;
591 if (-1==ioctl(audiofd
,SNDCTL_DSP_SPEED
,&speed
)) {
592 perror("ioctl SNDCTL_DSP_SPEED");
595 TRACE(dsound
,"(freq=%ld,channels=%d,bits=%d)\n",
596 wfex
->nSamplesPerSec
,wfex
->nChannels
,wfex
->wBitsPerSample
601 static LPDSBPOSITIONNOTIFY
602 DSOUND_nextevent(IDirectSoundBuffer
*dsb
) {
605 if (dsb
->nrofnotifies
) {
606 for (i
=0;i
<dsb
->nrofnotifies
;i
++) {
607 if (dsb
->playpos
<dsb
->notifies
[i
].dwOffset
)
610 if (i
==dsb
->nrofnotifies
)
612 return dsb
->notifies
+i
;
617 #define CHECK_EVENT \
618 if (nextevent && (dsb->playpos == nextevent->dwOffset)) { \
619 SetEvent(nextevent->hEventNotify); \
620 TRACE(dsound,"signalled event %d\n",nextevent->hEventNotify);\
621 nextevent = DSOUND_nextevent(dsb); \
626 DSOUND_MixInBuffer(IDirectSoundBuffer
*dsb
) {
627 int j
,buflen
= dsb
->buflen
;
628 LPDSBPOSITIONNOTIFY nextevent
;
629 int xdiff
= dsb
->wfx
.nSamplesPerSec
-dsound
->wfx
.nSamplesPerSec
;
631 /* Insomnia - Going along with REAL author's style */
632 long Rvoldec
, Lvoldec
;
634 long samp
; /* temporary sample workspace */
637 double tmpr
=dsb
->volume
-500;
639 if(pan
>0) tmpl
-= (double)pan
;
640 else tmpr
+= (double)pan
;
643 tmpl
= pow(2.0, tmpl
);
644 tmpr
= pow(2.0, tmpr
);
645 tmpl
*= 65536; /* Set to the correct multiple times */
646 tmpr
*= 65536; /* 65536 to be convenient for bit shifting */
647 tmpl
+= 0.5; /* Add .5 for rounding accuracy */
649 Lvoldec
= (long)tmpl
;
650 Rvoldec
= (long)tmpr
;
652 /* End Insomnia's mod */
654 if (xdiff
<0) xdiff
=-xdiff
;
656 WARN(dsound
,"mixing in buffer of different frequency (%ld vs %ld), argh!\n",
657 dsb
->wfx
.nSamplesPerSec
,dsound
->wfx
.nSamplesPerSec
);
659 nextevent
= DSOUND_nextevent(dsb
);
660 /* TRACE(dsound,"(%d.%d.%d.%d)\n",dsound->wfx.wBitsPerSample,dsb->wfx.wBitsPerSample,dsound->wfx.nChannels,dsb->wfx.nChannels);*/
662 if (dsound
->wfx
.wBitsPerSample
== 8) {
663 char *playbuf8
= (char*)playbuf
;
665 if (dsb
->wfx
.wBitsPerSample
== 8) {
666 unsigned char *xbuf
= (unsigned char*)(dsb
->buffer
);
667 if (dsb
->wfx
.nChannels
== 1) {
668 for (j
=0;j
<sizeof(playbuf
)/2;j
++) {
670 dsb
->playpos
=(dsb
->playpos
+1)%buflen
;
671 if (!dsb
->playpos
&& !(dsb
->playflags
&DSBPLAY_LOOPING
)) {
673 dsb
->playpos
= buflen
;
676 /* Insomnia- volume, panning, and correcting against wrap */
678 samp
= xbuf
[dsb
->playpos
>>1];
681 samp
+= playbuf8
[(j
<<1)];
682 if(samp
> 127L) samp
= 127L;
683 else if(samp
< -128L) samp
= -128L;
684 playbuf8
[(j
<<1)] = (short)samp
;
687 samp
= xbuf
[dsb
->playpos
>>1];
690 samp
+= playbuf8
[(j
<<1)+1];
691 if(samp
> 127L) samp
= 127L;
692 else if(samp
< -128L) samp
= -128L;
693 playbuf8
[(j
<<1)+1] = (short)samp
;
694 /* End Insomnia's mod */
699 for (j
=0;j
<sizeof(playbuf
);j
++) {
700 dsb
->playpos
=(dsb
->playpos
+1)%buflen
;
701 if (!dsb
->playpos
&& !(dsb
->playflags
&DSBPLAY_LOOPING
)) {
703 dsb
->playpos
= buflen
;
706 /* Insomnia- volume, panning, and correcting against wrap */
707 samp
= xbuf
[dsb
->playpos
>>1];
710 if(j
&1) samp
*= Rvoldec
;
712 else samp
*= Lvoldec
;
716 if(samp
> 127L) samp
= 127L;
717 else if(samp
< -128L) samp
= -128L;
718 playbuf8
[j
] = (short)samp
;
719 /* End Insomnia's mod */
725 short *xbuf
= (short*)(dsb
->buffer
);
726 if (dsb
->wfx
.nChannels
== 1) {
727 for (j
=0;j
<sizeof(playbuf
)/2;j
++) {
728 dsb
->playpos
=(dsb
->playpos
+2)%buflen
;
729 if (!dsb
->playpos
&& !(dsb
->playflags
&DSBPLAY_LOOPING
)) {
731 dsb
->playpos
= buflen
;
734 /* Insomnia- volume, panning, and correcting against wrap */
736 samp
= xbuf
[dsb
->playpos
>>1];
739 samp
+= playbuf8
[(j
<<1)];
740 if(samp
> 127L) samp
= 127L;
741 else if(samp
< -128L) samp
= -128L;
742 playbuf8
[(j
<<1)] = (short)samp
;
745 samp
= xbuf
[dsb
->playpos
>>1];
748 samp
+= playbuf8
[(j
<<1)+1];
749 if(samp
> 127L) samp
= 127L;
750 else if(samp
< -128L) samp
= -128L;
751 playbuf8
[(j
<<1)+1] = (short)samp
;
752 /* End Insomnia's mod */
757 for (j
=0;j
<sizeof(playbuf
);j
++) {
758 dsb
->playpos
=(dsb
->playpos
+2)%buflen
;
759 if (!dsb
->playpos
&& !(dsb
->playflags
&DSBPLAY_LOOPING
)) {
761 dsb
->playpos
= buflen
;
764 /* Insomnia- volume, panning, and correcting against wrap */
765 samp
= xbuf
[dsb
->playpos
>>1];
768 if(j
&1) samp
*= Rvoldec
;
770 else samp
*= Lvoldec
;
774 if(samp
> 127L) samp
= 127L;
775 else if(samp
< -128L) samp
= -128L;
776 playbuf8
[j
] = (short)samp
;
777 /* End Insomnia's mod */
783 } else { /* 16 bit */
784 if (dsb
->wfx
.wBitsPerSample
== 8) {
785 /* unsigned char *xbuf = (unsigned char*)(dsb->buffer); */
786 char *xbuf
= dsb
->buffer
;
787 if (dsb
->wfx
.nChannels
== 1) {
788 WARN(dsound
,"Mixing 8-bit stereo into 16!!\n");
789 for (j
=0;j
<sizeof(playbuf
)/sizeof(playbuf
[0])/2;j
++) {
790 dsb
->playpos
=(dsb
->playpos
+1)%buflen
;
791 if (!dsb
->playpos
&& !(dsb
->playflags
&DSBPLAY_LOOPING
)) {
793 dsb
->playpos
= buflen
;
796 /* Insomnia- volume, panning, and correcting against wrap */
798 samp
= xbuf
[dsb
->playpos
>>1];
801 samp
+= playbuf
[(j
<<1)];
802 if(samp
> 32767L) samp
= 32767L;
803 else if(samp
< -32768L) samp
= -32768L;
804 playbuf
[(j
<<1)] = (short)samp
;
807 samp
= xbuf
[dsb
->playpos
>>1];
810 samp
+= playbuf
[(j
<<1)+1];
811 if(samp
> 32767L) samp
= 32767L;
812 else if(samp
< -32768L) samp
= -32768L;
813 playbuf
[(j
<<1)+1] = (short)samp
;
814 /* End Insomnia's mod */
819 for (j
=0;j
<sizeof(playbuf
)/sizeof(playbuf
[0]);j
++) {
820 dsb
->playpos
=(dsb
->playpos
+1)%buflen
;
821 if (!dsb
->playpos
&& !(dsb
->playflags
&DSBPLAY_LOOPING
)) {
823 dsb
->playpos
= buflen
;
826 /* Insomnia- volume, panning, and correcting against wrap */
827 samp
= xbuf
[dsb
->playpos
>>1];
830 if(j
&1) samp
*= Rvoldec
;
832 else samp
*= Lvoldec
;
836 if(samp
> 32767L) samp
= 32767L;
837 else if(samp
< -32768L) samp
= -32768L;
838 playbuf
[j
] = (short)samp
;
839 /* End Insomnia's mod */
845 short *xbuf
= (short*)(dsb
->buffer
);
846 if (dsb
->wfx
.nChannels
== 1) {
847 for (j
=0;j
<sizeof(playbuf
)/sizeof(playbuf
[0])/2;j
++) {
848 dsb
->playpos
=(dsb
->playpos
+2)%buflen
;
849 if (!dsb
->playpos
&& !(dsb
->playflags
&DSBPLAY_LOOPING
)) {
851 dsb
->playpos
= buflen
;
854 /* Insomnia- volume, panning, and correcting against wrap */
856 samp
= xbuf
[dsb
->playpos
>>1];
859 samp
+= playbuf
[(j
<<1)];
860 if(samp
> 32767L) samp
= 32767L;
861 else if(samp
< -32768L) samp
= -32768L;
862 playbuf
[(j
<<1)] = (short)samp
;
865 samp
= xbuf
[dsb
->playpos
>>1];
868 samp
+= playbuf
[(j
<<1)+1];
869 if(samp
> 32767L) samp
= 32767L;
870 else if(samp
< -32768L) samp
= -32768L;
871 playbuf
[(j
<<1)+1] = (short)samp
;
872 /* End Insomnia's mod */
877 for (j
=0;j
<sizeof(playbuf
)/sizeof(playbuf
[0]);j
++) {
878 dsb
->playpos
=(dsb
->playpos
+2)%buflen
;
879 if (!dsb
->playpos
&& !(dsb
->playflags
&DSBPLAY_LOOPING
)) {
881 dsb
->playpos
= buflen
;
884 /* Insomnia- volume, panning, and correcting against wrap */
885 samp
= xbuf
[dsb
->playpos
>>1];
888 if(j
&1) samp
*= Rvoldec
;
890 else samp
*= Lvoldec
;
894 if(samp
> 32767L) samp
= 32767L;
895 else if(samp
< -32768L) samp
= -32768L;
896 playbuf
[j
] = (short)samp
;
897 /* End Insomnia's mod */
907 DSOUND_thread(LPVOID arg
) {
908 int res
,i
,curleft
,playing
,haveprimary
= 0;
910 TRACE(dsound
,"dsound is at pid %d\n",getpid());
913 WARN(dsound
,"DSOUND thread giving up.\n");
917 WARN(dsound
,"DSOUND father died? Giving up.\n");
920 /* RACE: dsound could be deleted */
921 dsound
->lpvtbl
->fnAddRef(dsound
);
922 if (!dsound
->nrofbuffers
) {
923 /* no soundbuffer yet... wait. */
927 memset(playbuf
,0,sizeof(playbuf
));
929 dsound
->lpvtbl
->fnAddRef(dsound
);
931 for (i
=dsound
->nrofbuffers
;i
--;) {
932 IDirectSoundBuffer
*dsb
= dsound
->buffers
[i
];
934 if (!dsb
|| !dsb
->lpvtbl
)
936 dsb
->lpvtbl
->fnAddRef(dsb
);
937 if (dsb
->playing
&& dsb
->buflen
)
939 if (dsb
->dsbd
.dwFlags
& DSBCAPS_PRIMARYBUFFER
) {
941 if (memcmp(&dsound
->wfx
,&(dsb
->wfx
),sizeof(dsound
->wfx
))) {
942 DSOUND_setformat(&(dsb
->wfx
));
943 memcpy(&dsound
->wfx
,&(dsb
->wfx
),sizeof(dsb
->wfx
));
946 dsb
->lpvtbl
->fnRelease(dsb
);
948 /* We have just one playbuffer, so use its format */
949 if ((playing
==1) && !haveprimary
) {
950 for (i
=dsound
->nrofbuffers
;i
--;) {
951 IDirectSoundBuffer
*dsb
= dsound
->buffers
[i
];
953 dsb
->lpvtbl
->fnAddRef(dsb
);
954 if (dsb
->playing
&& dsb
->buflen
) {
955 if (memcmp(&dsound
->wfx
,&(dsb
->wfx
),sizeof(dsound
->wfx
))) {
956 DSOUND_setformat(&(dsb
->wfx
));
957 memcpy(&dsound
->wfx
,&(dsb
->wfx
),sizeof(dsb
->wfx
));
960 dsb
->lpvtbl
->fnRelease(dsb
);
963 for (i
=dsound
->nrofbuffers
;i
--;) {
964 IDirectSoundBuffer
*dsb
= dsound
->buffers
[i
];
966 if (!dsb
|| !dsb
->lpvtbl
)
968 dsb
->lpvtbl
->fnAddRef(dsb
);
969 if (dsb
->buflen
&& dsb
->playing
) {
971 DSOUND_MixInBuffer(dsb
);
973 dsb
->lpvtbl
->fnRelease(dsb
);
975 dsound
->lpvtbl
->fnRelease(dsound
);
977 /*fputc('0'+playing,stderr);*/
979 while (curleft
< sizeof(playbuf
)) {
980 res
= write(audiofd
,(LPBYTE
)playbuf
+curleft
,sizeof(playbuf
)-curleft
);
984 perror("write audiofd");
994 #endif /* HAVE_OSS */
996 HRESULT WINAPI
DirectSoundCreate(LPGUID lpGUID
,LPDIRECTSOUND
*ppDS
,IUnknown
*pUnkOuter
) {
999 TRACE(dsound
,"(%p,%p,%p)\n",lpGUID
,ppDS
,pUnkOuter
);
1002 return DSERR_ALLOCATED
;
1003 audiofd
= open("/dev/audio",O_WRONLY
);
1005 perror("open /dev/audio");
1007 return DSERR_NODRIVER
;
1010 if (-1==ioctl(audiofd
,SNDCTL_DSP_SETFRAGMENT
,&xx
))
1011 perror("ioctl SETFRAGMENT");
1013 TRACE(dsound,"SETFRAGMENT. count is now %d, fragsize is %d\n",
1014 (xx>>16)+1,xx&0xffff
1018 *ppDS
= (LPDIRECTSOUND
)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSound
));
1020 (*ppDS
)->lpvtbl
= &dsvt
;
1021 (*ppDS
)->buffers
= NULL
;
1022 (*ppDS
)->nrofbuffers
= 0;
1024 (*ppDS
)->wfx
.wFormatTag
= 1;
1025 (*ppDS
)->wfx
.nChannels
= 2;
1026 (*ppDS
)->wfx
.nSamplesPerSec
= 22050;
1027 (*ppDS
)->wfx
.nAvgBytesPerSec
= 44100;
1028 (*ppDS
)->wfx
.nBlockAlign
= 2;
1029 (*ppDS
)->wfx
.wBitsPerSample
= 8;
1031 DSOUND_setformat(&((*ppDS
)->wfx
));
1038 hnd
= CreateThread(NULL
,0,DSOUND_thread
,0,0,&xid
);
1042 MessageBox32A(0,"DirectSound needs the Open Sound System Driver, which has not been found by ./configure.","WINE DirectSound",MB_OK
|MB_ICONSTOP
);
1043 return DSERR_NODRIVER
;
1048 /*******************************************************************************
1049 * DllGetClassObject [DSOUND.4]
1050 * Retrieves class object from a DLL object
1053 * Docs say returns STDAPI
1056 * rclsid [I] CLSID for the class object
1057 * riid [I] Reference to identifier of interface for class object
1058 * ppv [O] Address of variable to receive interface pointer for riid
1062 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
1065 DWORD WINAPI
DllGetClassObject( REFCLSID rclsid
, REFIID riid
, LPVOID
*ppv
)
1067 FIXME(dsound
, "(%p,%p,%p): stub\n", rclsid
, riid
, ppv
);
1072 /*******************************************************************************
1073 * DllCanUnloadNow [DSOUND.3] Determines whether the DLL is in use.
1079 DWORD WINAPI
DllCanUnloadNow(void)
1081 FIXME(dsound
, "(void): stub\n");