[PATCH] dsound: Use a 2 stage mixing/normalization for sound
Maarten Lankhorst
maarten at codeweavers.com
Sat Oct 13 13:15:40 CDT 2007
---
dlls/dsound/dsound.c | 5 +-
dlls/dsound/dsound_private.h | 9 ++-
dlls/dsound/mixer.c | 109 +++++++++++++++--------------------------
dlls/dsound/primary.c | 21 ++++++++-
4 files changed, 69 insertions(+), 75 deletions(-)
diff --git a/dlls/dsound/dsound.c b/dlls/dsound/dsound.c
index ed6c221..8368457 100644
--- a/dlls/dsound/dsound.c
+++ b/dlls/dsound/dsound.c
@@ -1271,8 +1271,9 @@ ULONG DirectSoundDevice_Release(DirectSoundDevice * device)
DSOUND_renderer[device->drvdesc.dnDevNode] = NULL;
- HeapFree(GetProcessHeap(),0,device->tmp_buffer);
- HeapFree(GetProcessHeap(),0,device->buffer);
+ HeapFree(GetProcessHeap(), 0, device->tmp_buffer);
+ HeapFree(GetProcessHeap(), 0, device->mix_buffer);
+ HeapFree(GetProcessHeap(), 0, device->buffer);
RtlDeleteResource(&device->buffer_list_lock);
device->mixlock.DebugInfo->Spare[0] = 0;
DeleteCriticalSection(&device->mixlock);
diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h
index 339877e..a5e3ddd 100644
--- a/dlls/dsound/dsound_private.h
+++ b/dlls/dsound/dsound_private.h
@@ -104,8 +104,11 @@ struct DirectSoundDevice
PrimaryBufferImpl* primary;
DSBUFFERDESC dsbd;
DWORD speaker_config;
- LPBYTE tmp_buffer;
- DWORD tmp_buffer_len;
+ LPBYTE tmp_buffer, mix_buffer;
+ DWORD tmp_buffer_len, mix_buffer_len;
+
+ mixfunc mixfunction;
+ normfunc normfunction;
/* DirectSound3DListener fields */
IDirectSound3DListenerImpl* listener;
@@ -441,7 +444,7 @@ HRESULT DSOUND_ReopenDevice(DirectSoundDevice *device, BOOL forcewave);
HRESULT DSOUND_FullDuplexCreate(REFIID riid, LPDIRECTSOUNDFULLDUPLEX* ppDSFD);
/* mixer.c */
-
+DWORD DSOUND_bufpos_to_mixpos(const DirectSoundDevice* device, DWORD pos);
void DSOUND_CheckEvent(const IDirectSoundBufferImpl *dsb, DWORD playpos, int len);
void DSOUND_RecalcVolPan(PDSVOLUMEPAN volpan);
void DSOUND_AmpFactorToVolPan(PDSVOLUMEPAN volpan);
diff --git a/dlls/dsound/mixer.c b/dlls/dsound/mixer.c
index 975bffd..77bc6ad 100644
--- a/dlls/dsound/mixer.c
+++ b/dlls/dsound/mixer.c
@@ -90,6 +90,19 @@ void DSOUND_AmpFactorToVolPan(PDSVOLUMEPAN volpan)
TRACE("Vol=%d Pan=%d\n", volpan->lVolume, volpan->lPan);
}
+/** Convert a primary buffer position to a pointer position for device->mix_buffer
+ * device: DirectSoundDevice for which to calculate
+ * pos: Primary buffer position to converts
+ * Returns: Offset for mix_buffer
+ */
+DWORD DSOUND_bufpos_to_mixpos(const DirectSoundDevice* device, DWORD pos)
+{
+ DWORD ret = pos * 32 / device->pwfx->wBitsPerSample;
+ if (device->pwfx->wBitsPerSample == 32)
+ ret *= 2;
+ return ret;
+}
+
/* NOTE: Not all secpos have to always be mapped to a bufpos, other way around is always the case
* DWORD64 is used here because a single DWORD wouldn't be big enough to fit the freqAcc for big buffers
*/
@@ -466,9 +479,9 @@ static LPBYTE DSOUND_MixerVol(const IDirectSoundBufferImpl *dsb, DWORD writepos,
*/
static DWORD DSOUND_MixInBuffer(IDirectSoundBufferImpl *dsb, DWORD writepos, DWORD fraglen)
{
- INT i, len = fraglen, field, todo, ilen;
+ INT len = fraglen, ilen;
BYTE *ibuf = (dsb->tmp_buffer ? dsb->tmp_buffer : dsb->buffer->memory) + dsb->buf_mixpos, *volbuf;
- DWORD oldpos;
+ DWORD oldpos, mixbufpos;
TRACE("buf_mixpos=%d/%d sec_mixpos=%d/%d\n", dsb->buf_mixpos, dsb->tmp_buffer_len, dsb->sec_mixpos, dsb->buflen);
TRACE("(%p,%d,%d)\n",dsb,writepos,fraglen);
@@ -486,82 +499,26 @@ static DWORD DSOUND_MixInBuffer(IDirectSoundBufferImpl *dsb, DWORD writepos, DWO
if (volbuf)
ibuf = volbuf;
+ mixbufpos = DSOUND_bufpos_to_mixpos(dsb->device, writepos);
/* Now mix the temporary buffer into the devices main buffer */
- if (dsb->device->pwfx->wBitsPerSample == 8) {
- BYTE *obuf = dsb->device->buffer + writepos;
-
- if ((writepos + len) <= dsb->device->buflen)
- todo = len;
- else
- todo = dsb->device->buflen - writepos;
-
- for (i = 0; i < todo; i++) {
- /* 8-bit WAV is unsigned */
- field = (*ibuf++ - 128);
- field += (*obuf - 128);
- if (field > 127) field = 127;
- else if (field < -128) field = -128;
- *obuf++ = field + 128;
- }
-
- if (todo < len) {
- todo = len - todo;
- obuf = dsb->device->buffer;
-
- for (i = 0; i < todo; i++) {
- /* 8-bit WAV is unsigned */
- field = (*ibuf++ - 128);
- field += (*obuf - 128);
- if (field > 127) field = 127;
- else if (field < -128) field = -128;
- *obuf++ = field + 128;
- }
- }
- } else {
- INT16 *ibufs, *obufs;
-
- ibufs = (INT16 *) ibuf;
- obufs = (INT16 *)(dsb->device->buffer + writepos);
-
- if ((writepos + len) <= dsb->device->buflen)
- todo = len / 2;
- else
- todo = (dsb->device->buflen - writepos) / 2;
-
- for (i = 0; i < todo; i++) {
- /* 16-bit WAV is signed */
- field = *ibufs++;
-
- field += *obufs;
- if (field > 32767) field = 32767;
- else if (field < -32768) field = -32768;
- *obufs++ = field;
- }
-
- if (todo < (len / 2)) {
- todo = (len / 2) - todo;
- obufs = (INT16 *)dsb->device->buffer;
-
- for (i = 0; i < todo; i++) {
- /* 16-bit WAV is signed */
- field = *ibufs++;
- field += *obufs;
- if (field > 32767) field = 32767;
- else if (field < -32768) field = -32768;
- *obufs++ = field;
- }
- }
+ if ((writepos + len) <= dsb->device->buflen)
+ dsb->device->mixfunction(ibuf, dsb->device->mix_buffer + mixbufpos, len);
+ else
+ {
+ DWORD todo = dsb->device->buflen - writepos;
+ dsb->device->mixfunction(ibuf, dsb->device->mix_buffer + mixbufpos, todo);
+ dsb->device->mixfunction(ibuf + todo, dsb->device->mix_buffer, len - todo);
}
oldpos = dsb->sec_mixpos;
dsb->buf_mixpos += len;
if (dsb->buf_mixpos >= dsb->tmp_buffer_len) {
+ if (dsb->buf_mixpos > dsb->tmp_buffer_len)
+ ERR("Mixpos (%u) past buflen (%u), capping...\n", dsb->buf_mixpos, dsb->tmp_buffer_len);
if (dsb->playflags & DSBPLAY_LOOPING) {
dsb->buf_mixpos -= dsb->tmp_buffer_len;
} else if (dsb->buf_mixpos >= dsb->tmp_buffer_len) {
- if (dsb->buf_mixpos > dsb->tmp_buffer_len)
- ERR("Mixpos (%u) past buflen (%u), capping...\n", dsb->buf_mixpos, dsb->tmp_buffer_len);
dsb->buf_mixpos = dsb->sec_mixpos = 0;
dsb->state = STATE_STOPPED;
}
@@ -817,7 +774,7 @@ static void DSOUND_PerformMix(DirectSoundDevice *device)
if (device->priolevel != DSSCL_WRITEPRIMARY) {
BOOL recover = FALSE, all_stopped = FALSE;
- DWORD playpos, writepos, writelead, maxq, frag, prebuff_max, prebuff_left, size1, size2;
+ DWORD playpos, writepos, writelead, maxq, frag, prebuff_max, prebuff_left, size1, size2, mixplaypos, mixplaypos2;
LPVOID buf1, buf2;
BOOL lock = (device->hwbuf && !(device->drvdesc.dwFlags & DSDDESC_DONTNEEDPRIMARYLOCK));
BOOL mustlock = FALSE;
@@ -836,12 +793,16 @@ static void DSOUND_PerformMix(DirectSoundDevice *device)
playpos,writepos,device->playpos,device->mixpos,device->buflen);
assert(device->playpos < device->buflen);
+ mixplaypos = DSOUND_bufpos_to_mixpos(device, device->playpos);
+ mixplaypos2 = DSOUND_bufpos_to_mixpos(device, playpos);
/* wipe out just-played sound data */
if (playpos < device->playpos) {
buf1 = device->buffer + device->playpos;
buf2 = device->buffer;
size1 = device->buflen - device->playpos;
size2 = playpos;
+ FillMemory(device->mix_buffer + mixplaypos, device->mix_buffer_len - mixplaypos, 0);
+ FillMemory(device->mix_buffer, mixplaypos2, 0);
if (lock)
IDsDriverBuffer_Lock(device->hwbuf, &buf1, &size1, &buf2, &size2, device->playpos, size1+size2, 0);
FillMemory(buf1, size1, nfiller);
@@ -855,6 +816,7 @@ static void DSOUND_PerformMix(DirectSoundDevice *device)
buf2 = NULL;
size1 = playpos - device->playpos;
size2 = 0;
+ FillMemory(device->mix_buffer + mixplaypos, mixplaypos2 - mixplaypos, 0);
if (lock)
IDsDriverBuffer_Lock(device->hwbuf, &buf1, &size1, &buf2, &size2, device->playpos, size1+size2, 0);
FillMemory(buf1, size1, nfiller);
@@ -906,6 +868,15 @@ static void DSOUND_PerformMix(DirectSoundDevice *device)
/* do the mixing */
frag = DSOUND_MixToPrimary(device, writepos, maxq, mustlock, recover, &all_stopped);
+ if (frag + writepos > device->buflen)
+ {
+ DWORD todo = device->buflen - writepos;
+ device->normfunction(device->mix_buffer + DSOUND_bufpos_to_mixpos(device, writepos), device->buffer + writepos, todo);
+ device->normfunction(device->mix_buffer, device->buffer, frag - todo);
+ }
+ else
+ device->normfunction(device->mix_buffer + DSOUND_bufpos_to_mixpos(device, writepos), device->buffer + writepos, frag);
+
/* update the mix position, taking wrap-around into acount */
device->mixpos = writepos + frag;
device->mixpos %= device->buflen;
diff --git a/dlls/dsound/primary.c b/dlls/dsound/primary.c
index 57facf8..eec681c 100644
--- a/dlls/dsound/primary.c
+++ b/dlls/dsound/primary.c
@@ -188,6 +188,16 @@ static HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device)
device->prebuf = device->helfrags;
}
+ device->mix_buffer_len = DSOUND_bufpos_to_mixpos(device, device->buflen);
+ device->mix_buffer = HeapAlloc(GetProcessHeap(), 0, device->mix_buffer_len);
+ if (!device->mix_buffer)
+ {
+ if (device->hwbuf)
+ IDsDriverBuffer_Release(device->hwbuf);
+ device->hwbuf = NULL;
+ return DSERR_OUTOFMEMORY;
+ }
+
if (device->state == STATE_PLAYING) device->state = STATE_STARTING;
else if (device->state == STATE_STOPPING) device->state = STATE_STOPPED;
@@ -256,7 +266,10 @@ static HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device)
TRACE("fraglen=%d, overshot=%d\n", device->fraglen, overshot);
}
+ device->mixfunction = mixfunctions[device->pwfx->wBitsPerSample/8 - 1];
+ device->normfunction = normfunctions[device->pwfx->wBitsPerSample/8 - 1];
FillMemory(device->buffer, device->buflen, (device->pwfx->wBitsPerSample == 8) ? 128 : 0);
+ FillMemory(device->mix_buffer, device->mix_buffer_len, 0);
device->pwplay = device->pwqueue = device->playpos = device->mixpos = 0;
return err;
}
@@ -443,7 +456,7 @@ HRESULT DSOUND_PrimarySetFormat(DirectSoundDevice *device, LPCWAVEFORMATEX wfex,
RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
EnterCriticalSection(&(device->mixlock));
- if (wfex->wFormatTag == WAVE_FORMAT_PCM) {
+ if (wfex->wFormatTag == WAVE_FORMAT_PCM) {
alloc_size = sizeof(WAVEFORMATEX);
cp_size = sizeof(PCMWAVEFORMAT);
} else
@@ -520,6 +533,12 @@ HRESULT DSOUND_PrimarySetFormat(DirectSoundDevice *device, LPCWAVEFORMATEX wfex,
}
}
+ device->mix_buffer_len = DSOUND_bufpos_to_mixpos(device, device->buflen);
+ device->mix_buffer = HeapReAlloc(GetProcessHeap(), 0, device->mix_buffer, device->mix_buffer_len);
+ FillMemory(device->mix_buffer, device->mix_buffer_len, 0);
+ device->mixfunction = mixfunctions[device->pwfx->wBitsPerSample/8 - 1];
+ device->normfunction = normfunctions[device->pwfx->wBitsPerSample/8 - 1];
+
if (nSamplesPerSec != device->pwfx->nSamplesPerSec || bpp != device->pwfx->wBitsPerSample || chans != device->pwfx->nChannels) {
IDirectSoundBufferImpl** dsb = device->buffers;
for (i = 0; i < device->nrofbuffers; i++, dsb++) {
--
1.5.2.5
--------------060204080307040402050504--
More information about the wine-patches
mailing list