Skip to content

Commit 33d7a89

Browse files
committed
feat: add dynamic band processing
1 parent 1be2ab3 commit 33d7a89

4 files changed

Lines changed: 87 additions & 33 deletions

File tree

source/dsp/filter/spec_dynamic/spec_dynamic.hpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ namespace zldsp::filter {
2424
states_.resize(fft_size);
2525
}
2626

27+
template <bool to_add = true>
2728
void process(FloatType* HWY_RESTRICT side_log_sqr,
2829
FloatType* HWY_RESTRICT dynamic_db,
2930
SpecResponse<FloatType>& response,
@@ -40,7 +41,7 @@ namespace zldsp::filter {
4041
const auto v_zero = hn::Set(d, static_cast<FloatType>(0));
4142
const auto v_one = hn::Set(d, static_cast<FloatType>(1));
4243
const auto i_start = response.getStartIdx();
43-
const auto i_stop = i_start + response.getDiffSize();
44+
const auto i_stop = response.getEndIdx();
4445
for (size_t i = i_start; i < i_stop; i+= lanes) {
4546
// threshold & knee
4647
const auto v_side = hn::Load(d, side_log_sqr + i);
@@ -57,8 +58,13 @@ namespace zldsp::filter {
5758
hn::Store(v_state, d, states + (i << 1));
5859
hn::Store(v_y, d, states + (i << 1) + lanes);
5960
// calculate diff
60-
const auto v_diff = hn::Load(d, diffs + i);
61-
hn::Store(hn::Mul(v_diff, v_y), d, dynamic_db + i);
61+
const auto v_diff = hn::Mul(hn::Load(d, diffs + i), v_y);
62+
if constexpr (to_add) {
63+
const auto v_dyn = hn::Load(d, dynamic_db + i);
64+
hn::Store(hn::Add(v_diff, v_dyn), d, dynamic_db + i);
65+
} else {
66+
hn::Store(v_diff, d, dynamic_db + i);
67+
}
6268
}
6369
}
6470

source/dsp/filter/spec_dynamic/spec_response.hpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,14 +94,18 @@ namespace zldsp::filter {
9494
return start_idx_;
9595
}
9696

97+
[[nodiscard]] auto getEndIdx() const {
98+
return end_idx_;
99+
}
100+
97101
[[nodiscard]] auto getDiffSize() const {
98102
return diff_size_;
99103
}
100104

101105
private:
102106
vector::aligned_vector<FloatType> base_response_;
103107
vector::aligned_vector<FloatType> diff_response_;
104-
size_t start_idx_{0}, diff_size_{0};
108+
size_t start_idx_{0}, end_idx_{0}, diff_size_{0};
105109

106110
static constexpr auto kLogSqrMin = static_cast<FloatType>(1e-24);
107111
static constexpr auto kDiffMin = static_cast<FloatType>(1e-2);

source/zlp/controller.cpp

Lines changed: 65 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ namespace zlp {
3030
auto* HWY_RESTRICT r_real_ptr = fft_out_reals_[1].data();
3131
auto* HWY_RESTRICT r_imag_ptr = fft_out_imags_[1].data();
3232

33-
const auto* HWY_RESTRICT mag_ptr = l_data_.static_response_linear.data();
33+
const auto* HWY_RESTRICT mag_ptr = l_data_.static_response.data();
3434

3535
for (size_t i = 0; i < num_bin_effective_; i += lanes) {
3636
const auto v_mag = hn::Load(d, mag_ptr + i);
@@ -61,7 +61,7 @@ namespace zlp {
6161
fft_->forward(fft_ins_[0].data(), {fft_out_reals_[0].data(), fft_out_imags_[0].data()});
6262
auto* HWY_RESTRICT l_real_ptr = fft_out_reals_[0].data();
6363
auto* HWY_RESTRICT l_imag_ptr = fft_out_imags_[0].data();
64-
const auto* HWY_RESTRICT l_mag_ptr = l_data_.static_response_linear.data();
64+
const auto* HWY_RESTRICT l_mag_ptr = l_data_.static_response.data();
6565
for (size_t i = 0; i < num_bin_effective_; i += lanes) {
6666
const auto vl_mag = hn::Load(d, l_mag_ptr + i);
6767
const auto vl_real = hn::Load(d, l_real_ptr + i);
@@ -79,7 +79,7 @@ namespace zlp {
7979
fft_->forward(fft_ins_[1].data(), {fft_out_reals_[1].data(), fft_out_imags_[1].data()});
8080
auto* HWY_RESTRICT r_real_ptr = fft_out_reals_[1].data();
8181
auto* HWY_RESTRICT r_imag_ptr = fft_out_imags_[1].data();
82-
const auto* HWY_RESTRICT r_mag_ptr = r_data_.static_response_linear.data();
82+
const auto* HWY_RESTRICT r_mag_ptr = r_data_.static_response.data();
8383
for (size_t i = 0; i < num_bin_effective_; i += lanes) {
8484
const auto vr_mag = hn::Load(d, r_mag_ptr + i);
8585
const auto vr_real = hn::Load(d, r_real_ptr + i);
@@ -101,7 +101,7 @@ namespace zlp {
101101
fft_->forward(fft_ins_[0].data(), {fft_out_reals_[0].data(), fft_out_imags_[0].data()});
102102
auto* HWY_RESTRICT m_real_ptr = fft_out_reals_[0].data();
103103
auto* HWY_RESTRICT m_imag_ptr = fft_out_imags_[0].data();
104-
const auto* HWY_RESTRICT m_mag_ptr = m_data_.static_response_linear.data();
104+
const auto* HWY_RESTRICT m_mag_ptr = m_data_.static_response.data();
105105
for (size_t i = 0; i < num_bin_effective_; i += lanes) {
106106
const auto vl_mag = hn::Load(d, m_mag_ptr + i);
107107
const auto vl_real = hn::Load(d, m_real_ptr + i);
@@ -119,7 +119,7 @@ namespace zlp {
119119
fft_->forward(fft_ins_[1].data(), {fft_out_reals_[1].data(), fft_out_imags_[1].data()});
120120
auto* HWY_RESTRICT s_real_ptr = fft_out_reals_[1].data();
121121
auto* HWY_RESTRICT s_imag_ptr = fft_out_imags_[1].data();
122-
const auto* HWY_RESTRICT s_mag_ptr = s_data_.static_response_linear.data();
122+
const auto* HWY_RESTRICT s_mag_ptr = s_data_.static_response.data();
123123
for (size_t i = 0; i < num_bin_effective_; i += lanes) {
124124
const auto vr_mag = hn::Load(d, s_mag_ptr + i);
125125
const auto vr_real = hn::Load(d, s_real_ptr + i);
@@ -147,10 +147,10 @@ namespace zlp {
147147
auto* HWY_RESTRICT r_real_ptr = fft_out_reals_[1].data();
148148
auto* HWY_RESTRICT r_imag_ptr = fft_out_imags_[1].data();
149149

150-
const auto* HWY_RESTRICT l_mag_ptr = l_data_.static_response_linear.data();
151-
const auto* HWY_RESTRICT r_mag_ptr = r_data_.static_response_linear.data();
152-
const auto* HWY_RESTRICT m_mag_ptr = m_data_.static_response_linear.data();
153-
const auto* HWY_RESTRICT s_mag_ptr = s_data_.static_response_linear.data();
150+
const auto* HWY_RESTRICT l_mag_ptr = l_data_.static_response.data();
151+
const auto* HWY_RESTRICT r_mag_ptr = r_data_.static_response.data();
152+
const auto* HWY_RESTRICT m_mag_ptr = m_data_.static_response.data();
153+
const auto* HWY_RESTRICT s_mag_ptr = s_data_.static_response.data();
154154

155155
const auto v_half = hn::Set(d, 0.5f);
156156

@@ -207,9 +207,9 @@ namespace zlp {
207207
auto* HWY_RESTRICT stereo_abs_sqr = stereo_data_.fft_side_abs_sqr_.data();
208208
const auto* HWY_RESTRICT l_abs_sqr = l_data_.fft_side_abs_sqr_.data();
209209
const auto* HWY_RESTRICT r_abs_sqr = r_data_.fft_side_abs_sqr_.data();
210-
for (size_t i = stereo_data_.smooth_bounds.pass1_start;
211-
i < stereo_data_.smooth_bounds.pass1_end;
212-
i += lanes) {
210+
const auto start_idx = stereo_data_.smooth_bounds.pass1_start;
211+
const auto end_idx = stereo_data_.smooth_bounds.pass1_end;
212+
for (size_t i = start_idx; i < end_idx; i += lanes) {
213213
const auto l_v = hn::Load(d, l_abs_sqr + i);
214214
const auto r_v = hn::Load(d, r_abs_sqr + i);
215215
hn::Store(hn::Add(l_v, r_v), d, stereo_abs_sqr + i);
@@ -238,9 +238,9 @@ namespace zlp {
238238
auto* HWY_RESTRICT stereo_abs_sqr = stereo_data_.fft_side_abs_sqr_.data();
239239
const auto* HWY_RESTRICT m_abs_sqr = m_data_.fft_side_abs_sqr_.data();
240240
const auto* HWY_RESTRICT s_abs_sqr = s_data_.fft_side_abs_sqr_.data();
241-
for (size_t i = stereo_data_.smooth_bounds.pass1_start;
242-
i < stereo_data_.smooth_bounds.pass1_end;
243-
i += lanes) {
241+
const auto start_idx = stereo_data_.smooth_bounds.pass1_start;
242+
const auto end_idx = stereo_data_.smooth_bounds.pass1_end;
243+
for (size_t i = start_idx; i < end_idx; i += lanes) {
244244
const auto m_v = hn::Load(d, m_abs_sqr + i);
245245
const auto s_v = hn::Load(d, s_abs_sqr + i);
246246
hn::Store(hn::Add(m_v, s_v), d, stereo_abs_sqr + i);
@@ -268,9 +268,9 @@ namespace zlp {
268268

269269
if (l_data_.is_side_required_) {
270270
auto* HWY_RESTRICT l_abs_sqr = l_data_.fft_side_abs_sqr_.data();
271-
for (size_t i = l_data_.smooth_bounds.pass1_start;
272-
i < l_data_.smooth_bounds.pass1_end;
273-
i += lanes) {
271+
const auto start_idx = l_data_.smooth_bounds.pass1_start;
272+
const auto end_idx = l_data_.smooth_bounds.pass1_end;
273+
for (size_t i = start_idx; i < end_idx; i += lanes) {
274274
const auto real_v = hn::Load(d, l_real_ptr + i);
275275
const auto imag_v = hn::Load(d, l_imag_ptr + i);
276276

@@ -281,7 +281,9 @@ namespace zlp {
281281
}
282282
if (r_data_.is_side_required_) {
283283
auto* HWY_RESTRICT r_abs_sqr = r_data_.fft_side_abs_sqr_.data();
284-
for (size_t i = r_data_.smooth_bounds.pass1_start; i < r_data_.smooth_bounds.pass1_end; i += lanes) {
284+
const auto start_idx = r_data_.smooth_bounds.pass1_start;
285+
const auto end_idx = r_data_.smooth_bounds.pass1_end;
286+
for (size_t i = start_idx; i < end_idx; i += lanes) {
285287
const auto real_v = hn::Load(d, r_real_ptr + i);
286288
const auto imag_v = hn::Load(d, r_imag_ptr + i);
287289

@@ -292,8 +294,9 @@ namespace zlp {
292294
}
293295
if (stereo_data_.is_side_required_) {
294296
auto* HWY_RESTRICT st_abs_sqr = stereo_data_.fft_side_abs_sqr_.data();
295-
for (size_t i = stereo_data_.smooth_bounds.pass1_start; i < stereo_data_.smooth_bounds.pass1_end; i +=
296-
lanes) {
297+
const auto start_idx = stereo_data_.smooth_bounds.pass1_start;
298+
const auto end_idx = stereo_data_.smooth_bounds.pass1_end;
299+
for (size_t i = start_idx; i < end_idx; i += lanes) {
297300
const auto l_real_v = hn::Load(d, l_real_ptr + i);
298301
const auto l_imag_v = hn::Load(d, l_imag_ptr + i);
299302
const auto l_abs_sqr_v = hn::MulAdd(l_real_v, l_real_v, hn::Mul(l_imag_v, l_imag_v));
@@ -307,12 +310,12 @@ namespace zlp {
307310
}
308311
spec_smoother_.smoothRange(stereo_data_.fft_side_abs_sqr_, stereo_data_.smooth_bounds);
309312
}
310-
311313
if (m_data_.is_side_required_) {
312314
auto* HWY_RESTRICT m_abs_sqr = m_data_.fft_side_abs_sqr_.data();
313315
const auto quarter_v = hn::Set(d, 0.25f);
314-
315-
for (size_t i = m_data_.smooth_bounds.pass1_start; i < m_data_.smooth_bounds.pass1_end; i += lanes) {
316+
const auto start_idx = m_data_.smooth_bounds.pass1_start;
317+
const auto end_idx = m_data_.smooth_bounds.pass1_end;
318+
for (size_t i = start_idx; i < end_idx; i += lanes) {
316319
const auto l_real_v = hn::Load(d, l_real_ptr + i);
317320
const auto r_real_v = hn::Load(d, r_real_ptr + i);
318321
const auto m_real_v = hn::Add(l_real_v, r_real_v);
@@ -326,12 +329,12 @@ namespace zlp {
326329
}
327330
spec_smoother_.smoothRange(m_data_.fft_side_abs_sqr_, m_data_.smooth_bounds);
328331
}
329-
330332
if (s_data_.is_side_required_) {
331333
auto* HWY_RESTRICT s_abs_sqr = s_data_.fft_side_abs_sqr_.data();
332334
const auto quarter_v = hn::Set(d, 0.25f);
333-
334-
for (size_t i = s_data_.smooth_bounds.pass1_start; i < s_data_.smooth_bounds.pass1_end; i += lanes) {
335+
const auto start_idx = s_data_.smooth_bounds.pass1_start;
336+
const auto end_idx = s_data_.smooth_bounds.pass1_end;
337+
for (size_t i = start_idx; i < end_idx; i += lanes) {
335338
const auto l_real_v = hn::Load(d, l_real_ptr + i);
336339
const auto r_real_v = hn::Load(d, r_real_ptr + i);
337340
const auto s_real_v = hn::Sub(l_real_v, r_real_v);
@@ -346,4 +349,39 @@ namespace zlp {
346349
spec_smoother_.smoothRange(s_data_.fft_side_abs_sqr_, s_data_.smooth_bounds);
347350
}
348351
}
352+
353+
void Controller::processDynamicBands(ChannelData& data) {
354+
if (data.dyn_bands_.empty()) {
355+
return;
356+
}
357+
const auto start_idx = data.smooth_bounds.target_start;
358+
const auto end_idx = data.smooth_bounds.target_end;
359+
auto* HWY_RESTRICT side_ptr = data.fft_side_abs_sqr_.data();
360+
auto* HWY_RESTRICT dyn_ptr = data.dynamic_response.data();
361+
// convert side from abs sqr to log
362+
{
363+
const auto v_min = hn::Set(d, 1e-24f);
364+
for (size_t i = start_idx; i < end_idx; i += lanes) {
365+
const auto v = hn::Load(d, side_ptr + i);
366+
hn::Store(hn::Log(d, hn::Max(v, v_min)), d, side_ptr + i);
367+
}
368+
}
369+
// process each dynamic band
370+
{
371+
const auto band = data.dyn_bands_[0];
372+
spec_dynamic_[band].template process<false>(side_ptr, dyn_ptr,
373+
spec_response_[band], spec_follower_[band]);
374+
std::fill(dyn_ptr + spec_response_[band].getEndIdx(), dyn_ptr + end_idx, 0.f);
375+
}
376+
for (size_t i = 1; i < data.dyn_bands_.size(); ++i) {
377+
const auto band = data.dyn_bands_[i];
378+
spec_dynamic_[band].template process<true>(side_ptr, dyn_ptr,
379+
spec_response_[band], spec_follower_[band]);
380+
}
381+
// convert dynamic response from db to linear
382+
for (size_t i = start_idx; i < end_idx; i += lanes) {
383+
const auto v = hn::Load(d, dyn_ptr + i);
384+
hn::Store(hn::Exp(d, v), d, dyn_ptr + i);
385+
}
386+
}
349387
}

source/zlp/controller.hpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,13 @@ namespace zlp {
6262
struct ChannelData {
6363
bool is_side_required_{false};
6464
bool is_static_active_{false};
65-
zldsp::vector::aligned_vector<float> static_response_linear;
65+
zldsp::vector::aligned_vector<float> static_response;
6666

6767
zldsp::vector::aligned_vector<float> fft_side_abs_sqr_;
6868
zldsp::filter::SpecSmoother<float>::SmoothBounds smooth_bounds;
69+
70+
std::vector<size_t> dyn_bands_{};
71+
zldsp::vector::aligned_vector<float> dynamic_response;
6972
};
7073

7174
static constexpr float kSqrt2Over2 = static_cast<float>(
@@ -98,7 +101,8 @@ namespace zlp {
98101

99102
ChannelData stereo_data_, l_data_, r_data_, m_data_, s_data_;
100103

101-
void handleAsyncUpdate() override {}
104+
void handleAsyncUpdate() override {
105+
}
102106

103107
void processStereoStatic();
104108

@@ -113,5 +117,7 @@ namespace zlp {
113117
void processSideMS();
114118

115119
void processSideLRMS();
120+
121+
void processDynamicBands(ChannelData& data);
116122
};
117123
}

0 commit comments

Comments
 (0)