Kill swapped out (wine) processes too and truncate diff after some xxx
[wine/multimedia.git] / multimedia / dsound.c
blobb70450103172f9978a53c0f7afc8e7739fe665fb
1 /* DirectSound
2 *
3 * Copyright 1998 Marcus Meissner
4 * Copyright 1998 Rob Riggs
5 */
6 /*
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.
16 * Status:
17 * - Wing Commander 4/W95:
18 * The intromovie plays without problems. Nearly lipsynchron.
19 * - DiscWorld 2
20 * The sound works, but noticeable chunks are left out (from the sound and
21 * the animation). Don't know why yet.
22 * - Diablo:
23 * Sound works, but slows down the movieplayer.
24 * - XvT:
25 * Doesn't sound yet.
26 * - Monkey Island 3:
27 * The background sound of the startscreen works ;)
28 * - WingCommander Prophecy Demo:
29 * Sound works for the intromovie.
32 #include "config.h"
33 #include <assert.h>
34 #include <errno.h>
35 #include <sys/types.h>
36 #include <sys/time.h>
37 #include <sys/fcntl.h>
38 #include <unistd.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <math.h> /* Insomnia - pow() function */
42 #include "windows.h"
43 #include "winerror.h"
44 #include "interfaces.h"
45 #include "mmsystem.h"
46 #include "dsound.h"
47 #include "thread.h"
48 #include "debug.h"
49 #include "xmalloc.h"
51 #ifdef HAVE_OSS
52 # include <sys/ioctl.h>
53 # ifdef HAVE_MACHINE_SOUNDCARD_H
54 # include <machine/soundcard.h>
55 # endif
56 # ifdef HAVE_SYS_SOUNDCARD_H
57 # include <sys/soundcard.h>
58 # endif
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);
76 #endif
78 HRESULT WINAPI DirectSoundEnumerate32A(LPDSENUMCALLBACK32A enumcb,LPVOID context) {
79 #ifdef HAVE_OSS
80 enumcb(NULL,"WINE DirectSound using Open Sound System","sound",context);
81 #endif
82 return 0;
85 #ifdef HAVE_OSS
86 static void _dump_DSBCAPS(DWORD xmask) {
87 struct {
88 DWORD mask;
89 char *name;
90 } flags[] = {
91 #define FE(x) { x, #x },
92 FE(DSBCAPS_PRIMARYBUFFER)
93 FE(DSBCAPS_STATIC)
94 FE(DSBCAPS_LOCHARDWARE)
95 FE(DSBCAPS_LOCSOFTWARE)
96 FE(DSBCAPS_CTRLFREQUENCY)
97 FE(DSBCAPS_CTRLPAN)
98 FE(DSBCAPS_CTRLVOLUME)
99 FE(DSBCAPS_CTRLDEFAULT)
100 FE(DSBCAPS_CTRLALL)
101 FE(DSBCAPS_STICKYFOCUS)
102 FE(DSBCAPS_GETCURRENTPOSITION2)
104 int i;
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
115 // IUnknown methods
116 static HRESULT WINAPI IDirectSound3DBuffer_QueryInterface(
117 LPDIRECTSOUND3DBUFFER this, REFIID riid, LPVOID *ppobj)
119 char xbuf[50];
121 WINE_StringFromCLSID(riid,xbuf);
122 TRACE(dsound,"(%p,%s,%p)\n",this,xbuf,ppobj);
123 return E_FAIL;
126 static ULONG WINAPI IDirectSound3DBuffer_AddRef(LPDIRECTSOUND3DBUFFER this)
128 this->ref++;
129 return this->ref;
132 static ULONG WINAPI IDirectSound3DBuffer_Release(LPDIRECTSOUND3DBUFFER this)
134 if(--this->ref)
135 return this->ref;
137 HeapFree(GetProcessHeap(),0,this->buffer);
138 HeapFree(GetProcessHeap(),0,this);
140 return 0;
143 // IDirectSound3DBuffer methods
144 static HRESULT WINAPI IDirectSound3DBuffer_GetAllParameters(
145 LPDIRECTSOUND3DBUFFER this,
146 LPDS3DBUFFER lpDs3dBuffer)
148 FIXME(dsound,"stub\n");
149 return DS_OK;
152 static HRESULT WINAPI IDirectSound3DBuffer_GetConeAngles(
153 LPDIRECTSOUND3DBUFFER this,
154 LPDWORD lpdwInsideConeAngle,
155 LPDWORD lpdwOutsideConeAngle)
157 FIXME(dsound,"stub\n");
158 return DS_OK;
161 static HRESULT WINAPI IDirectSound3DBuffer_GetConeOrientation(
162 LPDIRECTSOUND3DBUFFER this,
163 LPD3DVECTOR lpvConeOrientation)
165 FIXME(dsound,"stub\n");
166 return DS_OK;
169 static HRESULT WINAPI IDirectSound3DBuffer_GetConeOutsideVolume(
170 LPDIRECTSOUND3DBUFFER this,
171 LPLONG lplConeOutsideVolume)
173 FIXME(dsound,"stub\n");
174 return DS_OK;
177 static HRESULT WINAPI IDirectSound3DBuffer_GetMaxDistance(
178 LPDIRECTSOUND3DBUFFER this,
179 LPD3DVALUE lpfMaxDistance)
181 FIXME(dsound,"stub\n");
182 return DS_OK;
185 static HRESULT WINAPI IDirectSound3DBuffer_GetMinDistance(
186 LPDIRECTSOUND3DBUFFER this,
187 LPD3DVALUE lpfMinDistance)
189 FIXME(dsound,"stub\n");
190 return DS_OK;
193 static HRESULT WINAPI IDirectSound3DBuffer_GetMode(
194 LPDIRECTSOUND3DBUFFER this,
195 LPDWORD lpdwMode)
197 FIXME(dsound,"stub\n");
198 return DS_OK;
201 static HRESULT WINAPI IDirectSound3DBuffer_GetPosition(
202 LPDIRECTSOUND3DBUFFER this,
203 LPD3DVECTOR lpvPosition)
205 FIXME(dsound,"stub\n");
206 return DS_OK;
209 static HRESULT WINAPI IDirectSound3DBuffer_GetVelocity(
210 LPDIRECTSOUND3DBUFFER this,
211 LPD3DVECTOR lpvVelocity)
213 FIXME(dsound,"stub\n");
214 return DS_OK;
217 static HRESULT WINAPI IDirectSound3DBuffer_SetAllParameters(
218 LPDIRECTSOUND3DBUFFER this,
219 LPCDS3DBUFFER lpcDs3dBuffer,
220 DWORD dwApply)
222 FIXME(dsound,"stub\n");
223 return DS_OK;
226 static HRESULT WINAPI IDirectSound3DBuffer_SetConeAngles(
227 LPDIRECTSOUND3DBUFFER this,
228 DWORD dwInsideConeAngle,
229 DWORD dwOutsideConeAngle,
230 DWORD dwApply)
232 FIXME(dsound,"stub\n");
233 return DS_OK;
236 static HRESULT WINAPI IDirectSound3DBuffer_SetConeOrientation(
237 LPDIRECTSOUND3DBUFFER this,
238 D3DVALUE x, D3DVALUE y, D3DVALUE z,
239 DWORD dwApply)
241 FIXME(dsound,"stub\n");
242 return DS_OK;
245 static HRESULT WINAPI IDirectSound3DBuffer_SetConeOutsideVolume(
246 LPDIRECTSOUND3DBUFFER this,
247 LONG lConeOutsideVolume,
248 DWORD dwApply)
250 FIXME(dsound,"stub\n");
251 return DS_OK;
254 static HRESULT WINAPI IDirectSound3DBuffer_SetMaxDistance(
255 LPDIRECTSOUND3DBUFFER this,
256 D3DVALUE fMaxDistance,
257 DWORD dwApply)
259 FIXME(dsound,"stub\n");
260 return DS_OK;
263 static HRESULT WINAPI IDirectSound3DBuffer_SetMinDistance(
264 LPDIRECTSOUND3DBUFFER this,
265 D3DVALUE fMinDistance,
266 DWORD dwApply)
268 FIXME(dsound,"stub\n");
269 return DS_OK;
272 static HRESULT WINAPI IDirectSound3DBuffer_SetMode(
273 LPDIRECTSOUND3DBUFFER this,
274 DWORD dwMode,
275 DWORD dwApply)
277 TRACE(dsound, "mode = %lx\n", dwMode);
278 this->ds3db.dwMode = dwMode;
279 return DS_OK;
282 static HRESULT WINAPI IDirectSound3DBuffer_SetPosition(
283 LPDIRECTSOUND3DBUFFER this,
284 D3DVALUE x, D3DVALUE y, D3DVALUE z,
285 DWORD dwApply)
287 FIXME(dsound,"stub\n");
288 return DS_OK;
291 static HRESULT WINAPI IDirectSound3DBuffer_SetVelocity(
292 LPDIRECTSOUND3DBUFFER this,
293 D3DVALUE x, D3DVALUE y, D3DVALUE z,
294 DWORD dwApply)
296 FIXME(dsound,"stub\n");
297 return DS_OK;
300 IDirectSound3DBuffer_VTable ds3dbvt = {
301 // IUnknown methods
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,
326 #ifdef USE_DSOUND3D
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) {
335 // Convert to mono
336 if (dsb->wfx.wBitsPerSample == 16) {
337 iSize = dsb->buflen / 4;
338 wTbuf = malloc(dsb->buflen / 2);
339 if (wTbuf == NULL)
340 return DSERR_OUTOFMEMORY;
341 for (i = 0; i < iSize; i++)
342 wTbuf[i] = (dsb->buffer[i] + dsb->buffer[(i * 2) + 1]) / 2;
343 wIbuf = wTbuf;
344 } else {
345 iSize = dsb->buflen / 2;
346 bTbuf = malloc(dsb->buflen / 2);
347 if (bTbuf == NULL)
348 return DSERR_OUTOFMEMORY;
349 for (i = 0; i < iSize; i++)
350 bTbuf[i] = (dsb->buffer[i] + dsb->buffer[(i * 2) + 1]) / 2;
351 bIbuf = bTbuf;
353 } else {
354 if (dsb->wfx.wBitsPerSample == 16) {
355 iSize = dsb->buflen / 2;
356 wIbuf = (LPWORD) dsb->buffer;
357 } else {
358 bIbuf = (LPBYTE) dsb->buffer;
359 iSize = dsb->buflen;
363 if (primarybuf->wfx.wBitsPerSample == 16) {
364 wObuf = (LPWORD) dsb->ds3db->buffer;
365 oSize = dsb->ds3db->buflen / 2;
366 } else {
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++) {
374 temp = wIbuf[i];
375 if (i >= offset)
376 temp += wIbuf[i - offset] >> 9;
377 else
378 temp += wIbuf[i + iSize - offset] >> 9;
379 wObuf[i * 2] = temp;
380 wObuf[(i * 2) + 1] = temp;
382 else if (primarybuf->wfx.wBitsPerSample == 8 && dsb->wfx.wBitsPerSample == 8)
383 for (i = 0; i < iSize; i++) {
384 temp = bIbuf[i];
385 if (i >= offset)
386 temp += bIbuf[i - offset] >> 5;
387 else
388 temp += bIbuf[i + iSize - offset] >> 5;
389 bObuf[i * 2] = temp;
390 bObuf[(i * 2) + 1] = temp;
393 if (wTbuf)
394 free(wTbuf);
395 if (bTbuf)
396 free(bTbuf);
398 return DS_OK;
400 #endif
401 /*******************************************************************************
402 * IDirectSound3DListener
405 // IUnknown methods
406 static HRESULT WINAPI IDirectSound3DListener_QueryInterface(
407 LPDIRECTSOUND3DLISTENER this, REFIID riid, LPVOID *ppobj)
409 char xbuf[50];
411 WINE_StringFromCLSID(riid,xbuf);
412 TRACE(dsound,"(%p,%s,%p)\n",this,xbuf,ppobj);
413 return E_FAIL;
416 static ULONG WINAPI IDirectSound3DListener_AddRef(LPDIRECTSOUND3DLISTENER this)
418 this->ref++;
419 return this->ref;
422 static ULONG WINAPI IDirectSound3DListener_Release(LPDIRECTSOUND3DLISTENER this)
424 this->ref--;
425 return this->ref;
428 // IDirectSound3DListener methods
429 static HRESULT WINAPI IDirectSound3DListener_GetAllParameter(
430 LPDIRECTSOUND3DLISTENER this,
431 LPDS3DLISTENER lpDS3DL)
433 FIXME(dsound,"stub\n");
434 return DS_OK;
437 static HRESULT WINAPI IDirectSound3DListener_GetDistanceFactor(
438 LPDIRECTSOUND3DLISTENER this,
439 LPD3DVALUE lpfDistanceFactor)
441 FIXME(dsound,"stub\n");
442 return DS_OK;
445 static HRESULT WINAPI IDirectSound3DListener_GetDopplerFactor(
446 LPDIRECTSOUND3DLISTENER this,
447 LPD3DVALUE lpfDopplerFactor)
449 FIXME(dsound,"stub\n");
450 return DS_OK;
453 static HRESULT WINAPI IDirectSound3DListener_GetOrientation(
454 LPDIRECTSOUND3DLISTENER this,
455 LPD3DVECTOR lpvOrientFront,
456 LPD3DVECTOR lpvOrientTop)
458 FIXME(dsound,"stub\n");
459 return DS_OK;
462 static HRESULT WINAPI IDirectSound3DListener_GetPosition(
463 LPDIRECTSOUND3DLISTENER this,
464 LPD3DVECTOR lpvPosition)
466 FIXME(dsound,"stub\n");
467 return DS_OK;
470 static HRESULT WINAPI IDirectSound3DListener_GetRolloffFactor(
471 LPDIRECTSOUND3DLISTENER this,
472 LPD3DVALUE lpfRolloffFactor)
474 FIXME(dsound,"stub\n");
475 return DS_OK;
478 static HRESULT WINAPI IDirectSound3DListener_GetVelocity(
479 LPDIRECTSOUND3DLISTENER this,
480 LPD3DVECTOR lpvVelocity)
482 FIXME(dsound,"stub\n");
483 return DS_OK;
486 static HRESULT WINAPI IDirectSound3DListener_SetAllParameters(
487 LPDIRECTSOUND3DLISTENER this,
488 LPCDS3DLISTENER lpcDS3DL,
489 DWORD dwApply)
491 FIXME(dsound,"stub\n");
492 return DS_OK;
495 static HRESULT WINAPI IDirectSound3DListener_SetDistanceFactor(
496 LPDIRECTSOUND3DLISTENER this,
497 D3DVALUE fDistanceFactor,
498 DWORD dwApply)
500 FIXME(dsound,"stub\n");
501 return DS_OK;
504 static HRESULT WINAPI IDirectSound3DListener_SetDopplerFactor(
505 LPDIRECTSOUND3DLISTENER this,
506 D3DVALUE fDopplerFactor,
507 DWORD dwApply)
509 FIXME(dsound,"stub\n");
510 return DS_OK;
513 static HRESULT WINAPI IDirectSound3DListener_SetOrientation(
514 LPDIRECTSOUND3DLISTENER this,
515 D3DVALUE xFront, D3DVALUE yFront, D3DVALUE zFront,
516 D3DVALUE xTop, D3DVALUE yTop, D3DVALUE zTop,
517 DWORD dwApply)
519 FIXME(dsound,"stub\n");
520 return DS_OK;
523 static HRESULT WINAPI IDirectSound3DListener_SetPosition(
524 LPDIRECTSOUND3DLISTENER this,
525 D3DVALUE x, D3DVALUE y, D3DVALUE z,
526 DWORD dwApply)
528 FIXME(dsound,"stub\n");
529 return DS_OK;
532 static HRESULT WINAPI IDirectSound3DListener_SetRolloffFactor(
533 LPDIRECTSOUND3DLISTENER this,
534 D3DVALUE fRolloffFactor,
535 DWORD dwApply)
537 FIXME(dsound,"stub\n");
538 return DS_OK;
541 static HRESULT WINAPI IDirectSound3DListener_SetVelocity(
542 LPDIRECTSOUND3DLISTENER this,
543 D3DVALUE x, D3DVALUE y, D3DVALUE z,
544 DWORD dwApply)
546 FIXME(dsound,"stub\n");
547 return DS_OK;
550 static HRESULT WINAPI IDirectSound3DListener_CommitDeferredSettings(
551 LPDIRECTSOUND3DLISTENER this)
554 FIXME(dsound,"stub\n");
555 return DS_OK;
558 IDirectSound3DListener_VTable ds3dlvt = {
559 // IUnknown methods
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 /*******************************************************************************
582 * IDirectSoundNotify
584 static HRESULT WINAPI IDirectSoundNotify_QueryInterface(
585 LPDIRECTSOUNDNOTIFY this,REFIID riid,LPVOID *ppobj
587 char xbuf[50];
589 WINE_StringFromCLSID(riid,xbuf);
590 TRACE(dsound,"(%p,%s,%p)\n",this,xbuf,ppobj);
591 return E_FAIL;
594 static ULONG WINAPI IDirectSoundNotify_AddRef(LPDIRECTSOUNDNOTIFY this) {
595 return ++(this->ref);
598 static ULONG WINAPI IDirectSoundNotify_Release(LPDIRECTSOUNDNOTIFY this) {
599 this->ref--;
600 if (!this->ref) {
601 this->dsb->lpvtbl->fnRelease(this->dsb);
602 HeapFree(GetProcessHeap(),0,this);
603 return 0;
605 return this->ref;
608 static HRESULT WINAPI IDirectSoundNotify_SetNotificationPositions(
609 LPDIRECTSOUNDNOTIFY this,DWORD howmuch,LPCDSBPOSITIONNOTIFY notify
611 int i;
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,
621 notify,
622 howmuch*sizeof(DSBPOSITIONNOTIFY)
624 this->dsb->nrofnotifies+=howmuch;
626 return 0;
629 IDirectSoundNotify_VTable dsnvt = {
630 IDirectSoundNotify_QueryInterface,
631 IDirectSoundNotify_AddRef,
632 IDirectSoundNotify_Release,
633 IDirectSoundNotify_SetNotificationPositions,
636 /*******************************************************************************
637 * IDirectSoundBuffer
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;
646 int i;
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;
659 // ****
660 EnterCriticalSection(&(primarybuf->lock));
662 if (primarybuf->wfx.nSamplesPerSec != wfex->nSamplesPerSec) {
663 dsb = dsound->buffers;
664 for (i = 0; i < dsound->nrofbuffers; i++, dsb++) {
665 // ****
666 EnterCriticalSection(&((*dsb)->lock));
668 (*dsb)->freqAdjust = ((*dsb)->freq << DSOUND_FREQSHIFT) /
669 wfex->nSamplesPerSec;
671 LeaveCriticalSection(&((*dsb)->lock));
672 // ****
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;
687 DSOUND_CloseAudio();
689 LeaveCriticalSection(&(primarybuf->lock));
690 // ****
692 return DS_OK;
695 static HRESULT WINAPI IDirectSoundBuffer_SetVolume(
696 LPDIRECTSOUNDBUFFER this,LONG vol
698 double temp;
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");
713 this->volume = vol;
714 return DS_OK;
717 // ****
718 EnterCriticalSection(&(this->lock));
720 this->volume = vol;
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));
728 // ****
730 TRACE(dsound, "left = %lx, right = %lx\n", this->lVolAdjust, this->rVolAdjust);
732 return DS_OK;
735 static HRESULT WINAPI IDirectSoundBuffer_GetVolume(
736 LPDIRECTSOUNDBUFFER this,LPLONG vol
738 TRACE(dsound,"(%p,%p)\n",this,vol);
740 if (vol == NULL)
741 return DSERR_INVALIDPARAM;
743 *vol = this->volume;
744 return DS_OK;
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;
760 // ****
761 EnterCriticalSection(&(this->lock));
763 this->freq = freq;
764 this->freqAdjust = (freq << DSOUND_FREQSHIFT) / primarybuf->wfx.nSamplesPerSec;
765 this->nAvgBytesPerSec = freq * this->wfx.nBlockAlign;
767 LeaveCriticalSection(&(this->lock));
768 // ****
770 return DS_OK;
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;
780 this->playing = 1;
781 return DS_OK;
784 static HRESULT WINAPI IDirectSoundBuffer_Stop(LPDIRECTSOUNDBUFFER this)
786 TRACE(dsound,"(%p)\n",this);
788 // ****
789 EnterCriticalSection(&(this->lock));
791 this->playing = 0;
792 DSOUND_CheckEvent(this, 0);
794 LeaveCriticalSection(&(this->lock));
795 // ****
797 return DS_OK;
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) {
806 int i;
808 // TRACE(dsound,"(%p) ref was %ld\n",this, this->ref);
810 if (--this->ref)
811 return this->ref;
813 for (i=0;i<this->dsound->nrofbuffers;i++)
814 if (this->dsound->buffers[i] == this)
815 break;
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)
833 primarybuf = NULL;
835 return DS_OK;
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;
844 return DS_OK;
847 static HRESULT WINAPI IDirectSoundBuffer_GetStatus(
848 LPDIRECTSOUNDBUFFER this,LPDWORD status
850 TRACE(dsound,"(%p,%p)\n",this,status);
852 if (status == NULL)
853 return DSERR_INVALIDPARAM;
855 *status = 0;
856 if (this->playing)
857 *status |= DSBSTATUS_PLAYING;
858 if (this->playflags & DSBPLAY_LOOPING)
859 *status |= DSBSTATUS_LOOPING;
861 return DS_OK;
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);
874 if (wfwritten)
875 *wfwritten = wfsize;
876 } else
877 if (wfwritten)
878 *wfwritten = sizeof(this->wfx);
879 else
880 return DSERR_INVALIDPARAM;
882 return DS_OK;
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",
890 this,
891 writecursor,
892 writebytes,
893 lplpaudioptr1,
894 audiobytes1,
895 lplpaudioptr2,
896 audiobytes2,
897 flags
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;
911 if (lplpaudioptr2)
912 *(LPBYTE*)lplpaudioptr2 = NULL;
913 if (audiobytes2)
914 *audiobytes2 = 0;
915 TRACE(dsound,"->%ld.0\n",writebytes);
916 } else {
917 *(LPBYTE*)lplpaudioptr1 = this->buffer+writecursor;
918 *audiobytes1 = this->buflen-writecursor;
919 if (lplpaudioptr2)
920 *(LPBYTE*)lplpaudioptr2 = this->buffer;
921 if (audiobytes2)
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;
927 return DS_OK;
930 static HRESULT WINAPI IDirectSoundBuffer_SetCurrentPosition(
931 LPDIRECTSOUNDBUFFER this,DWORD newpos
933 TRACE(dsound,"(%p,%ld)\n",this,newpos);
935 // ****
936 EnterCriticalSection(&(this->lock));
938 this->playpos = newpos;
940 LeaveCriticalSection(&(this->lock));
941 // ****
943 return 0;
946 static HRESULT WINAPI IDirectSoundBuffer_SetPan(
947 LPDIRECTSOUNDBUFFER this,LONG pan
949 double temp;
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;
963 // ****
964 EnterCriticalSection(&(this->lock));
966 this->pan = pan;
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));
974 // ****
976 return DS_OK;
979 static HRESULT WINAPI IDirectSoundBuffer_GetPan(
980 LPDIRECTSOUNDBUFFER this,LPLONG pan
982 TRACE(dsound,"(%p,%p)\n",this,pan);
984 if (pan == NULL)
985 return DSERR_INVALIDPARAM;
987 *pan = this->pan;
989 return DS_OK;
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.
1003 #if 0
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);
1009 #endif
1011 return DS_OK;
1014 static HRESULT WINAPI IDirectSoundBuffer_GetFrequency(
1015 LPDIRECTSOUNDBUFFER this,LPDWORD freq
1017 TRACE(dsound,"(%p,%p)\n",this,freq);
1019 if (freq == NULL)
1020 return DSERR_INVALIDPARAM;
1022 *freq = this->freq;
1024 return DS_OK;
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);
1040 if (caps == NULL)
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;
1055 return DS_OK;
1058 static HRESULT WINAPI IDirectSoundBuffer_QueryInterface(
1059 LPDIRECTSOUNDBUFFER this,REFIID riid,LPVOID *ppobj
1061 char xbuf[50];
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));
1070 dsn->ref = 1;
1071 dsn->dsb = this;
1072 this->lpvtbl->fnAddRef(this);
1073 dsn->lpvtbl = &dsnvt;
1074 *ppobj = (LPVOID)dsn;
1075 return 0;
1078 if (!memcmp(&IID_IDirectSound3DBuffer,riid,sizeof(*riid))) {
1079 *ppobj = this->ds3db;
1080 if (*ppobj)
1081 return DS_OK;
1084 return E_FAIL;
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 /*******************************************************************************
1111 * IDirectSound
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);
1118 return 0;
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;
1141 if (wfex)
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) {
1149 if (primarybuf) {
1150 primarybuf->lpvtbl->fnAddRef(primarybuf);
1151 *ppdsb = primarybuf;
1152 return DS_OK;
1153 } // Else create primarybuf
1156 *ppdsb = (LPDIRECTSOUNDBUFFER)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectSoundBuffer));
1157 if (*ppdsb == NULL)
1158 return DSERR_OUTOFMEMORY;
1159 (*ppdsb)->ref = 1;
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;
1166 } else {
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));
1173 *ppdsb = NULL;
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));
1208 #if 0
1209 if (dsbd->dwFlags & DSBCAPS_CTRL3D) {
1210 IDirectSound3DBuffer *ds3db;
1212 ds3db = (LPDIRECTSOUND3DBUFFER)HeapAlloc(GetProcessHeap(),
1213 0,sizeof(*ds3db));
1214 ds3db->ref = 1;
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) {
1238 ds3db->buflen = 0;
1239 ds3db->ds3db.dwMode = DS3DMODE_DISABLE;
1242 #endif
1243 return DS_OK;
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));
1253 (*ppdsb)->ref =1;
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);
1267 return 0;
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);
1275 if (caps == NULL)
1276 return DSERR_INVALIDPARAM;
1278 // We should check this value, not set it. See Inside DirectX, p215.
1279 caps->dwSize = sizeof(*caps);
1281 caps->dwFlags =
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%
1319 return 0;
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);
1333 dsound = NULL;
1334 return 0;
1336 return this->ref;
1339 static HRESULT WINAPI IDirectSound_SetSpeakerConfig(
1340 LPDIRECTSOUND this,DWORD config
1342 FIXME(dsound,"(%p,0x%08lx):stub\n",this,config);
1343 return 0;
1346 static HRESULT WINAPI IDirectSound_QueryInterface(
1347 LPDIRECTSOUND this,REFIID riid,LPVOID *ppobj
1349 char xbuf[50];
1351 if (!memcmp(&IID_IDirectSound3DListener,riid,sizeof(*riid))) {
1353 if (this->listener) {
1354 *ppobj = this->listener;
1355 return DS_OK;
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;
1379 return DS_OK;
1382 WINE_StringFromCLSID(riid,xbuf);
1383 TRACE(dsound,"(%p,%s,%p)\n",this,xbuf,ppobj);
1384 return E_FAIL;
1387 static HRESULT WINAPI IDirectSound_Compact(
1388 LPDIRECTSOUND this)
1390 TRACE(dsound, "(%p)\n", this);
1391 return DS_OK;
1394 static HRESULT WINAPI IDirectSound_GetSpeakerConfig(
1395 LPDIRECTSOUND this,
1396 LPDWORD lpdwSpeakerConfig)
1398 TRACE(dsound, "(%p, %p)\n", this, lpdwSpeakerConfig);
1399 *lpdwSpeakerConfig = DSSPEAKER_STEREO | (DSSPEAKER_GEOMETRY_NARROW << 16);
1400 return DS_OK;
1403 static HRESULT WINAPI IDirectSound_Initialize(
1404 LPDIRECTSOUND this,
1405 LPGUID lpGuid)
1407 TRACE(dsound, "(%p, %p)\n", this, lpGuid);
1408 return DS_OK;
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
1425 static int
1426 DSOUND_setformat(LPWAVEFORMATEX wfex) {
1427 int xx,channels,speed,format,nformat;
1429 if (!audioOK) {
1430 TRACE(dsound, "(%p) deferred\n", wfex);
1431 return 0;
1433 switch (wfex->wFormatTag) {
1434 default:
1435 WARN(dsound,"unknown WAVE_FORMAT tag %d\n",wfex->wFormatTag);
1436 return DSERR_BADFORMAT;
1437 case WAVE_FORMAT_PCM:
1438 break;
1440 if (wfex->wBitsPerSample==8)
1441 format = AFMT_U8;
1442 else
1443 format = AFMT_S16_LE;
1445 if (-1==ioctl(audiofd,SNDCTL_DSP_GETFMTS,&xx)) {
1446 perror("ioctl SNDCTL_DSP_GETFMTS");
1447 return -1;
1449 if ((xx&format)!=format) {/* format unsupported */
1450 FIXME(dsound,"SNDCTL_DSP_GETFMTS: format not supported\n");
1451 return -1;
1453 nformat = format;
1454 if (-1==ioctl(audiofd,SNDCTL_DSP_SETFMT,&nformat)) {
1455 perror("ioctl SNDCTL_DSP_SETFMT");
1456 return -1;
1458 if (nformat!=format) {/* didn't work */
1459 FIXME(dsound,"SNDCTL_DSP_GETFMTS: format not set\n");
1460 return -1;
1463 channels = wfex->nChannels-1;
1464 if (-1==ioctl(audiofd,SNDCTL_DSP_STEREO,&channels)) {
1465 perror("ioctl SNDCTL_DSP_STEREO");
1466 return -1;
1468 speed = wfex->nSamplesPerSec;
1469 if (-1==ioctl(audiofd,SNDCTL_DSP_SPEED,&speed)) {
1470 perror("ioctl SNDCTL_DSP_SPEED");
1471 return -1;
1473 TRACE(dsound,"(freq=%ld,channels=%d,bits=%d)\n",
1474 wfex->nSamplesPerSec,wfex->nChannels,wfex->wBitsPerSample
1476 return 0;
1479 static void DSOUND_CheckEvent(IDirectSoundBuffer *dsb, int len)
1481 int i;
1482 DWORD offset;
1483 LPDSBPOSITIONNOTIFY event;
1485 if (dsb->nrofnotifies == 0)
1486 return;
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);
1504 return;
1505 } else
1506 return;
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);
1514 } else {
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;
1537 return s;
1540 static inline BYTE cvtS16toU8(INT16 word)
1542 BYTE b = (word + 32768) >> 8;
1544 return b;
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));
1559 return;
1562 if ((dsb->wfx.wBitsPerSample == 16) && dsb->wfx.nChannels == 2) {
1563 *fl = *bufs;
1564 *fr = *(bufs + 1);
1565 return;
1568 if ((dsb->wfx.wBitsPerSample == 8) && dsb->wfx.nChannels == 1) {
1569 *fl = cvtU8toS16(*buf);
1570 *fr = *fl;
1571 return;
1574 if ((dsb->wfx.wBitsPerSample == 16) && dsb->wfx.nChannels == 1) {
1575 *fl = *bufs;
1576 *fr = *bufs;
1577 return;
1580 FIXME(dsound, "get_fields found an unsupported configuration\n");
1581 return;
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);
1591 return;
1594 if ((primarybuf->wfx.wBitsPerSample == 16) && (primarybuf->wfx.nChannels == 2)) {
1595 *bufs = fl;
1596 *(bufs + 1) = fr;
1597 return;
1600 if ((primarybuf->wfx.wBitsPerSample == 8) && (primarybuf->wfx.nChannels == 1)) {
1601 *buf = cvtS16toU8((fl + fr) >> 1);
1602 return;
1605 if ((primarybuf->wfx.wBitsPerSample == 16) && (primarybuf->wfx.nChannels == 1)) {
1606 *bufs = (fl + fr) >> 1;
1607 return;
1609 FIXME(dsound, "set_fields found an unsupported configuration\n");
1610 return;
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;
1617 BYTE *ibp, *obp;
1618 INT32 iAdvance = dsb->wfx.nBlockAlign;
1619 INT32 oAdvance = primarybuf->wfx.nBlockAlign;
1621 ibp = dsb->buffer + dsb->playpos;
1622 obp = buf;
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);
1632 else { // wrap
1633 memcpy(obp, ibp, dsb->buflen - dsb->playpos);
1634 memcpy(obp + (dsb->buflen - dsb->playpos),
1635 dsb->buffer,
1636 len - (dsb->buflen - dsb->playpos));
1638 return len;
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);
1645 ilen = 0;
1646 for (i = 0; i < len; i += oAdvance) {
1647 get_fields(dsb, ibp, &fieldL, &fieldR);
1648 ibp += iAdvance;
1649 ilen += iAdvance;
1650 set_fields(obp, fieldL, fieldR);
1651 obp += oAdvance;
1652 if (ibp >= (BYTE *)(dsb->buffer + dsb->buflen))
1653 ibp = dsb->buffer; // wrap
1655 return (ilen);
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);
1677 obp += oAdvance;
1679 return ilen;
1682 static void DSOUND_MixerVol(IDirectSoundBuffer *dsb, BYTE *buf, INT32 len)
1684 INT32 i, inc = primarybuf->wfx.wBitsPerSample >> 3;
1685 BYTE *bpc = buf;
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) {
1700 INT32 val;
1702 switch (inc) {
1704 case 1:
1705 // 8-bit WAV is unsigned, but we need to operate
1706 // on signed data for this to work properly
1707 val = *bpc - 128;
1708 val = ((val * (i & inc ? dsb->rVolAdjust : dsb->lVolAdjust)) >> 15);
1709 *bpc = val + 128;
1710 bpc++;
1711 break;
1712 case 2:
1713 // 16-bit WAV is signed -- much better
1714 val = *bps;
1715 val = ((val * ((i & inc) ? dsb->rVolAdjust : dsb->lVolAdjust)) >> 15);
1716 *bps = val;
1717 bps++;
1718 break;
1719 default:
1720 // Very ugly!
1721 FIXME(dsound, "MixerVol had a nasty error\n");
1726 #ifdef USE_DSOUND3D
1727 static void DSOUND_Mixer3D(IDirectSoundBuffer *dsb, BYTE *buf, INT32 len)
1729 BYTE *ibp, *obp;
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;
1735 obp = buf;
1737 if (playpos > buflen) {
1738 FIXME(dsound, "Major breakage");
1739 return;
1742 if (len <= (playpos + buflen))
1743 memcpy(obp, ibp, len);
1744 else { // wrap
1745 memcpy(obp, ibp, buflen - playpos);
1746 memcpy(obp + (buflen - playpos),
1747 dsb->buffer,
1748 len - (buflen - playpos));
1750 return;
1752 #endif
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
1771 if (len == 0) {
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);
1776 // Stop
1777 dsb->playing = 0;
1778 dsb->writepos = 0;
1779 dsb->playpos = 0;
1780 // Check for DSBPN_OFFSETSTOP
1781 DSOUND_CheckEvent(dsb, 0);
1782 return 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)
1788 return 0;
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;
1808 } else {
1809 // 16-bit WAV is signed
1810 field = *ibufs;
1811 field += *obufs;
1812 field = field > 32767 ? 32767 : field;
1813 field = field < -32768 ? -32768 : field;
1814 *obufs = field;
1816 ibuf += advance;
1817 obuf += advance;
1818 if (obuf >= (BYTE *)(primarybuf->buffer + primarybuf->buflen))
1819 obuf = primarybuf->buffer;
1821 free(buf);
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)) {
1831 dsb->playing = 0;
1832 dsb->writepos = 0;
1833 dsb->playpos = 0;
1834 DSOUND_CheckEvent(dsb, 0); // For DSBPN_OFFSETSTOP
1835 } else
1836 dsb->playpos %= dsb->buflen; // wrap
1839 if (dsb->writepos >= dsb->buflen)
1840 dsb->writepos %= dsb->buflen;
1842 return len;
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))
1854 continue;
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);
1865 return maxlen;
1868 static int DSOUND_OpenAudio(void)
1870 int audioFragment;
1872 if (primarybuf == NULL)
1873 return DSERR_OUTOFMEMORY;
1875 while (audiofd != -1)
1876 sleep(5);
1877 audiofd = open("/dev/audio",O_WRONLY);
1878 if (audiofd==-1) {
1879 // Don't worry if sound is busy at the moment
1880 if (errno != EBUSY)
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");
1890 audioOK = 1;
1891 DSOUND_setformat(&(primarybuf->wfx));
1893 return 0;
1896 static void DSOUND_CloseAudio(void)
1898 int neutral;
1900 neutral = primarybuf->wfx.wBitsPerSample == 8 ? 128 : 0;
1901 audioOK = 0; // race condition
1902 Sleep(5);
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
1906 if (audiofd != -1)
1907 close(audiofd);
1908 primarybuf->playpos = 0;
1909 primarybuf->writepos = DSOUND_FRAGLEN;
1910 memset(primarybuf->buffer, neutral, primarybuf->buflen);
1911 audiofd = -1;
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);
1921 if (result == -1)
1922 if (errno == EINTR)
1923 continue;
1924 else
1925 return result;
1926 left += result;
1928 return 0;
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;
1941 // ****
1942 EnterCriticalSection(&(primarybuf->lock));
1944 // Write out the
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));
1954 ExitThread(0);
1956 memset(frag1, neutral, flen1);
1957 if (DSOUND_WriteAudio(frag2, flen2) != 0) {
1958 perror("DSOUND_WriteAudio");
1959 LeaveCriticalSection(&(primarybuf->lock));
1960 ExitThread(0);
1962 memset(frag2, neutral, flen2);
1963 } else {
1964 frag1 = primarybuf->buffer + primarybuf->playpos;
1965 flen1 = len;
1966 if (DSOUND_WriteAudio(frag1, flen1) != 0) {
1967 perror("DSOUND_WriteAudio");
1968 LeaveCriticalSection(&(primarybuf->lock));
1969 ExitThread(0);
1971 memset(frag1, neutral, flen1);
1973 } else {
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()
1976 // to /dev/audio
1977 Sleep(60);
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));
1987 // ****
1990 static DWORD WINAPI DSOUND_thread(LPVOID arg)
1992 int len;
1994 TRACE(dsound,"dsound is at pid %d\n",getpid());
1995 while (1) {
1996 if (!dsound) {
1997 WARN(dsound,"DSOUND thread giving up.\n");
1998 ExitThread(0);
2000 if (getppid()==1) {
2001 WARN(dsound,"DSOUND father died? Giving up.\n");
2002 ExitThread(0);
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);
2010 ExitThread(0);
2013 // ****
2014 EnterCriticalSection(&(primarybuf->lock));
2015 len = DSOUND_MixPrimary();
2016 LeaveCriticalSection(&(primarybuf->lock));
2017 // ****
2019 if (primarybuf->playing)
2020 len = DSOUND_FRAGLEN > len ? DSOUND_FRAGLEN : len;
2021 if (len) {
2022 // This does all the work
2023 DSOUND_OutputPrimary(len);
2024 } else {
2025 // no buffers playing -- close and wait
2026 if (audioOK)
2027 DSOUND_CloseAudio();
2028 Sleep(100);
2030 dsound->lpvtbl->fnRelease(dsound);
2032 ExitThread(0);
2035 #endif /* HAVE_OSS */
2037 HRESULT WINAPI DirectSoundCreate(LPGUID lpGUID,LPDIRECTSOUND *ppDS,IUnknown *pUnkOuter )
2039 if (lpGUID)
2040 TRACE(dsound,"(%p,%p,%p)\n",lpGUID,ppDS,pUnkOuter);
2041 else
2042 TRACE(dsound,"DirectSoundCreate (%p)\n", ppDS);
2044 #ifdef HAVE_OSS
2046 if (ppDS == NULL)
2047 return DSERR_INVALIDPARAM;
2049 if (primarybuf) {
2050 dsound->lpvtbl->fnAddRef(dsound);
2051 *ppDS = dsound;
2052 return DS_OK;
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");
2066 } else {
2067 TRACE(dsound, "Unexpected error while checking for sound support\n");
2068 return DSERR_GENERIC;
2070 } else {
2071 close(audiofd);
2072 audiofd = -1;
2075 *ppDS = (LPDIRECTSOUND)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSound));
2076 if (*ppDS == NULL)
2077 return DSERR_OUTOFMEMORY;
2079 (*ppDS)->ref = 1;
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;
2091 if (!dsound) {
2092 HANDLE32 hnd;
2093 DWORD xid;
2095 dsound = (*ppDS);
2096 if (primarybuf == NULL) {
2097 DSBUFFERDESC dsbd;
2098 HRESULT hr;
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);
2105 if (hr != DS_OK)
2106 return hr;
2107 dsound->primary = primarybuf;
2109 memset(primarybuf->buffer, 128, primarybuf->buflen);
2110 hnd = CreateThread(NULL,0,DSOUND_thread,0,0,&xid);
2112 return DS_OK;
2113 #else
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;
2116 #endif
2119 /*******************************************************************************
2120 * DirectSound ClassFactory
2122 static HRESULT WINAPI
2123 DSCF_QueryInterface(LPCLASSFACTORY this,REFIID riid,LPVOID *ppobj) {
2124 char buf[80];
2126 if (HIWORD(riid))
2127 WINE_StringFromCLSID(riid,buf);
2128 else
2129 sprintf(buf,"<guid-0x%04x>",LOWORD(riid));
2130 FIXME(dsound,"(%p)->(%s,%p),stub!\n",this,buf,ppobj);
2131 return E_NOINTERFACE;
2134 static ULONG WINAPI
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
2147 char buf[80];
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);
2160 return S_OK;
2163 static IClassFactory_VTable DSCF_VTable = {
2164 DSCF_QueryInterface,
2165 DSCF_AddRef,
2166 DSCF_Release,
2167 DSCF_CreateInstance,
2168 DSCF_LockServer
2170 static IClassFactory DSOUND_CF = {&DSCF_VTable, 1 };
2172 /*******************************************************************************
2173 * DllGetClassObject [DSOUND.4]
2174 * Retrieves class object from a DLL object
2176 * NOTES
2177 * Docs say returns STDAPI
2179 * PARAMS
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
2184 * RETURNS
2185 * Success: S_OK
2186 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
2187 * E_UNEXPECTED
2189 DWORD WINAPI DSOUND_DllGetClassObject(REFCLSID rclsid,REFIID riid,LPVOID *ppv)
2191 char buf[80],xbuf[80];
2193 if (HIWORD(rclsid))
2194 WINE_StringFromCLSID(rclsid,xbuf);
2195 else
2196 sprintf(xbuf,"<guid-0x%04x>",LOWORD(rclsid));
2197 if (HIWORD(riid))
2198 WINE_StringFromCLSID(riid,buf);
2199 else
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);
2206 return S_OK;
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.
2216 * RETURNS
2217 * Success: S_OK
2218 * Failure: S_FALSE
2220 DWORD WINAPI DSOUND_DllCanUnloadNow(void)
2222 FIXME(dsound, "(void): stub\n");
2223 return S_FALSE;