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