Make some structs nested
[openal-soft.git] / core / bformatdec.cpp
blob1ad46f9569d06923c6edc335647d142c4308172a
2 #include "config.h"
4 #include "bformatdec.h"
6 #include <algorithm>
7 #include <array>
8 #include <cmath>
9 #include <utility>
11 #include "almalloc.h"
12 #include "alnumbers.h"
13 #include "filters/splitter.h"
14 #include "front_stablizer.h"
15 #include "mixer.h"
16 #include "opthelpers.h"
19 BFormatDec::BFormatDec(const size_t inchans, const al::span<const ChannelDec> coeffs,
20 const al::span<const ChannelDec> coeffslf, const float xover_f0norm,
21 std::unique_ptr<FrontStablizer> stablizer)
22 : mStablizer{std::move(stablizer)}, mDualBand{!coeffslf.empty()}, mChannelDec{inchans}
24 if(!mDualBand)
26 for(size_t j{0};j < mChannelDec.size();++j)
28 float *outcoeffs{mChannelDec[j].mGains.Single};
29 for(const ChannelDec &incoeffs : coeffs)
30 *(outcoeffs++) = incoeffs[j];
33 else
35 mChannelDec[0].mXOver.init(xover_f0norm);
36 for(size_t j{1};j < mChannelDec.size();++j)
37 mChannelDec[j].mXOver = mChannelDec[0].mXOver;
39 for(size_t j{0};j < mChannelDec.size();++j)
41 float *outcoeffs{mChannelDec[j].mGains.Dual[sHFBand]};
42 for(const ChannelDec &incoeffs : coeffs)
43 *(outcoeffs++) = incoeffs[j];
45 outcoeffs = mChannelDec[j].mGains.Dual[sLFBand];
46 for(const ChannelDec &incoeffs : coeffslf)
47 *(outcoeffs++) = incoeffs[j];
53 void BFormatDec::process(const al::span<FloatBufferLine> OutBuffer,
54 const FloatBufferLine *InSamples, const size_t SamplesToDo)
56 ASSUME(SamplesToDo > 0);
58 if(mDualBand)
60 const al::span<float> hfSamples{mSamples[sHFBand].data(), SamplesToDo};
61 const al::span<float> lfSamples{mSamples[sLFBand].data(), SamplesToDo};
62 for(auto &chandec : mChannelDec)
64 chandec.mXOver.process({InSamples->data(), SamplesToDo}, hfSamples.data(),
65 lfSamples.data());
66 MixSamples(hfSamples, OutBuffer, chandec.mGains.Dual[sHFBand],
67 chandec.mGains.Dual[sHFBand], 0, 0);
68 MixSamples(lfSamples, OutBuffer, chandec.mGains.Dual[sLFBand],
69 chandec.mGains.Dual[sLFBand], 0, 0);
70 ++InSamples;
73 else
75 for(auto &chandec : mChannelDec)
77 MixSamples({InSamples->data(), SamplesToDo}, OutBuffer, chandec.mGains.Single,
78 chandec.mGains.Single, 0, 0);
79 ++InSamples;
84 void BFormatDec::processStablize(const al::span<FloatBufferLine> OutBuffer,
85 const FloatBufferLine *InSamples, const size_t lidx, const size_t ridx, const size_t cidx,
86 const size_t SamplesToDo)
88 ASSUME(SamplesToDo > 0);
90 /* Move the existing direct L/R signal out so it doesn't get processed by
91 * the stablizer. Add a delay to it so it stays aligned with the stablizer
92 * delay.
94 float *RESTRICT mid{al::assume_aligned<16>(mStablizer->MidDirect.data())};
95 float *RESTRICT side{al::assume_aligned<16>(mStablizer->Side.data())};
96 for(size_t i{0};i < SamplesToDo;++i)
98 mid[FrontStablizer::DelayLength+i] = OutBuffer[lidx][i] + OutBuffer[ridx][i];
99 side[FrontStablizer::DelayLength+i] = OutBuffer[lidx][i] - OutBuffer[ridx][i];
101 std::fill_n(OutBuffer[lidx].begin(), SamplesToDo, 0.0f);
102 std::fill_n(OutBuffer[ridx].begin(), SamplesToDo, 0.0f);
104 /* Decode the B-Format input to OutBuffer. */
105 process(OutBuffer, InSamples, SamplesToDo);
107 /* Apply a delay to all channels, except the front-left and front-right, so
108 * they maintain correct timing.
110 const size_t NumChannels{OutBuffer.size()};
111 for(size_t i{0u};i < NumChannels;i++)
113 if(i == lidx || i == ridx)
114 continue;
116 auto &DelayBuf = mStablizer->DelayBuf[i];
117 auto buffer_end = OutBuffer[i].begin() + SamplesToDo;
118 if LIKELY(SamplesToDo >= FrontStablizer::DelayLength)
120 auto delay_end = std::rotate(OutBuffer[i].begin(),
121 buffer_end - FrontStablizer::DelayLength, buffer_end);
122 std::swap_ranges(OutBuffer[i].begin(), delay_end, DelayBuf.begin());
124 else
126 auto delay_start = std::swap_ranges(OutBuffer[i].begin(), buffer_end,
127 DelayBuf.begin());
128 std::rotate(DelayBuf.begin(), delay_start, DelayBuf.end());
132 /* Include the side signal for what was just decoded. */
133 for(size_t i{0};i < SamplesToDo;++i)
134 side[FrontStablizer::DelayLength+i] += OutBuffer[lidx][i] - OutBuffer[ridx][i];
136 /* Combine the delayed mid signal with the decoded mid signal. Note that
137 * the samples are stored and combined in reverse, so the newest samples
138 * are at the front and the oldest at the back.
140 al::span<float> tmpbuf{mStablizer->TempBuf.data(), SamplesToDo+FrontStablizer::DelayLength};
141 auto tmpiter = tmpbuf.begin() + SamplesToDo;
142 std::copy(mStablizer->MidDelay.cbegin(), mStablizer->MidDelay.cend(), tmpiter);
143 for(size_t i{0};i < SamplesToDo;++i)
144 *--tmpiter = OutBuffer[lidx][i] + OutBuffer[ridx][i];
145 /* Save the newest samples for next time. */
146 std::copy_n(tmpbuf.cbegin(), mStablizer->MidDelay.size(), mStablizer->MidDelay.begin());
148 /* Apply an all-pass on the reversed signal, then reverse the samples to
149 * get the forward signal with a reversed phase shift. The future samples
150 * are included with the all-pass to reduce the error in the output
151 * samples (the smaller the delay, the more error is introduced).
153 mStablizer->MidFilter.applyAllpass(tmpbuf);
154 tmpbuf = tmpbuf.subspan<FrontStablizer::DelayLength>();
155 std::reverse(tmpbuf.begin(), tmpbuf.end());
157 /* Now apply the band-splitter, combining its phase shift with the reversed
158 * phase shift, restoring the original phase on the split signal.
160 mStablizer->MidFilter.process(tmpbuf, mStablizer->MidHF.data(), mStablizer->MidLF.data());
162 /* This pans the separate low- and high-frequency signals between being on
163 * the center channel and the left+right channels. The low-frequency signal
164 * is panned 1/3rd toward center and the high-frequency signal is panned
165 * 1/4th toward center. These values can be tweaked.
167 const float cos_lf{std::cos(1.0f/3.0f * (al::numbers::pi_v<float>*0.5f))};
168 const float cos_hf{std::cos(1.0f/4.0f * (al::numbers::pi_v<float>*0.5f))};
169 const float sin_lf{std::sin(1.0f/3.0f * (al::numbers::pi_v<float>*0.5f))};
170 const float sin_hf{std::sin(1.0f/4.0f * (al::numbers::pi_v<float>*0.5f))};
171 for(size_t i{0};i < SamplesToDo;i++)
173 const float m{mStablizer->MidLF[i]*cos_lf + mStablizer->MidHF[i]*cos_hf + mid[i]};
174 const float c{mStablizer->MidLF[i]*sin_lf + mStablizer->MidHF[i]*sin_hf};
175 const float s{side[i]};
177 /* The generated center channel signal adds to the existing signal,
178 * while the modified left and right channels replace.
180 OutBuffer[lidx][i] = (m + s) * 0.5f;
181 OutBuffer[ridx][i] = (m - s) * 0.5f;
182 OutBuffer[cidx][i] += c * 0.5f;
184 /* Move the delayed mid/side samples to the front for next time. */
185 auto mid_end = mStablizer->MidDirect.cbegin() + SamplesToDo;
186 std::copy(mid_end, mid_end+FrontStablizer::DelayLength, mStablizer->MidDirect.begin());
187 auto side_end = mStablizer->Side.cbegin() + SamplesToDo;
188 std::copy(side_end, side_end+FrontStablizer::DelayLength, mStablizer->Side.begin());
192 std::unique_ptr<BFormatDec> BFormatDec::Create(const size_t inchans,
193 const al::span<const ChannelDec> coeffs, const al::span<const ChannelDec> coeffslf,
194 const float xover_f0norm, std::unique_ptr<FrontStablizer> stablizer)
196 return std::make_unique<BFormatDec>(inchans, coeffs, coeffslf, xover_f0norm,
197 std::move(stablizer));