10 : m_container(container)
13 auto structure = container->get_structure();
16 container->register_state_change_callback(
17 [
this](
auto c,
auto s) {
30 buffer->mark_for_removal();
39 buffer->mark_for_removal();
52 auto audio_buffer = std::dynamic_pointer_cast<AudioBuffer>(buffer);
53 auto& buffer_data = audio_buffer->get_data();
54 uint32_t buffer_size = audio_buffer->get_num_samples();
56 auto read_positions =
m_container->get_read_position();
61 if (buffer_data.size() != buffer_size) {
62 buffer_data.resize(buffer_size);
72 buffer->mark_for_processing(
true);
79 std::dynamic_pointer_cast<Kakshya::SoundFileContainer>(
m_container)->clear_all_consumption();
83 }
catch (
const std::exception& e) {
84 std::cerr <<
"Error in ContainerToBufferAdapter::process: " << e.what() <<
'\n';
91 std::ranges::fill(output, 0.0);
95 auto sound_container = std::dynamic_pointer_cast<Kakshya::SoundStreamContainer>(
m_container);
96 if (!sound_container) {
97 std::ranges::fill(output, 0.0);
101 auto& processed_data = sound_container->get_processed_data();
102 if (processed_data.empty()) {
103 std::ranges::fill(output, 0.0);
107 auto structure = sound_container->get_structure();
110 thread_local std::vector<double> temp_storage;
111 auto data_span = Kakshya::extract_from_variant<double>(processed_data[0], temp_storage);
113 auto num_channels = structure.get_channel_count();
114 auto samples_to_copy = std::min(
static_cast<size_t>(output.size()),
115 static_cast<size_t>(data_span.size() / num_channels));
117 for (
auto i : std::views::iota(0UZ, samples_to_copy)) {
119 output[i] = (interleaved_idx < data_span.size()) ? data_span[interleaved_idx] : 0.0;
122 if (samples_to_copy < output.size()) {
123 std::ranges::fill(output | std::views::drop(samples_to_copy), 0.0);
128 std::ranges::fill(output, 0.0);
132 thread_local std::vector<double> temp_storage;
133 auto channel_data_span = Kakshya::extract_from_variant<double>(processed_data[
m_source_channel], temp_storage);
135 auto samples_to_copy = std::min(output.size(), channel_data_span.size());
136 std::ranges::copy_n(channel_data_span.begin(), samples_to_copy, output.begin());
138 if (samples_to_copy < output.size()) {
139 std::ranges::fill(output | std::views::drop(samples_to_copy), 0.0);
153 throw std::runtime_error(
"Container not ready for processing");
157 auto& buffer_data = std::dynamic_pointer_cast<AudioBuffer>(buffer)->get_data();
158 uint32_t num_samples = std::dynamic_pointer_cast<AudioBuffer>(buffer)->get_num_samples();
163 buffer->mark_for_processing(
true);
166 }
catch (
const std::exception& e) {
167 std::cerr <<
"Error pre-filling buffer: " << e.what() <<
'\n';
182 throw std::out_of_range(
"Channel index exceeds container channel count");
196 auto structure = container->get_structure();
199 container->register_state_change_callback(
207 std::shared_ptr<Kakshya::SignalSourceContainer> container,
215 std::cerr <<
"Container entered error state" <<
'\n';
224 std::shared_ptr<Kakshya::StreamContainer> container,
225 uint32_t source_channel)
227 , m_container(container)
228 , m_source_channel(source_channel)
231 throw std::invalid_argument(
"ContainerBuffer: container must not be null");
253 if (
auto adapter = std::dynamic_pointer_cast<ContainerToBufferAdapter>(
m_default_processor)) {
254 adapter->set_container(container);
288 auto adapter = std::make_shared<ContainerToBufferAdapter>(
m_container);
std::shared_ptr< BufferProcessor > m_default_processor
Default audio transformation processor for this buffer.
virtual void set_default_processor(std::shared_ptr< BufferProcessor > processor) override
Sets the default audio transformation processor for this buffer.
virtual void enforce_default_processing(bool should_process) override
Controls whether the audio buffer should use default processing.
Concrete audio implementation of the Buffer interface for double-precision audio data.
std::shared_ptr< Kakshya::StreamContainer > m_container
ContainerBuffer(uint32_t channel_id, uint32_t num_samples, std::shared_ptr< Kakshya::StreamContainer > container, uint32_t source_channel=0)
Construct a ContainerBuffer for a specific channel and container.
uint32_t m_source_channel
std::shared_ptr< BufferProcessor > m_pending_adapter
void initialize()
Initialize the buffer after construction.
std::shared_ptr< BufferProcessor > create_default_processor() override
Create the default processor (ContainerToBufferAdapter) for this buffer.
void setup_zero_copy_if_possible()
Attempt to enable zero-copy operation if container layout allows.
void set_container(std::shared_ptr< Kakshya::StreamContainer > container)
Update the container reference.
void on_container_state_change(std::shared_ptr< Kakshya::SignalSourceContainer > container, Kakshya::ProcessingState state)
Respond to container state changes (e.g., READY, PROCESSED, NEEDS_REMOVAL).
ContainerToBufferAdapter(std::shared_ptr< Kakshya::StreamContainer > container)
void on_attach(std::shared_ptr< Buffer > buffer) override
Attach the adapter to an AudioBuffer.
void processing_function(std::shared_ptr< Buffer > buffer) override
Extracts and processes data from the container into the target AudioBuffer.
void set_container(std::shared_ptr< Kakshya::StreamContainer > container)
Set the container to adapt.
uint32_t m_source_channel
void extract_channel_data(std::span< double > output)
Extract channel data from the container into the output buffer.
void set_source_channel(uint32_t channel_index)
Set which channel dimension to extract from the container.
void on_detach(std::shared_ptr< Buffer > buffer) override
Detach the adapter from its AudioBuffer.
std::shared_ptr< Kakshya::StreamContainer > m_container
ProcessingState
Represents the current processing lifecycle state of a container.
@ READY
Container has data loaded and is ready for processing.
@ NEEDS_REMOVAL
Container is marked for removal from the system.
@ ERROR
Container is in an error state and cannot proceed.
@ PROCESSED
Container has completed processing and results are available.
@ INTERLEAVED
Single DataVariant with interleaved data (LRLRLR for stereo)