Fixed 8-bit WAV format handling (it is unsigned data).
Fixed off-by-one checks for buffer wrap.
Increment ref count for primary buffer in CreateSoundBuffer().
Added DSBPN_OFFSETSTOP support to position notification code.
Lots of minor parameter validation checks.
Stubs for: IDirectSound_initialize(), IDirectSound_Compact(),
and IDirectSound_GetSpeakerConfig().
Fixed freq shifting with 16-bit data problem, fixed 8bit<->16bit
conversion.
Lots of thread locking for DirectSound buffers.
Dealloc primary buffer when dsound is deallocated.
diff --git a/include/dsound.h b/include/dsound.h
index 7fdf129..999ed7d 100644
--- a/include/dsound.h
+++ b/include/dsound.h
@@ -2,6 +2,7 @@
#define __WINE_DSOUND_H
#include "windows.h"
+#include "winbase.h"
#include "compobj.h"
#include "mmsystem.h"
#include "d3d.h" //FIXME: Need to break out d3dtypes.h
@@ -161,6 +162,11 @@
#define DSSPEAKER_STEREO 4
#define DSSPEAKER_SURROUND 5
+#define DSSPEAKER_GEOMETRY_MIN 0x00000005 // 5 degrees
+#define DSSPEAKER_GEOMETRY_NARROW 0x0000000A // 10 degrees
+#define DSSPEAKER_GEOMETRY_WIDE 0x00000014 // 20 degrees
+#define DSSPEAKER_GEOMETRY_MAX 0x000000B4 // 180 degrees
+
typedef LPVOID* LPLPVOID;
@@ -191,7 +197,7 @@
STDMETHOD( Compact)(THIS ) PURE;
STDMETHOD( GetSpeakerConfig)(THIS_ LPDWORD ) PURE;
STDMETHOD( SetSpeakerConfig)(THIS_ DWORD ) PURE;
- STDMETHOD( Initialize)(THIS_ GUID FAR * ) PURE;
+ STDMETHOD( Initialize)(THIS_ LPGUID ) PURE;
} *LPDIRECTSOUND_VTABLE;
struct IDirectSound {
@@ -247,16 +253,19 @@
DWORD freq;
ULONG freqAdjust;
LONG volume,pan;
- ULONG lVolAdjust,rVolAdjust;
+ LONG lVolAdjust,rVolAdjust;
LPDIRECTSOUND dsound;
DSBUFFERDESC dsbd;
LPDSBPOSITIONNOTIFY notifies;
int nrofnotifies;
+ CRITICAL_SECTION lock;
};
#undef THIS
#define WINE_NOBUFFER 0x80000000
+#define DSBPN_OFFSETSTOP -1
+
#define THIS LPDIRECTSOUNDNOTIFY this
typedef struct IDirectSoundNotify_VTable {
/* IUnknown methods */
@@ -347,7 +356,7 @@
DWORD ref;
LPDIRECTSOUNDBUFFER dsb;
DS3DLISTENER ds3dl;
-
+ CRITICAL_SECTION lock;
};
#undef THIS
@@ -402,6 +411,7 @@
DS3DBUFFER ds3db;
LPBYTE buffer;
DWORD buflen;
+ CRITICAL_SECTION lock;
};
#undef THIS
#undef STDMETHOD
diff --git a/multimedia/dsound.c b/multimedia/dsound.c
index 5f5570e..bd9fbb7 100644
--- a/multimedia/dsound.c
+++ b/multimedia/dsound.c
@@ -59,6 +59,9 @@
/* #define USE_DSOUND3D 1 */
+#define DSOUND_BUFLEN (primarybuf->wfx.nAvgBytesPerSec >> 4)
+#define DSOUND_FREQSHIFT (14)
+
static int audiofd = -1;
static int audioOK = 0;
@@ -67,6 +70,7 @@
static LPDIRECTSOUNDBUFFER primarybuf = NULL;
static int DSOUND_setformat(LPWAVEFORMATEX wfex);
+static void DSOUND_CheckEvent(IDirectSoundBuffer *dsb, int len);
static void DSOUND_CloseAudio(void);
#endif
@@ -601,13 +605,6 @@
return this->ref;
}
-static int _sort_notifies(const void *a,const void *b) {
- LPDSBPOSITIONNOTIFY na = (LPDSBPOSITIONNOTIFY)a;
- LPDSBPOSITIONNOTIFY nb = (LPDSBPOSITIONNOTIFY)b;
-
- return na->dwOffset-nb->dwOffset;
-}
-
static HRESULT WINAPI IDirectSoundNotify_SetNotificationPositions(
LPDIRECTSOUNDNOTIFY this,DWORD howmuch,LPCDSBPOSITIONNOTIFY notify
) {
@@ -625,7 +622,7 @@
howmuch*sizeof(DSBPOSITIONNOTIFY)
);
this->dsb->nrofnotifies+=howmuch;
- qsort(this->dsb->notifies,this->dsb->nrofnotifies,sizeof(DSBPOSITIONNOTIFY),_sort_notifies);
+
return 0;
}
@@ -648,28 +645,40 @@
LPDIRECTSOUNDBUFFER *dsb;
int i;
+ // ****
+ EnterCriticalSection(&(primarybuf->lock));
+
if (primarybuf->wfx.nSamplesPerSec != wfex->nSamplesPerSec) {
dsb = dsound->buffers;
- for (i = 0; i < dsound->nrofbuffers; i++, dsb++)
- (*dsb)->freqAdjust = ((*dsb)->freq << 14) / wfex->nSamplesPerSec;
+ for (i = 0; i < dsound->nrofbuffers; i++, dsb++) {
+ // ****
+ EnterCriticalSection(&((*dsb)->lock));
+
+ (*dsb)->freqAdjust = ((*dsb)->freq << DSOUND_FREQSHIFT) /
+ wfex->nSamplesPerSec;
+
+ LeaveCriticalSection(&((*dsb)->lock));
+ // ****
+ }
}
- memcpy(&(primarybuf->wfx),wfex,sizeof(primarybuf->wfx));
- TRACE(dsound,"(%p,%p)\n", this,wfex);
+ memcpy(&(primarybuf->wfx), wfex, sizeof(primarybuf->wfx));
+
TRACE(dsound,"(formattag=0x%04x,chans=%d,samplerate=%ld"
"bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec,
wfex->nAvgBytesPerSec, wfex->nBlockAlign,
wfex->wBitsPerSample, wfex->cbSize);
-
- if (this->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER) {
- this->wfx.nAvgBytesPerSec =
- this->wfx.nSamplesPerSec * this->wfx.nBlockAlign;
- DSOUND_CloseAudio();
- return DS_OK;
- }
- return 0;
+ primarybuf->wfx.nAvgBytesPerSec =
+ this->wfx.nSamplesPerSec * this->wfx.nBlockAlign;
+
+ DSOUND_CloseAudio();
+
+ LeaveCriticalSection(&(primarybuf->lock));
+ // ****
+
+ return DS_OK;
}
static HRESULT WINAPI IDirectSoundBuffer_SetVolume(
@@ -694,12 +703,18 @@
return DS_OK;
}
+ // ****
+ EnterCriticalSection(&(this->lock));
+
this->volume = vol;
- temp = (double) (this->volume + (this->pan < 0 ? this->pan : 0));
- this->lVolAdjust = (ULONG) (pow(2.0, temp / 600.0) * 65536.0);
temp = (double) (this->volume - (this->pan > 0 ? this->pan : 0));
- this->rVolAdjust = (ULONG) (pow(2.0, temp / 600.0) * 65536.0);
+ this->lVolAdjust = (ULONG) (pow(2.0, temp / 600.0) * 32768.0);
+ temp = (double) (this->volume + (this->pan < 0 ? this->pan : 0));
+ this->rVolAdjust = (ULONG) (pow(2.0, temp / 600.0) * 32768.0);
+
+ LeaveCriticalSection(&(this->lock));
+ // ****
TRACE(dsound, "left = %lx, right = %lx\n", this->lVolAdjust, this->rVolAdjust);
@@ -727,9 +742,15 @@
if ((freq < DSBFREQUENCY_MIN) || (freq > DSBFREQUENCY_MAX))
return DSERR_INVALIDPARAM;
+ // ****
+ EnterCriticalSection(&(this->lock));
+
this->freq = freq;
- this->freqAdjust = (freq << 14) / primarybuf->wfx.nSamplesPerSec;
- this->nAvgBytesPerSec = freq * (this->wfx.wBitsPerSample >> 3) * this->wfx.nChannels;
+ this->freqAdjust = (freq << DSOUND_FREQSHIFT) / primarybuf->wfx.nSamplesPerSec;
+ this->nAvgBytesPerSec = freq * this->wfx.nBlockAlign;
+
+ LeaveCriticalSection(&(this->lock));
+ // ****
return DS_OK;
}
@@ -745,9 +766,19 @@
return 0;
}
-static HRESULT WINAPI IDirectSoundBuffer_Stop(LPDIRECTSOUNDBUFFER this) {
+static HRESULT WINAPI IDirectSoundBuffer_Stop(LPDIRECTSOUNDBUFFER this)
+{
TRACE(dsound,"(%p)\n",this);
+
+ // ****
+ EnterCriticalSection(&(this->lock));
+
this->playing = 0;
+ DSOUND_CheckEvent(this, 0);
+
+ LeaveCriticalSection(&(this->lock));
+ // ****
+
return 0;
}
@@ -763,6 +794,7 @@
if (--this->ref)
return this->ref;
+
for (i=0;i<this->dsound->nrofbuffers;i++)
if (this->dsound->buffers[i] == this)
break;
@@ -774,10 +806,17 @@
this->dsound->lpvtbl->fnRelease(this->dsound);
}
+ DeleteCriticalSection(&(this->lock));
+
if (this->ds3db && this->ds3db->lpvtbl)
this->ds3db->lpvtbl->fnRelease(this->ds3db);
+
HeapFree(GetProcessHeap(),0,this->buffer);
HeapFree(GetProcessHeap(),0,this);
+
+ if (this == primarybuf)
+ primarybuf = NULL;
+
return 0;
}
@@ -837,7 +876,7 @@
flags
);
if (flags & DSBLOCK_FROMWRITECURSOR)
- writecursor = this->writepos;
+ writecursor += this->writepos;
if (flags & DSBLOCK_ENTIREBUFFER)
writebytes = this->buflen;
if (writebytes > this->buflen)
@@ -871,7 +910,15 @@
LPDIRECTSOUNDBUFFER this,DWORD newpos
) {
TRACE(dsound,"(%p,%ld)\n",this,newpos);
+
+ // ****
+ EnterCriticalSection(&(this->lock));
+
this->playpos = newpos;
+
+ LeaveCriticalSection(&(this->lock));
+ // ****
+
return 0;
}
@@ -882,8 +929,8 @@
TRACE(dsound,"(%p,%ld)\n",this,pan);
- // What do we do if some moron uses SetPan with
- // a mono primary buffer?
+ if (!(this) || (pan > DSBPAN_RIGHT) || (pan < DSBPAN_LEFT))
+ return DSERR_INVALIDPARAM;
// You cannot set the pan of the primary buffer
// and you cannot use both pan and 3D controls
@@ -892,15 +939,18 @@
(this->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER))
return DSERR_CONTROLUNAVAIL;
- if ((pan > DSBPAN_RIGHT) || (pan < DSBPAN_LEFT))
- return DSERR_INVALIDPARAM;
+ // ****
+ EnterCriticalSection(&(this->lock));
this->pan = pan;
- temp = (double) (this->volume + (this->pan < 0 ? this->pan : 0));
- this->lVolAdjust = (ULONG) (pow(2.0, temp / 600.0) * 65536.0);
temp = (double) (this->volume - (this->pan > 0 ? this->pan : 0));
- this->rVolAdjust = (ULONG) (pow(2.0, temp / 600.0) * 65536.0);
+ this->lVolAdjust = (ULONG) (pow(2.0, temp / 600.0) * 32768.0);
+ temp = (double) (this->volume + (this->pan < 0 ? this->pan : 0));
+ this->rVolAdjust = (ULONG) (pow(2.0, temp / 600.0) * 32768.0);
+
+ LeaveCriticalSection(&(this->lock));
+ // ****
return DS_OK;
}
@@ -917,9 +967,6 @@
LPDIRECTSOUNDBUFFER this,LPVOID p1,DWORD x1,LPVOID p2,DWORD x2
) {
TRACE(dsound,"(%p,%p,%ld,%p,%ld):stub\n", this,p1,x1,p2,x2);
- this->writepos = this->playpos + (this->wfx.nAvgBytesPerSec >> 4);
- this->writepos %= this->buflen;
-
#if 0
// This is highly experimental and liable to break things
if (this->dsbd.dwFlags & DSBCAPS_CTRL3D)
@@ -1028,10 +1075,14 @@
static HRESULT WINAPI IDirectSound_CreateSoundBuffer(
LPDIRECTSOUND this,LPDSBUFFERDESC dsbd,LPLPDIRECTSOUNDBUFFER ppdsb,LPUNKNOWN lpunk
) {
- LPWAVEFORMATEX wfex = dsbd->lpwfxFormat;
+ LPWAVEFORMATEX wfex;
+ TRACE(dsound,"(%p,%p,%p,%p)\n",this,dsbd,ppdsb,lpunk);
+
+ if ((this == NULL) || (dsbd == NULL) || (ppdsb == NULL))
+ return DSERR_INVALIDPARAM;
+
if (TRACE_ON(dsound)) {
- TRACE(dsound,"(%p,%p,%p,%p)\n",this,dsbd,ppdsb,lpunk);
TRACE(dsound,"(size=%ld)\n",dsbd->dwSize);
TRACE(dsound,"(flags=0x%08lx\n",dsbd->dwFlags);
_dump_DSBCAPS(dsbd->dwFlags);
@@ -1039,6 +1090,8 @@
TRACE(dsound,"(lpwfxFormat=%p)\n",dsbd->lpwfxFormat);
}
+ wfex = dsbd->lpwfxFormat;
+
if (wfex)
TRACE(dsound,"(formattag=0x%04x,chans=%d,samplerate=%ld"
"bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
@@ -1048,6 +1101,7 @@
if (dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) {
if (primarybuf) {
+ primarybuf->lpvtbl->fnAddRef(primarybuf);
*ppdsb = primarybuf;
return DS_OK;
} // Else create primarybuf
@@ -1056,14 +1110,17 @@
*ppdsb = (LPDIRECTSOUNDBUFFER)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectSoundBuffer));
if (*ppdsb == NULL)
return DSERR_OUTOFMEMORY;
- (*ppdsb)->ref =1;
+ (*ppdsb)->ref = 1;
TRACE(dsound, "Created buffer at %p\n", *ppdsb);
- if (dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)
+ if (dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) {
(*ppdsb)->buflen = dsound->wfx.nAvgBytesPerSec;
- else
+ (*ppdsb)->freq = dsound->wfx.nSamplesPerSec;
+ } else {
(*ppdsb)->buflen = dsbd->dwBufferBytes;
+ (*ppdsb)->freq = dsbd->lpwfxFormat->nSamplesPerSec;
+ }
(*ppdsb)->buffer = (LPBYTE)HeapAlloc(GetProcessHeap(),0,(*ppdsb)->buflen);
if ((*ppdsb)->buffer == NULL) {
HeapFree(GetProcessHeap(),0,(*ppdsb));
@@ -1075,16 +1132,14 @@
(*ppdsb)->lpvtbl = &dsbvt;
(*ppdsb)->dsound = this;
(*ppdsb)->playing = 0;
- (*ppdsb)->lVolAdjust = (1 << 16);
- (*ppdsb)->rVolAdjust = (1 << 16);
- (*ppdsb)->freq = dsbd->lpwfxFormat->nSamplesPerSec;
+ (*ppdsb)->lVolAdjust = (1 << 15);
+ (*ppdsb)->rVolAdjust = (1 << 15);
if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
- (*ppdsb)->freqAdjust = ((*ppdsb)->freq << 14) /
+ (*ppdsb)->freqAdjust = ((*ppdsb)->freq << DSOUND_FREQSHIFT) /
primarybuf->wfx.nSamplesPerSec;
(*ppdsb)->nAvgBytesPerSec = (*ppdsb)->freq *
- (dsbd->lpwfxFormat->wBitsPerSample >> 3) *
- dsbd->lpwfxFormat->nChannels;
+ dsbd->lpwfxFormat->nBlockAlign;
}
memcpy(&((*ppdsb)->dsbd),dsbd,sizeof(*dsbd));
@@ -1097,9 +1152,10 @@
this->lpvtbl->fnAddRef(this);
}
- if (dsbd->lpwfxFormat && !(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER))
- memcpy(&((*ppdsb)->wfx), dsbd->lpwfxFormat,
- sizeof((*ppdsb)->wfx));
+ if (dsbd->lpwfxFormat)
+ memcpy(&((*ppdsb)->wfx), dsbd->lpwfxFormat, sizeof((*ppdsb)->wfx));
+
+ InitializeCriticalSection(&((*ppdsb)->lock));
#if 0
if (dsbd->dwFlags & DSBCAPS_CTRL3D) {
@@ -1217,9 +1273,11 @@
static ULONG WINAPI IDirectSound_Release(LPDIRECTSOUND this) {
TRACE(dsound,"(%p), ref was %ld\n",this,this->ref);
if (!--(this->ref)) {
+ DSOUND_CloseAudio();
+ while(IDirectSoundBuffer_Release(primarybuf)); // Deallocate
+ FIXME(dsound, "need to release all buffers!\n");
HeapFree(GetProcessHeap(),0,this);
dsound = NULL;
- DSOUND_CloseAudio();
return 0;
}
return this->ref;
@@ -1273,9 +1331,28 @@
return E_FAIL;
}
-static HRESULT WINAPI IDirectSound_Initialize(LPDIRECTSOUND this,GUID*lpguid) {
- FIXME(dsound,"(%p)->(%p),stub!\n",this,lpguid);
- return 0;
+static HRESULT WINAPI IDirectSound_Compact(
+ LPDIRECTSOUND this)
+{
+ TRACE(dsound, "(%p)\n", this);
+ return DS_OK;
+}
+
+static HRESULT WINAPI IDirectSound_GetSpeakerConfig(
+ LPDIRECTSOUND this,
+ LPDWORD lpdwSpeakerConfig)
+{
+ TRACE(dsound, "(%p, %p)\n", this, lpdwSpeakerConfig);
+ *lpdwSpeakerConfig = DSSPEAKER_STEREO | DSSPEAKER_GEOMETRY_NARROW;
+ return DS_OK;
+}
+
+static HRESULT WINAPI IDirectSound_Initialize(
+ LPDIRECTSOUND this,
+ LPGUID lpGuid)
+{
+ TRACE(dsound, "(%p, %p)\n", this, lpGuid);
+ return DS_OK;
}
static struct tagLPDIRECTSOUND_VTABLE dsvt = {
@@ -1286,8 +1363,8 @@
IDirectSound_GetCaps,
IDirectSound_DuplicateSoundBuffer,
IDirectSound_SetCooperativeLevel,
- (void *)8,
- (void *)9,
+ IDirectSound_Compact,
+ IDirectSound_GetSpeakerConfig,
IDirectSound_SetSpeakerConfig,
IDirectSound_Initialize
};
@@ -1356,68 +1433,77 @@
if (dsb->nrofnotifies == 0)
return;
- TRACE(dsound,"(%p)\n", dsb);
- for (i = 0; i < dsb->nrofnotifies; i++) {
+ TRACE(dsound,"(%p) buflen = %ld, playpos = %ld, len = %d\n",
+ dsb, dsb->buflen, dsb->playpos, len);
+ for (i = 0; i < dsb->nrofnotifies ; i++) {
event = dsb->notifies + i;
offset = event->dwOffset;
- if ((dsb->playpos + len) >= dsb->buflen)
- if ((offset <= (dsb->playpos + len - dsb->buflen)) ||
- (offset > dsb->playpos)) {
+ TRACE(dsound, "checking %d, position %ld, event = %d\n",
+ i, offset, event->hEventNotify);
+ // DSBPN_OFFSETSTOP has to be the last element. So this is
+ // OK. [Inside DirectX, p274]
+ //
+ // This also means we can't sort the entries by offset,
+ // because DSBPN_OFFSETSTOP == -1
+ if (offset == DSBPN_OFFSETSTOP) {
+ if (dsb->playing == 0) {
SetEvent(event->hEventNotify);
- TRACE(dsound,"signalled event %d\n", event->hEventNotify);
- }
- else
- if ((offset > dsb->playpos) || (offset <= (dsb->playpos + len))) {
+ TRACE(dsound,"signalled event %d (%d)\n", event->hEventNotify, i);
+ return;
+ } else
+ return;
+ }
+ if ((dsb->playpos + len) >= dsb->buflen) {
+ if ((offset < ((dsb->playpos + len) % dsb->buflen)) ||
+ (offset >= dsb->playpos)) {
+ TRACE(dsound,"signalled event %d (%d)\n", event->hEventNotify, i);
SetEvent(event->hEventNotify);
- TRACE(dsound,"signalled event %d\n", event->hEventNotify);
}
+ } else {
+ if ((offset >= dsb->playpos) && (offset < (dsb->playpos + len))) {
+ TRACE(dsound,"signalled event %d (%d)\n", event->hEventNotify, i);
+ SetEvent(event->hEventNotify);
+ }
+ }
}
}
-// This should be the correct way to do this.
-// Anyone want to do the optimized assembly?
-static inline short cvt8to16(char byte)
-{
- short s = 0, sbit = 1;
- char cbit = 1;
- int i;
+// WAV format info can be found at:
+//
+// http://www.cwi.nl/ftp/audio/AudioFormats.part2
+// ftp://ftp.cwi.nl/pub/audio/RIFF-format
+//
+// Import points to remember:
+//
+// 8-bit WAV is unsigned
+// 16-bit WAV is signed
- for (i = 0; i < 8; i++) {
- if (byte & cbit)
- s |= sbit;
- cbit <<= 1;
- sbit <<= 2;
- }
- if (byte < 0)
- s |= 0x8000; // sign bit
+static inline INT16 cvtU8toS16(BYTE byte)
+{
+ INT16 s = (byte - 128) << 8;
+
return s;
}
-static inline char cvt16to8(short word)
+static inline BYTE cvtS16toU8(INT16 word)
{
- char c = 0, cbit = 1;
- short sbits = 3;
- int i;
-
- for (i = 0; i < 7; i++) {
- if (word & sbits)
- c |= cbit;
- cbit <<= 1;
- sbits <<= 2;
- }
- if (word < 0)
- c |= 0x80; // sign bit
- return c;
+ BYTE b = (word + 32768) >> 8;
+
+ return b;
}
-static inline void get_fields(const IDirectSoundBuffer *dsb, char *buf, int *fl, int *fr)
+
+// We should be able to optimize these two inline functions
+// so that we aren't doing 8->16->8 conversions when it is
+// not necessary. But this is still a WIP. Optimize later.
+static inline void get_fields(const IDirectSoundBuffer *dsb, BYTE *buf, INT32 *fl, INT32 *fr)
{
- short *bufs = (short *) buf;
+ INT16 *bufs = (INT16 *) buf;
// TRACE(dsound, "(%p)", buf);
if ((dsb->wfx.wBitsPerSample == 8) && dsb->wfx.nChannels == 2) {
- *fl = cvt8to16(*buf);
- *fr = cvt8to16(*(buf + 1));
+ *fl = cvtU8toS16(*buf);
+ *fr = cvtU8toS16(*(buf + 1));
return;
}
@@ -1428,12 +1514,14 @@
}
if ((dsb->wfx.wBitsPerSample == 8) && dsb->wfx.nChannels == 1) {
- *fr = *fl = cvt8to16(*buf);
+ *fl = cvtU8toS16(*buf);
+ *fr = *fl;
return;
}
if ((dsb->wfx.wBitsPerSample == 16) && dsb->wfx.nChannels == 1) {
- *fr = *fl = *bufs;
+ *fl = *bufs;
+ *fr = *bufs;
return;
}
@@ -1441,13 +1529,13 @@
return;
}
-static inline void set_fields(char *buf, int fl, int fr)
+static inline void set_fields(BYTE *buf, INT32 fl, INT32 fr)
{
- short *bufs = (short *) buf;
+ INT16 *bufs = (INT16 *) buf;
if ((primarybuf->wfx.wBitsPerSample == 8) && (primarybuf->wfx.nChannels == 2)) {
- *buf = cvt16to8(fl);
- *(buf + 1) = cvt16to8(fr);
+ *buf = cvtS16toU8(fl);
+ *(buf + 1) = cvtS16toU8(fr);
return;
}
@@ -1458,12 +1546,12 @@
}
if ((primarybuf->wfx.wBitsPerSample == 8) && (primarybuf->wfx.nChannels == 1)) {
- *buf = cvt16to8((fl + fr) / 2);
+ *buf = cvtS16toU8((fl + fr) >> 1);
return;
}
if ((primarybuf->wfx.wBitsPerSample == 16) && (primarybuf->wfx.nChannels == 1)) {
- *bufs = (fl + fr) / 2;
+ *bufs = (fl + fr) >> 1;
return;
}
FIXME(dsound, "set_fields found an unsupported configuration\n");
@@ -1471,12 +1559,12 @@
}
// Now with PerfectPitch (tm) technology
-static void DSOUND_MixerNorm(IDirectSoundBuffer *dsb, char *buf, int len)
+static INT32 DSOUND_MixerNorm(IDirectSoundBuffer *dsb, BYTE *buf, INT32 len)
{
- int i, ipos, fieldL, fieldR;
- char *ibp, *obp;
- int iAdvance = dsb->wfx.nBlockAlign;
- int oAdvance = primarybuf->wfx.nBlockAlign;
+ INT32 i, size, ipos, ilen, fieldL, fieldR;
+ BYTE *ibp, *obp;
+ INT32 iAdvance = dsb->wfx.nBlockAlign;
+ INT32 oAdvance = primarybuf->wfx.nBlockAlign;
ibp = dsb->buffer + dsb->playpos;
obp = buf;
@@ -1487,7 +1575,7 @@
(dsb->wfx.wBitsPerSample == primarybuf->wfx.wBitsPerSample) &&
(dsb->wfx.nChannels == primarybuf->wfx.nChannels)) {
TRACE(dsound, "(%p) Best case\n", dsb);
- if ((ibp + len) <= (char *)(dsb->buffer + dsb->buflen))
+ if ((ibp + len) < (BYTE *)(dsb->buffer + dsb->buflen))
memcpy(obp, ibp, len);
else { // wrap
memcpy(obp, ibp, dsb->buflen - dsb->playpos);
@@ -1495,31 +1583,39 @@
dsb->buffer,
len - (dsb->buflen - dsb->playpos));
}
- return;
+ return len;
}
// Check for same sample rate
if (dsb->freq == primarybuf->wfx.nSamplesPerSec) {
TRACE(dsound, "(%p) Same sample rate %ld = primary %ld\n", dsb,
dsb->freq, primarybuf->wfx.nSamplesPerSec);
+ ilen = 0;
for (i = 0; i < len; i += oAdvance) {
get_fields(dsb, ibp, &fieldL, &fieldR);
ibp += iAdvance;
+ ilen += iAdvance;
set_fields(obp, fieldL, fieldR);
obp += oAdvance;
- if (ibp > (char *)(dsb->buffer + dsb->buflen))
+ if (ibp >= (BYTE *)(dsb->buffer + dsb->buflen))
ibp = dsb->buffer; // wrap
}
- return;
+ return (ilen);
}
// Mix in different sample rates
//
// New PerfectPitch(tm) Technology (c) 1998 Rob Riggs
// Patent Pending :-]
- for (i = 0; i < len; i += oAdvance) {
- ipos = (iAdvance * ((i * dsb->freqAdjust) >> 14)) + dsb->playpos;
+ TRACE(dsound, "(%p) Adjusting frequency: %ld -> %ld\n",
+ dsb, dsb->freq, primarybuf->wfx.nSamplesPerSec);
+
+ size = len / oAdvance;
+ ilen = ((size * dsb->freqAdjust) >> DSOUND_FREQSHIFT) * iAdvance;
+ for (i = 0; i < size; i++) {
+
+ ipos = (((i * dsb->freqAdjust) >> DSOUND_FREQSHIFT) * iAdvance) + dsb->playpos;
if (ipos >= dsb->buflen)
ipos %= dsb->buflen; // wrap
@@ -1528,14 +1624,14 @@
set_fields(obp, fieldL, fieldR);
obp += oAdvance;
}
- return;
+ return ilen;
}
-static void DSOUND_MixerVol(IDirectSoundBuffer *dsb, char *buf, int len)
+static void DSOUND_MixerVol(IDirectSoundBuffer *dsb, BYTE *buf, INT32 len)
{
- int i;
- char *bpc;
- short *bps;
+ INT32 i, inc = primarybuf->wfx.wBitsPerSample >> 3;
+ BYTE *bpc = buf;
+ INT16 *bps = (INT16 *) buf;
TRACE(dsound, "(%p) left = %lx, right = %lx\n", dsb,
dsb->lVolAdjust, dsb->rVolAdjust);
@@ -1548,22 +1644,25 @@
// with a mono primary buffer, it could sound very weird using
// this method. Oh well, tough patooties.
- for (i = 0; i < len; i += (primarybuf->wfx.wBitsPerSample >> 3)) {
- register int val;
+ for (i = 0; i < len; i += inc) {
+ INT32 val;
- switch (primarybuf->wfx.wBitsPerSample) {
+ switch (inc) {
- case 8:
- bpc = buf + i;
- val = *bpc;
- val = (val * (i & 1 ? dsb->rVolAdjust : dsb->lVolAdjust)) >> 16;
- *bpc = (char) val;
+ case 1:
+ // 8-bit WAV is unsigned, but we need to operate
+ // on signed data for this to work properly
+ val = *bpc - 128;
+ val = ((val * (i & inc ? dsb->rVolAdjust : dsb->lVolAdjust)) >> 15);
+ *bpc = val + 128;
+ bpc++;
break;
- case 16:
- bps = (short *) (buf + i);
+ case 2:
+ // 16-bit WAV is signed -- much better
val = *bps;
- val = (val * (i & 1 ? dsb->rVolAdjust : dsb->lVolAdjust)) >> 16;
- *bps = (short) val;
+ val = ((val * ((i & inc) ? dsb->rVolAdjust : dsb->lVolAdjust)) >> 15);
+ *bps = val;
+ bps++;
break;
default:
// Very ugly!
@@ -1573,9 +1672,9 @@
}
#ifdef USE_DSOUND3D
-static void DSOUND_Mixer3D(IDirectSoundBuffer *dsb, char *buf, int len)
+static void DSOUND_Mixer3D(IDirectSoundBuffer *dsb, BYTE *buf, INT32 len)
{
- char *ibp, *obp;
+ BYTE *ibp, *obp;
DWORD buflen, playpos;
buflen = dsb->ds3db->buflen;
@@ -1602,30 +1701,27 @@
static DWORD DSOUND_MixInBuffer(IDirectSoundBuffer *dsb)
{
- int i, len, ilen, temp, field;
- int advance = primarybuf->wfx.wBitsPerSample >> 3;
- char *buf, *ibuf, *obuf;
- short *ibufs, *obufs;
+ INT32 i, len, ilen, temp, field;
+ INT32 advance = primarybuf->wfx.wBitsPerSample >> 3;
+ BYTE *buf, *ibuf, *obuf;
+ INT16 *ibufs, *obufs;
- // The most we will use
- len = primarybuf->wfx.nAvgBytesPerSec >> 4; // 60 ms
- len &= ~3; // 4 byte alignment
+ len = DSOUND_BUFLEN; // The most we will use
+ len &= ~3; // 4 byte alignment
if (!(dsb->playflags & DSBPLAY_LOOPING)) {
temp = ((primarybuf->wfx.nAvgBytesPerSec * dsb->buflen) /
- dsb->wfx.nAvgBytesPerSec) -
+ dsb->nAvgBytesPerSec) -
((primarybuf->wfx.nAvgBytesPerSec * dsb->playpos) /
dsb->nAvgBytesPerSec);
len = (len > temp) ? temp : len;
}
- ilen = (len * dsb->nAvgBytesPerSec) / primarybuf->wfx.nAvgBytesPerSec;
-
- if ((buf = ibuf = (char *) malloc(len)) == NULL)
+ if ((buf = ibuf = (BYTE *) malloc(len)) == NULL)
return 0;
TRACE(dsound, "MixInBuffer (%p) len = %d\n", dsb, len);
- DSOUND_MixerNorm(dsb, ibuf, len);
+ ilen = DSOUND_MixerNorm(dsb, ibuf, len);
if ((dsb->dsbd.dwFlags & DSBCAPS_CTRLPAN) ||
(dsb->dsbd.dwFlags & DSBCAPS_CTRLVOLUME))
DSOUND_MixerVol(dsb, ibuf, len);
@@ -1633,52 +1729,54 @@
TRACE(dsound, "Mixing buffer - advance = %d\n", advance);
obuf = primarybuf->buffer + primarybuf->playpos;
for (i = 0; i < len; i += advance) {
- obufs = (short *) obuf;
- ibufs = (short *) ibuf;
+ obufs = (INT16 *) obuf;
+ ibufs = (INT16 *) ibuf;
if (primarybuf->wfx.wBitsPerSample == 8) {
- field = (char) *ibuf;
- field += (char) *obuf;
- field = field > 127 ? 127 : field;
- field = field < -128 ? -128 : field;
- *obuf = (char) field;
+ field = *ibuf;
+ field += *obuf;
+ // 8-bit WAV is unsigned
+ field = field > 255 ? 255 : field;
+ *obuf = field;
} else {
field = *ibufs;
field += *obufs;
+ // 16-bit WAV is signed
field = field > 32767 ? 32767 : field;
field = field < -32768 ? -32768 : field;
*obufs = field;
}
ibuf += advance;
obuf += advance;
- if (obuf > (char *)(primarybuf->buffer + primarybuf->buflen))
+ if (obuf >= (BYTE *)(primarybuf->buffer + primarybuf->buflen))
obuf = primarybuf->buffer;
}
free(buf);
if (dsb->dsbd.dwFlags & DSBCAPS_CTRLPOSITIONNOTIFY)
- DSOUND_CheckEvent(dsb, len);
+ DSOUND_CheckEvent(dsb, ilen);
dsb->playpos += ilen;
- dsb->writepos += ilen;
+ dsb->writepos = dsb->playpos + ilen;
if (dsb->playpos >= dsb->buflen) {
if (!(dsb->playflags & DSBPLAY_LOOPING)) {
dsb->playing = 0;
dsb->writepos = 0;
dsb->playpos = 0;
+ DSOUND_CheckEvent(dsb, 0); // For DSBPN_OFFSETSTOP
} else
- dsb->playpos -= dsb->buflen; // wrap
+ dsb->playpos %= dsb->buflen; // wrap
}
- if (dsb->writepos > dsb->buflen)
- dsb->writepos -= dsb->buflen;
+ if (dsb->writepos >= dsb->buflen)
+ dsb->writepos %= dsb->buflen;
return len;
}
static DWORD WINAPI DSOUND_MixPrimary(void)
{
- int i, len, maxlen = 0;
+ INT32 i, len, maxlen = 0;
IDirectSoundBuffer *dsb;
for (i = dsound->nrofbuffers - 1; i >= 0; i--) {
@@ -1688,18 +1786,14 @@
continue;
dsb->lpvtbl->fnAddRef(dsb);
if (dsb->buflen && dsb->playing) {
+ EnterCriticalSection(&(dsb->lock));
len = DSOUND_MixInBuffer(dsb);
maxlen = len > maxlen ? len : maxlen;
+ LeaveCriticalSection(&(dsb->lock));
}
dsb->lpvtbl->fnRelease(dsb);
}
- if (maxlen > 0) {
- primarybuf->writepos += maxlen;
- if (primarybuf->writepos > primarybuf->buflen)
- primarybuf->writepos -= primarybuf->buflen;
- }
-
return maxlen;
}
@@ -1735,7 +1829,7 @@
Sleep(5);
close(audiofd);
primarybuf->playpos = 0;
- primarybuf->writepos = primarybuf->wfx.nAvgBytesPerSec >> 4;
+ primarybuf->writepos = DSOUND_BUFLEN;
memset(primarybuf->buffer, 0, primarybuf->buflen);
audiofd = -1;
TRACE(dsound, "Audio stopped\n");
@@ -1759,7 +1853,7 @@
static DWORD WINAPI DSOUND_thread(LPVOID arg)
{
- int maxlen = primarybuf->wfx.nAvgBytesPerSec >> 4;
+ int maxlen = DSOUND_BUFLEN;
int len;
TRACE(dsound,"dsound is at pid %d\n",getpid());
@@ -1780,13 +1874,22 @@
dsound->lpvtbl->fnRelease(dsound);
continue;
}
+
+ // ****
+ EnterCriticalSection(&(primarybuf->lock));
len = DSOUND_MixPrimary();
+ LeaveCriticalSection(&(primarybuf->lock));
+ // ****
+
if (primarybuf->playing)
len = maxlen > len ? maxlen : len;
if (len) {
+ // ****
+ EnterCriticalSection(&(primarybuf->lock));
+
if (audioOK == 0)
DSOUND_OpenAudio();
- if (primarybuf->playpos + len > primarybuf->buflen) {
+ if (primarybuf->playpos + len >= primarybuf->buflen) {
if (DSOUND_WriteAudio(
primarybuf->buffer + primarybuf->playpos,
primarybuf->buflen - primarybuf->playpos)
@@ -1814,10 +1917,13 @@
}
primarybuf->playpos += len;
if (primarybuf->playpos >= primarybuf->buflen)
- primarybuf->playpos -= primarybuf->buflen;
+ primarybuf->playpos %= primarybuf->buflen;
primarybuf->writepos = primarybuf->playpos + maxlen;
if (primarybuf->writepos >= primarybuf->buflen)
- primarybuf->writepos -= primarybuf->buflen;
+ primarybuf->writepos %= primarybuf->buflen;
+
+ LeaveCriticalSection(&(primarybuf->lock));
+ // ****
} else {
/* no soundbuffer. close and wait. */
if (audioOK)
@@ -1836,12 +1942,23 @@
if (lpGUID)
TRACE(dsound,"(%p,%p,%p)\n",lpGUID,ppDS,pUnkOuter);
else
- TRACE(dsound,"DirectSoundCreate\n");
+ TRACE(dsound,"DirectSoundCreate (%p)\n", ppDS);
+
#ifdef HAVE_OSS
- if (primarybuf)
- return DSERR_ALLOCATED;
+
+ if (ppDS == NULL)
+ return DSERR_INVALIDPARAM;
+
+ if (primarybuf) {
+ dsound->lpvtbl->fnAddRef(dsound);
+ *ppDS = dsound;
+ return DS_OK;
+ }
*ppDS = (LPDIRECTSOUND)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSound));
+ if (*ppDS == NULL)
+ return DSERR_OUTOFMEMORY;
+
(*ppDS)->ref = 1;
(*ppDS)->lpvtbl = &dsvt;
(*ppDS)->buffers = NULL;
@@ -1868,15 +1985,13 @@
dsbd.dwBufferBytes = 0;
dsbd.lpwfxFormat = &(dsound->wfx);
hr = IDirectSound_CreateSoundBuffer(*ppDS, &dsbd, &primarybuf, NULL);
- if (hr != DS_OK) {
- dsound->primary = primarybuf;
- return hr;
- }
+ if (hr != DS_OK) return hr;
+ dsound->primary = primarybuf;
}
hnd = CreateThread(NULL,0,DSOUND_thread,0,0,&xid);
}
- return 0;
+ return DS_OK;
#else
MessageBox32A(0,"DirectSound needs the Open Sound System Driver, which has not been found by ./configure.","WINE DirectSound",MB_OK|MB_ICONSTOP);
return DSERR_NODRIVER;