diff options
-rw-r--r-- | alc/alc.cpp | 5 | ||||
-rw-r--r-- | alc/panning.cpp | 4 | ||||
-rw-r--r-- | core/bformatdec.cpp | 80 | ||||
-rw-r--r-- | core/filters/splitter.cpp | 7 | ||||
-rw-r--r-- | core/filters/splitter.h | 7 | ||||
-rw-r--r-- | core/front_stablizer.h | 17 |
6 files changed, 43 insertions, 77 deletions
diff --git a/alc/alc.cpp b/alc/alc.cpp index db862a36..0b113884 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -2152,11 +2152,6 @@ ALCenum UpdateDeviceParams(ALCdevice *device, const int *attrList) nanoseconds::rep sample_delay{0}; if(auto *encoder{device->mUhjEncoder.get()}) sample_delay += encoder->getDelay(); - if(auto *ambidec = device->AmbiDecoder.get()) - { - if(ambidec->hasStablizer()) - sample_delay += FrontStablizer::DelayLength; - } if(device->getConfigValueBool(nullptr, "dither", true)) { diff --git a/alc/panning.cpp b/alc/panning.cpp index 1210b318..80418b39 100644 --- a/alc/panning.cpp +++ b/alc/panning.cpp @@ -116,13 +116,13 @@ inline const char *GetLabelFromChannel(Channel channel) std::unique_ptr<FrontStablizer> CreateStablizer(const size_t outchans, const uint srate) { auto stablizer = FrontStablizer::Create(outchans); - for(auto &buf : stablizer->DelayBuf) - std::fill(buf.begin(), buf.end(), 0.0f); /* Initialize band-splitting filter for the mid signal, with a crossover at * 5khz (could be higher). */ stablizer->MidFilter.init(5000.0f / static_cast<float>(srate)); + for(auto &filter : stablizer->ChannelFilters) + filter = stablizer->MidFilter; return stablizer; } diff --git a/core/bformatdec.cpp b/core/bformatdec.cpp index b93c2f44..129b9976 100644 --- a/core/bformatdec.cpp +++ b/core/bformatdec.cpp @@ -88,15 +88,14 @@ void BFormatDec::processStablize(const al::span<FloatBufferLine> OutBuffer, ASSUME(SamplesToDo > 0); /* Move the existing direct L/R signal out so it doesn't get processed by - * the stablizer. Add a delay to it so it stays aligned with the stablizer - * delay. + * the stablizer. */ float *RESTRICT mid{al::assume_aligned<16>(mStablizer->MidDirect.data())}; float *RESTRICT side{al::assume_aligned<16>(mStablizer->Side.data())}; for(size_t i{0};i < SamplesToDo;++i) { - mid[FrontStablizer::DelayLength+i] = OutBuffer[lidx][i] + OutBuffer[ridx][i]; - side[FrontStablizer::DelayLength+i] = OutBuffer[lidx][i] - OutBuffer[ridx][i]; + mid[i] = OutBuffer[lidx][i] + OutBuffer[ridx][i]; + side[i] = OutBuffer[lidx][i] - OutBuffer[ridx][i]; } std::fill_n(OutBuffer[lidx].begin(), SamplesToDo, 0.0f); std::fill_n(OutBuffer[ridx].begin(), SamplesToDo, 0.0f); @@ -104,55 +103,36 @@ void BFormatDec::processStablize(const al::span<FloatBufferLine> OutBuffer, /* Decode the B-Format input to OutBuffer. */ process(OutBuffer, InSamples, SamplesToDo); - /* Apply a delay to all channels, except the front-left and front-right, so - * they maintain correct timing. + /* Include the decoded side signal with the direct side signal. */ + for(size_t i{0};i < SamplesToDo;++i) + side[i] += OutBuffer[lidx][i] - OutBuffer[ridx][i]; + + /* Get the decoded mid signal and band-split it. */ + std::transform(OutBuffer[lidx].cbegin(), OutBuffer[lidx].cbegin()+SamplesToDo, + OutBuffer[ridx].cbegin(), mStablizer->Temp.begin(), + [](const float l, const float r) noexcept { return l + r; }); + + mStablizer->MidFilter.process({mStablizer->Temp.data(), SamplesToDo}, mStablizer->MidHF.data(), + mStablizer->MidLF.data()); + + /* Apply an all-pass to all channels to match the band-splitter's phase + * shift. This is to keep the phase synchronized between the existing + * signal and the split mid signal. */ const size_t NumChannels{OutBuffer.size()}; for(size_t i{0u};i < NumChannels;i++) { - if(i == lidx || i == ridx) - continue; - - auto &DelayBuf = mStablizer->DelayBuf[i]; - auto buffer_end = OutBuffer[i].begin() + SamplesToDo; - if(SamplesToDo >= FrontStablizer::DelayLength) [[likely]] - { - auto delay_end = std::rotate(OutBuffer[i].begin(), - buffer_end - FrontStablizer::DelayLength, buffer_end); - std::swap_ranges(OutBuffer[i].begin(), delay_end, DelayBuf.begin()); - } + /* Skip the left and right channels, which are going to get overwritten, + * and substitute the direct mid signal and direct+decoded side signal. + */ + if(i == lidx) + mStablizer->ChannelFilters[i].processAllPass({mid, SamplesToDo}); + else if(i == ridx) + mStablizer->ChannelFilters[i].processAllPass({side, SamplesToDo}); else - { - auto delay_start = std::swap_ranges(OutBuffer[i].begin(), buffer_end, - DelayBuf.begin()); - std::rotate(DelayBuf.begin(), delay_start, DelayBuf.end()); - } + mStablizer->ChannelFilters[i].processAllPass({OutBuffer[i].data(), SamplesToDo}); } - /* Include the side signal for what was just decoded. */ - for(size_t i{0};i < SamplesToDo;++i) - side[FrontStablizer::DelayLength+i] += OutBuffer[lidx][i] - OutBuffer[ridx][i]; - - /* Combine the delayed mid signal with the decoded mid signal. */ - float *tmpbuf{mStablizer->TempBuf.data()}; - auto tmpiter = std::copy(mStablizer->MidDelay.cbegin(), mStablizer->MidDelay.cend(), tmpbuf); - for(size_t i{0};i < SamplesToDo;++i,++tmpiter) - *tmpiter = OutBuffer[lidx][i] + OutBuffer[ridx][i]; - /* Save the newest samples for next time. */ - std::copy_n(tmpbuf+SamplesToDo, mStablizer->MidDelay.size(), mStablizer->MidDelay.begin()); - - /* Apply an all-pass on the signal in reverse. The future samples are - * included with the all-pass to reduce the error in the output samples - * (the smaller the delay, the more error is introduced). - */ - mStablizer->MidFilter.applyAllpassRev({tmpbuf, SamplesToDo+FrontStablizer::DelayLength}); - - /* Now apply the band-splitter, combining its phase shift with the reversed - * phase shift, restoring the original phase on the split signal. - */ - mStablizer->MidFilter.process({tmpbuf, SamplesToDo}, mStablizer->MidHF.data(), - mStablizer->MidLF.data()); - /* This pans the separate low- and high-frequency signals between being on * the center channel and the left+right channels. The low-frequency signal * is panned 1/3rd toward center and the high-frequency signal is panned @@ -164,6 +144,9 @@ void BFormatDec::processStablize(const al::span<FloatBufferLine> OutBuffer, const float sin_hf{std::sin(1.0f/4.0f * (al::numbers::pi_v<float>*0.5f))}; for(size_t i{0};i < SamplesToDo;i++) { + /* Add the direct mid signal to the processed mid signal so it can be + * properly combined with the direct+decoded side signal. + */ const float m{mStablizer->MidLF[i]*cos_lf + mStablizer->MidHF[i]*cos_hf + mid[i]}; const float c{mStablizer->MidLF[i]*sin_lf + mStablizer->MidHF[i]*sin_hf}; const float s{side[i]}; @@ -175,11 +158,6 @@ void BFormatDec::processStablize(const al::span<FloatBufferLine> OutBuffer, OutBuffer[ridx][i] = (m - s) * 0.5f; OutBuffer[cidx][i] += c * 0.5f; } - /* Move the delayed mid/side samples to the front for next time. */ - auto mid_end = mStablizer->MidDirect.cbegin() + SamplesToDo; - std::copy(mid_end, mid_end+FrontStablizer::DelayLength, mStablizer->MidDirect.begin()); - auto side_end = mStablizer->Side.cbegin() + SamplesToDo; - std::copy(side_end, side_end+FrontStablizer::DelayLength, mStablizer->Side.begin()); } diff --git a/core/filters/splitter.cpp b/core/filters/splitter.cpp index e7f03756..983ba36f 100644 --- a/core/filters/splitter.cpp +++ b/core/filters/splitter.cpp @@ -160,17 +160,18 @@ void BandSplitterR<Real>::processScale(const al::span<Real> samples, const Real } template<typename Real> -void BandSplitterR<Real>::applyAllpassRev(const al::span<Real> samples) const +void BandSplitterR<Real>::processAllPass(const al::span<Real> samples) { const Real coeff{mCoeff}; - Real z1{0.0f}; + Real z1{mApZ1}; auto proc_sample = [coeff,&z1](const Real in) noexcept -> Real { const Real out{in*coeff + z1}; z1 = in - out*coeff; return out; }; - std::transform(samples.rbegin(), samples.rend(), samples.rbegin(), proc_sample); + std::transform(samples.cbegin(), samples.cend(), samples.begin(), proc_sample); + mApZ1 = z1; } diff --git a/core/filters/splitter.h b/core/filters/splitter.h index fa15bd50..e853eb38 100644 --- a/core/filters/splitter.h +++ b/core/filters/splitter.h @@ -31,12 +31,9 @@ public: /** * The all-pass portion of the band splitter. Applies the same phase shift - * without splitting the signal, in reverse. It starts from the back of the - * span and works toward the front, creating a phase shift of -n degrees - * instead of +n. Note that each use of this method is indepedent, it does - * not track history between calls. + * without splitting or scaling the signal. */ - void applyAllpassRev(const al::span<Real> samples) const; + void processAllPass(const al::span<Real> samples); }; using BandSplitter = BandSplitterR<float>; diff --git a/core/front_stablizer.h b/core/front_stablizer.h index 3d328a8d..6825111a 100644 --- a/core/front_stablizer.h +++ b/core/front_stablizer.h @@ -10,27 +10,22 @@ struct FrontStablizer { - static constexpr size_t DelayLength{256u}; + FrontStablizer(size_t numchans) : ChannelFilters{numchans} { } - FrontStablizer(size_t numchans) : DelayBuf{numchans} { } - - alignas(16) std::array<float,BufferLineSize + DelayLength> Side{}; - alignas(16) std::array<float,BufferLineSize + DelayLength> MidDirect{}; - alignas(16) std::array<float,DelayLength> MidDelay{}; - - alignas(16) std::array<float,BufferLineSize + DelayLength> TempBuf{}; + alignas(16) std::array<float,BufferLineSize> MidDirect{}; + alignas(16) std::array<float,BufferLineSize> Side{}; + alignas(16) std::array<float,BufferLineSize> Temp{}; BandSplitter MidFilter; alignas(16) FloatBufferLine MidLF{}; alignas(16) FloatBufferLine MidHF{}; - using DelayLine = std::array<float,DelayLength>; - al::FlexArray<DelayLine,16> DelayBuf; + al::FlexArray<BandSplitter,16> ChannelFilters; static std::unique_ptr<FrontStablizer> Create(size_t numchans) { return std::unique_ptr<FrontStablizer>{new(FamCount(numchans)) FrontStablizer{numchans}}; } - DEF_FAM_NEWDEL(FrontStablizer, DelayBuf) + DEF_FAM_NEWDEL(FrontStablizer, ChannelFilters) }; #endif /* CORE_FRONT_STABLIZER_H */ |