MayaFlux 0.5.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
AudioOutputAccessProcessor.cpp
Go to the documentation of this file.
2
4
7
9
10namespace MayaFlux::Kakshya {
11
13 : m_buffer_size(buffer_size)
14 , m_backend_service(
15 Registry::BackendRegistry::instance()
16 .get_service<Registry::Service::AudioBackendService>())
17{
18 if (!m_backend_service) {
20 "AudioOutputAccessProcessor: AudioBackendService not yet registered"
21 "process() calls will be no-ops until the service is available");
22 }
23}
24
26 const std::shared_ptr<SignalSourceContainer>& container)
27{
28 auto ac = std::dynamic_pointer_cast<AudioOutputContainer>(container);
29 if (!ac) {
30 error<std::invalid_argument>(
33 std::source_location::current(),
34 "AudioOutputAccessProcessor requires an AudioOutputContainer");
35 }
36
37 m_channel_count = ac->get_structure().get_channel_count();
38 m_organization = ac->get_structure().organization;
39
40 ac->mark_ready_for_processing(true);
41
43 "AudioOutputAccessProcessor attached: {} channels, {} frames/cycle, {}",
45 m_organization == OrganizationStrategy::PLANAR ? "planar" : "interleaved");
46}
47
49 const std::shared_ptr<SignalSourceContainer>& /*container*/)
50{
52 m_buffer_size = 0;
53}
54
56 const std::shared_ptr<SignalSourceContainer>& container)
57{
58 if (m_is_processing.exchange(true, std::memory_order_acq_rel))
59 return;
60
61 auto ac = std::dynamic_pointer_cast<AudioOutputContainer>(container);
62 if (!ac) {
64 "AudioOutputAccessProcessor requires an AudioOutputContainer");
65 m_is_processing.store(false, std::memory_order_release);
66 return;
67 }
68
69 if (!m_backend_service) {
71 "AudioBackendService unavailable");
72 m_is_processing.store(false, std::memory_order_release);
73 return;
74 }
75
76 const auto snap = m_backend_service->get_output_snapshot();
77 if (snap.empty()) {
79 "AudioOutputAccessProcessor: snapshot empty, no cycle completed yet");
80 m_is_processing.store(false, std::memory_order_release);
81 return;
82 }
83
84 ac->update_processing_state(ProcessingState::PROCESSING);
85
86 thread_local std::vector<std::vector<double>> tl_channels;
87
88 tl_channels.resize(m_channel_count);
89 for (auto& ch : tl_channels)
90 ch.resize(m_buffer_size);
91
93 for (uint32_t ch = 0; ch < m_channel_count; ++ch) {
94 for (uint32_t f = 0; f < m_buffer_size; ++f) {
95 tl_channels[ch][f] = snap[f * m_channel_count + ch];
96 }
97 }
98 } else {
99 tl_channels[0].assign(snap.begin(), snap.end());
100 }
101
102 {
103 Memory::SeqlockWriteGuard g(ac->m_data_lock);
104 auto& pd = ac->get_processed_data();
106 pd.resize(m_channel_count);
107 for (uint32_t ch = 0; ch < m_channel_count; ++ch)
108 pd[ch] = DataVariant(tl_channels[ch]);
109 } else {
110 pd.resize(1);
111 pd[0] = DataVariant(tl_channels[0]);
112 }
113 }
114
115 const uint64_t write_head = ac->get_num_frames();
116
117 {
118 Memory::SeqlockWriteGuard g(ac->m_data_lock);
120 if (ac->m_data.size() < m_channel_count)
121 ac->m_data.resize(m_channel_count, DataVariant(std::vector<double> {}));
122 for (uint32_t ch = 0; ch < m_channel_count; ++ch) {
123 auto& vec = std::get<std::vector<double>>(ac->m_data[ch]);
124 vec.insert(vec.end(), tl_channels[ch].begin(), tl_channels[ch].end());
125 }
126 } else {
127 if (ac->m_data.empty())
128 ac->m_data.resize(1, DataVariant(std::vector<double> {}));
129 auto& vec = std::get<std::vector<double>>(ac->m_data[0]);
130 vec.insert(vec.end(), tl_channels[0].begin(), tl_channels[0].end());
131 }
132 ac->m_num_frames += m_buffer_size;
133 ac->setup_dimensions();
134 ac->invalidate_span_cache();
135 ac->m_double_extraction_dirty.store(true, std::memory_order_release);
136 }
137
138 ac->update_processing_state(ProcessingState::PROCESSED);
139 m_is_processing.store(false, std::memory_order_release);
140}
141
142} // namespace MayaFlux::Kakshya
#define MF_INFO(comp, ctx,...)
#define MF_RT_WARN(comp, ctx,...)
#define MF_RT_ERROR(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
AudioOutputAccessProcessor(uint32_t buffer_size)
Construct with the fixed output block size.
void on_attach(const std::shared_ptr< SignalSourceContainer > &container) override
Validate container type, cache structure, mark ready for processing.
Registry::Service::AudioBackendService * m_backend_service
void process(const std::shared_ptr< SignalSourceContainer > &container) override
Pull engine snapshot, write m_processed_data, append to m_data.
void on_detach(const std::shared_ptr< SignalSourceContainer > &container) override
Clear cached state.
RAII guard that brackets a Seqlock write region.
Definition SeqLock.hpp:136
@ Configuration
Configuration and parameter updates.
@ ContainerProcessing
Container operations (Kakshya - file/stream/region processing)
@ Kakshya
Containers[Signalsource, Stream, File], Regions, DataProcessors.
@ PROCESSING
Container is actively being processed.
@ PROCESSED
Container has completed processing and results are available.
std::variant< std::vector< double >, std::vector< float >, std::vector< uint8_t >, std::vector< uint16_t >, std::vector< uint32_t >, std::vector< std::complex< float > >, std::vector< std::complex< double > >, std::vector< glm::vec2 >, std::vector< glm::vec3 >, std::vector< glm::vec4 >, std::vector< glm::mat4 > > DataVariant
Multi-type data storage for different precision needs.
Definition NDData.hpp:102
@ PLANAR
Separate DataVariant per logical unit (LLL...RRR for stereo)
std::function< std::span< const double >()> get_output_snapshot
Returns a span over the last committed interleaved output buffer.