3 * Copyright 1998 Marcus Meissner
4 * Copyright 1998 Rob Riggs
7 * Note: This file requires multithread ability. It is not possible to
8 * implement the stuff in a single thread anyway. And most DirectX apps
9 * require threading themselves.
11 * Most thread locking is complete. There may be a few race
12 * conditions still lurking.
14 * Tested with a Soundblaster clone, a Gravis UltraSound Classic,
15 * and a Turtle Beach Tropez+.
18 * Implement DirectSoundCapture API
19 * Implement SetCooperativeLevel properly (need to address focus issues)
20 * Use wavetable synth for static buffers if available
21 * Implement DirectSound3DBuffers (stubs in place)
22 * Use hardware 3D support if available (OSS support may be needed first)
23 * Add support for APIs other than OSS: ALSA (http://alsa.jcu.cz/)
24 * and esound (http://www.gnome.org), for instance
26 * FIXME: Status needs updating.
29 * - Wing Commander 4/W95:
30 * The intromovie plays without problems. Nearly lipsynchron.
32 * The sound works, but noticeable chunks are left out (from the sound and
33 * the animation). Don't know why yet.
35 * Sound works, but slows down the movieplayer.
39 * The background sound of the startscreen works ;)
40 * - WingCommander Prophecy Demo:
41 * Sound works for the intromovie.
42 * - Total Annihilation (1998/12/04):
43 * Sound plays perfectly in the game, but the Smacker movies
44 * (http://www.smacker.com/) play silently.
45 * - A-10 Cuba! Demo (1998/12/04):
46 * Sound works properly (for some people).
47 * - dsstream.exe, from DirectX 5.2 SDK (1998/12/04):
48 * Works properly, but requires "-dll -winmm".
49 * - dsshow.exe, from DirectX 5.2 SDK (1998/12/04):
50 * Initializes the DLL properly with CoCreateInstance(), but the
51 * FileOpen dialog box is broken - could not test properly
57 #include <sys/types.h>
59 #include <sys/fcntl.h>
63 #include <math.h> /* Insomnia - pow() function */
67 #include "wine/obj_base.h"
69 #include "debugtools.h"
71 DEFAULT_DEBUG_CHANNEL(dsound)
74 /*****************************************************************************
75 * Predeclare the interface implementation structures
77 typedef struct IDirectSoundImpl IDirectSoundImpl;
78 typedef struct IDirectSoundBufferImpl IDirectSoundBufferImpl;
79 typedef struct IDirectSoundNotifyImpl IDirectSoundNotifyImpl;
80 typedef struct IDirectSound3DListenerImpl IDirectSound3DListenerImpl;
81 typedef struct IDirectSound3DBufferImpl IDirectSound3DBufferImpl;
83 /*****************************************************************************
84 * IDirectSound implementation structure
86 struct IDirectSoundImpl
89 ICOM_VFIELD(IDirectSound);
91 /* IDirectSoundImpl fields */
94 IDirectSoundBufferImpl** buffers;
95 IDirectSoundBufferImpl* primary;
96 IDirectSound3DListenerImpl* listener;
97 WAVEFORMATEX wfx; /* current main waveformat */
100 /*****************************************************************************
101 * IDirectSoundBuffer implementation structure
103 struct IDirectSoundBufferImpl
105 /* IUnknown fields */
106 ICOM_VFIELD(IDirectSoundBuffer);
108 /* IDirectSoundBufferImpl fields */
111 IDirectSound3DBufferImpl* ds3db;
112 DWORD playflags,playing;
113 DWORD playpos,writepos,buflen;
114 DWORD nAvgBytesPerSec;
118 LONG lVolAdjust,rVolAdjust;
119 IDirectSoundBufferImpl* parent; /* for duplicates */
120 IDirectSoundImpl* dsound;
122 LPDSBPOSITIONNOTIFY notifies;
124 CRITICAL_SECTION lock;
127 /*****************************************************************************
128 * IDirectSoundNotify implementation structure
130 struct IDirectSoundNotifyImpl
132 /* IUnknown fields */
133 ICOM_VFIELD(IDirectSoundNotify);
135 /* IDirectSoundNotifyImpl fields */
136 IDirectSoundBufferImpl* dsb;
139 /*****************************************************************************
140 * IDirectSound3DListener implementation structure
142 struct IDirectSound3DListenerImpl
144 /* IUnknown fields */
145 ICOM_VFIELD(IDirectSound3DListener);
147 /* IDirectSound3DListenerImpl fields */
148 IDirectSoundBufferImpl* dsb;
150 CRITICAL_SECTION lock;
153 /*****************************************************************************
154 * IDirectSound3DBuffer implementation structure
156 struct IDirectSound3DBufferImpl
158 /* IUnknown fields */
159 ICOM_VFIELD(IDirectSound3DBuffer);
161 /* IDirectSound3DBufferImpl fields */
162 IDirectSoundBufferImpl* dsb;
166 CRITICAL_SECTION lock;
171 # include <sys/ioctl.h>
172 # ifdef HAVE_MACHINE_SOUNDCARD_H
173 # include <machine/soundcard.h>
175 # ifdef HAVE_SYS_SOUNDCARD_H
176 # include <sys/soundcard.h>
178 # ifdef HAVE_SOUNDCARD_H
179 # include <soundcard.h>
182 /* #define USE_DSOUND3D 1 */
184 #define DSOUND_FRAGLEN (primarybuf->wfx.nAvgBytesPerSec >> 4)
185 #define DSOUND_FREQSHIFT (14)
187 static int audiofd = -1;
188 static int audioOK = 0;
190 static IDirectSoundImpl* dsound = NULL;
192 static IDirectSoundBufferImpl* primarybuf = NULL;
194 static int DSOUND_setformat(LPWAVEFORMATEX wfex);
195 static void DSOUND_CheckEvent(IDirectSoundBufferImpl *dsb, int len);
196 static void DSOUND_CloseAudio(void);
201 HRESULT WINAPI DirectSoundEnumerateA(
202 LPDSENUMCALLBACKA enumcb,
205 TRACE("enumcb = %p, context = %p\n", enumcb, context);
209 enumcb(NULL,"WINE DirectSound using Open Sound System",
217 static void _dump_DSBCAPS(DWORD xmask) {
222 #define FE(x) { x, #x },
223 FE(DSBCAPS_PRIMARYBUFFER)
225 FE(DSBCAPS_LOCHARDWARE)
226 FE(DSBCAPS_LOCSOFTWARE)
227 FE(DSBCAPS_CTRLFREQUENCY)
229 FE(DSBCAPS_CTRLVOLUME)
230 FE(DSBCAPS_CTRLDEFAULT)
232 FE(DSBCAPS_STICKYFOCUS)
233 FE(DSBCAPS_GETCURRENTPOSITION2)
237 for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++)
238 if (flags[i].mask & xmask)
239 fprintf(stderr,"%s ",flags[i].name);
242 /*******************************************************************************
243 * IDirectSound3DBuffer
246 /* IUnknown methods */
247 static HRESULT WINAPI IDirectSound3DBufferImpl_QueryInterface(
248 LPDIRECTSOUND3DBUFFER iface, REFIID riid, LPVOID *ppobj)
250 ICOM_THIS(IDirectSound3DBufferImpl,iface);
252 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
256 static ULONG WINAPI IDirectSound3DBufferImpl_AddRef(LPDIRECTSOUND3DBUFFER iface)
258 ICOM_THIS(IDirectSound3DBufferImpl,iface);
263 static ULONG WINAPI IDirectSound3DBufferImpl_Release(LPDIRECTSOUND3DBUFFER iface)
265 ICOM_THIS(IDirectSound3DBufferImpl,iface);
269 HeapFree(GetProcessHeap(),0,This->buffer);
270 HeapFree(GetProcessHeap(),0,This);
275 /* IDirectSound3DBuffer methods */
276 static HRESULT WINAPI IDirectSound3DBufferImpl_GetAllParameters(
277 LPDIRECTSOUND3DBUFFER iface,
278 LPDS3DBUFFER lpDs3dBuffer)
284 static HRESULT WINAPI IDirectSound3DBufferImpl_GetConeAngles(
285 LPDIRECTSOUND3DBUFFER iface,
286 LPDWORD lpdwInsideConeAngle,
287 LPDWORD lpdwOutsideConeAngle)
293 static HRESULT WINAPI IDirectSound3DBufferImpl_GetConeOrientation(
294 LPDIRECTSOUND3DBUFFER iface,
295 LPD3DVECTOR lpvConeOrientation)
301 static HRESULT WINAPI IDirectSound3DBufferImpl_GetConeOutsideVolume(
302 LPDIRECTSOUND3DBUFFER iface,
303 LPLONG lplConeOutsideVolume)
309 static HRESULT WINAPI IDirectSound3DBufferImpl_GetMaxDistance(
310 LPDIRECTSOUND3DBUFFER iface,
311 LPD3DVALUE lpfMaxDistance)
317 static HRESULT WINAPI IDirectSound3DBufferImpl_GetMinDistance(
318 LPDIRECTSOUND3DBUFFER iface,
319 LPD3DVALUE lpfMinDistance)
325 static HRESULT WINAPI IDirectSound3DBufferImpl_GetMode(
326 LPDIRECTSOUND3DBUFFER iface,
333 static HRESULT WINAPI IDirectSound3DBufferImpl_GetPosition(
334 LPDIRECTSOUND3DBUFFER iface,
335 LPD3DVECTOR lpvPosition)
341 static HRESULT WINAPI IDirectSound3DBufferImpl_GetVelocity(
342 LPDIRECTSOUND3DBUFFER iface,
343 LPD3DVECTOR lpvVelocity)
349 static HRESULT WINAPI IDirectSound3DBufferImpl_SetAllParameters(
350 LPDIRECTSOUND3DBUFFER iface,
351 LPCDS3DBUFFER lpcDs3dBuffer,
358 static HRESULT WINAPI IDirectSound3DBufferImpl_SetConeAngles(
359 LPDIRECTSOUND3DBUFFER iface,
360 DWORD dwInsideConeAngle,
361 DWORD dwOutsideConeAngle,
368 static HRESULT WINAPI IDirectSound3DBufferImpl_SetConeOrientation(
369 LPDIRECTSOUND3DBUFFER iface,
370 D3DVALUE x, D3DVALUE y, D3DVALUE z,
377 static HRESULT WINAPI IDirectSound3DBufferImpl_SetConeOutsideVolume(
378 LPDIRECTSOUND3DBUFFER iface,
379 LONG lConeOutsideVolume,
386 static HRESULT WINAPI IDirectSound3DBufferImpl_SetMaxDistance(
387 LPDIRECTSOUND3DBUFFER iface,
388 D3DVALUE fMaxDistance,
395 static HRESULT WINAPI IDirectSound3DBufferImpl_SetMinDistance(
396 LPDIRECTSOUND3DBUFFER iface,
397 D3DVALUE fMinDistance,
404 static HRESULT WINAPI IDirectSound3DBufferImpl_SetMode(
405 LPDIRECTSOUND3DBUFFER iface,
409 ICOM_THIS(IDirectSound3DBufferImpl,iface);
410 TRACE("mode = %lx\n", dwMode);
411 This->ds3db.dwMode = dwMode;
415 static HRESULT WINAPI IDirectSound3DBufferImpl_SetPosition(
416 LPDIRECTSOUND3DBUFFER iface,
417 D3DVALUE x, D3DVALUE y, D3DVALUE z,
424 static HRESULT WINAPI IDirectSound3DBufferImpl_SetVelocity(
425 LPDIRECTSOUND3DBUFFER iface,
426 D3DVALUE x, D3DVALUE y, D3DVALUE z,
433 ICOM_VTABLE(IDirectSound3DBuffer) ds3dbvt =
435 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
436 /* IUnknown methods */
437 IDirectSound3DBufferImpl_QueryInterface,
438 IDirectSound3DBufferImpl_AddRef,
439 IDirectSound3DBufferImpl_Release,
440 /* IDirectSound3DBuffer methods */
441 IDirectSound3DBufferImpl_GetAllParameters,
442 IDirectSound3DBufferImpl_GetConeAngles,
443 IDirectSound3DBufferImpl_GetConeOrientation,
444 IDirectSound3DBufferImpl_GetConeOutsideVolume,
445 IDirectSound3DBufferImpl_GetMaxDistance,
446 IDirectSound3DBufferImpl_GetMinDistance,
447 IDirectSound3DBufferImpl_GetMode,
448 IDirectSound3DBufferImpl_GetPosition,
449 IDirectSound3DBufferImpl_GetVelocity,
450 IDirectSound3DBufferImpl_SetAllParameters,
451 IDirectSound3DBufferImpl_SetConeAngles,
452 IDirectSound3DBufferImpl_SetConeOrientation,
453 IDirectSound3DBufferImpl_SetConeOutsideVolume,
454 IDirectSound3DBufferImpl_SetMaxDistance,
455 IDirectSound3DBufferImpl_SetMinDistance,
456 IDirectSound3DBufferImpl_SetMode,
457 IDirectSound3DBufferImpl_SetPosition,
458 IDirectSound3DBufferImpl_SetVelocity,
462 static int DSOUND_Create3DBuffer(IDirectSoundBufferImpl* dsb)
464 DWORD i, temp, iSize, oSize, offset;
465 LPBYTE bIbuf, bObuf, bTbuf = NULL;
466 LPWORD wIbuf, wObuf, wTbuf = NULL;
468 /* Inside DirectX says it's stupid but allowed */
469 if (dsb->wfx.nChannels == 2) {
470 /* Convert to mono */
471 if (dsb->wfx.wBitsPerSample == 16) {
472 iSize = dsb->buflen / 4;
473 wTbuf = malloc(dsb->buflen / 2);
475 return DSERR_OUTOFMEMORY;
476 for (i = 0; i < iSize; i++)
477 wTbuf[i] = (dsb->buffer[i] + dsb->buffer[(i * 2) + 1]) / 2;
480 iSize = dsb->buflen / 2;
481 bTbuf = malloc(dsb->buflen / 2);
483 return DSERR_OUTOFMEMORY;
484 for (i = 0; i < iSize; i++)
485 bTbuf[i] = (dsb->buffer[i] + dsb->buffer[(i * 2) + 1]) / 2;
489 if (dsb->wfx.wBitsPerSample == 16) {
490 iSize = dsb->buflen / 2;
491 wIbuf = (LPWORD) dsb->buffer;
493 bIbuf = (LPBYTE) dsb->buffer;
498 if (primarybuf->wfx.wBitsPerSample == 16) {
499 wObuf = (LPWORD) dsb->ds3db->buffer;
500 oSize = dsb->ds3db->buflen / 2;
502 bObuf = (LPBYTE) dsb->ds3db->buffer;
503 oSize = dsb->ds3db->buflen;
506 offset = primarybuf->wfx.nSamplesPerSec / 100; /* 10ms */
507 if (primarybuf->wfx.wBitsPerSample == 16 && dsb->wfx.wBitsPerSample == 16)
508 for (i = 0; i < iSize; i++) {
511 temp += wIbuf[i - offset] >> 9;
513 temp += wIbuf[i + iSize - offset] >> 9;
515 wObuf[(i * 2) + 1] = temp;
517 else if (primarybuf->wfx.wBitsPerSample == 8 && dsb->wfx.wBitsPerSample == 8)
518 for (i = 0; i < iSize; i++) {
521 temp += bIbuf[i - offset] >> 5;
523 temp += bIbuf[i + iSize - offset] >> 5;
525 bObuf[(i * 2) + 1] = temp;
536 /*******************************************************************************
537 * IDirectSound3DListener
540 /* IUnknown methods */
541 static HRESULT WINAPI IDirectSound3DListenerImpl_QueryInterface(
542 LPDIRECTSOUND3DLISTENER iface, REFIID riid, LPVOID *ppobj)
544 ICOM_THIS(IDirectSound3DListenerImpl,iface);
546 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
550 static ULONG WINAPI IDirectSound3DListenerImpl_AddRef(LPDIRECTSOUND3DLISTENER iface)
552 ICOM_THIS(IDirectSound3DListenerImpl,iface);
557 static ULONG WINAPI IDirectSound3DListenerImpl_Release(LPDIRECTSOUND3DLISTENER iface)
559 ICOM_THIS(IDirectSound3DListenerImpl,iface);
564 /* IDirectSound3DListener methods */
565 static HRESULT WINAPI IDirectSound3DListenerImpl_GetAllParameter(
566 LPDIRECTSOUND3DLISTENER iface,
567 LPDS3DLISTENER lpDS3DL)
573 static HRESULT WINAPI IDirectSound3DListenerImpl_GetDistanceFactor(
574 LPDIRECTSOUND3DLISTENER iface,
575 LPD3DVALUE lpfDistanceFactor)
581 static HRESULT WINAPI IDirectSound3DListenerImpl_GetDopplerFactor(
582 LPDIRECTSOUND3DLISTENER iface,
583 LPD3DVALUE lpfDopplerFactor)
589 static HRESULT WINAPI IDirectSound3DListenerImpl_GetOrientation(
590 LPDIRECTSOUND3DLISTENER iface,
591 LPD3DVECTOR lpvOrientFront,
592 LPD3DVECTOR lpvOrientTop)
598 static HRESULT WINAPI IDirectSound3DListenerImpl_GetPosition(
599 LPDIRECTSOUND3DLISTENER iface,
600 LPD3DVECTOR lpvPosition)
606 static HRESULT WINAPI IDirectSound3DListenerImpl_GetRolloffFactor(
607 LPDIRECTSOUND3DLISTENER iface,
608 LPD3DVALUE lpfRolloffFactor)
614 static HRESULT WINAPI IDirectSound3DListenerImpl_GetVelocity(
615 LPDIRECTSOUND3DLISTENER iface,
616 LPD3DVECTOR lpvVelocity)
622 static HRESULT WINAPI IDirectSound3DListenerImpl_SetAllParameters(
623 LPDIRECTSOUND3DLISTENER iface,
624 LPCDS3DLISTENER lpcDS3DL,
631 static HRESULT WINAPI IDirectSound3DListenerImpl_SetDistanceFactor(
632 LPDIRECTSOUND3DLISTENER iface,
633 D3DVALUE fDistanceFactor,
640 static HRESULT WINAPI IDirectSound3DListenerImpl_SetDopplerFactor(
641 LPDIRECTSOUND3DLISTENER iface,
642 D3DVALUE fDopplerFactor,
649 static HRESULT WINAPI IDirectSound3DListenerImpl_SetOrientation(
650 LPDIRECTSOUND3DLISTENER iface,
651 D3DVALUE xFront, D3DVALUE yFront, D3DVALUE zFront,
652 D3DVALUE xTop, D3DVALUE yTop, D3DVALUE zTop,
659 static HRESULT WINAPI IDirectSound3DListenerImpl_SetPosition(
660 LPDIRECTSOUND3DLISTENER iface,
661 D3DVALUE x, D3DVALUE y, D3DVALUE z,
668 static HRESULT WINAPI IDirectSound3DListenerImpl_SetRolloffFactor(
669 LPDIRECTSOUND3DLISTENER iface,
670 D3DVALUE fRolloffFactor,
677 static HRESULT WINAPI IDirectSound3DListenerImpl_SetVelocity(
678 LPDIRECTSOUND3DLISTENER iface,
679 D3DVALUE x, D3DVALUE y, D3DVALUE z,
686 static HRESULT WINAPI IDirectSound3DListenerImpl_CommitDeferredSettings(
687 LPDIRECTSOUND3DLISTENER iface)
694 ICOM_VTABLE(IDirectSound3DListener) ds3dlvt =
696 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
697 /* IUnknown methods */
698 IDirectSound3DListenerImpl_QueryInterface,
699 IDirectSound3DListenerImpl_AddRef,
700 IDirectSound3DListenerImpl_Release,
701 /* IDirectSound3DListener methods */
702 IDirectSound3DListenerImpl_GetAllParameter,
703 IDirectSound3DListenerImpl_GetDistanceFactor,
704 IDirectSound3DListenerImpl_GetDopplerFactor,
705 IDirectSound3DListenerImpl_GetOrientation,
706 IDirectSound3DListenerImpl_GetPosition,
707 IDirectSound3DListenerImpl_GetRolloffFactor,
708 IDirectSound3DListenerImpl_GetVelocity,
709 IDirectSound3DListenerImpl_SetAllParameters,
710 IDirectSound3DListenerImpl_SetDistanceFactor,
711 IDirectSound3DListenerImpl_SetDopplerFactor,
712 IDirectSound3DListenerImpl_SetOrientation,
713 IDirectSound3DListenerImpl_SetPosition,
714 IDirectSound3DListenerImpl_SetRolloffFactor,
715 IDirectSound3DListenerImpl_SetVelocity,
716 IDirectSound3DListenerImpl_CommitDeferredSettings,
719 /*******************************************************************************
722 static HRESULT WINAPI IDirectSoundNotifyImpl_QueryInterface(
723 LPDIRECTSOUNDNOTIFY iface,REFIID riid,LPVOID *ppobj
725 ICOM_THIS(IDirectSoundNotifyImpl,iface);
727 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
731 static ULONG WINAPI IDirectSoundNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface) {
732 ICOM_THIS(IDirectSoundNotifyImpl,iface);
733 return ++(This->ref);
736 static ULONG WINAPI IDirectSoundNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface) {
737 ICOM_THIS(IDirectSoundNotifyImpl,iface);
740 IDirectSoundNotify_Release((LPDIRECTSOUNDBUFFER)This->dsb);
741 HeapFree(GetProcessHeap(),0,This);
747 static HRESULT WINAPI IDirectSoundNotifyImpl_SetNotificationPositions(
748 LPDIRECTSOUNDNOTIFY iface,DWORD howmuch,LPCDSBPOSITIONNOTIFY notify
750 ICOM_THIS(IDirectSoundNotifyImpl,iface);
753 if (TRACE_ON(dsound)) {
754 TRACE("(%p,0x%08lx,%p)\n",This,howmuch,notify);
755 for (i=0;i<howmuch;i++)
756 TRACE("notify at %ld to 0x%08lx\n",
757 notify[i].dwOffset,(DWORD)notify[i].hEventNotify);
759 This->dsb->notifies = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,This->dsb->notifies,(This->dsb->nrofnotifies+howmuch)*sizeof(DSBPOSITIONNOTIFY));
760 memcpy( This->dsb->notifies+This->dsb->nrofnotifies,
762 howmuch*sizeof(DSBPOSITIONNOTIFY)
764 This->dsb->nrofnotifies+=howmuch;
769 ICOM_VTABLE(IDirectSoundNotify) dsnvt =
771 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
772 IDirectSoundNotifyImpl_QueryInterface,
773 IDirectSoundNotifyImpl_AddRef,
774 IDirectSoundNotifyImpl_Release,
775 IDirectSoundNotifyImpl_SetNotificationPositions,
778 /*******************************************************************************
782 /* This sets this format for the <em>Primary Buffer Only</em> */
783 /* See file:///cdrom/sdk52/docs/worddoc/dsound.doc page 120 */
784 static HRESULT WINAPI IDirectSoundBufferImpl_SetFormat(
785 LPDIRECTSOUNDBUFFER iface,LPWAVEFORMATEX wfex
787 ICOM_THIS(IDirectSoundBufferImpl,iface);
788 IDirectSoundBufferImpl** dsb;
791 /* Let's be pedantic! */
792 if ((wfex == NULL) ||
793 (wfex->wFormatTag != WAVE_FORMAT_PCM) ||
794 (wfex->nChannels < 1) || (wfex->nChannels > 2) ||
795 (wfex->nSamplesPerSec < 1) ||
796 (wfex->nBlockAlign < 1) || (wfex->nChannels > 4) ||
797 ((wfex->wBitsPerSample != 8) && (wfex->wBitsPerSample != 16))) {
798 TRACE("failed pedantic check!\n");
799 return DSERR_INVALIDPARAM;
803 EnterCriticalSection(&(primarybuf->lock));
805 if (primarybuf->wfx.nSamplesPerSec != wfex->nSamplesPerSec) {
806 dsb = dsound->buffers;
807 for (i = 0; i < dsound->nrofbuffers; i++, dsb++) {
809 EnterCriticalSection(&((*dsb)->lock));
811 (*dsb)->freqAdjust = ((*dsb)->freq << DSOUND_FREQSHIFT) /
812 wfex->nSamplesPerSec;
814 LeaveCriticalSection(&((*dsb)->lock));
819 memcpy(&(primarybuf->wfx), wfex, sizeof(primarybuf->wfx));
821 TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld"
822 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
823 wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec,
824 wfex->nAvgBytesPerSec, wfex->nBlockAlign,
825 wfex->wBitsPerSample, wfex->cbSize);
827 primarybuf->wfx.nAvgBytesPerSec =
828 This->wfx.nSamplesPerSec * This->wfx.nBlockAlign;
832 LeaveCriticalSection(&(primarybuf->lock));
838 static HRESULT WINAPI IDirectSoundBufferImpl_SetVolume(
839 LPDIRECTSOUNDBUFFER iface,LONG vol
841 ICOM_THIS(IDirectSoundBufferImpl,iface);
844 TRACE("(%p,%ld)\n",This,vol);
846 /* I'm not sure if we need this for primary buffer */
847 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME))
848 return DSERR_CONTROLUNAVAIL;
850 if ((vol > DSBVOLUME_MAX) || (vol < DSBVOLUME_MIN))
851 return DSERR_INVALIDPARAM;
853 /* This needs to adjust the soundcard volume when */
854 /* called for the primary buffer */
855 if (This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER) {
856 FIXME("Volume control of primary unimplemented.\n");
862 EnterCriticalSection(&(This->lock));
866 temp = (double) (This->volume - (This->pan > 0 ? This->pan : 0));
867 This->lVolAdjust = (ULONG) (pow(2.0, temp / 600.0) * 32768.0);
868 temp = (double) (This->volume + (This->pan < 0 ? This->pan : 0));
869 This->rVolAdjust = (ULONG) (pow(2.0, temp / 600.0) * 32768.0);
871 LeaveCriticalSection(&(This->lock));
874 TRACE("left = %lx, right = %lx\n", This->lVolAdjust, This->rVolAdjust);
879 static HRESULT WINAPI IDirectSoundBufferImpl_GetVolume(
880 LPDIRECTSOUNDBUFFER iface,LPLONG vol
882 ICOM_THIS(IDirectSoundBufferImpl,iface);
883 TRACE("(%p,%p)\n",This,vol);
886 return DSERR_INVALIDPARAM;
892 static HRESULT WINAPI IDirectSoundBufferImpl_SetFrequency(
893 LPDIRECTSOUNDBUFFER iface,DWORD freq
895 ICOM_THIS(IDirectSoundBufferImpl,iface);
896 TRACE("(%p,%ld)\n",This,freq);
898 /* You cannot set the frequency of the primary buffer */
899 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLFREQUENCY) ||
900 (This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER))
901 return DSERR_CONTROLUNAVAIL;
903 if ((freq < DSBFREQUENCY_MIN) || (freq > DSBFREQUENCY_MAX))
904 return DSERR_INVALIDPARAM;
907 EnterCriticalSection(&(This->lock));
910 This->freqAdjust = (freq << DSOUND_FREQSHIFT) / primarybuf->wfx.nSamplesPerSec;
911 This->nAvgBytesPerSec = freq * This->wfx.nBlockAlign;
913 LeaveCriticalSection(&(This->lock));
919 static HRESULT WINAPI IDirectSoundBufferImpl_Play(
920 LPDIRECTSOUNDBUFFER iface,DWORD reserved1,DWORD reserved2,DWORD flags
922 ICOM_THIS(IDirectSoundBufferImpl,iface);
923 TRACE("(%p,%08lx,%08lx,%08lx)\n",
924 This,reserved1,reserved2,flags
926 This->playflags = flags;
931 static HRESULT WINAPI IDirectSoundBufferImpl_Stop(LPDIRECTSOUNDBUFFER iface)
933 ICOM_THIS(IDirectSoundBufferImpl,iface);
934 TRACE("(%p)\n",This);
937 EnterCriticalSection(&(This->lock));
940 DSOUND_CheckEvent(This, 0);
942 LeaveCriticalSection(&(This->lock));
948 static DWORD WINAPI IDirectSoundBufferImpl_AddRef(LPDIRECTSOUNDBUFFER iface) {
949 ICOM_THIS(IDirectSoundBufferImpl,iface);
950 /* TRACE(dsound,"(%p) ref was %ld\n",This, This->ref); */
952 return ++(This->ref);
954 static DWORD WINAPI IDirectSoundBufferImpl_Release(LPDIRECTSOUNDBUFFER iface) {
955 ICOM_THIS(IDirectSoundBufferImpl,iface);
958 /* TRACE(dsound,"(%p) ref was %ld\n",This, This->ref); */
963 for (i=0;i<This->dsound->nrofbuffers;i++)
964 if (This->dsound->buffers[i] == This)
966 if (i < This->dsound->nrofbuffers) {
967 /* Put the last buffer of the list in the (now empty) position */
968 This->dsound->buffers[i] = This->dsound->buffers[This->dsound->nrofbuffers - 1];
969 This->dsound->buffers = HeapReAlloc(GetProcessHeap(),0,This->dsound->buffers,sizeof(LPDIRECTSOUNDBUFFER)*This->dsound->nrofbuffers);
970 This->dsound->nrofbuffers--;
971 IDirectSound_Release((LPDIRECTSOUND)This->dsound);
974 DeleteCriticalSection(&(This->lock));
976 if (This->ds3db && ICOM_VTBL(This->ds3db))
977 IDirectSound3DBuffer_Release((LPDIRECTSOUND3DBUFFER)This->ds3db);
980 /* this is a duplicate buffer */
981 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)This->parent);
983 /* this is a toplevel buffer */
984 HeapFree(GetProcessHeap(),0,This->buffer);
986 HeapFree(GetProcessHeap(),0,This);
988 if (This == primarybuf)
994 static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition(
995 LPDIRECTSOUNDBUFFER iface,LPDWORD playpos,LPDWORD writepos
997 ICOM_THIS(IDirectSoundBufferImpl,iface);
998 TRACE("(%p,%p,%p)\n",This,playpos,writepos);
999 if (playpos) *playpos = This->playpos;
1000 if (writepos) *writepos = This->writepos;
1001 TRACE("playpos = %ld, writepos = %ld\n", playpos?*playpos:0, writepos?*writepos:0);
1005 static HRESULT WINAPI IDirectSoundBufferImpl_GetStatus(
1006 LPDIRECTSOUNDBUFFER iface,LPDWORD status
1008 ICOM_THIS(IDirectSoundBufferImpl,iface);
1009 TRACE("(%p,%p)\n",This,status);
1012 return DSERR_INVALIDPARAM;
1016 *status |= DSBSTATUS_PLAYING;
1017 if (This->playflags & DSBPLAY_LOOPING)
1018 *status |= DSBSTATUS_LOOPING;
1024 static HRESULT WINAPI IDirectSoundBufferImpl_GetFormat(
1025 LPDIRECTSOUNDBUFFER iface,LPWAVEFORMATEX lpwf,DWORD wfsize,LPDWORD wfwritten
1027 ICOM_THIS(IDirectSoundBufferImpl,iface);
1028 TRACE("(%p,%p,%ld,%p)\n",This,lpwf,wfsize,wfwritten);
1030 if (wfsize>sizeof(This->wfx))
1031 wfsize = sizeof(This->wfx);
1032 if (lpwf) { /* NULL is valid */
1033 memcpy(lpwf,&(This->wfx),wfsize);
1035 *wfwritten = wfsize;
1038 *wfwritten = sizeof(This->wfx);
1040 return DSERR_INVALIDPARAM;
1045 static HRESULT WINAPI IDirectSoundBufferImpl_Lock(
1046 LPDIRECTSOUNDBUFFER iface,DWORD writecursor,DWORD writebytes,LPVOID lplpaudioptr1,LPDWORD audiobytes1,LPVOID lplpaudioptr2,LPDWORD audiobytes2,DWORD flags
1048 ICOM_THIS(IDirectSoundBufferImpl,iface);
1050 TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx)\n",
1060 if (flags & DSBLOCK_FROMWRITECURSOR)
1061 writecursor += This->writepos;
1062 if (flags & DSBLOCK_ENTIREBUFFER)
1063 writebytes = This->buflen;
1064 if (writebytes > This->buflen)
1065 writebytes = This->buflen;
1067 assert(audiobytes1!=audiobytes2);
1068 assert(lplpaudioptr1!=lplpaudioptr2);
1069 if (writecursor+writebytes <= This->buflen) {
1070 *(LPBYTE*)lplpaudioptr1 = This->buffer+writecursor;
1071 *audiobytes1 = writebytes;
1073 *(LPBYTE*)lplpaudioptr2 = NULL;
1076 TRACE("->%ld.0\n",writebytes);
1078 *(LPBYTE*)lplpaudioptr1 = This->buffer+writecursor;
1079 *audiobytes1 = This->buflen-writecursor;
1081 *(LPBYTE*)lplpaudioptr2 = This->buffer;
1083 *audiobytes2 = writebytes-(This->buflen-writecursor);
1084 TRACE("->%ld.%ld\n",*audiobytes1,audiobytes2?*audiobytes2:0);
1086 /* No. See file:///cdrom/sdk52/docs/worddoc/dsound.doc page 21 */
1087 /* This->writepos=(writecursor+writebytes)%This->buflen; */
1091 static HRESULT WINAPI IDirectSoundBufferImpl_SetCurrentPosition(
1092 LPDIRECTSOUNDBUFFER iface,DWORD newpos
1094 ICOM_THIS(IDirectSoundBufferImpl,iface);
1095 TRACE("(%p,%ld)\n",This,newpos);
1098 EnterCriticalSection(&(This->lock));
1100 This->playpos = newpos;
1102 LeaveCriticalSection(&(This->lock));
1108 static HRESULT WINAPI IDirectSoundBufferImpl_SetPan(
1109 LPDIRECTSOUNDBUFFER iface,LONG pan
1111 ICOM_THIS(IDirectSoundBufferImpl,iface);
1114 TRACE("(%p,%ld)\n",This,pan);
1116 if ((pan > DSBPAN_RIGHT) || (pan < DSBPAN_LEFT))
1117 return DSERR_INVALIDPARAM;
1119 /* You cannot set the pan of the primary buffer */
1120 /* and you cannot use both pan and 3D controls */
1121 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN) ||
1122 (This->dsbd.dwFlags & DSBCAPS_CTRL3D) ||
1123 (This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER))
1124 return DSERR_CONTROLUNAVAIL;
1127 EnterCriticalSection(&(This->lock));
1131 temp = (double) (This->volume - (This->pan > 0 ? This->pan : 0));
1132 This->lVolAdjust = (ULONG) (pow(2.0, temp / 600.0) * 32768.0);
1133 temp = (double) (This->volume + (This->pan < 0 ? This->pan : 0));
1134 This->rVolAdjust = (ULONG) (pow(2.0, temp / 600.0) * 32768.0);
1136 LeaveCriticalSection(&(This->lock));
1142 static HRESULT WINAPI IDirectSoundBufferImpl_GetPan(
1143 LPDIRECTSOUNDBUFFER iface,LPLONG pan
1145 ICOM_THIS(IDirectSoundBufferImpl,iface);
1146 TRACE("(%p,%p)\n",This,pan);
1149 return DSERR_INVALIDPARAM;
1156 static HRESULT WINAPI IDirectSoundBufferImpl_Unlock(
1157 LPDIRECTSOUNDBUFFER iface,LPVOID p1,DWORD x1,LPVOID p2,DWORD x2
1159 ICOM_THIS(IDirectSoundBufferImpl,iface);
1160 TRACE("(%p,%p,%ld,%p,%ld):stub\n", This,p1,x1,p2,x2);
1162 /* There is really nothing to do here. Should someone */
1163 /* choose to implement static buffers in hardware (by */
1164 /* using a wave table synth, for example) this is where */
1165 /* you'd want to do the loading. For software buffers, */
1166 /* which is what we currently use, we need do nothing. */
1169 /* It's also the place to pre-process 3D buffers... */
1171 /* This is highly experimental and liable to break things */
1172 if (This->dsbd.dwFlags & DSBCAPS_CTRL3D)
1173 DSOUND_Create3DBuffer(This);
1179 static HRESULT WINAPI IDirectSoundBufferImpl_GetFrequency(
1180 LPDIRECTSOUNDBUFFER iface,LPDWORD freq
1182 ICOM_THIS(IDirectSoundBufferImpl,iface);
1183 TRACE("(%p,%p)\n",This,freq);
1186 return DSERR_INVALIDPARAM;
1193 static HRESULT WINAPI IDirectSoundBufferImpl_Initialize(
1194 LPDIRECTSOUNDBUFFER iface,LPDIRECTSOUND dsound,LPDSBUFFERDESC dbsd
1196 ICOM_THIS(IDirectSoundBufferImpl,iface);
1197 FIXME("(%p,%p,%p):stub\n",This,dsound,dbsd);
1198 printf("Re-Init!!!\n");
1199 return DSERR_ALREADYINITIALIZED;
1202 static HRESULT WINAPI IDirectSoundBufferImpl_GetCaps(
1203 LPDIRECTSOUNDBUFFER iface,LPDSBCAPS caps
1205 ICOM_THIS(IDirectSoundBufferImpl,iface);
1206 TRACE("(%p)->(%p)\n",This,caps);
1209 return DSERR_INVALIDPARAM;
1211 /* I think we should check this value, not set it. See */
1212 /* Inside DirectX, p215. That should apply here, too. */
1213 caps->dwSize = sizeof(*caps);
1215 caps->dwFlags = This->dsbd.dwFlags | DSBCAPS_LOCSOFTWARE;
1216 caps->dwBufferBytes = This->dsbd.dwBufferBytes;
1217 /* This value represents the speed of the "unlock" command.
1218 As unlock is quite fast (it does not do anything), I put
1219 4096 ko/s = 4 Mo / s */
1220 caps->dwUnlockTransferRate = 4096;
1221 caps->dwPlayCpuOverhead = 0;
1226 static HRESULT WINAPI IDirectSoundBufferImpl_QueryInterface(
1227 LPDIRECTSOUNDBUFFER iface,REFIID riid,LPVOID *ppobj
1229 ICOM_THIS(IDirectSoundBufferImpl,iface);
1231 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
1233 if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
1234 IDirectSoundNotifyImpl *dsn;
1236 dsn = (IDirectSoundNotifyImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(*dsn));
1239 IDirectSoundBuffer_AddRef(iface);
1240 ICOM_VTBL(dsn) = &dsnvt;
1241 *ppobj = (LPVOID)dsn;
1245 if ( IsEqualGUID( &IID_IDirectSound3DBuffer, riid ) ) {
1246 *ppobj = This->ds3db;
1254 static ICOM_VTABLE(IDirectSoundBuffer) dsbvt =
1256 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1257 IDirectSoundBufferImpl_QueryInterface,
1258 IDirectSoundBufferImpl_AddRef,
1259 IDirectSoundBufferImpl_Release,
1260 IDirectSoundBufferImpl_GetCaps,
1261 IDirectSoundBufferImpl_GetCurrentPosition,
1262 IDirectSoundBufferImpl_GetFormat,
1263 IDirectSoundBufferImpl_GetVolume,
1264 IDirectSoundBufferImpl_GetPan,
1265 IDirectSoundBufferImpl_GetFrequency,
1266 IDirectSoundBufferImpl_GetStatus,
1267 IDirectSoundBufferImpl_Initialize,
1268 IDirectSoundBufferImpl_Lock,
1269 IDirectSoundBufferImpl_Play,
1270 IDirectSoundBufferImpl_SetCurrentPosition,
1271 IDirectSoundBufferImpl_SetFormat,
1272 IDirectSoundBufferImpl_SetVolume,
1273 IDirectSoundBufferImpl_SetPan,
1274 IDirectSoundBufferImpl_SetFrequency,
1275 IDirectSoundBufferImpl_Stop,
1276 IDirectSoundBufferImpl_Unlock
1279 /*******************************************************************************
1283 static HRESULT WINAPI IDirectSoundImpl_SetCooperativeLevel(
1284 LPDIRECTSOUND iface,HWND hwnd,DWORD level
1286 ICOM_THIS(IDirectSoundImpl,iface);
1287 FIXME("(%p,%08lx,%ld):stub\n",This,(DWORD)hwnd,level);
1291 static HRESULT WINAPI IDirectSoundImpl_CreateSoundBuffer(
1292 LPDIRECTSOUND iface,LPDSBUFFERDESC dsbd,LPLPDIRECTSOUNDBUFFER ppdsb,LPUNKNOWN lpunk
1294 ICOM_THIS(IDirectSoundImpl,iface);
1295 IDirectSoundBufferImpl** ippdsb=(IDirectSoundBufferImpl**)ppdsb;
1296 LPWAVEFORMATEX wfex;
1298 TRACE("(%p,%p,%p,%p)\n",This,dsbd,ippdsb,lpunk);
1300 if ((This == NULL) || (dsbd == NULL) || (ippdsb == NULL))
1301 return DSERR_INVALIDPARAM;
1303 if (TRACE_ON(dsound)) {
1304 TRACE("(size=%ld)\n",dsbd->dwSize);
1305 TRACE("(flags=0x%08lx\n",dsbd->dwFlags);
1306 _dump_DSBCAPS(dsbd->dwFlags);
1307 TRACE("(bufferbytes=%ld)\n",dsbd->dwBufferBytes);
1308 TRACE("(lpwfxFormat=%p)\n",dsbd->lpwfxFormat);
1311 wfex = dsbd->lpwfxFormat;
1314 TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld"
1315 "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
1316 wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec,
1317 wfex->nAvgBytesPerSec, wfex->nBlockAlign,
1318 wfex->wBitsPerSample, wfex->cbSize);
1320 if (dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) {
1322 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)primarybuf);
1323 *ippdsb = primarybuf;
1324 primarybuf->dsbd.dwFlags = dsbd->dwFlags;
1326 } /* Else create primarybuf */
1329 *ippdsb = (IDirectSoundBufferImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectSoundBufferImpl));
1330 if (*ippdsb == NULL)
1331 return DSERR_OUTOFMEMORY;
1334 TRACE("Created buffer at %p\n", *ippdsb);
1336 if (dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) {
1337 (*ippdsb)->buflen = dsound->wfx.nAvgBytesPerSec;
1338 (*ippdsb)->freq = dsound->wfx.nSamplesPerSec;
1340 (*ippdsb)->buflen = dsbd->dwBufferBytes;
1341 (*ippdsb)->freq = dsbd->lpwfxFormat->nSamplesPerSec;
1343 (*ippdsb)->buffer = (LPBYTE)HeapAlloc(GetProcessHeap(),0,(*ippdsb)->buflen);
1344 if ((*ippdsb)->buffer == NULL) {
1345 HeapFree(GetProcessHeap(),0,(*ippdsb));
1347 return DSERR_OUTOFMEMORY;
1349 /* It's not necessary to initialize values to zero since */
1350 /* we allocated this structure with HEAP_ZERO_MEMORY... */
1351 (*ippdsb)->playpos = 0;
1352 (*ippdsb)->writepos = 0;
1353 (*ippdsb)->parent = NULL;
1354 ICOM_VTBL(*ippdsb) = &dsbvt;
1355 (*ippdsb)->dsound = This;
1356 (*ippdsb)->playing = 0;
1357 (*ippdsb)->lVolAdjust = (1 << 15);
1358 (*ippdsb)->rVolAdjust = (1 << 15);
1360 if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
1361 (*ippdsb)->freqAdjust = ((*ippdsb)->freq << DSOUND_FREQSHIFT) /
1362 primarybuf->wfx.nSamplesPerSec;
1363 (*ippdsb)->nAvgBytesPerSec = (*ippdsb)->freq *
1364 dsbd->lpwfxFormat->nBlockAlign;
1367 memcpy(&((*ippdsb)->dsbd),dsbd,sizeof(*dsbd));
1369 /* register buffer */
1370 if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
1371 This->buffers = (IDirectSoundBufferImpl**)HeapReAlloc(GetProcessHeap(),0,This->buffers,sizeof(IDirectSoundBufferImpl*)*(This->nrofbuffers+1));
1372 This->buffers[This->nrofbuffers] = *ippdsb;
1373 This->nrofbuffers++;
1375 IDirectSound_AddRef(iface);
1377 if (dsbd->lpwfxFormat)
1378 memcpy(&((*ippdsb)->wfx), dsbd->lpwfxFormat, sizeof((*ippdsb)->wfx));
1380 InitializeCriticalSection(&((*ippdsb)->lock));
1383 if (dsbd->dwFlags & DSBCAPS_CTRL3D) {
1384 IDirectSound3DBufferImpl *ds3db;
1386 ds3db = (IDirectSound3DBufferImpl*)HeapAlloc(GetProcessHeap(),
1389 ds3db->dsb = (*ippdsb);
1390 ICOM_VTBL(ds3db) = &ds3dbvt;
1391 (*ippdsb)->ds3db = ds3db;
1392 ds3db->ds3db.dwSize = sizeof(DS3DBUFFER);
1393 ds3db->ds3db.vPosition.x.x = 0.0;
1394 ds3db->ds3db.vPosition.y.y = 0.0;
1395 ds3db->ds3db.vPosition.z.z = 0.0;
1396 ds3db->ds3db.vVelocity.x.x = 0.0;
1397 ds3db->ds3db.vVelocity.y.y = 0.0;
1398 ds3db->ds3db.vVelocity.z.z = 0.0;
1399 ds3db->ds3db.dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
1400 ds3db->ds3db.dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
1401 ds3db->ds3db.vConeOrientation.x.x = 0.0;
1402 ds3db->ds3db.vConeOrientation.y.y = 0.0;
1403 ds3db->ds3db.vConeOrientation.z.z = 0.0;
1404 ds3db->ds3db.lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
1405 ds3db->ds3db.flMinDistance = DS3D_DEFAULTMINDISTANCE;
1406 ds3db->ds3db.flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
1407 ds3db->ds3db.dwMode = DS3DMODE_NORMAL;
1408 ds3db->buflen = ((*ippdsb)->buflen * primarybuf->wfx.nBlockAlign) /
1409 (*ippdsb)->wfx.nBlockAlign;
1410 ds3db->buffer = HeapAlloc(GetProcessHeap(), 0, ds3db->buflen);
1411 if (ds3db->buffer == NULL) {
1413 ds3db->ds3db.dwMode = DS3DMODE_DISABLE;
1420 static HRESULT WINAPI IDirectSoundImpl_DuplicateSoundBuffer(
1421 LPDIRECTSOUND iface,LPDIRECTSOUNDBUFFER pdsb,LPLPDIRECTSOUNDBUFFER ppdsb
1423 ICOM_THIS(IDirectSoundImpl,iface);
1424 IDirectSoundBufferImpl* ipdsb=(IDirectSoundBufferImpl*)pdsb;
1425 IDirectSoundBufferImpl** ippdsb=(IDirectSoundBufferImpl**)ppdsb;
1426 TRACE("(%p,%p,%p)\n",This,ipdsb,ippdsb);
1428 *ippdsb = (IDirectSoundBufferImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectSoundBufferImpl));
1430 IDirectSoundBuffer_AddRef(pdsb);
1431 memcpy(*ippdsb, ipdsb, sizeof(IDirectSoundBufferImpl));
1433 (*ippdsb)->playpos = 0;
1434 (*ippdsb)->writepos = 0;
1435 (*ippdsb)->dsound = This;
1436 (*ippdsb)->parent = ipdsb;
1437 memcpy(&((*ippdsb)->wfx), &(ipdsb->wfx), sizeof((*ippdsb)->wfx));
1438 /* register buffer */
1439 This->buffers = (IDirectSoundBufferImpl**)HeapReAlloc(GetProcessHeap(),0,This->buffers,sizeof(IDirectSoundBufferImpl**)*(This->nrofbuffers+1));
1440 This->buffers[This->nrofbuffers] = *ippdsb;
1441 This->nrofbuffers++;
1442 IDirectSound_AddRef(iface);
1447 static HRESULT WINAPI IDirectSoundImpl_GetCaps(LPDIRECTSOUND iface,LPDSCAPS caps) {
1448 ICOM_THIS(IDirectSoundImpl,iface);
1449 TRACE("(%p,%p)\n",This,caps);
1450 TRACE("(flags=0x%08lx)\n",caps->dwFlags);
1453 return DSERR_INVALIDPARAM;
1455 /* We should check this value, not set it. See Inside DirectX, p215. */
1456 caps->dwSize = sizeof(*caps);
1459 DSCAPS_PRIMARYSTEREO |
1460 DSCAPS_PRIMARY16BIT |
1461 DSCAPS_SECONDARYSTEREO |
1462 DSCAPS_SECONDARY16BIT |
1463 DSCAPS_CONTINUOUSRATE;
1464 /* FIXME: query OSS */
1465 caps->dwMinSecondarySampleRate = DSBFREQUENCY_MIN;
1466 caps->dwMaxSecondarySampleRate = DSBFREQUENCY_MAX;
1468 caps->dwPrimaryBuffers = 1;
1470 caps->dwMaxHwMixingAllBuffers = 0;
1471 caps->dwMaxHwMixingStaticBuffers = 0;
1472 caps->dwMaxHwMixingStreamingBuffers = 0;
1474 caps->dwFreeHwMixingAllBuffers = 0;
1475 caps->dwFreeHwMixingStaticBuffers = 0;
1476 caps->dwFreeHwMixingStreamingBuffers = 0;
1478 caps->dwMaxHw3DAllBuffers = 0;
1479 caps->dwMaxHw3DStaticBuffers = 0;
1480 caps->dwMaxHw3DStreamingBuffers = 0;
1482 caps->dwFreeHw3DAllBuffers = 0;
1483 caps->dwFreeHw3DStaticBuffers = 0;
1484 caps->dwFreeHw3DStreamingBuffers = 0;
1486 caps->dwTotalHwMemBytes = 0;
1488 caps->dwFreeHwMemBytes = 0;
1490 caps->dwMaxContigFreeHwMemBytes = 0;
1492 caps->dwUnlockTransferRateHwBuffers = 4096; /* But we have none... */
1494 caps->dwPlayCpuOverheadSwBuffers = 1; /* 1% */
1499 static ULONG WINAPI IDirectSoundImpl_AddRef(LPDIRECTSOUND iface) {
1500 ICOM_THIS(IDirectSoundImpl,iface);
1501 return ++(This->ref);
1504 static ULONG WINAPI IDirectSoundImpl_Release(LPDIRECTSOUND iface) {
1505 ICOM_THIS(IDirectSoundImpl,iface);
1506 TRACE("(%p), ref was %ld\n",This,This->ref);
1507 if (!--(This->ref)) {
1508 DSOUND_CloseAudio();
1509 while(IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)primarybuf)); /* Deallocate */
1510 FIXME("need to release all buffers!\n");
1511 HeapFree(GetProcessHeap(),0,This);
1518 static HRESULT WINAPI IDirectSoundImpl_SetSpeakerConfig(
1519 LPDIRECTSOUND iface,DWORD config
1521 ICOM_THIS(IDirectSoundImpl,iface);
1522 FIXME("(%p,0x%08lx):stub\n",This,config);
1526 static HRESULT WINAPI IDirectSoundImpl_QueryInterface(
1527 LPDIRECTSOUND iface,REFIID riid,LPVOID *ppobj
1529 ICOM_THIS(IDirectSoundImpl,iface);
1531 if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) {
1533 if (This->listener) {
1534 *ppobj = This->listener;
1537 This->listener = (IDirectSound3DListenerImpl*)HeapAlloc(
1538 GetProcessHeap(), 0, sizeof(*(This->listener)));
1539 This->listener->ref = 1;
1540 ICOM_VTBL(This->listener) = &ds3dlvt;
1541 IDirectSound_AddRef(iface);
1542 This->listener->ds3dl.dwSize = sizeof(DS3DLISTENER);
1543 This->listener->ds3dl.vPosition.x.x = 0.0;
1544 This->listener->ds3dl.vPosition.y.y = 0.0;
1545 This->listener->ds3dl.vPosition.z.z = 0.0;
1546 This->listener->ds3dl.vVelocity.x.x = 0.0;
1547 This->listener->ds3dl.vVelocity.y.y = 0.0;
1548 This->listener->ds3dl.vVelocity.z.z = 0.0;
1549 This->listener->ds3dl.vOrientFront.x.x = 0.0;
1550 This->listener->ds3dl.vOrientFront.y.y = 0.0;
1551 This->listener->ds3dl.vOrientFront.z.z = 1.0;
1552 This->listener->ds3dl.vOrientTop.x.x = 0.0;
1553 This->listener->ds3dl.vOrientTop.y.y = 1.0;
1554 This->listener->ds3dl.vOrientTop.z.z = 0.0;
1555 This->listener->ds3dl.flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
1556 This->listener->ds3dl.flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
1557 This->listener->ds3dl.flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
1558 *ppobj = (LPVOID)This->listener;
1562 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
1566 static HRESULT WINAPI IDirectSoundImpl_Compact(
1567 LPDIRECTSOUND iface)
1569 ICOM_THIS(IDirectSoundImpl,iface);
1570 TRACE("(%p)\n", This);
1574 static HRESULT WINAPI IDirectSoundImpl_GetSpeakerConfig(
1575 LPDIRECTSOUND iface,
1576 LPDWORD lpdwSpeakerConfig)
1578 ICOM_THIS(IDirectSoundImpl,iface);
1579 TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
1580 *lpdwSpeakerConfig = DSSPEAKER_STEREO | (DSSPEAKER_GEOMETRY_NARROW << 16);
1584 static HRESULT WINAPI IDirectSoundImpl_Initialize(
1585 LPDIRECTSOUND iface,
1588 ICOM_THIS(IDirectSoundImpl,iface);
1589 TRACE("(%p, %p)\n", This, lpGuid);
1593 static ICOM_VTABLE(IDirectSound) dsvt =
1595 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1596 IDirectSoundImpl_QueryInterface,
1597 IDirectSoundImpl_AddRef,
1598 IDirectSoundImpl_Release,
1599 IDirectSoundImpl_CreateSoundBuffer,
1600 IDirectSoundImpl_GetCaps,
1601 IDirectSoundImpl_DuplicateSoundBuffer,
1602 IDirectSoundImpl_SetCooperativeLevel,
1603 IDirectSoundImpl_Compact,
1604 IDirectSoundImpl_GetSpeakerConfig,
1605 IDirectSoundImpl_SetSpeakerConfig,
1606 IDirectSoundImpl_Initialize
1610 /* See http://www.opensound.com/pguide/audio.html for more details */
1613 DSOUND_setformat(LPWAVEFORMATEX wfex) {
1614 int xx,channels,speed,format,nformat;
1617 TRACE("(%p) deferred\n", wfex);
1620 switch (wfex->wFormatTag) {
1622 WARN("unknown WAVE_FORMAT tag %d\n",wfex->wFormatTag);
1623 return DSERR_BADFORMAT;
1624 case WAVE_FORMAT_PCM:
1627 if (wfex->wBitsPerSample==8)
1630 format = AFMT_S16_LE;
1632 if (-1==ioctl(audiofd,SNDCTL_DSP_GETFMTS,&xx)) {
1633 perror("ioctl SNDCTL_DSP_GETFMTS");
1636 if ((xx&format)!=format) {/* format unsupported */
1637 FIXME("SNDCTL_DSP_GETFMTS: format not supported\n");
1641 if (-1==ioctl(audiofd,SNDCTL_DSP_SETFMT,&nformat)) {
1642 perror("ioctl SNDCTL_DSP_SETFMT");
1645 if (nformat!=format) {/* didn't work */
1646 FIXME("SNDCTL_DSP_GETFMTS: format not set\n");
1650 channels = wfex->nChannels-1;
1651 if (-1==ioctl(audiofd,SNDCTL_DSP_STEREO,&channels)) {
1652 perror("ioctl SNDCTL_DSP_STEREO");
1655 speed = wfex->nSamplesPerSec;
1656 if (-1==ioctl(audiofd,SNDCTL_DSP_SPEED,&speed)) {
1657 perror("ioctl SNDCTL_DSP_SPEED");
1660 TRACE("(freq=%ld,channels=%d,bits=%d)\n",
1661 wfex->nSamplesPerSec,wfex->nChannels,wfex->wBitsPerSample
1666 static void DSOUND_CheckEvent(IDirectSoundBufferImpl *dsb, int len)
1670 LPDSBPOSITIONNOTIFY event;
1672 if (dsb->nrofnotifies == 0)
1675 TRACE("(%p) buflen = %ld, playpos = %ld, len = %d\n",
1676 dsb, dsb->buflen, dsb->playpos, len);
1677 for (i = 0; i < dsb->nrofnotifies ; i++) {
1678 event = dsb->notifies + i;
1679 offset = event->dwOffset;
1680 TRACE("checking %d, position %ld, event = %d\n",
1681 i, offset, event->hEventNotify);
1682 /* DSBPN_OFFSETSTOP has to be the last element. So this is */
1683 /* OK. [Inside DirectX, p274] */
1685 /* This also means we can't sort the entries by offset, */
1686 /* because DSBPN_OFFSETSTOP == -1 */
1687 if (offset == DSBPN_OFFSETSTOP) {
1688 if (dsb->playing == 0) {
1689 SetEvent(event->hEventNotify);
1690 TRACE("signalled event %d (%d)\n", event->hEventNotify, i);
1695 if ((dsb->playpos + len) >= dsb->buflen) {
1696 if ((offset < ((dsb->playpos + len) % dsb->buflen)) ||
1697 (offset >= dsb->playpos)) {
1698 TRACE("signalled event %d (%d)\n", event->hEventNotify, i);
1699 SetEvent(event->hEventNotify);
1702 if ((offset >= dsb->playpos) && (offset < (dsb->playpos + len))) {
1703 TRACE("signalled event %d (%d)\n", event->hEventNotify, i);
1704 SetEvent(event->hEventNotify);
1710 /* WAV format info can be found at: */
1712 /* http://www.cwi.nl/ftp/audio/AudioFormats.part2 */
1713 /* ftp://ftp.cwi.nl/pub/audio/RIFF-format */
1715 /* Import points to remember: */
1717 /* 8-bit WAV is unsigned */
1718 /* 16-bit WAV is signed */
1720 static inline INT16 cvtU8toS16(BYTE byte)
1722 INT16 s = (byte - 128) << 8;
1727 static inline BYTE cvtS16toU8(INT16 word)
1729 BYTE b = (word + 32768) >> 8;
1735 /* We should be able to optimize these two inline functions */
1736 /* so that we aren't doing 8->16->8 conversions when it is */
1737 /* not necessary. But this is still a WIP. Optimize later. */
1738 static inline void get_fields(const IDirectSoundBufferImpl *dsb, BYTE *buf, INT *fl, INT *fr)
1740 INT16 *bufs = (INT16 *) buf;
1742 /* TRACE(dsound, "(%p)", buf); */
1743 if ((dsb->wfx.wBitsPerSample == 8) && dsb->wfx.nChannels == 2) {
1744 *fl = cvtU8toS16(*buf);
1745 *fr = cvtU8toS16(*(buf + 1));
1749 if ((dsb->wfx.wBitsPerSample == 16) && dsb->wfx.nChannels == 2) {
1755 if ((dsb->wfx.wBitsPerSample == 8) && dsb->wfx.nChannels == 1) {
1756 *fl = cvtU8toS16(*buf);
1761 if ((dsb->wfx.wBitsPerSample == 16) && dsb->wfx.nChannels == 1) {
1767 FIXME("get_fields found an unsupported configuration\n");
1771 static inline void set_fields(BYTE *buf, INT fl, INT fr)
1773 INT16 *bufs = (INT16 *) buf;
1775 if ((primarybuf->wfx.wBitsPerSample == 8) && (primarybuf->wfx.nChannels == 2)) {
1776 *buf = cvtS16toU8(fl);
1777 *(buf + 1) = cvtS16toU8(fr);
1781 if ((primarybuf->wfx.wBitsPerSample == 16) && (primarybuf->wfx.nChannels == 2)) {
1787 if ((primarybuf->wfx.wBitsPerSample == 8) && (primarybuf->wfx.nChannels == 1)) {
1788 *buf = cvtS16toU8((fl + fr) >> 1);
1792 if ((primarybuf->wfx.wBitsPerSample == 16) && (primarybuf->wfx.nChannels == 1)) {
1793 *bufs = (fl + fr) >> 1;
1796 FIXME("set_fields found an unsupported configuration\n");
1800 /* Now with PerfectPitch (tm) technology */
1801 static INT DSOUND_MixerNorm(IDirectSoundBufferImpl *dsb, BYTE *buf, INT len)
1803 INT i, size, ipos, ilen, fieldL, fieldR;
1805 INT iAdvance = dsb->wfx.nBlockAlign;
1806 INT oAdvance = primarybuf->wfx.nBlockAlign;
1808 ibp = dsb->buffer + dsb->playpos;
1811 TRACE("(%p, %p, %p), playpos=%8.8lx\n", dsb, ibp, obp, dsb->playpos);
1812 /* Check for the best case */
1813 if ((dsb->freq == primarybuf->wfx.nSamplesPerSec) &&
1814 (dsb->wfx.wBitsPerSample == primarybuf->wfx.wBitsPerSample) &&
1815 (dsb->wfx.nChannels == primarybuf->wfx.nChannels)) {
1816 TRACE("(%p) Best case\n", dsb);
1817 if ((ibp + len) < (BYTE *)(dsb->buffer + dsb->buflen))
1818 memcpy(obp, ibp, len);
1820 memcpy(obp, ibp, dsb->buflen - dsb->playpos);
1821 memcpy(obp + (dsb->buflen - dsb->playpos),
1823 len - (dsb->buflen - dsb->playpos));
1828 /* Check for same sample rate */
1829 if (dsb->freq == primarybuf->wfx.nSamplesPerSec) {
1830 TRACE("(%p) Same sample rate %ld = primary %ld\n", dsb,
1831 dsb->freq, primarybuf->wfx.nSamplesPerSec);
1833 for (i = 0; i < len; i += oAdvance) {
1834 get_fields(dsb, ibp, &fieldL, &fieldR);
1837 set_fields(obp, fieldL, fieldR);
1839 if (ibp >= (BYTE *)(dsb->buffer + dsb->buflen))
1840 ibp = dsb->buffer; /* wrap */
1845 /* Mix in different sample rates */
1847 /* New PerfectPitch(tm) Technology (c) 1998 Rob Riggs */
1848 /* Patent Pending :-] */
1850 TRACE("(%p) Adjusting frequency: %ld -> %ld\n",
1851 dsb, dsb->freq, primarybuf->wfx.nSamplesPerSec);
1853 size = len / oAdvance;
1854 ilen = ((size * dsb->freqAdjust) >> DSOUND_FREQSHIFT) * iAdvance;
1855 for (i = 0; i < size; i++) {
1857 ipos = (((i * dsb->freqAdjust) >> DSOUND_FREQSHIFT) * iAdvance) + dsb->playpos;
1859 if (ipos >= dsb->buflen)
1860 ipos %= dsb->buflen; /* wrap */
1862 get_fields(dsb, (dsb->buffer + ipos), &fieldL, &fieldR);
1863 set_fields(obp, fieldL, fieldR);
1869 static void DSOUND_MixerVol(IDirectSoundBufferImpl *dsb, BYTE *buf, INT len)
1871 INT i, inc = primarybuf->wfx.wBitsPerSample >> 3;
1873 INT16 *bps = (INT16 *) buf;
1875 TRACE("(%p) left = %lx, right = %lx\n", dsb,
1876 dsb->lVolAdjust, dsb->rVolAdjust);
1877 if ((!(dsb->dsbd.dwFlags & DSBCAPS_CTRLPAN) || (dsb->pan == 0)) &&
1878 (!(dsb->dsbd.dwFlags & DSBCAPS_CTRLVOLUME) || (dsb->volume == 0)) &&
1879 !(dsb->dsbd.dwFlags & DSBCAPS_CTRL3D))
1880 return; /* Nothing to do */
1882 /* If we end up with some bozo coder using panning or 3D sound */
1883 /* with a mono primary buffer, it could sound very weird using */
1884 /* this method. Oh well, tough patooties. */
1886 for (i = 0; i < len; i += inc) {
1892 /* 8-bit WAV is unsigned, but we need to operate */
1893 /* on signed data for this to work properly */
1895 val = ((val * (i & inc ? dsb->rVolAdjust : dsb->lVolAdjust)) >> 15);
1900 /* 16-bit WAV is signed -- much better */
1902 val = ((val * ((i & inc) ? dsb->rVolAdjust : dsb->lVolAdjust)) >> 15);
1908 FIXME("MixerVol had a nasty error\n");
1914 static void DSOUND_Mixer3D(IDirectSoundBufferImpl *dsb, BYTE *buf, INT len)
1917 DWORD buflen, playpos;
1919 buflen = dsb->ds3db->buflen;
1920 playpos = (dsb->playpos * primarybuf->wfx.nBlockAlign) / dsb->wfx.nBlockAlign;
1921 ibp = dsb->ds3db->buffer + playpos;
1924 if (playpos > buflen) {
1925 FIXME("Major breakage");
1929 if (len <= (playpos + buflen))
1930 memcpy(obp, ibp, len);
1932 memcpy(obp, ibp, buflen - playpos);
1933 memcpy(obp + (buflen - playpos),
1935 len - (buflen - playpos));
1941 static void *tmp_buffer;
1942 static size_t tmp_buffer_len = 0;
1944 static void *DSOUND_tmpbuffer(size_t len)
1946 if (len>tmp_buffer_len) {
1947 void *new_buffer = realloc(tmp_buffer, len);
1949 tmp_buffer = new_buffer;
1950 tmp_buffer_len = len;
1957 static DWORD DSOUND_MixInBuffer(IDirectSoundBufferImpl *dsb)
1959 INT i, len, ilen, temp, field;
1960 INT advance = primarybuf->wfx.wBitsPerSample >> 3;
1961 BYTE *buf, *ibuf, *obuf;
1962 INT16 *ibufs, *obufs;
1964 len = DSOUND_FRAGLEN; /* The most we will use */
1965 if (!(dsb->playflags & DSBPLAY_LOOPING)) {
1966 temp = MulDiv(primarybuf->wfx.nAvgBytesPerSec, dsb->buflen,
1967 dsb->nAvgBytesPerSec) -
1968 MulDiv(primarybuf->wfx.nAvgBytesPerSec, dsb->playpos,
1969 dsb->nAvgBytesPerSec);
1970 len = (len > temp) ? temp : len;
1972 len &= ~3; /* 4 byte alignment */
1975 /* This should only happen if we aren't looping and temp < 4 */
1977 /* We skip the remainder, so check for possible events */
1978 DSOUND_CheckEvent(dsb, dsb->buflen - dsb->playpos);
1983 /* Check for DSBPN_OFFSETSTOP */
1984 DSOUND_CheckEvent(dsb, 0);
1988 /* Been seeing segfaults in malloc() for some reason... */
1989 TRACE("allocating buffer (size = %d)\n", len);
1990 if ((buf = ibuf = (BYTE *) DSOUND_tmpbuffer(len)) == NULL)
1993 TRACE("MixInBuffer (%p) len = %d\n", dsb, len);
1995 ilen = DSOUND_MixerNorm(dsb, ibuf, len);
1996 if ((dsb->dsbd.dwFlags & DSBCAPS_CTRLPAN) ||
1997 (dsb->dsbd.dwFlags & DSBCAPS_CTRLVOLUME))
1998 DSOUND_MixerVol(dsb, ibuf, len);
2000 obuf = primarybuf->buffer + primarybuf->playpos;
2001 for (i = 0; i < len; i += advance) {
2002 obufs = (INT16 *) obuf;
2003 ibufs = (INT16 *) ibuf;
2004 if (primarybuf->wfx.wBitsPerSample == 8) {
2005 /* 8-bit WAV is unsigned */
2006 field = (*ibuf - 128);
2007 field += (*obuf - 128);
2008 field = field > 127 ? 127 : field;
2009 field = field < -128 ? -128 : field;
2010 *obuf = field + 128;
2012 /* 16-bit WAV is signed */
2015 field = field > 32767 ? 32767 : field;
2016 field = field < -32768 ? -32768 : field;
2021 if (obuf >= (BYTE *)(primarybuf->buffer + primarybuf->buflen))
2022 obuf = primarybuf->buffer;
2026 if (dsb->dsbd.dwFlags & DSBCAPS_CTRLPOSITIONNOTIFY)
2027 DSOUND_CheckEvent(dsb, ilen);
2029 dsb->playpos += ilen;
2030 dsb->writepos = dsb->playpos + ilen;
2032 if (dsb->playpos >= dsb->buflen) {
2033 if (!(dsb->playflags & DSBPLAY_LOOPING)) {
2037 DSOUND_CheckEvent(dsb, 0); /* For DSBPN_OFFSETSTOP */
2039 dsb->playpos %= dsb->buflen; /* wrap */
2042 if (dsb->writepos >= dsb->buflen)
2043 dsb->writepos %= dsb->buflen;
2048 static DWORD WINAPI DSOUND_MixPrimary(void)
2050 INT i, len, maxlen = 0;
2051 IDirectSoundBufferImpl *dsb;
2053 for (i = dsound->nrofbuffers - 1; i >= 0; i--) {
2054 dsb = dsound->buffers[i];
2056 if (!dsb || !(ICOM_VTBL(dsb)))
2058 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)dsb);
2059 if (dsb->buflen && dsb->playing) {
2060 EnterCriticalSection(&(dsb->lock));
2061 len = DSOUND_MixInBuffer(dsb);
2062 maxlen = len > maxlen ? len : maxlen;
2063 LeaveCriticalSection(&(dsb->lock));
2065 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)dsb);
2071 static int DSOUND_OpenAudio(void)
2075 if (primarybuf == NULL)
2076 return DSERR_OUTOFMEMORY;
2078 while (audiofd >= 0)
2081 /* we will most likely not get one, avoid excessive opens ... */
2082 if (audiofd == -ENODEV)
2084 audiofd = open("/dev/audio",O_WRONLY);
2086 /* Don't worry if sound is busy at the moment */
2087 if ((errno != EBUSY) && (errno != ENODEV))
2088 perror("open /dev/audio");
2093 /* We should probably do something here if SETFRAGMENT fails... */
2094 audioFragment=0x0002000c;
2095 if (-1==ioctl(audiofd,SNDCTL_DSP_SETFRAGMENT,&audioFragment))
2096 perror("ioctl SETFRAGMENT");
2099 DSOUND_setformat(&(primarybuf->wfx));
2104 static void DSOUND_CloseAudio(void)
2108 neutral = primarybuf->wfx.wBitsPerSample == 8 ? 128 : 0;
2109 audioOK = 0; /* race condition */
2111 /* It's possible we've been called with audio closed */
2112 /* from SetFormat()... this is just to force a call */
2113 /* to OpenAudio() to reset the hardware properly */
2116 primarybuf->playpos = 0;
2117 primarybuf->writepos = DSOUND_FRAGLEN;
2118 memset(primarybuf->buffer, neutral, primarybuf->buflen);
2120 TRACE("Audio stopped\n");
2123 static int DSOUND_WriteAudio(char *buf, int len)
2125 int result, left = 0;
2127 while (left < len) {
2128 result = write(audiofd, buf + left, len - left);
2140 static void DSOUND_OutputPrimary(int len)
2142 int neutral, flen1, flen2;
2143 char *frag1, *frag2;
2145 /* This is a bad place for this. We need to clear the */
2146 /* buffer with a neutral value, for unsigned 8-bit WAVE */
2147 /* that's 128, for signed 16-bit it's 0 */
2148 neutral = primarybuf->wfx.wBitsPerSample == 8 ? 128 : 0;
2151 EnterCriticalSection(&(primarybuf->lock));
2154 if ((audioOK == 1) || (DSOUND_OpenAudio() == 0)) {
2155 if (primarybuf->playpos + len >= primarybuf->buflen) {
2156 frag1 = primarybuf->buffer + primarybuf->playpos;
2157 flen1 = primarybuf->buflen - primarybuf->playpos;
2158 frag2 = primarybuf->buffer;
2159 flen2 = len - (primarybuf->buflen - primarybuf->playpos);
2160 if (DSOUND_WriteAudio(frag1, flen1) != 0) {
2161 perror("DSOUND_WriteAudio");
2162 LeaveCriticalSection(&(primarybuf->lock));
2165 memset(frag1, neutral, flen1);
2166 if (DSOUND_WriteAudio(frag2, flen2) != 0) {
2167 perror("DSOUND_WriteAudio");
2168 LeaveCriticalSection(&(primarybuf->lock));
2171 memset(frag2, neutral, flen2);
2173 frag1 = primarybuf->buffer + primarybuf->playpos;
2175 if (DSOUND_WriteAudio(frag1, flen1) != 0) {
2176 perror("DSOUND_WriteAudio");
2177 LeaveCriticalSection(&(primarybuf->lock));
2180 memset(frag1, neutral, flen1);
2183 /* Can't play audio at the moment -- we need to sleep */
2184 /* to make up for the time we'd be blocked in write() */
2188 primarybuf->playpos += len;
2189 if (primarybuf->playpos >= primarybuf->buflen)
2190 primarybuf->playpos %= primarybuf->buflen;
2191 primarybuf->writepos = primarybuf->playpos + DSOUND_FRAGLEN;
2192 if (primarybuf->writepos >= primarybuf->buflen)
2193 primarybuf->writepos %= primarybuf->buflen;
2195 LeaveCriticalSection(&(primarybuf->lock));
2199 static DWORD WINAPI DSOUND_thread(LPVOID arg)
2203 TRACE("dsound is at pid %d\n",getpid());
2206 WARN("DSOUND thread giving up.\n");
2210 /* EP: since the thread creating this thread can
2211 * die before the end of the DSOUND one, this
2213 * What shall be tested is whether the DSOUND thread
2214 * is the last one in the process
2217 WARN("DSOUND father died? Giving up.\n");
2221 /* RACE: dsound could be deleted */
2222 IDirectSound_AddRef((LPDIRECTSOUND)dsound);
2223 if (primarybuf == NULL) {
2224 /* Should never happen */
2225 WARN("Lost the primary buffer!\n");
2226 IDirectSound_Release((LPDIRECTSOUND)dsound);
2231 EnterCriticalSection(&(primarybuf->lock));
2232 len = DSOUND_MixPrimary();
2233 LeaveCriticalSection(&(primarybuf->lock));
2236 if (primarybuf->playing)
2237 len = DSOUND_FRAGLEN > len ? DSOUND_FRAGLEN : len;
2239 /* This does all the work */
2240 DSOUND_OutputPrimary(len);
2242 /* no buffers playing -- close and wait */
2244 DSOUND_CloseAudio();
2247 IDirectSound_Release((LPDIRECTSOUND)dsound);
2252 #endif /* HAVE_OSS */
2254 HRESULT WINAPI DirectSoundCreate(REFGUID lpGUID,LPDIRECTSOUND *ppDS,IUnknown *pUnkOuter )
2256 IDirectSoundImpl** ippDS=(IDirectSoundImpl**)ppDS;
2258 TRACE("(%p,%p,%p)\n",lpGUID,ippDS,pUnkOuter);
2260 TRACE("DirectSoundCreate (%p)\n", ippDS);
2265 return DSERR_INVALIDPARAM;
2268 IDirectSound_AddRef((LPDIRECTSOUND)dsound);
2273 /* Check that we actually have audio capabilities */
2274 /* If we do, whether it's busy or not, we continue */
2275 /* otherwise we return with DSERR_NODRIVER */
2277 audiofd = open("/dev/audio",O_WRONLY);
2278 if (audiofd == -1) {
2280 if (errno == ENODEV) {
2281 MESSAGE("No sound hardware found, but continuing anyway.\n");
2282 } else if (errno == EBUSY) {
2283 MESSAGE("Sound device busy, will keep trying.\n");
2285 MESSAGE("Unexpected error (%d) while checking for sound support.\n",errno);
2286 return DSERR_GENERIC;
2293 *ippDS = (IDirectSoundImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundImpl));
2295 return DSERR_OUTOFMEMORY;
2298 ICOM_VTBL(*ippDS) = &dsvt;
2299 (*ippDS)->buffers = NULL;
2300 (*ippDS)->nrofbuffers = 0;
2302 (*ippDS)->wfx.wFormatTag = 1;
2303 (*ippDS)->wfx.nChannels = 2;
2304 (*ippDS)->wfx.nSamplesPerSec = 22050;
2305 (*ippDS)->wfx.nAvgBytesPerSec = 44100;
2306 (*ippDS)->wfx.nBlockAlign = 2;
2307 (*ippDS)->wfx.wBitsPerSample = 8;
2314 if (primarybuf == NULL) {
2318 dsbd.dwSize = sizeof(DSBUFFERDESC);
2319 dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;
2320 dsbd.dwBufferBytes = 0;
2321 dsbd.lpwfxFormat = &(dsound->wfx);
2322 hr = IDirectSound_CreateSoundBuffer(*ppDS, &dsbd, (LPDIRECTSOUNDBUFFER*)&primarybuf, NULL);
2325 dsound->primary = primarybuf;
2327 memset(primarybuf->buffer, 128, primarybuf->buflen);
2328 hnd = CreateThread(NULL,0,DSOUND_thread,0,0,&xid);
2332 MessageBoxA(0,"DirectSound needs the Open Sound System Driver, which has not been found by ./configure.","WINE DirectSound",MB_OK|MB_ICONSTOP);
2333 return DSERR_NODRIVER;
2337 /*******************************************************************************
2338 * DirectSound ClassFactory
2342 /* IUnknown fields */
2343 ICOM_VFIELD(IClassFactory);
2345 } IClassFactoryImpl;
2347 static HRESULT WINAPI
2348 DSCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
2349 ICOM_THIS(IClassFactoryImpl,iface);
2351 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
2352 return E_NOINTERFACE;
2356 DSCF_AddRef(LPCLASSFACTORY iface) {
2357 ICOM_THIS(IClassFactoryImpl,iface);
2358 return ++(This->ref);
2361 static ULONG WINAPI DSCF_Release(LPCLASSFACTORY iface) {
2362 ICOM_THIS(IClassFactoryImpl,iface);
2363 /* static class, won't be freed */
2364 return --(This->ref);
2367 static HRESULT WINAPI DSCF_CreateInstance(
2368 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
2370 ICOM_THIS(IClassFactoryImpl,iface);
2372 TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
2373 if ( IsEqualGUID( &IID_IDirectSound, riid ) ) {
2374 /* FIXME: reuse already created dsound if present? */
2375 return DirectSoundCreate(riid,(LPDIRECTSOUND*)ppobj,pOuter);
2377 return E_NOINTERFACE;
2380 static HRESULT WINAPI DSCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
2381 ICOM_THIS(IClassFactoryImpl,iface);
2382 FIXME("(%p)->(%d),stub!\n",This,dolock);
2386 static ICOM_VTABLE(IClassFactory) DSCF_Vtbl = {
2387 DSCF_QueryInterface,
2390 DSCF_CreateInstance,
2393 static IClassFactoryImpl DSOUND_CF = {&DSCF_Vtbl, 1 };
2395 /*******************************************************************************
2396 * DllGetClassObject [DSOUND.4]
2397 * Retrieves class object from a DLL object
2400 * Docs say returns STDAPI
2403 * rclsid [I] CLSID for the class object
2404 * riid [I] Reference to identifier of interface for class object
2405 * ppv [O] Address of variable to receive interface pointer for riid
2409 * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
2412 DWORD WINAPI DSOUND_DllGetClassObject(REFCLSID rclsid,REFIID riid,LPVOID *ppv)
2414 TRACE("(%p,%p,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
2415 if ( IsEqualCLSID( &IID_IClassFactory, riid ) ) {
2416 *ppv = (LPVOID)&DSOUND_CF;
2417 IClassFactory_AddRef((IClassFactory*)*ppv);
2421 FIXME("(%p,%p,%p): no interface found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
2422 return CLASS_E_CLASSNOTAVAILABLE;
2426 /*******************************************************************************
2427 * DllCanUnloadNow [DSOUND.3] Determines whether the DLL is in use.
2433 DWORD WINAPI DSOUND_DllCanUnloadNow(void)
2435 FIXME("(void): stub\n");