From 82873486b7227c628fe4860e90700216bb909114 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 30 Aug 2020 04:28:01 -0700 Subject: Dynamically allocate the convolution channel mixing data --- alc/effects/convolution.cpp | 92 ++++++++++++++++++++++----------------------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/alc/effects/convolution.cpp b/alc/effects/convolution.cpp index 77efc11e..9924bc81 100644 --- a/alc/effects/convolution.cpp +++ b/alc/effects/convolution.cpp @@ -111,8 +111,20 @@ struct ConvolutionFilter final : public EffectBufferBase { AmbiScaling mAmbiScaling{}; ALuint mAmbiOrder{}; + struct ChannelData { + alignas(16) FloatBufferLine mBuffer{}; + float mHfScale{}; + BandSplitter mFilter{}; + float Current[MAX_OUTPUT_CHANNELS]{}; + float Target[MAX_OUTPUT_CHANNELS]{}; + }; + using ChannelDataArray = al::FlexArray; + std::unique_ptr mChans; std::unique_ptr mComplexData; + ConvolutionFilter(size_t numChannels) : mChans{ChannelDataArray::Create(numChannels)} + { } + DEF_NEWDEL(ConvolutionFilter) }; @@ -123,15 +135,6 @@ struct ConvolutionState final : public EffectState { alignas(16) std::array mOutput[MAX_FILTER_CHANNELS]{}; alignas(16) std::array mFftBuffer{}; - ALuint mNumChannels; - struct { - alignas(16) FloatBufferLine mBuffer{}; - float mHfScale{}; - BandSplitter mFilter{}; - float Current[MAX_OUTPUT_CHANNELS]{}; - float Target[MAX_OUTPUT_CHANNELS]{}; - } mChans[MAX_FILTER_CHANNELS]; - ConvolutionState() = default; ~ConvolutionState() override = default; @@ -151,38 +154,30 @@ struct ConvolutionState final : public EffectState { void ConvolutionState::NormalMix(const al::span samplesOut, const size_t samplesToDo) { - for(size_t c{0};c < mNumChannels;++c) - MixSamples({mChans[c].mBuffer.data(), samplesToDo}, samplesOut, mChans[c].Current, - mChans[c].Target, samplesToDo, 0); + auto &chans = *mFilter->mChans; + for(size_t c{0};c < chans.size();++c) + MixSamples({chans[c].mBuffer.data(), samplesToDo}, samplesOut, chans[c].Current, + chans[c].Target, samplesToDo, 0); } void ConvolutionState::UpsampleMix(const al::span samplesOut, const size_t samplesToDo) { - for(size_t c{0};c < mNumChannels;++c) + auto &chans = *mFilter->mChans; + for(size_t c{0};c < chans.size();++c) { - const al::span src{mChans[c].mBuffer.data(), samplesToDo}; - mChans[c].mFilter.processHfScale(src, mChans[c].mHfScale); - MixSamples(src, samplesOut, mChans[c].Current, mChans[c].Target, samplesToDo, 0); + const al::span src{chans[c].mBuffer.data(), samplesToDo}; + chans[c].mFilter.processHfScale(src, chans[c].mHfScale); + MixSamples(src, samplesOut, chans[c].Current, chans[c].Target, samplesToDo, 0); } } -void ConvolutionState::deviceUpdate(const ALCdevice *device) +void ConvolutionState::deviceUpdate(const ALCdevice* /*device*/) { mFifoPos = 0; for(auto &buffer : mOutput) buffer.fill(0.0f); mFftBuffer.fill(complex_d{}); - - const BandSplitter splitter{400.0f / static_cast(device->Frequency)}; - for(auto &e : mChans) - { - e.mBuffer.fill(0.0f); - e.mHfScale = 1.0f; - e.mFilter = splitter; - std::fill(std::begin(e.Current), std::end(e.Current), 0.0f); - std::fill(std::begin(e.Target), std::end(e.Target), 0.0f); - } } EffectBufferBase *ConvolutionState::createBuffer(const ALCdevice *device, @@ -211,12 +206,17 @@ EffectBufferBase *ConvolutionState::createBuffer(const ALCdevice *device, (uint64_t{buffer.mSampleLen}*device->Frequency + (buffer.mSampleRate-1)) / buffer.mSampleRate); - al::intrusive_ptr filter{new ConvolutionFilter{}}; - auto bytesPerSample = BytesFromFmt(buffer.mType); - auto numChannels = ChannelsFromFmt(buffer.mChannels, buffer.mAmbiOrder); + auto realChannels = ChannelsFromFmt(buffer.mChannels, buffer.mAmbiOrder); + auto numChannels = ChannelsFromFmt(buffer.mChannels, + minu(buffer.mAmbiOrder, device->mAmbiOrder)); constexpr size_t m{ConvolveUpdateSize/2 + 1}; + const BandSplitter splitter{400.0f / static_cast(device->Frequency)}; + al::intrusive_ptr filter{new ConvolutionFilter{numChannels}}; + for(auto &e : *filter->mChans) + e.mFilter = splitter; + /* Calculate the number of segments needed to hold the impulse response and * the input history (rounded up), and allocate them. */ @@ -242,7 +242,7 @@ EffectBufferBase *ConvolutionState::createBuffer(const ALCdevice *device, for(size_t c{0};c < numChannels;++c) { /* Load the samples from the buffer, and resample to match the device. */ - LoadSamples(srcsamples.get(), buffer.mData.data() + bytesPerSample*c, numChannels, + LoadSamples(srcsamples.get(), buffer.mData.data() + bytesPerSample*c, realChannels, buffer.mType, buffer.mSampleLen); if(device->Frequency != buffer.mSampleRate) resampler.process(buffer.mSampleLen, srcsamples.get(), resampledCount, @@ -273,8 +273,6 @@ void ConvolutionState::update(const ALCcontext *context, const ALeffectslot *slo if(!mFilter) return; ALCdevice *device{context->mDevice.get()}; - const ALuint min_order{minu(mFilter->mAmbiOrder, device->mAmbiOrder)}; - mNumChannels = mFilter ? ChannelsFromFmt(mFilter->mChannels, min_order) : 0u; mMix = &ConvolutionState::NormalMix; /* The iFFT'd response is scaled up by the number of bins, so apply the @@ -282,6 +280,7 @@ void ConvolutionState::update(const ALCcontext *context, const ALeffectslot *slo */ constexpr size_t m{ConvolveUpdateSize/2 + 1}; const float gain{slot->Params.Gain * (1.0f/m)}; + auto &chans = *mFilter->mChans; if(mFilter->mChannels == FmtBFormat3D || mFilter->mChannels == FmtBFormat2D) { if(device->mAmbiOrder > mFilter->mAmbiOrder) @@ -289,9 +288,9 @@ void ConvolutionState::update(const ALCcontext *context, const ALeffectslot *slo mMix = &ConvolutionState::UpsampleMix; const auto scales = BFormatDec::GetHFOrderScales(mFilter->mAmbiOrder, device->mAmbiOrder); - mChans[0].mHfScale = scales[0]; - for(size_t i{1};i < mNumChannels;++i) - mChans[i].mHfScale = scales[1]; + chans[0].mHfScale = scales[0]; + for(size_t i{1};i < chans.size();++i) + chans[i].mHfScale = scales[1]; } mOutTarget = target.Main->Buffer; @@ -301,11 +300,11 @@ void ConvolutionState::update(const ALCcontext *context, const ALeffectslot *slo GetAmbiLayout(mFilter->mAmbiLayout).data()}; std::array coeffs{}; - for(size_t c{0u};c < mNumChannels;++c) + for(size_t c{0u};c < chans.size();++c) { const size_t acn{index_map[c]}; coeffs[acn] = scales[acn]; - ComputePanGains(target.Main, coeffs.data(), gain, mChans[c].Target); + ComputePanGains(target.Main, coeffs.data(), gain, chans[c].Target); coeffs[acn] = 0.0f; } } @@ -319,8 +318,8 @@ void ConvolutionState::update(const ALCcontext *context, const ALeffectslot *slo if(lidx != INVALID_CHANNEL_INDEX && ridx != INVALID_CHANNEL_INDEX) { mOutTarget = target.RealOut->Buffer; - mChans[0].Target[lidx] = gain; - mChans[1].Target[ridx] = gain; + chans[0].Target[lidx] = gain; + chans[1].Target[ridx] = gain; } else { @@ -328,8 +327,8 @@ void ConvolutionState::update(const ALCcontext *context, const ALeffectslot *slo const auto rcoeffs = CalcDirectionCoeffs({ 1.0f, 0.0f, 0.0f}, 0.0f); mOutTarget = target.Main->Buffer; - ComputePanGains(target.Main, lcoeffs.data(), gain, mChans[0].Target); - ComputePanGains(target.Main, rcoeffs.data(), gain, mChans[1].Target); + ComputePanGains(target.Main, lcoeffs.data(), gain, chans[0].Target); + ComputePanGains(target.Main, rcoeffs.data(), gain, chans[1].Target); } } else if(mFilter->mChannels == FmtMono) @@ -337,7 +336,7 @@ void ConvolutionState::update(const ALCcontext *context, const ALeffectslot *slo const auto coeffs = CalcDirectionCoeffs({0.0f, 0.0f, -1.0f}, 0.0f); mOutTarget = target.Main->Buffer; - ComputePanGains(target.Main, coeffs.data(), gain, mChans[0].Target); + ComputePanGains(target.Main, coeffs.data(), gain, chans[0].Target); } } @@ -349,6 +348,7 @@ void ConvolutionState::process(const size_t samplesToDo, constexpr size_t m{ConvolveUpdateSize/2 + 1}; size_t curseg{mFilter->mCurrentSegment}; + auto &chans = *mFilter->mChans; for(size_t base{0u};base < samplesToDo;) { @@ -357,10 +357,10 @@ void ConvolutionState::process(const size_t samplesToDo, /* Retrieve the output samples from the FIFO and fill in the new input * samples. */ - for(size_t c{0};c < mNumChannels;++c) + for(size_t c{0};c < chans.size();++c) { auto fifo_iter = mOutput[c].begin() + mFifoPos; - std::transform(fifo_iter, fifo_iter+todo, mChans[c].mBuffer.begin()+base, + std::transform(fifo_iter, fifo_iter+todo, chans[c].mBuffer.begin()+base, [](double d) noexcept -> float { return static_cast(d); }); } @@ -380,7 +380,7 @@ void ConvolutionState::process(const size_t samplesToDo, std::copy_n(mFftBuffer.begin(), m, &mFilter->mInputHistory[curseg*m]); mFftBuffer.fill(complex_d{}); - for(size_t c{0};c < mNumChannels;++c) + for(size_t c{0};c < chans.size();++c) { /* Convolve each input segment with its IR filter counterpart * (aligned in time). -- cgit v1.2.3