From 93a0ca7c6c4e111e90d3735f232f796202e77ccd Mon Sep 17 00:00:00 2001 From: "Alexander E. Patrakov" Date: Mon, 12 Dec 2011 14:07:49 -0600 Subject: [PATCH] dsound: Clean up channels. --- dlls/dsound/dsound_convert.c | 18 +++++++++ dlls/dsound/dsound_private.h | 8 +++- dlls/dsound/mixer.c | 77 ++++++++++++++++-------------------- 3 files changed, 59 insertions(+), 44 deletions(-) diff --git a/dlls/dsound/dsound_convert.c b/dlls/dsound/dsound_convert.c index b670c044895..63f1eb0bfbe 100644 --- a/dlls/dsound/dsound_convert.c +++ b/dlls/dsound/dsound_convert.c @@ -104,6 +104,18 @@ static float getieee32(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD chann const bitsgetfunc getbpp[5] = {get8, get16, get24, get32, getieee32}; +float get_mono(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel) +{ + DWORD channels = dsb->pwfx->nChannels; + DWORD c; + float val = 0; + /* XXX: does Windows include LFE into the mix? */ + for (c = 0; c < channels; c++) + val += dsb->get_aux(dsb, pos, c); + val /= channels; + return val; +} + static void put8(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value) { BYTE* buf = dsb->device->tmp_buffer; @@ -158,6 +170,12 @@ static void put32(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, f const bitsputfunc putbpp[4] = {put8, put16, put24, put32}; +void put_mono2stereo(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value) +{ + dsb->put_aux(dsb, pos, 0, value); + dsb->put_aux(dsb, pos, 1, value); +} + static void mix8(signed char *src, INT *dst, unsigned len) { TRACE("%p - %p %d\n", src, dst, len); diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h index 9f30bff9969..5d1d62a1fa9 100644 --- a/dlls/dsound/dsound_private.h +++ b/dlls/dsound/dsound_private.h @@ -193,12 +193,16 @@ struct IDirectSoundBufferImpl LONG ds3db_lVolume; BOOL ds3db_need_recalc; /* Used for bit depth conversion */ - bitsgetfunc get; - bitsputfunc put; + int mix_channels; + bitsgetfunc get, get_aux; + bitsputfunc put, put_aux; struct list entry; }; +float get_mono(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel) DECLSPEC_HIDDEN; +void put_mono2stereo(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value) DECLSPEC_HIDDEN; + HRESULT IDirectSoundBufferImpl_Create( DirectSoundDevice *device, IDirectSoundBufferImpl **ppdsb, diff --git a/dlls/dsound/mixer.c b/dlls/dsound/mixer.c index 4f738311e7e..5fa15b27910 100644 --- a/dlls/dsound/mixer.c +++ b/dlls/dsound/mixer.c @@ -178,6 +178,8 @@ static void DSOUND_RecalcFreqAcc(IDirectSoundBufferImpl *dsb) */ void DSOUND_RecalcFormat(IDirectSoundBufferImpl *dsb) { + DWORD ichannels = dsb->pwfx->nChannels; + DWORD ochannels = dsb->device->pwfx->nChannels; BOOL needremix = TRUE, needresample = (dsb->freq != dsb->device->pwfx->nSamplesPerSec); DWORD bAlign = dsb->pwfx->nBlockAlign, pAlign = dsb->device->pwfx->nBlockAlign; WAVEFORMATEXTENSIBLE *pwfxe; @@ -200,8 +202,36 @@ void DSOUND_RecalcFormat(IDirectSoundBufferImpl *dsb) dsb->freqAcc = dsb->freqAccNext = 0; dsb->freqneeded = needresample; - dsb->get = ieee ? getbpp[4] : getbpp[dsb->pwfx->wBitsPerSample/8 - 1]; - dsb->put = putbpp[dsb->device->pwfx->wBitsPerSample/8 - 1]; + dsb->get_aux = ieee ? getbpp[4] : getbpp[dsb->pwfx->wBitsPerSample/8 - 1]; + dsb->put_aux = putbpp[dsb->device->pwfx->wBitsPerSample/8 - 1]; + + dsb->get = dsb->get_aux; + dsb->put = dsb->put_aux; + + if (ichannels == ochannels) + { + dsb->mix_channels = ichannels; + if (ichannels > 32) { + FIXME("Copying %u channels is unsupported, limiting to first 32\n", ichannels); + dsb->mix_channels = 32; + } + } + else if (ichannels == 1) + { + dsb->mix_channels = 1; + dsb->put = put_mono2stereo; + } + else if (ochannels == 1) + { + dsb->mix_channels = 1; + dsb->get = get_mono; + } + else + { + if (ichannels > 2) + FIXME("Conversion from %u to %u channels is not implemented, falling back to stereo\n", ichannels, ochannels); + dsb->mix_channels = 2; + } if (needremix) { @@ -278,38 +308,13 @@ static inline void cp_fields(const IDirectSoundBufferImpl *dsb, DWORD ipos = dsb->sec_mixpos; UINT istride = dsb->pwfx->nBlockAlign; UINT adj = dsb->freqAdjust; - DirectSoundDevice *device = dsb->device; - float value; ULONG adv; DWORD opos = 0; while (count-- > 0) { - if (device->pwfx->nChannels == dsb->pwfx->nChannels || - (device->pwfx->nChannels == 2 && dsb->pwfx->nChannels == 6) || - (device->pwfx->nChannels == 8 && dsb->pwfx->nChannels == 2) || - (device->pwfx->nChannels == 6 && dsb->pwfx->nChannels == 2)) { - value = dsb->get(dsb, ipos, 0); - dsb->put(dsb, opos, 0, value); - if (device->pwfx->nChannels == 2 || dsb->pwfx->nChannels == 2) { - value = dsb->get(dsb, ipos, 1); - dsb->put(dsb, opos, 1, value); - } - } - - if (device->pwfx->nChannels == 1 && dsb->pwfx->nChannels == 2) - { - float val = (dsb->get(dsb, ipos, 0) + dsb->get(dsb, ipos, 1)) / 2.; - - dsb->put(dsb, opos, 0, val); - } - - if (device->pwfx->nChannels == 2 && dsb->pwfx->nChannels == 1) - { - value = dsb->get(dsb, ipos, 0); - dsb->put(dsb, opos, 0, value); - dsb->put(dsb, opos, 1, value); - } - + DWORD channel; + for (channel = 0; channel < dsb->mix_channels; channel++) + dsb->put(dsb, opos, channel, dsb->get(dsb, ipos, channel)); freqAcc += adj; adv = (freqAcc >> DSOUND_FREQSHIFT); freqAcc &= (1 << DSOUND_FREQSHIFT) - 1; @@ -361,18 +366,6 @@ static void DSOUND_MixToTemporary(const IDirectSoundBufferImpl *dsb, DWORD tmp_l dsb->device->tmp_buffer = HeapAlloc(GetProcessHeap(), 0, tmp_len); } - /* Check for same sample rate */ - if (dsb->freq == dsb->device->pwfx->nSamplesPerSec) { - TRACE("(%p) Same sample rate %d = primary %d\n", dsb, - dsb->freq, dsb->device->pwfx->nSamplesPerSec); - - cp_fields(dsb, oAdvance, size, 0); - return; - } - - /* Mix in different sample rates */ - TRACE("(%p) Adjusting frequency: %d -> %d\n", dsb, dsb->freq, dsb->device->pwfx->nSamplesPerSec); - DSOUND_secpos_to_bufpos(dsb, dsb->sec_mixpos, dsb->sec_mixpos, &freqAcc); /* FIXME: Small problem here when we're overwriting buf_mixpos, it then STILL uses old freqAcc, not sure if it matters or not */