4 #include "bformatdec.h"
12 #include "alnumbers.h"
13 #include "bufferline.h"
14 #include "filters/splitter.h"
15 #include "flexarray.h"
16 #include "front_stablizer.h"
18 #include "opthelpers.h"
23 template<typename
... Ts
>
24 struct overloaded
: Ts
... { using Ts::operator()...; };
26 template<typename
... Ts
>
27 overloaded(Ts
...) -> overloaded
<Ts
...>;
31 BFormatDec::BFormatDec(const size_t inchans
, const al::span
<const ChannelDec
> coeffs
,
32 const al::span
<const ChannelDec
> coeffslf
, const float xover_f0norm
,
33 std::unique_ptr
<FrontStablizer
> stablizer
)
34 : mStablizer
{std::move(stablizer
)}
38 auto &decoder
= mChannelDec
.emplace
<std::vector
<ChannelDecoderSingle
>>(inchans
);
39 for(size_t j
{0};j
< decoder
.size();++j
)
41 std::transform(coeffs
.cbegin(), coeffs
.cend(), decoder
[j
].mGains
.begin(),
42 [j
](const ChannelDec
&incoeffs
) { return incoeffs
[j
]; });
47 auto &decoder
= mChannelDec
.emplace
<std::vector
<ChannelDecoderDual
>>(inchans
);
48 decoder
[0].mXOver
.init(xover_f0norm
);
49 for(size_t j
{1};j
< decoder
.size();++j
)
50 decoder
[j
].mXOver
= decoder
[0].mXOver
;
52 for(size_t j
{0};j
< decoder
.size();++j
)
54 std::transform(coeffs
.cbegin(), coeffs
.cend(), decoder
[j
].mGains
[sHFBand
].begin(),
55 [j
](const ChannelDec
&incoeffs
) { return incoeffs
[j
]; });
57 std::transform(coeffslf
.cbegin(), coeffslf
.cend(), decoder
[j
].mGains
[sLFBand
].begin(),
58 [j
](const ChannelDec
&incoeffs
) { return incoeffs
[j
]; });
64 void BFormatDec::process(const al::span
<FloatBufferLine
> OutBuffer
,
65 const al::span
<const FloatBufferLine
> InSamples
, const size_t SamplesToDo
)
67 ASSUME(SamplesToDo
> 0);
69 auto decode_dualband
= [=](std::vector
<ChannelDecoderDual
> &decoder
)
71 auto input
= InSamples
.cbegin();
72 const auto hfSamples
= al::span
<float>{mSamples
[sHFBand
]}.first(SamplesToDo
);
73 const auto lfSamples
= al::span
<float>{mSamples
[sLFBand
]}.first(SamplesToDo
);
74 for(auto &chandec
: decoder
)
76 chandec
.mXOver
.process(al::span
{*input
++}.first(SamplesToDo
), hfSamples
, lfSamples
);
77 MixSamples(hfSamples
, OutBuffer
, chandec
.mGains
[sHFBand
], chandec
.mGains
[sHFBand
],0,0);
78 MixSamples(lfSamples
, OutBuffer
, chandec
.mGains
[sLFBand
], chandec
.mGains
[sLFBand
],0,0);
81 auto decode_singleband
= [=](std::vector
<ChannelDecoderSingle
> &decoder
)
83 auto input
= InSamples
.cbegin();
84 for(auto &chandec
: decoder
)
86 MixSamples(al::span
{*input
++}.first(SamplesToDo
), OutBuffer
, chandec
.mGains
,
87 chandec
.mGains
, 0, 0);
91 std::visit(overloaded
{decode_dualband
, decode_singleband
}, mChannelDec
);
94 void BFormatDec::processStablize(const al::span
<FloatBufferLine
> OutBuffer
,
95 const al::span
<const FloatBufferLine
> InSamples
, const size_t lidx
, const size_t ridx
,
96 const size_t cidx
, const size_t SamplesToDo
)
98 ASSUME(SamplesToDo
> 0);
100 /* Move the existing direct L/R signal out so it doesn't get processed by
103 const auto leftout
= al::span
<float>{OutBuffer
[lidx
]}.first(SamplesToDo
);
104 const auto rightout
= al::span
<float>{OutBuffer
[ridx
]}.first(SamplesToDo
);
105 const auto mid
= al::span
{mStablizer
->MidDirect
}.first(SamplesToDo
);
106 const auto side
= al::span
{mStablizer
->Side
}.first(SamplesToDo
);
107 std::transform(leftout
.cbegin(), leftout
.cend(), rightout
.cbegin(), mid
.begin(),std::plus
{});
108 std::transform(leftout
.cbegin(), leftout
.cend(), rightout
.cbegin(), side
.begin(),std::minus
{});
109 std::fill_n(leftout
.begin(), leftout
.size(), 0.0f
);
110 std::fill_n(rightout
.begin(), rightout
.size(), 0.0f
);
112 /* Decode the B-Format input to OutBuffer. */
113 process(OutBuffer
, InSamples
, SamplesToDo
);
115 /* Include the decoded side signal with the direct side signal. */
116 for(size_t i
{0};i
< SamplesToDo
;++i
)
117 side
[i
] += leftout
[i
] - rightout
[i
];
119 /* Get the decoded mid signal and band-split it. */
120 const auto tmpsamples
= al::span
{mStablizer
->Temp
}.first(SamplesToDo
);
121 std::transform(leftout
.cbegin(), leftout
.cend(), rightout
.cbegin(), tmpsamples
.begin(),
124 mStablizer
->MidFilter
.process(tmpsamples
, mStablizer
->MidHF
, mStablizer
->MidLF
);
126 /* Apply an all-pass to all channels to match the band-splitter's phase
127 * shift. This is to keep the phase synchronized between the existing
128 * signal and the split mid signal.
130 const size_t NumChannels
{OutBuffer
.size()};
131 for(size_t i
{0u};i
< NumChannels
;i
++)
133 /* Skip the left and right channels, which are going to get overwritten,
134 * and substitute the direct mid signal and direct+decoded side signal.
137 mStablizer
->ChannelFilters
[i
].processAllPass(mid
);
139 mStablizer
->ChannelFilters
[i
].processAllPass(side
);
141 mStablizer
->ChannelFilters
[i
].processAllPass({OutBuffer
[i
].data(), SamplesToDo
});
144 /* This pans the separate low- and high-frequency signals between being on
145 * the center channel and the left+right channels. The low-frequency signal
146 * is panned 1/3rd toward center and the high-frequency signal is panned
147 * 1/4th toward center. These values can be tweaked.
149 const float cos_lf
{std::cos(1.0f
/3.0f
* (al::numbers::pi_v
<float>*0.5f
))};
150 const float cos_hf
{std::cos(1.0f
/4.0f
* (al::numbers::pi_v
<float>*0.5f
))};
151 const float sin_lf
{std::sin(1.0f
/3.0f
* (al::numbers::pi_v
<float>*0.5f
))};
152 const float sin_hf
{std::sin(1.0f
/4.0f
* (al::numbers::pi_v
<float>*0.5f
))};
153 const auto centerout
= al::span
<float>{OutBuffer
[cidx
]}.first(SamplesToDo
);
154 for(size_t i
{0};i
< SamplesToDo
;i
++)
156 /* Add the direct mid signal to the processed mid signal so it can be
157 * properly combined with the direct+decoded side signal.
159 const float m
{mStablizer
->MidLF
[i
]*cos_lf
+ mStablizer
->MidHF
[i
]*cos_hf
+ mid
[i
]};
160 const float c
{mStablizer
->MidLF
[i
]*sin_lf
+ mStablizer
->MidHF
[i
]*sin_hf
};
161 const float s
{side
[i
]};
163 /* The generated center channel signal adds to the existing signal,
164 * while the modified left and right channels replace.
166 leftout
[i
] = (m
+ s
) * 0.5f
;
167 rightout
[i
] = (m
- s
) * 0.5f
;
168 centerout
[i
] += c
* 0.5f
;
173 std::unique_ptr
<BFormatDec
> BFormatDec::Create(const size_t inchans
,
174 const al::span
<const ChannelDec
> coeffs
, const al::span
<const ChannelDec
> coeffslf
,
175 const float xover_f0norm
, std::unique_ptr
<FrontStablizer
> stablizer
)
177 return std::make_unique
<BFormatDec
>(inchans
, coeffs
, coeffslf
, xover_f0norm
,
178 std::move(stablizer
));