16 if (data.empty() || data[0].empty()) {
20 uint64_t num_frames {};
30 num_frames = data[0].size();
32 if (!std::ranges::all_of(data | std::views::drop(1) | std::views::take(
get_num_channels() - 1),
33 [num_frames](
const auto& span) {
return span.size() == num_frames; })) {
39 if (num_frames == 0) {
44 if (uint64_t required_end_frame = start_frame + num_frames;
m_auto_resize) {
51 if (available_frames == 0) {
55 if (num_frames > available_frames) {
56 num_frames = available_frames;
78 uint64_t num_frames = data.size();
79 uint64_t required_end_frame = start_frame + num_frames;
88 if (available_frames == 0) {
92 if (num_frames > available_frames) {
93 num_frames = available_frames;
107 auto num_frames =
validate(data, start_frame);
114 uint64_t frames_from_start = num_frames - frames_to_end;
116 if (frames_to_end > 0) {
117 std::vector<std::span<const double>> first_part;
118 first_part.reserve(data.size());
119 for (
const auto& span : data) {
120 first_part.emplace_back(span.subspan(0, frames_to_end));
125 if (frames_from_start > 0) {
126 std::vector<std::span<const double>> second_part;
127 second_part.reserve(data.size());
128 for (
const auto& span : data) {
129 second_part.emplace_back(span.subspan(frames_to_end, frames_from_start));
142 std::vector<DataVariant> data_variants;
146 data_variants.emplace_back(
147 std::vector<double>(data[0].begin(), data[0].begin() + samples_to_write));
151 | std::views::transform([num_frames](
const auto& span) ->
DataVariant {
152 return DataVariant(std::vector<double>(span.begin(), span.begin() + num_frames));
154 | std::ranges::to<std::vector>();
167 std::span<const double> data, uint64_t start_frame, uint32_t channel)
175 uint64_t frames_from_start = num_frames - frames_to_end;
176 if (frames_to_end > 0)
177 write_frames(data.subspan(0, frames_to_end), start_frame, channel);
178 if (frames_from_start > 0)
179 write_frames(data.subspan(frames_to_end, frames_from_start), 0, channel);
188 auto& interleaved_data = std::get<std::vector<double>>(
m_data[0]);
191 for (uint64_t frame = 0; frame < num_frames; ++frame) {
192 uint64_t idx = (start_frame + frame) * num_channels + channel;
193 if (idx < interleaved_data.size())
194 interleaved_data[idx] = data[frame];
198 if (channel >=
m_data.size())
201 auto dest_span = convert_variant<double>(
m_data[channel]);
202 if (start_frame + num_frames > dest_span.size()) {
203 std::vector<double> current_data(dest_span.begin(), dest_span.end());
204 current_data.resize(start_frame + num_frames, 0.0);
206 dest_span = convert_variant<double>(
m_data[channel]);
209 std::copy(data.begin(), data.begin() + num_frames,
210 dest_span.begin() + start_frame);
228 "Direct span access not supported for interleaved data. "
229 "Use get_frames() or Kakshya::extract_channel_data() instead.");
233 std::span<const double> result;
235 if (channel >=
m_data.size())
240 uint64_t available_frames =
channel_data.size() - start_frame;
241 uint64_t actual_frames = std::min(num_frames, available_frames);
242 result = {
channel_data.data() + start_frame, actual_frames };
252 const uint64_t num_frames =
output.size();
257 std::ranges::fill(output, 0.0);
260 const auto& interleaved_data = std::get<std::vector<double>>(
m_data[0]);
262 for (uint64_t frame = 0; frame < num_frames; ++frame) {
263 uint64_t idx = (start_frame + frame) * num_channels + channel;
264 output[frame] = (idx < interleaved_data.size()) ? interleaved_data[idx] : 0.0;
269 if (channel >=
m_data.size()) {
270 std::ranges::fill(output, 0.0);
274 for (uint64_t frame = 0; frame < num_frames; ++frame) {
275 uint64_t idx = start_frame + frame;
285 required_frames > current_frames) {
350 m_data.resize(data.size());
351 std::ranges::for_each(std::views::zip(data,
m_data),
353 auto&& [source, dest] = pair;
358 return static_cast<uint64_t
>(vec.size());
378 uint64_t new_capacity = std::max(target_frames, current_frames * 2);
387 std::vector<DataVariant> expanded_data(1);
392 std::vector<double> current_data;
395 std::vector<double> expanded_buffer(new_frame_count *
get_num_channels(), 0.0);
397 std::ranges::copy_n(current_data.begin(),
398 std::min<size_t>(current_data.size(), expanded_buffer.size()),
399 expanded_buffer.begin());
401 expanded_data[0] =
DataVariant(std::move(expanded_buffer));
403 return expanded_data;
407 | std::views::transform([
this, new_frame_count](uint32_t ch) ->
DataVariant {
409 std::vector<double> current_channel_data;
410 extract_from_variant(m_data[ch], current_channel_data);
412 std::vector<double> expanded_channel(new_frame_count, 0.0);
413 std::ranges::copy_n(current_channel_data.begin(),
414 std::min<size_t>(current_channel_data.size(), expanded_channel.size()),
415 expanded_channel.begin());
417 return { std::move(expanded_channel) };
420 return { std::vector<double>(new_frame_count, 0.0) };
422 | std::ranges::to<std::vector>();
#define MF_ERROR(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
std::shared_ptr< Core::VKImage > output
uint32_t allocate_dynamic_slot()
Allocate an independent processed data slot.
uint64_t validate_single_channel(std::span< const double > data, uint64_t start_frame=0, uint32_t channel=0)
bool m_auto_resize
Enable automatic capacity expansion.
DynamicSoundStream(uint32_t sample_rate=48000, uint32_t num_channels=2)
Construct a DynamicSoundStream with specified audio parameters.
std::vector< DataVariant > create_expanded_data(uint64_t new_frame_count)
std::vector< bool > m_dynamic_slots
void expand_to(uint64_t target_frames)
bool m_is_circular
True when operating in circular buffer mode.
void enable_circular_buffer(uint64_t capacity)
Enable circular buffer mode with fixed capacity.
void ensure_capacity(uint64_t required_frames)
Pre-allocate capacity for the specified number of frames.
void set_all_data(const DataVariant &new_data)
void disable_circular_buffer()
Disable circular buffer mode and return to linear operation.
std::span< const double > get_channel_frames(uint32_t channel, uint64_t start_frame, uint64_t num_frames) const
Get the fixed capacity of the circular buffer if enabled.
uint64_t validate(std::vector< std::span< const double > > &data, uint64_t start_frame=0)
uint64_t write_frames(std::span< const double > data, uint64_t start_frame=0, uint32_t channel=0)
Write audio frame data to the container with automatic capacity management.
void release_dynamic_slot(uint32_t index)
Release a previously allocated dynamic slot, clearing its data.
std::vector< std::vector< DataVariant > > m_dynamic_data
uint64_t m_circular_capacity
Fixed capacity for circular mode.
std::vector< DataVariant > & get_dynamic_data(uint32_t index)
Access a dynamic processed data slot by index.
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::atomic< bool > m_double_extraction_dirty
void update_processing_state(ProcessingState new_state) override
Update the processing state of the container.
std::vector< DataVariant > m_data
Memory::Seqlock m_data_lock
void invalidate_span_cache()
Invalidate the span cache when data or layout changes.
virtual uint32_t get_num_channels() const
DataAccess channel_data(size_t channel) override
Get channel data with semantic interpretation.
uint64_t get_num_frames() const override
Get the number of frames in the primary (temporal) dimension.
void set_region_data(const Region ®ion, const std::vector< DataVariant > &data) override
Set data for a specific region.
void set_loop_region(const Region ®ion) override
Set the loop region using a Region.
ContainerDataStructure m_structure
Concrete base implementation for streaming audio containers.
RAII guard that brackets a Seqlock write region.
@ ContainerProcessing
Container operations (Kakshya - file/stream/region processing)
@ Kakshya
Containers[Signalsource, Stream, File], Regions, DataProcessors.
@ READY
Container has data loaded and is ready for processing.
std::span< T > extract_from_variant(const DataVariant &variant, std::vector< T > &storage, ComplexConversionStrategy strategy=ComplexConversionStrategy::MAGNITUDE)
Get typed span from DataVariant using concepts.
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.
@ 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.
OrganizationStrategy organization
Represents a point or span in N-dimensional space.