Fix lambda callback parameter type
[openal-soft.git] / core / bformatdec.cpp
blob1e46e9508ced9f00b25f1c629cd100c2883183c9
2 #include "config.h"
4 #include "bformatdec.h"
6 #include <algorithm>
7 #include <array>
8 #include <cmath>
9 #include <functional>
10 #include <utility>
12 #include "alnumbers.h"
13 #include "bufferline.h"
14 #include "filters/splitter.h"
15 #include "flexarray.h"
16 #include "front_stablizer.h"
17 #include "mixer.h"
18 #include "opthelpers.h"
21 namespace {
23 template<typename... Ts>
24 struct overloaded : Ts... { using Ts::operator()...; };
26 template<typename... Ts>
27 overloaded(Ts...) -> overloaded<Ts...>;
29 } // namespace
31 BFormatDec::BFormatDec(const size_t inchans, const al::span<const ChannelDec> coeffs,
32 const al::span<const ChannelDec> coeffslf, const float xover_f0norm,
33 std::unique_ptr<FrontStablizer> stablizer)
34 : mStablizer{std::move(stablizer)}
36 if(coeffslf.empty())
38 auto &decoder = mChannelDec.emplace<std::vector<ChannelDecoderSingle>>(inchans);
39 for(size_t j{0};j < decoder.size();++j)
41 std::transform(coeffs.cbegin(), coeffs.cend(), decoder[j].mGains.begin(),
42 [j](const ChannelDec &incoeffs) { return incoeffs[j]; });
45 else
47 auto &decoder = mChannelDec.emplace<std::vector<ChannelDecoderDual>>(inchans);
48 decoder[0].mXOver.init(xover_f0norm);
49 for(size_t j{1};j < decoder.size();++j)
50 decoder[j].mXOver = decoder[0].mXOver;
52 for(size_t j{0};j < decoder.size();++j)
54 std::transform(coeffs.cbegin(), coeffs.cend(), decoder[j].mGains[sHFBand].begin(),
55 [j](const ChannelDec &incoeffs) { return incoeffs[j]; });
57 std::transform(coeffslf.cbegin(), coeffslf.cend(), decoder[j].mGains[sLFBand].begin(),
58 [j](const ChannelDec &incoeffs) { return incoeffs[j]; });
64 void BFormatDec::process(const al::span<FloatBufferLine> OutBuffer,
65 const al::span<const FloatBufferLine> InSamples, const size_t SamplesToDo)
67 ASSUME(SamplesToDo > 0);
69 auto decode_dualband = [=](std::vector<ChannelDecoderDual> &decoder)
71 auto input = InSamples.cbegin();
72 const auto hfSamples = al::span<float>{mSamples[sHFBand]}.first(SamplesToDo);
73 const auto lfSamples = al::span<float>{mSamples[sLFBand]}.first(SamplesToDo);
74 for(auto &chandec : decoder)
76 chandec.mXOver.process(al::span{*input++}.first(SamplesToDo), hfSamples, lfSamples);
77 MixSamples(hfSamples, OutBuffer, chandec.mGains[sHFBand], chandec.mGains[sHFBand],0,0);
78 MixSamples(lfSamples, OutBuffer, chandec.mGains[sLFBand], chandec.mGains[sLFBand],0,0);
81 auto decode_singleband = [=](std::vector<ChannelDecoderSingle> &decoder)
83 auto input = InSamples.cbegin();
84 for(auto &chandec : decoder)
86 MixSamples(al::span{*input++}.first(SamplesToDo), OutBuffer, chandec.mGains,
87 chandec.mGains, 0, 0);
91 std::visit(overloaded{decode_dualband, decode_singleband}, mChannelDec);
94 void BFormatDec::processStablize(const al::span<FloatBufferLine> OutBuffer,
95 const al::span<const FloatBufferLine> InSamples, const size_t lidx, const size_t ridx,
96 const size_t cidx, const size_t SamplesToDo)
98 ASSUME(SamplesToDo > 0);
100 /* Move the existing direct L/R signal out so it doesn't get processed by
101 * the stablizer.
103 const auto leftout = al::span<float>{OutBuffer[lidx]}.first(SamplesToDo);
104 const auto rightout = al::span<float>{OutBuffer[ridx]}.first(SamplesToDo);
105 const auto mid = al::span{mStablizer->MidDirect}.first(SamplesToDo);
106 const auto side = al::span{mStablizer->Side}.first(SamplesToDo);
107 std::transform(leftout.cbegin(), leftout.cend(), rightout.cbegin(), mid.begin(),std::plus{});
108 std::transform(leftout.cbegin(), leftout.cend(), rightout.cbegin(), side.begin(),std::minus{});
109 std::fill_n(leftout.begin(), leftout.size(), 0.0f);
110 std::fill_n(rightout.begin(), rightout.size(), 0.0f);
112 /* Decode the B-Format input to OutBuffer. */
113 process(OutBuffer, InSamples, SamplesToDo);
115 /* Include the decoded side signal with the direct side signal. */
116 for(size_t i{0};i < SamplesToDo;++i)
117 side[i] += leftout[i] - rightout[i];
119 /* Get the decoded mid signal and band-split it. */
120 const auto tmpsamples = al::span{mStablizer->Temp}.first(SamplesToDo);
121 std::transform(leftout.cbegin(), leftout.cend(), rightout.cbegin(), tmpsamples.begin(),
122 std::plus{});
124 mStablizer->MidFilter.process(tmpsamples, mStablizer->MidHF, mStablizer->MidLF);
126 /* Apply an all-pass to all channels to match the band-splitter's phase
127 * shift. This is to keep the phase synchronized between the existing
128 * signal and the split mid signal.
130 const size_t NumChannels{OutBuffer.size()};
131 for(size_t i{0u};i < NumChannels;i++)
133 /* Skip the left and right channels, which are going to get overwritten,
134 * and substitute the direct mid signal and direct+decoded side signal.
136 if(i == lidx)
137 mStablizer->ChannelFilters[i].processAllPass(mid);
138 else if(i == ridx)
139 mStablizer->ChannelFilters[i].processAllPass(side);
140 else
141 mStablizer->ChannelFilters[i].processAllPass({OutBuffer[i].data(), SamplesToDo});
144 /* This pans the separate low- and high-frequency signals between being on
145 * the center channel and the left+right channels. The low-frequency signal
146 * is panned 1/3rd toward center and the high-frequency signal is panned
147 * 1/4th toward center. These values can be tweaked.
149 const float cos_lf{std::cos(1.0f/3.0f * (al::numbers::pi_v<float>*0.5f))};
150 const float cos_hf{std::cos(1.0f/4.0f * (al::numbers::pi_v<float>*0.5f))};
151 const float sin_lf{std::sin(1.0f/3.0f * (al::numbers::pi_v<float>*0.5f))};
152 const float sin_hf{std::sin(1.0f/4.0f * (al::numbers::pi_v<float>*0.5f))};
153 const auto centerout = al::span<float>{OutBuffer[cidx]}.first(SamplesToDo);
154 for(size_t i{0};i < SamplesToDo;i++)
156 /* Add the direct mid signal to the processed mid signal so it can be
157 * properly combined with the direct+decoded side signal.
159 const float m{mStablizer->MidLF[i]*cos_lf + mStablizer->MidHF[i]*cos_hf + mid[i]};
160 const float c{mStablizer->MidLF[i]*sin_lf + mStablizer->MidHF[i]*sin_hf};
161 const float s{side[i]};
163 /* The generated center channel signal adds to the existing signal,
164 * while the modified left and right channels replace.
166 leftout[i] = (m + s) * 0.5f;
167 rightout[i] = (m - s) * 0.5f;
168 centerout[i] += c * 0.5f;
173 std::unique_ptr<BFormatDec> BFormatDec::Create(const size_t inchans,
174 const al::span<const ChannelDec> coeffs, const al::span<const ChannelDec> coeffslf,
175 const float xover_f0norm, std::unique_ptr<FrontStablizer> stablizer)
177 return std::make_unique<BFormatDec>(inchans, coeffs, coeffslf, xover_f0norm,
178 std::move(stablizer));