diff options
author | Chris Robinson <[email protected]> | 2023-01-06 01:40:10 -0800 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2023-01-06 01:40:10 -0800 |
commit | ec30a306df6c1d2079786c9cd4ae37fd6554e229 (patch) | |
tree | 223928cf686f6f62cdcc9c51f75f3b394065ff8d /core/bformatdec.cpp | |
parent | 3f8a3af3637606dae61ba112cb5bd9d2d897e5cb (diff) |
Avoid using a reversed all-pass for the front stablizer
While a neat trick, it's been shown to be too volatile and add noise as the
signal gets louder. It's better to just accept the phase shift and ensure
everything stays aligned.
Diffstat (limited to 'core/bformatdec.cpp')
-rw-r--r-- | core/bformatdec.cpp | 80 |
1 files changed, 29 insertions, 51 deletions
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()); } |