]> git.tdb.fi Git - ext/openal.git/blob - core/bformatdec.cpp
Import OpenAL Soft 1.23.1 sources
[ext/openal.git] / core / bformatdec.cpp
1
2 #include "config.h"
3
4 #include "bformatdec.h"
5
6 #include <algorithm>
7 #include <array>
8 #include <cmath>
9 #include <utility>
10
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"
17
18
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}
23 {
24     if(!mDualBand)
25     {
26         for(size_t j{0};j < mChannelDec.size();++j)
27         {
28             float *outcoeffs{mChannelDec[j].mGains.Single};
29             for(const ChannelDec &incoeffs : coeffs)
30                 *(outcoeffs++) = incoeffs[j];
31         }
32     }
33     else
34     {
35         mChannelDec[0].mXOver.init(xover_f0norm);
36         for(size_t j{1};j < mChannelDec.size();++j)
37             mChannelDec[j].mXOver = mChannelDec[0].mXOver;
38
39         for(size_t j{0};j < mChannelDec.size();++j)
40         {
41             float *outcoeffs{mChannelDec[j].mGains.Dual[sHFBand]};
42             for(const ChannelDec &incoeffs : coeffs)
43                 *(outcoeffs++) = incoeffs[j];
44
45             outcoeffs = mChannelDec[j].mGains.Dual[sLFBand];
46             for(const ChannelDec &incoeffs : coeffslf)
47                 *(outcoeffs++) = incoeffs[j];
48         }
49     }
50 }
51
52
53 void BFormatDec::process(const al::span<FloatBufferLine> OutBuffer,
54     const FloatBufferLine *InSamples, const size_t SamplesToDo)
55 {
56     ASSUME(SamplesToDo > 0);
57
58     if(mDualBand)
59     {
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)
63         {
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;
71         }
72     }
73     else
74     {
75         for(auto &chandec : mChannelDec)
76         {
77             MixSamples({InSamples->data(), SamplesToDo}, OutBuffer, chandec.mGains.Single,
78                 chandec.mGains.Single, 0, 0);
79             ++InSamples;
80         }
81     }
82 }
83
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)
87 {
88     ASSUME(SamplesToDo > 0);
89
90     /* Move the existing direct L/R signal out so it doesn't get processed by
91      * the stablizer.
92      */
93     float *RESTRICT mid{al::assume_aligned<16>(mStablizer->MidDirect.data())};
94     float *RESTRICT side{al::assume_aligned<16>(mStablizer->Side.data())};
95     for(size_t i{0};i < SamplesToDo;++i)
96     {
97         mid[i] = OutBuffer[lidx][i] + OutBuffer[ridx][i];
98         side[i] = OutBuffer[lidx][i] - OutBuffer[ridx][i];
99     }
100     std::fill_n(OutBuffer[lidx].begin(), SamplesToDo, 0.0f);
101     std::fill_n(OutBuffer[ridx].begin(), SamplesToDo, 0.0f);
102
103     /* Decode the B-Format input to OutBuffer. */
104     process(OutBuffer, InSamples, SamplesToDo);
105
106     /* Include the decoded side signal with the direct side signal. */
107     for(size_t i{0};i < SamplesToDo;++i)
108         side[i] += OutBuffer[lidx][i] - OutBuffer[ridx][i];
109
110     /* Get the decoded mid signal and band-split it. */
111     std::transform(OutBuffer[lidx].cbegin(), OutBuffer[lidx].cbegin()+SamplesToDo,
112         OutBuffer[ridx].cbegin(), mStablizer->Temp.begin(),
113         [](const float l, const float r) noexcept { return l + r; });
114
115     mStablizer->MidFilter.process({mStablizer->Temp.data(), SamplesToDo}, mStablizer->MidHF.data(),
116         mStablizer->MidLF.data());
117
118     /* Apply an all-pass to all channels to match the band-splitter's phase
119      * shift. This is to keep the phase synchronized between the existing
120      * signal and the split mid signal.
121      */
122     const size_t NumChannels{OutBuffer.size()};
123     for(size_t i{0u};i < NumChannels;i++)
124     {
125         /* Skip the left and right channels, which are going to get overwritten,
126          * and substitute the direct mid signal and direct+decoded side signal.
127          */
128         if(i == lidx)
129             mStablizer->ChannelFilters[i].processAllPass({mid, SamplesToDo});
130         else if(i == ridx)
131             mStablizer->ChannelFilters[i].processAllPass({side, SamplesToDo});
132         else
133             mStablizer->ChannelFilters[i].processAllPass({OutBuffer[i].data(), SamplesToDo});
134     }
135
136     /* This pans the separate low- and high-frequency signals between being on
137      * the center channel and the left+right channels. The low-frequency signal
138      * is panned 1/3rd toward center and the high-frequency signal is panned
139      * 1/4th toward center. These values can be tweaked.
140      */
141     const float cos_lf{std::cos(1.0f/3.0f * (al::numbers::pi_v<float>*0.5f))};
142     const float cos_hf{std::cos(1.0f/4.0f * (al::numbers::pi_v<float>*0.5f))};
143     const float sin_lf{std::sin(1.0f/3.0f * (al::numbers::pi_v<float>*0.5f))};
144     const float sin_hf{std::sin(1.0f/4.0f * (al::numbers::pi_v<float>*0.5f))};
145     for(size_t i{0};i < SamplesToDo;i++)
146     {
147         /* Add the direct mid signal to the processed mid signal so it can be
148          * properly combined with the direct+decoded side signal.
149          */
150         const float m{mStablizer->MidLF[i]*cos_lf + mStablizer->MidHF[i]*cos_hf + mid[i]};
151         const float c{mStablizer->MidLF[i]*sin_lf + mStablizer->MidHF[i]*sin_hf};
152         const float s{side[i]};
153
154         /* The generated center channel signal adds to the existing signal,
155          * while the modified left and right channels replace.
156          */
157         OutBuffer[lidx][i] = (m + s) * 0.5f;
158         OutBuffer[ridx][i] = (m - s) * 0.5f;
159         OutBuffer[cidx][i] += c * 0.5f;
160     }
161 }
162
163
164 std::unique_ptr<BFormatDec> BFormatDec::Create(const size_t inchans,
165     const al::span<const ChannelDec> coeffs, const al::span<const ChannelDec> coeffslf,
166     const float xover_f0norm, std::unique_ptr<FrontStablizer> stablizer)
167 {
168     return std::make_unique<BFormatDec>(inchans, coeffs, coeffslf, xover_f0norm,
169         std::move(stablizer));
170 }