MayaFlux 0.1.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
AudioSubsystem.cpp
Go to the documentation of this file.
1#include "AudioSubsystem.hpp"
2
4
5namespace MayaFlux::Core {
6
8 : m_stream_info(stream_info)
9 , m_audiobackend(AudioBackendFactory::create_backend(backend_type))
10 , m_audio_device(m_audiobackend->create_device_manager())
11 , m_subsystem_tokens {
12 .Buffer = MayaFlux::Buffers::ProcessingToken::AUDIO_BACKEND,
13 .Node = MayaFlux::Nodes::ProcessingToken::AUDIO_RATE,
14 .Task = MayaFlux::Vruta::ProcessingToken::SAMPLE_ACCURATE
15 }
16{
17}
18
20{
21 m_handle = &handle;
22
23 m_audio_stream = m_audiobackend->create_stream(
24 m_audio_device->get_default_output_device(),
25 m_audio_device->get_default_input_device(),
27 this);
28
29 m_is_ready = true;
30}
31
33{
34 if (!m_is_ready || !m_audio_stream) {
35 error<std::runtime_error>(
38 std::source_location::current(),
39 "AudioSubsystem not initialized");
40 }
41
42 m_audio_stream->set_process_callback(
43 [this](void* output_buffer, void* input_buffer, unsigned int num_frames) -> int {
44 auto input_ptr = static_cast<double*>(input_buffer);
45 auto output_ptr = static_cast<double*>(output_buffer);
46
47 if (input_ptr && output_ptr) {
48 return this->process_audio(input_ptr, output_ptr, num_frames);
49 }
50
51 if (output_ptr) {
52 return this->process_output(output_ptr, num_frames);
53 }
54
55 if (input_ptr) {
56 return this->process_input(input_ptr, num_frames);
57 }
58 return 0;
59 });
60}
61
62int AudioSubsystem::process_output(double* output_buffer, unsigned int num_frames)
63{
64 if (output_buffer == nullptr) {
66 "No output available");
67 return 1;
68 }
69
70 if (m_handle == nullptr) {
72 "Invalid processing handle");
73 return 1;
74 }
75
76 uint32_t num_channels = m_stream_info.output.channels;
77 size_t total_samples = static_cast<size_t>(num_frames) * num_channels;
78 std::span<double> output_span(output_buffer, total_samples);
79
80 std::vector<std::span<const double>> buffer_data(num_channels);
81 std::vector<std::vector<std::vector<double>>> all_network_outputs(num_channels);
82 bool has_underrun = false;
83
85
86 for (uint32_t channel = 0; channel < num_channels; channel++) {
87 m_handle->buffers.process_channel(channel, num_frames);
88 all_network_outputs[channel] = m_handle->nodes.process_audio_networks(num_frames, channel);
89
90 auto channel_data = m_handle->buffers.read_channel_data(channel);
91
92 if (channel_data.size() < num_frames) {
94 "Channel buffer underrun");
95 has_underrun = true;
96
97 buffer_data[channel] = std::span<const double>();
98 } else {
99 buffer_data[channel] = channel_data;
100 }
101 }
102
103 for (size_t i = 0; i < num_frames; ++i) {
105 for (size_t j = 0; j < num_channels; ++j) {
106 double buffer_sample = 0.0;
107 if (!buffer_data[j].empty() && i < buffer_data[j].size()) {
108 buffer_sample = buffer_data[j][i];
109 }
110
111 double sample = m_handle->nodes.process_sample(j) + buffer_sample;
112
113 for (const auto& network_buffer : all_network_outputs[j]) {
114 if (i < network_buffer.size()) {
115 sample += network_buffer[i];
116 }
117 }
118
119 size_t index = i * num_channels + j;
120 output_span[index] = std::clamp(sample, -1., 1.);
121 }
122 }
123
124 return has_underrun ? 1 : 0;
125}
126
127int AudioSubsystem::process_input(double* input_buffer, unsigned int num_frames)
128{
129 m_handle->buffers.process_input(input_buffer, m_stream_info.input.channels, num_frames);
130 return 0;
131}
132
133int AudioSubsystem::process_audio(double* input_buffer, double* output_buffer, unsigned int num_frames)
134{
135 for (const auto& [name, hook] : m_handle->pre_process_hooks) {
136 hook(num_frames);
137 }
138
139 process_input(input_buffer, num_frames);
140 process_output(output_buffer, num_frames);
141
142 for (const auto& [name, hook] : m_handle->post_process_hooks) {
143 hook(num_frames);
144 }
145
146 return 0;
147}
148
150{
151 if (!m_is_ready || !m_audio_stream) {
152 error<std::runtime_error>(
155 std::source_location::current(),
156 "Cannot start AudioSubsystem: not initialized");
157 }
158
159 m_audio_stream->open();
160 m_audio_stream->start();
161 m_is_running = true;
162}
163
165{
166 if (m_audio_stream && m_audio_stream->is_running()) {
167 m_audio_stream->stop();
168 m_is_running = false;
169 }
170}
171
173{
175 m_audio_stream->stop();
176 m_is_paused = true;
177 }
178}
179
181{
183 m_audio_stream->start();
184 m_is_paused = false;
185 }
186}
187
189{
190 stop();
191 if (m_audio_stream) {
192 m_audio_stream.reset();
193 }
194 m_audio_device.reset();
195 m_audiobackend.reset();
196 m_is_ready = false;
197}
198}
#define MF_RT_WARN(comp, ctx,...)
#define MF_RT_ERROR(comp, ctx,...)
Factory pattern implementation for audio backend instantiation.
void initialize(SubsystemProcessingHandle &handle) override
Initialize audio processing with provided handle.
bool m_is_ready
Subsystem ready state.
void stop() override
Stop audio processing and streaming.
void shutdown() override
Shutdown and cleanup audio resources.
std::unique_ptr< IAudioBackend > m_audiobackend
Audio backend implementation.
int process_output(double *output_buffer, unsigned int num_frames)
Processes output data for audio interface.
int process_audio(double *input_buffer, double *output_buffer, unsigned int num_frames)
Processes both input and output data in full-duplex mode.
AudioSubsystem(GlobalStreamInfo &stream_info, Utils::AudioBackendType backend_type=Utils::AudioBackendType::RTAUDIO)
Constructs AudioSubsystem with stream configuration.
void pause() override
Pause audio processing without stopping the stream.
bool m_is_running
Subsystem running state.
void start() override
Start audio processing and streaming.
GlobalStreamInfo m_stream_info
Audio stream configuration.
SubsystemProcessingHandle * m_handle
Reference to processing handle.
bool m_is_paused
Subsystem paused state.
int process_input(double *input_buffer, unsigned int num_frames)
Processes input data from audio interface.
void resume() override
Resume audio processing after pause.
std::unique_ptr< AudioDevice > m_audio_device
Audio device manager.
std::unique_ptr< AudioStream > m_audio_stream
Audio stream manager.
void register_callbacks() override
Register audio backend callbacks for real-time processing.
std::span< const double > read_channel_data(uint32_t channel) const
Get read-only access to channel data.
void process_channel(uint32_t channel, uint32_t processing_units)
Process specific channel.
void process_input(double *input_data, uint32_t num_channels, uint32_t num_frames)
@brienf Process Input from backend into buffer manager
std::vector< std::vector< double > > process_audio_networks(uint32_t num_samples, uint32_t channel=0)
std::map< std::string, ProcessHook > post_process_hooks
NodeProcessingHandle nodes
Node processing interface.
std::map< std::string, ProcessHook > pre_process_hooks
BufferProcessingHandle buffers
Buffer processing interface.
Unified interface combining buffer and node processing for subsystems.
void process_buffer_cycle()
Process all tasks scheduled for current buffer cycle.
void process(uint64_t processing_units)
Process all tasks in token domain.
@ AudioSubsystem
Audio subsystem operations (backend, device, stream management)
@ AudioCallback
Audio callback thread - strictest real-time requirements.
@ Core
Core engine, backend, subsystems.
Main namespace for the Maya Flux audio engine.
Definition LiveAid.hpp:6
uint32_t channels
Number of discrete channels in this set.
ChannelConfig input
Configuration for input signal channels (disabled by default)
ChannelConfig output
Configuration for output signal channels.
Comprehensive configuration for digital audio stream processing.