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