MayaFlux 1.0.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
TapSet.cpp
Go to the documentation of this file.
1#include "TapSet.hpp"
2
6
8
9namespace MayaFlux::Kriya {
10
11void TapSet::level(size_t tap, double gain)
12{
13 for (const auto& seat : m_taps.at(tap).seats) {
14 seat.sampler->slice(seat.slot).scale = gain;
15 }
16}
17
18void TapSet::speed(size_t tap, double ratio)
19{
20 const auto& target = m_taps.at(tap);
21 *target.velocity = ratio * target.rate;
22}
23
24std::shared_ptr<SamplingPipeline> TapSet::sampler(size_t tap, size_t output) const
25{
26 return m_taps.at(tap).seats.at(output).sampler;
27}
28
29Kakshya::StreamSlice& TapSet::slice(size_t tap, size_t output)
30{
31 const auto& seat = m_taps.at(tap).seats.at(output);
32 return seat.sampler->slice(seat.slot);
33}
34
36{
37 if (m_entries) {
38 m_entries->cancel();
39 m_entries.reset();
40 }
41
42 for (const auto& tap : m_taps) {
43 for (const auto& seat : tap.seats) {
44 seat.sampler->stop(seat.slot);
45 }
46 }
47}
48
50 std::shared_ptr<Kakshya::DynamicSoundStream> stream,
52 Vruta::TaskScheduler& scheduler,
53 uint32_t buf_size)
54 : m_stream(std::move(stream))
55 , m_mgr(mgr)
56 , m_scheduler(scheduler)
57 , m_buf_size(buf_size)
58{
59}
60
62{
63 if (m_specs.empty()) {
64 m_specs.emplace_back();
65 }
66 return m_specs.back();
67}
68
70{
71 m_specs.emplace_back();
72 return *this;
73}
74
76{
77 current().delay = std::max(seconds, 0.0);
78 return *this;
79}
80
82{
83 auto& spec = current();
84 spec.ratio = std::abs(ratio);
85 spec.backward = spec.backward || ratio < 0.0;
86 return *this;
87}
88
90{
91 current().backward = enable;
92 return *this;
93}
94
96{
97 current().level = gain;
98 return *this;
99}
100
102{
103 current().channels = { channel };
104 return *this;
105}
106
108{
109 if (!channels.empty()) {
111 }
112 return *this;
113}
114
116{
117 current().source = channel;
118 return *this;
119}
120
122{
123 return lag(Kinesis::constant<double, double>(seconds));
124}
125
127{
128 current().lag = std::make_shared<const Kinesis::TimeMap>(std::move(seconds));
129 return *this;
130}
131
133{
134 return repeat_every(Kinesis::constant<double, double>(seconds));
135}
136
138{
139 current().repeat = std::make_shared<const Kinesis::TimeMap>(std::move(seconds));
140 return *this;
141}
142
144{
145 m_looping = enable;
146 return *this;
147}
148
149TapSetBuilder& TapSetBuilder::region(uint64_t start_frame, uint64_t end_frame)
150{
151 m_start_frame = start_frame;
152 m_end_frame = end_frame;
153 return *this;
154}
155
157{
158 TapSet taps;
159
160 if (!m_stream) {
162 "TapSetBuilder::start called with a null stream");
163 return taps;
164 }
165
166 if (m_specs.empty()) {
167 m_specs.emplace_back();
168 }
169
170 const uint64_t frames = m_stream->get_num_frames();
171 const uint64_t end_frame = (m_end_frame == 0 || m_end_frame > frames) ? frames : m_end_frame;
172
173 if (m_start_frame + 1 >= end_frame) {
175 "TapSetBuilder::start region [{}, {}) is too short", m_start_frame, end_frame);
176 return taps;
177 }
178
179 const auto rate = static_cast<double>(m_stream->get_sample_rate());
180 const auto first = static_cast<double>(m_start_frame);
181 const auto last = static_cast<double>(end_frame - 1);
182 const uint32_t source_count = std::max<uint32_t>(m_stream->get_num_channels(), 1);
183 const double shortest = 2.0 * static_cast<double>(m_buf_size) / rate;
184
185 std::vector<uint32_t> channels;
186 std::vector<size_t> slot_counts;
187
188 for (const auto& spec : m_specs) {
189 TapSet::Tap built;
190 built.rate = rate;
191 built.velocity = std::make_shared<double>((spec.backward ? -spec.ratio : spec.ratio) * rate);
192
193 Kinesis::TimeMap lag_frames;
194 if (spec.lag) {
195 lag_frames = Kinesis::TimeMap { .fn = [lag = spec.lag, rate, shortest](const double& t) -> double {
196 return std::max((*lag)(t), shortest) * rate;
197 } };
198 }
199 const double origin = static_cast<double>(m_stream->get_write_head(0)) + rate * spec.delay;
200
201 for (const uint32_t output : spec.channels) {
202 auto found = std::ranges::find(channels, output);
203 if (found == channels.end()) {
204 auto made = std::make_shared<SamplingPipeline>(
206 made->build();
207 taps.m_pipelines.push_back(std::move(made));
208 channels.push_back(output);
209 slot_counts.push_back(0);
210 found = std::prev(channels.end());
211 }
212
213 const auto pipeline = static_cast<size_t>(std::distance(channels.begin(), found));
214 const auto& sampler = taps.m_pipelines[pipeline];
215 const size_t slot = slot_counts[pipeline]++;
216
217 auto slice = sampler->slice_from_range(m_start_frame, end_frame, static_cast<uint8_t>(slot));
218 slice.looping = m_looping;
219 slice.scale = spec.level;
220 slice.source_channel = spec.source.value_or(output % source_count);
221 if (!spec.lag) {
222 slice.repeat = spec.repeat;
223 }
224 slice.with_time_map(spec.lag
225 ? Kinesis::TimeMaps::lagged(origin, rate, lag_frames)
226 : Kinesis::TimeMaps::integrated(spec.backward ? last : first, built.velocity));
227 sampler->load(slot, std::move(slice));
228
229 built.seats.push_back({ .sampler = sampler, .slot = slot });
230 }
231
232 taps.m_taps.push_back(std::move(built));
233 }
234
235 std::vector<size_t> order(m_specs.size());
236 for (size_t i = 0; i < order.size(); ++i) {
237 order[i] = i;
238 }
239 std::ranges::stable_sort(order, {}, [this](size_t i) { return m_specs[i].delay; });
240
241 auto entries = std::make_shared<EventChain>(m_scheduler);
242 double elapsed = 0.0;
243
244 for (const size_t i : order) {
245 const auto& seats = taps.m_taps[i].seats;
246 const double delay = m_specs[i].delay;
247
248 if (delay <= 0.0) {
249 for (const auto& seat : seats) {
250 seat.sampler->play(seat.slot);
251 }
252 continue;
253 }
254
255 entries->then([seats] {
256 for (const auto& seat : seats) {
257 seat.sampler->play(seat.slot);
258 }
259 },
260 delay - elapsed);
261 elapsed = delay;
262 }
263
264 if (entries->event_count() > 0) {
265 entries->start();
266 taps.m_entries = std::move(entries);
267 }
268
269 return taps;
270}
271
272} // namespace MayaFlux::Kriya
#define MF_ERROR(comp, ctx,...)
Core::GlobalStreamInfo stream
Definition Config.cpp:40
float rate
Factories for TimeMap: seconds since a voice started in, position in recorded material out (frames fo...
uint32_t channels
float gain
Token-based multimodal buffer management system for unified data stream processing.
TapSetBuilder & loop(bool enable=true)
Whether taps loop the region (default) or play it once.
Definition TapSet.cpp:143
TapSet start()
Build the taps and start them.
Definition TapSet.cpp:156
std::shared_ptr< Kakshya::DynamicSoundStream > m_stream
Definition TapSet.hpp:242
TapSetBuilder & backward(bool enable=true)
Read the current tap backwards from the end of the region.
Definition TapSet.cpp:89
TapSetBuilder & from_channel(uint32_t channel)
Source channel the current tap plays on every output.
Definition TapSet.cpp:115
std::vector< Spec > m_specs
Definition TapSet.hpp:247
TapSetBuilder(std::shared_ptr< Kakshya::DynamicSoundStream > stream, Buffers::BufferManager &mgr, Vruta::TaskScheduler &scheduler, uint32_t buf_size)
Definition TapSet.cpp:49
Buffers::BufferManager & m_mgr
Definition TapSet.hpp:243
TapSetBuilder & enters_after(double seconds)
Seconds after start() before the current tap enters.
Definition TapSet.cpp:75
TapSetBuilder & repeat_every(double seconds)
Restart the current tap every seconds.
Definition TapSet.cpp:132
TapSetBuilder & speed(double ratio)
Speed of the current tap relative to the source.
Definition TapSet.cpp:81
TapSetBuilder & on_channels(const std::vector< uint32_t > &channels)
Several output channels for the current tap, which stay in step.
Definition TapSet.cpp:107
TapSetBuilder & on_channel(uint32_t channel)
Output channel of the current tap.
Definition TapSet.cpp:101
TapSetBuilder & tap()
Begin a new tap.
Definition TapSet.cpp:69
TapSetBuilder & lag(double seconds)
Make the current tap trail the write head of a live ring by seconds.
Definition TapSet.cpp:121
TapSetBuilder & region(uint64_t start_frame, uint64_t end_frame=0)
Restrict every tap to a region of the stream.
Definition TapSet.cpp:149
Vruta::TaskScheduler & m_scheduler
Definition TapSet.hpp:244
TapSetBuilder & level(double gain)
Linear gain of the current tap on each of its outputs.
Definition TapSet.cpp:95
Describes a tap set one tap at a time, then starts it.
Definition TapSet.hpp:119
std::shared_ptr< EventChain > m_entries
Definition TapSet.hpp:88
std::vector< std::shared_ptr< SamplingPipeline > > m_pipelines
Definition TapSet.hpp:86
std::shared_ptr< SamplingPipeline > sampler(size_t tap, size_t output=0) const
The sampling pipeline that plays one output of a tap.
Definition TapSet.cpp:24
void level(size_t tap, double gain)
Change the level of a tap on all of its outputs.
Definition TapSet.cpp:11
std::vector< Tap > m_taps
Definition TapSet.hpp:87
void stop()
Silence every tap and cancel entries that have not happened yet.
Definition TapSet.cpp:35
void speed(size_t tap, double ratio)
Change the speed of a tap while it plays.
Definition TapSet.cpp:18
Kakshya::StreamSlice & slice(size_t tap, size_t output=0)
The slice behind one output of a tap, for looping and region edits.
Definition TapSet.cpp:29
One stream read by several independent taps.
Definition TapSet.hpp:17
Token-based multimodal task scheduling system for unified coroutine processing.
Definition Scheduler.hpp:51
@ Configuration
Configuration and parameter updates.
@ Kriya
Automatable tasks and fluent scheduling api for Nodes and Buffers.
TimeMap lagged(double origin, double rate, TimeMap lag)
Position of a moving reference minus a lag that can itself change.
Definition TimeMap.hpp:95
TimeMap integrated(double start, std::shared_ptr< const double > velocity)
Position that integrates a velocity you can change while it plays.
Definition TimeMap.hpp:113
A bounded region of a DynamicSoundStream with associated playback parameters.
std::function< R(const D &)> fn
Definition Tendency.hpp:23
Typed, composable, stateless callable from domain D to range R.
Definition Tendency.hpp:22
std::shared_ptr< const Kinesis::TimeMap > lag
Definition TapSet.hpp:237
std::vector< uint32_t > channels
Definition TapSet.hpp:234
std::shared_ptr< const Kinesis::TimeMap > repeat
Definition TapSet.hpp:236
std::optional< uint32_t > source
Definition TapSet.hpp:235
std::shared_ptr< double > velocity
Definition TapSet.hpp:82
std::vector< Seat > seats
Definition TapSet.hpp:81