MayaFlux 0.3.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
ContiguousAccessProcessor.cpp
Go to the documentation of this file.
2
4
7
8namespace MayaFlux::Kakshya {
9
10void ContiguousAccessProcessor::on_attach(const std::shared_ptr<SignalSourceContainer>& container)
11{
12 if (!container) {
13 return;
14 }
15
16 m_source_container_weak = container;
17
18 try {
19 store_metadata(container);
20 validate();
21
22 m_prepared = true;
23 container->mark_ready_for_processing(true);
24
26 "ContiguousAccessProcessor attached: {} layout, {} total elements, {} channels",
27 (m_structure.organization == OrganizationStrategy::INTERLEAVED ? "interleaved" : "planar"),
30
31 } catch (const std::exception& e) {
32 m_prepared = false;
34 std::source_location::current(),
35 "Failed to attach ContiguousAccessProcessor: {}",
36 e.what());
37 }
38}
39
40void ContiguousAccessProcessor::store_metadata(const std::shared_ptr<SignalSourceContainer>& container)
41{
42 m_structure = container->get_structure();
44
45 if (m_current_position.empty()) {
46 uint64_t num_channels = m_structure.get_channel_count();
47 m_current_position.assign(num_channels, 0);
48 }
49
50 if (m_output_shape.empty()) {
51 uint64_t num_frames = m_structure.get_samples_count_per_channel();
52 uint64_t num_channels = m_structure.get_channel_count();
53
55 std::min<uint64_t>(1024UL, num_frames),
56 num_channels
57 };
58 }
59
60 if (auto stream = std::dynamic_pointer_cast<StreamContainer>(container)) {
61 m_looping_enabled = stream->is_looping();
62 m_loop_region = stream->get_loop_region();
63
64 auto stream_positions = stream->get_read_position();
65 if (!stream_positions.empty()) {
66 m_current_position = stream_positions;
67 }
68 }
69}
70
72{
73 if (m_total_elements == 0) {
75 "ContiguousAccessProcessor validation: Container has no data elements");
76 }
77
78 if (m_output_shape.size() != 2) {
80 std::source_location::current(),
81 "Audio output shape must be [frames, channels]");
82 }
83
84 uint64_t frames_requested = m_output_shape[0];
85 uint64_t channels_requested = m_output_shape[1];
86 uint64_t available_channels = m_structure.get_channel_count();
87
88 if (frames_requested == 0 || channels_requested == 0) {
90 std::source_location::current(),
91 "Frame and channel counts cannot be zero");
92 }
93
94 if (frames_requested > m_structure.get_samples_count_per_channel()) {
96 std::source_location::current(),
97 "Requested {} frames exceeds available {} samples per channel",
98 frames_requested,
100 }
101
102 if (channels_requested > available_channels) {
104 std::source_location::current(),
105 "Requested {} channels exceeds available {} channels",
106 channels_requested,
107 available_channels);
108 }
109
110 if (m_current_position.size() != available_channels) {
112 "Current position size {} doesn't match available channel count {}, resetting positions",
113 m_current_position.size(),
114 available_channels);
115 m_current_position.resize(available_channels, 0);
116 }
117
119 "ContiguousAccessProcessor validated: memory layout {}, processing {}×{} blocks, current positions for {} channels",
120 (m_structure.organization == OrganizationStrategy::INTERLEAVED ? "interleaved" : "planar"),
121 frames_requested,
122 channels_requested, m_current_position.size());
123}
124
125void ContiguousAccessProcessor::on_detach(const std::shared_ptr<SignalSourceContainer>& /*container*/)
126{
128 m_current_position.clear();
129 m_prepared = false;
131}
132
133void ContiguousAccessProcessor::process(const std::shared_ptr<SignalSourceContainer>& container)
134{
135 if (!m_prepared) {
137 "ContiguousAccessProcessor not prepared for processing");
138 return;
139 }
140
141 auto source_container = m_source_container_weak.lock();
142 if (!source_container || source_container.get() != container.get()) {
144 "ContiguousAccessProcessor: Source container mismatch or expired");
145 return;
146 }
147
148 m_is_processing = true;
149 m_last_process_time = std::chrono::steady_clock::now();
150
151 try {
152 uint64_t min_frame = *std::ranges::min_element(m_current_position);
153 std::vector<uint64_t> region_coords = { min_frame, 0 };
154
155 Region output_region = calculate_output_region(region_coords, m_output_shape);
156
157 auto region_data = container->get_region_data(output_region);
158 auto& processed_data_vector = container->get_processed_data();
159
161 processed_data_vector.resize(1);
162 if (!region_data.empty()) {
163 safe_copy_data_variant(region_data[0], processed_data_vector[0]);
164 }
165 } else {
166 uint64_t channels_to_process = std::min(m_output_shape[1], static_cast<uint64_t>(region_data.size()));
167 processed_data_vector.resize(channels_to_process);
168
169 for (size_t ch = 0; ch < channels_to_process; ++ch) {
170 safe_copy_data_variant(region_data[ch], processed_data_vector[ch]);
171 }
172 }
173
174 if (m_auto_advance) {
175 uint64_t frames_to_advance = m_output_shape[0];
176
179 frames_to_advance,
183
184 if (auto stream = std::dynamic_pointer_cast<StreamContainer>(container)) {
185 stream->set_read_position(m_current_position);
186 }
187 }
188
189 container->update_processing_state(ProcessingState::PROCESSED);
190 } catch (const std::exception& e) {
192 "Error during ContiguousAccessProcessor processing: {}",
193 e.what());
194 container->update_processing_state(ProcessingState::ERROR);
195 }
196
197 m_is_processing = false;
198}
199
200void ContiguousAccessProcessor::set_output_size(const std::vector<uint64_t>& shape)
201{
202 m_output_shape = shape;
203 if (auto container = m_source_container_weak.lock()) {
204 store_metadata(container);
205 validate();
206 }
207}
208
209} // namespace MayaFlux::Kakshya
#define MF_INFO(comp, ctx,...)
#define MF_ERROR(comp, ctx,...)
#define MF_RT_ERROR(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
void set_output_size(const std::vector< uint64_t > &shape)
Set the output buffer size (shape) for each processing call.
void on_detach(const std::shared_ptr< SignalSourceContainer > &container) override
Detach the processor from its container.
void validate()
Validate the container's structure and output configuration.
std::chrono::steady_clock::time_point m_last_process_time
void on_attach(const std::shared_ptr< SignalSourceContainer > &container) override
Attach the processor to a signal source container.
void store_metadata(const std::shared_ptr< SignalSourceContainer > &container)
Store dimension and layout metadata from the container.
void process(const std::shared_ptr< SignalSourceContainer > &container) override
Process the current region or block of data.
std::weak_ptr< SignalSourceContainer > m_source_container_weak
@ ContainerProcessing
Container operations (Kakshya - file/stream/region processing)
@ Kakshya
Containers[Signalsource, Stream, File], Regions, DataProcessors.
@ ERROR
Container is in an error state and cannot proceed.
@ PROCESSED
Container has completed processing and results are available.
std::vector< uint64_t > advance_position(const std::vector< uint64_t > &current_positions, uint64_t frames_to_advance, const ContainerDataStructure &structure, bool looping_enabled, const Region &loop_region)
Advance current positions by a number of frames, with optional looping.
@ INTERLEAVED
Single DataVariant with interleaved data (LRLRLR for stereo)
void safe_copy_data_variant(const DataVariant &input, DataVariant &output)
Safely copy data from a DataVariant to another DataVariant, handling type conversion.
Definition DataUtils.cpp:34
Region calculate_output_region(const std::vector< uint64_t > &current_pos, const std::vector< uint64_t > &output_shape)
Calculate output region bounds from current position and shape.
static uint64_t get_channel_count(const std::vector< DataDimension > &dimensions)
Extract channel count from dimensions.
static uint64_t get_samples_count_per_channel(const std::vector< DataDimension > &dimensions)
Get samples per channel (time dimension only).
static uint64_t get_total_elements(const std::vector< DataDimension > &dimensions)
Get total elements across all dimensions.
Represents a point or span in N-dimensional space.
Definition Region.hpp:67