MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
CursorAccessProcessor.cpp
Go to the documentation of this file.
2
5
7
8namespace MayaFlux::Kakshya {
9
11 : m_frames_per_block(frames_per_block)
12{
13}
14
15void CursorAccessProcessor::on_attach(const std::shared_ptr<SignalSourceContainer>& container)
16{
17 auto stream = std::dynamic_pointer_cast<DynamicSoundStream>(container);
18 if (!stream) {
20 "CursorAccessProcessor requires a DynamicSoundStream");
21 return;
22 }
23
24 m_structure = container->get_structure();
25
26 m_slot_index = stream->allocate_dynamic_slot();
27
28 const uint64_t num_channels = m_structure.get_channel_count();
29 m_cursor.assign(num_channels, m_loop_start);
30}
31
32void CursorAccessProcessor::on_detach(const std::shared_ptr<SignalSourceContainer>& container)
33{
34 auto stream = std::dynamic_pointer_cast<DynamicSoundStream>(container);
35 if (!stream) {
37 "CursorAccessProcessor requires a DynamicSoundStream, slot index can potentially leak");
38 return;
39 }
40
41 m_active = false;
42 m_cursor.clear();
43 stream->release_dynamic_slot(m_slot_index);
44}
45
46void CursorAccessProcessor::process(const std::shared_ptr<SignalSourceContainer>& container)
47{
48 m_is_processing.store(true, std::memory_order_relaxed);
49
50 auto stream = std::dynamic_pointer_cast<DynamicSoundStream>(container);
51 if (!stream) {
53 "CursorAccessProcessor requires a DynamicSoundStream");
54 m_is_processing.store(false, std::memory_order_relaxed);
55 return;
56 }
57
58 auto& pd = stream->get_dynamic_data(m_slot_index);
59
60 if (!m_active) {
61 const uint64_t num_channels = m_structure.get_channel_count();
63 pd.resize(1);
64 std::get<std::vector<double>>(pd[0]).assign(m_frames_per_block * num_channels, 0.0);
65 } else {
66 pd.resize(num_channels);
67 for (auto& ch : pd)
68 std::get<std::vector<double>>(ch).assign(m_frames_per_block, 0.0);
69 }
70 m_is_processing.store(false, std::memory_order_relaxed);
71 return;
72 }
73
74 const uint64_t frame = m_cursor.empty() ? 0 : m_cursor[0];
75
76 const uint64_t total_frames = m_structure.get_samples_count_per_channel();
77 const uint64_t read_end = std::min(frame + m_frames_per_block - 1, total_frames - 1);
78
79 const Region region {
80 std::vector<uint64_t> { frame, 0 },
81 std::vector<uint64_t> { read_end, m_structure.get_channel_count() - 1 }
82 };
83
84 auto region_data = container->get_region_data(region);
85
87 pd.resize(1);
88 if (!region_data.empty())
89 safe_copy_data_variant(region_data[0], pd[0]);
90 } else {
91 const uint64_t ch_count = std::min(
92 static_cast<uint64_t>(region_data.size()),
94 pd.resize(ch_count);
95 for (size_t c = 0; c < ch_count; ++c)
96 safe_copy_data_variant(region_data[c], pd[c]);
97 }
98
99 const double raw_advance = static_cast<double>(m_frames_per_block) * m_speed + m_speed_remainder;
100 const auto int_advance = static_cast<uint64_t>(raw_advance);
101 m_speed_remainder = raw_advance - static_cast<double>(int_advance);
102
103 const uint64_t next = frame + int_advance;
104 const uint64_t loop_end = m_loop_end;
105
106 if (next >= loop_end) {
107 if (m_looping) {
108 if (m_loop_count > 0) {
110 if (m_loops_remaining == 0) {
111 m_active = false;
112 m_speed_remainder = 0.0;
113 m_cursor.assign(m_cursor.size(), m_loop_start);
114 if (m_on_end)
115 m_on_end();
116 m_is_processing.store(false, std::memory_order_relaxed);
117 return;
118 }
119 }
120 m_speed_remainder = 0.0;
121 m_cursor.assign(m_cursor.size(), m_loop_start);
122 } else {
123 m_active = false;
124 m_speed_remainder = 0.0;
125 m_cursor.assign(m_cursor.size(), m_loop_start);
126 if (m_on_end)
127 m_on_end();
128 }
129 } else {
130 m_cursor.assign(m_cursor.size(), next);
131 }
132
133 m_is_processing.store(false, std::memory_order_relaxed);
134}
135
142
144{
145 if (speed > 0.0)
146 m_speed = speed;
147}
148
150{
151 m_active = false;
152}
153
159
160void CursorAccessProcessor::set_frames_per_block(uint64_t frames_per_block)
161{
162 m_frames_per_block = frames_per_block;
163}
164
165void CursorAccessProcessor::set_loop_region(uint64_t start_frame, uint64_t end_frame)
166{
167 m_loop_start = start_frame;
168 m_loop_end = end_frame;
169}
170
171} // namespace MayaFlux::Kakshya
#define MF_ERROR(comp, ctx,...)
#define MF_RT_ERROR(comp, ctx,...)
void process(const std::shared_ptr< SignalSourceContainer > &container) override
Extract one block of frames into container processed_data[0].
CursorAccessProcessor(uint64_t frames_per_block)
Construct with a fixed output block size.
void on_detach(const std::shared_ptr< SignalSourceContainer > &container) override
Called when this processor is detached from a container.
void set_loop_count(size_t n)
Set the number of loops to play before stopping.
void stop()
Deactivate without resetting the cursor position.
void set_frames_per_block(uint64_t frames_per_block)
Set the output block size in frames.
void set_speed(double speed)
Set the playback speed relative to nominal rate.
void reset()
Reset cursor to loop start and activate the processor.
void set_loop_region(uint64_t start_frame, uint64_t end_frame)
Set the loop region in frames.
void on_attach(const std::shared_ptr< SignalSourceContainer > &container) override
Called when this processor is attached to a container.
@ ContainerProcessing
Container operations (Kakshya - file/stream/region processing)
@ Kakshya
Containers[Signalsource, Stream, File], Regions, DataProcessors.
@ 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.
Definition DataUtils.cpp:34
static uint64_t get_channel_count(const std::vector< DataDimension > &dimensions)
Extract channel count from dimensions.
static uint64_t get_samples_count_per_channel(const std::vector< DataDimension > &dimensions)
Get samples per channel (time dimension only).
Represents a point or span in N-dimensional space.
Definition Region.hpp:67