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
frame.hpp
Go to the documentation of this file.
1// sbl/dsp/types/frame.hpp — Stereo buffer management (Signal layer)
2//
3// Manages the stereo float buffer pair that every audio callback needs.
4// Eliminates manual buffer declaration, zeroing, gain staging, and DMA
5// interleave boilerplate.
6//
7// Frame is the workhorse of the Signal layer — the connective tissue
8// between widgets in a processing chain. Every method is a trivial loop
9// that the compiler will vectorize. Zero abstraction cost.
10//
11// Part of the Audio Stack: Atoms → Signal → Widgets
12// See FDP-031 for architecture rationale.
13//
14// Usage:
15// sbl::dsp::types::Frame<48> frame;
16//
17// void audio_callback(int32_t* tx, const int32_t* rx, uint16_t frames) {
18// uint16_t n = frame.begin(frames);
19//
20// osc.process(frame.left, n); // source → left channel
21// filter.process(frame.left, n); // in-place filter
22// env.process(env_buf, n);
23// frame.apply(env_buf, n); // VCA: L *= env, R *= env
24// frame.mix_mono(bass_buf, 0.5f, n); // mix bass at -6 dB
25// delay.process(frame.left, frame.right, n);
26//
27// frame.end(tx, n); // float → int32 stereo DMA
28// }
29
30#ifndef SBL_DSP_TYPES_FRAME_HPP_
31#define SBL_DSP_TYPES_FRAME_HPP_
32
33#include <cstdint>
34
36
37namespace sbl::dsp::types {
38
39template<uint16_t MaxFrames = 48>
40struct Frame {
41 float left[MaxFrames];
42 float right[MaxFrames];
43
44 /// Begin a processing block: clamp frame count and zero buffers.
45 ///
46 /// Call this at the top of every audio callback. Returns the actual
47 /// frame count to use (clamped to MaxFrames).
48 ///
49 /// @param requested Frame count from DMA callback
50 /// @return Actual frame count (min of requested and MaxFrames)
51 uint16_t begin(uint16_t requested) {
52 uint16_t n = (requested > MaxFrames) ? MaxFrames : requested;
53 for (uint16_t i = 0; i < n; ++i) {
54 left[i] = 0.0f;
55 right[i] = 0.0f;
56 }
57 return n;
58 }
59
60 /// Finalize block: float → int32 stereo interleave to DMA tx buffer.
61 ///
62 /// This is the DMA boundary — NaN guard, clamp to [-1.0, 1.0], and
63 /// 24-bit scaling all happen inside interleave_from_float().
64 ///
65 /// @param tx DMA transmit buffer (interleaved stereo int32)
66 /// @param n Frame count
67 void end(int32_t* tx, uint16_t n) const {
69 }
70
71 /// Scale both channels by a constant gain.
72 ///
73 /// Use for headroom management (e.g., 1/sqrt(N) for N summed voices).
74 ///
75 /// @param gain Gain factor
76 /// @param n Frame count
77 void scale(float gain, uint16_t n) {
78 for (uint16_t i = 0; i < n; ++i) {
79 left[i] *= gain;
80 right[i] *= gain;
81 }
82 }
83
84 /// Apply per-sample modulation to both channels (stereo VCA).
85 ///
86 /// Multiplies both L and R by a control signal — typically an
87 /// envelope output [0.0, 1.0].
88 ///
89 /// @param mod Control signal buffer (e.g., envelope output)
90 /// @param n Frame count
91 void apply(const float* mod, uint16_t n) {
92 for (uint16_t i = 0; i < n; ++i) {
93 left[i] *= mod[i];
94 right[i] *= mod[i];
95 }
96 }
97
98 /// Mix a mono source into both channels at a given gain.
99 ///
100 /// Adds src * gain to both L and R. Use for mixing a mono sub-voice
101 /// into a stereo frame (e.g., bass at -6 dB = gain 0.5).
102 ///
103 /// @param src Mono source buffer
104 /// @param gain Mix gain (e.g., 0.5 for -6 dB)
105 /// @param n Frame count
106 void mix_mono(const float* src, float gain, uint16_t n) {
107 for (uint16_t i = 0; i < n; ++i) {
108 float s = src[i] * gain;
109 left[i] += s;
110 right[i] += s;
111 }
112 }
113
114 /// Mix another stereo frame into this one at a given gain.
115 ///
116 /// @param other Source frame
117 /// @param gain Mix gain
118 /// @param n Frame count
119 void mix(const Frame& other, float gain, uint16_t n) {
120 for (uint16_t i = 0; i < n; ++i) {
121 left[i] += other.left[i] * gain;
122 right[i] += other.right[i] * gain;
123 }
124 }
125
126 /// Mix separate stereo buffers into this frame at a given gain.
127 ///
128 /// @param src_l Left source buffer
129 /// @param src_r Right source buffer
130 /// @param gain Mix gain
131 /// @param n Frame count
132 void mix_stereo(const float* src_l, const float* src_r, float gain,
133 uint16_t n) {
134 for (uint16_t i = 0; i < n; ++i) {
135 left[i] += src_l[i] * gain;
136 right[i] += src_r[i] * gain;
137 }
138 }
139
140 /// Snapshot current buffer state into separate L/R buffers.
141 ///
142 /// Use for explicit feedback paths: tap the signal before effects,
143 /// then mix the tapped (and possibly processed) signal back in on
144 /// the next block.
145 ///
146 /// @param dst_l Destination left buffer
147 /// @param dst_r Destination right buffer
148 /// @param n Frame count
149 void tap(float* dst_l, float* dst_r, uint16_t n) const {
150 for (uint16_t i = 0; i < n; ++i) {
151 dst_l[i] = left[i];
152 dst_r[i] = right[i];
153 }
154 }
155
156 /// Zero both channels.
157 ///
158 /// @param n Frame count
159 void clear(uint16_t n) {
160 for (uint16_t i = 0; i < n; ++i) {
161 left[i] = 0.0f;
162 right[i] = 0.0f;
163 }
164 }
165};
166
167} // namespace sbl::dsp::types
168
169#endif // SBL_DSP_TYPES_FRAME_HPP_
DMA boundary conversion utilities.
Sample rate, sample formats, blocks and frames.
Definition block.hpp:20
void interleave_from_float(const float *left, const float *right, int32_t *interleaved, uint16_t frames)
Definition convert.hpp:96
void end(int32_t *tx, uint16_t n) const
Definition frame.hpp:67
void mix(const Frame &other, float gain, uint16_t n)
Definition frame.hpp:119
void mix_mono(const float *src, float gain, uint16_t n)
Definition frame.hpp:106
void apply(const float *mod, uint16_t n)
Definition frame.hpp:91
float left[MaxFrames]
Definition frame.hpp:41
void tap(float *dst_l, float *dst_r, uint16_t n) const
Definition frame.hpp:149
void mix_stereo(const float *src_l, const float *src_r, float gain, uint16_t n)
Definition frame.hpp:132
float right[MaxFrames]
Definition frame.hpp:42
void clear(uint16_t n)
Definition frame.hpp:159
uint16_t begin(uint16_t requested)
Definition frame.hpp:51
void scale(float gain, uint16_t n)
Definition frame.hpp:77