MayaFlux 1.0.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
SoundStreamContainer.cpp
Go to the documentation of this file.
2
5
8
9namespace MayaFlux::Kakshya {
10
11SoundStreamContainer::SoundStreamContainer(uint32_t sample_rate, uint32_t num_channels,
12 uint64_t initial_capacity, bool circular_mode)
13 : m_sample_rate(sample_rate)
14 , m_num_channels(num_channels)
15 , m_num_frames(initial_capacity)
16 , m_circular_mode(circular_mode)
17{
18 m_processing_chain = std::make_shared<DataProcessingChain>();
20
21 m_read_position = std::vector<std::atomic<uint64_t>>(m_num_channels);
22 for (auto& pos : m_read_position) {
23 pos.store(0);
24 }
25
26 m_data = std::views::iota(0U, num_channels)
27 | std::views::transform([](auto) { return DataVariant(std::vector<double> {}); })
28 | std::ranges::to<std::vector>();
29}
30
32{
33 DataModality modality = (m_num_channels > 1)
36
37 std::vector<uint64_t> shape;
38 if (modality == DataModality::AUDIO_1D) {
39 shape = { m_num_frames };
40 } else {
41 shape = { m_num_frames, m_num_channels };
42 }
43
44 auto layout = m_structure.memory_layout;
46
47 m_structure = ContainerDataStructure(modality, org, layout);
49
52}
53
54std::vector<DataDimension> SoundStreamContainer::get_dimensions() const
55{
57}
58
63
73
75{
76 // return m_structure.get_channel_count();
77 return m_num_channels;
78}
79
81{
82 // return m_structure.get_samples_count_per_channel();
83 return m_num_frames;
84}
85
86std::vector<DataVariant> SoundStreamContainer::get_region_data(const Region& region) const
87{
88 const auto& spans = get_span_cache();
89
91 if (spans.empty())
92 return {};
93
94 std::span<const double> const_span(spans[0].data(), spans[0].size());
95 auto extracted = extract_region_data<double>(const_span, region, m_structure.dimensions);
96 return { DataVariant(std::move(extracted)) };
97 }
98
99 auto const_spans = spans | std::views::transform([](const auto& span) {
100 return std::span<const double>(span.data(), span.size());
101 });
102
103 auto extracted_channels = extract_region_data<double>(
104 std::vector<std::span<const double>>(const_spans.begin(), const_spans.end()),
105 region, m_structure.dimensions);
106
107 return extracted_channels
108 | std::views::transform([](auto&& channel) {
109 return DataVariant(std::forward<decltype(channel)>(channel));
110 })
111 | std::ranges::to<std::vector>();
112}
113
114void SoundStreamContainer::set_region_data(const Region& region, const std::vector<DataVariant>& data)
115{
117 if (m_data.empty() || data.empty())
118 return;
119
121 auto dest_span = convert_variant<double>(m_data[0]);
122 auto src_span = convert_variant<double>(data[0]);
123
124 set_or_update_region_data<double>(dest_span, src_span, region, m_structure.dimensions);
125 } else {
126 size_t channels_to_update = std::min(m_data.size(), data.size());
128
129 for (size_t i = 0; i < channels_to_update; ++i) {
130 auto dest_span = convert_variant<double>(m_data[i]);
131 auto src_span = convert_variant<double>(data[i]);
132 set_or_update_region_data<double>(dest_span, src_span, region, m_structure.dimensions);
133 }
134 }
135
137 m_double_extraction_dirty.store(true, std::memory_order_release);
138}
139
140std::vector<DataVariant> SoundStreamContainer::get_region_group_data(const RegionGroup& region_group) const
141{
142 const auto& spans = get_span_cache();
143
144 if (spans.empty())
145 return {};
146
147 auto const_spans = spans | std::views::transform([](const auto& span) {
148 return std::span<const double>(span.data(), span.size());
149 });
150
151 auto extracted_channels = extract_group_data<double>(
152 std::vector<std::span<const double>>(const_spans.begin(), const_spans.end()),
154
155 return extracted_channels
156 | std::views::transform([](auto&& channel) {
157 return DataVariant(std::forward<decltype(channel)>(channel));
158 })
159 | std::ranges::to<std::vector>();
160}
161
162std::vector<DataVariant> SoundStreamContainer::get_segments_data(const std::vector<RegionSegment>& segments) const
163{
164 const auto& spans = get_span_cache();
165
166 if (spans.empty() || segments.empty())
167 return {};
168
169 auto const_spans = spans | std::views::transform([](const auto& span) {
170 return std::span<const double>(span.data(), span.size());
171 });
172
173 auto extracted_channels = extract_segments_data<double>(
174 segments,
175 std::vector<std::span<const double>>(const_spans.begin(), const_spans.end()),
177
178 return extracted_channels
179 | std::views::transform([](auto&& channel) {
180 return DataVariant(std::forward<decltype(channel)>(channel));
181 })
182 | std::ranges::to<std::vector>();
183}
184
185void SoundStreamContainer::gather_frames(std::span<const uint64_t> frames, std::span<double> out) const
186{
187 std::ranges::fill(out, 0.0);
188
189 const uint64_t channels = m_num_channels;
190 const auto& spans = get_span_cache();
191 if (spans.empty() || channels == 0) {
192 return;
193 }
194
196 const size_t count = std::min<size_t>(frames.size(), out.size() / channels);
197
198 for (size_t k = 0; k < count; ++k) {
199 const uint64_t frame = frames[k];
200 if (frame >= m_num_frames) {
201 continue;
202 }
203
204 double* dst = out.data() + k * channels;
205
206 if (interleaved) {
207 const uint64_t base = frame * channels;
208 if (base + channels <= spans[0].size()) {
209 std::copy_n(spans[0].data() + base, channels, dst);
210 }
211 continue;
212 }
213
214 for (uint64_t c = 0; c < channels && c < spans.size(); ++c) {
215 if (frame < spans[c].size()) {
216 dst[c] = spans[c][frame];
217 }
218 }
219 }
220}
221
222void SoundStreamContainer::get_frames_impl(void* output, size_t count, uint64_t start_frame, uint64_t num_frames, const std::type_info& type) const
223{
224 if (type == typeid(double)) {
225 get_frames_typed(std::span<double>(static_cast<double*>(output), count), start_frame, num_frames);
226 return;
227 }
229 "SoundStreamContainer::get_frames_impl: unsupported type requested");
230}
231
232std::span<const double> SoundStreamContainer::get_frame_typed(uint64_t frame_index) const
233{
234 if (frame_index >= m_num_frames) {
235 return {};
236 }
237
238 const auto& spans = get_span_cache();
239
241 if (spans.empty())
242 return {};
243
244 auto frame_span = extract_frame<double>(spans[0], frame_index, m_num_channels);
245 return { frame_span.data(), frame_span.size() };
246 }
247
248 static thread_local std::vector<double> frame_buffer;
249 auto frame_span = extract_frame<double>(spans, frame_index, frame_buffer);
250 return { frame_span.data(), frame_span.size() };
251}
252
253void SoundStreamContainer::get_frames_typed(std::span<double> output, uint64_t start_frame, uint64_t num_frames) const
254{
255 if (start_frame >= m_num_frames || output.empty()) {
256 std::ranges::fill(output, 0.0);
257 return;
258 }
259
260 uint64_t frames_to_copy = std::min<size_t>(num_frames, m_num_frames - start_frame);
261 uint64_t elements_to_copy = std::min(
262 frames_to_copy * m_num_channels,
263 static_cast<uint64_t>(output.size()));
264
265 auto interleaved_data = get_data_as_double();
266 uint64_t offset = start_frame * m_num_channels;
267
268 if (offset < interleaved_data.size()) {
269 uint64_t available = std::min<size_t>(elements_to_copy, interleaved_data.size() - offset);
270 std::copy_n(interleaved_data.begin() + offset, available, output.begin());
271
272 if (available < output.size()) {
273 std::fill(output.begin() + available, output.end(), 0.0);
274 }
275 } else {
276 std::ranges::fill(output, 0.0);
277 }
278}
279
280uint64_t SoundStreamContainer::coordinates_to_linear_index(const std::vector<uint64_t>& coordinates) const
281{
282 return coordinates_to_linear(coordinates, m_structure.dimensions);
283}
284
285std::vector<uint64_t> SoundStreamContainer::linear_index_to_coordinates(uint64_t linear_index) const
286{
287 return linear_to_coordinates(linear_index, m_structure.dimensions);
288}
289
291{
292 {
294 std::ranges::for_each(m_data, [](auto& vec) {
295 std::visit([](auto& v) { v.clear(); }, vec);
296 });
297 std::ranges::for_each(m_processed_data, [](auto& vec) {
298 std::visit([](auto& v) { v.clear(); }, vec);
299 });
300 m_num_frames = 0;
302 m_read_position = std::vector<std::atomic<uint64_t>>(m_num_channels);
303 for (auto& pos : m_read_position)
304 pos.store(0);
306 }
307
310}
311
313{
314 auto span = get_data_as_double();
315 return span.empty() ? nullptr : span.data();
316}
317
319{
320 bool result = false;
321 seqlock_read_void(m_data_lock, 8, [&] {
322 result = std::ranges::any_of(m_data, [](const auto& variant) {
323 return std::visit([](const auto& vec) { return !vec.empty(); }, variant);
324 });
325 });
326 return result;
327}
328
334
336{
337 static const RegionGroup empty_group;
338
339 std::optional<RegionGroup> result;
340 seqlock_read_void(m_region_lock, 8, [&] {
341 auto it = m_region_groups.find(name);
342 result = (it != m_region_groups.end()) ? it->second : empty_group;
343 });
344 return result.value_or(empty_group);
345}
346
347std::unordered_map<std::string, RegionGroup> SoundStreamContainer::get_all_region_groups() const
348{
349 std::optional<std::unordered_map<std::string, RegionGroup>> result;
350
351 seqlock_read_void(m_region_lock, 8, [&] {
352 result = m_region_groups;
353 });
354 return result.value_or(std::unordered_map<std::string, RegionGroup> {});
355}
356
362
364{
365 return true;
366}
367
369{
370 // No-op for in-memory container
371}
372
374{
375 // No-op for in-memory container
376}
377
378void SoundStreamContainer::set_read_position(const std::vector<uint64_t>& position)
379{
380 if (m_read_position.size() != position.size()) {
381 m_read_position = std::vector<std::atomic<uint64_t>>(position.size());
382 }
383
385
386 for (size_t i = 0; i < wrapped_pos.size(); ++i) {
387 m_read_position[i].store(wrapped_pos[i]);
388 }
389}
390
392{
393 if (channel < m_read_position.size()) {
394 m_read_position[channel].store(frame);
395 }
396}
397
398const std::vector<uint64_t>& SoundStreamContainer::get_read_position() const
399{
400 static thread_local std::vector<uint64_t> pos_cache;
401 pos_cache.resize(m_read_position.size());
402
403 for (size_t i = 0; i < m_read_position.size(); ++i) {
404 pos_cache[i] = m_read_position[i].load();
405 }
406
407 return pos_cache;
408}
409
410void SoundStreamContainer::advance_read_position(const std::vector<uint64_t>& frames)
411{
412 if (frames.empty())
413 return;
414
415 std::vector<uint64_t> current_pos(m_read_position.size());
416 for (size_t i = 0; i < m_read_position.size(); ++i) {
417 current_pos[i] = m_read_position[i].load();
418 }
419
420 auto new_pos = advance_position(current_pos, frames, m_structure, m_looping_enabled, m_loop_region);
421
422 for (size_t i = 0; i < new_pos.size() && i < m_read_position.size(); ++i) {
423 m_read_position[i].store(new_pos[i]);
424 }
425}
426
428{
429 if (m_looping_enabled) {
430 return false;
431 }
432
433 if (m_read_position.empty()) {
434 return true;
435 }
436
437 uint64_t current_frame = m_read_position[0].load();
438 return current_frame >= m_num_frames;
439}
440
442{
443 std::vector<uint64_t> start_pos;
444
447 } else {
448 start_pos = std::vector<uint64_t>(m_num_channels, 0);
449 }
450
451 if (m_read_position.size() != start_pos.size()) {
452 m_read_position = std::vector<std::atomic<uint64_t>>(start_pos.size());
453 }
454
455 for (size_t i = 0; i < start_pos.size(); ++i) {
456 m_read_position[i].store(start_pos[i]);
457 }
458}
459
460uint64_t SoundStreamContainer::time_to_position(double time) const
461{
463}
464
469
471{
472 m_looping_enabled = enable;
473 if (enable && m_loop_region.start_coordinates.empty()) {
475 }
476}
477
479{
480 m_loop_region = region;
481
482 if (m_looping_enabled && !region.start_coordinates.empty()) {
483 std::vector<uint64_t> current_pos(m_read_position.size());
484 for (size_t i = 0; i < m_read_position.size(); ++i) {
485 current_pos[i] = m_read_position[i].load();
486 }
487
488 bool outside_loop = false;
489 for (size_t i = 0; i < current_pos.size() && i < region.start_coordinates.size() && i < region.end_coordinates.size(); ++i) {
490 if (current_pos[i] < region.start_coordinates[i] || current_pos[i] > region.end_coordinates[i]) {
491 outside_loop = true;
492 break;
493 }
494 }
495
496 if (outside_loop) {
498 }
499 }
500}
501
506
508{
509 auto state = get_processing_state();
510 return has_data() && (state == ProcessingState::READY || state == ProcessingState::PROCESSED);
511}
512
514{
515 std::vector<uint64_t> frames(m_num_channels);
516 if (m_looping_enabled || m_read_position.empty()) {
517
518 for (auto& frame : frames) {
519 frame = std::numeric_limits<uint64_t>::max();
520 }
521 return frames;
522 }
523
524 for (size_t i = 0; i < frames.size(); i++) {
525 uint64_t current_frame = m_read_position[i].load();
526 frames[i] = (current_frame < m_num_frames) ? (m_num_frames - current_frame) : 0;
527 }
528 return frames;
529}
530
531uint64_t SoundStreamContainer::read_sequential(std::span<double> output, uint64_t count)
532{
533 uint64_t frames_read = peek_sequential(output, count, 0);
534
535 uint64_t frames_to_advance = frames_read / m_num_channels;
536 std::vector<uint64_t> advance_amount(m_num_channels, frames_to_advance);
537
538 advance_read_position(advance_amount);
539 return frames_read;
540}
541
542uint64_t SoundStreamContainer::peek_sequential(std::span<double> output, uint64_t count, uint64_t offset) const
543{
544 auto interleaved_span = get_data_as_double();
545 if (interleaved_span.empty() || output.empty())
546 return 0;
547
548 uint64_t start_frame = m_read_position.empty() ? 0 : m_read_position[0].load();
549 start_frame += offset;
550 uint64_t elements_to_read = std::min<uint64_t>(count, static_cast<uint64_t>(output.size()));
551
552 if (!m_looping_enabled) {
553 uint64_t linear_start = start_frame * m_num_channels;
554 if (linear_start >= interleaved_span.size()) {
555 std::ranges::fill(output, 0.0);
556 return 0;
557 }
558 auto view = interleaved_span
559 | std::views::drop(linear_start)
560 | std::views::take(elements_to_read);
561
562 auto copied = std::ranges::copy(view, output.begin());
563 std::ranges::fill(output.subspan(copied.out - output.begin()), 0.0);
564 return static_cast<uint64_t>(copied.out - output.begin());
565 }
566
567 if (m_loop_region.start_coordinates.empty()) {
568 std::ranges::fill(output, 0.0);
569 return 0;
570 }
571
572 uint64_t loop_start_frame = m_loop_region.start_coordinates[0];
573 uint64_t loop_end_frame = m_loop_region.end_coordinates[0];
574 uint64_t loop_length_frames = loop_end_frame - loop_start_frame + 1;
575
576 std::ranges::for_each(
577 std::views::iota(0UZ, elements_to_read),
578 [&](uint64_t i) {
579 uint64_t element_pos = start_frame * m_num_channels + i;
580 uint64_t frame_pos = element_pos / m_num_channels;
581 uint64_t channel_offset = element_pos % m_num_channels;
582
583 uint64_t wrapped_frame = ((frame_pos - loop_start_frame) % loop_length_frames) + loop_start_frame;
584 uint64_t wrapped_element = wrapped_frame * m_num_channels + channel_offset;
585
586 output[i] = (wrapped_element < interleaved_span.size()) ? interleaved_span[wrapped_element] : 0.0;
587 });
588
589 if (elements_to_read < output.size()) {
590 std::ranges::fill(output.subspan(elements_to_read), 0.0);
591 }
592 return elements_to_read;
593}
594
596{
597 ProcessingState old_state = m_processing_state.exchange(new_state);
598
599 if (old_state != new_state) {
600 notify_state_change(new_state);
601
602 if (new_state == ProcessingState::READY) {
604 m_consumed_dimensions.clear();
605 }
606 }
607}
608
610{
611 seqlock_read_void(m_cb_lock, 8, [&] {
613 m_state_callback(shared_from_this(), new_state);
614 });
615}
616
618{
619 auto state = get_processing_state();
620 return has_data() && (state == ProcessingState::READY || state == ProcessingState::PROCESSED);
621}
622
631
633{
634 auto processor = std::make_shared<ContiguousAccessProcessor>();
635 set_default_processor(processor);
636}
637
646
647void SoundStreamContainer::set_default_processor(const std::shared_ptr<DataProcessor>& processor)
648{
649 auto old_processor = m_default_processor;
650 m_default_processor = processor;
651
652 if (old_processor) {
653 old_processor->on_detach(shared_from_this());
654 }
655
656 if (processor) {
657 processor->on_attach(shared_from_this());
658 }
659}
660
661std::shared_ptr<DataProcessor> SoundStreamContainer::get_default_processor() const
662{
663 return m_default_processor;
664}
665
666std::shared_ptr<DataProcessingChain> SoundStreamContainer::get_processing_chain()
667{
668 if (!m_processing_chain) {
669 m_processing_chain = std::make_shared<DataProcessingChain>();
670 }
671 return m_processing_chain;
672}
673
674uint32_t SoundStreamContainer::register_dimension_reader(uint32_t dimension_index)
675{
677 m_active_readers[dimension_index]++;
678 uint32_t reader_id = m_dimension_to_next_reader_id[dimension_index]++;
679 m_reader_consumed_dimensions[reader_id] = std::unordered_set<uint32_t>();
680 return reader_id;
681}
682
684{
686 if (auto it = m_active_readers.find(dimension_index); it != m_active_readers.end()) {
687 auto& [dim, count] = *it;
688 if (--count <= 0) {
689 m_active_readers.erase(it);
690 m_dimension_to_next_reader_id.erase(dimension_index);
691 }
692 }
693}
694
696{
697 bool result = false;
698 seqlock_read_void(m_reader_lock, 8, [&] {
699 result = !m_active_readers.empty();
700 });
701 return result;
702}
703
704void SoundStreamContainer::mark_dimension_consumed(uint32_t dimension_index, uint32_t reader_id)
705{
707 if (m_reader_consumed_dimensions.contains(reader_id)) {
708 m_reader_consumed_dimensions[reader_id].insert(dimension_index);
709 } else {
711 "Attempted to mark dimension {} as consumed for unknown reader_id {}. "
712 "This may indicate the reader was not registered or has already been unregistered. "
713 "Please ensure readers are properly registered before marking dimensions as consumed.",
714 dimension_index, reader_id);
715 }
716}
717
719{
720 bool result = false;
721 seqlock_read_void(m_reader_lock, 8, [&] {
722 result = std::ranges::all_of(m_active_readers, [this](const auto& dim_reader_pair) {
723 const auto& [dim, expected_count] = dim_reader_pair;
724 auto actual_count = std::ranges::count_if(m_reader_consumed_dimensions,
725 [dim](const auto& reader_dims_pair) {
726 return reader_dims_pair.second.contains(dim);
727 });
728 return actual_count >= expected_count;
729 });
730 });
731 return result;
732}
733
735{
737 std::ranges::for_each(m_reader_consumed_dimensions,
738 [](auto& reader_dims_pair) {
739 reader_dims_pair.second.clear();
740 });
741}
742
744{
745 if (new_layout == m_structure.memory_layout) {
746 return;
747 }
748
750 m_structure.memory_layout = new_layout;
752 return;
753 }
754
756 m_structure.memory_layout = new_layout;
758 return;
759 }
760
761 auto current_span = convert_variant<double>(m_data[0]);
762 std::vector<double> current_data(current_span.begin(), current_span.end());
763
764 auto channels = deinterleave_channels<double>(
765 std::span<const double>(current_data.data(), current_data.size()),
767
768 std::vector<double> reorganized_data;
769 if (new_layout == MemoryLayout::ROW_MAJOR) {
770 reorganized_data = interleave_channels(channels);
771 } else {
772 reorganized_data.reserve(current_data.size());
773 for (const auto& channel : channels) {
774 reorganized_data.insert(reorganized_data.end(), channel.begin(), channel.end());
775 }
776 }
777
778 m_data[0] = DataVariant(std::move(reorganized_data));
779
781 m_double_extraction_dirty.store(true, std::memory_order_release);
782
783 m_structure.memory_layout = new_layout;
785}
786
787std::span<const double> SoundStreamContainer::get_data_as_double() const
788{
789 if (!m_double_extraction_dirty.load(std::memory_order_acquire))
790 return { m_cached_ext_buffer };
791
793 if (m_data.empty())
794 return {};
795
796 std::span<const double> result;
797 seqlock_read_void(m_data_lock, 8, [&] {
798 auto span = convert_variant<double>(m_data[0]);
799 result = { span.data(), span.size() };
800 });
801 return result;
802 }
803
804 const auto& spans = get_span_cache();
805
806 auto channels = spans
807 | std::views::transform([](const auto& span) {
808 return std::vector<double>(span.begin(), span.end());
809 })
810 | std::ranges::to<std::vector>();
811
813 m_double_extraction_dirty.store(false, std::memory_order_release);
814
815 return { m_cached_ext_buffer };
816}
817
819{
820 if (channel >= m_data.size()) {
821 error<std::out_of_range>(
824 std::source_location::current(),
825 "Channel index {} out of range (max {})",
826 channel, m_data.size() - 1);
827 }
829}
830
832{
833 std::vector<DataAccess> result;
834 result.reserve(m_data.size());
835
836 for (auto& i : m_data) {
837 result.emplace_back(i, m_structure.dimensions, m_structure.modality);
838 }
839 return result;
840}
841
842const std::vector<std::span<double>>& SoundStreamContainer::get_span_cache() const
843{
844 if (!m_span_cache_dirty.load(std::memory_order_acquire) && m_span_cache.has_value())
845 return *m_span_cache;
846
847 seqlock_read_void(m_data_lock, 8, [&] {
848 if (!m_span_cache_dirty.load(std::memory_order_acquire) && m_span_cache.has_value())
849 return;
850
851 auto spans = m_data
852 | std::views::transform([](auto& variant) {
853 return convert_variant<double>(const_cast<DataVariant&>(variant));
854 })
855 | std::ranges::to<std::vector>();
856
857 m_span_cache = std::move(spans);
858 m_span_cache_dirty.store(false, std::memory_order_release);
859 });
860
861 return *m_span_cache;
862}
863
865{
866 m_span_cache_dirty.store(true, std::memory_order_release);
867}
868
870 const std::vector<uint64_t>& coords,
871 void* out,
872 const std::type_info& type) const
873{
874 if (type != typeid(double) || coords.size() != 2 || !has_data())
875 return;
876
877 const uint64_t frame = coords[0];
878 const uint64_t channel = coords[1];
879
880 if (frame >= m_num_frames || channel >= m_num_channels)
881 return;
882
883 const auto& spans = get_span_cache();
884
886 if (spans.empty())
887 return;
888 const uint64_t idx = frame * m_num_channels + channel;
889 if (idx >= spans[0].size())
890 return;
891 *static_cast<double*>(out) = spans[0][idx];
892 } else {
893 if (channel >= spans.size() || frame >= spans[channel].size())
894 return;
895 *static_cast<double*>(out) = spans[channel][frame];
896 }
897}
898
900 const std::vector<uint64_t>& coords,
901 const void* in,
902 const std::type_info& type)
903{
904 if (type != typeid(double) || coords.size() != 2)
905 return;
906
907 const uint64_t frame = coords[0];
908 const uint64_t channel = coords[1];
909
910 if (frame >= m_num_frames || channel >= m_num_channels)
911 return;
912
913 const auto& spans = get_span_cache();
914
916 if (spans.empty())
917 return;
918 const uint64_t idx = frame * m_num_channels + channel;
919 if (idx >= spans[0].size())
920 return;
921 const_cast<std::span<double>&>(spans[0])[idx] = *static_cast<const double*>(in);
922 } else {
923 if (channel >= spans.size() || frame >= spans[channel].size())
924 return;
925 const_cast<std::span<double>&>(spans[channel])[frame] = *static_cast<const double*>(in);
926 }
927
929 m_double_extraction_dirty.store(true, std::memory_order_release);
930}
931
932}
#define MF_ERROR(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
uint64_t offset
Definition Composite.cpp:10
std::optional< glm::vec3 > position
Definition Decoder.cpp:93
bool size
uint32_t * dst
std::vector< float > * out
std::vector< glm::ivec3 > coords
Definition VDBWriter.cpp:25
vk::PhysicalDeviceType type
Definition VKDevice.cpp:126
bool available
Definition VKDevice.cpp:41
std::string name
Definition VKDevice.cpp:123
size_t count
uint32_t channels
Type-erased accessor for NDData with semantic view construction.
std::span< const double > get_frame_typed(uint64_t frame_index) const
void reset_read_position() override
Reset read position to the beginning of the stream.
std::atomic< ProcessingState > m_processing_state
std::span< const double > get_data_as_double() const
Get the audio data as a specific type.
void get_frames_typed(std::span< double > output, uint64_t start_frame, uint64_t num_frames) const
std::optional< std::vector< std::span< double > > > m_span_cache
void set_memory_layout(MemoryLayout layout) override
Set the memory layout for this container.
std::unordered_map< std::string, RegionGroup > m_region_groups
double position_to_time(uint64_t position) const override
Convert from position units (e.g., frame/sample index) to time (seconds).
Region get_loop_region() const override
Get the current loop region.
std::unordered_map< uint32_t, int > m_active_readers
void unload_region(const Region &region) override
Unload a region from memory.
std::unordered_set< uint32_t > m_consumed_dimensions
uint32_t register_dimension_reader(uint32_t dimension_index) override
Register a reader for a specific dimension.
bool has_active_readers() const override
Check if any dimensions currently have active readers.
void set_looping(bool enable) override
Enable or disable looping behavior for the stream.
uint64_t get_total_elements() const override
Get the total number of elements in the container.
std::vector< std::atomic< uint64_t > > m_read_position
const std::vector< std::span< double > > & get_span_cache() const
Get the cached spans for each channel, recomputing if dirty.
bool is_region_loaded(const Region &region) const override
Check if a region is loaded in memory.
std::shared_ptr< DataProcessingChain > m_processing_chain
bool all_dimensions_consumed() const override
Check if all active dimensions have been consumed in this cycle.
uint64_t peek_sequential(std::span< double > output, uint64_t count, uint64_t offset=0) const override
Peek at data without advancing the read position.
std::vector< DataVariant > get_region_data(const Region &region) const override
Get data for a specific region.
void get_value_impl(const std::vector< uint64_t > &coords, void *out, const std::type_info &type) const override
Type-erased single-element read.
uint64_t time_to_position(double time) const override
Convert from time (seconds) to position units (e.g., frame/sample index).
const void * get_raw_data() const override
Get a raw pointer to the underlying data storage.
void advance_read_position(const std::vector< uint64_t > &frames) override
Advance the read position by a specified amount.
void unregister_dimension_reader(uint32_t dimension_index) override
Unregister a reader for a specific dimension.
void reorganize_data_layout(MemoryLayout new_layout)
void update_processing_state(ProcessingState new_state) override
Update the processing state of the container.
void mark_ready_for_processing(bool ready) override
Mark the container as ready or not ready for processing.
void set_value_impl(const std::vector< uint64_t > &coords, const void *in, const std::type_info &type) override
Type-erased single-element write.
void set_read_position(const std::vector< uint64_t > &position) override
Set the current read position in the primary temporal dimension per channel.
std::vector< uint64_t > linear_index_to_coordinates(uint64_t linear_index) const override
Convert linear index to coordinates based on current memory layout.
void notify_state_change(ProcessingState new_state)
bool has_data() const override
Check if the container currently holds any data.
void gather_frames(std::span< const uint64_t > frames, std::span< double > out) const
Copy arbitrary frames into a caller-owned buffer without allocating.
const std::vector< uint64_t > & get_read_position() const override
Get the current read position.
void set_default_processor(const std::shared_ptr< DataProcessor > &processor) override
Set the default data processor for this container.
void load_region(const Region &region) override
Load a region into memory.
void add_region_group(const RegionGroup &group) override
Add a named group of regions to the container.
ProcessingState get_processing_state() const override
Get the current processing state of the container.
void create_default_processor() override
Create and configure a default processor for this container.
void invalidate_span_cache()
Invalidate the span cache when data or layout changes.
bool is_ready_for_processing() const override
Check if the container is ready for processing.
std::shared_ptr< DataProcessingChain > get_processing_chain() override
Get the current processing chain for this container.
uint64_t read_sequential(std::span< double > output, uint64_t count) override
Read data sequentially from the current position.
DataAccess channel_data(size_t channel) override
Get channel data with semantic interpretation.
std::vector< DataDimension > get_dimensions() const override
Get the dimensions describing the structure of the data.
std::unordered_map< std::string, RegionGroup > get_all_region_groups() const override
Get all region groups in the container.
bool is_at_end() const override
Check if read position has reached the end of the stream.
std::vector< DataAccess > all_channel_data() override
Get all channel data as accessors.
std::vector< DataVariant > get_segments_data(const std::vector< RegionSegment > &segment) const override
Get data for multiple region segments efficiently.
uint64_t get_num_frames() const override
Get the number of frames in the primary (temporal) dimension.
std::unordered_map< uint32_t, std::unordered_set< uint32_t > > m_reader_consumed_dimensions
std::shared_ptr< DataProcessor > m_default_processor
void remove_region_group(const std::string &name) override
Remove a region group by name.
std::vector< DataVariant > get_region_group_data(const RegionGroup &group) const override
Get data for multiple regions efficiently.
void get_frames_impl(void *output, size_t count, uint64_t start_frame, uint64_t num_frames, const std::type_info &type) const override
Implementation-specific method to retrieve multiple frames.
void clear() override
Clear all data in the container.
void process_default() override
Process the container's data using the default processor.
void set_region_data(const Region &region, const std::vector< DataVariant > &data) override
Set data for a specific region.
void update_read_position_for_channel(size_t channel, uint64_t frame) override
Update the read position for a specific channel.
uint64_t coordinates_to_linear_index(const std::vector< uint64_t > &coordinates) const override
Convert coordinates to linear index based on current memory layout.
SoundStreamContainer(uint32_t sample_rate=48000, uint32_t num_channels=2, uint64_t initial_capacity=0, bool circular_mode=false)
Construct a SoundStreamContainer with specified parameters.
void set_loop_region(const Region &region) override
Set the loop region using a Region.
std::vector< uint64_t > get_remaining_frames() const override
Get the number of remaining frames from the current position, per channel.
void mark_dimension_consumed(uint32_t dimension_index, uint32_t reader_id) override
Mark a dimension as consumed for the current processing cycle.
std::function< void(std::shared_ptr< SignalSourceContainer >, ProcessingState)> m_state_callback
bool is_ready() const override
Check if the stream is ready for reading.
std::unordered_map< uint32_t, uint32_t > m_dimension_to_next_reader_id
std::shared_ptr< DataProcessor > get_default_processor() const override
Get the current default data processor.
RegionGroup get_region_group(const std::string &name) const override
Get a region group by name.
uint64_t get_frame_size() const override
Get the number of elements that constitute one "frame".
RAII guard that brackets a Seqlock write region.
Definition SeqLock.hpp:155
@ ContainerProcessing
Container operations (Kakshya - file/stream/region processing)
@ Runtime
General runtime operations (default fallback)
@ Kakshya
Containers[Signalsource, Stream, File], Regions, DataProcessors.
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.
ProcessingState
Represents the current processing lifecycle state of a container.
@ READY
Container has data loaded and is ready for processing.
@ IDLE
Container is inactive with no data or not ready for processing.
@ PROCESSING
Container is actively being processed.
@ PROCESSED
Container has completed processing and results are available.
uint64_t coordinates_to_linear(const std::vector< uint64_t > &coords, const std::vector< DataDimension > &dimensions)
Convert N-dimensional coordinates to a linear index for interleaved data.
Definition CoordUtils.cpp:8
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:70
DataModality
Data modality types for cross-modal analysis.
Definition NDData.hpp:132
@ AUDIO_MULTICHANNEL
Multi-channel audio.
MemoryLayout
Memory layout for multi-dimensional data.
Definition NDData.hpp:33
@ ROW_MAJOR
C/C++ style (last dimension varies fastest)
uint64_t time_to_position(double time, double sample_rate)
Convert time (seconds) to position (samples/frames) given a sample rate.
OrganizationStrategy
Data organization strategy for multi-channel/multi-frame data.
Definition NDData.hpp:43
@ PLANAR
Separate DataVariant per logical unit (LLL...RRR for stereo)
@ INTERLEAVED
Single DataVariant with interleaved data (LRLRLR for stereo)
std::vector< uint64_t > linear_to_coordinates(uint64_t index, const std::vector< DataDimension > &dimensions)
Convert a linear index to N-dimensional coordinates for interleaved data.
std::vector< T > interleave_channels(const std::vector< std::vector< T > > &channels)
Interleave multiple channels of data into a single vector.
double position_to_time(uint64_t position, double sample_rate)
Convert position (samples/frames) to time (seconds) given a sample rate.
std::vector< uint64_t > wrap_position_with_loop(const std::vector< uint64_t > &positions, const Region &loop_region, bool looping_enabled)
Wrap a position within loop boundaries if looping is enabled.
static uint64_t get_total_elements(const std::vector< DataDimension > &dimensions)
Get total elements across all dimensions.
Container structure for consistent dimension ordering.
static std::vector< DataDimension > create_dimensions(DataModality modality, const std::vector< uint64_t > &shape, MemoryLayout layout=MemoryLayout::ROW_MAJOR)
Create dimension descriptors for a data modality.
Definition NDData.cpp:127
std::string name
Descriptive name of the group.
Organizes related signal regions into a categorized collection.
static Region time_span(uint64_t start_frame, uint64_t end_frame, const std::string &label="", const std::any &extra_data={})
Create a Region representing a time span (e.g., a segment of frames).
Definition Region.hpp:141
std::vector< uint64_t > end_coordinates
Ending frame index (inclusive)
Definition Region.hpp:78
std::vector< uint64_t > start_coordinates
Starting frame index (inclusive)
Definition Region.hpp:75
Represents a point or span in N-dimensional space.
Definition Region.hpp:73