From d912b92a6042464546d0588313741b46d63ec297 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 22 Sep 2020 07:46:21 -0700 Subject: Support all buffer layouts for convolution --- alc/effects/convolution.cpp | 121 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 99 insertions(+), 22 deletions(-) diff --git a/alc/effects/convolution.cpp b/alc/effects/convolution.cpp index 8f1f2c5d..ffd2f0c7 100644 --- a/alc/effects/convolution.cpp +++ b/alc/effects/convolution.cpp @@ -94,6 +94,12 @@ auto GetAmbi2DLayout(AmbiLayout layouttype) noexcept -> const std::array; constexpr size_t ConvolveUpdateSize{1024}; @@ -220,11 +226,6 @@ void ConvolutionState::setBuffer(const ALCdevice *device, const BufferStorage *b /* An empty buffer doesn't need a convolution filter. */ if(!buffer || buffer->mSampleLen < 1) return; - /* FIXME: Support anything. */ - if(buffer->mChannels != FmtMono && buffer->mChannels != FmtStereo - && buffer->mChannels != FmtBFormat2D && buffer->mChannels != FmtBFormat3D) - return; - constexpr size_t m{ConvolveUpdateSize/2 + 1}; auto bytesPerSample = BytesFromFmt(buffer->mType); auto realChannels = ChannelsFromFmt(buffer->mChannels, buffer->mAmbiOrder); @@ -306,13 +307,61 @@ void ConvolutionState::setBuffer(const ALCdevice *device, const BufferStorage *b void ConvolutionState::update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps* /*props*/, const EffectTarget target) { + /* NOTE: Stereo and Rear are slightly different from normal mixing (as + * defined in alu.cpp). These are 45 degrees from center, rather than the + * 30 degrees used there. + * + * TODO: LFE is not mixed to output. This will require each buffer channel + * to have its own output target since the main mixing buffer won't have an + * LFE channel (due to being B-Format). + */ + static const ChanMap MonoMap[1]{ + { FrontCenter, 0.0f, 0.0f } + }, StereoMap[2]{ + { FrontLeft, Deg2Rad(-45.0f), Deg2Rad(0.0f) }, + { FrontRight, Deg2Rad( 45.0f), Deg2Rad(0.0f) } + }, RearMap[2]{ + { BackLeft, Deg2Rad(-135.0f), Deg2Rad(0.0f) }, + { BackRight, Deg2Rad( 135.0f), Deg2Rad(0.0f) } + }, QuadMap[4]{ + { FrontLeft, Deg2Rad( -45.0f), Deg2Rad(0.0f) }, + { FrontRight, Deg2Rad( 45.0f), Deg2Rad(0.0f) }, + { BackLeft, Deg2Rad(-135.0f), Deg2Rad(0.0f) }, + { BackRight, Deg2Rad( 135.0f), Deg2Rad(0.0f) } + }, X51Map[6]{ + { FrontLeft, Deg2Rad( -30.0f), Deg2Rad(0.0f) }, + { FrontRight, Deg2Rad( 30.0f), Deg2Rad(0.0f) }, + { FrontCenter, Deg2Rad( 0.0f), Deg2Rad(0.0f) }, + { LFE, 0.0f, 0.0f }, + { SideLeft, Deg2Rad(-110.0f), Deg2Rad(0.0f) }, + { SideRight, Deg2Rad( 110.0f), Deg2Rad(0.0f) } + }, X61Map[7]{ + { FrontLeft, Deg2Rad(-30.0f), Deg2Rad(0.0f) }, + { FrontRight, Deg2Rad( 30.0f), Deg2Rad(0.0f) }, + { FrontCenter, Deg2Rad( 0.0f), Deg2Rad(0.0f) }, + { LFE, 0.0f, 0.0f }, + { BackCenter, Deg2Rad(180.0f), Deg2Rad(0.0f) }, + { SideLeft, Deg2Rad(-90.0f), Deg2Rad(0.0f) }, + { SideRight, Deg2Rad( 90.0f), Deg2Rad(0.0f) } + }, X71Map[8]{ + { FrontLeft, Deg2Rad( -30.0f), Deg2Rad(0.0f) }, + { FrontRight, Deg2Rad( 30.0f), Deg2Rad(0.0f) }, + { FrontCenter, Deg2Rad( 0.0f), Deg2Rad(0.0f) }, + { LFE, 0.0f, 0.0f }, + { BackLeft, Deg2Rad(-150.0f), Deg2Rad(0.0f) }, + { BackRight, Deg2Rad( 150.0f), Deg2Rad(0.0f) }, + { SideLeft, Deg2Rad( -90.0f), Deg2Rad(0.0f) }, + { SideRight, Deg2Rad( 90.0f), Deg2Rad(0.0f) } + }; + if(mNumConvolveSegs < 1) return; mMix = &ConvolutionState::NormalMix; + for(auto &chan : *mChans) + std::fill(std::begin(chan.Target), std::end(chan.Target), 0.0f); const float gain{slot->Params.Gain}; - auto &chans = *mChans; if(mChannels == FmtBFormat3D || mChannels == FmtBFormat2D) { ALCdevice *device{context->mDevice.get()}; @@ -320,9 +369,9 @@ void ConvolutionState::update(const ALCcontext *context, const ALeffectslot *slo { mMix = &ConvolutionState::UpsampleMix; const auto scales = BFormatDec::GetHFOrderScales(mAmbiOrder, device->mAmbiOrder); - chans[0].mHfScale = scales[0]; - for(size_t i{1};i < chans.size();++i) - chans[i].mHfScale = scales[1]; + (*mChans)[0].mHfScale = scales[0]; + for(size_t i{1};i < mChans->size();++i) + (*mChans)[i].mHfScale = scales[1]; } mOutTarget = target.Main->Buffer; @@ -332,29 +381,57 @@ void ConvolutionState::update(const ALCcontext *context, const ALeffectslot *slo GetAmbiLayout(mAmbiLayout).data()}; std::array coeffs{}; - for(size_t c{0u};c < chans.size();++c) + for(size_t c{0u};c < mChans->size();++c) { const size_t acn{index_map[c]}; coeffs[acn] = scales[acn]; - ComputePanGains(target.Main, coeffs.data(), gain, chans[c].Target); + ComputePanGains(target.Main, coeffs.data(), gain, (*mChans)[c].Target); coeffs[acn] = 0.0f; } } - else if(mChannels == FmtStereo) + else { - const auto lcoeffs = CalcDirectionCoeffs({-1.0f, 0.0f, 0.0f}, 0.0f); - const auto rcoeffs = CalcDirectionCoeffs({ 1.0f, 0.0f, 0.0f}, 0.0f); + ALCdevice *device{context->mDevice.get()}; + al::span chanmap{}; + switch(mChannels) + { + case FmtMono: chanmap = MonoMap; break; + case FmtStereo: chanmap = StereoMap; break; + case FmtRear: chanmap = RearMap; break; + case FmtQuad: chanmap = QuadMap; break; + case FmtX51: chanmap = X51Map; break; + case FmtX61: chanmap = X61Map; break; + case FmtX71: chanmap = X71Map; break; + case FmtBFormat2D: + case FmtBFormat3D: + break; + } mOutTarget = target.Main->Buffer; - ComputePanGains(target.Main, lcoeffs.data(), gain, chans[0].Target); - ComputePanGains(target.Main, rcoeffs.data(), gain, chans[1].Target); - } - else if(mChannels == FmtMono) - { - const auto coeffs = CalcDirectionCoeffs({0.0f, 0.0f, -1.0f}, 0.0f); + if(device->mRenderMode == RenderMode::Pairwise) + { + auto ScaleAzimuthFront = [](float azimuth, float scale) -> float + { + const float abs_azi{std::fabs(azimuth)}; + if(!(abs_azi >= al::MathDefs::Pi()*0.5f)) + return std::copysign(minf(abs_azi*scale, al::MathDefs::Pi()*0.5f), azimuth); + return azimuth; + }; - mOutTarget = target.Main->Buffer; - ComputePanGains(target.Main, coeffs.data(), gain, chans[0].Target); + for(size_t i{0};i < chanmap.size();++i) + { + if(chanmap[i].channel == LFE) continue; + const auto coeffs = CalcAngleCoeffs(ScaleAzimuthFront(chanmap[i].angle, 2.0f), + chanmap[i].elevation, 0.0f); + ComputePanGains(target.Main, coeffs.data(), gain, (*mChans)[i].Target); + } + } + else for(size_t i{0};i < chanmap.size();++i) + { + if(chanmap[i].channel == LFE) continue; + const auto coeffs = CalcAngleCoeffs(chanmap[i].angle, chanmap[i].elevation, 0.0f); + ComputePanGains(target.Main, coeffs.data(), gain, (*mChans)[i].Target); + } } } -- cgit v1.2.3