4#include "detail/audio_range.hpp"
22 static_assert(MaxPaths > 0);
23 static_assert(std::is_floating_point_v<SampleType>);
26 bool configure(std::size_t paths, std::size_t initial_path, std::size_t fade_samples)
noexcept {
27 if (paths == 0 || paths > MaxPaths || initial_path >= paths)
30 fade_samples_ = fade_samples < 2 ? 0 : fade_samples;
31 selected_path_ = initial_path;
32 position_ = fade_samples_;
33 from_.fill(SampleType{0});
34 weights_.fill(SampleType{0});
35 target_.fill(SampleType{0});
36 weights_[initial_path] = SampleType{1};
37 from_[initial_path] = SampleType{1};
38 target_[initial_path] = SampleType{1};
45 selected_path_ = path;
47 target_.fill(SampleType{0});
48 target_[path] = SampleType{1};
50 if (fade_samples_ == 0) {
58 weights_.fill(SampleType{0});
59 from_.fill(SampleType{0});
60 target_.fill(SampleType{0});
62 weights_[selected_path_] = SampleType{1};
63 from_[selected_path_] = SampleType{1};
64 target_[selected_path_] = SampleType{1};
66 position_ = fade_samples_;
73 return selected_path_;
76 return position_ < fade_samples_;
78 std::span<const SampleType>
weights() const noexcept {
79 return {weights_.data(), paths_};
82 bool next_gains(std::span<SampleType> destination)
noexcept {
83 if (paths_ == 0 || destination.size() < paths_)
85 if (position_ < fade_samples_) {
88 }
else if (position_ + 1 == fade_samples_) {
92 std::conditional_t<(
sizeof(SampleType) <
sizeof(double)),
double,
long double>;
93 const auto t =
static_cast<ProgressType
>(position_) /
94 static_cast<ProgressType
>(fade_samples_ - 1);
96 std::array<ProgressType, MaxPaths> mixed{};
97 ProgressType norm_squared{};
98 for (std::size_t path = 0; path < paths_; ++path) {
99 mixed[path] =
static_cast<ProgressType
>(from_[path]) * (ProgressType{1} -
u) +
100 static_cast<ProgressType
>(target_[path]) *
u;
101 norm_squared += mixed[path] * mixed[path];
103 const auto scale = norm_squared > ProgressType{0}
104 ? ProgressType{1} / std::sqrt(norm_squared)
106 for (std::size_t path = 0; path < paths_; ++path)
107 weights_[path] =
static_cast<SampleType
>(mixed[path] * scale);
111 std::copy_n(weights_.begin(), paths_, destination.begin());
115 bool process(
const SampleType*
const* sources, std::size_t source_count,
116 SampleType* destination, std::size_t frames)
noexcept {
117 if (sources ==
nullptr || destination ==
nullptr || source_count != paths_ || paths_ == 0)
119 for (std::size_t path = 0; path < paths_; ++path)
120 if (sources[path] ==
nullptr ||
121 detail::audio_ranges_overlap(sources[path], destination, frames))
123 std::array<SampleType, MaxPaths> gains{};
124 for (std::size_t frame = 0; frame < frames; ++frame) {
125 next_gains(std::span<SampleType>(gains.data(), paths_));
127 for (std::size_t path = 0; path < paths_; ++path)
128 sum += sources[path][frame] * gains[path];
129 destination[frame] = sum;
135 std::size_t paths_ = 0;
136 std::size_t selected_path_ = 0;
137 std::size_t fade_samples_ = 0;
138 std::size_t position_ = 0;
139 std::array<SampleType, MaxPaths> from_{};
140 std::array<SampleType, MaxPaths> target_{};
141 std::array<SampleType, MaxPaths> weights_{};
Fixed-capacity, click-free path selector.
Definition path_switcher.hpp:20
bool switching() const noexcept
Definition path_switcher.hpp:75
bool configure(std::size_t paths, std::size_t initial_path, std::size_t fade_samples) noexcept
Definition path_switcher.hpp:26
static constexpr std::size_t max_paths
Definition path_switcher.hpp:24
std::span< const SampleType > weights() const noexcept
Definition path_switcher.hpp:78
bool process(const SampleType *const *sources, std::size_t source_count, SampleType *destination, std::size_t frames) noexcept
Definition path_switcher.hpp:115
std::size_t path_count() const noexcept
Definition path_switcher.hpp:69
bool request_path(std::size_t path) noexcept
Definition path_switcher.hpp:42
std::size_t selected_path() const noexcept
Definition path_switcher.hpp:72
void reset() noexcept
Definition path_switcher.hpp:57
bool next_gains(std::span< SampleType > destination) noexcept
Definition path_switcher.hpp:82
The one shared old→new crossfade gain law for the SIGNAL side.
Definition additive_bank.hpp:218
ClickFreePathSwitcherT< double > ClickFreePathSwitcher64
Definition path_switcher.hpp:145
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
@ u
Definition formant_filter_bank.hpp:20
ClickFreePathSwitcherT< float > ClickFreePathSwitcher
Definition path_switcher.hpp:144