Sound Byte Libs 0.5.1-121-g3358a44
C++ firmware library for audio applications on 32-bit ARM Cortex-M processors
Loading...
Searching...
No Matches
channel.hpp
Go to the documentation of this file.
1// sbl/dsp/widgets/channel.hpp — Mixer channel strip (Audio Stack — Widgets)
2//
3// Composes Fader + Pan + Sends into a self-contained channel strip. Each
4// channel owns its audio buffers, fader gain, stereo pan, and send routing.
5// The Mixer module composes multiple Channels for summing and master output.
6//
7// Front side (application writes):
8// write_input_mono(src, n) — write mono source into channel
9// write_input_stereo(src_l, src_r, n) — write stereo source into channel
10// set_gain_su(float) — [0,1] channel fader level
11// set_pan_su(float) — [0,1] pan position (0=L, 0.5=center, 1=R)
12// set_send_level_su(idx, float) — [0,1] send amount
13//
14// Back side (mixer reads after process()):
15// post_l() / post_r() — post-gain, post-pan stereo output
16// buf_l / buf_r — raw input (pre-pan, pre-fader) for sends
17//
18// process(n) applies the full channel strip:
19// 1. Mono spread (copy L to R if mono)
20// 2. Fader gain + pan → post_l_/post_r_
21// buf_l/buf_r are NOT modified — they stay as pre-pan, pre-fader source for sends.
22//
23// Send routing:
24// Sends tap from buf_l/buf_r (always pre-pan). Gain is either:
25// PreFader: send_level only
26// PostFader: fader_gain * send_level
27// Pan only affects the master bus sum via post_l/post_r. This matches
28// real console behavior where sends are mono taps before the pan pot.
29//
30// Usage:
31// sbl::dsp::widgets::Channel<48, 2> ch;
32// ch.set_format(Format::Mono);
33// ch.add_send(0, 0.3f); // send to return 0 at 30%
34// ch.set_gain_su(0.8f);
35// ch.set_pan_su(0.5f); // center
36// ch.write_input_mono(voice_buf, n);
37// ch.process(n);
38// // Mixer reads ch.post_l(), ch.post_r() for master summing
39// // Mixer reads ch.buf_l, ch.buf_r for send routing
40
41#ifndef SBL_DSP_WIDGETS_CHANNEL_HPP_
42#define SBL_DSP_WIDGETS_CHANNEL_HPP_
43
44#include <cstdint>
45
47#include <sbl/dsp/comp/pan.hpp>
48
50
51enum class Format : uint8_t {
52 Mono, // L buffer only, copied to R on process()
53 Stereo, // Independent L/R buffers
54};
55
56enum class SendType : uint8_t {
57 PostFader, // signal * fader * send_level (Ableton default)
58 PreFader, // signal * send_level (ignores channel fader)
59};
60
61struct Send {
62 uint8_t target = 0; // return channel index
63 comp::Fader level; // send amount with smoothing
65};
66
67template <uint16_t MaxFrames, uint8_t MaxSends = 4>
68class Channel {
69public:
70 // Input buffers — written via write_input_*, read by mixer for sends.
71 // These are the raw, pre-pan, pre-fader signal. NOT modified by process().
72 float buf_l[MaxFrames] = {};
73 float buf_r[MaxFrames] = {};
74
75 // ── Front side: input ─────────────────────────────────────────────
76
77 /// Write mono input — channel spreads to both L/R on process().
78 void write_input_mono(const float* src, uint16_t n) {
79 for (uint16_t i = 0; i < n; ++i)
80 buf_l[i] = src[i];
81 }
82
83 /// Write stereo input.
84 void write_input_stereo(const float* src_l, const float* src_r, uint16_t n) {
85 for (uint16_t i = 0; i < n; ++i) {
86 buf_l[i] = src_l[i];
87 buf_r[i] = src_r[i];
88 }
89 }
90
91 // ── Ports ────────────────────────────────────────────────────────
92
93 /// Port: channel gain level [0,1].
94 void set_gain_su(float su) { fader_.set_level_su(su); }
95
96 /// Port: pan position [0,1]. 0=L, 0.5=center, 1=R.
97 void set_pan_su(float su) { pan_.set_position_su(su); }
98
99 /// Port: send level [0,1] for send at index.
100 void set_send_level_su(uint8_t send_index, float su) {
101 if (send_index < send_count_) {
102 sends_[send_index].level.set_level_su(su);
103 }
104 }
105
106 // ── Parameters ───────────────────────────────────────────────────
107
108 void set_format(Format f) { format_ = f; }
109 void set_mute(bool m) { mute_ = m; }
110 void set_solo(bool s) { solo_ = s; }
111 void set_fader_taper(comp::Taper t) { fader_.set_taper(t); }
112
113 // ── Send configuration ───────────────────────────────────────────
114
115 /// Configure a send at init time. Default taper is Audio for send faders.
116 void add_send(uint8_t target, float initial_level,
118 if (send_count_ < MaxSends) {
119 Send& s = sends_[send_count_++];
120 s.target = target;
121 s.type = type;
123 s.level.set_level_su(initial_level);
124 }
125 }
126
127 // ── Processing ───────────────────────────────────────────────────
128
129 /// Process the full channel strip: mono spread, fader gain, pan.
130 /// After this call, post_l()/post_r() contain the master-ready output.
131 /// buf_l/buf_r remain unmodified (pre-pan, pre-fader) for send routing.
132 void process(uint16_t n) {
133 // Mono spread: copy L to R so both buffers are valid
134 if (format_ == Format::Mono) {
135 for (uint16_t i = 0; i < n; ++i)
136 buf_r[i] = buf_l[i];
137 }
138
139 // Apply fader gain to produce post-fader output. The smoother
140 // advances by the full block; the gain is block-constant.
141 float gain = fader_.tick(n);
142 for (uint16_t i = 0; i < n; ++i) {
143 post_l_[i] = buf_l[i] * gain;
144 post_r_[i] = buf_r[i] * gain;
145 }
146
147 // Apply pan in-place on post buffers
148 pan_.process(post_l_, post_r_, n);
149 }
150
151 // ── Back side: mixer reads these after process() ─────────────────
152
153 const float* post_l() const { return post_l_; }
154 const float* post_r() const { return post_r_; }
155
156 // ── Accessors ────────────────────────────────────────────────────
157
158 float fader_gain() const { return fader_.gain(); }
159 bool muted() const { return mute_; }
160 bool soloed() const { return solo_; }
161 Format format() const { return format_; }
162 uint8_t send_count() const { return send_count_; }
163 const Send& send(uint8_t i) const { return sends_[i]; }
164 Send& send(uint8_t i) { return sends_[i]; }
165
166 comp::Fader& fader() { return fader_; }
167 comp::Pan& pan() { return pan_; }
168
169private:
170 comp::Fader fader_; // channel level
171 comp::Pan pan_; // stereo placement
172 Send sends_[MaxSends] = {};
173 uint8_t send_count_ = 0;
174 Format format_ = Format::Mono;
175 bool mute_ = false;
176 bool solo_ = false;
177
178 // Post-gain, post-pan output buffers (master-ready)
179 float post_l_[MaxFrames] = {};
180 float post_r_[MaxFrames] = {};
181};
182
183} // namespace sbl::dsp::widgets
184
185#endif // SBL_DSP_WIDGETS_CHANNEL_HPP_
float tick(uint16_t n)
Definition fader.hpp:86
void set_taper(Taper t)
Definition fader.hpp:55
float gain() const
Current smoothed gain value (after taper mapping + smoothing).
Definition fader.hpp:92
void set_level_su(float su)
Definition fader.hpp:46
void set_position_su(float su)
Set pan position. Port — accepts normalized [0,1] signal.
Definition pan.hpp:44
void process(const float *in, float *out_l, float *out_r, uint16_t n)
Apply panning to a mono input, writing to stereo output buffers.
Definition pan.hpp:61
float buf_r[MaxFrames]
Definition channel.hpp:73
void write_input_mono(const float *src, uint16_t n)
Write mono input — channel spreads to both L/R on process().
Definition channel.hpp:78
const float * post_r() const
Definition channel.hpp:154
void add_send(uint8_t target, float initial_level, SendType type=SendType::PostFader)
Configure a send at init time. Default taper is Audio for send faders.
Definition channel.hpp:116
void set_send_level_su(uint8_t send_index, float su)
Port: send level [0,1] for send at index.
Definition channel.hpp:100
comp::Fader & fader()
Definition channel.hpp:166
uint8_t send_count() const
Definition channel.hpp:162
void write_input_stereo(const float *src_l, const float *src_r, uint16_t n)
Write stereo input.
Definition channel.hpp:84
float buf_l[MaxFrames]
Definition channel.hpp:72
void set_format(Format f)
Definition channel.hpp:108
const float * post_l() const
Definition channel.hpp:153
const Send & send(uint8_t i) const
Definition channel.hpp:163
void set_fader_taper(comp::Taper t)
Definition channel.hpp:111
Send & send(uint8_t i)
Definition channel.hpp:164
void set_pan_su(float su)
Port: pan position [0,1]. 0=L, 0.5=center, 1=R.
Definition channel.hpp:97
void process(uint16_t n)
Definition channel.hpp:132
void set_gain_su(float su)
Port: channel gain level [0,1].
Definition channel.hpp:94
Gain control with taper curve (Audio Stack — Compositions)
Black boxes with _su ports.
Definition channel.hpp:49
Stereo pan composition with smoothing.