MayaFlux 1.0.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
RootAudioBuffer.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "RootBuffer.hpp"
4
7
8namespace MayaFlux::Buffers {
9
10/**
11 * @class RootAudioBuffer
12 * @brief Top-level aggregation buffer for computational data streams
13 *
14 * RootAudioBuffer serves as the final convergence point for data streams in each channel
15 * before output to hardware interfaces. Similar to RootNode in the node system,
16 * there is typically one RootAudioBuffer per output channel in a multi-channel system.
17 *
18 * Key responsibilities:
19 * - Aggregating and combining data from multiple tributary buffers
20 * - Receiving direct output from computational node networks (via set_node_output)
21 * - Applying final normalization and boundary enforcement to ensure valid output
22 * - Ensuring thread-safe access to shared data resources
23 *
24 * RootAudioBuffer implements a hierarchical data aggregation pattern where multiple
25 * computational streams (child buffers and node output) are combined through a
26 * configurable mixing algorithm before being transmitted to hardware interfaces.
27 */
28class MAYAFLUX_API RootAudioBuffer : public RootBuffer<AudioBuffer> {
29public:
30 /**
31 * @brief Creates a new root aggregation buffer for a channel
32 * @param channel_id Channel identifier in multi-channel systems
33 * @param num_samples Buffer capacity in samples (default: 512)
34 *
35 * Initializes a root buffer with the specified channel ID and capacity.
36 * The buffer is automatically configured with a ChannelProcessor as
37 * its default processor for data aggregation.
38 */
39 RootAudioBuffer(uint32_t channel_id, uint32_t num_samples = 512);
40
41 void initialize();
42
43 /**
44 * @brief Virtual destructor for proper resource management
45 */
46 ~RootAudioBuffer() override = default;
47
48 /**
49 * @brief Processes this buffer using its default aggregation processor
50 *
51 * For a root buffer, this typically involves:
52 * 1. Processing all tributary buffers to ensure current data
53 * 2. Combining tributary outputs with direct node network output
54 * 3. Applying final normalization to ensure valid output ranges
55 *
56 * This method is thread-safe and can be called from real-time threads.
57 */
58 void process_default() override;
59
60 /**
61 * @brief Resizes this buffer and all tributary buffers
62 * @param num_samples New buffer capacity in samples
63 *
64 * Adjusts the capacity of this buffer and all its tributary buffers to
65 * ensure consistent buffer dimensions throughout the aggregation hierarchy.
66 */
67 void resize(uint32_t num_samples) override;
68
69 /**
70 * @brief Sets direct node network output data for this buffer
71 * @param data Vector of data samples from node network processing
72 *
73 * This allows computational node networks to directly contribute data
74 * to the root buffer, which is combined with tributary buffer outputs.
75 * The data is copied to ensure thread safety between computational domains.
76 */
77 void set_node_output(const std::vector<double>& data);
78
79 /**
80 * @brief Gets the current node network output data
81 * @return Constant reference to the node output vector
82 */
83 inline const std::vector<double>& get_node_output() const { return m_node_output; }
84
85 /**
86 * @brief Checks if this buffer has node network output data
87 * @return true if node output is present, false otherwise
88 */
89 inline bool has_node_output() const { return m_has_node_output; }
90
91 /**
92 * @brief Choose whether this channel's mix is averaged over its sources.
93 *
94 * On by default: every source is divided by the number of sources, so adding
95 * one makes the others quieter. Off sums the sources at their own levels and
96 * leaves headroom to the caller; the final limiter still applies.
97 */
98 inline void set_mix_normalization(bool enabled) { m_normalize_mix = enabled; }
99
100 /**
101 * @brief Whether this channel's mix is averaged over its sources.
102 */
103 [[nodiscard]] inline bool is_mix_normalized() const { return m_normalize_mix; }
104
105 /**
106 * @brief Activates/deactivates processing for the current token
107 * @param active Whether this buffer should process when its token is active
108 *
109 * For RootAudioBuffer, this controls whether the buffer participates in
110 * token-based processing cycles. When inactive, the buffer won't process
111 * even if its token is being processed by the system.
112 */
113 inline void set_token_active(bool active) override { m_token_active = active; }
114
115 /**
116 * @brief Checks if the buffer is active for its assigned token
117 * @return True if the buffer will process when its token is processed
118 */
119 inline bool is_token_active() const override { return m_token_active; }
120
121protected:
122 /**
123 * @brief Creates the default processor for this buffer type
124 * @return Shared pointer to a ChannelProcessor
125 *
126 * Root buffers use a ChannelProcessor as their default processor,
127 * which handles combining tributary buffers and node network output.
128 */
129 std::shared_ptr<BufferProcessor> create_default_processor() override;
130
131private:
132 /**
133 * @brief Data received directly from computational node networks
134 */
135 std::vector<double> m_node_output;
136
137 /**
138 * @brief Flag indicating if node network output data is present
139 */
141
142 /**
143 * @brief Whether the channel mix is divided by the number of sources
144 */
145 bool m_normalize_mix { true };
146
147 /**
148 * @brief Flag indicating if this buffer is active for token processing
149 */
151};
152
153/**
154 * @class ChannelProcessor
155 * @brief Processor that implements hierarchical data aggregation for root buffers
156 *
157 * ChannelProcessor is the default processor for RootAudioBuffer objects.
158 * It implements a configurable algorithm for combining data from tributary
159 * buffers and direct node network output to produce the final output for a channel.
160 *
161 * This processor is automatically created and attached to root buffers,
162 * but can be replaced with custom aggregation algorithms if needed.
163 *
164 * Token Compatibility:
165 * - Primary Token: AUDIO_BACKEND (sample-rate, CPU, sequential processing)
166 * - Compatible with other audio processing tokens through token compatibility rules
167 * - Not compatible with GRAPHICS_BACKEND tokens due to different processing models
168 */
169class MAYAFLUX_API ChannelProcessor : public BufferProcessor {
170public:
171 /**
172 * @brief Creates a new channel aggregation processor
173 * @param root_buffer Shared pointer to the root buffer this processor will manage
174 *
175 * The processor maintains a raw pointer to its root buffer to avoid
176 * circular references, as the root buffer already owns a shared_ptr
177 * to this processor in the object composition hierarchy.
178 */
179 ChannelProcessor(const std::shared_ptr<Buffer>& root_buffer);
180
181 /**
182 * @brief Processes a buffer by combining tributary buffers and node network output
183 * @param buffer Buffer to process (should be the root buffer)
184 *
185 * This method implements a hierarchical data aggregation algorithm:
186 * 1. Processes all tributary buffers to ensure current data
187 * 2. Combines their outputs into the root buffer using a weighted averaging algorithm
188 * 3. Incorporates node network output if present
189 *
190 * The combination algorithm can be customized in the implementation.
191 */
192 void processing_function(const std::shared_ptr<Buffer>& buffer) override;
193
194 /**
195 * @brief Called when processor is attached to a buffer
196 * @param buffer Buffer being attached to
197 *
198 * Validates that the buffer is a compatible RootAudioBuffer and ensures
199 * token compatibility for proper processing pipeline integration.
200 */
201 void on_attach(const std::shared_ptr<Buffer>& buffer) override;
202
203 /**
204 * @brief Checks compatibility with a specific buffer type
205 * @param buffer Buffer to check compatibility with
206 * @return True if compatible (buffer is RootAudioBuffer), false otherwise
207 */
208 bool is_compatible_with(const std::shared_ptr<Buffer>& buffer) const override;
209
210private:
211 /**
212 * @brief Shared pointer to the root buffer this processor manages
213 */
214 std::shared_ptr<RootAudioBuffer> m_root_buffer;
215};
216
217/**
218 * @class FinalLimiterProcessor
219 * @brief Processor that enforces boundary conditions on output data
220 *
221 * FinalLimiterProcessor is typically used as the final processor in
222 * a root buffer's processing chain. It ensures that output values
223 * remain within defined boundaries before transmission to hardware interfaces.
224 *
225 * This boundary enforcement is critical for root buffers since they connect
226 * directly to hardware interfaces, where out-of-range values can cause
227 * distortion, artifacts, or potentially damage physical components.
228 *
229 * Token Compatibility:
230 * - Primary Token: AUDIO_BACKEND (optimized for audio sample rate processing)
231 * - Can adapt to GPU_PROCESS tokens for parallel limiting when beneficial
232 * - Compatible with SEQUENTIAL and PARALLEL processing modes
233 */
234class MAYAFLUX_API FinalLimiterProcessor : public BufferProcessor {
235public:
236 /**
237 * @brief Creates a new final limiter processor
238 *
239 * Initializes the processor with default AUDIO_BACKEND token for
240 * standard audio processing compatibility.
241 */
243
244 /**
245 * @brief Processes a buffer by enforcing boundary conditions
246 * @param buffer Buffer to process
247 *
248 * This method applies a non-linear boundary enforcement algorithm to ensure
249 * all values stay within the valid range (typically -1.0 to 1.0) before
250 * being transmitted to hardware interfaces, while preserving the perceptual
251 * characteristics of the original signal.
252 */
253 void processing_function(const std::shared_ptr<Buffer>& buffer) override;
254
255 /**
256 * @brief Called when processor is attached to a buffer
257 * @param buffer Buffer being attached to
258 *
259 * Validates that the buffer is an AudioBuffer-derived type and ensures
260 * token compatibility for proper audio processing.
261 */
262 void on_attach(const std::shared_ptr<Buffer>& buffer) override;
263
264 /**
265 * @brief Checks compatibility with a specific buffer type
266 * @param buffer Buffer to check compatibility with
267 * @return True if compatible (buffer is AudioBuffer-derived), false otherwise
268 */
269 bool is_compatible_with(const std::shared_ptr<Buffer>& buffer) const override;
270};
271
272}
std::shared_ptr< NetworkGeometryBuffer > buffer
Central computational transformation interface for continuous buffer processing.
std::shared_ptr< RootAudioBuffer > m_root_buffer
Shared pointer to the root buffer this processor manages.
Processor that implements hierarchical data aggregation for root buffers.
Processor that enforces boundary conditions on output data.
const std::vector< double > & get_node_output() const
Gets the current node network output data.
bool m_token_active
Flag indicating if this buffer is active for token processing.
std::vector< double > m_node_output
Data received directly from computational node networks.
void set_mix_normalization(bool enabled)
Choose whether this channel's mix is averaged over its sources.
bool is_mix_normalized() const
Whether this channel's mix is averaged over its sources.
bool m_has_node_output
Flag indicating if node network output data is present.
~RootAudioBuffer() override=default
Virtual destructor for proper resource management.
void set_token_active(bool active) override
Activates/deactivates processing for the current token.
bool is_token_active() const override
Checks if the buffer is active for its assigned token.
bool has_node_output() const
Checks if this buffer has node network output data.
Top-level aggregation buffer for computational data streams.
void initialize()
Definition main.cpp:10