36template <
typename SampleType =
float>
42 std::uint64_t& bytes)
noexcept {
43 const auto bins =
static_cast<std::uint64_t
>(fft_size / 2 + 1);
45 if (!charge.
add<
double>(bins) || !charge.
add<
double>(bins)
46 || !charge.
add<SampleType>(bins) || !charge.
add<
double>(bins)
47 || !charge.
add<
int>(bins))
49 bytes = charge.
total();
53 void prepare(
int fft_size,
int channels) {
54 assert(fft_size >= 256 && (fft_size & (fft_size - 1)) == 0);
55 assert(channels >= 1);
58 num_bins_ = fft_size / 2 + 1;
59 prev_phase_.assign(
static_cast<size_t>(num_bins_), 0.0);
60 synth_phase_.assign(
static_cast<size_t>(num_bins_), 0.0);
61 ref_mag_.assign(
static_cast<size_t>(num_bins_), SampleType{0});
62 ref_phase_.assign(
static_cast<size_t>(num_bins_), 0.0);
63 peaks_.assign(
static_cast<size_t>(num_bins_), 0);
68 std::fill(prev_phase_.begin(), prev_phase_.end(), 0.0);
69 std::fill(synth_phase_.begin(), synth_phase_.end(), 0.0);
85 int analysis_hop,
int synthesis_hop, SampleType reset_amount = SampleType{0}) {
87 assert(analysis_hop > 0 && synthesis_hop > 0);
90 for (
int k = 0; k < num_bins_; ++k) {
91 std::complex<SampleType> sum(SampleType{0}, SampleType{0});
92 for (
int ch = 0; ch < channels_; ++ch) sum += frames[ch][k];
93 ref_mag_[
static_cast<size_t>(k)] = std::abs(sum);
94 ref_phase_[
static_cast<size_t>(k)] =
static_cast<double>(std::arg(sum));
97 if (first_frame_ || reset_amount >= SampleType{1}) {
98 std::copy(ref_phase_.begin(), ref_phase_.end(), synth_phase_.begin());
99 std::copy(ref_phase_.begin(), ref_phase_.end(), prev_phase_.begin());
100 first_frame_ =
false;
107 for (
int k = 2;
k <= num_bins_ - 3; ++
k) {
108 const SampleType
m = ref_mag_[
static_cast<size_t>(
k)];
109 if (m > ref_mag_[
static_cast<size_t>(k - 1)] && m > ref_mag_[
static_cast<size_t>(k - 2)]
110 && m > ref_mag_[
static_cast<size_t>(k + 1)] && m > ref_mag_[
static_cast<size_t>(k + 2)])
111 peaks_[
static_cast<size_t>(num_peaks_++)] = k;
113 if (num_peaks_ == 0) peaks_[num_peaks_++] = 1;
117 const double ha =
static_cast<double>(analysis_hop);
118 const double hs =
static_cast<double>(synthesis_hop);
119 for (
int i = 0;
i < num_peaks_; ++
i) {
120 const int p = peaks_[
static_cast<size_t>(
i)];
121 const double omega = two_pi_ *
p / fft_size_;
122 const double delta = princarg(ref_phase_[
static_cast<size_t>(p)]
123 - prev_phase_[
static_cast<size_t>(p)] - omega * ha);
124 const double inst = omega + delta / ha;
125 synth_phase_[
static_cast<size_t>(
p)] += inst * hs;
132 for (
int k = 0;
k < num_bins_; ++
k) {
133 while (pi_idx + 1 < num_peaks_
134 && std::abs(peaks_[
static_cast<size_t>(pi_idx + 1)] - k)
135 < std::abs(peaks_[
static_cast<size_t>(pi_idx)] - k))
137 const int p = peaks_[
static_cast<size_t>(pi_idx)];
139 synth_phase_[
static_cast<size_t>(
k)] =
140 synth_phase_[
static_cast<size_t>(p)]
141 + (ref_phase_[
static_cast<size_t>(
k)] - ref_phase_[
static_cast<size_t>(
p)]);
145 double rotation = princarg(synth_phase_[
static_cast<size_t>(k)]
146 - ref_phase_[
static_cast<size_t>(k)]);
147 if (reset_amount > SampleType{0})
148 rotation *= 1.0 -
static_cast<double>(reset_amount);
149 synth_phase_[
static_cast<size_t>(
k)] =
150 ref_phase_[
static_cast<size_t>(k)] + rotation;
152 const SampleType rot =
static_cast<SampleType
>(rotation);
153 if (rot != SampleType{0}) {
154 const std::complex<SampleType>
r(std::cos(rot), std::sin(rot));
155 for (
int ch = 0; ch < channels_; ++ch)
160 std::copy(ref_phase_.begin(), ref_phase_.end(), prev_phase_.begin());
164 static double princarg(
double p) {
165 return p - two_pi_ * std::round(p / two_pi_);
168 static constexpr double two_pi_ = 6.28318530717958647692;
173 bool first_frame_ =
true;
175 std::vector<double> prev_phase_;
176 std::vector<double> synth_phase_;
177 std::vector<SampleType> ref_mag_;
178 std::vector<double> ref_phase_;
179 std::vector<int> peaks_;
Definition checked_allocation.hpp:57
bool add(std::uint64_t elements) noexcept
Definition checked_allocation.hpp:63
std::uint64_t total() const noexcept
Definition checked_allocation.hpp:83
RT contract: prepare() allocates internal phase/magnitude storage and must run off the audio thread.
Definition multichannel_phase_coordinator.hpp:37
static bool checked_retained_bytes(int fft_size, std::uint64_t target_max_bytes, std::uint64_t &bytes) noexcept
Definition multichannel_phase_coordinator.hpp:41
int num_bins() const
Definition multichannel_phase_coordinator.hpp:76
void process_group(std::complex< SampleType > *const *frames, int num_bins, int analysis_hop, int synthesis_hop, SampleType reset_amount=SampleType{0})
Propagate phases for one frame group and rotate every channel's bins in place.
Definition multichannel_phase_coordinator.hpp:84
const SampleType * reference_magnitudes() const
Sum of reference magnitudes from the last processed frame — cheap energy proxy callers (transient det...
Definition multichannel_phase_coordinator.hpp:75
void reset()
Definition multichannel_phase_coordinator.hpp:67
void prepare(int fft_size, int channels)
Definition multichannel_phase_coordinator.hpp:53
MultichannelPhaseCoordinatorT()=default
Definition additive_bank.hpp:218
MultichannelPhaseCoordinatorT< double > MultichannelPhaseCoordinator64
Definition multichannel_phase_coordinator.hpp:184
MultichannelPhaseCoordinatorT< float > MultichannelPhaseCoordinator
Definition multichannel_phase_coordinator.hpp:183
@ i
Definition formant_filter_bank.hpp:20
@ r
Definition input_events.hpp:41
@ m
Definition input_events.hpp:40
@ p
Definition input_events.hpp:40
@ k
Definition input_events.hpp:40