13 for (
const auto& seat :
m_taps.at(tap).seats) {
14 seat.sampler->slice(seat.slot).scale =
gain;
20 const auto& target =
m_taps.at(tap);
21 *target.velocity = ratio * target.rate;
26 return m_taps.at(tap).seats.at(output).sampler;
31 const auto& seat =
m_taps.at(tap).seats.at(output);
32 return seat.sampler->slice(seat.slot);
42 for (
const auto& tap :
m_taps) {
43 for (
const auto& seat : tap.seats) {
44 seat.sampler->stop(seat.slot);
50 std::shared_ptr<Kakshya::DynamicSoundStream>
stream,
56 , m_scheduler(scheduler)
57 , m_buf_size(buf_size)
84 spec.ratio = std::abs(ratio);
85 spec.backward = spec.backward || ratio < 0.0;
123 return lag(Kinesis::constant<double, double>(seconds));
128 current().
lag = std::make_shared<const Kinesis::TimeMap>(std::move(seconds));
134 return repeat_every(Kinesis::constant<double, double>(seconds));
139 current().
repeat = std::make_shared<const Kinesis::TimeMap>(std::move(seconds));
162 "TapSetBuilder::start called with a null stream");
170 const uint64_t frames =
m_stream->get_num_frames();
175 "TapSetBuilder::start region [{}, {}) is too short",
m_start_frame, end_frame);
179 const auto rate =
static_cast<double>(
m_stream->get_sample_rate());
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;
186 std::vector<size_t> slot_counts;
188 for (
const auto& spec :
m_specs) {
191 built.
velocity = std::make_shared<double>((spec.backward ? -spec.ratio : spec.ratio) *
rate);
196 return std::max((*
lag)(t), shortest) *
rate;
199 const double origin =
static_cast<double>(
m_stream->get_write_head(0)) +
rate * spec.delay;
201 for (
const uint32_t output : spec.channels) {
202 auto found = std::ranges::find(
channels, output);
204 auto made = std::make_shared<SamplingPipeline>(
209 slot_counts.push_back(0);
213 const auto pipeline =
static_cast<size_t>(std::distance(
channels.begin(), found));
215 const size_t slot = slot_counts[pipeline]++;
217 auto slice = sampler->slice_from_range(
m_start_frame, end_frame,
static_cast<uint8_t
>(slot));
219 slice.scale = spec.level;
220 slice.source_channel = spec.source.value_or(output % source_count);
222 slice.repeat = spec.repeat;
224 slice.with_time_map(spec.lag
227 sampler->load(slot, std::move(slice));
229 built.
seats.push_back({ .sampler = sampler, .slot = slot });
232 taps.
m_taps.push_back(std::move(built));
235 std::vector<size_t> order(
m_specs.size());
236 for (
size_t i = 0; i < order.size(); ++i) {
239 std::ranges::stable_sort(order, {}, [
this](
size_t i) {
return m_specs[i].delay; });
241 auto entries = std::make_shared<EventChain>(
m_scheduler);
242 double elapsed = 0.0;
244 for (
const size_t i : order) {
245 const auto& seats = taps.
m_taps[i].seats;
246 const double delay =
m_specs[i].delay;
249 for (
const auto& seat : seats) {
250 seat.sampler->play(seat.slot);
255 entries->then([seats] {
256 for (
const auto& seat : seats) {
257 seat.sampler->play(seat.slot);
264 if (entries->event_count() > 0) {
#define MF_ERROR(comp, ctx,...)
Core::GlobalStreamInfo stream
Factories for TimeMap: seconds since a voice started in, position in recorded material out (frames fo...
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.
TapSet start()
Build the taps and start them.
std::shared_ptr< Kakshya::DynamicSoundStream > m_stream
TapSetBuilder & backward(bool enable=true)
Read the current tap backwards from the end of the region.
TapSetBuilder & from_channel(uint32_t channel)
Source channel the current tap plays on every output.
std::vector< Spec > m_specs
TapSetBuilder(std::shared_ptr< Kakshya::DynamicSoundStream > stream, Buffers::BufferManager &mgr, Vruta::TaskScheduler &scheduler, uint32_t buf_size)
Buffers::BufferManager & m_mgr
TapSetBuilder & enters_after(double seconds)
Seconds after start() before the current tap enters.
TapSetBuilder & repeat_every(double seconds)
Restart the current tap every seconds.
TapSetBuilder & speed(double ratio)
Speed of the current tap relative to the source.
TapSetBuilder & on_channels(const std::vector< uint32_t > &channels)
Several output channels for the current tap, which stay in step.
TapSetBuilder & on_channel(uint32_t channel)
Output channel of the current tap.
TapSetBuilder & tap()
Begin a new tap.
TapSetBuilder & lag(double seconds)
Make the current tap trail the write head of a live ring by seconds.
TapSetBuilder & region(uint64_t start_frame, uint64_t end_frame=0)
Restrict every tap to a region of the stream.
Vruta::TaskScheduler & m_scheduler
TapSetBuilder & level(double gain)
Linear gain of the current tap on each of its outputs.
Describes a tap set one tap at a time, then starts it.
std::shared_ptr< EventChain > m_entries
std::vector< std::shared_ptr< SamplingPipeline > > m_pipelines
std::shared_ptr< SamplingPipeline > sampler(size_t tap, size_t output=0) const
The sampling pipeline that plays one output of a tap.
void level(size_t tap, double gain)
Change the level of a tap on all of its outputs.
std::vector< Tap > m_taps
void stop()
Silence every tap and cancel entries that have not happened yet.
void speed(size_t tap, double ratio)
Change the speed of a tap while it plays.
Kakshya::StreamSlice & slice(size_t tap, size_t output=0)
The slice behind one output of a tap, for looping and region edits.
One stream read by several independent taps.
Token-based multimodal task scheduling system for unified coroutine processing.
@ 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.
TimeMap integrated(double start, std::shared_ptr< const double > velocity)
Position that integrates a velocity you can change while it plays.
A bounded region of a DynamicSoundStream with associated playback parameters.
std::function< R(const D &)> fn
Typed, composable, stateless callable from domain D to range R.
std::shared_ptr< const Kinesis::TimeMap > lag
std::vector< uint32_t > channels
std::shared_ptr< const Kinesis::TimeMap > repeat
std::optional< uint32_t > source
std::shared_ptr< double > velocity
std::vector< Seat > seats