4 #include "bformatdec.h"
18 #include "filters/splitter.h"
19 #include "front_stablizer.h"
20 #include "math_defs.h"
21 #include "opthelpers.h"
26 constexpr std::array
<float,MAX_AMBI_ORDER
+1> Ambi3DDecoderHFScale
{{
27 1.00000000e+00f
, 1.00000000e+00f
29 constexpr std::array
<float,MAX_AMBI_ORDER
+1> Ambi3DDecoderHFScale2O
{{
30 7.45355990e-01f
, 1.00000000e+00f
, 1.00000000e+00f
32 constexpr std::array
<float,MAX_AMBI_ORDER
+1> Ambi3DDecoderHFScale3O
{{
33 5.89792205e-01f
, 8.79693856e-01f
, 1.00000000e+00f
, 1.00000000e+00f
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
;
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
);
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
;
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
;
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
}
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
];
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);
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(),
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);
155 for(auto &chandec
: mChannelDec
)
157 MixSamples({InSamples
->data(), SamplesToDo
}, OutBuffer
, chandec
.mGains
.Single
,
158 chandec
.mGains
.Single
, 0, 0);
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
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
)
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());
206 auto delay_start
= std::swap_ranges(OutBuffer
[i
].begin(), buffer_end
,
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
];
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
)}};