59 constexpr explicit operator bool() const noexcept {
67 std::int64_t& result)
noexcept {
68 constexpr auto minimum = std::numeric_limits<std::int64_t>::min();
69 constexpr auto maximum = std::numeric_limits<std::int64_t>::max();
70 if ((rhs > 0 && lhs >
maximum - rhs) || (rhs < 0 && lhs < minimum - rhs))
77 std::int64_t& result)
noexcept {
78 constexpr auto minimum = std::numeric_limits<std::int64_t>::min();
79 constexpr auto maximum = std::numeric_limits<std::int64_t>::max();
80 if ((rhs > 0 && lhs < minimum + rhs) || (rhs < 0 && lhs >
maximum + rhs))
87 std::int64_t& result)
noexcept {
90 const auto remainder = value % quantum;
95 const auto delta = remainder < 0 ? -remainder : quantum - remainder;
104inline BeatRepeatPlanResult
110 const auto quantum = quantum_result.value().value;
111 auto candidate_source = tempo.samples_to_ticks(requested_sample).value;
112 std::int64_t candidate = 0;
116 auto edge = tempo.ticks_to_samples({candidate});
117 if (edge.value == std::numeric_limits<std::int64_t>::min() ||
118 edge.value == std::numeric_limits<std::int64_t>::max())
120 if (edge.value <= requested_sample.value) {
121 const auto candidate_bits =
static_cast<std::uint64_t
>(candidate);
122 const auto maximum_bits =
123 static_cast<std::uint64_t
>(std::numeric_limits<std::int64_t>::max());
124 const auto maximum_steps =
125 (maximum_bits - candidate_bits) /
static_cast<std::uint64_t
>(quantum);
126 if (maximum_steps == 0)
128 const auto tick_at_step = [&](std::uint64_t step)
noexcept {
129 const auto offset = step *
static_cast<std::uint64_t
>(quantum);
130 return static_cast<std::int64_t
>(candidate_bits + offset);
133 std::uint64_t lower_step = 0;
134 std::uint64_t upper_step = 1;
136 upper_step = std::min(upper_step, maximum_steps);
137 const auto probe = tick_at_step(upper_step);
138 edge = tempo.ticks_to_samples({probe});
139 if (edge.value > requested_sample.value)
141 if (upper_step == maximum_steps)
143 lower_step = upper_step;
144 upper_step = upper_step > maximum_steps / 2 ? maximum_steps : upper_step * 2;
146 while (upper_step - lower_step > 1) {
147 const auto middle_step = lower_step + (upper_step - lower_step) / 2;
148 const auto middle = tick_at_step(middle_step);
149 if (tempo.ticks_to_samples({middle}).value <= requested_sample.value)
150 lower_step = middle_step;
152 upper_step = middle_step;
154 candidate = tick_at_step(upper_step);
155 edge = tempo.ticks_to_samples({candidate});
158 if (edge.value == std::numeric_limits<std::int64_t>::min() ||
159 edge.value == std::numeric_limits<std::int64_t>::max())
162 std::int64_t previous_tick = 0;
165 const auto previous_sample = tempo.ticks_to_samples({previous_tick});
166 if (previous_sample.value == std::numeric_limits<std::int64_t>::min() ||
167 previous_sample.value == std::numeric_limits<std::int64_t>::max())
169 std::int64_t capture_frames = 0;
171 capture_frames <= 0 || capture_frames > std::numeric_limits<int>::max())
173 return {{requested_sample, edge, {candidate},
static_cast<int>(capture_frames)},
211 SampleType
gate = SampleType{1};
234 if (
this != &other) {
242 if (config.channels <= 0 || config.history_capacity_frames <= 0 ||
243 config.transition_frames < 0 || !config.sample_rate.valid())
245 const auto normalized_rate = config.sample_rate.normalized();
247#if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)
251 replacement_sampler.
prepare(config.channels, config.history_capacity_frames, 0);
252 if (replacement_sampler.
channels() != config.channels ||
253 replacement_sampler.
capacity() != config.history_capacity_frames)
255 std::vector<const SampleType*> replacement_inputs(
256 static_cast<std::size_t
>(config.channels),
nullptr);
257 std::vector<SampleType> replacement_last(
static_cast<std::size_t
>(config.channels),
259 std::vector<SampleType> replacement_transition(
260 static_cast<std::size_t
>(config.channels), SampleType{});
262 sampler_ = std::move(replacement_sampler);
263 history_inputs_.swap(replacement_inputs);
264 last_output_.swap(replacement_last);
265 transition_old_.swap(replacement_transition);
266 transition_frames_ = config.transition_frames;
267 sample_rate_ = normalized_rate;
271#if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)
272 }
catch (
const std::bad_alloc&) {
274 }
catch (
const std::length_error&) {
284 return sampler_.channels();
287 return sampler_.capacity();
290 return sampler_.available_history();
296 return last_capture_rejected_;
299 return !pending_capture_;
302 return active_loop_ ? sampler_.loop_length() : 0;
305 return loop_position_;
308 return completed_repeats_;
314 return active_transition_frames();
317 return sampler_.retained_bytes() + (history_inputs_.capacity() *
sizeof(
const SampleType*) +
318 last_output_.capacity() *
sizeof(SampleType) +
319 transition_old_.capacity() *
sizeof(SampleType));
325 repeat_count_ = count;
327 completed_repeats_ >= count) {
328 pending_capture_ =
false;
336 if (!std::isfinite(
static_cast<double>(duty)))
338 gate_ = std::clamp(duty, SampleType{}, SampleType{1});
356 transition_frames_ = frames;
365 if (tempo.sample_rate().normalized() != sample_rate_)
372 if (lowered.plan.capture_frames > sampler_.capacity())
374 if (have_expected_sample_ && lowered.plan.edge_sample.value < expected_sample_)
376 pending_plan_ = lowered.plan;
377 pending_capture_ =
true;
378 last_capture_rejected_ =
false;
384 pending_capture_ =
false;
396 bool seek(
int captured_frame)
noexcept {
397 if (!active_loop_ || status_ ==
Status::Releasing || sampler_.loop_length() <= 0)
399 const auto clamped = std::clamp(captured_frame, 0, sampler_.loop_length() - 1);
401 reverse_for_current_repeat() ? sampler_.loop_length() - 1 - clamped : clamped;
409 pending_capture_ =
false;
410 active_loop_ =
false;
411 last_capture_rejected_ =
false;
413 completed_repeats_ = 0;
414 alternate_repeat_ =
false;
416 transition_position_ = 0;
417 have_expected_sample_ =
false;
418 std::fill(last_output_.begin(), last_output_.end(), SampleType{});
419 std::fill(transition_old_.begin(), transition_old_.end(), SampleType{});
428 void process(
const SampleType*
const* input, SampleType*
const* output,
int frames,
430 if (!prepared_ || frames <= 0 || input ==
nullptr || output ==
nullptr)
432 for (
int channel = 0; channel < sampler_.channels(); ++channel) {
433 if (input[channel] ==
nullptr || output[channel] ==
nullptr)
436 std::int64_t block_end = 0;
439 copy_dry(input, output, 0, frames);
442 if (have_expected_sample_ && block_start.value != expected_sample_) {
446 int capture_offset = -1;
447 if (pending_capture_ && pending_plan_.edge_sample.value >= block_start.value &&
448 pending_plan_.edge_sample.value < block_end) {
449 capture_offset =
static_cast<int>(pending_plan_.edge_sample.value - block_start.value);
450 }
else if (pending_capture_ && pending_plan_.edge_sample.value < block_start.value) {
451 pending_capture_ =
false;
455 if (capture_offset >= 0) {
456 write_history(input, 0, capture_offset);
457 render_segment(input, output, 0, capture_offset);
458 if (pending_capture_)
460 write_history(input, capture_offset, frames - capture_offset);
461 render_segment(input, output, capture_offset, frames - capture_offset);
463 write_history(input, 0, frames);
464 render_segment(input, output, 0, frames);
466 expected_sample_ = block_end;
467 have_expected_sample_ =
true;
473 result.sample_rate = sample_rate_;
474 result.repeat_count = repeat_count_;
476 result.reverse = reverse_;
481 result.alternate_repeat = result.active && alternate_repeat_;
482 result.last_capture_rejected = last_capture_rejected_;
483 result.transition_frames = transition_frames_;
485 result.loop_position = loop_position_;
486 result.completed_repeats = completed_repeats_;
487 result.sampler = sampler_.snapshot();
488 result.transition = transition_kind_;
489 result.transition_position = transition_position_;
490 result.transition_length = active_transition_frames();
491 result.transition_old = transition_old_;
492 result.last_output = last_output_;
494 result.last_output.assign(last_output_.size(), SampleType{});
500 if (!prepared_ || !value.resumable || value.repeat_count < 0 ||
501 !value.sample_rate.valid() || value.sample_rate.normalized() != sample_rate_ ||
502 value.transition_frames < 0 || !std::isfinite(
static_cast<double>(value.gate)) ||
503 value.gate < SampleType{} || value.gate > SampleType{1} ||
506 value.last_output.size() != last_output_.size())
509 (!value.sampler.empty() || value.loop_position != 0 || value.completed_repeats != 0 ||
511 value.transition_position != 0 || value.transition_length != 0 ||
512 !value.transition_old.empty()))
514 for (
const auto sample : value.last_output) {
515 if (!std::isfinite(
static_cast<double>(sample)))
519 if (value.sampler.size() < 4 || !std::isfinite(
static_cast<double>(value.sampler[0])) ||
520 !std::isfinite(
static_cast<double>(value.sampler[1])) ||
521 value.sampler[0] !=
static_cast<SampleType
>(sampler_.channels()) ||
522 value.sampler[1] < SampleType{1} ||
523 value.sampler[1] >
static_cast<SampleType
>(sampler_.capacity()) ||
524 std::trunc(value.sampler[1]) != value.sampler[1] || value.loop_position < 0 ||
525 value.loop_position >=
static_cast<int>(value.sampler[1]) ||
526 value.completed_repeats < 0 ||
527 (value.completed_repeats < std::numeric_limits<int>::max() &&
528 value.alternate_repeat != (value.completed_repeats % 2 != 0)) ||
529 (value.repeat_count > 0 && value.completed_repeats >= value.repeat_count))
531 const auto loop_length =
static_cast<int>(value.sampler[1]);
532 const auto expected_size =
533 static_cast<std::size_t
>(4) +
static_cast<std::size_t
>(sampler_.channels()) *
535 if (value.sampler.size() != expected_size ||
536 !std::isfinite(
static_cast<double>(value.sampler[3])) ||
537 std::trunc(value.sampler[3]) != value.sampler[3] ||
538 value.sampler[3] < SampleType{} ||
539 value.sampler[3] >=
static_cast<SampleType
>(
loop_length))
541 const auto transition_length = std::min(value.transition_frames,
loop_length / 2);
545 value.transition_old.size() != transition_old_.size() ||
546 value.transition_position < 0 || value.transition_length < 0 ||
547 value.transition_length != transition_length ||
550 (transition_length == 0 || value.transition_position >= transition_length)))
552 for (
const auto sample : value.transition_old) {
553 if (!std::isfinite(
static_cast<double>(sample)))
556 for (
const auto sample : value.sampler) {
557 if (!std::isfinite(
static_cast<double>(sample)))
560 if (!sampler_.restore(value.sampler))
565 sampler_.clear_history();
566 repeat_count_ = value.repeat_count;
568 reverse_ = value.reverse;
569 transition_frames_ = value.transition_frames;
570 loop_position_ = value.active ? value.loop_position : 0;
571 completed_repeats_ = value.active ? value.completed_repeats : 0;
572 alternate_repeat_ = value.active && value.alternate_repeat;
573 active_loop_ = value.active;
574 last_capture_rejected_ = value.last_capture_rejected;
575 last_output_ = value.last_output;
577 transition_position_ = value.active ? value.transition_position : 0;
579 transition_old_ = value.transition_old;
581 std::fill(transition_old_.begin(), transition_old_.end(), SampleType{});
582 pending_capture_ =
false;
585 have_expected_sample_ =
false;
592 swap(sampler_, other.sampler_);
593 swap(sample_rate_, other.sample_rate_);
594 swap(history_inputs_, other.history_inputs_);
595 swap(last_output_, other.last_output_);
596 swap(transition_old_, other.transition_old_);
597 swap(pending_plan_, other.pending_plan_);
598 swap(repeat_count_, other.repeat_count_);
599 swap(gate_, other.gate_);
600 swap(reverse_, other.reverse_);
601 swap(status_, other.status_);
602 swap(transition_kind_, other.transition_kind_);
603 swap(transition_frames_, other.transition_frames_);
604 swap(transition_position_, other.transition_position_);
605 swap(loop_position_, other.loop_position_);
606 swap(completed_repeats_, other.completed_repeats_);
607 swap(expected_sample_, other.expected_sample_);
608 swap(prepared_, other.prepared_);
609 swap(pending_capture_, other.pending_capture_);
610 swap(active_loop_, other.active_loop_);
611 swap(alternate_repeat_, other.alternate_repeat_);
612 swap(last_capture_rejected_, other.last_capture_rejected_);
613 swap(have_expected_sample_, other.have_expected_sample_);
616 int active_transition_frames() const noexcept {
617 if (!active_loop_ || sampler_.loop_length() <= 0)
618 return transition_frames_;
619 return std::min(transition_frames_, sampler_.loop_length() / 2);
623 std::copy(last_output_.begin(), last_output_.end(), transition_old_.begin());
625 transition_position_ = 0;
630 void capture_pending() noexcept {
631 pending_capture_ =
false;
632 const auto capture = sampler_.try_freeze_recent(pending_plan_.capture_frames);
634 last_capture_rejected_ =
true;
638 const bool replacing = active_loop_;
641 completed_repeats_ = 0;
642 alternate_repeat_ =
false;
644 last_capture_rejected_ =
false;
650 transition_position_ = 0;
654 void write_history(
const SampleType*
const* input,
int offset,
int frames)
noexcept {
657 for (
int channel = 0; channel < sampler_.channels(); ++channel)
658 history_inputs_[
static_cast<std::size_t
>(channel)] = input[channel] + offset;
659 sampler_.write(history_inputs_.data(), frames);
662 void copy_dry(
const SampleType*
const* input, SampleType*
const* output,
int offset,
663 int frames)
noexcept {
664 for (
int channel = 0; channel < sampler_.channels(); ++channel) {
665 for (
int frame = 0; frame < frames; ++frame)
666 output[channel][offset + frame] = finite_sample(input[channel][offset + frame]);
670 bool reverse_for_current_repeat() const noexcept {
675 SampleType gate_gain() const noexcept {
676 const int length = sampler_.loop_length();
677 if (length <= 0 || gate_ <= SampleType{})
679 if (gate_ >= SampleType{1})
680 return SampleType{1};
681 const int audible = std::clamp(
682 static_cast<int>(std::llround(
static_cast<double>(gate_) * length)), 0, length);
683 if (audible <= 0 || loop_position_ >= audible)
685 const int fade = std::min(active_transition_frames(), audible / 2);
687 return SampleType{1};
688 if (loop_position_ < fade) {
690 static_cast<SampleType
>(loop_position_) /
static_cast<SampleType
>(fade - 1);
691 SampleType old_gain{};
692 SampleType new_gain{};
697 if (loop_position_ >= audible - fade) {
698 const auto t =
static_cast<SampleType
>(loop_position_ - (audible - fade)) /
699 static_cast<SampleType
>(fade - 1);
700 SampleType old_gain{};
701 SampleType new_gain{};
706 return SampleType{1};
709 SampleType wet_sample(
int channel)
const noexcept {
710 const int length = sampler_.loop_length();
711 if (!active_loop_ || length <= 0)
714 reverse_for_current_repeat() ? length - 1 - loop_position_ : loop_position_;
715 return sampler_.loop_sample(channel, index) * gate_gain();
718 void render_segment(
const SampleType*
const* input, SampleType*
const* output,
int offset,
719 int frames)
noexcept {
720 for (
int frame = 0; frame < frames; ++frame) {
721 SampleType old_gain{};
722 SampleType new_gain{SampleType{1}};
724 const auto length = active_transition_frames();
725 const auto t = length <= 1 ? SampleType{1}
726 :
static_cast<SampleType
>(transition_position_) /
727 static_cast<SampleType
>(length - 1);
732 for (
int channel = 0; channel < sampler_.channels(); ++channel) {
733 const auto dry = finite_sample(input[channel][offset + frame]);
734 const auto wet = wet_sample(channel);
735 SampleType rendered = active_loop_ ? wet : dry;
736 switch (transition_kind_) {
740 rendered = dry * old_gain + wet * new_gain;
743 rendered = transition_old_[
static_cast<std::size_t
>(channel)] * old_gain +
747 rendered = transition_old_[
static_cast<std::size_t
>(channel)] * old_gain +
751 rendered = finite_sample(rendered);
752 output[channel][offset + frame] = rendered;
753 last_output_[
static_cast<std::size_t
>(channel)] = rendered;
756 advance_transition();
762 void advance_transition() noexcept {
765 const auto completed_kind = transition_kind_;
766 if (++transition_position_ < active_transition_frames())
769 transition_position_ = 0;
774 static SampleType finite_sample(SampleType value)
noexcept {
775 return std::isfinite(
static_cast<double>(value)) ?
value : SampleType{};
778 void advance_loop() noexcept {
779 if (++loop_position_ < sampler_.loop_length())
782 if (completed_repeats_ < std::numeric_limits<int>::max())
783 ++completed_repeats_;
784 alternate_repeat_ = !alternate_repeat_;
785 if (repeat_count_ > 0 && completed_repeats_ >= repeat_count_) {
786 pending_capture_ =
false;
796 void finish_release() noexcept {
797 active_loop_ =
false;
801 completed_repeats_ = 0;
802 alternate_repeat_ =
false;
805 FreezeLoopSamplerT<SampleType> sampler_;
806 timebase::RationalRate sample_rate_{48'000, 1};
807 std::vector<const SampleType*> history_inputs_;
808 std::vector<SampleType> last_output_;
809 std::vector<SampleType> transition_old_;
810 BeatRepeatCapturePlan pending_plan_{};
811 int repeat_count_ = 4;
812 SampleType gate_ = SampleType{1};
816 int transition_frames_ = 144;
817 int transition_position_ = 0;
818 int loop_position_ = 0;
819 int completed_repeats_ = 0;
820 std::int64_t expected_sample_ = 0;
821 bool prepared_ =
false;
822 bool pending_capture_ =
false;
823 bool active_loop_ =
false;
824 bool alternate_repeat_ =
false;
825 bool last_capture_rejected_ =
false;
826 bool have_expected_sample_ =
false;
Definition beat_repeat_kernel.hpp:177
bool set_gate(SampleType duty) noexcept
Definition beat_repeat_kernel.hpp:335
int loop_length() const noexcept
Definition beat_repeat_kernel.hpp:301
void transport_discontinuity() noexcept
A seek, loop jump, or clock-domain replacement invalidates both pending grid ownership and the contin...
Definition beat_repeat_kernel.hpp:424
BeatRepeatPlanResult trigger(const timebase::CompiledTempoMap &tempo, timebase::BeatDivision division, timebase::SamplePosition requested_sample) noexcept
Definition beat_repeat_kernel.hpp:360
bool last_capture_rejected() const noexcept
Definition beat_repeat_kernel.hpp:295
BeatRepeatKernelT(BeatRepeatKernelT &&other) noexcept
Definition beat_repeat_kernel.hpp:230
Status status() const noexcept
Definition beat_repeat_kernel.hpp:292
BeatRepeatKernelT & operator=(BeatRepeatKernelT &&other) noexcept
Definition beat_repeat_kernel.hpp:233
void stop() noexcept
Definition beat_repeat_kernel.hpp:383
bool seek(int captured_frame) noexcept
Definition beat_repeat_kernel.hpp:396
bool set_reverse(ReverseMode mode) noexcept
Definition beat_repeat_kernel.hpp:342
ReverseMode
Definition beat_repeat_kernel.hpp:179
@ On
Definition beat_repeat_kernel.hpp:181
@ Alternate
Definition beat_repeat_kernel.hpp:182
@ Off
Definition beat_repeat_kernel.hpp:180
int latency_samples() const noexcept
Definition beat_repeat_kernel.hpp:310
int history_capacity_frames() const noexcept
Definition beat_repeat_kernel.hpp:286
int channels() const noexcept
Definition beat_repeat_kernel.hpp:283
Snapshot snapshot() const
Definition beat_repeat_kernel.hpp:470
int max_tail_samples() const noexcept
Definition beat_repeat_kernel.hpp:313
int completed_repeats() const noexcept
Definition beat_repeat_kernel.hpp:307
void process(const SampleType *const *input, SampleType *const *output, int frames, timebase::SamplePosition block_start) noexcept
Definition beat_repeat_kernel.hpp:428
void reset() noexcept
Definition beat_repeat_kernel.hpp:406
int loop_position() const noexcept
Definition beat_repeat_kernel.hpp:304
std::size_t retained_bytes() const noexcept
Definition beat_repeat_kernel.hpp:316
bool restore(const Snapshot &value)
Definition beat_repeat_kernel.hpp:499
bool prepare(const Config &config)
Definition beat_repeat_kernel.hpp:241
TransitionKind
Definition beat_repeat_kernel.hpp:193
@ None
Definition beat_repeat_kernel.hpp:194
@ DryToWet
Definition beat_repeat_kernel.hpp:195
@ HeldToDry
Definition beat_repeat_kernel.hpp:197
@ HeldToWet
Definition beat_repeat_kernel.hpp:196
bool can_snapshot() const noexcept
Definition beat_repeat_kernel.hpp:298
BeatRepeatKernelT()=default
BeatRepeatKernelT(const BeatRepeatKernelT &)=delete
bool set_transition_frames(int frames) noexcept
Definition beat_repeat_kernel.hpp:351
Status
Definition beat_repeat_kernel.hpp:185
@ Active
Definition beat_repeat_kernel.hpp:189
@ Releasing
Definition beat_repeat_kernel.hpp:190
@ Armed
Definition beat_repeat_kernel.hpp:187
@ CaptureRejectedInsufficientHistory
Definition beat_repeat_kernel.hpp:188
@ Idle
Definition beat_repeat_kernel.hpp:186
BeatRepeatKernelT & operator=(const BeatRepeatKernelT &)=delete
bool set_repeat_count(int count) noexcept
Definition beat_repeat_kernel.hpp:322
bool prepared() const noexcept
Definition beat_repeat_kernel.hpp:280
int available_history_frames() const noexcept
Definition beat_repeat_kernel.hpp:289
Definition freeze_loop_sampler.hpp:33
@ Success
Definition freeze_loop_sampler.hpp:38
void prepare(int channels, int capacity, int crossfade)
Definition freeze_loop_sampler.hpp:52
int capacity() const noexcept
Definition freeze_loop_sampler.hpp:98
int channels() const noexcept
Definition freeze_loop_sampler.hpp:95
Definition compiled_tempo_map.hpp:91
Capture-and-loop "freeze": snapshot a slice of recent audio and play it back as a seamless loop.
@ index
Definition gpu_pass.hpp:140
bool beat_repeat_checked_add(std::int64_t lhs, std::int64_t rhs, std::int64_t &result) noexcept
Definition beat_repeat_kernel.hpp:66
bool beat_repeat_checked_subtract(std::int64_t lhs, std::int64_t rhs, std::int64_t &result) noexcept
Definition beat_repeat_kernel.hpp:76
bool beat_repeat_ceil_tick(std::int64_t value, std::int64_t quantum, std::int64_t &result) noexcept
Definition beat_repeat_kernel.hpp:86
Definition additive_bank.hpp:218
BeatRepeatPlanError
Definition beat_repeat_kernel.hpp:35
@ InvalidDivision
Definition beat_repeat_kernel.hpp:37
@ StaleRequest
Definition beat_repeat_kernel.hpp:45
@ ReleaseInProgress
Definition beat_repeat_kernel.hpp:44
@ None
Definition beat_repeat_kernel.hpp:36
@ SampleRateMismatch
Definition beat_repeat_kernel.hpp:43
@ HistoryCapacityExceeded
Definition beat_repeat_kernel.hpp:41
@ SampleRangeExceeded
Definition beat_repeat_kernel.hpp:39
@ Unprepared
Definition beat_repeat_kernel.hpp:42
@ CaptureRangeExceeded
Definition beat_repeat_kernel.hpp:40
@ TickRangeExceeded
Definition beat_repeat_kernel.hpp:38
BeatRepeatKernelT< double > BeatRepeatKernel64
Definition beat_repeat_kernel.hpp:830
BeatRepeatPlanResult lower_beat_repeat_capture(const timebase::CompiledTempoMap &tempo, timebase::BeatDivision division, timebase::SamplePosition requested_sample) noexcept
Lower the first grid edge strictly after requested_sample and the exact preceding grid interval into ...
Definition beat_repeat_kernel.hpp:105
@ EqualGain
(1−u, u) — amplitude sum == 1.
Definition crossfade.hpp:42
@ maximum
Definition spectrum_trace.hpp:34
constexpr T crossfade_smoothstep(T t) noexcept
Smoothstep progress shaping: cubic 3u²−2u³ with zero slope at both ends, clamped to [0,...
Definition crossfade.hpp:50
BeatRepeatKernelT< float > BeatRepeatKernel
Definition beat_repeat_kernel.hpp:829
void crossfade_gains(T u, CrossfadeGainLaw law, T &old_gain, T &new_gain) noexcept
Old/new blend gains for an ALREADY-SHAPED progress u (the caller applies any smoothstep/clamp first).
Definition crossfade.hpp:61
BeatDivision
Definition beat_division.hpp:15
runtime::Result< TickDuration, BeatDivisionError > division_ticks(BeatDivision division) noexcept
Definition beat_division.hpp:88
@ value
the widget's primary value (Knob, Fader, RangeSlider, Toggle, ProgressBar)
Definition binding_diagnostics.hpp:19
@ t
Definition input_events.hpp:41
Definition beat_repeat_kernel.hpp:48
constexpr auto operator<=>(const BeatRepeatCapturePlan &) const =default
timebase::SamplePosition requested_sample
Definition beat_repeat_kernel.hpp:49
timebase::SamplePosition edge_sample
Definition beat_repeat_kernel.hpp:50
int capture_frames
Definition beat_repeat_kernel.hpp:52
timebase::TickPosition edge_tick
Definition beat_repeat_kernel.hpp:51
Definition beat_repeat_kernel.hpp:200
int transition_frames
Definition beat_repeat_kernel.hpp:203
int channels
Definition beat_repeat_kernel.hpp:201
timebase::RationalRate sample_rate
Definition beat_repeat_kernel.hpp:204
int history_capacity_frames
Definition beat_repeat_kernel.hpp:202
Definition beat_repeat_kernel.hpp:207
std::vector< SampleType > sampler
Definition beat_repeat_kernel.hpp:222
int loop_position
Definition beat_repeat_kernel.hpp:213
std::vector< SampleType > transition_old
Definition beat_repeat_kernel.hpp:224
int transition_position
Definition beat_repeat_kernel.hpp:220
int completed_repeats
Definition beat_repeat_kernel.hpp:214
int transition_frames
Definition beat_repeat_kernel.hpp:219
int repeat_count
Definition beat_repeat_kernel.hpp:210
bool resumable
Definition beat_repeat_kernel.hpp:208
bool last_capture_rejected
Definition beat_repeat_kernel.hpp:217
std::vector< SampleType > last_output
Definition beat_repeat_kernel.hpp:223
bool alternate_repeat
Definition beat_repeat_kernel.hpp:215
SampleType gate
Definition beat_repeat_kernel.hpp:211
timebase::RationalRate sample_rate
Definition beat_repeat_kernel.hpp:209
TransitionKind transition
Definition beat_repeat_kernel.hpp:218
bool active
Definition beat_repeat_kernel.hpp:216
ReverseMode reverse
Definition beat_repeat_kernel.hpp:212
int transition_length
Definition beat_repeat_kernel.hpp:221
Definition beat_repeat_kernel.hpp:56
BeatRepeatCapturePlan plan
Definition beat_repeat_kernel.hpp:57
BeatRepeatPlanError error
Definition beat_repeat_kernel.hpp:58
Definition rational_time.hpp:14
Definition rational_time.hpp:9
Shared click-free crossfade primitive.