Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
transition_mixer.hpp
Go to the documentation of this file.
1#pragma once
2
25
26#include "crossfade.hpp"
27
28#include <algorithm>
29#include <cmath>
30#include <cstddef>
31
32namespace pulp::signal {
33
35
36template <typename SampleType = float>
38public:
39 TransitionMixerT() = default;
40
43 void configure(std::size_t length_samples, TransitionCurve curve) {
44 length_ = length_samples;
45 curve_ = curve;
46 pos_ = 0;
47 }
49 TransitionCurve curve() const { return curve_; }
50
51 void reset() { pos_ = 0; }
52 void advance(std::size_t frames) { pos_ += frames; }
53
54 std::size_t length() const { return length_; }
55 std::size_t position() const { return pos_; }
56 bool done() const { return length_ == 0 || pos_ >= length_; }
57
61 void gains_at(std::size_t fade_pos,
62 SampleType& old_gain,
63 SampleType& new_gain) const {
64 const SampleType t = (length_ == 0)
65 ? SampleType{1.0f}
66 : static_cast<SampleType>(fade_pos) / static_cast<SampleType>(length_);
67 // Smoothstep-shaped progress (click-free ends), then the shared old→new
68 // gain law: EqualPower → constant power (cos/sin), Smoothstep → equal gain.
69 const SampleType u = crossfade_smoothstep(t);
74 old_gain, new_gain);
75 }
76
77private:
78 std::size_t length_ = 0;
79 std::size_t pos_ = 0;
81};
82
85
96template <class Mixer, class OutView, class OldView>
97inline bool blend_fade_out(Mixer& mixer, OutView& out, const OldView& old_render) noexcept {
98 const std::size_t frames = std::min<std::size_t>(out.num_samples(), old_render.num_samples());
99 const std::size_t ch = std::min<std::size_t>(out.num_channels(), old_render.num_channels());
100 const std::size_t base = mixer.position();
101 // The old/new gain pair depends only on the (shared) fade position, not the
102 // channel, so compute each pair ONCE per frame and reuse it across channels
103 // instead of re-evaluating gains_at (two transcendentals for EqualPower) per
104 // channel per sample. Precompute in bounded stack chunks to stay alloc-free
105 // while keeping the per-channel apply loop contiguous. Bit-identical to the
106 // previous channel-outer form (gains_at is a pure function of base+n).
107 constexpr std::size_t kChunk = 64;
108 float old_gain[kChunk];
109 float new_gain[kChunk];
110 for (std::size_t start = 0; start < frames; start += kChunk) {
111 const std::size_t len = std::min<std::size_t>(kChunk, frames - start);
112 for (std::size_t j = 0; j < len; ++j)
113 mixer.gains_at(base + start + j, old_gain[j], new_gain[j]);
114 for (std::size_t c = 0; c < ch; ++c) {
115 auto o = out.channel(c);
116 auto old_ch = old_render.channel(c);
117 for (std::size_t j = 0; j < len; ++j)
118 o[start + j] = old_ch[start + j] * old_gain[j] + o[start + j] * new_gain[j];
119 }
120 }
121 mixer.advance(frames);
122 return mixer.done();
123}
124
125} // namespace pulp::signal
Definition transition_mixer.hpp:37
std::size_t position() const
Definition transition_mixer.hpp:55
void gains_at(std::size_t fade_pos, SampleType &old_gain, SampleType &new_gain) const
Old/new blend gains at an ABSOLUTE fade position (pure — no state change), so a caller can compute pe...
Definition transition_mixer.hpp:61
void reset()
Definition transition_mixer.hpp:51
void advance(std::size_t frames)
Definition transition_mixer.hpp:52
void set_curve(TransitionCurve curve)
Definition transition_mixer.hpp:48
void configure(std::size_t length_samples, TransitionCurve curve)
Configure the fade length (samples) + curve and rewind to the start.
Definition transition_mixer.hpp:43
bool done() const
Definition transition_mixer.hpp:56
std::size_t length() const
Definition transition_mixer.hpp:54
TransitionCurve curve() const
Definition transition_mixer.hpp:49
The one shared old→new crossfade gain law for the SIGNAL side.
Definition additive_bank.hpp:218
TransitionMixerT< float > TransitionMixer
Definition transition_mixer.hpp:83
@ c
Definition spectrum_trace.hpp:35
TransitionMixerT< double > TransitionMixer64
Definition transition_mixer.hpp:84
@ EqualPower
(cos(u·π/2), sin(u·π/2)) — power sum == 1.
Definition crossfade.hpp:43
@ EqualGain
(1−u, u) — amplitude sum == 1.
Definition crossfade.hpp:42
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
@ o
Definition formant_filter_bank.hpp:20
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
TransitionCurve
Definition transition_mixer.hpp:34
@ Smoothstep
Definition transition_mixer.hpp:34
@ EqualPower
Definition transition_mixer.hpp:34
bool blend_fade_out(Mixer &mixer, OutView &out, const OldView &old_render) noexcept
Blend an already-rendered fading-out buffer into the live output under a TransitionMixer's old->new g...
Definition transition_mixer.hpp:97