MayaFlux 1.0.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches

◆ start()

TapSet MayaFlux::Kriya::TapSetBuilder::start ( )

Build the taps and start them.

Returns
The running set, empty if the stream or region is unusable.

Definition at line 156 of file TapSet.cpp.

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}
#define MF_ERROR(comp, ctx,...)
float rate
uint32_t channels
std::shared_ptr< Kakshya::DynamicSoundStream > m_stream
Definition TapSet.hpp:242
std::vector< Spec > m_specs
Definition TapSet.hpp:247
Buffers::BufferManager & m_mgr
Definition TapSet.hpp:243
TapSetBuilder & lag(double seconds)
Make the current tap trail the write head of a live ring by seconds.
Definition TapSet.cpp:121
Vruta::TaskScheduler & m_scheduler
Definition TapSet.hpp:244
@ Configuration
Configuration and parameter updates.
@ Kriya
Automatable tasks and fluent scheduling api for Nodes and Buffers.
std::vector< double > delay(std::span< const double > data, uint32_t delay_samples, double fill_value)
Prepend delay_samples zero-valued (or fill_value) samples, returning a new vector.
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.
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
T velocity(const Memory::HistoryBuffer< T > &history, double dt) noexcept
First difference: rate of change of position.
Tendency< double, double > TimeMap
Definition Tendency.hpp:48

References channels, MayaFlux::Journal::Configuration, MayaFlux::Kinesis::Tendency< D, R >::fn, MayaFlux::Kinesis::TimeMaps::integrated(), MayaFlux::Journal::Kriya, lag(), MayaFlux::Kinesis::TimeMaps::lagged(), m_buf_size, m_end_frame, MayaFlux::Kriya::TapSet::m_entries, m_looping, m_mgr, MayaFlux::Kriya::TapSet::m_pipelines, m_scheduler, m_specs, m_start_frame, m_stream, MayaFlux::Kriya::TapSet::m_taps, MF_ERROR, rate, MayaFlux::Kriya::TapSet::Tap::rate, MayaFlux::Kriya::TapSet::Tap::seats, and MayaFlux::Kriya::TapSet::Tap::velocity.

+ Here is the call graph for this function: