MayaFlux 0.1.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
AudioBuffer.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "Buffer.hpp"
4
5namespace MayaFlux::Buffers {
6
7/**
8 * @class AudioBuffer
9 * @brief Concrete audio implementation of the Buffer interface for double-precision audio data
10 *
11 * AudioBuffer provides the primary concrete implementation for audio data storage and processing
12 * in the MayaFlux engine. It specializes the generic Buffer interface for audio-specific operations,
13 * storing sequential audio samples as double-precision floating-point values and providing
14 * optimized processing capabilities for audio backends.
15 *
16 * This implementation serves as the foundation for audio processing in MayaFlux and is the
17 * preferred buffer type for audio backends due to its optimized memory layout and processing
18 * characteristics. Other specialized audio buffer types can inherit from AudioBuffer to extend
19 * its functionality while maintaining compatibility with the audio processing pipeline.
20 *
21 * AudioBuffer capabilities:
22 * - Store and manage sequential double-precision audio samples
23 * - Support multi-channel audio through channel identification
24 * - Provide efficient block-based audio processing via BufferProcessor objects
25 * - Integrate with BufferProcessingChain for complex audio transformation pipelines
26 * - Bridge between continuous audio streams (nodes) and discrete audio blocks (buffers)
27 * - Support dynamic buffer lifecycle management for streaming audio applications
28 *
29 * The AudioBuffer complements the node system by providing block-based audio processing
30 * capabilities essential for real-time audio processing, hardware interfacing, and
31 * computationally intensive audio transformations that benefit from batch operations.
32 */
33class MAYAFLUX_API AudioBuffer : public Buffer {
34public:
35 /**
36 * @brief Creates a new uninitialized audio buffer
37 *
38 * Initializes an audio buffer with no channel assignment and no allocated capacity.
39 * The buffer must be configured with setup() before use. This constructor is useful
40 * when buffer parameters will be determined at runtime.
41 */
43
44 /**
45 * @brief Creates a new audio buffer with specified channel and capacity
46 * @param channel_id Audio channel identifier for this buffer
47 * @param num_samples Buffer capacity in audio samples (default: 512)
48 *
49 * Initializes an audio buffer with the specified channel ID and allocates
50 * memory for the specified number of double-precision audio samples.
51 * The default capacity of 512 samples is optimized for typical audio
52 * processing block sizes.
53 */
54 AudioBuffer(uint32_t channel_id, uint32_t num_samples = 512);
55
56 /**
57 * @brief Virtual destructor for proper resource management
58 *
59 * Ensures proper cleanup of audio buffer resources and any attached
60 * audio processors when the buffer is destroyed.
61 */
62 virtual ~AudioBuffer() override = default;
63
64 /**
65 * @brief Initializes the audio buffer with specified channel and capacity
66 * @param channel Audio channel identifier for this buffer
67 * @param num_samples Buffer capacity in audio samples
68 *
69 * Configures the audio buffer with the specified channel ID and allocates
70 * memory for the specified number of audio samples. This method should be
71 * called on uninitialized buffers before use.
72 */
73 virtual void setup(uint32_t channel, uint32_t num_samples);
74
75 /**
76 * @brief Adjusts the audio buffer's sample capacity
77 * @param num_samples New buffer capacity in audio samples
78 *
79 * Changes the buffer's capacity while preserving existing audio data
80 * where possible. If the new size is smaller, audio data may be truncated.
81 * This operation maintains audio continuity when possible.
82 */
83 virtual void resize(uint32_t num_samples);
84
85 /**
86 * @brief Resets all audio samples in the buffer to silence
87 *
88 * Initializes all audio sample values to zero (silence) without changing
89 * the buffer capacity. This is the audio-specific implementation of the
90 * Buffer interface's clear() method.
91 */
92 virtual void clear() override;
93
94 /**
95 * @brief Gets the current capacity of the audio buffer
96 * @return Buffer capacity in audio samples
97 *
98 * Returns the number of double-precision audio samples that can be
99 * stored in this buffer.
100 */
101 inline virtual uint32_t get_num_samples() const { return m_num_samples; }
102
103 /**
104 * @brief Gets mutable access to the buffer's underlying audio data
105 * @return Reference to the vector containing audio sample data
106 *
107 * Provides direct access to the underlying double-precision audio data
108 * for reading or modification. Use with caution as it bypasses any
109 * audio transformation chain that may be configured.
110 */
111 inline virtual std::vector<double>& get_data() { return m_data; }
112
113 /**
114 * @brief Gets read-only access to the buffer's underlying audio data
115 * @return Const reference to the vector containing audio sample data
116 *
117 * Provides read-only access to the underlying double-precision audio
118 * samples for analysis or copying without modification risk.
119 */
120 inline virtual const std::vector<double>& get_data() const { return m_data; }
121
122 /**
123 * @brief Applies the default audio transformation to the buffer's data
124 *
125 * Executes the default audio processing algorithm on the buffer's sample data.
126 * The specific transformation depends on the configured default audio processor,
127 * which may perform operations like normalization, filtering, or effects processing.
128 */
129 virtual void process_default() override;
130
131 /**
132 * @brief Gets the audio channel identifier for this buffer
133 * @return Audio channel ID
134 *
135 * Returns the audio channel identifier, which typically corresponds to a
136 * logical audio stream in multi-channel audio systems (e.g., left/right
137 * for stereo, or numbered channels in surround sound configurations).
138 */
139 virtual uint32_t get_channel_id() const { return m_channel_id; }
140
141 /**
142 * @brief Sets the audio channel identifier for this buffer
143 * @param id New audio channel ID
144 *
145 * Updates the channel identifier for this audio buffer, allowing it to
146 * be reassigned to different audio channels in multi-channel configurations.
147 */
148 inline void set_channel_id(uint32_t id) { m_channel_id = id; }
149
150 /**
151 * @brief Sets the capacity of the audio buffer
152 * @param num_samples New buffer capacity in audio samples
153 *
154 * Updates the buffer's sample capacity. Similar to resize(), but the
155 * implementation may vary in derived audio buffer classes to provide
156 * specialized behavior for different audio buffer types.
157 */
158 virtual void set_num_samples(uint32_t num_samples);
159
160 /**
161 * @brief Sets the default audio transformation processor for this buffer
162 * @param processor Audio processor to use as default transformation
163 *
164 * Configures the default audio processor that will be used when
165 * process_default() is called. The processor should be compatible
166 * with double-precision audio data processing.
167 */
168 virtual void set_default_processor(std::shared_ptr<BufferProcessor> processor) override;
169
170 /**
171 * @brief Gets the current default audio transformation processor
172 * @return Shared pointer to the default audio processor
173 *
174 * Returns the audio processor that will be used for default transformations
175 * on this buffer's audio data, or nullptr if no default processor is set.
176 */
177 inline virtual std::shared_ptr<BufferProcessor> get_default_processor() const override { return m_default_processor; }
178
179 /**
180 * @brief Gets the audio transformation chain attached to this buffer
181 * @return Shared pointer to the audio buffer processing chain
182 *
183 * Returns the processing chain that contains multiple audio transformations
184 * applied in sequence when the buffer is processed. This enables complex
185 * audio processing pipelines for effects, filtering, and analysis.
186 */
187 inline virtual std::shared_ptr<BufferProcessingChain> get_processing_chain() override { return m_processing_chain; }
188
189 /**
190 * @brief Sets the audio transformation chain for this buffer
191 * @param chain New audio processing chain for sequential transformations
192 * @param force If true, replaces the existing chain even if one is already set
193 *
194 * Replaces the current audio processing chain with the provided one.
195 * The chain should contain processors compatible with double-precision
196 * audio data.
197 */
198 virtual void set_processing_chain(std::shared_ptr<BufferProcessingChain> chain, bool force = false) override;
199
200 /**
201 * @brief Gets a reference to a specific audio sample in the buffer
202 * @param index Audio sample index
203 * @return Reference to the audio sample value at the specified index
204 *
205 * Provides direct access to a specific audio sample for reading or modification.
206 * No bounds checking is performed, so the caller must ensure the index is valid
207 * within the buffer's capacity.
208 */
209 inline virtual double& get_sample(uint32_t index) { return get_data()[index]; }
210
211 /**
212 * @brief Checks if the audio buffer has data for the current processing cycle
213 * @return True if the buffer has audio data for processing, false otherwise
214 *
215 * This method is particularly relevant when using SignalSourceContainers or
216 * streaming audio systems. Standard audio buffers typically return true unless
217 * explicitly marked otherwise, but derived classes may implement different
218 * behavior based on streaming state or data availability.
219 */
220 inline virtual bool has_data_for_cycle() const override { return m_has_data; }
221
222 /**
223 * @brief Checks if the buffer should be removed from the processing chain
224 * This is relevant when using SignalSourceContainers. Standard audio buffers will
225 * always return false unless specified otherwise by their derived class implementations.
226 * @return True if the buffer should be removed, false otherwise
227 *
228 * This method enables dynamic audio buffer lifecycle management. Standard audio
229 * buffers typically return false unless explicitly marked for removal, but
230 * derived classes may implement automatic removal based on streaming end
231 * conditions or resource management policies.
232 */
233 inline virtual bool needs_removal() const override { return m_should_remove; }
234
235 /**
236 * @brief Marks the audio buffer for processing in the current cycle
237 * @param has_data True if the buffer has audio data to process, false otherwise
238 *
239 * This method allows external audio systems to control whether the buffer should
240 * be considered for processing in the current audio cycle. Standard audio buffers
241 * are typically always marked as having data unless explicitly disabled.
242 */
243 inline virtual void mark_for_processing(bool has_data) override { m_has_data = has_data; }
244
245 /**
246 * @brief Marks the audio buffer for removal from processing chains
247 *
248 * Sets the buffer's removal flag, indicating it should be removed from
249 * any audio processing chains or management systems. Standard audio buffers
250 * rarely need removal unless explicitly requested by the application or
251 * when audio streams end.
252 */
253 inline virtual void mark_for_removal() override { m_should_remove = true; }
254
255 /**
256 * @brief Controls whether the audio buffer should use default processing
257 * @param should_process True if default audio processing should be applied, false otherwise
258 *
259 * This method allows fine-grained control over when the buffer's default
260 * audio processor is applied. Standard audio buffers typically always use
261 * default processing unless specific audio processing requirements dictate
262 * otherwise.
263 */
264 inline virtual void enforce_default_processing(bool should_process) override { m_process_default = should_process; }
265
266 /**
267 * @brief Checks if the audio buffer should undergo default processing
268 * @return True if default audio processing should be applied, false otherwise
269 *
270 * Determines whether the buffer's default audio processor should be executed
271 * during the current processing cycle. Standard audio buffers typically always
272 * need default processing unless specifically configured otherwise for
273 * specialized audio processing scenarios.
274 */
275 inline virtual bool needs_default_processing() override { return m_process_default; }
276
277 /**
278 * @brief Attempts to acquire processing rights for the buffer
279 * @return True if processing rights were successfully acquired, false otherwise
280 *
281 * This method is used to control access to the buffer's data during processing.
282 * It allows the buffer to manage concurrent access and ensure that only one
283 * processing operation occurs at a time. The specific implementation may vary
284 * based on the buffer type and its processing backend.
285 */
286 inline bool try_acquire_processing() override
287 {
288 bool expected = false;
289 return m_is_processing.compare_exchange_strong(expected, true,
290 std::memory_order_acquire, std::memory_order_relaxed);
291 }
292
293 /**
294 * @brief Releases processing rights for the buffer
295 *
296 * This method is called to release the processing rights acquired by
297 * try_acquire_processing(). It allows other processing operations to
298 * access the buffer's data once the current operation is complete.
299 * The specific implementation may vary based on the buffer type and
300 * its processing backend.
301 */
302 inline void release_processing() override
303 {
304 m_is_processing.store(false, std::memory_order_release);
305 }
306
307 /**
308 * @brief Checks if the buffer is currently being processed
309 * @return True if the buffer is in a processing state, false otherwise
310 *
311 * This method indicates whether the buffer is currently undergoing
312 * a processing operation. It is used to manage concurrent access and
313 * ensure that processing operations do not interfere with each other.
314 * The specific implementation may vary based on the buffer type and
315 * its processing backend.
316 */
317 inline bool is_processing() const override
318 {
319 return m_is_processing.load(std::memory_order_acquire);
320 }
321
322 /**
323 * @brief Creates a clone of this audio buffer for a specific channel
324 * @param channel Channel identifier for the cloned buffer
325 * @return Shared pointer to the cloned audio buffer
326 *
327 * This method creates a new instance of the audio buffer with the same
328 * data and properties, but assigned to a different audio channel. The
329 * cloned buffer can be used independently in audio processing chains.
330 *
331 * NOTE: The moment of cloning is the divergence point between the original
332 * and the cloned. While they both will follow the same processing chain or have the same
333 * default procesor, any changes made to one buffer after cloning will not affect the other.
334 */
335 virtual std::shared_ptr<AudioBuffer> clone_to(uint32_t channel);
336
337 std::shared_ptr<Buffer> clone_to(uint8_t dest_desc) override;
338
339 /**
340 * @brief Reads audio data into the buffer from the audio backend
341 * @param buffer Shared pointer to the AudioBuffer to read data into
342 * @param force Whether to force reading even if in processing state
343 * @return True if data was successfully read, false otherwise
344 *
345 * This method attempts to read audio data from the audio backend into the
346 * provided AudioBuffer. If force is true, it will attempt to read even if
347 * the current buffer or the copy buffer are in processing state
348 */
349 virtual bool read_once(std::shared_ptr<AudioBuffer> buffer, bool force = false);
350
351 /**
352 * @brief Marks the buffer as internal-only, preventing root aggregation
353 * @param internal True to mark as internal-only, false to allow root aggregation
354 *
355 * Internal-only buffers are excluded from root-level aggregation and
356 * processing. This is typically used for buffers that are processed
357 * entirely within a specific backend or domain (e.g., GPU-only buffers).
358 */
359 void force_internal_usage(bool internal) override { m_internal_usage = internal; }
360
361 /**
362 * @brief Checks if the buffer is marked as internal-only
363 * @return True if the buffer is internal-only, false otherwise
364 *
365 * Indicates whether the buffer is excluded from root-level aggregation
366 * and processing. Internal-only buffers are typically processed entirely
367 * within a specific backend or domain.
368 */
369 bool is_internal_only() const override { return m_internal_usage; }
370
371protected:
372 /**
373 * @brief Audio channel identifier for this buffer
374 *
375 * Identifies which audio channel this buffer represents in multi-channel
376 * audio systems. Typically corresponds to logical audio channels like
377 * left/right for stereo or numbered channels in surround configurations.
378 */
379 uint32_t m_channel_id;
380
381 /**
382 * @brief Capacity of the buffer in audio samples
383 *
384 * Stores the maximum number of double-precision audio samples this
385 * buffer can contain. This determines the buffer's memory allocation
386 * and processing block size.
387 */
389
390 /**
391 * @brief Vector storing the actual double-precision audio sample data
392 *
393 * Contains the raw audio sample data as double-precision floating-point
394 * values. This provides high precision for audio processing while
395 * maintaining compatibility with most audio processing algorithms.
396 */
397 std::vector<double> m_data;
398
399 /**
400 * @brief Default audio transformation processor for this buffer
401 *
402 * Stores the audio processor that will be used when process_default()
403 * is called. This enables automatic audio processing without explicit
404 * processor management.
405 */
406 std::shared_ptr<BufferProcessor> m_default_processor;
407
408 /**
409 * @brief Audio transformation processing chain for this buffer
410 *
411 * Contains a sequence of audio processors that will be applied in order
412 */
413 std::shared_ptr<BufferProcessingChain> m_processing_chain;
414
415 /**
416 * @brief Creates a default audio transformation processor for this buffer type
417 * @return Shared pointer to the created audio processor, or nullptr if none
418 *
419 * This method is called when a default audio processor is needed but none
420 * has been explicitly set. The base AudioBuffer implementation returns nullptr,
421 * but derived audio buffer classes can override this to provide type-specific
422 * default audio processors.
423 */
424 virtual std::shared_ptr<BufferProcessor> create_default_processor() { return nullptr; }
425
426 /**
427 * @brief Whether the audio buffer has data to process this cycle
428 *
429 * Tracks whether this audio buffer contains valid audio data for the
430 * current processing cycle. Relevant for streaming audio systems and
431 * dynamic buffer management.
432 */
434
435 /**
436 * @brief Whether the audio buffer should be removed from processing chains
437 *
438 * Indicates whether this audio buffer should be removed from any
439 * processing chains or management systems. Used for dynamic audio
440 * buffer lifecycle management.
441 */
443
444 /**
445 * @brief Whether the audio buffer should be processed using its default processor
446 *
447 * Controls whether the buffer's default audio processor should be
448 * applied during processing cycles. Allows for selective audio
449 * processing based on current requirements.
450 */
452
453private:
454 std::atomic<bool> m_is_processing;
455
456 bool m_internal_usage {};
457};
458
459}
virtual ~AudioBuffer() override=default
Virtual destructor for proper resource management.
virtual void mark_for_processing(bool has_data) override
Marks the audio buffer for processing in the current cycle.
void set_channel_id(uint32_t id)
Sets the audio channel identifier for this buffer.
bool m_has_data
Whether the audio buffer has data to process this cycle.
bool m_should_remove
Whether the audio buffer should be removed from processing chains.
virtual uint32_t get_channel_id() const
Gets the audio channel identifier for this buffer.
virtual std::shared_ptr< BufferProcessor > create_default_processor()
Creates a default audio transformation processor for this buffer type.
void force_internal_usage(bool internal) override
Marks the buffer as internal-only, preventing root aggregation.
virtual bool needs_removal() const override
Checks if the buffer should be removed from the processing chain This is relevant when using SignalSo...
uint32_t m_channel_id
Audio channel identifier for this buffer.
virtual bool has_data_for_cycle() const override
Checks if the audio buffer has data for the current processing cycle.
std::atomic< bool > m_is_processing
bool is_processing() const override
Checks if the buffer is currently being processed.
uint32_t m_num_samples
Capacity of the buffer in audio samples.
virtual double & get_sample(uint32_t index)
Gets a reference to a specific audio sample in the buffer.
virtual std::vector< double > & get_data()
Gets mutable access to the buffer's underlying audio data.
virtual uint32_t get_num_samples() const
Gets the current capacity of the audio buffer.
virtual void mark_for_removal() override
Marks the audio buffer for removal from processing chains.
std::shared_ptr< BufferProcessingChain > m_processing_chain
Audio transformation processing chain for this buffer.
virtual bool needs_default_processing() override
Checks if the audio buffer should undergo default processing.
void release_processing() override
Releases processing rights for the buffer.
bool try_acquire_processing() override
Attempts to acquire processing rights for the buffer.
std::shared_ptr< BufferProcessor > m_default_processor
Default audio transformation processor for this buffer.
virtual std::shared_ptr< BufferProcessor > get_default_processor() const override
Gets the current default audio transformation processor.
virtual void enforce_default_processing(bool should_process) override
Controls whether the audio buffer should use default processing.
std::vector< double > m_data
Vector storing the actual double-precision audio sample data.
virtual std::shared_ptr< BufferProcessingChain > get_processing_chain() override
Gets the audio transformation chain attached to this buffer.
bool is_internal_only() const override
Checks if the buffer is marked as internal-only.
virtual const std::vector< double > & get_data() const
Gets read-only access to the buffer's underlying audio data.
bool m_process_default
Whether the audio buffer should be processed using its default processor.
Concrete audio implementation of the Buffer interface for double-precision audio data.
Backend-agnostic interface for sequential data storage and transformation.
Definition Buffer.hpp:37