177template <
typename SampleType =
float>
207 && ch >= 1 && ch <= kMaxChannels && hop > 0 && hop <= fft / 2;
214 const auto bins =
static_cast<std::size_t
>(fft / 2 + 1);
215 const auto channel_bins =
static_cast<std::size_t
>(ch) * bins;
217 + channel_bins *
sizeof(
double) + bins *
sizeof(double);
223 const auto bins =
static_cast<std::size_t
>(fft / 2 + 1);
234 magnitudes.assign(
static_cast<std::size_t
>(ch) * bins, SampleType{0});
235 phases.assign(
static_cast<std::size_t
>(ch) * bins, 0.0);
250 const auto bins =
static_cast<std::size_t
>(
fft_size / 2 + 1);
251 const auto channel_bins =
static_cast<std::size_t
>(
channels) * bins;
255 constexpr double kPhaseBound = 3.14159265358979323846 + 1
e-6;
257 if (!std::isfinite(m) || m < SampleType{0})
return false;
258 for (
const auto p :
phases)
259 if (!std::isfinite(p) || std::abs(p) > kPhaseBound)
return false;
261 if (!std::isfinite(f) || std::abs(f) > 2.0 * kPhaseBound)
return false;
269 if (!
valid())
return false;
271 const std::uint8_t magic[4] = {
'P',
'F',
'H',
'S'};
272 out.insert(out.end(), magic, magic + 4);
274 put_u32_(out,
static_cast<std::uint32_t
>(
fft_size));
275 put_u32_(out,
static_cast<std::uint32_t
>(
channels));
276 put_u32_(out,
static_cast<std::uint32_t
>(
analysis_hop));
279 put_u32_(out,
static_cast<std::uint32_t
>(
fade_step));
285 const auto f =
static_cast<float>(m);
286 std::uint32_t bits = 0;
287 std::memcpy(&bits, &f,
sizeof(bits));
290 for (
const auto p :
phases) put_f64_(out, p);
291 for (
const auto f :
inst_freq) put_f64_(out, f);
299 static bool read_bytes(
const std::uint8_t* data, std::size_t size,
302 || std::memcmp(data,
"PFHS", 4) != 0)
306 const auto fft = get_u32_(data, at);
307 const auto ch = get_u32_(data, at);
308 const auto hop = get_u32_(data, at);
309 const auto depth = get_u32_(data, at);
310 const auto crossfade = get_u32_(data, at);
311 const auto step = get_u32_(data, at);
312 const auto flags = get_u32_(data, at);
313 const auto reserved = get_u32_(data, at);
314 constexpr std::uint32_t kIntBound = 0x7fffffffu;
317 || hop >
static_cast<std::uint32_t
>(
kMaxFftSize) || depth > kIntBound
318 ||
crossfade > kIntBound || step > kIntBound
322 if (!image.prepare(
static_cast<int>(fft),
static_cast<int>(ch),
323 static_cast<int>(hop))
326 image.capture_frames =
static_cast<int>(depth);
327 image.crossfade_frames =
static_cast<int>(
crossfade);
328 image.fade_step =
static_cast<int>(step);
331 image.sample_rate = get_f64_(data, at);
332 image.rng_state = get_u64_(data, at);
333 for (
auto& m : image.magnitudes) {
334 const std::uint32_t bits = get_u32_(data, at);
336 std::memcpy(&f, &bits,
sizeof(f));
337 m =
static_cast<SampleType
>(f);
339 for (
auto& p : image.phases) p = get_f64_(data, at);
340 for (
auto& f : image.inst_freq) f = get_f64_(data, at);
341 if (at != size || !image.valid())
return false;
342 out = std::move(image);
347 static void put_u32_(std::vector<std::uint8_t>& out, std::uint32_t v) {
348 for (
int i = 0;
i < 4; ++
i)
349 out.push_back(
static_cast<std::uint8_t
>((v >> (8 *
i)) & 0xffu));
351 static void put_u64_(std::vector<std::uint8_t>& out, std::uint64_t v) {
352 for (
int i = 0;
i < 8; ++
i)
353 out.push_back(
static_cast<std::uint8_t
>((v >> (8 *
i)) & 0xffu));
355 static void put_f64_(std::vector<std::uint8_t>& out,
double v) {
356 std::uint64_t bits = 0;
357 std::memcpy(&bits, &v,
sizeof(bits));
360 static std::uint32_t get_u32_(
const std::uint8_t* data, std::size_t& at) {
362 for (
int i = 0;
i < 4; ++
i)
363 v |=
static_cast<std::uint32_t
>(data[at +
static_cast<std::size_t
>(
i)]) << (8 *
i);
367 static std::uint64_t get_u64_(
const std::uint8_t* data, std::size_t& at) {
369 for (
int i = 0;
i < 8; ++
i)
370 v |=
static_cast<std::uint64_t
>(data[at +
static_cast<std::size_t
>(
i)]) << (8 *
i);
374 static double get_f64_(
const std::uint8_t* data, std::size_t& at) {
375 const std::uint64_t bits = get_u64_(data, at);
377 std::memcpy(&v, &bits,
sizeof(v));
401template <
typename SampleType =
float>
465 if (
config.sample_rate > 0.0 &&
config.analysis_hop > 0) {
468 out.phase_jitter =
static_cast<float>(
469 std::max(
config.phase_jitter_per_sqrt_second, 0.0)
470 * std::sqrt(
static_cast<double>(
config.analysis_hop) /
config.sample_rate));
473 out.capture_frames = std::max(out.capture_frames, 2);
474 out.crossfade_frames = std::max(out.crossfade_frames, 1);
475 out.max_capture_frames = std::max(out.max_capture_frames, out.capture_frames);
482 if (!(
config.sample_rate > 0.0) ||
config.analysis_hop <= 0 || !(seconds > 0.0))
484 const double frames =
485 seconds *
config.sample_rate /
static_cast<double>(
config.analysis_hop);
486 return static_cast<int>(std::lround(std::min(frames, 1.0e6)));
490 std::uint64_t target_max_bytes,
491 std::uint64_t& bytes)
noexcept {
493 const auto bins =
static_cast<std::uint64_t
>(
config.fft_size / 2 + 1);
494 const auto channels =
static_cast<std::uint64_t
>(
config.channels);
495 const auto depth =
static_cast<std::uint64_t
>(
config.max_capture_frames);
496 std::uint64_t channel_bins = 0;
497 std::uint64_t channel_capture_bins = 0;
500 channel_capture_bins))
505 if (!charge.
add<SampleType>(channel_capture_bins)
506 || !charge.
add<
double>(bins)
507 || !charge.
add<std::complex<SampleType>>(channel_bins)
508 || !charge.
add<SampleType>(channel_bins)
509 || !charge.
add<
double>(channel_bins) || !charge.
add<
double>(bins)
510 || !charge.
add<SampleType>(channel_bins)
511 || !charge.
add<
double>(channel_bins) || !charge.
add<
double>(bins))
516 std::uint64_t capture_bins = 0;
518 || !charge.
add<std::complex<SampleType>>(capture_bins)
519 || !charge.
add<std::complex<double>>(bins))
523 && !charge.
add<
double>(channel_bins))
526 && (!charge.
add<std::complex<double>>(channel_bins)
527 || !charge.
add<std::complex<double>>(bins)))
530 && (!charge.
add<
int>(bins) || !charge.
add<
double>(bins)
531 || !charge.
add<
double>(bins)))
533 bytes = charge.
total();
544 assert(
config.channels >= 1);
546 num_bins_ =
config.fft_size / 2 + 1;
548 const auto bins =
static_cast<size_t>(num_bins_);
549 const auto channels =
static_cast<size_t>(
config.channels);
550 const auto depth =
static_cast<size_t>(
config.max_capture_frames);
551 capture_mag_.assign(channels * depth * bins, SampleType{0});
552 latest_increment_.assign(bins, 0.0);
553 latest_increment_raw_.assign(bins, std::complex<double>{});
554 prev_frame_.assign(channels * bins, std::complex<SampleType>{});
555 held_mag_.assign(channels * bins, SampleType{0});
556 held_phase_.assign(channels * bins, 0.0);
557 inst_freq_.assign(bins, 0.0);
558 pending_mag_.assign(channels * bins, SampleType{0});
559 pending_phase_.assign(channels * bins, 0.0);
560 pending_inst_freq_.assign(bins, 0.0);
562 increment_ring_.assign(weighted ? depth * bins : 0, std::complex<SampleType>{});
563 increment_sum_.assign(weighted ? bins : 0, std::complex<double>{});
564 running_mag_sum_.assign(
567 phasor_.assign(
rotor ? channels * bins : 0, std::complex<double>(1.0, 0.0));
568 rotor_.assign(
rotor ? bins : 0, std::complex<double>(1.0, 0.0));
571 for (std::size_t j = 0; j < jitter_table_.size(); ++j) {
572 const double u = (
static_cast<double>(j) + 0.5) / 128.0 - 1.0;
573 jitter_table_[j] = std::polar(1.0,
static_cast<double>(
config.phase_jitter) *
u);
574 random_phase_table_[j] = std::polar(1.0, 3.14159265358979323846 *
u);
577 peak_of_.assign(lock ? bins : 0, -1);
578 lobe_power_.assign(lock ? bins : 0, 0.0);
579 lobe_draw_.assign(lock ? bins : 0, 0.0);
580 pending_.value.store(kRestoreIdle, std::memory_order_release);
581 active_capture_frames_ =
config.capture_frames;
582 latched_capture_frames_ = 0;
587 const Config&
config()
const {
return config_; }
595 if (num_bins_ == 0)
return;
596 active_capture_frames_ = std::clamp(frames, 2, config_.max_capture_frames);
601 if (config_.sample_rate > 0.0)
619 fade_ = SampleType{0};
622 engage_staging_.cancel();
623 renormalise_countdown_ = kRenormaliseHops;
645 if (engaged_ && !frozen && latched_) {
675 return {held_mag_.data() +
static_cast<size_t>(channel) *
static_cast<size_t>(num_bins_),
676 static_cast<size_t>(num_bins_)};
684 if (rotor_mode()) sync_phases_from_phasors();
685 return {held_phase_.data() +
static_cast<size_t>(channel) *
static_cast<size_t>(num_bins_),
686 static_cast<size_t>(num_bins_)};
691 return {inst_freq_.data(), inst_freq_.size()};
697 bool write_hold(std::complex<SampleType>*
const* frames,
int channels,
698 int num_bins)
const {
699 if (!has_hold_ || channels != config_.channels || num_bins != num_bins_)
702 for (
int ch = 0; ch < channels; ++ch) {
704 const auto* z = phasor_.data() +
static_cast<size_t>(ch) *
static_cast<size_t>(num_bins_);
705 for (
int k = 0; k < num_bins; ++k)
706 frames[ch][k] = scaled_phasor(z[k], mags[
static_cast<size_t>(k)]);
710 for (
int ch = 0; ch < channels; ++ch) {
713 for (
int k = 0; k < num_bins; ++k)
714 frames[ch][k] =
rt::polar(mags[
static_cast<size_t>(k)],
715 static_cast<SampleType
>(phases[
static_cast<size_t>(k)]));
730 for (
int i = 0;
i < frames; ++
i) advance_hold_phases();
743 if (engage_staging_.active())
744 engage_staging_.finish_now([
this](
int step) { build_rotor_chunk(step); });
746 for (
int k = 0; k < num_bins_; ++k) {
747 std::complex<double> base = std::conj(rotor_[
static_cast<size_t>(k)]);
748 std::complex<double> back(1.0, 0.0);
749 for (
int n = std::max(frames, 0); n > 0; n >>= 1) {
750 if (n & 1) back *= base;
753 for (
int ch = 0; ch < config_.channels; ++ch)
754 phasor_[
static_cast<size_t>(ch) * num_bins_ +
static_cast<size_t>(k)] *= back;
758 const double hops =
static_cast<double>(frames)
759 *
static_cast<double>(config_.analysis_hop);
760 for (
int k = 0; k < num_bins_; ++k) {
761 const double back = inst_freq_[
static_cast<size_t>(k)] * hops;
762 for (
int ch = 0; ch < config_.channels; ++ch) {
763 double& phase = held_phase_[
static_cast<size_t>(ch) * num_bins_
764 +
static_cast<size_t>(k)];
765 phase = princarg(phase - back);
777 const auto bins =
static_cast<std::size_t
>(num_bins_);
778 const auto channel_bins =
static_cast<std::size_t
>(config_.channels) * bins;
779 if (engage_staging_.active())
return false;
780 if (rotor_mode()) sync_phases_from_phasors();
781 if (!has_hold_ || num_bins_ == 0 || out.
fft_size != config_.fft_size
787 std::copy(held_mag_.begin(), held_mag_.end(), out.
magnitudes.begin());
788 std::copy(held_phase_.begin(), held_phase_.end(), out.
phases.begin());
789 std::copy(inst_freq_.begin(), inst_freq_.end(), out.
inst_freq.begin());
792 out.
fade_step = latched_ ? fade_step_ : 0;
793 out.
engaged = latched_ && engaged_ && !releasing_;
812 if (num_bins_ == 0 || in.
fft_size != config_.fft_size
815 || (in.
sample_rate > 0.0 && config_.sample_rate > 0.0
818 if (pending_.value.load(std::memory_order_acquire) != kRestoreIdle)
821 std::copy(in.
phases.begin(), in.
phases.end(), pending_phase_.begin());
824 const int steps = config_.crossfade_frames;
827 pending_engaged_ =
true;
828 pending_releasing_ =
false;
829 pending_fade_step_ = steps;
835 pending_fade_step_ =
static_cast<int>(std::lround(
840 pending_engaged_ =
true;
841 pending_releasing_ =
false;
842 pending_fade_step_ = 0;
845 pending_.value.store(kRestoreReady, std::memory_order_release);
852 return pending_.value.load(std::memory_order_acquire) == kRestoreReady;
860 void process_group(std::complex<SampleType>*
const* frames,
int channels,
int num_bins) {
861 assert(num_bins == num_bins_);
862 assert(channels == config_.channels);
864 if (pending_.value.load(std::memory_order_acquire) == kRestoreReady)
872 if (!latched_ || releasing_)
873 capture(frames, channels);
875 if (releasing_ && fade_step_ <= 0) {
880 if (engaged_ && !latched_ && captured_ >= active_capture_frames_)
883 if (engage_staging_.active())
884 engage_staging_.run_next(1, [
this](
int step) { build_rotor_chunk(step); });
905 const int steps = config_.crossfade_frames;
906 fade_step_ = std::clamp(fade_step_ + (releasing_ ? -1 : 1), 0, steps);
907 fade_ =
static_cast<SampleType
>(fade_step_) /
static_cast<SampleType
>(steps);
908 SampleType hold_gain, live_gain;
911 live_gain = SampleType{1} - fade_;
913 const SampleType t = fade_ *
static_cast<SampleType
>(1.57079632679489662);
914 hold_gain = std::sin(t);
915 live_gain = std::cos(t);
918 const bool rotor = rotor_mode();
919 for (
int ch = 0; ch < channels; ++ch) {
920 const SampleType* mags = held_mag_.data()
921 +
static_cast<size_t>(ch) * num_bins_;
922 const double* phases = held_phase_.data()
923 +
static_cast<size_t>(ch) * num_bins_;
924 const std::complex<double>* phasors =
925 rotor ? phasor_.data() +
static_cast<size_t>(ch) * num_bins_ :
nullptr;
934 double e_live = 0.0, e_hold = 0.0, e_mix = 0.0;
935 for (
int k = 0; k < num_bins_; ++k) {
936 const auto live = frames[ch][k];
937 const auto held =
rotor
938 ? scaled_phasor(phasors[k], mags[k] * hold_gain)
939 :
rt::polar(mags[k] * hold_gain,
static_cast<SampleType
>(phases[k]));
940 e_live +=
static_cast<double>(std::norm(live));
941 e_hold +=
static_cast<double>(mags[k]) * mags[k];
942 const auto mixed = live * live_gain + held;
943 e_mix +=
static_cast<double>(std::norm(mixed));
944 frames[ch][k] = mixed;
946 if (live_gain > SampleType{0}) {
951 const double target =
952 (1.0 -
static_cast<double>(fade_)) * e_live
953 +
static_cast<double>(fade_) * e_hold;
954 const double scale_sq = target / std::max(e_mix, 1
e-12);
955 const SampleType scale =
static_cast<SampleType
>(std::sqrt(
956 std::clamp(scale_sq, 0.0625, 16.0)));
957 for (
int k = 0; k < num_bins_; ++k) frames[ch][k] *= scale;
964 advance_hold_phases();
968 void capture(std::complex<SampleType>*
const* frames,
int channels) {
969 const auto bins =
static_cast<size_t>(num_bins_);
976 remove_from_window(capture_pos_);
979 for (
int ch = 0; ch < channels; ++ch) {
980 SampleType* slot = capture_mag_.data()
981 + (
static_cast<size_t>(ch) * depth
982 +
static_cast<size_t>(capture_pos_)) * bins;
983 for (
int k = 0; k < num_bins_; ++k)
984 slot[k] = std::abs(frames[ch][k]);
996 std::complex<SampleType>* ring = increment_ring_.data()
997 +
static_cast<size_t>(capture_pos_) * bins;
998 for (
int k = 0; k < num_bins_; ++k) {
999 std::complex<double> acc(0.0, 0.0);
1000 for (
int ch = 0; ch < channels; ++ch) {
1001 const auto now = frames[ch][k];
1002 auto& prev = prev_frame_[
static_cast<size_t>(ch) * bins +
static_cast<size_t>(k)];
1003 acc += std::complex<double>(now) * std::conj(std::complex<double>(prev));
1006 ring[
k] = prev_valid_ ? std::complex<SampleType>(acc) : std::complex<SampleType>{};
1015 std::complex<double>* raw = latest_increment_raw_.data();
1016 for (
int k = 0;
k < num_bins_; ++
k) {
1017 std::complex<double> acc(0.0, 0.0);
1018 for (
int ch = 0; ch < channels; ++ch) {
1019 const auto now = frames[ch][
k];
1020 auto& prev = prev_frame_[
static_cast<size_t>(ch) * bins +
static_cast<size_t>(k)];
1021 acc += std::complex<double>(now) * std::conj(std::complex<double>(prev));
1026 latest_increment_valid_ = prev_valid_;
1029 last_frames_ = frames;
1030 const int written = capture_pos_;
1031 capture_pos_ = (capture_pos_ + 1) % config_.max_capture_frames;
1032 if (captured_ < config_.max_capture_frames) ++captured_;
1034 add_to_window(written);
1036 slide_window(kWindowAdjustPerHop);
1042 int ring_slot_back(
int back)
const {
1043 const int ring = config_.max_capture_frames;
1044 return ((capture_pos_ - back) % ring + ring) %
ring;
1047 void add_to_window(
int slot) {
1048 accumulate_slot(slot, window_ == 0 ? 0 : 1);
1051 void remove_from_window(
int slot) { accumulate_slot(slot, -1); }
1055 void accumulate_slot(
int slot,
int sign) {
1056 const auto bins =
static_cast<size_t>(num_bins_);
1057 const auto ring =
static_cast<size_t>(config_.max_capture_frames);
1058 for (
int ch = 0; ch < config_.channels; ++ch) {
1059 const SampleType* mags = capture_mag_.data()
1060 + (
static_cast<size_t>(ch) *
ring +
static_cast<size_t>(slot)) * bins;
1061 double*
sum = running_mag_sum_.data() +
static_cast<size_t>(ch) * bins;
1062 for (
size_t k = 0;
k < bins; ++
k) {
1063 const double m =
static_cast<double>(mags[
k]);
1067 std::uint64_t work =
static_cast<std::uint64_t
>(config_.channels) * bins;
1069 const std::complex<SampleType>* inc = increment_ring_.data()
1070 +
static_cast<size_t>(slot) * bins;
1071 for (
size_t k = 0;
k < bins; ++
k) {
1072 const std::complex<double>
v(inc[k]);
1073 increment_sum_[
k] = sign == 0 ?
v
1074 : sign > 0 ? increment_sum_[
k] +
v
1075 : increment_sum_[
k] -
v;
1086 void slide_window(
int extra) {
1087 const int target = std::min(active_capture_frames_, captured_);
1088 if (window_ > target) {
1089 remove_from_window(ring_slot_back(window_));
1092 for (
int i = 0;
i < extra && window_ != target; ++
i) {
1093 if (window_ > target) {
1094 remove_from_window(ring_slot_back(window_));
1097 add_to_window(ring_slot_back(window_ + 1));
1104 const auto bins =
static_cast<size_t>(num_bins_);
1105 const int ring = config_.max_capture_frames;
1106 const int count = active_capture_frames_;
1113 while (window_ != count) slide_window(1);
1114 const double inv = 1.0 /
static_cast<double>(
count);
1115 for (
size_t i = 0;
i < held_mag_.size(); ++
i)
1116 held_mag_[
i] =
static_cast<SampleType
>(std::max(running_mag_sum_[
i], 0.0) * inv);
1121 rt::count_bins(
static_cast<std::uint64_t
>(count) * config_.channels * bins);
1122 for (
int ch = 0; ch < config_.channels; ++ch) {
1123 SampleType* held = held_mag_.data() +
static_cast<size_t>(ch) * bins;
1124 std::fill(held, held + bins, SampleType{0});
1126 const auto slot_index =
static_cast<size_t>((capture_pos_ -
back +
ring) %
ring);
1127 const SampleType* slot = capture_mag_.data()
1128 + (
static_cast<size_t>(ch) *
static_cast<size_t>(
ring) + slot_index) * bins;
1129 for (
int k = 0;
k < num_bins_; ++
k) held[k] += slot[k];
1131 const SampleType inv = SampleType{1} /
static_cast<SampleType
>(
count);
1132 for (
int k = 0;
k < num_bins_; ++
k) held[k] *= inv;
1135 latched_capture_frames_ =
count;
1139 std::fill(increment_sum_.begin(), increment_sum_.end(), std::complex<double>{});
1141 const std::complex<SampleType>* inc = increment_ring_.data()
1142 +
static_cast<size_t>((capture_pos_ -
back +
ring) %
ring) * bins;
1143 for (
size_t k = 0;
k < bins; ++
k)
1144 increment_sum_[k] += std::complex<double>(inc[k]);
1149 const bool staged = rotor_mode() && config_.engage_bins_per_hop > 0;
1151 if (lock) assign_lobes();
1156 for (
int k = 0;
k < num_bins_; ++
k) derive_weighted_frequency(k);
1158 for (
int k = 0;
k < num_bins_; ++
k)
1159 if (peak_of_[
static_cast<size_t>(k)] == k) derive_weighted_frequency(k);
1165 double* increment = latest_increment_.data();
1166 const double ha =
static_cast<double>(config_.analysis_hop);
1167 const std::complex<double>* raw = latest_increment_raw_.data();
1168 for (
int k = 0;
k < num_bins_; ++
k)
1169 increment[k] = latest_increment_valid_ ?
rt::arg(raw[k])
1170 : two_pi_ *
k / config_.fft_size * ha;
1171 for (
int k = 0;
k < num_bins_; ++
k) {
1172 const double omega = two_pi_ *
k / config_.fft_size;
1173 const double delta = princarg(increment[k] - omega * ha);
1174 inst_freq_[
static_cast<size_t>(
k)] = omega + delta / ha;
1180 if (last_frames_ !=
nullptr) {
1183 for (
int ch = 0; ch < config_.channels; ++ch) {
1184 std::complex<double>*
z = phasor_.data() +
static_cast<size_t>(ch) * bins;
1185 for (
int k = 0;
k < num_bins_; ++
k) {
1186 const std::complex<double>
x(last_frames_[ch][k]);
1187 const double r = std::abs(x);
1188 z[
k] =
r > 0.0 ?
x /
r : std::complex<double>(1.0, 0.0);
1192 for (
int ch = 0; ch < config_.channels; ++ch) {
1193 double* phases = held_phase_.data() +
static_cast<size_t>(ch) * bins;
1194 for (
int k = 0;
k < num_bins_; ++
k)
1195 phases[k] =
static_cast<double>(
rt::arg(last_frames_[ch][k]));
1200 if (!(weighted && staged)) lock_lobe_frequencies();
1201 randomise_unlocked_phases();
1204 begin_rotor_build(weighted && staged, staged);
1205 fade_ = SampleType{0};
1211 void adopt_restore() {
1212 std::swap(held_mag_, pending_mag_);
1213 std::swap(held_phase_, pending_phase_);
1214 std::swap(inst_freq_, pending_inst_freq_);
1215 rng_ = pending_rng_;
1216 engaged_ = pending_engaged_;
1217 releasing_ = pending_releasing_;
1220 latched_ = engaged_ || releasing_;
1222 fade_step_ = pending_fade_step_;
1223 fade_ =
static_cast<SampleType
>(fade_step_)
1224 /
static_cast<SampleType
>(config_.crossfade_frames);
1230 std::fill(peak_of_.begin(), peak_of_.end(), -1);
1234 for (
size_t i = 0;
i < phasor_.size(); ++
i)
1236 begin_rotor_build(
false,
false);
1238 pending_.value.store(kRestoreIdle, std::memory_order_release);
1245 static std::complex<SampleType> scaled_phasor(
const std::complex<double>& z,
1246 SampleType magnitude) {
1247 const double m =
static_cast<double>(magnitude);
1248 return {
static_cast<SampleType
>(
z.real() * m),
static_cast<SampleType
>(
z.imag() * m)};
1255 void begin_rotor_build(
bool derive_frequency,
bool staged) {
1256 derive_frequency_in_steps_ = derive_frequency;
1257 const int chunk = staged ? config_.engage_bins_per_hop : num_bins_;
1258 engage_chunk_ = chunk;
1260 std::fill(rotor_.begin(), rotor_.end(), std::complex<double>(1.0, 0.0));
1261 engage_staging_.begin((num_bins_ + chunk - 1) / chunk);
1263 engage_staging_.finish_now([
this](
int step) { build_rotor_chunk(step); });
1266 void build_rotor_chunk(
int step) {
1267 const double ha =
static_cast<double>(config_.analysis_hop);
1268 const int first = step * engage_chunk_;
1269 const int last = std::min(
first + engage_chunk_, num_bins_);
1270 const bool lock = !peak_of_.empty();
1271 for (
int k =
first;
k < last; ++
k) {
1272 if (derive_frequency_in_steps_) {
1273 const int peak = lock ? peak_of_[
static_cast<size_t>(
k)] : -1;
1275 derive_weighted_frequency(k);
1277 inst_freq_[
static_cast<size_t>(
k)] = inst_freq_[
static_cast<size_t>(
peak)];
1279 rotor_[
static_cast<size_t>(
k)] =
1280 rt::polar(1.0, inst_freq_[
static_cast<size_t>(k)] * ha);
1286 void derive_weighted_frequency(
int k) {
1287 const double ha =
static_cast<double>(config_.analysis_hop);
1288 const double omega = two_pi_ *
k / config_.fft_size;
1289 const auto sum = increment_sum_[
static_cast<size_t>(
k)];
1290 const double increment = (
sum.real() == 0.0 &&
sum.imag() == 0.0)
1293 const double delta = princarg(increment - omega * ha);
1294 inst_freq_[
static_cast<size_t>(
k)] = omega + delta / ha;
1304 void assign_lobes() {
1305 const int bins = num_bins_;
1306 const int w = std::max(config_.lobe_half_width, 0);
1308 for (
int k = 0;
k < bins; ++
k) {
1310 for (
int ch = 0; ch < config_.channels; ++ch) {
1311 const double m = held_mag_[
static_cast<size_t>(ch) * bins +
static_cast<size_t>(k)];
1314 lobe_power_[
static_cast<size_t>(
k)] = p;
1315 top = std::max(top, p);
1317 std::fill(peak_of_.begin(), peak_of_.end(), -1);
1318 const double floor =
top * 1
e-6;
1319 for (
int k = 0;
k < bins; ++
k) {
1320 const double p = lobe_power_[
static_cast<size_t>(
k)];
1321 if (!(p > floor))
continue;
1323 for (
int j = std::max(k - w, 0);
peak &&
j <= std::min(k + w, bins - 1); ++
j)
1324 if (j != k && (j < k ? lobe_power_[
static_cast<size_t>(j)] >= p
1325 : lobe_power_[
static_cast<size_t>(j)] > p))
1327 if (!
peak)
continue;
1328 for (
int j = std::max(k - w, 0);
j <= std::min(k + w, bins - 1); ++
j) {
1329 int& owner = peak_of_[
static_cast<size_t>(
j)];
1330 if (owner < 0 || lobe_power_[
static_cast<size_t>(owner)] < p) owner =
k;
1334 *
static_cast<std::uint64_t
>(config_.channels + 2 * w + 1));
1337 void lock_lobe_frequencies() {
1338 for (
int k = 0;
k < num_bins_; ++
k) {
1339 const int peak = peak_of_[
static_cast<size_t>(
k)];
1341 inst_freq_[
static_cast<size_t>(
k)] = inst_freq_[
static_cast<size_t>(
peak)];
1347 void randomise_unlocked_phases() {
1348 const auto bins =
static_cast<size_t>(num_bins_);
1349 for (
size_t k = 0;
k < bins; ++
k) {
1350 if (peak_of_[k] >= 0)
continue;
1352 const auto turn = random_phase_table_[next_jitter_index()];
1353 for (
int ch = 0; ch < config_.channels; ++ch)
1354 phasor_[
static_cast<size_t>(ch) * bins +
k] *= turn;
1356 const double turn = 3.14159265358979323846 * next_uniform();
1357 for (
int ch = 0; ch < config_.channels; ++ch) {
1358 double& phase = held_phase_[
static_cast<size_t>(ch) * bins + k];
1359 phase = princarg(phase + turn);
1365 void sync_phases_from_phasors()
const {
1366 for (
size_t i = 0;
i < phasor_.size(); ++
i)
1370 void advance_hold_phases() {
1374 const bool lock = !peak_of_.empty();
1376 for (
size_t k = 0;
k < lobe_draw_.size(); ++
k)
1377 lobe_draw_[k] = rotor_mode() ?
static_cast<double>(next_jitter_index())
1379 const auto draw_for = [&](
size_t k) {
1380 const int peak = peak_of_[
k];
1381 return lobe_draw_[
peak >= 0 ?
static_cast<size_t>(
peak) :
k];
1384 const auto bins =
static_cast<size_t>(num_bins_);
1385 for (
size_t k = 0;
k < bins; ++
k) {
1386 const std::size_t
index = lock ?
static_cast<std::size_t
>(draw_for(k))
1387 : next_jitter_index();
1388 const auto step = rotor_[
k] * jitter_table_[
index];
1389 for (
int ch = 0; ch < config_.channels; ++ch)
1390 phasor_[
static_cast<size_t>(ch) * bins +
k] *= step;
1394 if (--renormalise_countdown_ <= 0) {
1395 renormalise_countdown_ = kRenormaliseHops;
1396 for (
auto& z : phasor_)
z *= 0.5 * (3.0 - std::norm(z));
1400 const double ha =
static_cast<double>(config_.analysis_hop);
1401 const double jitter =
static_cast<double>(config_.phase_jitter);
1402 for (
int k = 0;
k < num_bins_; ++
k) {
1403 const double advance = inst_freq_[
static_cast<size_t>(
k)] * ha
1404 + jitter * (lock ? draw_for(
static_cast<size_t>(k))
1409 for (
int ch = 0; ch < config_.channels; ++ch) {
1410 double& phase = held_phase_[
static_cast<size_t>(ch) * num_bins_
1411 +
static_cast<size_t>(k)];
1412 phase = princarg(phase + advance);
1418 double next_uniform() {
1419 return static_cast<double>(
next_random() >> 11) * (2.0 / 9007199254740992.0) - 1.0;
1423 std::size_t next_jitter_index() {
1424 return static_cast<std::size_t
>(
next_random() >> 56);
1431 return rng_ * 0x2545f4914f6cdd1dull;
1434 static double princarg(
double p) {
1435 return p - two_pi_ * std::round(p / two_pi_);
1438 static constexpr double two_pi_ = 6.28318530717958647692;
1439 static constexpr std::uint64_t kRngSeed = 0x9e3779b97f4a7c15ull;
1440 static constexpr std::uint32_t kRestoreIdle = 0;
1441 static constexpr std::uint32_t kRestoreReady = 1;
1442 static constexpr int kRenormaliseHops = 64;
1443 static constexpr int kWindowAdjustPerHop = 2;
1447 struct RestoreFlag {
1448 std::atomic<std::uint32_t>
value{kRestoreIdle};
1449 RestoreFlag() =
default;
1450 RestoreFlag(
const RestoreFlag& other) noexcept
1451 :
value(
other.value.load(std::memory_order_acquire)) {}
1452 RestoreFlag& operator=(
const RestoreFlag& other)
noexcept {
1453 value.store(
other.value.load(std::memory_order_acquire),
1454 std::memory_order_release);
1462 std::vector<SampleType> capture_mag_;
1463 std::vector<double> latest_increment_;
1467 std::vector<std::complex<double>> latest_increment_raw_;
1468 bool latest_increment_valid_ =
false;
1469 std::vector<std::complex<SampleType>> prev_frame_;
1470 std::vector<SampleType> held_mag_;
1473 mutable std::vector<double> held_phase_;
1474 std::vector<double> inst_freq_;
1477 std::vector<std::complex<SampleType>> increment_ring_;
1478 std::vector<std::complex<double>> increment_sum_;
1479 std::vector<double> running_mag_sum_;
1480 std::vector<std::complex<double>> phasor_;
1481 std::vector<std::complex<double>> rotor_;
1482 std::array<std::complex<double>, 256> jitter_table_{};
1483 std::array<std::complex<double>, 256> random_phase_table_{};
1484 std::vector<int> peak_of_;
1485 std::vector<double> lobe_power_;
1486 std::vector<double> lobe_draw_;
1488 int engage_chunk_ = 0;
1489 bool derive_frequency_in_steps_ =
false;
1491 int renormalise_countdown_ = kRenormaliseHops;
1494 std::vector<SampleType> pending_mag_;
1495 std::vector<double> pending_phase_;
1496 std::vector<double> pending_inst_freq_;
1497 std::uint64_t pending_rng_ = 0;
1498 int pending_fade_step_ = 0;
1499 bool pending_engaged_ =
false;
1500 bool pending_releasing_ =
false;
1501 RestoreFlag pending_;
1503 std::complex<SampleType>*
const* last_frames_ =
nullptr;
1505 int capture_pos_ = 0;
1506 int active_capture_frames_ = 2;
1507 int latched_capture_frames_ = 0;
1508 bool prev_valid_ =
false;
1509 bool engaged_ =
false;
1510 bool latched_ =
false;
1511 bool releasing_ =
false;
1512 bool has_hold_ =
false;
1513 SampleType fade_ = SampleType{0};
1515 std::uint64_t rng_ = kRngSeed;
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
Definition freeze_hold.hpp:402
bool is_engaged() const
The last engage/release request.
Definition freeze_hold.hpp:653
std::span< const double > held_phases(int channel) const
Current hold phases of one channel, wrapped to [-pi, pi]: the phases the next hold frame is rendered ...
Definition freeze_hold.hpp:683
const Config & config() const
Definition freeze_hold.hpp:587
bool restore_pending() const
True while a staged restore is waiting for the next frame group.
Definition freeze_hold.hpp:851
void reset()
Full reset: drops the hold and the capture history and re-seeds the PRNG (the prepared state).
Definition freeze_hold.hpp:613
bool is_latched() const
True once held content is actually playing (capture was full).
Definition freeze_hold.hpp:656
std::span< const double > instantaneous_frequency() const
Per-bin instantaneous frequency of the hold, radians per sample.
Definition freeze_hold.hpp:690
static bool checked_retained_bytes(const Config &requested, std::uint64_t target_max_bytes, std::uint64_t &bytes) noexcept
Definition freeze_hold.hpp:489
void advance_hold(int frames=1)
Advance the hold by frames analysis hops exactly as process_group() does after each held frame (insta...
Definition freeze_hold.hpp:729
void process_group(std::complex< SampleType > *const *frames, int channels, int num_bins)
Run at the head of the vocoder chain for every analysis frame group.
Definition freeze_hold.hpp:860
static Config resolve(const Config &config) noexcept
Resolve the time-based fields of config into frame counts: the exact configuration prepare() runs wit...
Definition freeze_hold.hpp:463
std::span< const SampleType > held_magnitudes(int channel) const
Averaged magnitudes of one channel's hold (num_bins values).
Definition freeze_hold.hpp:674
void prepare(const Config &requested)
RT contract: prepare() allocates capture/hold storage and is not audio-thread safe.
Definition freeze_hold.hpp:541
bool is_releasing() const
True while a released hold is fading out.
Definition freeze_hold.hpp:658
bool write_hold(std::complex< SampleType > *const *frames, int channels, int num_bins) const
Render the current hold frame (magnitude and phase only — no live mix, no crossfade,...
Definition freeze_hold.hpp:697
bool engage_pending() const
True while latch- or restore-side rotor construction is still being staged across frame groups (engag...
Definition freeze_hold.hpp:722
static int frames_for_seconds(double seconds, const Config &config) noexcept
round(seconds * sample_rate / analysis_hop) for a seconds-based config (0 when it is not seconds-base...
Definition freeze_hold.hpp:481
SampleType engage_progress() const
Hold-weight position of the crossfade used for the most recent frame group: 0 = live only,...
Definition freeze_hold.hpp:669
int capture_frames() const
The capture depth the next latch uses.
Definition freeze_hold.hpp:605
void set_frozen(bool frozen)
RT-safe engage/release request.
Definition freeze_hold.hpp:644
void set_capture_seconds(double seconds)
Seconds-based form of set_capture_frames(); ignored unless the hold was prepared with a sample rate.
Definition freeze_hold.hpp:600
bool snapshot(Snapshot &out) const
Copy the current hold into out, which must have been prepared for this geometry.
Definition freeze_hold.hpp:776
bool stage_restore(const Snapshot &in, FreezeRestoreEngage engage=FreezeRestoreEngage::crossfade)
Stage in to become the hold at the start of the next process_group().
Definition freeze_hold.hpp:810
FreezeHoldSnapshotT< SampleType > Snapshot
Definition freeze_hold.hpp:459
void clear_history()
Forget captured input only.
Definition freeze_hold.hpp:630
bool has_hold() const
True once a hold has been latched or restored since the last reset(); the held-state accessors and wr...
Definition freeze_hold.hpp:661
void rewind_hold_phases(int frames)
Move the hold phases back by frames hops at the instantaneous frequency, without the random walk and ...
Definition freeze_hold.hpp:741
void set_capture_frames(int frames)
Hold length: the number of most recent frames the NEXT latch averages, clamped to [2,...
Definition freeze_hold.hpp:594
Definition staged_transition.hpp:33
std::uint64_t next_random(std::uint64_t &state) noexcept
Definition sample_heritage_engine.hpp:25
@ top
Definition canvas.hpp:222
@ count
sentinel: number of real capabilities (keep LAST)
Definition canvas_capability.hpp:38
@ Config
Set via InspectorConfig / setEditorUrlTemplate.
Definition editor_url.hpp:50
MidiEvent at(MidiEvent event, std::int32_t sample_offset) noexcept
Definition utility_contract.hpp:140
@ index
Definition gpu_pass.hpp:140
@ back
Definition gpu_pass.hpp:283
@ other
Definition udev_monitor.hpp:26
@ ring
Definition string.hpp:18
std::complex< T > polar(T magnitude, T phase) noexcept
Counted std::polar. Bit-identical result.
Definition rt_work_counter.hpp:133
void count_bins(std::uint64_t n) noexcept
Record n units of per-bin accumulation work.
Definition rt_work_counter.hpp:100
T arg(const std::complex< T > &z) noexcept
Counted std::arg (an atan2). Bit-identical result.
Definition rt_work_counter.hpp:161
Definition additive_bank.hpp:218
@ first
Definition dither.hpp:23
FreezeHoldFrequency
Where a held bin's instantaneous frequency comes from.
Definition freeze_hold.hpp:124
@ newest
The newest captured frame's phase increment (the original estimate).
Definition freeze_hold.hpp:126
@ energy_weighted
Energy-weighted circular mean of the increments over the window.
Definition freeze_hold.hpp:128
@ peak
Sample peak. Literal, fastest-responding.
Definition feedforward_compressor.hpp:119
FreezeHoldPhaseLock
Phase structure of a hold as it starts (see the class notes on stationarity).
Definition freeze_hold.hpp:141
@ none
Every bin starts at its latched phase and rotates at its own frequency (the original behaviour).
Definition freeze_hold.hpp:144
@ peak_lobe
Bins within lobe_half_width of a spectral peak rotate at the peak's frequency; every other bin starts...
Definition freeze_hold.hpp:147
FreezeHoldT< double > FreezeHold64
Definition freeze_hold.hpp:1519
FreezeHoldSnapshotT< float > FreezeHoldSnapshot
Definition freeze_hold.hpp:382
bool checked_capacity_product(std::uint64_t lhs, std::uint64_t rhs, std::uint64_t maximum, std::uint64_t &product) noexcept
Definition checked_allocation.hpp:12
FreezeHoldT< float > FreezeHold
Definition freeze_hold.hpp:1518
@ u
Definition formant_filter_bank.hpp:20
@ i
Definition formant_filter_bank.hpp:20
@ e
Definition formant_filter_bank.hpp:20
@ none
Definition dither.hpp:17
FreezeHoldSynthesis
How held frames are synthesised (see the class notes on per-callback cost).
Definition freeze_hold.hpp:116
@ rotor
Unit phasor per bin advanced by a rotor and a jitter table.
Definition freeze_hold.hpp:120
@ polar
One std::polar per channel per bin per hop (the original path).
Definition freeze_hold.hpp:118
FreezeRestoreEngage
How a restored hold enters the output.
Definition freeze_hold.hpp:151
@ crossfade
Fade in over the configured crossfade, like a normal engage.
Definition freeze_hold.hpp:153
@ immediate
Replace the output with the hold from the adopting frame onward.
Definition freeze_hold.hpp:155
@ as_captured
Resume the recorded request and fade position (a hold captured mid-release keeps releasing).
Definition freeze_hold.hpp:158
FreezeHoldSnapshotT< double > FreezeHoldSnapshot64
Definition freeze_hold.hpp:383
FreezeHoldAverage
When the capture window is averaged.
Definition freeze_hold.hpp:132
@ running
Maintain running sums as frames arrive; the latch only divides.
Definition freeze_hold.hpp:136
@ at_latch
Sum the window inside the latching frame group (the original path).
Definition freeze_hold.hpp:134
float sum(const float *data, std::size_t count) noexcept
@ value
the widget's primary value (Knob, Fader, RangeSlider, Toggle, ProgressBar)
Definition binding_diagnostics.hpp:19
@ j
Definition input_events.hpp:40
@ r
Definition input_events.hpp:41
@ m
Definition input_events.hpp:40
@ p
Definition input_events.hpp:40
@ k
Definition input_events.hpp:40
@ x
Definition input_events.hpp:41
@ v
Definition input_events.hpp:41
@ w
Definition input_events.hpp:41
@ z
Definition input_events.hpp:42
Deterministic operation counters for audio-callback cost gates.
Amortise a bounded piece of transition work over several audio callbacks.
Time-based FreezeHold timing that reproduces the frame-count defaults (8 capture frames,...
Definition freeze_hold.hpp:389
static constexpr int kAnalysisHop
Definition freeze_hold.hpp:391
static constexpr double kSampleRate
Definition freeze_hold.hpp:390
static constexpr double kCrossfadeSeconds
6 hops: 6 * 512 / 48000 s.
Definition freeze_hold.hpp:395
static constexpr double kPhaseJitterPerSqrtSecond
0.015 rad per 512-sample frame, as a random-walk rate: 0.015 * sqrt(48000 / 512) rad per sqrt(second)...
Definition freeze_hold.hpp:398
static constexpr double kCaptureSeconds
8 hops: 8 * 512 / 48000 s.
Definition freeze_hold.hpp:393
Value image of a FreezeHold's held state: everything needed to reproduce the held output bit-for-bit ...
Definition freeze_hold.hpp:178
std::vector< float > magnitudes
Definition freeze_hold.hpp:201
int crossfade_frames
Definition freeze_hold.hpp:193
static constexpr int kMaxChannels
Definition freeze_hold.hpp:182
static constexpr std::uint32_t kFlagReleasing
Definition freeze_hold.hpp:185
static constexpr int kMinFftSize
Definition freeze_hold.hpp:180
static constexpr int kMaxFftSize
Definition freeze_hold.hpp:181
bool write_bytes(std::vector< std::uint8_t > &out) const
Serialize to the versioned byte image.
Definition freeze_hold.hpp:267
static std::size_t serialized_size(int fft, int ch) noexcept
Byte size of the serialized image for a geometry, or 0 when the geometry is outside the supported bou...
Definition freeze_hold.hpp:212
int fft_size
Definition freeze_hold.hpp:187
bool valid() const noexcept
Shape and value check: geometry in bounds, storage sized for it, a consistent fade record,...
Definition freeze_hold.hpp:244
static constexpr std::uint32_t kFlagEngaged
Definition freeze_hold.hpp:184
int analysis_hop
Definition freeze_hold.hpp:189
int capture_frames
Definition freeze_hold.hpp:191
bool releasing
Definition freeze_hold.hpp:196
std::vector< double > inst_freq
Definition freeze_hold.hpp:203
std::uint64_t rng_state
Definition freeze_hold.hpp:200
bool engaged
Definition freeze_hold.hpp:195
static bool valid_geometry(int fft, int ch, int hop) noexcept
Definition freeze_hold.hpp:205
int channels
Definition freeze_hold.hpp:188
static bool read_bytes(const std::uint8_t *data, std::size_t size, FreezeHoldSnapshotT &out)
Parse a byte image.
Definition freeze_hold.hpp:299
static constexpr std::uint32_t kFormatVersion
Definition freeze_hold.hpp:179
int fade_step
Definition freeze_hold.hpp:194
std::vector< double > phases
Definition freeze_hold.hpp:202
bool prepare(int fft, int ch, int hop)
Allocate storage for a geometry. Not audio-thread safe.
Definition freeze_hold.hpp:221
static constexpr std::size_t kHeaderBytes
Definition freeze_hold.hpp:183
double sample_rate
Definition freeze_hold.hpp:199
Two sizing modes.
Definition freeze_hold.hpp:410
int lobe_half_width
With peak_lobe: bins either side of a peak locked to it (2 spans a Hann main lobe).
Definition freeze_hold.hpp:456
int max_capture_frames
Largest capture depth set_capture_frames() may select later; storage is preallocated for it.
Definition freeze_hold.hpp:422
FreezeHoldSynthesis synthesis
Held-frame synthesis. polar reproduces the original output.
Definition freeze_hold.hpp:440
int capture_frames
Frames averaged into the hold (rolling capture depth, >= 2).
Definition freeze_hold.hpp:415
FreezeHoldPhaseLock phase_lock
Phase structure at the latch. none reproduces the original.
Definition freeze_hold.hpp:451
int engage_bins_per_hop
With rotor synthesis: bins whose rotor (and, with energy_weighted, frequency) is built per frame grou...
Definition freeze_hold.hpp:449
double max_capture_seconds
Longest capture set_capture_seconds() may select later.
Definition freeze_hold.hpp:437
int crossfade_frames
Engage/release crossfade length in frames (>= 1).
Definition freeze_hold.hpp:417
double sample_rate
Definition freeze_hold.hpp:425
FreezeHoldAverage average
Capture-window averaging. at_latch reproduces the original.
Definition freeze_hold.hpp:444
double crossfade_seconds
Crossfade length: frames = round(s * sr / hop).
Definition freeze_hold.hpp:429
int fft_size
Definition freeze_hold.hpp:411
int analysis_hop
Definition freeze_hold.hpp:413
int channels
Definition freeze_hold.hpp:412
float phase_jitter
Random-walk step bound (radians/frame) for de-looping.
Definition freeze_hold.hpp:419
double phase_jitter_per_sqrt_second
Random-walk rate in radians per sqrt(second); the per-frame bound is rate * sqrt(hop / sr),...
Definition freeze_hold.hpp:433
FreezeHoldFrequency frequency
Per-bin frequency estimate. newest reproduces the original.
Definition freeze_hold.hpp:442
double capture_seconds
Capture window in seconds of hop grid: frames = round(s * sr / hop).
Definition freeze_hold.hpp:427