96 return prepare_impl(profile, 0, 0,
false,
nullptr) ==
102 return prepare_impl(config.profile, config.channel_count,
103 config.maximum_output_frames,
true,
104 config.external_sinc_bank,
105 config.maximum_runtime_clock_factor,
106 config.maximum_note_pitch_factor);
112 input_src_.release();
113 return_src_.release();
114 live_cyclic_.release();
115 voice_dsp_.release();
116 sinc_bank_.release();
117 std::vector<float>().swap(machine_scratch_);
118 std::vector<float>().swap(pre_live_scratch_);
119 std::vector<float>().swap(dynamic_identity_delay_);
120 machine_ptrs_.fill(
nullptr);
121 machine_const_ptrs_.fill(
nullptr);
122 pre_live_ptrs_.fill(
nullptr);
123 pre_live_const_ptrs_.fill(
nullptr);
125 exact_prepared_ =
false;
126 all_bypassed_ =
false;
127 typed_voice_ =
false;
128 live_cyclic_active_ =
false;
129 runtime_dynamic_clock_ =
false;
130 dynamic_identity_exact_ =
false;
131 dynamic_identity_epoch_ =
false;
132 dynamic_identity_delay_frames_ = 0;
133 dynamic_identity_delay_head_ = 0;
134 dynamic_return_latency_output_frames_ = 0.0;
135 dynamic_input_latency_machine_frames_ = 0.0;
136 dynamic_return_src_latency_output_frames_ = 0.0;
137 input_identity_ =
true;
138 return_identity_ =
true;
140 maximum_output_frames_ = 0;
141 maximum_input_frames_ = 0;
142 maximum_machine_frames_ = 0;
143 maximum_pre_live_machine_frames_ = 0;
144 maximum_runtime_clock_factor_ = 1.0;
145 maximum_artifact_clock_factor_ = 1.0;
146 maximum_note_pitch_factor_ = 1.0;
147 machine_sample_rate_ = 0.0;
149 clocked_sample_rate_ = 0.0;
152 process_sequence_ = 0;
153 last_valid_output_frames_ = 0;
155 if (prepare_epoch_ == 0) ++prepare_epoch_;
159 if (!prepared_)
return;
160 for (std::size_t index = 0; index < profile_.stage_count; ++index) {
161 auto&
runtime = stages_[index];
162 runtime.filter_state.fill(0.0f);
165 std::visit([&](
const auto& stage)
noexcept {
166 using Stage = std::decay_t<
decltype(stage)>;
167 if constexpr (std::is_same_v<Stage, SampleHeritageNoiseStage> ||
168 std::is_same_v<Stage, SampleHeritageQuantizationStage>) {
169 if (stage.seed_policy ==
171 runtime.random_state = stage.seed;
177 live_cyclic_.reset();
179 std::fill(dynamic_identity_delay_.begin(),
180 dynamic_identity_delay_.end(), 0.0f);
181 dynamic_identity_delay_head_ = 0;
182 dynamic_identity_epoch_ = dynamic_identity_exact_;
183 process_sequence_ = 0;
184 last_valid_output_frames_ = 0;
186 if (prepare_epoch_ == 0) ++prepare_epoch_;
189 bool prepared() const noexcept {
return prepared_; }
192 return maximum_input_frames_;
195 return maximum_machine_frames_;
198 return maximum_pre_live_machine_frames_;
201 return live_cyclic_.resources();
212 if (!exact_prepared_)
return 0.0;
213 if (!valid_runtime_clock_multiplier(runtime_clock_multiplier))
return 0.0;
214 if (all_bypassed_ && !runtime_dynamic_clock_)
return 0.0;
215 if (runtime_dynamic_clock_)
216 return dynamic_return_latency_output_frames_;
217 constexpr double half =
219 const auto input_latency = input_identity_ ? 0.0 : half;
220 const auto effective_return_ratio = return_ratio_ *
221 runtime_clock_multiplier;
222 const auto return_latency =
223 return_identity_ ? 0.0 : half / effective_return_ratio;
224 return input_latency + return_latency;
230 if (!exact_prepared_ || (all_bypassed_ && !runtime_dynamic_clock_))
233 long double machine_frames = typed_voice_
234 ?
static_cast<long double>(voice_dsp_.tail_machine_domain_frames())
236 const auto host_frames = typed_voice_
237 ?
static_cast<long double>(voice_dsp_.tail_host_frames())
239 for (std::size_t index = 0; index < profile_.stage_count; ++index) {
240 const auto&
runtime = stages_[index];
244 [&](
const auto& stage)
noexcept {
245 using Stage = std::decay_t<
decltype(stage)>;
246 if constexpr (std::is_same_v<Stage, SampleHeritageDacHoldStage>) {
247 machine_frames += stage.hold_samples;
248 }
else if constexpr (std::is_same_v<Stage,
250 const auto pole =
static_cast<long double>(
runtime.filter_pole);
251 if (pole > 0.0L && pole < 1.0L) {
252 constexpr long double reference_peak = 16.0L;
253 machine_frames += std::ceil(
254 std::log(
static_cast<long double>(
264 std::min(machine_frames, std::ceil(
static_cast<long double>(machine_sample_rate_) *
266 if (live_cyclic_active_)
267 machine_frames +=
static_cast<long double>(live_cyclic_.remaining_output_frames());
268 if (live_cyclic_active_) {
270 static_cast<long double>(input_src_.remaining_valid_output_frames()) /
271 static_cast<long double>(live_cyclic_.source_frames_per_output_frame());
274 const auto required_frames =
277 static_cast<long double>(return_ratio_ /
278 maximum_runtime_clock_factor_) +
280 const auto output_frames = std::ceil(required_frames);
281 if (!std::isfinite(output_frames) || output_frames <= 0.0L)
282 return output_frames <= 0.0L ? 0 : std::numeric_limits<std::uint64_t>::max();
283 if (output_frames >=
static_cast<long double>(std::numeric_limits<std::uint64_t>::max()))
284 return std::numeric_limits<std::uint64_t>::max();
285 return static_cast<std::uint64_t
>(output_frames);
291 if (!prepared_ || exact_prepared_ || !input_identity_ || !return_identity_ ||
292 buffer.num_channels() == 0 ||
296 process_machine_stages(buffer);
298 voice_dsp_.process_host_frame(buffer);
307 std::size_t output_frames,
308 double runtime_clock_multiplier)
const noexcept {
309 return plan_exact(output_frames, runtime_clock_multiplier, 1.0);
313 std::size_t output_frames,
314 double runtime_clock_multiplier,
315 double note_pitch_multiplier)
const noexcept {
318 result.
sequence = process_sequence_;
322 if (!exact_prepared_)
return result;
323 if (!valid_runtime_rate_multipliers(runtime_clock_multiplier,
324 note_pitch_multiplier)) {
328 if (output_frames > maximum_output_frames_) {
332 if (all_bypassed_ && !runtime_dynamic_clock_) {
337 if (dynamic_identity_epoch_ && runtime_clock_multiplier == 1.0 &&
338 note_pitch_multiplier == 1.0) {
343 const auto return_plan = return_src_.plan(
344 output_frames, return_ratio_ * runtime_clock_multiplier *
345 note_pitch_multiplier);
346 if (!return_plan.valid()) {
352 if (live_cyclic_active_) {
354 if (!live_plan.valid()) {
360 const auto input_plan = input_src_.plan(
362 input_ratio_ / runtime_clock_multiplier);
363 if (!input_plan.valid() || result.
machine_frames > maximum_machine_frames_ ||
365 input_plan.input_frames > maximum_input_frames_) {
378 return process_exact_impl(plan, input, output,
false,
379 input.num_samples(),
false);
386 std::size_t valid_input_frames,
387 bool end_of_source)
noexcept {
388 return process_exact_impl(plan, input, output,
false,
389 valid_input_frames, end_of_source);
393 return last_valid_output_frames_;
402 for (std::size_t channel = 0; channel < input.num_channels(); ++channel)
403 for (
const auto sample : input.channel(channel))
406 return process_exact_impl(plan, input, output,
true, 0,
true);
415 std::size_t valid_input_frames,
416 bool end_of_source)
noexcept {
418 const auto expected =
plan_exact(output.num_samples(),
419 plan.runtime_clock_multiplier,
420 plan.note_pitch_multiplier);
421 if (!plan.valid() || !expected.valid() ||
422 plan.prepare_epoch != expected.prepare_epoch ||
423 plan.sequence != expected.sequence ||
424 plan.output_frames != expected.output_frames ||
425 plan.machine_frames != expected.machine_frames ||
426 plan.pre_live_machine_frames != expected.pre_live_machine_frames ||
427 plan.input_frames != expected.input_frames ||
428 plan.runtime_clock_multiplier != expected.runtime_clock_multiplier ||
429 plan.note_pitch_multiplier != expected.note_pitch_multiplier) {
432 if (input.num_channels() != channel_count_ ||
433 output.num_channels() != channel_count_) {
436 if (input.num_samples() != plan.input_frames)
438 if (valid_input_frames > input.num_samples())
440 last_valid_output_frames_ = output.num_samples();
442 if (all_bypassed_ && !runtime_dynamic_clock_) {
443 for (std::size_t channel = 0; channel < channel_count_; ++channel)
444 std::copy(input.channel(channel).begin(), input.channel(channel).end(),
445 output.channel(channel).begin());
448 last_valid_output_frames_ =
449 std::min(output.num_samples(), valid_input_frames);
452 if (dynamic_identity_epoch_ &&
453 plan.runtime_clock_multiplier == 1.0 &&
454 plan.note_pitch_multiplier == 1.0) {
455 for (std::size_t channel = 0; channel < channel_count_; ++channel)
456 std::copy(input.channel(channel).begin(),
457 input.channel(channel).end(),
458 output.channel(channel).begin());
459 process_dynamic_latency_delay(output,
460 dynamic_identity_delay_frames_);
463 std::min(output.num_samples(), valid_input_frames);
464 last_valid_output_frames_ =
valid + std::min(
465 output.num_samples() - valid,
466 dynamic_identity_delay_frames_);
472 auto* prepared_ptrs = live_cyclic_active_ ? pre_live_ptrs_.data() : machine_ptrs_.data();
473 BufferView<float> prepared_machine(prepared_ptrs, channel_count_,
474 plan.pre_live_machine_frames);
475 const auto effective_input_ratio =
476 input_ratio_ / plan.runtime_clock_multiplier;
477 const auto input_status = live_cyclic_active_
478 ? input_src_.process_source(input, prepared_machine,
479 valid_input_frames, end_of_source,
480 effective_input_ratio)
481 : input_src_.process(input, prepared_machine,
482 effective_input_ratio);
485 BufferView<float> machine(machine_ptrs_.data(), channel_count_, plan.machine_frames);
486 if (live_cyclic_active_) {
487 const auto valid_pre_live_frames = input_src_.last_valid_output_frames();
488 BufferView<float> valid_pre_live(pre_live_ptrs_.data(), channel_count_,
489 valid_pre_live_frames);
490 voice_dsp_.process_before_live(valid_pre_live, draining_tail);
491 if (valid_pre_live_frames < plan.pre_live_machine_frames) {
492 for (std::size_t channel = 0; channel < channel_count_; ++channel)
493 std::fill(pre_live_ptrs_[channel] + valid_pre_live_frames,
494 pre_live_ptrs_[channel] + plan.pre_live_machine_frames, 0.0f);
496 BufferView<const float> live_input(pre_live_const_ptrs_.data(), channel_count_,
497 plan.pre_live_machine_frames);
498 const auto live_end_of_source = end_of_source && input_src_.source_drained();
499 if (live_cyclic_.process(live_input, machine, valid_pre_live_frames,
502 if (live_end_of_source) {
503 const auto valid_machine = live_cyclic_.last_valid_output_frames();
504 const auto converted = std::ceil(
static_cast<double>(valid_machine) /
505 (return_ratio_ * plan.runtime_clock_multiplier *
506 plan.note_pitch_multiplier));
507 last_valid_output_frames_ =
508 static_cast<std::size_t
>(std::min<double>(output.num_samples(), converted));
510 voice_dsp_.process_after_live(machine, draining_tail);
512 process_machine_stages(machine, draining_tail);
514 BufferView<const float> machine_input(machine_const_ptrs_.data(), channel_count_,
515 plan.machine_frames);
516 if (return_src_.process(machine_input, output,
517 return_ratio_ * plan.runtime_clock_multiplier *
518 plan.note_pitch_multiplier) !=
522 voice_dsp_.process_host_frame(output, draining_tail);
523 if (runtime_dynamic_clock_) {
524 const auto effective_return_ratio = return_ratio_ *
525 plan.runtime_clock_multiplier * plan.note_pitch_multiplier;
526 const auto active_input_latency =
527 input_identity_ && maximum_artifact_clock_factor_ == 1.0
529 : dynamic_input_latency_machine_frames_;
530 const auto raw_latency =
static_cast<std::size_t
>(std::ceil(
531 active_input_latency /
532 effective_return_ratio)) +
533 static_cast<std::size_t
>(
534 dynamic_return_src_latency_output_frames_);
535 const auto correction = raw_latency < dynamic_identity_delay_frames_
536 ? dynamic_identity_delay_frames_ - raw_latency
538 process_dynamic_latency_delay(output, correction);
540 last_valid_output_frames_ < output.num_samples())
541 last_valid_output_frames_ += std::min(
542 output.num_samples() - last_valid_output_frames_,
544 if (plan.runtime_clock_multiplier != 1.0 ||
545 plan.note_pitch_multiplier != 1.0)
546 dynamic_identity_epoch_ =
false;
559 if (!prepared_)
return result;
561 std::copy(profile_.profile_id.begin(), profile_.profile_id.end(),
565 for (std::size_t index = 0; index < profile_.voice_count; ++index) {
566 if (voice_dsp_.converter_continues_state(index)) {
569 saved.stage_index =
static_cast<std::uint8_t
>(index);
572 saved.random_state = voice_dsp_.converter_random_state(index);
576 std::get_if<SampleHeritageVoiceLiveCyclicStretchBlock>(
577 &profile_.voice[index].parameters);
578 if (live ==
nullptr || profile_.voice[index].bypass ||
582 const auto continuation =
583 live_cyclic_.capture_next_cycle_rng_continuation();
584 if (continuation.next_cycle_index ==
585 std::numeric_limits<std::uint64_t>::max())
589 saved.stage_index =
static_cast<std::uint8_t
>(index);
591 saved.random_state = continuation.next_cycle_index + 1;
596 for (std::size_t index = 0; index < profile_.stage_count; ++index) {
597 const auto&
runtime = stages_[index];
599 [&](
const auto& stage)
noexcept {
600 using Stage = std::decay_t<
decltype(stage)>;
601 if constexpr (std::is_same_v<Stage,
603 std::is_same_v<Stage,
605 if (stage.seed_policy !=
610 saved.stage_index =
static_cast<std::uint8_t
>(index);
612 std::is_same_v<Stage, SampleHeritageQuantizationStage>
615 saved.random_state =
runtime.random_state;
631 if (
state.profile_schema_version != profile_.schema_version ||
632 state.bound_profile_id() != profile_.id() ||
634 state.profile_digest != profile_.profile_digest)
638 std::size_t expected_count = 0;
639 for (std::size_t index = 0; index < profile_.voice_count; ++index) {
641 std::get_if<SampleHeritageVoiceLiveCyclicStretchBlock>(
642 &profile_.voice[index].parameters);
643 const auto converter =
644 voice_dsp_.converter_continues_state(index);
645 const auto cyclic = live !=
nullptr &&
646 !profile_.voice[index].bypass &&
649 if (!converter && !cyclic)
continue;
650 if (expected_count >=
state.rng_state_count)
652 const auto& saved =
state.rng_states[expected_count];
653 if (saved.stage_index != index ||
654 saved.stage_type != (converter
657 saved.random_state == 0)
661 if (expected_count !=
state.rng_state_count ||
662 state.rng_state_count >
state.rng_states.size())
665 for (std::size_t index = 0; index <
state.rng_state_count; ++index) {
666 const auto& saved =
state.rng_states[index];
667 if (saved.stage_type ==
669 if (!voice_dsp_.restore_converter_random_state(
670 saved.stage_index, saved.random_state))
674 std::get_if<SampleHeritageVoiceLiveCyclicStretchBlock>(
675 &profile_.voice[saved.stage_index].parameters);
676 if (live ==
nullptr || live->seed == 0)
678 live_cyclic_.reset_with_rng_continuation(
679 {live->seed, saved.random_state - 1});
685 std::size_t expected_count = 0;
686 for (std::size_t index = 0; index < profile_.stage_count; ++index) {
687 const auto expected = std::visit(
688 [](
const auto& stage)
noexcept
689 -> std::pair<bool, SampleHeritageRuntimeRngStageType> {
690 using Stage = std::decay_t<
decltype(stage)>;
691 if constexpr (std::is_same_v<Stage,
693 return {stage.seed_policy ==
696 if constexpr (std::is_same_v<Stage, SampleHeritageNoiseStage>)
697 return {stage.seed_policy ==
702 stages_[index].spec.parameters);
703 if (!expected.first)
continue;
704 if (expected_count >=
state.rng_state_count)
706 const auto& saved =
state.rng_states[expected_count];
707 if (saved.stage_index != index || saved.stage_type != expected.second)
709 if (saved.random_state == 0)
713 if (expected_count !=
state.rng_state_count ||
714 state.rng_state_count >
state.rng_states.size())
718 for (std::size_t index = 0; index <
state.rng_state_count; ++index) {
719 const auto& saved =
state.rng_states[index];
720 stages_[saved.stage_index].random_state = saved.random_state;
726 struct RuntimeStage {
728 std::uint64_t random_state = 0;
729 float filter_pole = 0.0f;
730 std::array<float, kSampleHeritageMaximumChannels> filter_state{};
731 std::array<float, kSampleHeritageMaximumChannels> hold_value{};
732 std::array<std::uint32_t, kSampleHeritageMaximumChannels> hold_phase{};
736 const SampleHeritagePreparedProfile& profile,
737 std::size_t channel_count,
738 std::size_t maximum_output_frames,
740 const SampleSincKernelBankView* external_sinc_bank,
741 double maximum_runtime_clock_factor = 1.0) noexcept {
742 return prepare_impl(profile, channel_count, maximum_output_frames,
743 exact, external_sinc_bank,
744 maximum_runtime_clock_factor, 1.0);
748 const SampleHeritagePreparedProfile& profile,
749 std::size_t channel_count,
750 std::size_t maximum_output_frames,
752 const SampleSincKernelBankView* external_sinc_bank,
753 double maximum_runtime_clock_factor,
754 double maximum_note_pitch_factor)
noexcept {
757 profile.stage_count > stages_.size() ||
758 !(profile.host_sample_rate > 0.0) ||
759 !std::isfinite(profile.host_sample_rate)) {
762 if (exact && (channel_count == 0 ||
764 maximum_output_frames == 0 ||
765 !(maximum_runtime_clock_factor >= 1.0) ||
766 maximum_runtime_clock_factor > 64.0 ||
767 !std::isfinite(maximum_runtime_clock_factor) ||
768 !(maximum_note_pitch_factor >= 1.0) ||
769 maximum_note_pitch_factor > 64.0 ||
770 !std::isfinite(maximum_note_pitch_factor) ||
771 maximum_runtime_clock_factor *
772 maximum_note_pitch_factor >
777 SampleHeritageProfile authoring;
778 authoring.schema_version = profile.schema_version;
779 authoring.profile_id = std::string(profile.id());
780 authoring.host_sample_rate = profile.host_sample_rate;
781 if (profile.voice_count != 0 || profile.bus_count != 0 ||
782 profile.record_commit_count != 0) {
783 authoring.voice.assign(
784 profile.voice.begin(),
785 profile.voice.begin() +
786 static_cast<std::ptrdiff_t
>(profile.voice_count));
787 authoring.bus.assign(
789 profile.bus.begin() +
790 static_cast<std::ptrdiff_t
>(profile.bus_count));
791 authoring.record_commit.assign(
792 profile.record_commit.begin(),
793 profile.record_commit.begin() +
794 static_cast<std::ptrdiff_t
>(profile.record_commit_count));
796 authoring.stages.assign(
797 profile.stages.begin(),
798 profile.stages.begin() +
799 static_cast<std::ptrdiff_t
>(profile.stage_count));
802 if (!validated.valid() ||
803 validated.profile.profile_digest != profile.profile_digest)
805 profile_ = validated.profile;
810 machine_sample_rate_ = profile_.host_sample_rate;
812 all_bypassed_ =
true;
813 typed_voice_ = profile_.voice_count != 0;
815 for (std::size_t index = 0;
index < profile_.voice_count; ++
index) {
816 const auto& spec = profile_.voice[
index];
817 all_bypassed_ = all_bypassed_ && spec.bypass;
818 if (spec.bypass)
continue;
819 if (
const auto* machine =
820 std::get_if<SampleHeritageVoiceMachineDomainBlock>(
822 machine_sample_rate_ = machine->sample_rate;
823 else if (
const auto* clock =
824 std::get_if<SampleHeritageVoiceClockBlock>(
826 clock_ratio_ = clock->ratio;
829 for (std::size_t index = 0;
index < profile_.stage_count; ++
index) {
830 const auto& spec = profile_.stages[
index];
831 all_bypassed_ = all_bypassed_ && spec.bypass;
832 if (spec.bypass)
continue;
833 if (
const auto* machine =
834 std::get_if<SampleHeritageMachineDomainStage>(
836 machine_sample_rate_ = machine->sample_rate;
837 else if (
const auto* clock =
838 std::get_if<SampleHeritageClockPitchStage>(
840 clock_ratio_ = clock->ratio;
843 clocked_sample_rate_ = machine_sample_rate_ * clock_ratio_;
844 input_ratio_ = profile_.host_sample_rate / clocked_sample_rate_;
845 return_ratio_ = clocked_sample_rate_ / profile_.host_sample_rate;
846 input_identity_ = clocked_sample_rate_ == profile_.host_sample_rate;
847 return_identity_ = clocked_sample_rate_ == profile_.host_sample_rate;
848 if ((!input_identity_ && input_ratio_ >
850 (!return_identity_ && return_ratio_ >
852 !std::isfinite(input_ratio_) || !std::isfinite(return_ratio_)) {
856 if (!exact && (!input_identity_ || !return_identity_)) {
861 for (std::size_t index = 0;
index < profile_.stage_count; ++
index) {
863 initialize_seed(stages_[index]);
864 if (
const auto* filter =
865 std::get_if<SampleHeritageReconstructionFilterStage>(
866 &stages_[index].spec.parameters)) {
867 stages_[
index].filter_pole =
static_cast<float>(
868 std::exp(-2.0 * 3.14159265358979323846 * filter->cutoff_hz /
869 clocked_sample_rate_));
873 !voice_dsp_.prepare(profile_, machine_sample_rate_,
874 profile_.host_sample_rate)) {
878 live_cyclic_active_ = typed_voice_ && voice_dsp_.live_stage_active();
879 if (live_cyclic_active_ && !exact) {
885 const auto maximum_combined_factor =
886 maximum_runtime_clock_factor * maximum_note_pitch_factor;
887 runtime_dynamic_clock_ = maximum_combined_factor > 1.0;
888 const auto maximum_return_ratio =
889 return_ratio_ * maximum_combined_factor;
890 const auto maximum_input_ratio =
891 input_ratio_ * maximum_runtime_clock_factor;
892 const auto maximum_ratio =
893 std::max(maximum_input_ratio, maximum_return_ratio);
894 SampleSincKernelBankView bank;
895 if (external_sinc_bank !=
nullptr) {
896 bank = *external_sinc_bank;
901 }
else if (!input_identity_ || !return_identity_ ||
902 runtime_dynamic_clock_) {
903 if (!sinc_bank_.build_dense_for_maximum_consumption(
908 bank = sinc_bank_.view();
910 const auto input_selection = input_identity_ &&
911 maximum_runtime_clock_factor == 1.0
912 ? SampleSincKernelSelection{}
913 : bank.select(input_ratio_);
914 const auto return_selection = return_identity_
915 ? SampleSincKernelSelection{}
916 : bank.select(return_ratio_);
917 if ((!(input_identity_ && maximum_runtime_clock_factor == 1.0) &&
918 !input_selection.valid()) ||
919 (!return_identity_ && !return_selection.valid())) {
923 const auto input_status = maximum_runtime_clock_factor == 1.0
924 ? input_src_.prepare(input_ratio_, channel_count,
925 input_selection, input_identity_)
926 : input_src_.prepare_variable(
928 input_ratio_ / maximum_runtime_clock_factor,
929 maximum_input_ratio, channel_count, bank);
930 const auto return_status = maximum_combined_factor == 1.0
931 ? return_src_.prepare(return_ratio_, channel_count,
932 return_selection, return_identity_)
933 : return_src_.prepare_variable(return_ratio_,
935 maximum_combined_factor,
936 maximum_return_ratio,
937 channel_count, bank);
943 const auto overflow =
953 if (!checked_frame_bound(maximum_output_frames,
954 maximum_return_ratio,
956 maximum_combined_factor == 1.0,
957 maximum_machine_frames_) ||
958 (channel_count != 0 && maximum_machine_frames_ >
959 std::numeric_limits<std::size_t>::max() / channel_count)) {
963 maximum_pre_live_machine_frames_ = maximum_machine_frames_;
964 if (live_cyclic_active_) {
965 const auto live_index = voice_dsp_.live_stage_index();
967 std::get_if<SampleHeritageVoiceLiveCyclicStretchBlock>(
968 &profile_.voice[live_index].parameters);
969 std::size_t cycle_samples = 0;
970 std::size_t splice_samples = 0;
971 if (block ==
nullptr ||
972 !milliseconds_to_machine_frames(
block->cycle_ms,
973 machine_sample_rate_,
975 !milliseconds_to_machine_frames(
block->splice_ms,
976 machine_sample_rate_,
977 splice_samples,
true) ||
978 splice_samples > cycle_samples / 2) {
982 const auto divisions =
block->shuffle_divisions == 0
984 :
static_cast<std::size_t
>(
block->shuffle_divisions);
985 const SampleHeritageLiveCyclicConfig live_config{
986 .factor =
block->factor,
987 .cycle_samples = cycle_samples,
988 .crossfade_samples = splice_samples,
989 .shuffle_divisions = divisions,
990 .linked_channels =
block->stereo_link,
992 .shuffle =
block->shuffle_divisions == 0
995 .max_block_samples = maximum_machine_frames_,
996 .channel_count = channel_count,
997 .pitch_mode =
block->pitch_mode,
998 .tempo_lock =
block->tempo_lock};
999 const auto live_status = live_cyclic_.prepare(live_config);
1002 return live_status ==
1007 maximum_pre_live_machine_frames_ =
1008 live_cyclic_.resources().maximum_input_frames;
1009 if (maximum_pre_live_machine_frames_ == 0) {
1014 if (!checked_frame_bound(maximum_pre_live_machine_frames_,
1016 maximum_runtime_clock_factor,
1018 maximum_combined_factor == 1.0,
1019 maximum_input_frames_) ||
1020 (channel_count != 0 && maximum_pre_live_machine_frames_ >
1021 std::numeric_limits<std::size_t>::max() / channel_count)) {
1026 machine_scratch_.assign(channel_count * maximum_machine_frames_, 0.0f);
1027 if (live_cyclic_active_)
1028 pre_live_scratch_.assign(
1029 channel_count * maximum_pre_live_machine_frames_, 0.0f);
1030 dynamic_identity_exact_ = runtime_dynamic_clock_ &&
1031 runtime_clock_identity_only() &&
1032 input_identity_ && return_ratio_ == 1.0;
1033 dynamic_input_latency_machine_frames_ = runtime_dynamic_clock_
1036 (input_ratio_ / maximum_runtime_clock_factor))
1038 dynamic_return_src_latency_output_frames_ = runtime_dynamic_clock_
1041 (return_ratio_ / maximum_combined_factor))
1043 dynamic_return_latency_output_frames_ = runtime_dynamic_clock_
1044 ? std::ceil(dynamic_input_latency_machine_frames_ /
1046 maximum_combined_factor)) +
1047 dynamic_return_src_latency_output_frames_
1049 dynamic_identity_delay_frames_ = runtime_dynamic_clock_
1050 ?
static_cast<std::size_t
>(
1051 dynamic_return_latency_output_frames_)
1053 dynamic_identity_delay_.assign(
1054 channel_count * dynamic_identity_delay_frames_, 0.0f);
1059 for (std::size_t channel = 0; channel < channel_count; ++channel) {
1060 auto* pointer = machine_scratch_.data() +
1061 channel * maximum_machine_frames_;
1062 machine_ptrs_[channel] = pointer;
1063 machine_const_ptrs_[channel] = pointer;
1064 if (live_cyclic_active_) {
1065 auto* pre_live = pre_live_scratch_.data() +
1066 channel * maximum_pre_live_machine_frames_;
1067 pre_live_ptrs_[channel] = pre_live;
1068 pre_live_const_ptrs_[channel] = pre_live;
1071 channel_count_ = channel_count;
1072 maximum_output_frames_ = maximum_output_frames;
1073 maximum_runtime_clock_factor_ = maximum_combined_factor;
1074 maximum_artifact_clock_factor_ =
1075 maximum_runtime_clock_factor;
1076 maximum_note_pitch_factor_ = maximum_note_pitch_factor;
1077 exact_prepared_ =
true;
1078 dynamic_identity_epoch_ = dynamic_identity_exact_;
1082 process_sequence_ = 0;
1084 if (prepare_epoch_ == 0) ++prepare_epoch_;
1088 static bool checked_frame_bound(std::size_t output_frames,
1091 std::size_t& result)
noexcept {
1093 result = output_frames;
1096 const auto frames = std::ceil(
static_cast<double>(output_frames) * ratio);
1097 if (!std::isfinite(frames) || frames < 0.0 ||
1098 frames >=
static_cast<double>(std::numeric_limits<std::size_t>::max()))
1100 result =
static_cast<std::size_t
>(frames) + 1;
1106 static bool milliseconds_to_machine_frames(
double milliseconds,
1108 std::size_t& result,
1109 bool allow_zero =
false) noexcept {
1110 const auto frames = std::floor(milliseconds * sample_rate * 0.001 + 0.5);
1111 if (!std::isfinite(frames) || frames < 0.0 ||
1112 frames >=
static_cast<double>(std::numeric_limits<std::size_t>::max()) ||
1113 (!allow_zero && frames < 1.0))
1115 result =
static_cast<std::size_t
>(frames);
1119 bool valid_runtime_clock_multiplier(
double multiplier)
const noexcept {
1120 return std::isfinite(multiplier) &&
1121 multiplier >= 1.0 / maximum_runtime_clock_factor_ &&
1122 multiplier <= maximum_runtime_clock_factor_;
1125 bool valid_runtime_rate_multipliers(
double clock_multiplier,
1126 double pitch_multiplier)
const noexcept {
1127 if (!(clock_multiplier > 0.0) || !std::isfinite(clock_multiplier) ||
1128 !(pitch_multiplier > 0.0) || !std::isfinite(pitch_multiplier))
1130 return clock_multiplier >= 1.0 / maximum_artifact_clock_factor_ &&
1131 clock_multiplier <= maximum_artifact_clock_factor_ &&
1132 pitch_multiplier >= 1.0 / maximum_note_pitch_factor_ &&
1133 pitch_multiplier <= maximum_note_pitch_factor_;
1136 bool runtime_clock_identity_only() const noexcept {
1137 if (!typed_voice_) {
1138 for (std::size_t index = 0;
index < profile_.stage_count; ++
index) {
1139 const auto& spec = profile_.stages[
index];
1140 if (spec.bypass)
continue;
1142 [&](
const auto& stage)
noexcept {
1143 using Stage = std::decay_t<
decltype(stage)>;
1144 if constexpr (std::is_same_v<
1146 SampleHeritageMachineDomainStage>)
1147 return stage.sample_rate == profile_.host_sample_rate;
1148 if constexpr (std::is_same_v<
1150 SampleHeritageClockPitchStage>)
1151 return stage.ratio == 1.0;
1155 if (!supported)
return false;
1159 bool has_pitch_marker =
false;
1160 for (std::size_t index = 0;
index < profile_.voice_count; ++
index) {
1161 const auto& spec = profile_.voice[
index];
1162 if (spec.bypass)
continue;
1164 [&](
const auto& block)
noexcept {
1165 using Block = std::decay_t<
decltype(
block)>;
1166 if constexpr (std::is_same_v<
1168 SampleHeritageVoiceMachineDomainBlock>)
1169 return block.sample_rate == profile_.host_sample_rate;
1170 if constexpr (std::is_same_v<Block,
1171 SampleHeritageVoiceClockBlock>)
1172 return block.ratio == 1.0;
1173 if constexpr (std::is_same_v<Block,
1174 SampleHeritageVoicePitchBlock>) {
1175 has_pitch_marker =
true;
1181 if (!supported)
return false;
1183 return has_pitch_marker;
1186 void process_dynamic_latency_delay(BufferView<float> output,
1187 std::size_t delay_frames)
noexcept {
1188 if (dynamic_identity_delay_frames_ == 0)
return;
1189 delay_frames = std::min(delay_frames, dynamic_identity_delay_frames_);
1190 for (std::size_t frame = 0; frame < output.num_samples(); ++frame) {
1191 for (std::size_t channel = 0; channel < channel_count_; ++channel) {
1192 const auto read_index =
1193 (dynamic_identity_delay_head_ +
1194 dynamic_identity_delay_frames_ - delay_frames) %
1195 dynamic_identity_delay_frames_;
1196 auto& destination = dynamic_identity_delay_[
1197 channel * dynamic_identity_delay_frames_ +
1198 dynamic_identity_delay_head_];
1199 const auto delayed = dynamic_identity_delay_[
1200 channel * dynamic_identity_delay_frames_ + read_index];
1201 destination = output.channel(channel)[frame];
1202 if (delay_frames != 0)
1203 output.channel(channel)[frame] = delayed;
1205 dynamic_identity_delay_head_ =
1206 (dynamic_identity_delay_head_ + 1) %
1207 dynamic_identity_delay_frames_;
1211 static void initialize_seed(RuntimeStage& runtime)
noexcept {
1212 std::visit([&](
const auto& stage)
noexcept {
1213 using Stage = std::decay_t<
decltype(stage)>;
1214 if constexpr (std::is_same_v<Stage, SampleHeritageNoiseStage> ||
1215 std::is_same_v<Stage, SampleHeritageQuantizationStage>)
1216 runtime.random_state = stage.seed;
1217 }, runtime.spec.parameters);
1220 void process_machine_stages(BufferView<float> buffer,
1221 bool draining_tail =
false) noexcept {
1224 voice_dsp_.process_machine_tail(buffer);
1226 voice_dsp_.process_before_live(buffer);
1229 for (std::size_t index = 0;
index < profile_.stage_count; ++
index) {
1230 auto& runtime = stages_[
index];
1231 if (runtime.spec.bypass)
continue;
1232 if (draining_tail &&
1233 (std::holds_alternative<SampleHeritageQuantizationStage>(
1234 runtime.spec.parameters) ||
1235 std::holds_alternative<SampleHeritageNoiseStage>(
1236 runtime.spec.parameters)))
1238 std::visit([&](
const auto& stage)
noexcept {
1239 process_stage(runtime, stage, buffer);
1240 }, runtime.spec.parameters);
1244 static void process_stage(RuntimeStage&,
1245 const SampleHeritageMachineDomainStage&,
1246 BufferView<float>)
noexcept {}
1247 static void process_stage(RuntimeStage&,
1248 const SampleHeritageClockPitchStage&,
1249 BufferView<float>)
noexcept {}
1251 static void process_stage(RuntimeStage& runtime,
1252 const SampleHeritageQuantizationStage& stage,
1253 BufferView<float> buffer)
noexcept {
1254 const auto levels =
static_cast<float>(std::uint32_t{1} << (stage.bit_depth - 1));
1255 const auto upper = 1.0f - 1.0f /
levels;
1256 for (std::size_t frame = 0; frame <
buffer.num_samples(); ++frame) {
1257 for (std::size_t channel = 0; channel <
buffer.num_channels(); ++channel) {
1258 auto& sample =
buffer.channel(channel)[frame];
1259 const auto dither = stage.dither_lsb == 0.0f
1262 sample = std::round(std::clamp(sample, -1.0f, upper) * levels + dither) /
1268 static void process_stage(RuntimeStage& runtime,
1269 const SampleHeritageDacHoldStage& stage,
1270 BufferView<float> buffer)
noexcept {
1271 for (std::size_t channel = 0; channel <
buffer.num_channels(); ++channel) {
1272 auto& held = runtime.hold_value[channel];
1273 auto& phase = runtime.hold_phase[channel];
1274 for (
auto& sample :
buffer.channel(channel)) {
1275 if (phase == 0) held = sample;
1277 phase = (phase + 1) % stage.hold_samples;
1282 static void process_stage(RuntimeStage& runtime,
1283 const SampleHeritageReconstructionFilterStage&,
1284 BufferView<float> buffer)
noexcept {
1285 const auto pole = runtime.filter_pole;
1286 for (std::size_t channel = 0; channel <
buffer.num_channels(); ++channel) {
1287 auto previous = runtime.filter_state[channel];
1288 for (
auto& sample :
buffer.channel(channel)) {
1289 previous = (1.0f - pole) * sample + pole * previous;
1292 runtime.filter_state[channel] = previous;
1296 static void process_stage(RuntimeStage& runtime,
1297 const SampleHeritageNoiseStage& stage,
1298 BufferView<float> buffer)
noexcept {
1299 for (std::size_t frame = 0; frame <
buffer.num_samples(); ++frame) {
1300 for (std::size_t channel = 0; channel <
buffer.num_channels(); ++channel) {
1301 buffer.channel(channel)[frame] +=
1307 static void process_stage(RuntimeStage&,
1308 const SampleHeritageOutputStage& stage,
1309 BufferView<float> buffer)
noexcept {
1310 for (std::size_t channel = 0; channel <
buffer.num_channels(); ++channel)
1311 for (
auto& sample :
buffer.channel(channel)) sample *= stage.gain;
1314 SampleHeritagePreparedProfile profile_{};
1315 std::array<RuntimeStage, kSampleHeritageMaximumStages> stages_{};
1316 SampleSincKernelBank sinc_bank_;
1317 SampleHeritageCausalSrc input_src_;
1318 SampleHeritageCausalSrc return_src_;
1319 SampleHeritageLiveCyclicStretch live_cyclic_;
1320 SampleHeritageVoiceDsp voice_dsp_;
1321 std::vector<float> machine_scratch_;
1322 std::vector<float> pre_live_scratch_;
1323 std::vector<float> dynamic_identity_delay_;
1324 std::array<float*, kSampleHeritageMaximumChannels> machine_ptrs_{};
1325 std::array<const float*, kSampleHeritageMaximumChannels> machine_const_ptrs_{};
1326 std::array<float*, kSampleHeritageMaximumChannels> pre_live_ptrs_{};
1327 std::array<const float*, kSampleHeritageMaximumChannels>
1328 pre_live_const_ptrs_{};
1329 bool prepared_ =
false;
1330 bool exact_prepared_ =
false;
1331 bool all_bypassed_ =
false;
1332 bool typed_voice_ =
false;
1333 bool live_cyclic_active_ =
false;
1334 bool input_identity_ =
true;
1335 bool return_identity_ =
true;
1336 bool runtime_dynamic_clock_ =
false;
1337 bool dynamic_identity_exact_ =
false;
1338 bool dynamic_identity_epoch_ =
false;
1339 std::size_t channel_count_ = 0;
1340 std::size_t maximum_output_frames_ = 0;
1341 std::size_t maximum_input_frames_ = 0;
1342 std::size_t maximum_machine_frames_ = 0;
1343 std::size_t maximum_pre_live_machine_frames_ = 0;
1344 double machine_sample_rate_ = 0.0;
1345 double clock_ratio_ = 1.0;
1346 double clocked_sample_rate_ = 0.0;
1347 double input_ratio_ = 1.0;
1348 double return_ratio_ = 1.0;
1349 double maximum_runtime_clock_factor_ = 1.0;
1350 double maximum_artifact_clock_factor_ = 1.0;
1351 double maximum_note_pitch_factor_ = 1.0;
1352 double dynamic_return_latency_output_frames_ = 0.0;
1353 double dynamic_input_latency_machine_frames_ = 0.0;
1354 double dynamic_return_src_latency_output_frames_ = 0.0;
1355 std::size_t dynamic_identity_delay_frames_ = 0;
1356 std::size_t dynamic_identity_delay_head_ = 0;
1357 std::uint64_t prepare_epoch_ = 1;
1358 std::uint64_t process_sequence_ = 0;
1359 std::size_t last_valid_output_frames_ = 0;