Skip to content

Commit 965bbd8

Browse files
committed
feat(zlp::controller): add main process function
1 parent c77cd63 commit 965bbd8

2 files changed

Lines changed: 111 additions & 24 deletions

File tree

source/zlp/controller.cpp

Lines changed: 100 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ namespace zlp {
1313
namespace {
1414
template <size_t Mask>
1515
void dispatchMask(Controller* instance) {
16-
instance->processImpl<
16+
instance->processMainImpl<
1717
(Mask & 1) != 0,
1818
(Mask & 2) != 0,
1919
(Mask & 4) != 0,
@@ -24,7 +24,7 @@ namespace zlp {
2424

2525
template <size_t... Is>
2626
constexpr std::array<void (*)(Controller*), sizeof...(Is)> makeDispatchTable(std::index_sequence<Is...>) {
27-
return { &dispatchMask<Is>... };
27+
return {&dispatchMask<Is>...};
2828
}
2929

3030
constexpr auto dispatcher = makeDispatchTable(std::make_index_sequence<32>{});
@@ -38,21 +38,106 @@ namespace zlp {
3838

3939
}
4040

41-
void Controller::process(const bool is_bypass) {
42-
processSide();
43-
processDynamicBands(stereo_data_);
44-
processDynamicBands(l_data_);
45-
processDynamicBands(r_data_);
46-
processDynamicBands(m_data_);
47-
processDynamicBands(s_data_);
48-
processMain(is_bypass);
41+
void Controller::process(const std::array<float*, 4>& buffer, const size_t num_samples, const bool is_bypass) {
42+
size_t samples_processed = 0;
43+
const bool requires_side = (side_status_ != SideStatus::kNotRequired);
44+
45+
while (samples_processed < num_samples) {
46+
// copy data to FIFO until reach a hop size or buffer size
47+
const size_t chunk = std::min(num_samples - samples_processed, fft_hop_size_ - fft_count_);
48+
const size_t chunk1 = std::min(chunk, fft_size_ - fft_pos_);
49+
const size_t chunk2 = chunk - chunk1;
50+
for (size_t chan = 0; chan < 2; ++chan) {
51+
std::copy_n(buffer[chan] + samples_processed, chunk1,
52+
input_fifos_[chan].data() + fft_pos_);
53+
if (chunk2 > 0) {
54+
std::copy_n(buffer[chan] + samples_processed + chunk1, chunk2,
55+
input_fifos_[chan].data());
56+
}
57+
std::copy_n(output_fifos_[chan].data() + fft_pos_, chunk1,
58+
buffer[chan] + samples_processed);
59+
if (chunk2 > 0) {
60+
std::copy_n(output_fifos_[chan].data(), chunk2,
61+
buffer[chan] + samples_processed + chunk1);
62+
}
63+
std::fill_n(output_fifos_[chan].data() + fft_pos_, chunk1, 0.0f);
64+
if (chunk2 > 0) {
65+
std::fill_n(output_fifos_[chan].data(), chunk2, 0.0f);
66+
}
67+
}
68+
if (requires_side) {
69+
for (size_t chan = 2; chan < 4; ++chan) {
70+
std::copy_n(buffer[chan] + samples_processed, chunk1,
71+
input_fifos_[chan].data() + fft_pos_);
72+
if (chunk2 > 0) {
73+
std::copy_n(buffer[chan] + samples_processed + chunk1, chunk2,
74+
input_fifos_[chan].data());
75+
}
76+
}
77+
}
78+
// forward FFT pos
79+
fft_pos_ += chunk;
80+
if (fft_pos_ >= fft_size_) {
81+
fft_pos_ -= fft_size_;
82+
}
83+
fft_count_ += chunk;
84+
// if reach a hop size, process spectrum
85+
if (fft_count_ >= fft_hop_size_) {
86+
fft_count_ = 0;
87+
// copy to FFT working space
88+
for (size_t chan = 0; chan < 2; ++chan) {
89+
std::copy_n(input_fifos_[chan].data() + fft_pos_, fft_size_ - fft_pos_,
90+
fft_ins_[chan].data());
91+
if (fft_pos_ > 0) {
92+
std::copy_n(input_fifos_[chan].data(), fft_pos_,
93+
fft_ins_[chan].data() + fft_size_ - fft_pos_);
94+
}
95+
}
96+
if (requires_side) {
97+
for (size_t chan = 2; chan < 4; ++chan) {
98+
std::copy_n(input_fifos_[chan].data() + fft_pos_, fft_size_ - fft_pos_,
99+
fft_ins_[chan].data());
100+
if (fft_pos_ > 0) {
101+
std::copy_n(input_fifos_[chan].data(), fft_pos_,
102+
fft_ins_[chan].data() + fft_size_ - fft_pos_);
103+
}
104+
}
105+
processSide();
106+
processDynamicBands(stereo_data_);
107+
processDynamicBands(l_data_);
108+
processDynamicBands(r_data_);
109+
processDynamicBands(m_data_);
110+
processDynamicBands(s_data_);
111+
}
112+
processMain(is_bypass);
113+
// overlap-add
114+
const size_t range1 = fft_size_ - fft_pos_;
115+
for (size_t chan = 0; chan < 2; ++chan) {
116+
{
117+
auto* HWY_RESTRICT out_ptr = output_fifos_[chan].data() + fft_pos_;
118+
const auto* HWY_RESTRICT in_ptr = fft_ins_[chan].data();
119+
for (size_t k = 0; k < range1; k += lanes) {
120+
const auto v_out = hn::Load(d, out_ptr + k);
121+
const auto v_in = hn::Load(d, in_ptr + k);
122+
hn::Store(hn::Add(v_out, v_in), d, out_ptr + k);
123+
}
124+
}
125+
{
126+
auto* HWY_RESTRICT out_ptr = output_fifos_[chan].data();
127+
const auto* HWY_RESTRICT in_ptr = fft_ins_[chan].data() + range1;
128+
for (size_t k = 0; k < fft_pos_; k += lanes) {
129+
const auto v_out = hn::Load(d, out_ptr + k);
130+
const auto v_in = hn::Load(d, in_ptr + k);
131+
hn::Store(hn::Add(v_out, v_in), d, out_ptr + k);
132+
}
133+
}
134+
}
135+
}
136+
samples_processed += chunk;
137+
}
49138
}
50139

51140
void Controller::processSide() {
52-
if (side_status_ == SideStatus::kNotRequired) {
53-
return;
54-
}
55-
// side FFT FIFO in
56141
if (side_status_ == SideStatus::kLR) {
57142
processSideLR();
58143
} else if (side_status_ == SideStatus::kMS) {
@@ -63,13 +148,11 @@ namespace zlp {
63148
}
64149

65150
void Controller::processMain(const bool is_bypass) {
66-
// main FFT FIFO in
67151
if (is_bypass) {
68152
dispatcher[0](this);
69153
} else {
70154
dispatcher[dispatch_mask_](this);
71155
}
72-
// main FFT FIFO out
73156
}
74157

75158
void Controller::processSideLR() {
@@ -266,7 +349,7 @@ namespace zlp {
266349
}
267350

268351
template <bool has_stereo, bool has_l, bool has_r, bool has_m, bool has_s>
269-
void Controller::processImpl() {
352+
void Controller::processMainImpl() {
270353
if constexpr (!(has_stereo || has_l || has_r || has_m || has_s)) {
271354
zldsp::vector::multiply(fft_ins_[0].data(), window_bypass_.data(), fft_size_);
272355
zldsp::vector::multiply(fft_ins_[1].data(), window_bypass_.data(), fft_size_);

source/zlp/controller.hpp

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,10 @@ namespace zlp {
4444

4545
void prepare(double sample_rate, size_t max_num_samples);
4646

47-
void process(bool is_bypass);
47+
void process(const std::array<float*, 4>& buffer, size_t num_samples, bool is_bypass);
4848

4949
template <bool has_stereo, bool has_l, bool has_r, bool has_m, bool has_s>
50-
void processImpl();
50+
void processMainImpl();
5151

5252
private:
5353
static constexpr hn::ScalableTag<float> d;
@@ -72,9 +72,6 @@ namespace zlp {
7272
zldsp::vector::aligned_vector<float> dynamic_response;
7373
};
7474

75-
static constexpr float kSqrt2Over2 = static_cast<float>(
76-
0.7071067811865475244008443621048490392848359376884740365883398690);
77-
7875
juce::AudioProcessor& p_ref_;
7976

8077
std::array<zldsp::filter::Empty, kBandNum> emptys_{};
@@ -89,12 +86,19 @@ namespace zlp {
8986
= make_array_of<zldsp::filter::SpecDynamic<float>, kBandNum>();
9087
zldsp::filter::SpecSmoother<float> spec_smoother_;
9188
// fft working space
92-
std::unique_ptr<zldsp::fft::RFFT<float>> fft_;
93-
size_t fft_order_ = 12;
89+
std::unique_ptr<zldsp::fft::RFFT<float>> fft_low_;
90+
std::unique_ptr<zldsp::fft::RFFT<float>> fft_medium_;
91+
std::unique_ptr<zldsp::fft::RFFT<float>> fft_high_;
92+
std::unique_ptr<zldsp::fft::RFFT<float>> fft_extreme_;
93+
zldsp::fft::RFFT<float>* fft_{nullptr};
94+
size_t fft_order_ = 13;
9495
size_t fft_size_ = static_cast<size_t>(1) << fft_order_;
9596
size_t num_bin_ = fft_size_ / 2 + 1;
9697
size_t num_bin_effective_ = fft_size_ / 2;
9798
zldsp::vector::aligned_vector<float> window1_, window2_, window_bypass_;
99+
size_t fft_count_ = 0;
100+
size_t fft_pos_ = 0;
101+
size_t fft_hop_size_ = fft_size_ / 4;
98102

99103
std::array<zldsp::vector::aligned_vector<float>, 4> input_fifos_, output_fifos_;
100104
std::array<zldsp::vector::aligned_vector<float>, 4> fft_ins_;

0 commit comments

Comments
 (0)