Small fixes.
[wine.git] / multimedia / dsound.c
blobd0e65127b11985b3b1d66a814dde094dc86f9af4
1 /* DirectSound
2 *
3 * Copyright 1998 Marcus Meissner
4 */
5 /*
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.
15 * Status:
16 * - Wing Commander 4/W95:
17 * The intromovie plays without problems. Nearly lipsynchron.
18 * - DiscWorld 2
19 * The sound works, but noticeable chunks are left out (from the sound and
20 * the animation). Don't know why yet.
21 * - Diablo:
22 * Sound works, but slows down the movieplayer.
23 * - XvT:
24 * Doesn't sound yet.
25 * - Monkey Island 3:
26 * The background sound of the startscreen works ;)
27 * - WingCommander Prophecy Demo:
28 * Sound works for the intromovie.
31 #include "config.h"
32 #include <assert.h>
33 #include <errno.h>
34 #include <sys/types.h>
35 #include <sys/time.h>
36 #include <sys/fcntl.h>
37 #include <unistd.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <math.h> /* Insomnia - pow() function */
41 #include "windows.h"
42 #include "winerror.h"
43 #include "interfaces.h"
44 #include "mmsystem.h"
45 #include "dsound.h"
46 #include "thread.h"
47 #include "debug.h"
49 #ifdef HAVE_OSS
50 # include <sys/ioctl.h>
51 # ifdef HAVE_MACHINE_SOUNDCARD_H
52 # include <machine/soundcard.h>
53 # endif
54 # ifdef HAVE_SYS_SOUNDCARD_H
55 # include <sys/soundcard.h>
56 # endif
58 static int audiofd = -1;
59 static LPDIRECTSOUND dsound = NULL;
61 static short playbuf[2048];
63 #endif
65 HRESULT WINAPI DirectSoundEnumerate32A(LPDSENUMCALLBACK32A enumcb,LPVOID context) {
66 #ifdef HAVE_OSS
67 enumcb(NULL,"WINE DirectSound using Open Sound System","sound",context);
68 #endif
69 return 0;
72 #ifdef HAVE_OSS
73 static void _dump_DSBCAPS(DWORD xmask) {
74 struct {
75 DWORD mask;
76 char *name;
77 } flags[] = {
78 #define FE(x) { x, #x },
79 FE(DSBCAPS_PRIMARYBUFFER)
80 FE(DSBCAPS_STATIC)
81 FE(DSBCAPS_LOCHARDWARE)
82 FE(DSBCAPS_LOCSOFTWARE)
83 FE(DSBCAPS_CTRLFREQUENCY)
84 FE(DSBCAPS_CTRLPAN)
85 FE(DSBCAPS_CTRLVOLUME)
86 FE(DSBCAPS_CTRLDEFAULT)
87 FE(DSBCAPS_CTRLALL)
88 FE(DSBCAPS_STICKYFOCUS)
89 FE(DSBCAPS_GETCURRENTPOSITION2)
91 int i;
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 /*******************************************************************************
99 * IDirectSoundNotify
101 static HRESULT WINAPI IDirectSoundNotify_QueryInterface(
102 LPDIRECTSOUNDNOTIFY this,REFIID riid,LPVOID *ppobj
104 char xbuf[50];
106 WINE_StringFromCLSID(riid,xbuf);
107 TRACE(dsound,"(%p,%s,%p)\n",this,xbuf,ppobj);
108 return E_FAIL;
111 static ULONG WINAPI IDirectSoundNotify_AddRef(LPDIRECTSOUNDNOTIFY this) {
112 return ++(this->ref);
115 static ULONG WINAPI IDirectSoundNotify_Release(LPDIRECTSOUNDNOTIFY this) {
116 this->ref--;
117 if (!this->ref) {
118 this->dsb->lpvtbl->fnRelease(this->dsb);
119 HeapFree(GetProcessHeap(),0,this);
120 return 0;
122 return this->ref;
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
135 int i;
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,
145 notify,
146 howmuch*sizeof(DSBPOSITIONNOTIFY)
148 this->dsb->nrofnotifies+=howmuch;
149 qsort(this->dsb->notifies,this->dsb->nrofnotifies,sizeof(DSBPOSITIONNOTIFY),_sort_notifies);
150 return 0;
153 IDirectSoundNotify_VTable dsnvt = {
154 IDirectSoundNotify_QueryInterface,
155 IDirectSoundNotify_AddRef,
156 IDirectSoundNotify_Release,
157 IDirectSoundNotify_SetNotificationPositions,
160 /*******************************************************************************
161 * IDirectSoundBuffer
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);
175 return 0;
178 static HRESULT WINAPI IDirectSoundBuffer_SetVolume(
179 LPDIRECTSOUNDBUFFER this,LONG vol
181 TRACE(dsound,"(%p,%ld)\n",this,vol);
182 this->volume = vol;
183 this->volfac = ((double)vol+10000.0)/10000.0;
185 return 0;
188 static HRESULT WINAPI IDirectSoundBuffer_GetVolume(
189 LPDIRECTSOUNDBUFFER this,LPLONG vol
191 TRACE(dsound,"(%p,%p)\n",this,vol);
192 *vol = this->volume;
193 return 0;
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);
202 return 0;
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
211 this->playpos = 0;
212 this->playflags = flags;
213 this->playing = 1;
214 return 0;
217 static HRESULT WINAPI IDirectSoundBuffer_Stop(LPDIRECTSOUNDBUFFER this) {
218 TRACE(dsound,"(%p)\n",this);
219 this->playing = 0;
220 this->writepos = 0; /* hmm */
221 return 0;
224 static DWORD WINAPI IDirectSoundBuffer_AddRef(LPDIRECTSOUNDBUFFER this) {
225 return ++(this->ref);
227 static DWORD WINAPI IDirectSoundBuffer_Release(LPDIRECTSOUNDBUFFER this) {
228 int i;
230 if (--this->ref)
231 return this->ref;
232 for (i=0;i<this->dsound->nrofbuffers;i++)
233 if (this->dsound->buffers[i] == this)
234 break;
235 if (i < this->dsound->nrofbuffers) {
236 memcpy(
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);
247 return 0;
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;
256 return 0;
259 static HRESULT WINAPI IDirectSoundBuffer_GetStatus(
260 LPDIRECTSOUNDBUFFER this,LPDWORD status
262 TRACE(dsound,"(%p,%p)\n",this,status);
263 *status = 0;
264 if (this->playing)
265 *status |= DSBSTATUS_PLAYING;
266 if (this->playflags & DSBPLAY_LOOPING)
267 *status |= DSBSTATUS_LOOPING;
268 return 0;
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;
278 return 0;
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",
286 this,
287 writecursor,
288 writebytes,
289 lplpaudioptr1,
290 audiobytes1,
291 lplpaudioptr2,
292 audiobytes2,
293 flags
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;
302 if (lplpaudioptr2)
303 *(LPBYTE*)lplpaudioptr2 = NULL;
304 if (audiobytes2)
305 *audiobytes2 = 0;
306 TRACE(dsound,"->%ld.0\n",writebytes);
307 } else {
308 *(LPBYTE*)lplpaudioptr1 = this->buffer+writecursor;
309 *audiobytes1 = this->buflen-writecursor;
310 if (lplpaudioptr2)
311 *(LPBYTE*)lplpaudioptr2 = this->buffer;
312 if (audiobytes2)
313 *audiobytes2 = writebytes-(this->buflen-writecursor);
314 TRACE(dsound,"->%ld.%ld\n",*audiobytes1,audiobytes2?*audiobytes2:0);
316 this->writepos=(writecursor+writebytes)%this->buflen;
317 return 0;
320 static HRESULT WINAPI IDirectSoundBuffer_SetCurrentPosition(
321 LPDIRECTSOUNDBUFFER this,DWORD newpos
323 TRACE(dsound,"(%p,%ld)\n",this,newpos);
324 this->playpos = newpos;
325 return 0;
328 static HRESULT WINAPI IDirectSoundBuffer_SetPan(
329 LPDIRECTSOUNDBUFFER this,LONG newpan
331 TRACE(dsound,"(%p,%ld)\n",this,newpan);
332 this->pan = newpan;
333 return 0;
336 static HRESULT WINAPI IDirectSoundBuffer_GetPan(
337 LPDIRECTSOUNDBUFFER this,LPLONG pan
339 TRACE(dsound,"(%p,%p)\n",this,pan);
340 *pan = this->pan;
341 return 0;
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); */
348 return 0;
351 static HRESULT WINAPI IDirectSoundBuffer_GetFrequency(
352 LPDIRECTSOUNDBUFFER this,LPDWORD freq
354 TRACE(dsound,"(%p,%p)\n",this,freq);
355 *freq = this->wfx.nSamplesPerSec;
356 return 0;
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;
375 return DS_OK;
378 static HRESULT WINAPI IDirectSoundBuffer_QueryInterface(
379 LPDIRECTSOUNDBUFFER this,REFIID riid,LPVOID *ppobj
381 char xbuf[50];
383 if (!memcmp(&IID_IDirectSoundNotify,riid,sizeof(*riid))) {
384 IDirectSoundNotify *dsn;
386 dsn = (LPDIRECTSOUNDNOTIFY)HeapAlloc(GetProcessHeap(),0,sizeof(*dsn));
387 dsn->ref = 1;
388 dsn->dsb = this;
389 this->lpvtbl->fnAddRef(this);
390 dsn->lpvtbl = &dsnvt;
391 *ppobj = (LPVOID)dsn;
392 return 0;
394 WINE_StringFromCLSID(riid,xbuf);
395 TRACE(dsound,"(%p,%s,%p)\n",this,xbuf,ppobj);
396 return E_FAIL;
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 /*******************************************************************************
423 * IDirectSound
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);
430 return 0;
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));
446 (*ppdsb)->ref =1;
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;
460 this->nrofbuffers++;
461 this->lpvtbl->fnAddRef(this);
463 if (dsbd->lpwfxFormat) dsbvt.fnSetFormat(*ppdsb,dsbd->lpwfxFormat);
464 return 0;
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));
473 (*ppdsb)->ref =1;
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;
485 this->nrofbuffers++;
486 this->lpvtbl->fnAddRef(this);
487 return 0;
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 */
502 return 0;
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);
514 dsound = NULL;
515 close(audiofd);audiofd = -1;
516 return 0;
518 return this->ref;
521 static HRESULT WINAPI IDirectSound_SetSpeakerConfig(
522 LPDIRECTSOUND this,DWORD config
524 FIXME(dsound,"(%p,0x%08lx):stub\n",this,config);
525 return 0;
528 static HRESULT WINAPI IDirectSound_QueryInterface(
529 LPDIRECTSOUND this,REFIID riid,LPVOID *ppobj
531 char xbuf[50];
533 WINE_StringFromCLSID(riid,xbuf);
534 TRACE(dsound,"(%p,%s,%p)\n",this,xbuf,ppobj);
535 return E_FAIL;
538 static struct tagLPDIRECTSOUND_VTABLE dsvt = {
539 IDirectSound_QueryInterface,
540 IDirectSound_AddRef,
541 IDirectSound_Release,
542 IDirectSound_CreateSoundBuffer,
543 IDirectSound_GetCaps,
544 IDirectSound_DuplicateSoundBuffer,
545 IDirectSound_SetCooperativeLevel,
546 (void *)8,
547 (void *)9,
548 IDirectSound_SetSpeakerConfig,
549 (void *)11
552 static int
553 DSOUND_setformat(LPWAVEFORMATEX wfex) {
554 int xx,channels,speed,format,nformat;
557 switch (wfex->wFormatTag) {
558 default:
559 WARN(dsound,"unknown WAVE_FORMAT tag %d\n",wfex->wFormatTag);
560 return DSERR_BADFORMAT;
561 case WAVE_FORMAT_PCM:
562 break;
564 if (wfex->wBitsPerSample==8)
565 format = AFMT_U8;
566 else
567 format = AFMT_S16_LE;
569 if (-1==ioctl(audiofd,SNDCTL_DSP_GETFMTS,&xx)) {
570 perror("ioctl SNDCTL_DSP_GETFMTS");
571 return -1;
573 if ((xx&format)!=format) {/* format unsupported */
574 FIXME(dsound,"SNDCTL_DSP_GETFMTS: format not supported\n");
575 return -1;
577 nformat = format;
578 if (-1==ioctl(audiofd,SNDCTL_DSP_SETFMT,&nformat)) {
579 perror("ioctl SNDCTL_DSP_SETFMT");
580 return -1;
582 if (nformat!=format) {/* didn't work */
583 FIXME(dsound,"SNDCTL_DSP_GETFMTS: format not set\n");
584 return -1;
587 channels = wfex->nChannels-1;
588 if (-1==ioctl(audiofd,SNDCTL_DSP_STEREO,&channels)) {
589 perror("ioctl SNDCTL_DSP_STEREO");
590 return -1;
592 speed = wfex->nSamplesPerSec;
593 if (-1==ioctl(audiofd,SNDCTL_DSP_SPEED,&speed)) {
594 perror("ioctl SNDCTL_DSP_SPEED");
595 return -1;
597 TRACE(dsound,"(freq=%ld,channels=%d,bits=%d)\n",
598 wfex->nSamplesPerSec,wfex->nChannels,wfex->wBitsPerSample
600 return 0;
603 static LPDSBPOSITIONNOTIFY
604 DSOUND_nextevent(IDirectSoundBuffer *dsb) {
605 int i;
607 if (dsb->nrofnotifies) {
608 for (i=0;i<dsb->nrofnotifies;i++) {
609 if (dsb->playpos<dsb->notifies[i].dwOffset)
610 break;
612 if (i==dsb->nrofnotifies)
613 i=0;
614 return dsb->notifies+i;
616 return NULL;
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); \
627 static void
628 DSOUND_MixInBuffer(IDirectSoundBuffer *dsb) {
629 int j,buflen = dsb->buflen;
630 LPDSBPOSITIONNOTIFY nextevent;
631 int xdiff = dsb->wfx.nSamplesPerSec-dsound->wfx.nSamplesPerSec;
632 long Rvoldec, Lvoldec, samp;
633 long pan = dsb->pan;
636 double tmpr=dsb->volume-500;
637 double tmpl=tmpr;
638 if(pan>0) tmpl -= (double)pan;
639 else tmpr += (double)pan;
640 tmpl /= 1000.0;
641 tmpr /= 1000.0;
642 tmpl = pow(2.0, tmpl);
643 tmpr = pow(2.0, tmpr);
644 tmpl *= 65536; /* Set to the correct multiple times */
645 tmpr *= 65536; /* 65536 to be convenient for bit shifting */
646 tmpl += 0.5; /* Add .5 for rounding accuracy */
647 tmpr += 0.5;
648 Lvoldec = (long)tmpl;
649 Rvoldec = (long)tmpr;
651 /* End Insomnia's mod */
653 if (xdiff<0) xdiff=-xdiff;
654 if (xdiff>1500) {
655 WARN(dsound,"mixing in buffer of different frequency (%ld vs %ld), argh!\n",
656 dsb->wfx.nSamplesPerSec,dsound->wfx.nSamplesPerSec);
658 nextevent = DSOUND_nextevent(dsb);
659 TRACE(dsound,"(%d.%d.%d.%d)\n",dsound->wfx.wBitsPerSample,dsb->wfx.wBitsPerSample,dsound->wfx.nChannels,dsb->wfx.nChannels);
661 if (dsound->wfx.wBitsPerSample == 8) {
662 char *playbuf8 = (char*)playbuf;
664 if (dsb->wfx.wBitsPerSample == 8) {
665 unsigned char *xbuf = (unsigned char*)(dsb->buffer);
666 if (dsb->wfx.nChannels == 1) {
667 /* 8.1 -> 8.2 */
668 for (j=0;j<sizeof(playbuf)/2;j++) {
670 dsb->playpos=(dsb->playpos+1)%buflen;
671 if (!dsb->playpos && !(dsb->playflags&DSBPLAY_LOOPING)) {
672 dsb->playing = 0;
673 dsb->playpos = buflen;
674 return;
676 /* Insomnia- volume, panning, and correcting against wrap */
677 /* Left Channel */
678 samp = xbuf[dsb->playpos];
679 samp *= Lvoldec;
680 samp >>= 16;
681 samp += playbuf8[(j<<1)];
682 if(samp > 127L) samp = 127L;
683 else if(samp < -128L) samp = -128L;
684 playbuf8[(j<<1)] = (short)samp;
686 /* Right Channel */
687 samp = xbuf[dsb->playpos];
688 samp *= Rvoldec;
689 samp >>= 16;
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 */
696 CHECK_EVENT
698 } else {
699 /* 8.2 -> 8.2 */
700 for (j=0;j<sizeof(playbuf);j++) {
701 dsb->playpos=(dsb->playpos+1)%buflen;
702 if (!dsb->playpos && !(dsb->playflags&DSBPLAY_LOOPING)) {
703 dsb->playing = 0;
704 dsb->playpos = buflen;
705 return;
707 /* Insomnia- volume, panning, and correcting against wrap */
708 samp = xbuf[dsb->playpos];
710 /* Right Channel */
711 if(j&1) samp *= Rvoldec;
712 /* Left Channel */
713 else samp *= Lvoldec;
715 samp >>= 16;
716 samp += playbuf8[j];
717 if(samp > 127L) samp = 127L;
718 else if(samp < -128L) samp = -128L;
719 playbuf8[j] = (short)samp;
720 /* End Insomnia's mod */
722 CHECK_EVENT
725 } else { /* 16 */
726 short *xbuf = (short*)(dsb->buffer);
727 if (dsb->wfx.nChannels == 1) {
728 /* 16.1 -> 8.2 */
729 for (j=0;j<sizeof(playbuf)/sizeof(playbuf[0])/2;j++) {
730 dsb->playpos=(dsb->playpos+2)%buflen;
731 if (!dsb->playpos && !(dsb->playflags&DSBPLAY_LOOPING)) {
732 dsb->playing = 0;
733 dsb->playpos = buflen;
734 return;
736 /* Insomnia- volume, panning, and correcting against wrap */
737 /* Left Channel */
738 samp = xbuf[dsb->playpos>>1];
739 samp *= Lvoldec;
740 samp >>= 24;
741 samp += playbuf8[(j<<1)];
742 if(samp > 127L) samp = 127L;
743 else if(samp < -128L) samp = -128L;
744 playbuf8[(j<<1)] = (short)samp;
746 /* Right Channel */
747 samp = xbuf[dsb->playpos>>1];
748 samp *= Rvoldec;
749 samp >>= 24;
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 */
756 CHECK_EVENT
758 } else {
759 /* 16.2 -> 8.2 */
760 for (j=0;j<sizeof(playbuf);j++) {
761 dsb->playpos=(dsb->playpos+2)%buflen;
762 if (!dsb->playpos && !(dsb->playflags&DSBPLAY_LOOPING)) {
763 dsb->playing = 0;
764 dsb->playpos = buflen;
765 return;
767 /* Insomnia- volume, panning, and correcting against wrap */
768 samp = xbuf[dsb->playpos>>1];
770 /* Right Channel */
771 if(j&1) samp *= Rvoldec;
772 /* Left Channel */
773 else samp *= Lvoldec;
775 samp >>= 24;
776 samp += playbuf8[j];
777 if(samp > 127L) samp = 127L;
778 else if(samp < -128L) samp = -128L;
779 playbuf8[j] = (short)samp;
780 /* End Insomnia's mod */
782 CHECK_EVENT
786 } else { /* 16 bit */
787 if (dsb->wfx.wBitsPerSample == 8) {
788 /* unsigned char *xbuf = (unsigned char*)(dsb->buffer); */
789 char *xbuf = dsb->buffer;
790 if (dsb->wfx.nChannels == 1) {
791 /* 8.1 -> 16.2 */
792 WARN(dsound,"Mixing 8-bit stereo into 16!!\n");
793 for (j=0;j<sizeof(playbuf)/sizeof(playbuf[0])/2;j++) {
794 dsb->playpos=(dsb->playpos+1)%buflen;
795 if (!dsb->playpos && !(dsb->playflags&DSBPLAY_LOOPING)) {
796 dsb->playing = 0;
797 dsb->playpos = buflen;
798 return;
800 /* Insomnia- volume, panning, and correcting against wrap */
801 /* Left Channel */
802 samp = xbuf[dsb->playpos];
803 samp *= Lvoldec;
804 samp >>= 8;
805 samp += playbuf[(j<<1)];
806 if(samp > 32767L) samp = 32767L;
807 else if(samp < -32768L) samp = -32768L;
808 playbuf[(j<<1)] = (short)samp;
810 /* Right Channel */
811 samp = xbuf[dsb->playpos];
812 samp *= Rvoldec;
813 samp >>= 8;
814 samp += playbuf[(j<<1)+1];
815 if(samp > 32767L) samp = 32767L;
816 else if(samp < -32768L) samp = -32768L;
817 playbuf[(j<<1)+1] = (short)samp;
818 /* End Insomnia's mod */
820 CHECK_EVENT
822 } else {
823 /* 8.2 -> 16.2 */
824 for (j=0;j<sizeof(playbuf)/sizeof(playbuf[0]);j++) {
825 dsb->playpos=(dsb->playpos+1)%buflen;
826 if (!dsb->playpos && !(dsb->playflags&DSBPLAY_LOOPING)) {
827 dsb->playing = 0;
828 dsb->playpos = buflen;
829 return;
831 /* Insomnia- volume, panning, and correcting against wrap */
832 samp = xbuf[dsb->playpos];
834 /* Right Channel */
835 if(j&1) samp *= Rvoldec;
836 /* Left Channel */
837 else samp *= Lvoldec;
839 samp >>= 8;
840 samp += playbuf[j];
841 if(samp > 32767L) samp = 32767L;
842 else if(samp < -32768L) samp = -32768L;
843 playbuf[j] = (short)samp;
844 /* End Insomnia's mod */
846 CHECK_EVENT
849 } else { /* 16 */
850 /* 16.1 -> 16.2 */
851 short *xbuf = (short*)(dsb->buffer);
852 if (dsb->wfx.nChannels == 1) {
853 for (j=0;j<sizeof(playbuf)/sizeof(playbuf[0])/2;j++) {
854 dsb->playpos=(dsb->playpos+2)%buflen;
855 if (!dsb->playpos && !(dsb->playflags&DSBPLAY_LOOPING)) {
856 dsb->playing = 0;
857 dsb->playpos = buflen;
858 return;
860 /* Insomnia- volume, panning, and correcting against wrap */
861 /* Left Channel */
862 samp = xbuf[dsb->playpos>>1];
863 samp *= Lvoldec;
864 samp >>= 16;
865 samp += playbuf[(j<<1)];
866 if(samp > 32767L) samp = 32767L;
867 else if(samp < -32768L) samp = -32768L;
868 playbuf[(j<<1)] = (short)samp;
870 /* Right Channel */
871 samp = xbuf[dsb->playpos>>1];
872 samp *= Rvoldec;
873 samp >>= 16;
874 samp += playbuf[(j<<1)+1];
875 if(samp > 32767L) samp = 32767L;
876 else if(samp < -32768L) samp = -32768L;
877 playbuf[(j<<1)+1] = (short)samp;
878 /* End Insomnia's mod */
880 CHECK_EVENT
882 } else {
883 for (j=0;j<sizeof(playbuf)/sizeof(playbuf[0]);j++) {
884 dsb->playpos=(dsb->playpos+2)%buflen;
885 if (!dsb->playpos && !(dsb->playflags&DSBPLAY_LOOPING)) {
886 dsb->playing = 0;
887 dsb->playpos = buflen;
888 return;
890 /* Insomnia- volume, panning, and correcting against wrap */
891 samp = xbuf[dsb->playpos>>1];
893 /* Right Channel */
894 if(j&1) samp *= Rvoldec;
895 /* Left Channel */
896 else samp *= Lvoldec;
898 samp >>= 16;
899 samp += playbuf[j];
900 if(samp > 32767L) samp = 32767L;
901 else if(samp < -32768L) samp = -32768L;
902 playbuf[j] = (short)samp;
903 /* End Insomnia's mod */
905 CHECK_EVENT
912 static DWORD WINAPI
913 DSOUND_thread(LPVOID arg) {
914 int res,i,curleft,playing,haveprimary = 0;
916 TRACE(dsound,"dsound is at pid %d\n",getpid());
917 while (1) {
918 if (!dsound) {
919 WARN(dsound,"DSOUND thread giving up.\n");
920 ExitThread(0);
922 if (getppid()==1) {
923 WARN(dsound,"DSOUND father died? Giving up.\n");
924 ExitThread(0);
926 /* RACE: dsound could be deleted */
927 dsound->lpvtbl->fnAddRef(dsound);
928 if (!dsound->nrofbuffers) {
929 /* no soundbuffer yet... wait. */
930 Sleep(1000);
931 dsound->lpvtbl->fnRelease(dsound);
932 continue;
934 memset(playbuf,0,sizeof(playbuf));
935 playing = 0;
936 haveprimary = 0;
937 for (i=dsound->nrofbuffers;i--;) {
938 IDirectSoundBuffer *dsb = dsound->buffers[i];
940 if (!dsb || !dsb->lpvtbl)
941 continue;
942 dsb->lpvtbl->fnAddRef(dsb);
943 if (dsb->playing && dsb->buflen)
944 playing++;
945 if (dsb->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER) {
946 haveprimary = 1;
947 if (memcmp(&dsound->wfx,&(dsb->wfx),sizeof(dsound->wfx))) {
948 DSOUND_setformat(&(dsb->wfx));
949 memcpy(&dsound->wfx,&(dsb->wfx),sizeof(dsb->wfx));
952 dsb->lpvtbl->fnRelease(dsb);
954 /* We have just one playbuffer, so use its format */
955 if ((playing==1) && !haveprimary) {
956 for (i=dsound->nrofbuffers;i--;) {
957 IDirectSoundBuffer *dsb = dsound->buffers[i];
959 dsb->lpvtbl->fnAddRef(dsb);
960 if (dsb->playing && dsb->buflen) {
961 if (memcmp(&dsound->wfx,&(dsb->wfx),sizeof(dsound->wfx))) {
962 DSOUND_setformat(&(dsb->wfx));
963 memcpy(&dsound->wfx,&(dsb->wfx),sizeof(dsb->wfx));
966 dsb->lpvtbl->fnRelease(dsb);
969 for (i=dsound->nrofbuffers;i--;) {
970 IDirectSoundBuffer *dsb = dsound->buffers[i];
972 if (!dsb || !dsb->lpvtbl)
973 continue;
974 dsb->lpvtbl->fnAddRef(dsb);
975 if (dsb->buflen && dsb->playing)
976 DSOUND_MixInBuffer(dsb);
977 dsb->lpvtbl->fnRelease(dsb);
979 dsound->lpvtbl->fnRelease(dsound);
981 fputc('0'+playing,stderr);
982 curleft = 0;
983 while (curleft < sizeof(playbuf)) {
984 res = write(audiofd,(LPBYTE)playbuf+curleft,sizeof(playbuf)-curleft);
985 if (res==-1) {
986 if (errno==EINTR)
987 continue;
988 perror("write audiofd");
989 ExitThread(0);
990 break;
992 curleft+=res;
995 ExitThread(0);
998 #endif /* HAVE_OSS */
1000 HRESULT WINAPI DirectSoundCreate(LPGUID lpGUID,LPDIRECTSOUND *ppDS,IUnknown *pUnkOuter ) {
1001 int xx;
1002 if (lpGUID)
1003 TRACE(dsound,"(%p,%p,%p)\n",lpGUID,ppDS,pUnkOuter);
1004 #ifdef HAVE_OSS
1005 if (audiofd>=0)
1006 return DSERR_ALLOCATED;
1007 audiofd = open("/dev/audio",O_WRONLY);
1008 if (audiofd==-1) {
1009 perror("open /dev/audio");
1010 audiofd=0;
1011 return DSERR_NODRIVER;
1013 xx=0x0002000c;
1014 if (-1==ioctl(audiofd,SNDCTL_DSP_SETFRAGMENT,&xx))
1015 perror("ioctl SETFRAGMENT");
1017 TRACE(dsound,"SETFRAGMENT. count is now %d, fragsize is %d\n",
1018 (xx>>16)+1,xx&0xffff
1022 *ppDS = (LPDIRECTSOUND)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSound));
1023 (*ppDS)->ref = 1;
1024 (*ppDS)->lpvtbl = &dsvt;
1025 (*ppDS)->buffers = NULL;
1026 (*ppDS)->nrofbuffers = 0;
1028 (*ppDS)->wfx.wFormatTag = 1;
1029 (*ppDS)->wfx.nChannels = 2;
1030 (*ppDS)->wfx.nSamplesPerSec = 22050;
1031 (*ppDS)->wfx.nAvgBytesPerSec = 44100;
1032 (*ppDS)->wfx.nBlockAlign = 2;
1033 (*ppDS)->wfx.wBitsPerSample = 8;
1035 DSOUND_setformat(&((*ppDS)->wfx));
1037 if (!dsound) {
1038 HANDLE32 hnd;
1039 DWORD xid;
1041 dsound = (*ppDS);
1042 hnd = CreateThread(NULL,0,DSOUND_thread,0,0,&xid);
1044 return 0;
1045 #else
1046 MessageBox32A(0,"DirectSound needs the Open Sound System Driver, which has not been found by ./configure.","WINE DirectSound",MB_OK|MB_ICONSTOP);
1047 return DSERR_NODRIVER;
1048 #endif
1052 /*******************************************************************************
1053 * DllGetClassObject [DSOUND.4]
1054 * Retrieves class object from a DLL object
1056 * NOTES
1057 * Docs say returns STDAPI
1059 * PARAMS
1060 * rclsid [I] CLSID for the class object
1061 * riid [I] Reference to identifier of interface for class object
1062 * ppv [O] Address of variable to receive interface pointer for riid
1064 * RETURNS
1065 * Success: S_OK
1066 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
1067 * E_UNEXPECTED
1069 DWORD WINAPI DllGetClassObject( REFCLSID rclsid, REFIID riid, LPVOID *ppv )
1071 FIXME(dsound, "(%p,%p,%p): stub\n", rclsid, riid, ppv);
1072 return S_OK;
1076 /*******************************************************************************
1077 * DllCanUnloadNow [DSOUND.3] Determines whether the DLL is in use.
1079 * RETURNS
1080 * Success: S_OK
1081 * Failure: S_FALSE
1083 DWORD WINAPI DllCanUnloadNow(void)
1085 FIXME(dsound, "(void): stub\n");
1086 return S_FALSE;