From: Anton Baskanov <baskanov@gmail.com> Inspired by a patch by Matteo Bruni, which was in turn inspired by a patch by Giovanni Mascellani. --- dlls/dsound/dsound_convert.c | 56 ++++++++++++++++++--------- dlls/dsound/dsound_private.h | 4 +- dlls/dsound/mixer.c | 74 ++++++++++++++++++++++++++---------- 3 files changed, 95 insertions(+), 39 deletions(-) diff --git a/dlls/dsound/dsound_convert.c b/dlls/dsound/dsound_convert.c index d6c86f1959d..3160a4ddefa 100644 --- a/dlls/dsound/dsound_convert.c +++ b/dlls/dsound/dsound_convert.c @@ -47,46 +47,68 @@ WINE_DEFAULT_DEBUG_CHANNEL(dsound); -static float get8(const IDirectSoundBufferImpl *dsb, BYTE *base, DWORD channel) +static void get8(const IDirectSoundBufferImpl *dsb, BYTE *base, float *dst, unsigned samples, DWORD channel) { + DWORD channels = dsb->pwfx->nChannels; const BYTE *buf = base + channel; - return (buf[0] - 0x80) / (float)0x80; + int i; + + for (i = 0; i < samples; ++i) + dst[i] = (buf[i * channels] - 0x80) / (float)0x80; } -static float get16(const IDirectSoundBufferImpl *dsb, BYTE *base, DWORD channel) +static void get16(const IDirectSoundBufferImpl *dsb, BYTE *base, float *dst, unsigned samples, DWORD channel) { + DWORD channels = dsb->pwfx->nChannels; const BYTE *buf = base + 2 * channel; const SHORT *sbuf = (const SHORT*)(buf); - return sbuf[0] / (float)0x8000; + int i; + + for (i = 0; i < samples; ++i) + dst[i] = sbuf[i * channels] / (float)0x8000; } -static float get24(const IDirectSoundBufferImpl *dsb, BYTE *base, DWORD channel) +static void get24(const IDirectSoundBufferImpl *dsb, BYTE *base, float *dst, unsigned samples, DWORD channel) { - LONG sample; + DWORD channels = dsb->pwfx->nChannels; const BYTE *buf = base + 3 * channel; - - /* 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); - return sample / (float)0x80000000U; + int i; + + for (i = 0; i < samples; ++i) { + /* The next expression deliberately has an overflow for buf[2] >= 0x80, + this is how negative values are made. + */ + LONG sample = + (buf[i * channels * 3 + 0] << 8) | + (buf[i * channels * 3 + 1] << 16) | + (buf[i * channels * 3 + 2] << 24); + dst[i] = sample / (float)0x80000000U; + } } -static float get32(const IDirectSoundBufferImpl *dsb, BYTE *base, DWORD channel) +static void get32(const IDirectSoundBufferImpl *dsb, BYTE *base, float *dst, unsigned samples, DWORD channel) { + DWORD channels = dsb->pwfx->nChannels; const BYTE *buf = base + 4 * channel; const LONG *sbuf = (const LONG*)(buf); - return sbuf[0] / (float)0x80000000U; + int i; + + for (i = 0; i < samples; ++i) + dst[i] = sbuf[i * channels] / (float)0x80000000U; } const bitsgetfunc getbpp[4] = {get8, get16, get24, get32}; -float getieee32(const IDirectSoundBufferImpl *dsb, BYTE *base, DWORD channel) +void getieee32(const IDirectSoundBufferImpl *dsb, BYTE *base, float *dst, unsigned samples, DWORD channel) { + DWORD channels = dsb->pwfx->nChannels; const BYTE *buf = base + 4 * channel; const float *sbuf = (const float*)(buf); - /* The value will be clipped later, when put into some non-float buffer */ - return *sbuf; + int i; + + for (i = 0; i < samples; ++i) + /* The value will be clipped later, when put into some non-float buffer */ + dst[i] = sbuf[i * channels]; } void putieee32(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value) diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h index c569aa64eb5..fc6fbfd1cc5 100644 --- a/dlls/dsound/dsound_private.h +++ b/dlls/dsound/dsound_private.h @@ -43,10 +43,10 @@ typedef struct IDirectSoundBufferImpl IDirectSoundBufferImpl; typedef struct DirectSoundDevice DirectSoundDevice; /* dsound_convert.h */ -typedef float (*bitsgetfunc)(const IDirectSoundBufferImpl *dsb, BYTE *base, DWORD channel); +typedef void (*bitsgetfunc)(const IDirectSoundBufferImpl *dsb, BYTE *base, float *dst, unsigned samples, DWORD channel); typedef void (*bitsputfunc)(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value); extern const bitsgetfunc getbpp[4]; -float getieee32(const IDirectSoundBufferImpl *dsb, BYTE *base, DWORD channel); +void getieee32(const IDirectSoundBufferImpl *dsb, BYTE *base, float *dst, unsigned samples, DWORD channel); void putieee32(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value); void putieee32_sum(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value); void mixieee32(float *src, float *dst, unsigned samples); diff --git a/dlls/dsound/mixer.c b/dlls/dsound/mixer.c index 7234394e8df..fca7f09d6b6 100644 --- a/dlls/dsound/mixer.c +++ b/dlls/dsound/mixer.c @@ -279,12 +279,28 @@ void DSOUND_CheckEvent(const IDirectSoundBufferImpl *dsb, DWORD playpos, int len } } -static inline float get_current_sample(const IDirectSoundBufferImpl *dsb, - BYTE *buffer, DWORD buflen, DWORD mixpos, DWORD channel) +static inline void get_samples(const IDirectSoundBufferImpl *dsb, BYTE *buffer, DWORD buflen, + DWORD mixpos, DWORD channel, DWORD count, float *dst) { - if (mixpos >= buflen && !(dsb->playflags & DSBPLAY_LOOPING)) - return 0.0f; - return dsb->get(dsb, buffer + (mixpos % buflen), channel); + UINT istride = dsb->pwfx->nBlockAlign; + DWORD advance; + DWORD pos; + + if (!(dsb->playflags & DSBPLAY_LOOPING)) { + advance = buflen < mixpos ? 0 : min((buflen - mixpos) / istride, count); + dsb->get(dsb, buffer + mixpos, dst, advance, channel); + memset(dst + advance, 0, (count - advance) * sizeof(float)); + return; + } + + advance = min((buflen - mixpos % buflen) / istride, count); + dsb->get(dsb, buffer + mixpos % buflen, dst, advance, channel); + pos = advance; + while (pos < count) { + advance = min(buflen / istride, count - pos); + dsb->get(dsb, buffer, dst + pos, advance, channel); + pos += advance; + } } #ifdef __SSE__ @@ -536,7 +552,7 @@ static UINT cp_fields_resample(IDirectSoundBufferImpl *dsb, UINT count, DWORD *f UINT required_input = max( (freqAcc_start + (count - 1) * dsb->freqAdjustNum) / dsb->freqAdjustDen + FIR_WIDTH, (freqAcc_start + (count - 1 + FIR_WIDTH) * dsb->freqAdjustNum) / dsb->freqAdjustDen); - float *intermediate, *output, *itmp; + float *intermediate, *output; DWORD len = required_input * channels; /* Allocate an output buffer for each channel with padding on both ends as @@ -570,14 +586,14 @@ static UINT cp_fields_resample(IDirectSoundBufferImpl *dsb, UINT count, DWORD *f * if you want -msse3 to have any effect. * This is good for CPU cache effects, too. */ - itmp = intermediate; for (channel = 0; channel < channels; channel++) { - for (i = 0; i < committed_samples; i++) - *(itmp++) = get_current_sample(dsb, dsb->committedbuff, - dsb->writelead, dsb->committed_mixpos + i * istride, channel); - for (; i < required_input; i++) - *(itmp++) = get_current_sample(dsb, dsb->buffer->memory, - dsb->buflen, dsb->sec_mixpos + i * istride, channel); + get_samples(dsb, dsb->committedbuff, dsb->writelead, dsb->committed_mixpos, channel, + committed_samples, intermediate + channel * required_input); + if (required_input > committed_samples) + get_samples(dsb, dsb->buffer->memory, dsb->buflen, + dsb->sec_mixpos + committed_samples * istride, channel, + required_input - committed_samples, + intermediate + channel * required_input + committed_samples); } for (channel = 0; channel < channels; channel++) @@ -597,25 +613,43 @@ static UINT cp_fields_noresample(IDirectSoundBufferImpl *dsb, UINT count) UINT istride = dsb->pwfx->nBlockAlign; UINT ostride = dsb->device->pwfx->nChannels * sizeof(float); UINT committed_samples = 0; + float *intermediate; DWORD channel, i; + DWORD len = count * dsb->mix_channels; + len *= sizeof(float); + if (!secondarybuffer_is_audible(dsb)) return count; + if (!dsb->device->cp_buffer) { + dsb->device->cp_buffer = malloc(len); + dsb->device->cp_buffer_len = len; + } else if (len > dsb->device->cp_buffer_len) { + dsb->device->cp_buffer = realloc(dsb->device->cp_buffer, len); + dsb->device->cp_buffer_len = len; + } + + intermediate = dsb->device->cp_buffer; + if(dsb->use_committed) { committed_samples = (dsb->writelead - dsb->committed_mixpos) / istride; committed_samples = committed_samples <= count ? committed_samples : count; } - for (i = 0; i < committed_samples; i++) - for (channel = 0; channel < dsb->mix_channels; channel++) - dsb->put(dsb, i * ostride, channel, get_current_sample(dsb, dsb->committedbuff, - dsb->writelead, dsb->committed_mixpos + i * istride, channel)); + for (channel = 0; channel < dsb->mix_channels; channel++) + { + get_samples(dsb, dsb->committedbuff, dsb->writelead, dsb->committed_mixpos, channel, + committed_samples, intermediate + channel * count); + if (count > committed_samples) + get_samples(dsb, dsb->buffer->memory, dsb->buflen, + dsb->sec_mixpos + committed_samples * istride, channel, + count - committed_samples, intermediate + channel * count + committed_samples); + } - for (; i < count; i++) + for (i = 0; i < count; i++) for (channel = 0; channel < dsb->mix_channels; channel++) - dsb->put(dsb, i * ostride, channel, get_current_sample(dsb, dsb->buffer->memory, - dsb->buflen, dsb->sec_mixpos + i * istride, channel)); + dsb->put(dsb, i * ostride, channel, intermediate[channel * count + i]); return count; } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11082