From: Anton Baskanov <baskanov@gmail.com> --- dlls/dsound/dsound_convert.c | 78 ++++++++++++++++++++++++++++++++++-- dlls/dsound/dsound_private.h | 4 +- dlls/dsound/mixer.c | 6 +-- 3 files changed, 79 insertions(+), 9 deletions(-) diff --git a/dlls/dsound/dsound_convert.c b/dlls/dsound/dsound_convert.c index ac52df6cc64..8bc3eb38203 100644 --- a/dlls/dsound/dsound_convert.c +++ b/dlls/dsound/dsound_convert.c @@ -99,18 +99,90 @@ static float getieee32(const IDirectSoundBufferImpl *dsb, BYTE *base, DWORD chan const bitsgetfunc getbpp[5] = {get8, get16, get24, get32, getieee32}; -float get_mono(const IDirectSoundBufferImpl *dsb, BYTE *base, DWORD channel) +static float get8_mono(const IDirectSoundBufferImpl *dsb, BYTE *base, 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, base, c); + for (c = 0; c < channels; c++) { + const BYTE *buf = base + c; + val += (buf[0] - 0x80) / (float)0x80; + } + val /= channels; + return val; +} + +static float get16_mono(const IDirectSoundBufferImpl *dsb, BYTE *base, 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++) { + const BYTE *buf = base + 2 * c; + const SHORT *sbuf = (const SHORT*)(buf); + SHORT sample = (SHORT)le16(*sbuf); + val += sample / (float)0x8000; + } + val /= channels; + return val; +} + +static float get24_mono(const IDirectSoundBufferImpl *dsb, BYTE *base, 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++) { + LONG sample; + const BYTE *buf = base + 3 * c; + + /* The next expression deliberately has an overflow for buf[2] >= 0x80, + this is how negative values are made. + */ + sample = (buf[0] << 8) | (buf[1] << 16) | (buf[2] << 24); + val += sample / (float)0x80000000U; + } val /= channels; return val; } +static float get32_mono(const IDirectSoundBufferImpl *dsb, BYTE *base, 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++) { + const BYTE *buf = base + 4 * c; + const LONG *sbuf = (const LONG*)(buf); + LONG sample = le32(*sbuf); + val += sample / (float)0x80000000U; + } + val /= channels; + return val; +} + +static float getieee32_mono(const IDirectSoundBufferImpl *dsb, BYTE *base, 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++) { + const BYTE *buf = base + 4 * c; + const float *sbuf = (const float*)(buf); + /* The value will be clipped later, when put into some non-float buffer */ + val += *sbuf; + } + val /= channels; + return val; +} + +const bitsgetfunc getbpp_mono[5] = {get8_mono, get16_mono, get24_mono, get32_mono, getieee32_mono}; + static inline unsigned char f_to_8(float value) { if(value <= -1.f) diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h index 875f111ac4f..8753410b18b 100644 --- a/dlls/dsound/dsound_private.h +++ b/dlls/dsound/dsound_private.h @@ -46,6 +46,7 @@ typedef struct DirectSoundDevice DirectSoundDevice; typedef float (*bitsgetfunc)(const IDirectSoundBufferImpl *dsb, BYTE *base, DWORD channel); typedef void (*bitsputfunc)(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value); extern const bitsgetfunc getbpp[5]; +extern const bitsgetfunc getbpp_mono[5]; void putieee32(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value); void mixieee32(float *src, float *dst, unsigned samples); typedef void (*normfunc)(const void *src, void *dst, unsigned samples); @@ -164,7 +165,7 @@ struct IDirectSoundBufferImpl BOOL ds3db_need_recalc; /* Used for bit depth conversion */ int mix_channels; - bitsgetfunc get, get_aux; + bitsgetfunc get; bitsputfunc put; int num_filters; DSFilter* filters; @@ -172,7 +173,6 @@ struct IDirectSoundBufferImpl struct list entry; }; -float get_mono(const IDirectSoundBufferImpl *dsb, BYTE *base, DWORD channel); void put_mono2stereo(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value); void put_mono2quad(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value); void put_stereo2quad(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value); diff --git a/dlls/dsound/mixer.c b/dlls/dsound/mixer.c index 9afb7651796..fd532408999 100644 --- a/dlls/dsound/mixer.c +++ b/dlls/dsound/mixer.c @@ -137,9 +137,7 @@ void DSOUND_RecalcFormat(IDirectSoundBufferImpl *dsb) dsb->freqAccNum = (dsb->freqAccNum * (LONG64)dsb->freqAdjustDen + oldFreqAdjustDen / 2) / oldFreqAdjustDen; - dsb->get_aux = ieee ? getbpp[4] : getbpp[dsb->pwfx->wBitsPerSample/8 - 1]; - - dsb->get = dsb->get_aux; + dsb->get = ieee ? getbpp[4] : getbpp[dsb->pwfx->wBitsPerSample/8 - 1]; dsb->put = putieee32; if (ichannels == ochannels) @@ -164,7 +162,7 @@ void DSOUND_RecalcFormat(IDirectSoundBufferImpl *dsb) else if (ochannels == 1) { dsb->mix_channels = 1; - dsb->get = get_mono; + dsb->get = ieee ? getbpp_mono[4] : getbpp_mono[dsb->pwfx->wBitsPerSample/8 - 1]; } else if (ichannels == 2 && ochannels == 4) { -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11082