11 : m_stream_info(stream_info)
13 , m_audio_device(m_audiobackend->create_device_manager())
14 , m_subsystem_tokens {
15 .Buffer =
MayaFlux::Buffers::ProcessingToken::AUDIO_BACKEND,
16 .Node =
MayaFlux::Nodes::ProcessingToken::AUDIO_RATE,
17 .Task =
MayaFlux::Vruta::ProcessingToken::SAMPLE_ACCURATE
35#ifdef MAYAFLUX_PLATFORM_MACOS
36 m_observers_ptr.store(
new ObserverMap(), std::memory_order_release);
46 error<std::runtime_error>(
49 std::source_location::current(),
50 "AudioSubsystem not initialized");
54 [
this](
void* output_buffer,
void* input_buffer,
unsigned int num_frames) ->
int {
55 auto input_ptr =
static_cast<double*
>(input_buffer);
56 auto output_ptr =
static_cast<double*
>(output_buffer);
58 if (input_ptr && output_ptr) {
59 return this->
process_audio(input_ptr, output_ptr, num_frames);
77 if (output_buffer ==
nullptr) {
79 "No output available");
87 std::memset(output_buffer, 0, total_samples *
sizeof(
double));
95 "Invalid processing handle");
102 size_t total_samples =
static_cast<size_t>(num_frames) * num_channels;
103 std::span<double> output_span(output_buffer, total_samples);
108 std::vector<std::span<const double>> buffer_data(num_channels);
109 std::vector<std::vector<std::vector<double>>> all_network_outputs(num_channels);
110 bool has_underrun =
false;
114 for (uint32_t channel = 0; channel < num_channels; channel++) {
120 if (channel_data.size() < num_frames) {
122 "Channel buffer underrun");
125 buffer_data[channel] = std::span<const double>();
127 buffer_data[channel] = channel_data;
131 for (
size_t i = 0; i < num_frames; ++i) {
135 for (
size_t j = 0; j < num_channels; ++j) {
136 double buffer_sample = 0.0;
137 if (!buffer_data[j].empty() && i < buffer_data[j].size()) {
138 buffer_sample = buffer_data[j][i];
143 for (
const auto& network_buffer : all_network_outputs[j]) {
144 if (i < network_buffer.size()) {
145 sample += network_buffer[i];
149 size_t index = i * num_channels + j;
150 output_span[index] = std::clamp(sample, -1., 1.);
160 std::memcpy(
m_snapshot_copy.data(), output_buffer, total_samples *
sizeof(
double));
161 m_snapshot_size.store(
static_cast<uint32_t
>(total_samples), std::memory_order_release);
167 return has_underrun ? 1 : 0;
169 }
catch (
const std::exception& e) {
171 "Exception during audio output processing: {}", e.what());
175 std::memset(output_buffer, 0, total_samples *
sizeof(
double));
188 "Invalid processing handle");
196 std::memset(input_buffer, 0, total_samples *
sizeof(
double));
226 auto svc = std::make_shared<Registry::Service::AudioBackendService>();
228 svc->get_output_snapshot = [
this]() -> std::span<const double> {
236 svc->register_output_observer = [
this](
237 std::function<void(
const double*, uint32_t)> cb) -> uint32_t {
239#ifdef MAYAFLUX_PLATFORM_MACOS
246 }
while (!m_observers_ptr.compare_exchange_weak(
248 std::memory_order_release, std::memory_order_acquire));
252 std::shared_ptr<ObserverMap> next;
254 next = std::make_shared<ObserverMap>(*
current);
258 std::memory_order_release, std::memory_order_acquire));
263 svc->unregister_output_observer = [
this](uint32_t id) {
264#ifdef MAYAFLUX_PLATFORM_MACOS
271 }
while (!m_observers_ptr.compare_exchange_weak(
273 std::memory_order_release, std::memory_order_acquire));
277 std::shared_ptr<ObserverMap> next;
279 next = std::make_shared<ObserverMap>(*
current);
283 std::memory_order_release, std::memory_order_acquire));
290 [svc]() ->
void* {
return svc.get(); });
295 uint64_t last_gen = 0;
311#ifdef MAYAFLUX_PLATFORM_MACOS
312 auto [obs, slot] = acquire_observers();
314 for (
auto& [
id, cb] : *obs)
317 release_observers(slot);
319 auto obs =
m_observers.load(std::memory_order_acquire);
320 for (
auto& [
id, cb] : *obs)
326#ifdef MAYAFLUX_PLATFORM_MACOS
327std::pair<const AudioSubsystem::ObserverMap*, size_t>
328AudioSubsystem::acquire_observers()
const
330 size_t slot = m_obs_hazard_counter.fetch_add(1, std::memory_order_relaxed)
331 % MAX_OBSERVER_READERS;
334 current = m_observers_ptr.load(std::memory_order_acquire);
335 m_obs_hazard_ptrs[slot].store(
current, std::memory_order_release);
336 }
while (
current != m_observers_ptr.load(std::memory_order_acquire));
340void AudioSubsystem::release_observers(
size_t slot)
const
342 m_obs_hazard_ptrs[slot].store(
nullptr, std::memory_order_release);
345void AudioSubsystem::retire_observers(
const ObserverMap* old)
347 m_obs_retired.push_back(old);
348 auto it = m_obs_retired.begin();
349 while (it != m_obs_retired.end()) {
350 bool referenced =
false;
351 for (
size_t i = 0; i < MAX_OBSERVER_READERS; ++i) {
352 if (m_obs_hazard_ptrs[i].load(std::memory_order_acquire) == *it) {
359 it = m_obs_retired.erase(it);
370 error<std::runtime_error>(
373 std::source_location::current(),
374 "Cannot start AudioSubsystem: not initialized");
389 "Stopping AudioSubsystem...");
410 "AudioSubsystem stopped");
432 std::this_thread::yield();
452#ifdef MAYAFLUX_PLATFORM_MACOS
453 delete m_observers_ptr.exchange(
nullptr, std::memory_order_acq_rel);
#define MF_INFO(comp, ctx,...)
#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.
void wait_until_running() override
Block until the subsystem's processing loop is confirmed live.
void register_backend_service()
std::atomic< uint64_t > m_snapshot_generation
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.
std::atomic< int > m_callback_active
Active callback counter.
int process_audio(double *input_buffer, double *output_buffer, unsigned int num_frames)
Processes both input and output data in full-duplex mode.
void pause() override
Pause audio processing without stopping the stream.
std::atomic< bool > m_is_running
Subsystem running state.
void start() override
Start audio processing and streaming.
GlobalStreamInfo m_stream_info
Audio stream configuration.
std::atomic< std::shared_ptr< ObserverMap > > m_observers
SubsystemProcessingHandle * m_handle
Reference to processing handle.
bool m_is_paused
Subsystem paused state.
std::atomic< uint32_t > m_snapshot_size
std::thread m_notify_thread
int process_input(double *input_buffer, unsigned int num_frames)
Processes input data from audio interface.
std::atomic< const double * > m_snapshot_ptr
std::atomic< bool > m_notify_running
std::unordered_map< uint32_t, std::function< void(const double *, uint32_t)> > ObserverMap
std::vector< double > m_snapshot_copy
Owned copy of the last output cycle; decouples notification-thread reads from the callback write buff...
std::shared_ptr< Registry::Service::AudioBackendService > m_audio_backend_service
AudioSubsystem(GlobalStreamInfo &stream_info)
Constructs AudioSubsystem with stream configuration.
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::atomic< uint32_t > m_next_observer_id
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
void update_routing_states()
void cleanup_completed_routing()
void update_routing_states()
void cleanup_completed_routing()
std::vector< std::vector< double > > process_audio_networks(uint32_t num_samples, uint32_t channel=0)
double process_sample(uint32_t channel)
std::map< std::string, ProcessHook > post_process_hooks
TaskSchedulerHandle tasks
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.
void register_service(ServiceFactory factory)
Register a backend service capability.
static BackendRegistry & instance()
Get the global registry instance.
void unregister_service()
Unregister a service.
@ 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.
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.
Backend audio subsystem service interface.