Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
panner.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <cmath>
4#include <algorithm>
5
6namespace pulp::signal {
7
31
32// Stereo panner with selectable pan law.
33// pan = -1 (full left), 0 (center), +1 (full right)
34//
35// RT contract: setters, gain computation, and process paths are scalar-only and
36// allocate no memory.
37template <typename SampleType = float>
38class PannerT {
39public:
40 PannerT() { update_gains(); }
41
42 void set_pan(SampleType pan) {
43 pan_ = std::clamp(pan, SampleType{-1.0f}, SampleType{1.0f});
44 update_gains();
45 }
46 SampleType pan() const { return pan_; }
47
49 law_ = law;
50 update_gains();
51 }
52 PanLaw law() const { return law_; }
53
54 struct StereoSample {
55 SampleType left, right;
56 };
57
59 StereoSample process(SampleType input) const {
60 return {input * l_gain_, input * r_gain_};
61 }
62
64 void process(SampleType& left, SampleType& right) const {
65 left *= l_gain_;
66 right *= r_gain_;
67 }
68
73 void compute_gains(SampleType& l_gain, SampleType& r_gain) const {
74 l_gain = l_gain_;
75 r_gain = r_gain_;
76 }
77
78private:
79 void update_gains() {
80 SampleType& l_gain = l_gain_;
81 SampleType& r_gain = r_gain_;
82 constexpr SampleType kHalfPi = SampleType{1.57079632679489661923f};
83 const SampleType position =
84 (pan_ + SampleType{1.0f}) * SampleType{0.5f}; // [0, 1] : 0 = full L, 1 = full R
85 const SampleType theta = position * kHalfPi; // [0, pi/2]
86 switch (law_) {
87 case PanLaw::Linear:
88 l_gain = SampleType{1.0f} - position;
89 r_gain = position;
90 break;
92 l_gain = pan_ <= SampleType{0.0f}
93 ? SampleType{1.0f}
94 : (SampleType{1.0f} - pan_);
95 r_gain = pan_ >= SampleType{0.0f}
96 ? SampleType{1.0f}
97 : (SampleType{1.0f} + pan_);
98 break;
99 case PanLaw::Sin3dB: // == EqualPower
100 l_gain = std::cos(theta);
101 r_gain = std::sin(theta);
102 break;
103 case PanLaw::Sin4_5dB: {
104 // Clamp before pow to guard against tiny negative
105 // floating-point residue at the endpoints (cos(pi/2)).
106 const SampleType c = std::max(SampleType{0.0f}, std::cos(theta));
107 const SampleType s = std::max(SampleType{0.0f}, std::sin(theta));
108 l_gain = std::pow(c, SampleType{1.5f});
109 r_gain = std::pow(s, SampleType{1.5f});
110 break;
111 }
112 case PanLaw::Sin6dB:
113 l_gain = std::cos(theta) * std::cos(theta);
114 r_gain = std::sin(theta) * std::sin(theta);
115 break;
116 case PanLaw::Sqrt3dB:
117 l_gain = std::sqrt(SampleType{1.0f} - position);
118 r_gain = std::sqrt(position);
119 break;
121 // -4.5 dB = geometric mean of -3 dB sqrt and -6 dB linear
122 // → exponent 0.75. At center yields 0.5^0.75 ≈ 0.5946
123 // ≈ -4.51 dB per channel, matching the documented notch.
124 l_gain = std::pow(SampleType{1.0f} - position, SampleType{0.75f});
125 r_gain = std::pow(position, SampleType{0.75f});
126 break;
127 }
128 }
129
130 SampleType pan_ = SampleType{0.0f};
132 SampleType l_gain_ = SampleType{0.0f};
133 SampleType r_gain_ = SampleType{0.0f};
134};
135
138
139} // namespace pulp::signal
Definition panner.hpp:38
void set_law(PanLaw law)
Definition panner.hpp:48
void set_pan(SampleType pan)
Definition panner.hpp:42
StereoSample process(SampleType input) const
Pan a mono signal to stereo.
Definition panner.hpp:59
PanLaw law() const
Definition panner.hpp:52
void process(SampleType &left, SampleType &right) const
Pan stereo in-place (adjust balance).
Definition panner.hpp:64
PannerT()
Definition panner.hpp:40
float pan() const
Definition panner.hpp:46
void compute_gains(SampleType &l_gain, SampleType &r_gain) const
Per-channel gains for the current pan + law.
Definition panner.hpp:73
Definition additive_bank.hpp:218
PannerT< double > Panner64
Definition panner.hpp:137
@ right
Definition multi_channel_meter.hpp:67
@ left
Definition multi_channel_meter.hpp:66
PannerT< float > Panner
Definition panner.hpp:136
@ c
Definition spectrum_trace.hpp:35
PanLaw
Stereo pan law selector.
Definition panner.hpp:21
@ Sqrt3dB
Definition panner.hpp:28
@ Sqrt4_5dB
Definition panner.hpp:29
@ Linear
Definition panner.hpp:22
@ EqualPower
Definition panner.hpp:25
@ Sin4_5dB
Definition panner.hpp:26
@ Sin6dB
Definition panner.hpp:27
@ Sin3dB
Definition panner.hpp:24
@ Balanced
Definition panner.hpp:23
@ EqualPower
(cos(u·π/2), sin(u·π/2)) — power sum == 1.
Definition crossfade.hpp:43
@ Sqrt3dB
Definition dry_wet_mixer.hpp:36
@ Sqrt4_5dB
Definition dry_wet_mixer.hpp:37
@ Linear
Definition dry_wet_mixer.hpp:30
@ Sin4_5dB
Definition dry_wet_mixer.hpp:34
@ Sin6dB
Definition dry_wet_mixer.hpp:35
@ Sin3dB
Definition dry_wet_mixer.hpp:33
@ Balanced
Definition dry_wet_mixer.hpp:32
@ s
Definition input_events.hpp:41
Definition panner.hpp:54
SampleType right
Definition panner.hpp:55
SampleType left
Definition panner.hpp:55