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
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
)
97 mid
[i
] = OutBuffer
[lidx
][i
] + OutBuffer
[ridx
][i
];
98 side
[i
] = OutBuffer
[lidx
][i
] - OutBuffer
[ridx
][i
];
100 std::fill_n(OutBuffer
[lidx
].begin(), SamplesToDo
, 0.0f
);
101 std::fill_n(OutBuffer
[ridx
].begin(), SamplesToDo
, 0.0f
);
103 /* Decode the B-Format input to OutBuffer. */
104 process(OutBuffer
, InSamples
, SamplesToDo
);
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
];
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
; });
115 mStablizer
->MidFilter
.process({mStablizer
->Temp
.data(), SamplesToDo
}, mStablizer
->MidHF
.data(),
116 mStablizer
->MidLF
.data());
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.
122 const size_t NumChannels
{OutBuffer
.size()};
123 for(size_t i
{0u};i
< NumChannels
;i
++)
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.
129 mStablizer
->ChannelFilters
[i
].processAllPass({mid
, SamplesToDo
});
131 mStablizer
->ChannelFilters
[i
].processAllPass({side
, SamplesToDo
});
133 mStablizer
->ChannelFilters
[i
].processAllPass({OutBuffer
[i
].data(), SamplesToDo
});
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.
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
++)
147 /* Add the direct mid signal to the processed mid signal so it can be
148 * properly combined with the direct+decoded side signal.
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
]};
154 /* The generated center channel signal adds to the existing signal,
155 * while the modified left and right channels replace.
157 OutBuffer
[lidx
][i
] = (m
+ s
) * 0.5f
;
158 OutBuffer
[ridx
][i
] = (m
- s
) * 0.5f
;
159 OutBuffer
[cidx
][i
] += c
* 0.5f
;
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
)
168 return std::make_unique
<BFormatDec
>(inchans
, coeffs
, coeffslf
, xover_f0norm
,
169 std::move(stablizer
));