4 #include "bformatdec.h"
12 #include "alnumbers.h"
13 #include "filters/splitter.h"
14 #include "front_stablizer.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
}
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
];
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);
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(),
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);
75 for(auto &chandec
: mChannelDec
)
77 MixSamples({InSamples
->data(), SamplesToDo
}, OutBuffer
, chandec
.mGains
.Single
,
78 chandec
.mGains
.Single
, 0, 0);
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
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
)
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());
126 auto delay_start
= std::swap_ranges(OutBuffer
[i
].begin(), buffer_end
,
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
));