aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--alc/alc.cpp5
-rw-r--r--alc/panning.cpp4
-rw-r--r--core/bformatdec.cpp80
-rw-r--r--core/filters/splitter.cpp7
-rw-r--r--core/filters/splitter.h7
-rw-r--r--core/front_stablizer.h17
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 */