Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
soft_bypass.hpp
Go to the documentation of this file.
1#pragma once
2
27
28#include <algorithm>
29#include <cstddef>
30#include <utility>
31
32namespace pulp::signal {
33
34template <typename Processor, typename SampleType = float>
36public:
37 SoftBypassT() = default;
38 explicit SoftBypassT(Processor processor) : processor_(std::move(processor)) {}
39
43 Processor& processor() noexcept { return processor_; }
44 const Processor& processor() const noexcept { return processor_; }
45
47 void set_fade_samples(int samples) noexcept {
48 fade_step_ = SampleType{1.0f} /
49 static_cast<SampleType>(samples < 1 ? 1 : samples);
50 }
51
53 void set_bypassed(bool bypassed) noexcept {
54 target_wet_ = bypassed ? SampleType{0.0f} : SampleType{1.0f};
55 }
56
57 bool bypassed() const noexcept { return target_wet_ <= SampleType{0.0f}; }
59 bool fading() const noexcept { return current_wet_ != target_wet_; }
61 SampleType wet_mix() const noexcept { return current_wet_; }
62
64 SampleType process(SampleType input) noexcept {
65 advance_fade();
66 // Fully bypassed and settled: skip the wrapped processor entirely. The
67 // fade-in on re-engage ramps the wet contribution up from zero, so this
68 // stays click-free despite the processor's state being frozen meanwhile.
69 if (current_wet_ <= SampleType{0.0f}) return input;
70 const SampleType wet = processor_.process(input);
71 if (current_wet_ >= SampleType{1.0f}) return wet;
72 return input * (SampleType{1.0f} - current_wet_) + wet * current_wet_;
73 }
74
76 void process(SampleType* data, int num_samples) noexcept {
77 for (int i = 0; i < num_samples; ++i) data[i] = process(data[i]);
78 }
79
81 void reset() noexcept {
82 if constexpr (requires { processor_.reset(); }) processor_.reset();
83 current_wet_ = target_wet_;
84 }
85
86private:
87 void advance_fade() noexcept {
88 if (current_wet_ < target_wet_) {
89 current_wet_ = std::min(target_wet_, current_wet_ + fade_step_);
90 } else if (current_wet_ > target_wet_) {
91 current_wet_ = std::max(target_wet_, current_wet_ - fade_step_);
92 }
93 }
94
95 Processor processor_{};
96 SampleType current_wet_ = SampleType{1.0f}; // start active
97 SampleType target_wet_ = SampleType{1.0f};
98 SampleType fade_step_ = SampleType{1.0f} / SampleType{256.0f}; // ~256-sample default fade
99};
100
101template <typename Processor>
103
104template <typename Processor>
106
107} // namespace pulp::signal
Definition soft_bypass.hpp:35
bool fading() const noexcept
True while a crossfade is still in progress.
Definition soft_bypass.hpp:59
void set_fade_samples(int samples) noexcept
Crossfade length in samples for a bypass toggle (clamped to >= 1).
Definition soft_bypass.hpp:47
Processor & processor() noexcept
Definition soft_bypass.hpp:43
void set_bypassed(bool bypassed) noexcept
Request bypassed (true) or active (false). The change crossfades in.
Definition soft_bypass.hpp:53
SoftBypassT(Processor processor)
Definition soft_bypass.hpp:38
const Processor & processor() const noexcept
Definition soft_bypass.hpp:44
bool bypassed() const noexcept
Definition soft_bypass.hpp:57
SampleType wet_mix() const noexcept
Current wet mix in [0, 1] (1 = fully active, 0 = fully bypassed).
Definition soft_bypass.hpp:61
void process(SampleType *data, int num_samples) noexcept
Process a buffer in place.
Definition soft_bypass.hpp:76
void reset() noexcept
Reset the wrapped processor (if it supports it) and settle the fade.
Definition soft_bypass.hpp:81
SampleType process(SampleType input) noexcept
Process one sample with the current (possibly fading) bypass mix.
Definition soft_bypass.hpp:64
@ Processor
Definition graph_runtime_plan.hpp:15
Definition additive_bank.hpp:218
@ i
Definition formant_filter_bank.hpp:20
SoftBypassT< Processor, float > SoftBypass
Definition soft_bypass.hpp:102
SoftBypassT< Processor, double > SoftBypass64
Definition soft_bypass.hpp:105
STL namespace.