13 if (segment_index >= region.
segments.size())
16 auto& segment = region.
segments[segment_index];
17 return (region.
current_position[0] >= segment.source_region.end_coordinates[0]);
29 auto region_groups = container->get_all_region_groups();
31 std::ranges::for_each(region_groups | std::views::values,
32 [
this, &container](
const auto& group) {
39 if (a.
segments[0].source_region.start_coordinates.empty() || b.
segments[0].source_region.start_coordinates.empty())
41 return a.
segments[0].source_region.start_coordinates[0] < b.
segments[0].source_region.start_coordinates[0];
54 std::vector<uint64_t> output_shape;
55 uint64_t current_region_frames = 0;
58 for (
const auto& segment : current_region.segments) {
59 current_region_frames += segment.segment_size[0];
63 output_shape.push_back(current_region_frames);
66 auto& output_data = container->get_processed_data();
73 }
catch (
const std::exception& e) {
78 std::source_location::current(),
79 "Error during region organization processing: {}",
90 container->add_region_group(new_group);
97 const std::vector<uint64_t>& start_coords,
98 const std::vector<uint64_t>& end_coords,
99 const std::unordered_map<std::string, std::any>& attributes)
106 Region region(start_coords, end_coords, attributes);
109 region_it->segments.push_back(std::move(segment));
127 region_it->transition_type = type;
128 region_it->transition_duration_ms = duration_ms;
141 region_it->selection_pattern = pattern;
148 const std::vector<uint64_t>& loop_start,
149 const std::vector<uint64_t>& loop_end)
156 region_it->looping_enabled = enabled;
157 if (!loop_start.empty())
158 region_it->loop_start = loop_start;
159 if (!loop_end.empty())
160 region_it->loop_end = loop_end;
172 if (!region_it->segments.empty()) {
189 std::vector<DataVariant>& output_data)
199 bool segment_changed = (selected_segment != current_region.active_segment_index);
201 bool region_completed = (segment_completed && selected_segment == current_region.segments.size() - 1);
206 bool should_transition =
false;
207 switch (current_region.transition_type) {
209 should_transition =
false;
213 should_transition = (current_region.transition_duration_ms > 0);
216 should_transition =
false;
220 if (should_transition) {
224 container, output_data);
230 new_current.active_segment_index = 0;
234 container, output_data);
235 current_region.active_segment_index = selected_segment;
241 const std::shared_ptr<SignalSourceContainer>& container,
242 std::vector<DataVariant>& output_data)
246 output_data.resize(cached_data->data.size());
248 std::ranges::for_each(std::views::zip(cached_data->data, output_data),
250 auto&& [source, dest] = pair;
251 safe_copy_data_variant(source, dest);
257 auto region_data = container->get_region_data(segment.
source_region);
259 output_data.resize(region_data.size());
261 std::ranges::for_each(std::views::zip(region_data, output_data),
263 auto&& [source, dest] = pair;
282 const std::shared_ptr<SignalSourceContainer>& container,
283 std::vector<DataVariant>& output_data)
289 auto next_data = container->get_region_data(next_region.
segments[0].source_region);
321 const size_t data_count = std::min<size_t>(output_data.size(), next_data.size());
322 for (
size_t variant_idx = 0; variant_idx < data_count; ++variant_idx) {
323 auto current_span = convert_variant<double>(output_data[variant_idx]);
324 auto next_span = convert_variant<double>(
const_cast<DataVariant&
>(next_data[variant_idx]));
326 const size_t sample_count = std::min<size_t>(current_span.size(), next_span.size());
330 for (
size_t i = 0; i < sample_count; ++i) {
331 double fade_factor =
static_cast<double>(i) /
static_cast<double>(sample_count);
332 current_span[i] = current_span[i] * (1.0 - fade_factor) + next_span[i] * fade_factor;
337 for (
size_t i = 0; i < sample_count; ++i) {
338 current_span[i] = current_span[i] * 0.5 + next_span[i] * 0.5;
358 if (std::uniform_int_distribution<size_t> dist(0, region.
segments.size() - 1);
true) {
377 const std::vector<uint64_t>& position,
378 const std::vector<OrganizedRegion>& regions)
const
380 if (
auto it = std::ranges::find_if(regions,
381 [&position](
const auto& region) {
return region.contains_position(position); });
382 it != regions.end()) {
383 return std::distance(regions.begin(), it);
411 for (
size_t i = 0;
const auto& region : group.
regions) {
415 organized_region.
segments.push_back(std::move(segment));
418 std::ranges::copy(region.attributes,
void process(const std::shared_ptr< SignalSourceContainer > &container) override
Processes audio, performing reorganization if needed.
std::function< bool(const std::vector< OrganizedRegion > &, const std::shared_ptr< SignalSourceContainer > &)> m_auto_reorganization_criteria
Criteria function for automatic reorganization.
void set_reorganization_callback(RegionOrganizer callback)
Sets the callback for region reorganization.
RegionOrganizer m_reorganizer_callback
Callback for reorganization.
DynamicRegionProcessor(const std::shared_ptr< SignalSourceContainer > &container)
Construct a dynamic region processor for a given container.
std::atomic< bool > m_needs_reorganization
Flag for pending reorganization.
bool should_reorganize(const std::shared_ptr< SignalSourceContainer > &container)
Checks if reorganization should occur for the current container.
void trigger_reorganization()
Triggers a reorganization on the next processing cycle.
void set_region_transition(const std::string &group_name, size_t region_index, RegionTransition type, double duration_ms=0.0)
Configures the transition between regions.
void add_region_group(const std::string &group_name)
Creates a new region group for organizing related regions.
void jump_to_region(const std::string &group_name, size_t region_index)
Jump to a specific region for processing or playback.
void process(const std::shared_ptr< SignalSourceContainer > &container) override
Processes audio data according to the current region organization.
void jump_to_position(const std::vector< uint64_t > &position)
Jump to a specific position in the data.
virtual void apply_region_transition(const OrganizedRegion ¤t_region, const OrganizedRegion &next_region, const std::shared_ptr< SignalSourceContainer > &container, std::vector< DataVariant > &output_data)
Apply a transition between two regions.
std::mt19937 m_random_engine
void refresh_organized_data()
Refresh the internal organization of regions.
void organize_group(const std::shared_ptr< SignalSourceContainer > &container, const RegionGroup &group)
Organize a group of regions within the container.
virtual void process_organized_regions(const std::shared_ptr< SignalSourceContainer > &container, std::vector< DataVariant > &output_data)
Process regions according to their selection pattern.
void add_segment_to_region(const std::string &group_name, size_t region_index, const std::vector< uint64_t > &start_coords, const std::vector< uint64_t > &end_coords, const std::unordered_map< std::string, std::any > &attributes)
Adds a segment to an existing region.
void set_selection_pattern(const std::string &group_name, size_t region_index, RegionSelectionPattern pattern)
Set the selection pattern for a region (e.g., sequential, random).
void set_region_looping(const std::string &group_name, size_t region_index, bool enabled, const std::vector< uint64_t > &loop_start={}, const std::vector< uint64_t > &loop_end={})
Enable or disable looping for a region.
RegionOrganizationProcessor(const std::shared_ptr< SignalSourceContainer > &container)
Construct a region organization processor for a given container.
void organize_container_data(const std::shared_ptr< SignalSourceContainer > &container) override
Organize the container's data into regions and segments.
std::optional< size_t > find_region_for_position(const std::vector< uint64_t > &position, const std::vector< OrganizedRegion > ®ions) const
virtual size_t select_next_segment(const OrganizedRegion ®ion) const
Select the next segment to process according to the region's pattern.
std::vector< double > m_segment_weights
virtual void process_region_segment(const OrganizedRegion ®ion, const RegionSegment &segment, const std::shared_ptr< SignalSourceContainer > &container, std::vector< DataVariant > &output_data)
Process a single region segment.
Data-driven processor for organizing and processing non-linear audio regions.
virtual void cache_region_if_needed(const RegionSegment &segment, const std::shared_ptr< SignalSourceContainer > &container)
Cache a region's data if beneficial and not already cached.
std::unique_ptr< RegionCacheManager > m_cache_manager
virtual void ensure_output_dimensioning(std::vector< DataVariant > &output_data, const std::vector< uint64_t > &required_shape)
Ensure output data is properly dimensioned for region extraction.
ContainerDataStructure m_structure
size_t m_current_region_index
std::vector< OrganizedRegion > m_organized_regions
std::atomic< bool > m_is_processing
std::vector< uint64_t > m_current_position
void on_attach(const std::shared_ptr< SignalSourceContainer > &container) override
Attach this processor to a signal source container.
std::weak_ptr< SignalSourceContainer > m_container_weak
@ Runtime
General runtime operations (default fallback)
@ 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::function< void(std::vector< OrganizedRegion > &, std::shared_ptr< SignalSourceContainer >)> RegionOrganizer
Function type for dynamic region reorganization.
bool is_segment_complete(const OrganizedRegion ®ion, size_t segment_index)
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.
RegionSelectionPattern
Describes how regions are selected for processing or playback.
@ RANDOM
Random selection.
@ SEQUENTIAL
Process regions in order.
@ WEIGHTED
Weighted random selection.
RegionTransition
Describes how transitions between regions are handled.
@ OVERLAP
Overlap regions during transition.
@ CROSSFADE
Crossfade between regions.
@ IMMEDIATE
No transition, jump directly.
void safe_copy_data_variant(const DataVariant &input, DataVariant &output)
Safely copy data from a DataVariant to another DataVariant, handling type conversion.
@ ACTIVE
Currently being processed.
@ READY
Ready for processing.
static size_t get_frame_size(const std::vector< DataDimension > &dimensions)
Extract the size of non time dimensions (channel, spatial, frequency)
std::vector< uint64_t > current_position
Current read position.
RegionTransition transition_type
Transition to next region.
size_t active_segment_index
Currently active segment.
std::unordered_map< std::string, std::any > attributes
Extensible metadata.
std::vector< RegionSegment > segments
Audio segments in this region.
size_t region_index
Index within the group.
RegionSelectionPattern selection_pattern
std::string group_name
Name of the region group.
A structured audio region with metadata and transition information.
std::unordered_map< std::string, std::any > attributes
Flexible key-value store for group-specific attributes.
std::vector< Region > regions
Collection of regions belonging to this group.
std::string name
Descriptive name of the group.
Organizes related signal regions into a categorized collection.
Region source_region
Associated region.
Represents a discrete segment of audio data with caching capabilities.
Represents a point or span in N-dimensional space.