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