Limit convolution processing to the output ambisonic order
[openal-soft.git] / alc / bformatdec.cpp
blobb2a2aec98adb9bb9b3b44026fb7ac361218b8cde
2 #include "config.h"
4 #include "bformatdec.h"
6 #include <algorithm>
7 #include <array>
8 #include <cassert>
9 #include <cmath>
10 #include <iterator>
11 #include <numeric>
13 #include "AL/al.h"
15 #include "almalloc.h"
16 #include "alu.h"
17 #include "ambdec.h"
18 #include "filters/splitter.h"
19 #include "front_stablizer.h"
20 #include "math_defs.h"
21 #include "opthelpers.h"
24 namespace {
26 constexpr std::array<float,MAX_AMBI_ORDER+1> Ambi3DDecoderHFScale{{
27 1.00000000e+00f, 1.00000000e+00f
28 }};
29 constexpr std::array<float,MAX_AMBI_ORDER+1> Ambi3DDecoderHFScale2O{{
30 7.45355990e-01f, 1.00000000e+00f, 1.00000000e+00f
31 }};
32 constexpr std::array<float,MAX_AMBI_ORDER+1> Ambi3DDecoderHFScale3O{{
33 5.89792205e-01f, 8.79693856e-01f, 1.00000000e+00f, 1.00000000e+00f
34 }};
36 inline auto GetDecoderHFScales(ALuint order) noexcept -> const std::array<float,MAX_AMBI_ORDER+1>&
38 if(order >= 3) return Ambi3DDecoderHFScale3O;
39 if(order == 2) return Ambi3DDecoderHFScale2O;
40 return Ambi3DDecoderHFScale;
43 inline auto GetAmbiScales(AmbDecScale scaletype) noexcept
44 -> const std::array<float,MAX_AMBI_CHANNELS>&
46 if(scaletype == AmbDecScale::FuMa) return AmbiScale::FromFuMa;
47 if(scaletype == AmbDecScale::SN3D) return AmbiScale::FromSN3D;
48 return AmbiScale::FromN3D;
51 } // namespace
54 BFormatDec::BFormatDec(const AmbDecConf *conf, const bool allow_2band, const size_t inchans,
55 const ALuint srate, const ALuint (&chanmap)[MAX_OUTPUT_CHANNELS],
56 std::unique_ptr<FrontStablizer> stablizer)
57 : mStablizer{std::move(stablizer)}, mDualBand{allow_2band && (conf->FreqBands == 2)}
58 , mChannelDec{inchans}
60 const bool periphonic{(conf->ChanMask&AMBI_PERIPHONIC_MASK) != 0};
61 const std::array<float,MAX_AMBI_CHANNELS> &coeff_scale = GetAmbiScales(conf->CoeffScale);
63 if(!mDualBand)
65 for(size_t j{0},k{0};j < mChannelDec.size();++j)
67 const size_t acn{periphonic ? j : AmbiIndex::From2D[j]};
68 if(!(conf->ChanMask&(1u<<acn))) continue;
69 const size_t order{AmbiIndex::OrderFromChannel[acn]};
70 const float gain{conf->HFOrderGain[order] / coeff_scale[acn]};
71 for(size_t i{0u};i < conf->Speakers.size();++i)
73 const size_t chanidx{chanmap[i]};
74 mChannelDec[j].mGains.Single[chanidx] = conf->HFMatrix[i][k] * gain;
76 ++k;
79 else
81 mChannelDec[0].mXOver.init(conf->XOverFreq / static_cast<float>(srate));
82 for(size_t j{1};j < mChannelDec.size();++j)
83 mChannelDec[j].mXOver = mChannelDec[0].mXOver;
85 const float ratio{std::pow(10.0f, conf->XOverRatio / 40.0f)};
86 for(size_t j{0},k{0};j < mChannelDec.size();++j)
88 const size_t acn{periphonic ? j : AmbiIndex::From2D[j]};
89 if(!(conf->ChanMask&(1u<<acn))) continue;
90 const size_t order{AmbiIndex::OrderFromChannel[acn]};
91 const float hfGain{conf->HFOrderGain[order] * ratio / coeff_scale[acn]};
92 const float lfGain{conf->LFOrderGain[order] / ratio / coeff_scale[acn]};
93 for(size_t i{0u};i < conf->Speakers.size();++i)
95 const size_t chanidx{chanmap[i]};
96 mChannelDec[j].mGains.Dual[sHFBand][chanidx] = conf->HFMatrix[i][k] * hfGain;
97 mChannelDec[j].mGains.Dual[sLFBand][chanidx] = conf->LFMatrix[i][k] * lfGain;
99 ++k;
104 BFormatDec::BFormatDec(const size_t inchans, const al::span<const ChannelDec> coeffs,
105 const al::span<const ChannelDec> coeffslf, std::unique_ptr<FrontStablizer> stablizer)
106 : mStablizer{std::move(stablizer)}, mDualBand{!coeffslf.empty()}, mChannelDec{inchans}
108 if(!mDualBand)
110 for(size_t j{0};j < mChannelDec.size();++j)
112 float *outcoeffs{mChannelDec[j].mGains.Single};
113 for(const ChannelDec &incoeffs : coeffs)
114 *(outcoeffs++) = incoeffs[j];
117 else
119 for(size_t j{0};j < mChannelDec.size();++j)
121 float *outcoeffs{mChannelDec[j].mGains.Dual[sHFBand]};
122 for(const ChannelDec &incoeffs : coeffs)
123 *(outcoeffs++) = incoeffs[j];
125 outcoeffs = mChannelDec[j].mGains.Dual[sLFBand];
126 for(const ChannelDec &incoeffs : coeffslf)
127 *(outcoeffs++) = incoeffs[j];
133 void BFormatDec::process(const al::span<FloatBufferLine> OutBuffer,
134 const FloatBufferLine *InSamples, const size_t SamplesToDo)
136 ASSUME(SamplesToDo > 0);
138 if(mDualBand)
140 const al::span<float> hfSamples{mSamples[sHFBand].data(), SamplesToDo};
141 const al::span<float> lfSamples{mSamples[sLFBand].data(), SamplesToDo};
142 for(auto &chandec : mChannelDec)
144 chandec.mXOver.process({InSamples->data(), SamplesToDo}, hfSamples.data(),
145 lfSamples.data());
146 MixSamples(hfSamples, OutBuffer, chandec.mGains.Dual[sHFBand],
147 chandec.mGains.Dual[sHFBand], 0, 0);
148 MixSamples(lfSamples, OutBuffer, chandec.mGains.Dual[sLFBand],
149 chandec.mGains.Dual[sLFBand], 0, 0);
150 ++InSamples;
153 else
155 for(auto &chandec : mChannelDec)
157 MixSamples({InSamples->data(), SamplesToDo}, OutBuffer, chandec.mGains.Single,
158 chandec.mGains.Single, 0, 0);
159 ++InSamples;
164 void BFormatDec::processStablize(const al::span<FloatBufferLine> OutBuffer,
165 const FloatBufferLine *InSamples, const size_t lidx, const size_t ridx, const size_t cidx,
166 const size_t SamplesToDo)
168 ASSUME(SamplesToDo > 0);
170 /* Move the existing direct L/R signal out so it doesn't get processed by
171 * the stablizer. Add a delay to it so it stays aligned with the stablizer
172 * delay.
174 float *RESTRICT mid{al::assume_aligned<16>(mStablizer->MidDirect.data())};
175 float *RESTRICT side{al::assume_aligned<16>(mStablizer->Side.data())};
176 for(size_t i{0};i < SamplesToDo;++i)
178 mid[FrontStablizer::DelayLength+i] = OutBuffer[lidx][i] + OutBuffer[ridx][i];
179 side[FrontStablizer::DelayLength+i] = OutBuffer[lidx][i] - OutBuffer[ridx][i];
181 std::fill_n(OutBuffer[lidx].begin(), SamplesToDo, 0.0f);
182 std::fill_n(OutBuffer[ridx].begin(), SamplesToDo, 0.0f);
184 /* Decode the B-Format input to OutBuffer. */
185 process(OutBuffer, InSamples, SamplesToDo);
187 /* Apply a delay to all channels, except the front-left and front-right, so
188 * they maintain correct timing.
190 const size_t NumChannels{OutBuffer.size()};
191 for(size_t i{0u};i < NumChannels;i++)
193 if(i == lidx || i == ridx)
194 continue;
196 auto &DelayBuf = mStablizer->DelayBuf[i];
197 auto buffer_end = OutBuffer[i].begin() + SamplesToDo;
198 if LIKELY(SamplesToDo >= FrontStablizer::DelayLength)
200 auto delay_end = std::rotate(OutBuffer[i].begin(),
201 buffer_end - FrontStablizer::DelayLength, buffer_end);
202 std::swap_ranges(OutBuffer[i].begin(), delay_end, DelayBuf.begin());
204 else
206 auto delay_start = std::swap_ranges(OutBuffer[i].begin(), buffer_end,
207 DelayBuf.begin());
208 std::rotate(DelayBuf.begin(), delay_start, DelayBuf.end());
212 /* Include the side signal for what was just decoded. */
213 for(size_t i{0};i < SamplesToDo;++i)
214 side[FrontStablizer::DelayLength+i] += OutBuffer[lidx][i] - OutBuffer[ridx][i];
216 /* Combine the delayed mid signal with the decoded mid signal. Note that
217 * the samples are stored and combined in reverse, so the newest samples
218 * are at the front and the oldest at the back.
220 al::span<float> tmpbuf{mStablizer->TempBuf.data(), SamplesToDo+FrontStablizer::DelayLength};
221 auto tmpiter = tmpbuf.begin() + SamplesToDo;
222 std::copy(mStablizer->MidDelay.cbegin(), mStablizer->MidDelay.cend(), tmpiter);
223 for(size_t i{0};i < SamplesToDo;++i)
224 *--tmpiter = OutBuffer[lidx][i] + OutBuffer[ridx][i];
225 /* Save the newest samples for next time. */
226 std::copy_n(tmpbuf.cbegin(), mStablizer->MidDelay.size(), mStablizer->MidDelay.begin());
228 /* Apply an all-pass on the reversed signal, then reverse the samples to
229 * get the forward signal with a reversed phase shift. The future samples
230 * are included with the all-pass to reduce the error in the output
231 * samples (the smaller the delay, the more error is introduced).
233 mStablizer->MidFilter.applyAllpass(tmpbuf);
234 tmpbuf = tmpbuf.subspan<FrontStablizer::DelayLength>();
235 std::reverse(tmpbuf.begin(), tmpbuf.end());
237 /* Now apply the band-splitter, combining its phase shift with the reversed
238 * phase shift, restoring the original phase on the split signal.
240 mStablizer->MidFilter.process(tmpbuf, mStablizer->MidHF.data(), mStablizer->MidLF.data());
242 /* This pans the separate low- and high-frequency signals between being on
243 * the center channel and the left+right channels. The low-frequency signal
244 * is panned 1/3rd toward center and the high-frequency signal is panned
245 * 1/4th toward center. These values can be tweaked.
247 const float cos_lf{std::cos(1.0f/3.0f * (al::MathDefs<float>::Pi()*0.5f))};
248 const float cos_hf{std::cos(1.0f/4.0f * (al::MathDefs<float>::Pi()*0.5f))};
249 const float sin_lf{std::sin(1.0f/3.0f * (al::MathDefs<float>::Pi()*0.5f))};
250 const float sin_hf{std::sin(1.0f/4.0f * (al::MathDefs<float>::Pi()*0.5f))};
251 for(size_t i{0};i < SamplesToDo;i++)
253 const float m{mStablizer->MidLF[i]*cos_lf + mStablizer->MidHF[i]*cos_hf + mid[i]};
254 const float c{mStablizer->MidLF[i]*sin_lf + mStablizer->MidHF[i]*sin_hf};
255 const float s{side[i]};
257 /* The generated center channel signal adds to the existing signal,
258 * while the modified left and right channels replace.
260 OutBuffer[lidx][i] = (m + s) * 0.5f;
261 OutBuffer[ridx][i] = (m - s) * 0.5f;
262 OutBuffer[cidx][i] += c * 0.5f;
264 /* Move the delayed mid/side samples to the front for next time. */
265 auto mid_end = mStablizer->MidDirect.cbegin() + SamplesToDo;
266 std::copy(mid_end, mid_end+FrontStablizer::DelayLength, mStablizer->MidDirect.begin());
267 auto side_end = mStablizer->Side.cbegin() + SamplesToDo;
268 std::copy(side_end, side_end+FrontStablizer::DelayLength, mStablizer->Side.begin());
272 auto BFormatDec::GetHFOrderScales(const ALuint in_order, const ALuint out_order) noexcept
273 -> std::array<float,MAX_AMBI_ORDER+1>
275 std::array<float,MAX_AMBI_ORDER+1> ret{};
277 assert(out_order >= in_order);
279 const auto &target = GetDecoderHFScales(out_order);
280 const auto &input = GetDecoderHFScales(in_order);
282 for(size_t i{0};i < in_order+1;++i)
283 ret[i] = input[i] / target[i];
285 return ret;
288 std::unique_ptr<BFormatDec> BFormatDec::Create(const AmbDecConf *conf, const bool allow_2band,
289 const size_t inchans, const ALuint srate, const ALuint (&chanmap)[MAX_OUTPUT_CHANNELS],
290 std::unique_ptr<FrontStablizer> stablizer)
292 return std::unique_ptr<BFormatDec>{new(FamCount(inchans))
293 BFormatDec{conf, allow_2band, inchans, srate, chanmap, std::move(stablizer)}};
295 std::unique_ptr<BFormatDec> BFormatDec::Create(const size_t inchans,
296 const al::span<const ChannelDec> coeffs, const al::span<const ChannelDec> coeffslf,
297 std::unique_ptr<FrontStablizer> stablizer)
299 return std::unique_ptr<BFormatDec>{new(FamCount(inchans))
300 BFormatDec{inchans, coeffs, coeffslf, std::move(stablizer)}};