MayaFlux 1.0.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
StreamSliceProcessor.cpp
Go to the documentation of this file.
2
5
7
8namespace MayaFlux::Buffers {
9
10namespace {
11
12 void apply_slice(const Kakshya::StreamSlice& slice, Kakshya::CursorAccessProcessor& proc)
13 {
14 proc.set_loop_region(slice.start_frame(), slice.end_frame());
15 proc.set_looping(slice.looping);
16 proc.set_speed(slice.speed);
17 proc.set_time_map(slice.time_map);
18 proc.set_repeat(slice.repeat);
19
20 if (slice.loop_count != proc.loop_count())
21 proc.set_loop_count(slice.loop_count);
22 }
23
24}
25
26void StreamSliceProcessor::on_attach(const std::shared_ptr<Buffer>& buffer)
27{
28 auto audio = std::dynamic_pointer_cast<AudioBuffer>(buffer);
29 if (!audio) {
31 "StreamSliceProcessor requires an AudioBuffer");
32 return;
33 }
34 m_frames_per_block = static_cast<uint32_t>(audio->get_num_samples());
35}
36
37void StreamSliceProcessor::on_detach(const std::shared_ptr<Buffer>&)
38{
39 for (size_t i = 0; i < m_slots.size(); ++i)
40 detach_slot(i);
41}
42
43bool StreamSliceProcessor::is_compatible_with(const std::shared_ptr<Buffer>& buffer) const
44{
45 return std::dynamic_pointer_cast<AudioBuffer>(buffer) != nullptr;
46}
47
49{
50 auto& slot = m_slots[index];
51 if (slot.proc && slot.slice.stream)
52 slot.proc->on_detach(slot.slice.stream);
53 slot = {};
54}
55
57{
58 if (m_frames_per_block == 0) {
60 "StreamSliceProcessor::load called before attachment to a buffer -- attach first");
61 return;
62 }
63
64 if (!slice.stream)
65 return;
66
67 if (index > m_slots.size()) {
69 "StreamSliceProcessor::load index {} exceeds slot count {}; use {} for next available",
70 index, m_slots.size(), m_slots.size());
71 }
72
73 if (index >= m_slots.size())
74 m_slots.resize(index + 1);
75
77
78 slice.active = false;
79 slice.index = static_cast<uint8_t>(index);
80
81 auto proc = std::make_shared<Kakshya::CursorAccessProcessor>(m_frames_per_block);
82 apply_slice(slice, *proc);
83
84 proc->set_on_end([this, index] {
85 m_slots[index].slice.active = false;
86 if (m_on_end)
88 });
89
90 proc->on_attach(slice.stream);
91
92 m_slots[index].slice = std::move(slice);
93 m_slots[index].proc = std::move(proc);
94}
95
97{
98 if (index >= m_slots.size() || !m_slots[index].proc)
99 return;
100
101 apply_slice(m_slots[index].slice, *m_slots[index].proc);
102 m_slots[index].proc->reset();
103 m_slots[index].slice.active = true;
104}
105
107{
108 if (index >= m_slots.size() || !m_slots[index].proc)
109 return;
110
111 m_slots[index].proc->stop();
112 m_slots[index].slice.active = false;
113}
114
116{
117 return std::ranges::any_of(m_slots, [](const auto& slot) {
118 return slot.slice.active;
119 });
120}
121
122void StreamSliceProcessor::processing_function(const std::shared_ptr<Buffer>& buffer)
123{
124 auto audio = std::dynamic_pointer_cast<AudioBuffer>(buffer);
125 if (!audio)
126 return;
127
128 const uint32_t ch = audio->get_channel_id();
129 auto& dst = audio->get_data();
130 std::ranges::fill(dst, 0.0);
131
132 for (auto& slot : m_slots) {
133 if (!slot.slice.active || !slot.slice.stream || !slot.proc)
134 continue;
135
136 apply_slice(slot.slice, *slot.proc);
137 slot.proc->process(slot.slice.stream);
138
139 const auto& pd = slot.slice.stream->get_dynamic_data(slot.proc->get_slot_index());
140 if (pd.empty())
141 continue;
142
143 const auto structure = slot.slice.stream->get_structure();
144 std::vector<double> tmp(dst.size(), 0.0);
145 Kakshya::extract_processed_data(pd, structure.organization, structure.get_channel_count(),
146 slot.slice.source_channel.value_or(ch), tmp);
147
148 for (size_t s = 0; s < dst.size(); ++s)
149 dst[s] += tmp[s] * slot.slice.scale;
150 }
151}
152
153} // namespace MayaFlux::Buffers
#define MF_ERROR(comp, ctx,...)
#define MF_RT_ERROR(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
std::shared_ptr< NetworkGeometryBuffer > buffer
uint32_t * dst
uint32_t index
Definition VKDevice.cpp:122
void unbind(size_t index)
Deactivate a slot, stopping its processor without resetting the cursor.
void on_attach(const std::shared_ptr< Buffer > &buffer) override
Called when this processor is attached to a buffer.
void bind(size_t index)
Activate a slot, resetting its processor cursor to region start.
bool is_compatible_with(const std::shared_ptr< Buffer > &buffer) const override
Checks if this processor can handle the specified buffer type.
void on_detach(const std::shared_ptr< Buffer > &buffer) override
Called when this processor is detached from a buffer.
bool any_active() const
Check if any slot is active.
void load(size_t index, Kakshya::StreamSlice slice)
Assign a StreamSlice to a slot.
void processing_function(const std::shared_ptr< Buffer > &buffer) override
The core processing function that must be implemented by derived classes.
Kakshya::StreamSlice & slice(size_t index)
@ Configuration
Configuration and parameter updates.
@ BufferProcessing
Buffer processing (Buffers::BufferManager, processing chains)
@ Buffers
Buffers, Managers, processors and processing chains.
void extract_processed_data(const std::vector< DataVariant > &pd, OrganizationStrategy organization, uint64_t num_channels, uint32_t ch, std::span< double > output)
Extract one channel's samples from a processed dynamic data block.
std::vector< double > slice(std::span< const double > data, double start_ratio, double end_ratio)
Extract a contiguous slice by ratio, returning a new vector.
std::shared_ptr< DynamicSoundStream > stream
A bounded region of a DynamicSoundStream with associated playback parameters.