From 4d1129f7859b6c777f0e281548d05e8ba5d5b3b8 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Wed, 7 Nov 2007 20:32:22 +0100 Subject: [PATCH] dsound: Use a 2 stage mixing/normalization for sound. --- 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 457ced1d8a7..ea947130ddc 100644 --- a/dlls/dsound/dsound.c +++ b/dlls/dsound/dsound.c @@ -1275,8 +1275,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 fbddefe59a5..004ed45f55a 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 08147822858..6598b03e381 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 57facf81e9f..eec681c3dfc 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++) { -- 2.11.4.GIT