Loading...
Searching...
No Matches
AudioLooper.hpp
1#pragma once
2#include <Fx/Looper/AudioLayers.hpp>
3#include <Fx/Looper/LooperNode.hpp>
4#include <Fx/Types.hpp>
5
6#include <ossia/dataflow/exec_state_facade.hpp>
7#include <ossia/dataflow/nodes/sound.hpp>
8#include <ossia/dataflow/token_request.hpp>
9
10#include <halp/audio.hpp>
11#include <halp/controls.hpp>
12#include <halp/layout.hpp>
13#include <halp/meta.hpp>
14#include <halp/soundfile_port.hpp>
15
16#include <functional>
17#include <limits>
18#include <memory>
19
20namespace Nodes::Looper
21{
22inline ossia::audio_stretch_mode stretch_mode(FollowTempo f) noexcept
23{
24 switch(f)
25 {
26 case FollowTempo::Repitch:
27 return ossia::audio_stretch_mode::Repitch;
28 case FollowTempo::RepitchFast:
29 return ossia::audio_stretch_mode::RepitchFastestQ;
30 case FollowTempo::Timestretch:
31 return ossia::audio_stretch_mode::RubberBandStandard;
32 case FollowTempo::TimestretchPercussive:
33 return ossia::audio_stretch_mode::RubberBandPercussive;
34 case FollowTempo::Off:
35 default:
36 return ossia::audio_stretch_mode::None;
37 }
38}
39
41inline halp::clip_stretch clip_stretch(FollowTempo f) noexcept
42{
43 switch(f)
44 {
45 case FollowTempo::Repitch:
46 return halp::clip_stretch::repitch;
47 case FollowTempo::RepitchFast:
48 return halp::clip_stretch::repitch_fast;
49 case FollowTempo::Timestretch:
50 return halp::clip_stretch::timestretch;
51 case FollowTempo::TimestretchPercussive:
52 return halp::clip_stretch::timestretch_percussive;
53 case FollowTempo::Off:
54 default:
55 return halp::clip_stretch::none;
56 }
57}
58}
59
60namespace Nodes::AudioLooper
61{
63{
64 halp_meta(name, "Looper (audio)")
65 halp_meta(c_name, "Looper (audio)")
66 halp_meta(category, "Audio/Utilities")
67 halp_meta(author, "ossia score")
68 halp_meta(manual_url, "https://ossia.io/score-docs/processes/audio-looper.html")
69 halp_meta(
70 description,
71 "Loop audio in layers, and turn the loop into a clip of the timeline")
72 halp_meta(uuid, "a0ad4227-ac3d-448b-a19b-19581ed4e2c6");
73 halp_meta(recommended_height, 200);
74 halp_flag(process_exec);
75
78 static constexpr std::array<int, 1> removed_inlets() noexcept { return {16}; }
79
80 using LoopMode = Looper::LoopMode;
81 using Passthrough = Looper::Passthrough;
82
83 struct ins
84 {
85 halp::dynamic_audio_bus<"in", double> audio;
86
87 struct : halp::enum_t<LoopMode, "Mode">
88 {
89 using halp::enum_t<LoopMode, "Mode">::operator=;
90 static constexpr std::string_view former_name() noexcept { return "Loop"; }
91 halp_meta(
92 description,
93 "What the looper is doing, or about to do on the grid: playing the "
94 "loop, recording it, overdubbing on top of it, or nothing. It follows "
95 "every change, by an action, a recording's end or a full buffer. "
96 "Record on a loop overdubs it: Clear it first to record a new one. "
97 "Overdub on an empty loop records it, then overdubs.")
99 std::function<void(std::string_view)> update_controller;
101 void update(Node& n) noexcept { n.loop_arrived(); }
102 } mode;
103
105
106 struct : Looper::enum_combobox<"Passthrough", Passthrough, Passthrough::Record>
107 {
108 using enum_combobox::operator=;
109 halp_meta(
110 description,
111 "Whether the input is heard as well as the loop. Record passthrough "
112 "is heard only while recording or overdubbing; Full is heard always.")
113 } passthrough;
114
116
117 struct : halp::spinbox_i32<"Record bars", halp::irange{0, 64, 4}>
118 {
119 static constexpr std::string_view former_name() noexcept { return "Bars"; }
120 halp_meta(
121 description,
122 "How long a recording runs before After record takes over, and so "
123 "how long the loop it leaves is. Zero leaves recording to be ended by "
124 "hand, and the loop is then as long as it was played for.")
125 } postaction_bars;
126
128
129 struct : halp::impulse_button<"Undo">
130 {
131 halp_meta(
132 description,
133 "Undoes the last pass, erase or mute. Undoing the first recording "
134 "empties the loop.")
135 } undo;
136 struct : halp::impulse_button<"Redo">
137 {
138 halp_meta(description, "Redoes what Undo took back")
139 } redo;
140 struct : halp::impulse_button<"Clear">
141 {
142 halp_meta(description, "Empties the loop and forgets every pass")
143 } clear;
144
145 struct : halp::knob_f32<"Feedback", halp::range{0., 1., 1.}>
146 {
147 halp_meta(
148 description,
149 "How much of the loop is kept each time an overdub goes round it: "
150 "one keeps it all, lower values let older passes fade away.")
151 } feedback;
152
153 struct : halp::spinbox_i32<"Late stop (ms)", halp::irange{0, 500, 120}>
154 {
155 halp_meta(
156 description,
157 "A recording asked to stop this long after a point of the grid ends "
158 "on that point, instead of a whole grid step later.")
159 } late;
160
161 struct : halp::spinbox_i32<"Latency (ms)", halp::irange{0, 500, 0}>
162 {
163 halp_meta(
164 description,
165 "How late the input reaches the looper: what was recorded is moved "
166 "this much earlier in the loop.")
167 } latency;
168
169 struct : halp::spinbox_i32<"Max length (s)", halp::irange{1, 3600, 60}>
170 {
171 halp_meta(
172 description,
173 "Longest loop. The memory is reserved when playback starts, so a "
174 "change applies from the next start.")
175 } max_seconds;
176
177 struct : halp::spinbox_i32<"Max layers", halp::irange{2, 32, 8}>
178 {
179 halp_meta(
180 description,
181 "Layers kept apart, for undo, mute, solo and erase. What a pass does "
182 "past it is what At max layers says. Applies from the next start.")
183 } max_layers;
184
185 struct : halp::spinbox_i32<"Channels", halp::irange{1, 16, 2}>
186 {
187 halp_meta(
188 description,
189 "Channels recorded; the input's other channels are not. Applies from "
190 "the next start.")
191 } channels;
192
193 struct : halp::spinbox_i32<"Keep last (s)", halp::irange{0, 600, 0}>
194 {
195 halp_meta(
196 description,
197 "Seconds of input kept at all times, for Capture. Zero keeps none. "
198 "Applies from the next start.")
199 } keep;
200
201 struct : halp::spinbox_i32<"Capture bars", halp::irange{1, 64, 4}>
202 {
203 halp_meta(
204 description,
205 "How many bars Capture makes a loop of when there is none. Over a "
206 "loop, Capture takes one round of it, whatever this says.")
207 } capture_bars;
208
209 struct : halp::impulse_button<"Capture">
210 {
211 halp_meta(
212 description,
213 "Takes the input of the last moments, recorded or not, without having "
214 "to press Record first. With no loop, the last Capture bars become "
215 "the loop, played at once. Over a loop, the input over its last round "
216 "becomes a new layer, where it was played in the loop. Undo takes it "
217 "out. Pressed just after a grid point, it ends there, as Late says. "
218 "Needs Keep last.")
219 } capture;
220
221 // Controls added after the first presets go last: presets address the
222 // inputs by their index.
223 struct : halp::toggle<"Engine latency">
224 {
225 halp_meta(
226 description,
227 "Also moves what is recorded earlier by the latency the audio driver "
228 "reports for its input and output, for input that comes from the "
229 "sound card while the loop is heard. Leave off for input made inside "
230 "score.")
231 } engine_latency;
232
233 struct : halp::soundfile_port<"Loop file">
234 {
235 halp_meta(
236 description,
237 "A sound file to loop: dropping one on the looper replaces the loop "
238 "with it, up to Max length.")
239 } file;
240
241 struct : Looper::enum_combobox<"Export", Looper::TakeFiles, Looper::TakeFiles::Mix>
242 {
243 using enum_combobox::operator=;
244 static constexpr std::string_view former_name() noexcept { return "Takes"; }
245 halp_meta(
246 description,
247 "What Send, or a drag from it, places: the loop as it is heard "
248 "(Mix), each pass in a file of its own (Layers), or both, each on a "
249 "lane of its own. A take written as a pass closes has these files; "
250 "one Send or a drag asks for, or the score's stop leaves, has them "
251 "all, so that Export can still be changed once the score is "
252 "stopped. Dragging a lane places its layer alone.")
253 } exported;
254
256 {
257 using enum_combobox::operator=;
258 halp_meta(
259 description,
260 "What an overdub does at the end of the loop: go round it again "
261 "(Wrap), or make the loop longer by its own length each time, the "
262 "passes under it playing again (Extend). An extended loop ends when "
263 "overdubbing stops.")
264 } past_end;
265
266 struct : Looper::enum_combobox<"Follow tempo", Looper::FollowTempo, Looper::FollowTempo::Off>
267 {
268 using enum_combobox::operator=;
269 struct range
270 {
271 std::string_view values[5]
272 = {"Off", "Repitch", "Repitch fast", "Timestretch", "Timestretch percussive"};
273 Looper::FollowTempo init = Looper::FollowTempo::Off;
274 };
275 halp_meta(
276 description,
277 "Plays the loop at the tempo of the score, as sound files are: "
278 "resampled (Repitch: the pitch follows), or time-stretched (the "
279 "pitch stays). A loop being recorded or overdubbed plays at its own "
280 "speed, and a tempo change applies from the next round of the loop. "
281 "Applies from the next start.")
282 } follow_tempo;
283
284 Looper::erase_layer_button erase_layer;
285
286 struct : halp::spinbox_i32<"Layer", halp::irange{1, 32, 1}>
287 {
288 halp_meta(
289 description,
290 "The layer Mute layer, Erase layer and Solo layer act on, counting "
291 "from the oldest one: the lane of that number from the top while "
292 "there are no more layers than lanes, and the file of that number of "
293 "a take written as layers. It moves to each new layer as it is "
294 "added.")
295 std::function<void(int)> update_controller;
296 } layer;
297
298 struct : halp::toggle<"Reverse">
299 {
300 halp_meta(
301 description,
302 "Plays the loop backwards, from where the playhead is. An overdub "
303 "writes where the playhead goes, as on tape: what is played over the "
304 "reversed loop sounds reversed once it plays forwards again. "
305 "Recording a new loop is always forwards.")
306 std::function<void(bool)> update_controller;
307 } reverse;
308
309 struct : Looper::speed_selector<"Speed">
310 {
311 halp_meta(
312 description,
313 "Plays the loop slower or faster, as a tape: the pitch follows. An "
314 "overdub writes where the playhead goes, so what is played at x1/2 "
315 "sounds an octave up at x1. The grid, the bars and the loop's length "
316 "stay in the score's time; combines with Follow tempo.")
317 std::function<void(float)> update_controller;
318 } speed;
319
321 {
322 using enum_combobox::operator=;
323 struct range
324 {
325 std::string_view values[2] = {"Whole", "Per cycle"};
326 Looper::Passes init = Looper::Passes::Whole;
327 };
328 halp_meta(
329 description,
330 "What an overdub that goes round the loop several times leaves: one "
331 "layer (Whole), or a layer for each time round (Per cycle), cut on "
332 "the loop's start, to keep the best one with Solo layer or Mute "
333 "layer, erase the others, or splice them in the timeline from a take "
334 "written as layers. With Past the end on Extend, a cut is made each "
335 "time the loop grows.")
336 } passes;
337
338 Looper::mute_layer_button mute_layer;
339
340 // The Switches tab: actions for footswitches.
341 Looper::rec_play_dub_button rec_play_dub;
342 Looper::after_overdub_selector after_overdub;
343 Looper::play_stop_button play_stop;
347 Looper::new_layer_button new_layer;
350 Looper::retrigger_button retrigger;
351 Looper::previous_layer_button previous_layer;
352 Looper::next_layer_button next_layer;
353 Looper::solo_layer_button solo_layer;
354 Looper::reverse_button reverse_toggle;
355 Looper::half_speed_button half_speed;
356 Looper::double_speed_button double_speed;
357 Looper::at_max_layers_selector at_max_layers;
358 } inputs;
359
360 struct
361 {
362 halp::mimic_audio_bus<"out", &ins::audio> audio;
363 struct : halp::val_port<"Phase", float>
364 {
365 halp_meta(description, "Position in the loop, from 0 to 1")
366 } phase;
367 } outputs;
368
369 // Writing takes to files
370 struct worker_t
371 {
372 std::function<void(Looper::take_job)> request;
374 static bool must_run(const Looper::take_job& job) noexcept { return job.alone; }
375 static std::function<void(Node&)> work(Looper::take_job&& job)
376 {
377 const bool ok = job.run();
378 return [slot = job.slot, number = job.number, alone = job.alone, ok](Node& self) {
379 self.take_written(slot, number, ok, alone);
380 };
381 }
382 } worker;
383
384 std::function<void(Looper::view_message)> send_message;
388
391
392 const score::DocumentContext* ossia_document_context{};
393 ossia::exec_state_facade ossia_state;
394
396 std::shared_ptr<Looper::take_writer> writer;
397 std::shared_ptr<Looper::export_buffer> export_audio;
400 std::shared_ptr<Looper::audio_stop_take> stop_take;
401
402 Node()
403 {
404 layers.allocate(2, 8, 60 * 48000);
405 export_audio = Looper::export_buffer::make(layers.channels, layers.capacity);
406 stop_take = std::make_shared<Looper::audio_stop_take>();
407 }
408
409 void prepare(halp::setup s)
410 {
411 const double rate = s.rate > 0 ? s.rate : 48000.;
412 layers.allocate(
413 inputs.channels.value, inputs.max_layers.value,
414 int64_t(inputs.max_seconds.value * rate));
415 if(!m_writing
416 && (export_audio->channels != layers.channels
417 || export_audio->capacity != layers.capacity))
418 export_audio = Looper::export_buffer::make(layers.channels, layers.capacity);
419 allocate_ring(layers.channels, int64_t(inputs.keep.value * rate));
420 m_switches.seen_passes = layers.count;
421 prepare_stretch(rate, s.frames);
422 if(ossia_document_context)
423 writer = Looper::take_writer::make(*ossia_document_context, "Looper", "wav");
424 if(writer)
425 writer->tell_views = send_message_from_worker;
426 }
427
431 void prepare_stretch(double rate, int frames)
432 {
433 m_follow_tempo = inputs.follow_tempo.value;
434 m_stretch_mode = Looper::stretch_mode(m_follow_tempo);
435 const auto chans = std::size_t(layers.channels);
436 m_stretcher.reset(0, m_stretch_mode, chans, std::size_t(rate), std::size_t(rate));
437 const auto longest = std::size_t(std::max(frames, 8192));
438 m_stretch_out.resize(chans);
439 for(auto& c : m_stretch_out)
440 c.assign(longest, 0.);
441 m_stretch_span.clear();
442 for(auto& c : m_stretch_out)
443 m_stretch_span.emplace_back(c.data(), longest);
444 m_stretch_ready = false;
445
446 if(m_stretch_mode != ossia::audio_stretch_mode::None)
447 {
448 struct silence_source
449 {
450 void fetch_audio(int64_t, int64_t n, float** out) const noexcept
451 {
452 for(std::size_t c = 0; c < chans; c++)
453 std::fill_n(out[c], n, 0.f);
454 }
455 void fetch_audio(int64_t, int64_t n, double** out) const noexcept
456 {
457 for(std::size_t c = 0; c < chans; c++)
458 std::fill_n(out[c], n, 0.);
459 }
460 void fetch_audio_backward(int64_t s, int64_t n, float** out) const noexcept
461 {
462 fetch_audio(s, n, out);
463 }
464 void fetch_audio_backward(int64_t s, int64_t n, double** out) const noexcept
465 {
466 fetch_audio(s, n, out);
467 }
468 std::size_t chans;
469 } source{chans};
470 ossia::token_request tk;
471 tk.prev_date = ossia::time_value{0};
472 tk.date = ossia::time_value{int64_t(longest)};
473 m_stretcher.run(
474 source, tk, ossia_state, 1., 1., chans, int64_t(longest), int64_t(longest),
475 int64_t(longest), 0, m_stretch_span);
476 m_stretcher.transport(0);
477 for(auto& c : m_stretch_out)
478 std::fill(c.begin(), c.end(), 0.);
479 }
480 }
481
483 void allocate_ring(int channels, int64_t frames)
484 {
485 if(channels == m_ring_channels && frames == m_ring_capacity)
486 return;
487 m_ring.clear();
488 m_ring.shrink_to_fit();
489 m_ring_channels = channels;
490 m_ring_capacity = std::max<int64_t>(0, frames);
491 m_ring.resize(
492 std::size_t(m_ring_channels) * std::size_t(m_ring_capacity),
493 boost::container::default_init);
494 }
495
496 // The transport's engine
497 int64_t looper_run(int64_t start, int64_t length);
498 int64_t run_mode(int64_t start, int64_t length);
499 void looper_trim_recording(int64_t frames)
500 {
501 // What was recorded past the grid point stays in the buffer, after the
502 // loop's end, for an overdub that starts there.
503 const int64_t end = std::max<int64_t>(0, layers.length - frames);
504 m_carried_span += layers.length - end;
505 layers.length = end;
506 if(auto* l = layers.top())
507 l->written = layers.length;
508 }
509
510 void operator()(const tick& tk)
511 {
512 if(tk.date == tk.prev_date)
513 return;
514 run_tick(tk);
515 send_view(ossia_state.timings(tk).length);
516 }
517
519 void stop() { stop_score(); }
520
521 struct ui
522 {
523 halp_meta(layout, halp::layouts::hbox)
524 halp_meta(background, halp::colors::background_dark)
525 struct
526 {
527 halp_meta(layout, halp::layouts::vbox)
528 struct
529 {
530 halp_meta(layout, halp::layouts::vbox)
532 struct
533 {
534 halp_meta(layout, halp::layouts::hbox)
535 halp::item<&ins::quantif> quantif;
536 halp::item<&ins::exported> exported;
537 } timing;
538 } transport;
539 struct
540 {
541 halp_meta(name, "Settings")
542 halp_meta(layout, halp::layouts::tabs)
543 halp_meta(background, halp::colors::background_darker)
544 struct
545 {
546 halp_meta(name, "Length")
547 halp_meta(layout, halp::layouts::grid)
548 halp_meta(alignment, halp::alignments::left)
549 halp_meta(spacing, 6)
550 halp_meta(columns, 3)
551 halp::item<&ins::after_record> after_record;
552 halp::item<&ins::postaction_bars> bars;
553 halp::item<&ins::late> late;
554 halp::item<&ins::capture> capture;
555 halp::item<&ins::capture_bars> capture_bars;
556 } length;
557 struct
558 {
559 halp_meta(name, "Play")
560 halp_meta(layout, halp::layouts::grid)
561 halp_meta(alignment, halp::alignments::left)
562 halp_meta(spacing, 6)
563 halp_meta(columns, 3)
564 halp::item<&ins::passthrough> passthrough;
565 halp::item<&ins::start_from> start_from;
566 halp::item<&ins::feedback> feedback;
567 halp::item<&ins::past_end> past_end;
568 halp::item<&ins::passes> passes;
569 } play;
573 struct
574 {
575 halp_meta(name, "Memory")
576 halp_meta(layout, halp::layouts::grid)
577 halp_meta(alignment, halp::alignments::left)
578 halp_meta(spacing, 6)
579 halp_meta(columns, 3)
580 halp::item<&ins::max_seconds> max_seconds;
581 halp::item<&ins::keep> keep;
582 halp::item<&ins::max_layers> max_layers;
583 halp::item<&ins::at_max_layers> at_max_layers;
584 halp::item<&ins::channels> channels;
585 halp::item<&ins::latency> latency;
586 halp::item<&ins::engine_latency> engine_latency;
587 } memory;
588 } settings;
589 } controls;
590
591 struct
592 {
593 halp_meta(layout, halp::layouts::container)
594 halp_meta(background, halp::colors::background_mid)
596 } view;
597
598 struct bus
599 {
600 void init(ui& self)
601 {
602 self.view.view.erase = [this](Looper::erase_request r) {
603 if(send_message)
604 send_message(r);
605 };
606 }
607 static void process_message(ui& self, Looper::view_message msg)
608 {
609 self.view.view.receive(msg);
610 }
611 std::function<void(Looper::erase_request)> send_message;
612 };
613 };
614
615 // Public for the tests: the audio of one pass.
616 const float* layer_data(int layer, int chan) const noexcept
617 {
618 return layers.data(layers.layers[layer].slot, chan);
619 }
620
623 static constexpr int64_t work_per_tick = 262144;
624
625private:
626 friend struct Looper::looper_node<Node>;
627
628 // looper_node's hooks
629 Looper::audio_layers& stack() noexcept { return layers; }
630 const Looper::audio_layers& stack() const noexcept { return layers; }
631 int max_layers() const noexcept { return layers.slots; }
632 void layers_changing() noexcept { }
633 bool busy() const noexcept { return m_loading; }
634 void cleared() noexcept
635 {
636 m_loading = false;
637 m_tail_open = -1;
638 m_full = false;
639 }
640 void pass_dropped() noexcept { }
641 void begin_overdub(int64_t start, bool oldest, int replaced)
642 {
643 layers.begin_overdub(start, oldest, replaced);
644 m_pass_closed = false;
645 m_head_from = -1;
646 m_lapped = false;
647 m_pass_in_place = false;
648 m_last_n = 0;
649 }
650 bool can_merge_newest() const noexcept { return !layers.merging.active; }
651 void merge_newest() noexcept { layers.start_merge(layers.count - 2, true); }
653 bool pass_closing() noexcept { return !std::exchange(m_pass_closed, true); }
657 void pass_closed()
658 {
659 auto& top = *layers.top();
660 if(!m_cutting)
661 {
662 if(m_pass_in_place)
663 fade_out_written();
664 else
665 layers.fade_out_top();
666 }
667 if(!m_pass_in_place)
668 shift_pass(top);
669 // A pass that went round over its own start has its start under what it
670 // wrote after.
671 if(m_head_from >= 0 && !m_lapped)
672 layers.open_seam(top, false, m_head_from);
673 if(m_cutting)
674 {
676 m_tail_open = top.slot;
677 }
678 layers.update_seams();
679 }
680 void tick_started(const tick& tk)
681 {
682 m_in_chans = std::min<int>(inputs.audio.channels, layers.channels);
683 m_tick_start = Looper::timeline_start(tk, ossia_state);
684 m_write_shift = std::llround(double(latency_frames()) * m_speed);
685 }
686 void prepare_loop() { load_file(); }
687 void forget_carried() noexcept { m_carried_span = 0; }
688 void tick_finished(const tick& tk)
689 {
690 keep_input(ossia_state.timings(tk).length);
691 // About a quarter of a million samples of merging per tick, whatever the
692 // number of channels.
693 layers.merge_step(std::max<int64_t>(1024, work_per_tick / std::max(1, layers.channels)));
694 }
695 void close_recording(int64_t bars);
696 void close_overdub()
697 {
698 end_open_tail();
699 close_pass();
700 }
701 bool cut_after(int64_t end) const noexcept
702 {
703 return layers.layers[layers.count - 1].start >= end;
704 }
705 void cut_pass_dropped() noexcept { m_pass_closed = true; }
706 void trim_top_pass(int64_t end) noexcept
707 {
708 auto& top = *layers.top();
709 top.written = std::clamp<int64_t>(end - top.start, 0, top.written);
710 }
711 void head_moved(int64_t) noexcept { }
714 double rate_for(LoopMode m) const noexcept
715 {
716 return by_quarters() && m != LoopMode::Overdub
717 ? m_speed * std::max(1., m_tempo) / m_loop_tempo
718 : m_speed;
719 }
720 bool by_quarters() const noexcept
721 {
722 return m_stretch_mode != ossia::audio_stretch_mode::None && m_loop_tempo > 0.;
723 }
724 void set_head(double y, int64_t len) noexcept
725 {
726 set_head_y(y, len);
727 m_stretch_ready = false;
728 }
729 int64_t capture_clock() const noexcept { return m_ring_written; }
730 int64_t capture_limit() const noexcept
731 {
732 return m_ring_capacity > 0 ? std::min(m_ring_capacity, layers.capacity) : 0;
733 }
734 void capture_into(int64_t end, int64_t n);
735 void captured() noexcept { }
738 bool capture_layer_ready(const Looper::capture_window&) noexcept
739 {
740 if(m_ring_capacity <= 0)
741 return false;
742 layers.reserved_overwritten = false;
743 return true;
744 }
745 void capture_layer_into(const Looper::capture_window& w);
746 void stopping() noexcept { }
747 void close_on_stop(bool recording)
748 {
749 if(!recording)
750 close_overdub();
751 }
752 bool export_ready() const noexcept
753 {
754 return !m_flattening && !export_audio->in_use && export_audio->capacity >= layers.length
755 && export_audio->channels >= layers.channels;
756 }
757 void start_export(int passes, bool open, bool recording);
758 void continue_export();
759 void export_item(int item) { start_export_item(item); }
760 bool take_cancelled() noexcept { return std::exchange(m_export_cancelled, false); }
761 void take_released() noexcept { layers.reserved = 0; }
762 void stop_take_written() noexcept { layers.held = 0; }
763 const Looper::stop_take_notice& stop_notice() const noexcept { return stop_take->notice; }
764 static constexpr const char* take_extension = "wav";
766 halp::clip_stretch take_stretch() const noexcept
767 {
768 return Looper::clip_stretch(m_follow_tempo);
769 }
770 bool view_full() const noexcept { return m_full; }
771 bool view_writing() const noexcept { return m_flattening || m_writing; }
772
773 int m_in_chans{};
775 Looper::transport::timeline_point m_tick_start{};
776
777 // Export of a take: the passes are flattened into the export buffer a
778 // bounded number of frames per tick, then a worker writes it.
779 bool m_flattening{};
780 int64_t m_flatten_pos{};
781 int64_t m_export_length{};
782 int m_export_channels{};
783 bool m_export_cancelled{};
786 std::array<Looper::audio_layer, Looper::audio_layers::max_passes> m_export_snapshot{};
787 int m_export_count{};
788 void cancel_export() noexcept;
789 bool m_full{};
790
791 // Playing the loop at the tempo of the score, with the stretchers of the
792 // sound files reading the loop as their source.
793 ossia::resampler m_stretcher;
794 Looper::FollowTempo m_follow_tempo{Looper::FollowTempo::Off};
795 ossia::audio_stretch_mode m_stretch_mode{ossia::audio_stretch_mode::None};
796 std::vector<std::vector<double>> m_stretch_out;
799 ossia::mutable_audio_span<double> m_stretch_span;
801 double m_heard{};
802 double m_cycle_ratio{1.};
803 bool m_stretch_ready{};
804 int64_t m_expected_pos{};
805 bool m_wrapped{};
807 double m_stretch_speed{1.};
808 bool m_stretch_reverse{};
809 void play_stretched(int64_t first_pos, int64_t samples);
810
811 // The playhead as a tape's: it reads the loop at m_speed, backwards when
812 // m_reverse is set. Its position is transport.playbackPos and the part of a
813 // frame m_frac it is past it, which a move of the playhead by anything else
814 // than playing drops.
815 double m_frac{};
816 int64_t m_head_pos{-1};
819 std::array<float, Looper::audio_layers::max_channels> m_prev_in{};
820 std::array<float, Looper::audio_layers::max_channels> m_acc{};
821 int m_acc_n{};
824 int64_t m_pass_frames{};
826 int64_t m_clock{};
828 bool m_cutting{};
830 bool m_lapped{};
832 int m_head_from{-1};
834 int m_tail_open{-1};
839 int64_t m_write_shift{};
842 bool m_pass_in_place{};
843 int64_t written_at(int64_t k, int64_t len) const noexcept
844 {
845 const int64_t w = (k - (m_reverse ? -m_write_shift : m_write_shift)) % len;
846 return w < 0 ? w + len : w;
847 }
851 int64_t m_fresh_k{-1};
852 std::array<float, Looper::audio_layers::max_channels> m_fresh_delta{};
853 bool m_hide_fresh{};
857 static constexpr int last_frames = Looper::audio_layers::fade_frames;
858 std::array<int64_t, last_frames> m_last_k{};
859 std::array<float, Looper::audio_layers::max_channels * last_frames> m_last_v{};
860 int m_last_n{};
861 int m_last_i{};
862 void fade_out_written();
863 bool continue_seam();
864 void end_open_tail();
866 int64_t m_carried_span{};
867 void begin_pass_carried(int64_t len);
868 double head_y(int64_t len) const noexcept;
869 void set_head_y(double y, int64_t len) noexcept;
870 float tape(int c, int64_t k, int64_t len) const noexcept
871 {
872 const int64_t at = m_reverse ? len - 1 - k : k;
873 const float v = layers.mix(c, at);
874 return m_hide_fresh && at == m_fresh_k ? v - m_fresh_delta[c] : v;
875 }
876 float read_span(int c, double y, double s, int64_t len) const noexcept;
877 void write_tape(int64_t y, const float* v, float feedback);
878 bool cycle_end(int64_t& len, bool extend, float feedback);
879 int64_t latency_frames() const noexcept;
880 void shift_pass(Looper::audio_layer& l);
882 bool m_pass_closed{};
883
884public:
886 template <typename T>
887 void fetch_audio(int64_t start, int64_t frames, T** out) noexcept
888 {
889 const int64_t len = layers.length;
890 if(len > 0 && (m_stretch_speed != 1. || m_stretch_reverse))
891 {
892 // Frame u of what the stretchers read is the tape at u * speed.
893 const double sp = m_stretch_speed;
894 for(int c = 0; c < layers.channels; c++)
895 for(int64_t j = 0; j < frames; j++)
896 out[c][j] = T(read_span(c, std::fmod(double(start + j) * sp, double(len)), sp, len));
897 if(std::floor(double(start + frames) * sp / double(len))
898 > std::floor(double(start) * sp / double(len)))
899 m_wrapped = true;
900 return;
901 }
902 for(int c = 0; c < layers.channels; c++)
903 {
904 int64_t k = len > 0 ? start % len : 0;
905 for(int64_t j = 0; j < frames; j++)
906 {
907 out[c][j] = len > 0 ? T(layers.mix(c, k)) : T(0);
908 if(++k >= len)
909 {
910 k = 0;
911 m_wrapped = true;
912 }
913 }
914 }
915 }
916 template <typename T>
917 void fetch_audio_backward(int64_t, int64_t frames, T** out) noexcept
918 {
919 for(int c = 0; c < layers.channels; c++)
920 std::fill_n(out[c], frames, T(0));
921 }
922
923private:
924 // The overview of the passes, worked out over as many messages as a long
925 // loop needs.
926 std::array<float, Looper::view_message::max_lanes * Looper::view_message::bins>
927 m_scan_peaks{};
928 int m_scan_layer{};
929 int64_t m_scan_pos{};
930 int m_scan_count{-1};
931 uint64_t m_scan_changes{};
932 int64_t m_scan_length{-1};
933 void scan_peaks(bool whole = false);
934
935 void load_file();
936
937 // A file being copied into the loop, a part per tick.
938 const float** m_file_data{};
939 int64_t m_file_frames{};
940 int64_t m_file_pos{};
941 int64_t m_file_target{};
942 bool m_loading{};
943 void keep_input(int64_t frames);
944 void fade_edges(int slot, bool end = true);
947 bool m_seamless{};
948
949 // The input of the last seconds, for Capture.
950 boost::container::vector<float> m_ring;
951 int64_t m_ring_capacity{};
952 int m_ring_channels{};
954 int64_t m_ring_written{};
955 void start_export_item(int item);
956 void flatten(
957 const Looper::audio_layer* passes, int count, int item, int64_t len, int64_t from,
958 int64_t to);
959 void copy_open_pass();
960 void write_stop_take(bool recording, double date, int64_t pos);
964 int m_copy_from{-1};
965 int m_copy_to{-1};
966 int64_t m_copy_pos{};
967 int64_t m_copy_left{};
968 int64_t m_copy_period{};
969 int m_copy_dir{1};
970 void send_view(int64_t frames);
971 void fill_message(Looper::view_message& v);
972
973 void play(int64_t first_pos, int64_t samples);
974 void play_tape(int64_t first_pos, int64_t samples);
975 void silence(int64_t first_pos, int64_t samples);
976 void mix_input(int64_t first_pos, int64_t samples);
977 void through(int64_t first_pos, int64_t samples);
978 int64_t record(int64_t first_pos, int64_t samples, bool echo);
979 void overdub(int64_t first_pos, int64_t samples, bool echo);
980};
981
982inline int64_t Node::looper_run(int64_t start, int64_t length)
983{
984 const int64_t done = run_mode(start, length);
985 m_clock += done;
986 layers.now = m_clock;
987 return done;
988}
989
990inline int64_t Node::run_mode(int64_t start, int64_t length)
991{
992 layers.now = m_clock;
993 // A pass cut on the last frame of an overdub that ended has nothing going
994 // on from it.
995 if(m_tail_open >= 0 && transport.actualMode != LoopMode::Overdub)
996 end_open_tail();
997 layers.update_seams();
998 // Stretching starts again from where the loop is, the next time it plays.
999 if(transport.actualMode != LoopMode::Play)
1000 m_stretch_ready = false;
1001 if(transport.playbackPos != m_head_pos)
1002 m_frac = 0.;
1003
1004 // Record passthrough is what its name says: the input while something is
1005 // being taken in, and nothing else. Only Full is heard the rest of the time.
1006 const Passthrough pt = inputs.passthrough;
1007 const bool echo_while_taking_in = pt != Passthrough::None;
1008 const bool echo_otherwise = pt == Passthrough::Full;
1009 switch(transport.actualMode)
1010 {
1011 case LoopMode::Play:
1012 if(layers.empty())
1013 echo_otherwise ? through(start, length) : silence(start, length);
1014 else
1015 {
1016 if(m_stretch_mode != ossia::audio_stretch_mode::None)
1017 play_stretched(start, length);
1018 else if(m_speed != 1. || m_reverse || m_frac != 0.)
1019 play_tape(start, length);
1020 else
1021 play(start, length);
1022 if(echo_otherwise)
1023 mix_input(start, length);
1024 }
1025 return length;
1026 case LoopMode::Stop:
1027 echo_otherwise ? through(start, length) : silence(start, length);
1028 break;
1029 case LoopMode::Record:
1030 return record(start, length, echo_while_taking_in);
1031 case LoopMode::Overdub:
1032 overdub(start, length, echo_while_taking_in);
1033 break;
1034 }
1035 return length;
1036}
1037
1040inline void Node::close_recording(int64_t bars)
1041{
1042 auto* top = layers.top();
1043 if(!top || layers.length <= 0)
1044 return;
1045
1046 // Overdubbing from the frame the recording ends on carries on what was
1047 // played: the end of the loop goes on into the first pass over it. The
1048 // edges are those of what was recorded, wherever the latency puts them.
1049 m_seamless = transport.actualMode == LoopMode::Overdub;
1050 fade_edges(top->slot, !m_seamless);
1051 top->start = 0;
1052 top->written = layers.length;
1053 if(const int64_t latency = latency_frames(); latency > 0)
1054 layers.shift_earlier(*top, latency);
1055 m_tail_open = -1;
1056 if(m_seamless)
1057 {
1058 layers.open_seam(*top, true, Looper::audio_seam_end::pending);
1059 m_tail_open = top->slot;
1060 }
1061
1062 if(bars > layers.length)
1063 {
1064 const int64_t end = std::min(bars, layers.capacity);
1065 for(int c = 0; c < layers.channels; c++)
1066 std::fill(layers.data(top->slot, c) + layers.length, layers.data(top->slot, c) + end, 0.f);
1067 layers.length = end;
1068 }
1069 top->written = layers.length;
1070}
1071
1072inline int64_t Node::latency_frames() const noexcept
1073{
1074 return int64_t(inputs.latency.value * m_rate / 1000.)
1075 + (inputs.engine_latency.value
1076 ? int64_t(ossia_state.inputLatency()) + ossia_state.outputLatency()
1077 : 0);
1078}
1079
1083inline void Node::shift_pass(Looper::audio_layer& l)
1084{
1085 const int64_t latency = latency_frames();
1086 if(latency <= 0)
1087 return;
1088 const int64_t positions = std::llround(double(latency) * m_speed);
1089 layers.shift_earlier(l, l.backwards ? -positions : positions);
1090}
1091
1094inline void Node::cancel_export() noexcept
1095{
1096 m_flattening = false;
1097 m_copy_left = 0;
1098 if(m_writing)
1099 m_export_cancelled = true;
1100 layers.reserved = 0;
1101}
1102
1105inline bool Node::continue_seam()
1106{
1107 const int from = std::exchange(m_tail_open, -1);
1108 auto* top = layers.top();
1109 if(from < 0 || !top)
1110 return false;
1111 const int s = layers.resolve(from);
1112 bool met = false;
1113 layers.for_each_kept([&](Looper::audio_layer& l) {
1114 if(l.slot == s && &l != top && l.tail.partner == Looper::audio_seam_end::pending)
1115 {
1116 l.tail.partner = top->slot;
1117 l.tail.meet = top->start;
1118 met = true;
1119 }
1120 });
1121 if(met)
1122 m_head_from = s;
1123 else
1124 end_open_tail();
1125 return met;
1126}
1127
1129inline void Node::fade_out_written()
1130{
1131 auto* top = layers.top();
1132 if(!top)
1133 return;
1134 const int n = m_last_n;
1135 for(int i = 0; i < n; i++)
1136 {
1137 const int j = (m_last_i - 1 - i + last_frames) % last_frames;
1138 const float cut = 1.f - float(i) / float(n);
1139 for(int c = 0; c < layers.channels; c++)
1140 layers.data(top->slot, c)[m_last_k[j]] -= m_last_v[c * last_frames + j] * cut;
1141 }
1142 m_last_n = 0;
1143}
1144
1146inline void Node::end_open_tail()
1147{
1148 m_cycle_pending = false;
1149 const int from = std::exchange(m_tail_open, -1);
1150 if(from < 0)
1151 return;
1152 const int s = layers.resolve(from);
1153 layers.for_each_kept([&](Looper::audio_layer& l) {
1154 if(l.slot == s && l.tail.partner == Looper::audio_seam_end::pending)
1155 l.tail.partner = -1;
1156 });
1157 layers.update_seams();
1158}
1159
1161inline void Node::fade_edges(int slot, bool end)
1162{
1163 for(int c = 0; c < layers.channels; c++)
1164 {
1165 float* chan = layers.data(slot, c);
1166 const int64_t samples = layers.length;
1167 if(int64_t min_n = std::min(samples, int64_t(Looper::audio_layers::fade_frames));
1168 min_n > 0)
1169 {
1170 float f = 1.f / min_n;
1171 float ff = 0.f;
1172 for(int64_t i = 0; i < min_n; i++)
1173 {
1174 chan[i] *= ff;
1175 ff += f;
1176 }
1177 if(!end)
1178 continue;
1179 for(int64_t i = samples - min_n; i < samples; i++)
1180 {
1181 chan[i] *= ff;
1182 ff -= f;
1183 }
1184 }
1185 }
1186}
1187
1188inline void Node::keep_input(int64_t frames)
1189{
1190 if(m_ring_capacity > 0)
1191 {
1192 auto& in = inputs.audio;
1193 for(int c = 0; c < m_ring_channels; c++)
1194 {
1195 float* ring = m_ring.data() + std::size_t(c) * std::size_t(m_ring_capacity);
1196 int64_t k = m_ring_written % m_ring_capacity;
1197 for(int64_t j = 0; j < frames; j++)
1198 {
1199 ring[k] = c < in.channels ? float(in.samples[c][j]) : 0.f;
1200 if(++k == m_ring_capacity)
1201 k = 0;
1202 }
1203 }
1204 }
1205 m_ring_written += frames;
1206}
1207
1209inline void Node::capture_into(int64_t end, int64_t n)
1210{
1211 cancel_export();
1212 layers.begin_recording();
1213 m_tail_open = -1;
1214 const int slot = layers.layers[0].slot;
1215 for(int c = 0; c < layers.channels; c++)
1216 {
1217 float* dst = layers.data(slot, c);
1218 if(c >= m_ring_channels)
1219 {
1220 std::fill_n(dst, n, 0.f);
1221 continue;
1222 }
1223 const float* ring = m_ring.data() + std::size_t(c) * std::size_t(m_ring_capacity);
1224 for(int64_t i = 0; i < n; i++)
1225 {
1226 const float v = ring[(end - n + i) % m_ring_capacity];
1227 dst[i] = v;
1228 layers.note_peak(slot, i, v);
1229 }
1230 }
1231 layers.length = n;
1232 layers.layers[0].written = n;
1233 fade_edges(slot);
1234 m_full = false;
1235}
1236
1242inline void Node::capture_layer_into(const Looper::capture_window& w)
1243{
1244 if(layers.reserved_overwritten)
1245 cancel_export();
1246 auto* top = layers.top();
1247 if(!top)
1248 return;
1249 const int64_t len = layers.length;
1250 const int64_t positions = w.positions();
1251 const auto y_last = int64_t(std::floor(w.y_end));
1252 const int64_t first = w.end - w.n;
1253 const int fade = Looper::audio_layers::fade_frames;
1254 const auto input = [&](int c, double t) {
1255 if(c >= m_ring_channels)
1256 return 0.f;
1257 const float* ring = m_ring.data() + std::size_t(c) * std::size_t(m_ring_capacity);
1258 const auto at = [&](int64_t f) {
1259 return ring[std::clamp<int64_t>(f, first, w.end - 1) % m_ring_capacity];
1260 };
1261 const auto f = int64_t(std::floor(t));
1262 const float a = float(t - double(f));
1263 return at(f) + a * (at(f + 1) - at(f));
1264 };
1265 for(int64_t i = 0; i < positions; i++)
1266 {
1267 const int64_t y = y_last - positions + i;
1268 const double t = double(w.end) - (w.y_end - double(y)) / w.rate;
1269 const int64_t yw = Looper::capture_window::wrap(y, len);
1270 const int64_t k = w.backwards ? len - 1 - yw : yw;
1271 const float ramp = i < fade ? float(i) / float(fade) : 1.f;
1272 for(int c = 0; c < layers.channels; c++)
1273 {
1274 const float v = input(c, t) * ramp;
1275 layers.data(top->slot, c)[k] = v;
1276 layers.note_peak(top->slot, k, v);
1277 }
1278 }
1279 top->start = w.start();
1280 top->written = positions;
1281 top->backwards = w.backwards;
1282 if(y_last - positions < 0)
1283 layers.decay(std::clamp(inputs.feedback.value, 0.f, 1.f));
1284}
1285
1289inline void Node::load_file()
1290{
1291 const auto& f = inputs.file.soundfile;
1292 if(f.data != m_file_data || f.frames != m_file_frames)
1293 {
1294 m_file_data = f.data;
1295 m_file_frames = f.frames;
1296 m_loading = false;
1297
1298 if(!inputs.file || transport.is_taking())
1299 return;
1300
1301 const double ratio = f.rate > 0 ? m_rate / f.rate : 1.;
1302 m_file_target = std::min<int64_t>(int64_t(f.frames * ratio), layers.capacity);
1303 if(m_file_target <= 0)
1304 return;
1305 cancel_export();
1306 layers.begin_recording();
1307 m_tail_open = -1;
1308 m_switches.soloed.forget();
1309 // Nothing is heard until the whole file is in.
1310 layers.count = 0;
1311 m_file_pos = 0;
1312 m_loading = true;
1313 m_full = false;
1314 }
1315
1316 if(!m_loading)
1317 return;
1318
1319 const double step = f.rate > 0 ? double(f.rate) / m_rate : 1.;
1320 const int slot = layers.layers[0].slot;
1321 const int64_t end = std::min(m_file_target, m_file_pos + 65536);
1322 for(int c = 0; c < layers.channels; c++)
1323 {
1324 float* dst = layers.data(slot, c);
1325 // A mono file goes to every channel.
1326 const float* src = f.channels > 0 ? f.data[std::min(c, f.channels - 1)] : nullptr;
1327 for(int64_t k = m_file_pos; k < end; k++)
1328 {
1329 const double x = k * step;
1330 const int64_t i = int64_t(x);
1331 const float a = i < f.frames ? src[i] : 0.f;
1332 const float b = i + 1 < f.frames ? src[i + 1] : a;
1333 const float v = a + float(x - i) * (b - a);
1334 dst[k] = v;
1335 layers.note_peak(slot, k, v);
1336 }
1337 }
1338 m_file_pos = end;
1339 if(m_file_pos < m_file_target)
1340 return;
1341
1342 m_loading = false;
1343 m_loop_tempo = m_tempo;
1344 layers.length = m_file_target;
1345 layers.layers[0].written = m_file_target;
1346 layers.count = 1;
1347 layers.total = 1;
1348 fade_edges(slot);
1349 transport.play_captured(0);
1350 m_origin = m_tick_start;
1351}
1352
1355inline void Node::play_stretched(int64_t first_pos, int64_t samples)
1356{
1357 const int64_t len = layers.length;
1358 const int chans = layers.channels;
1359 if(std::ssize(m_stretch_out) < chans || std::ssize(m_stretch_span) < chans
1360 || samples > std::ssize(m_stretch_out[0]))
1361 {
1362 play(first_pos, samples);
1363 return;
1364 }
1365 if(!m_stretch_ready || transport.playbackPos % len != m_expected_pos
1366 || m_stretch_speed != m_speed || m_stretch_reverse != m_reverse)
1367 {
1368 // The stretchers read the tape at m_speed: their frame u is position
1369 // u * m_speed of it, which goes round every len / m_speed frames.
1370 m_stretch_speed = m_speed;
1371 m_stretch_reverse = m_reverse;
1372 const auto u = int64_t(head_y(len) / m_speed);
1373 m_stretcher.transport(u);
1374 m_heard = double(u);
1375 m_cycle_ratio = m_loop_tempo / std::max(1., m_tempo);
1376 m_stretch_ready = true;
1377 }
1378
1379 for(int c = 0; c < chans; c++)
1380 m_stretch_span[c] = std::span<double>(m_stretch_out[c].data(), std::size_t(samples));
1381
1382 ossia::token_request tk;
1383 tk.prev_date = ossia::time_value{0};
1384 tk.date = ossia::time_value{samples};
1385 m_wrapped = false;
1386 // Frames of output per frame of the loop, for this run.
1387 const double ratio = m_stretcher.stretch() ? m_cycle_ratio : 1.;
1388 m_stretcher.run(
1389 *this, tk, ossia_state, m_cycle_ratio, 1., std::size_t(chans), len, samples,
1390 samples, 0, m_stretch_span);
1391 if(m_wrapped)
1392 m_cycle_ratio = m_loop_tempo / std::max(1., m_tempo);
1393
1394 auto& p2 = outputs.audio;
1395 const int loop_chans = std::min(chans, p2.channels);
1396 for(int c = 0; c < loop_chans; c++)
1397 for(int64_t j = 0; j < samples; j++)
1398 p2.samples[c][first_pos + j] = m_stretch_out[c][j];
1399 for(int c = loop_chans; c < p2.channels; c++)
1400 for(int64_t j = 0; j < samples; j++)
1401 p2.samples[c][first_pos + j] = 0.;
1402
1403 // The stretcher reads ahead of what it outputs, by what it keeps buffered
1404 // and its own latency: the position is the one of what was heard, which an
1405 // overdub that carries on from here writes at.
1406 m_heard = std::fmod(
1407 m_heard + double(samples) / std::max(1e-9, ratio), double(len) / m_stretch_speed);
1408 if(m_stretch_speed == 1. && !m_stretch_reverse)
1409 {
1410 transport.playbackPos = int64_t(m_heard) % len;
1411 m_frac = 0.;
1412 m_head_pos = transport.playbackPos;
1413 }
1414 else
1415 {
1416 set_head_y(std::fmod(m_heard * m_stretch_speed, double(len)), len);
1417 }
1418 m_expected_pos = transport.playbackPos;
1419}
1420
1423inline double Node::head_y(int64_t len) const noexcept
1424{
1425 const double h = double(transport.playbackPos % len) + m_frac;
1426 double y = m_reverse ? double(len) - h : h;
1427 if(y >= double(len))
1428 y -= double(len);
1429 if(y < 0.)
1430 y += double(len);
1431 return y;
1432}
1433
1434inline void Node::set_head_y(double y, int64_t len) noexcept
1435{
1436 double h = m_reverse ? double(len) - y : y;
1437 h = std::fmod(h, double(len));
1438 if(h < 0.)
1439 h += double(len);
1440 const double whole = std::floor(h);
1441 transport.playbackPos = int64_t(whole) % len;
1442 m_frac = h - whole;
1443 // A position that rounds to the loop's end is its start.
1444 if(m_frac >= 1. - 1e-9)
1445 {
1446 transport.playbackPos = (transport.playbackPos + 1) % len;
1447 m_frac = 0.;
1448 }
1449 m_head_pos = transport.playbackPos;
1450}
1451
1455inline float Node::read_span(int c, double y, double s, int64_t len) const noexcept
1456{
1457 if(s > 1.)
1458 {
1459 const int n = int(std::lround(s));
1460 const auto k0 = int64_t(y);
1461 float sum = 0.f;
1462 for(int i = 0; i < n; i++)
1463 sum += tape(c, (k0 + i) % len, len);
1464 return sum / float(n);
1465 }
1466 const double centre = y + 0.5 * s - 0.5;
1467 const double whole = std::floor(centre);
1468 const double f = centre - whole;
1469 int64_t k = int64_t(whole) % len;
1470 if(k < 0)
1471 k += len;
1472 const float a = tape(c, k, len);
1473 if(f < 1e-9)
1474 return a;
1475 return a + float(f) * (tape(c, (k + 1) % len, len) - a);
1476}
1477
1479inline void Node::play_tape(int64_t first_pos, int64_t samples)
1480{
1481 auto& p2 = outputs.audio;
1482 const int64_t last = first_pos + samples;
1483 const int out_chans = p2.channels;
1484 const int loop_chans = std::min(layers.channels, out_chans);
1485 const int64_t len = layers.length;
1486 const double s = m_speed;
1487 double y = head_y(len);
1488 // Faster than x1, whole positions are gone over.
1489 if(s > 1.)
1490 y = std::floor(y);
1491
1492 for(int64_t j = first_pos; j < last; j++)
1493 {
1494 layers.now = m_clock + (j - first_pos);
1495 for(int i = 0; i < loop_chans; i++)
1496 p2.samples[i][j] = read_span(i, y, s, len);
1497 y += s;
1498 while(y >= double(len))
1499 y -= double(len);
1500 }
1501 for(int i = loop_chans; i < out_chans; i++)
1502 for(int64_t j = first_pos; j < last; j++)
1503 p2.samples[i][j] = 0.;
1504
1505 set_head_y(y, len);
1506}
1507
1508inline void Node::play(int64_t first_pos, int64_t samples)
1509{
1510 auto& p2 = outputs.audio;
1511 const int64_t last = first_pos + samples;
1512 const int out_chans = p2.channels;
1513 const int loop_chans = std::min(layers.channels, out_chans);
1514 const int64_t len = layers.length;
1515 const int64_t start = transport.playbackPos % len;
1516
1517 for(int i = 0; i < loop_chans; i++)
1518 {
1519 auto& out = p2.samples[i];
1520 // The loop is free to be shorter than the tick, and to end anywhere
1521 // inside it.
1522 int64_t k = start;
1523 for(int64_t j = first_pos; j < last; j++)
1524 {
1525 layers.now = m_clock + (j - first_pos);
1526 out[j] = layers.mix(i, k);
1527 if(++k == len)
1528 k = 0;
1529 }
1530 }
1531
1532 // The bus can carry more channels than the loop was recorded with.
1533 for(int i = loop_chans; i < out_chans; i++)
1534 {
1535 auto& out = p2.samples[i];
1536 for(int64_t j = first_pos; j < last; j++)
1537 out[j] = 0.;
1538 }
1539
1540 // The loop goes on with no output to play it to, e.g. nothing patched in.
1541 transport.playbackPos = (start + samples) % len;
1542}
1543
1546inline void Node::silence(int64_t first_pos, int64_t samples)
1547{
1548 auto& p2 = outputs.audio;
1549 const int64_t last = first_pos + samples;
1550 for(int i = 0; i < p2.channels; i++)
1551 {
1552 auto& out = p2.samples[i];
1553 for(int64_t j = first_pos; j < last; j++)
1554 out[j] = 0.;
1555 }
1556}
1557
1558inline void Node::mix_input(int64_t first_pos, int64_t samples)
1559{
1560 auto& p1 = inputs.audio;
1561 auto& p2 = outputs.audio;
1562 const int chans = std::min(p1.channels, p2.channels);
1563 const int64_t last = first_pos + samples;
1564 for(int i = 0; i < chans; i++)
1565 {
1566 auto& in = p1.samples[i];
1567 auto& out = p2.samples[i];
1568 for(int64_t j = first_pos; j < last; j++)
1569 out[j] += in[j];
1570 }
1571}
1572
1573inline void Node::through(int64_t first_pos, int64_t samples)
1574{
1575 auto& p1 = inputs.audio;
1576 auto& p2 = outputs.audio;
1577 const int chans = std::min(p1.channels, p2.channels);
1578 const int64_t last = first_pos + samples;
1579 for(int i = 0; i < chans; i++)
1580 {
1581 auto& in = p1.samples[i];
1582 auto& out = p2.samples[i];
1583 for(int64_t j = first_pos; j < last; j++)
1584 out[j] = in[j];
1585 }
1586 for(int i = chans; i < p2.channels; i++)
1587 {
1588 auto& out = p2.samples[i];
1589 for(int64_t j = first_pos; j < last; j++)
1590 out[j] = 0.;
1591 }
1592}
1593
1594inline int64_t Node::record(int64_t first_pos, int64_t samples, bool echo)
1595{
1596 auto& p1 = inputs.audio;
1597 if(!transport.is_taking())
1598 {
1599 // A new recording: the passes go, and an export of them that was still
1600 // being flattened would read the new one.
1601 cancel_export();
1602 layers.begin_recording();
1603 m_tail_open = -1;
1604 m_switches.soloed.forget();
1605 m_seamless = false;
1606 transport.playbackPos = 0;
1607 m_export_pending = false;
1608 m_full = false;
1609 m_loading = false;
1610 }
1611 transport.taking(LoopMode::Record);
1612
1613 auto& base = layers.layers[0];
1614 const int64_t pos = layers.length;
1615 const int64_t room = std::max<int64_t>(0, layers.capacity - pos);
1616 const int64_t n = std::min(samples, room);
1617 const int chans = std::min(p1.channels, layers.channels);
1618
1619 for(int c = 0; c < layers.channels; c++)
1620 {
1621 float* dst = layers.data(base.slot, c) + pos;
1622 if(c < chans)
1623 {
1624 auto& in = p1.samples[c];
1625 for(int64_t j = 0; j < n; j++)
1626 {
1627 const float v = float(in[first_pos + j]);
1628 dst[j] = v;
1629 layers.note_peak(base.slot, pos + j, v);
1630 }
1631 }
1632 else
1633 {
1634 std::fill_n(dst, n, 0.f);
1635 }
1636 }
1637 layers.length += n;
1638 base.written = layers.length;
1639 transport.playbackPos = layers.length;
1640
1641 echo ? through(first_pos, n) : silence(first_pos, n);
1642
1643 if(n < samples)
1644 {
1645 // The buffer is full: the loop is what fitted, and the post-action takes
1646 // over for the rest of the span.
1647 m_full = true;
1648 transport.end_recording(inputs.after_record);
1649 transport.playbackPos = 0;
1650 }
1651 return n;
1652}
1653
1657inline void Node::write_tape(int64_t y, const float* v, float feedback)
1658{
1659 if(std::exchange(m_cycle_pending, false))
1660 {
1661 // The pass of the cycle that ended is closed as any pass is, but for its
1662 // end: the next one goes on from it.
1663 m_cutting = true;
1664 close_pass(true);
1665 m_cutting = false;
1666 layers.reserved_overwritten = false;
1667 begin_pass(written_at(m_reverse ? layers.length - 1 - y : y, layers.length));
1668 m_pass_in_place = true;
1669 if(layers.reserved_overwritten)
1670 cancel_export();
1671 // It is not faded in where it meets the one before it.
1672 m_pass_frames = continue_seam() ? Looper::audio_layers::fade_frames : 0;
1673 }
1674 auto* t = layers.top();
1675 if(!t)
1676 return;
1677 auto& top = *t;
1678 const int64_t len = layers.length;
1679 const int64_t k = written_at(m_reverse ? len - 1 - y : y, len);
1680 const bool first_time = !layers.valid(top, k);
1681 const int fade = Looper::audio_layers::fade_frames;
1682 const float ramp
1683 = m_pass_frames < fade ? float(m_pass_frames) / fade : 1.f;
1684 m_pass_frames++;
1685 const float g = layers.heard_gain(top);
1686 for(int c = 0; c < layers.channels; c++)
1687 {
1688 float& d = layers.data(top.slot, c)[k];
1689 const float before = first_time ? 0.f : d;
1690 // Later laps of the pass fade what it laid down on the earlier ones.
1691 d = before * feedback + v[c] * ramp;
1692 layers.note_peak(top.slot, k, d);
1693 m_fresh_delta[c] = top.muted ? 0.f : g * (d - before);
1694 m_last_v[c * last_frames + m_last_i] = v[c] * ramp;
1695 }
1696 m_fresh_k = k;
1697 m_last_k[m_last_i] = k;
1698 m_last_i = (m_last_i + 1) % last_frames;
1699 m_last_n = std::min(m_last_n + 1, last_frames);
1700 m_lapped = m_lapped || !first_time;
1701 layers.cover(top, k);
1702 top.backwards = m_reverse;
1703}
1704
1709inline bool Node::cycle_end(int64_t& len, bool extend, float feedback)
1710{
1711 // A cycle is the loop's length when the overdub started: the loop growing
1712 // by one is a cycle gone round as well.
1713 const bool per_cycle = inputs.passes.value == Looper::Passes::PerCycle;
1714 if(extend && layers.extend(m_extend_unit))
1715 {
1716 len = layers.length;
1717 m_extended = true;
1718 if(per_cycle)
1719 m_cycle_pending = true;
1720 return false;
1721 }
1722 // The gains glide while the playhead goes over the frames the seams weigh.
1723 layers.decay(
1724 feedback,
1725 int64_t(std::ceil(double(Looper::audio_layers::fade_frames) / std::max(1e-3, m_speed))));
1726 if(per_cycle)
1727 m_cycle_pending = true;
1728 return true;
1729}
1730
1735inline void Node::begin_pass_carried(int64_t len)
1736{
1737 const int64_t span = m_carried_span;
1738 m_carried_span = 0;
1739 // A pass that carries on a recording starts at full level: it is not faded
1740 // in, as if it had already written its fade.
1741 const bool seamless = std::exchange(m_seamless, false);
1742 const int fade = seamless ? 0 : Looper::audio_layers::fade_frames;
1743 m_pass_frames = seamless ? Looper::audio_layers::fade_frames : 0;
1744 const int64_t k = transport.playbackPos % len;
1745 const bool carried = span > 0 && span < len && k == span && layers.count == 1
1746 && m_speed == 1. && !m_reverse
1747 && len + span <= layers.capacity;
1748 m_fresh_k = -1;
1749 begin_pass(written_at(carried ? 0 : k, len));
1750 m_pass_in_place = true;
1751 if(seamless)
1752 continue_seam();
1753 else
1754 end_open_tail();
1755 auto* top = layers.top();
1756 if(!carried || !top || layers.count != 2)
1757 return;
1758 const auto& base = layers.layers[0];
1759 for(int64_t i = 0; i < span; i++)
1760 {
1761 const float ramp = i < fade ? float(i) / fade : 1.f;
1762 const int64_t at = written_at(i, len);
1763 for(int c = 0; c < layers.channels; c++)
1764 {
1765 const float v = layers.data(base.slot, c)[len + i] * ramp;
1766 layers.data(top->slot, c)[at] = v;
1767 layers.note_peak(top->slot, at, v);
1768 }
1769 layers.cover(*top, at);
1770 }
1771 m_pass_frames = std::max<int64_t>(m_pass_frames, span);
1772}
1773
1774inline void Node::overdub(int64_t first_pos, int64_t samples, bool echo)
1775{
1776 auto& p1 = inputs.audio;
1777 auto& p2 = outputs.audio;
1778 const int64_t last = first_pos + samples;
1779
1780 // Nothing to layer onto: an overdub of an empty loop is an echo.
1781 if(layers.empty())
1782 {
1783 echo ? through(first_pos, samples) : silence(first_pos, samples);
1784 return;
1785 }
1786
1787 const int in_chans = std::min(p1.channels, layers.channels);
1788 const int out_chans = p2.channels;
1789 auto input = [&](int c, int64_t j) {
1790 return c < in_chans ? float(p1.samples[c][j]) : 0.f;
1791 };
1792
1793 int64_t len = layers.length;
1794 if(!transport.is_taking())
1795 {
1796 layers.reserved_overwritten = false;
1797 begin_pass_carried(len);
1798 // No buffer was left but one a take being written still reads.
1799 if(layers.reserved_overwritten)
1800 cancel_export();
1801 // An extending pass grows the loop by the loop it started over.
1802 m_extend_unit = len;
1803 m_extended = false;
1804 m_cycle_pending = false;
1805 m_acc_n = 0;
1806 for(int c = 0; c < layers.channels; c++)
1807 {
1808 m_acc[c] = 0.f;
1809 m_prev_in[c] = input(c, first_pos);
1810 }
1811 }
1812 transport.taking(LoopMode::Overdub);
1813 // Backwards, the playhead reaches the loop's start, not its end.
1814 const bool extend = inputs.past_end.value == Looper::PastEnd::Extend && !m_reverse;
1815
1816 if(!layers.top())
1817 return;
1818
1819 const float feedback = std::clamp(inputs.feedback.value, 0.f, 1.f);
1820 const double s = m_speed;
1821 double y = head_y(len);
1822 if(s >= 1.)
1823 y = std::floor(y);
1824 const int steps = s >= 1. ? int(std::lround(s)) : 1;
1825 std::array<float, Looper::audio_layers::max_channels> v{};
1826
1827 for(int64_t j = first_pos; j < last; j++)
1828 {
1829 layers.now = m_clock + (j - first_pos);
1830 m_hide_fresh = true;
1831 for(int c = 0; c < layers.channels; c++)
1832 {
1833 const float in = input(c, j);
1834 const float before = read_span(c, y, s, len);
1835 if(c < out_chans)
1836 p2.samples[c][j] = echo ? before + in : before;
1837 }
1838 m_hide_fresh = false;
1839 for(int c = layers.channels; c < out_chans; c++)
1840 p2.samples[c][j] = 0.;
1841
1842 if(s >= 1.)
1843 {
1844 // Each frame goes over `steps` positions: the input between the last
1845 // frame and this one, interpolated, the last of them this frame's.
1846 auto w = int64_t(y);
1847 for(int i = 0; i < steps; i++)
1848 {
1849 const float t = float(i + 1) / float(steps);
1850 for(int c = 0; c < layers.channels; c++)
1851 v[c] = steps == 1 ? input(c, j) : m_prev_in[c] + t * (input(c, j) - m_prev_in[c]);
1852 write_tape(w, v.data(), feedback);
1853 if(++w == len && cycle_end(len, extend, feedback))
1854 w = 0;
1855 }
1856 y = double(w);
1857 }
1858 else
1859 {
1860 // A position takes several frames: what came in over them, averaged,
1861 // once the playhead leaves it.
1862 for(int c = 0; c < layers.channels; c++)
1863 m_acc[c] += input(c, j);
1864 m_acc_n++;
1865 const auto k = int64_t(y);
1866 y += s;
1867 if(y >= double(k + 1) - 1e-9)
1868 {
1869 for(int c = 0; c < layers.channels; c++)
1870 {
1871 v[c] = m_acc[c] / float(m_acc_n);
1872 m_acc[c] = 0.f;
1873 }
1874 m_acc_n = 0;
1875 write_tape(k, v.data(), feedback);
1876 if(k + 1 == len && cycle_end(len, extend, feedback))
1877 y -= double(len);
1878 }
1879 }
1880 for(int c = 0; c < layers.channels; c++)
1881 m_prev_in[c] = input(c, j);
1882 }
1883 set_head_y(y, len);
1884}
1885
1886inline void Node::start_export_item(int item)
1887{
1888 m_export_item = item;
1889 m_flattening = true;
1890 m_flatten_pos = 0;
1891}
1892
1895inline void Node::start_export(int passes, bool open, bool recording)
1896{
1897 m_export_length = layers.length;
1898 m_export_channels = layers.channels;
1899 // The passes as they are now: gains change with feedback, the loop's
1900 // length with undo, and new passes come while the files are written.
1901 m_export_count = passes;
1902 std::copy_n(layers.layers.begin(), layers.count, m_export_snapshot.begin());
1903 layers.reserved = 0;
1904 for(int i = 0; i < m_export_count; i++)
1905 layers.reserved |= uint64_t(1) << m_export_snapshot[i].slot;
1906 start_export_item(m_export_first);
1907 if(open && !recording)
1908 copy_open_pass();
1909}
1910
1911inline void Node::continue_export()
1912{
1913 if(!m_flattening)
1914 return;
1915
1916 if(m_copy_left > 0)
1917 {
1918 const int64_t n = std::min(
1919 m_copy_left,
1920 std::max<int64_t>(65536, work_per_tick / std::max(1, m_export_channels)));
1921 for(int c = 0; c < m_export_channels; c++)
1922 {
1923 const float* src = layers.data(m_copy_from, c);
1924 float* dst = layers.data(m_copy_to, c);
1925 int64_t q = m_copy_pos;
1926 for(int64_t i = 0; i < n; i++)
1927 {
1928 dst[q] = src[q];
1929 q += m_copy_dir;
1930 if(q >= m_copy_period)
1931 q = 0;
1932 else if(q < 0)
1933 q = m_copy_period - 1;
1934 }
1935 }
1936 m_copy_pos = (m_copy_pos + m_copy_dir * n) % m_copy_period;
1937 if(m_copy_pos < 0)
1938 m_copy_pos += m_copy_period;
1939 m_copy_left -= n;
1940 if(m_copy_left > 0)
1941 return;
1942 }
1943
1944 // A bounded amount of work per tick: a minute-long loop of many passes and
1945 // channels does not make one tick a minute of work.
1946 const int64_t per_frame
1947 = int64_t(m_export_channels) * (m_export_item < 0 ? std::max(1, m_export_count) : 1);
1948 const int64_t chunk = std::max<int64_t>(1024, work_per_tick / std::max<int64_t>(1, per_frame));
1949 const int64_t end = std::min(m_export_length, m_flatten_pos + chunk);
1950 flatten(
1951 m_export_snapshot.data(), m_export_count, m_export_item, m_export_length,
1952 m_flatten_pos, end);
1953 m_flatten_pos = end;
1954
1955 if(m_flatten_pos < m_export_length)
1956 return;
1957
1958 m_flattening = false;
1959 m_writing = true;
1960
1961 Looper::take_job job;
1962 job.writer = writer;
1963 job.audio = export_audio;
1964 job.slot = m_export_slot;
1965 job.number = m_export_number;
1966 job.layer = m_export_item;
1967 job.channels = m_export_channels;
1968 job.frames = m_export_length;
1969 job.rate = int(m_rate);
1970 job.tempo = m_export_tempo;
1971 job.meter_numerator = m_export_signature.upper;
1972 job.meter_denominator = m_export_signature.lower;
1973 export_audio->in_use = true;
1974 worker.request(std::move(job));
1975}
1976
1979inline void Node::flatten(
1980 const Looper::audio_layer* passes, int count, int item, int64_t len, int64_t from,
1981 int64_t to)
1982{
1983 const auto data = [this](int slot, int c) -> const float* { return layers.data(slot, c); };
1984 for(int c = 0; c < m_export_channels; c++)
1985 {
1986 float* dst = export_audio->channel(c);
1987 if(item < 0)
1988 {
1989 Looper::mix_passes(data, passes, count, c, len, from, to, dst);
1990 }
1991 else
1992 {
1993 // A muted pass has its file, as it would be heard.
1994 const auto& l = passes[item];
1995 const float* src = layers.data(l.slot, c);
1996 for(int64_t k = from; k < to; k++)
1997 dst[k] = Looper::audio_layers::valid_in(l, k, len)
1998 ? l.unmuted_gain * src[Looper::audio_layers::index_in(l, k, len)]
1999 : 0.f;
2000 }
2001 }
2002}
2003
2008inline void Node::copy_open_pass()
2009{
2010 auto& l = m_export_snapshot[m_export_count - 1];
2011 int spare = -1;
2012 for(int s = 0; s < layers.buffers() && spare < 0; s++)
2013 if(!layers.slot_used(s) && !layers.is_reserved(s))
2014 spare = s;
2015 const int64_t period = Looper::audio_layers::period_in(l, m_export_length);
2016 if(spare < 0 || period <= 0)
2017 return;
2018 layers.reserved |= uint64_t(1) << spare;
2019 m_copy_from = l.slot;
2020 m_copy_to = spare;
2021 l.slot = spare;
2022 m_copy_period = period;
2023 m_copy_left = period;
2024 m_copy_dir = m_reverse ? -1 : 1;
2025 const int64_t head
2026 = written_at(transport.playbackPos % std::max<int64_t>(1, m_export_length), std::max<int64_t>(1, m_export_length))
2027 % period;
2028 const int64_t behind = std::min<int64_t>(period / 2, 8192);
2029 m_copy_pos = ((head - m_copy_dir * behind) % period + period) % period;
2030}
2031
2037inline void Node::write_stop_take(bool recording, double date, int64_t)
2038{
2039 auto& s = *stop_take;
2040 if(!writer || layers.empty() || s.in_use)
2041 return;
2042
2043 auto& src = s.passes;
2044 src.pool = layers.pool;
2045 std::copy_n(layers.layers.begin(), layers.count, src.passes.begin());
2046 src.count = layers.count;
2047 src.channels = layers.channels;
2048 src.capacity = layers.capacity;
2049 src.length = layers.length;
2050 for(int i = 0; i < layers.count; i++)
2051 layers.held |= uint64_t(1) << layers.layers[i].slot;
2052 // The views are shown every pass, as the take has them.
2053 scan_peaks(true);
2054 prepare_stop_notice(s.notice, date);
2055
2056 Looper::take_job job;
2057 job.writer = writer;
2058 job.stop = stop_take;
2059 job.slot = claim_take_slot();
2060 job.alone = true;
2061 job.channels = layers.channels;
2062 job.frames = layers.length;
2063 job.rate = int(m_rate);
2064 job.tempo = recording ? m_tempo : m_loop_tempo;
2065 job.meter_numerator = m_signature.upper;
2066 job.meter_denominator = m_signature.lower;
2067 s.in_use = true;
2068 worker.request(std::move(job));
2069}
2070
2071inline void Node::send_view(int64_t frames)
2072{
2073 if(!view_due(frames))
2074 return;
2075 fill_message(m_view);
2076 send_message(m_view);
2077}
2078
2081inline void Node::fill_message(Looper::view_message& v)
2082{
2083 fill_view(v);
2084 v.max_seconds = float(layers.capacity / m_rate);
2085 scan_peaks();
2086 if(&v != &m_view)
2087 {
2088 v.lanes = m_view.lanes;
2089 v.peaks = m_view.peaks;
2090 }
2091}
2092
2097inline void Node::scan_peaks(bool whole)
2098{
2099 using layers_t = Looper::audio_layers;
2100 constexpr int bins = Looper::view_message::bins;
2101 const int count = layers.count;
2102 const int64_t len = layers.length;
2103 const int lanes = std::min(count, Looper::view_message::max_lanes);
2104 if(count != m_scan_count || len != m_scan_length || layers.changes != m_scan_changes)
2105 {
2106 m_scan_count = count;
2107 m_scan_length = len;
2108 m_scan_changes = layers.changes;
2109 m_scan_layer = 0;
2110 m_scan_pos = 0;
2111 std::fill(m_scan_peaks.begin(), m_scan_peaks.end(), 0.f);
2112 }
2113
2114 const int64_t micro = (len + layers_t::peak_frames - 1) / layers_t::peak_frames;
2115 int64_t budget = whole ? std::numeric_limits<int64_t>::max() / 2 : work_per_tick / 8;
2116 while(m_scan_layer < count && budget > 0)
2117 {
2118 const int i = m_scan_layer;
2119 const int lane = std::max(0, i - (count - lanes));
2120 const auto& l = layers.layers[i];
2121 const float* p = layers.peaks_of(l.slot);
2122 float* dst = m_scan_peaks.data() + lane * bins;
2123 // A pass shorter than the loop plays again over the rest of it.
2124 const int64_t own = std::max<int64_t>(
2125 1, (layers.period_of(l) + layers_t::peak_frames - 1) / layers_t::peak_frames);
2126 const int64_t end = std::min(micro, m_scan_pos + budget);
2127 // A muted pass of a lane of its own is drawn as it would be heard, the
2128 // view dims it; in the lane of the oldest passes, it is left out.
2129 const float gain = count > lanes && i <= count - lanes ? l.gain : l.unmuted_gain;
2130 for(int64_t m = m_scan_pos; m < end; m++)
2131 {
2132 const int b = int(m * bins / micro);
2133 dst[b] = std::max(dst[b], p[m % own] * gain);
2134 }
2135 budget -= end - m_scan_pos;
2136 m_scan_pos = end;
2137 if(m_scan_pos >= micro)
2138 {
2139 m_scan_layer++;
2140 m_scan_pos = 0;
2141 }
2142 }
2143
2144 if(m_scan_layer < count)
2145 return;
2146 m_view.lanes = lanes;
2147 m_view.peaks = m_scan_peaks;
2148 // The next message goes through the passes again: gains change as an
2149 // overdub goes round, and what it records with them.
2150 m_scan_layer = 0;
2151 m_scan_pos = 0;
2152 std::fill(m_scan_peaks.begin(), m_scan_peaks.end(), 0.f);
2153}
2154}
Definition AudioLayers.hpp:14
PastEnd
What an overdub does at the end of the loop.
Definition score-plugin-fx/Fx/Looper/Transport.hpp:197
@ Extend
Makes the loop longer by the loop's length, the passes under it repeating.
@ Wrap
Goes round the loop again.
TakeFiles
Definition LooperView.hpp:46
FollowTempo
How an audio loop follows the tempo of the score, as sound files do.
Definition score-plugin-fx/Fx/Looper/Transport.hpp:204
halp::clip_stretch clip_stretch(FollowTempo f) noexcept
How a take made with f asks the timeline to play it: as the loop was.
Definition AudioLooper.hpp:41
transport::timeline_point timeline_start(const ossia::token_request &tk, ossia::exec_state_facade st) noexcept
Definition score-plugin-fx/Fx/Looper/Transport.hpp:1052
Passthrough
Definition score-plugin-fx/Fx/Looper/Transport.hpp:189
Passes
What an overdub that goes round the loop several times leaves.
Definition score-plugin-fx/Fx/Looper/Transport.hpp:131
@ PerCycle
A pass for each time it goes round, cut on the loop's start.
@ Whole
One pass, from when the overdub starts to when it stops.
void mix_passes(Data &&data, const audio_layer *passes, int count, int c, int64_t len, int64_t from, int64_t to, float *dst)
Definition AudioLayers.hpp:981
Definition AudioLooper.hpp:84
Definition AudioLooper.hpp:599
Definition AudioLooper.hpp:522
Definition AudioLooper.hpp:371
static bool must_run(const Looper::take_job &job) noexcept
The take the score's stop leaves is written once the looper is gone.
Definition AudioLooper.hpp:374
Definition AudioLooper.hpp:63
static constexpr int64_t work_per_tick
Definition AudioLooper.hpp:623
void process_message(const Looper::erase_request &r)
From the view: applied at the start of the next tick.
Definition AudioLooper.hpp:390
void allocate_ring(int channels, int64_t frames)
Main thread only.
Definition AudioLooper.hpp:483
void fetch_audio(int64_t start, int64_t frames, T **out) noexcept
What the stretchers read: the loop as it is heard, round and round.
Definition AudioLooper.hpp:887
std::shared_ptr< Looper::audio_stop_take > stop_take
Definition AudioLooper.hpp:400
void stop()
Stopping the process keeps the loop: only the transport starts over.
Definition AudioLooper.hpp:519
void prepare_stretch(double rate, int frames)
Definition AudioLooper.hpp:431
std::function< void(Looper::view_message)> send_message_from_worker
Definition AudioLooper.hpp:387
static constexpr std::array< int, 1 > removed_inlets() noexcept
Definition AudioLooper.hpp:78
Definition Switches.hpp:344
Definition Switches.hpp:161
Definition Switches.hpp:300
int64_t written
Definition AudioLayers.hpp:65
Definition AudioLayers.hpp:98
bool reserved_overwritten
Set when a new pass had to go into a reserved buffer after all.
Definition AudioLayers.hpp:124
void decay(float feedback, int64_t glide=fade_frames) noexcept
Definition AudioLayers.hpp:903
void start_merge(int at=0, bool undoable=false) noexcept
Definition AudioLayers.hpp:718
void shift_earlier(audio_layer &l, int64_t frames) noexcept
Definition AudioLayers.hpp:947
void update_seams() noexcept
Definition AudioLayers.hpp:630
uint64_t reserved
Definition AudioLayers.hpp:119
int resolve(int s) const noexcept
The buffer a merge forwarded buffer s to.
Definition AudioLayers.hpp:517
float mix(int c, int64_t k) const noexcept
What the loop sounds like at position k of channel c.
Definition AudioLayers.hpp:331
void allocate(int chans, int layer_count, int64_t frames)
Main thread only.
Definition AudioLayers.hpp:167
uint64_t held
Definition AudioLayers.hpp:122
void fade_out_top() noexcept
Definition AudioLayers.hpp:923
void for_each_kept(F &&f) noexcept
Every pass kept: heard, brought back by redo, set aside or merged.
Definition AudioLayers.hpp:500
uint64_t changes
Definition AudioLayers.hpp:115
float heard_gain(const audio_layer &l) const noexcept
Gain pass l is heard with at frame now.
Definition AudioLayers.hpp:323
void begin_recording() noexcept
Forgets every pass and starts a recording in a free buffer.
Definition AudioLayers.hpp:441
void begin_overdub(int64_t start, bool oldest=true, int replace=-1) noexcept
Definition AudioLayers.hpp:666
static int64_t index_in(const audio_layer &l, int64_t k, int64_t loop_length) noexcept
Definition AudioLayers.hpp:282
int64_t now
Frame counter of the processing: gains glide over frames of it.
Definition AudioLayers.hpp:138
void merge_step(int64_t frames) noexcept
Definition AudioLayers.hpp:754
void open_seam(audio_layer &l, bool tail, int partner) noexcept
Definition AudioLayers.hpp:575
void cover(audio_layer &l, int64_t k) noexcept
Definition AudioLayers.hpp:389
bool extend(int64_t unit) noexcept
Definition AudioLayers.hpp:438
static constexpr int pending
The pass on the other side is not there yet.
Definition AudioLayers.hpp:23
Definition Switches.hpp:458
An enumeration shown as a combobox: compact where the choices are many.
Definition Switches.hpp:59
Definition Switches.hpp:430
Definition LooperView.hpp:64
static std::shared_ptr< export_buffer > make(int channels, int64_t frames)
Main thread only. The memory is reserved without being written.
Definition TakeWriter.hpp:193
Definition Switches.hpp:453
Definition Switches.hpp:50
Definition Switches.hpp:828
Definition LooperNode.hpp:169
int64_t m_extend_unit
Definition LooperNode.hpp:398
void stop_score()
Definition LooperNode.hpp:990
void begin_pass(int64_t start)
Definition LooperNode.hpp:677
bool m_cycle_pending
Definition LooperNode.hpp:402
void close_pass(bool cycle=false)
Definition LooperNode.hpp:705
void prepare_stop_notice(Looper::stop_take_notice &n, double date)
Definition LooperNode.hpp:1021
void view_request(const Looper::erase_request &r) noexcept
From the view: applied at the start of the next tick.
Definition LooperNode.hpp:285
Looper::transport::timeline_point m_origin
Definition LooperNode.hpp:393
double m_speed
The playhead goes at m_speed, backwards when m_reverse is set.
Definition LooperNode.hpp:389
double m_loop_tempo
Tempo the loop was recorded at: the loop keeps its own speed.
Definition LooperNode.hpp:395
void capture(const tick &tk)
Definition LooperNode.hpp:888
void fill_view(Looper::view_message &v) const noexcept
Definition LooperNode.hpp:1177
bool view_due(int64_t frames) noexcept
Whether the view is due a message: some 30 a second.
Definition LooperNode.hpp:358
Definition LooperView.hpp:1331
Definition Switches.hpp:420
Definition Switches.hpp:390
Definition Switches.hpp:415
Definition Switches.hpp:372
int total
Passes kept, the ones past count being what redo brings back.
Definition PassStack.hpp:92
int64_t length
Frames in the loop.
Definition PassStack.hpp:94
int count
Passes heard.
Definition PassStack.hpp:90
std::array< Pass, max_passes+1 > layers
The passes heard, then the ones redo brings back.
Definition PassStack.hpp:88
static int64_t period_in(const audio_layer &l, int64_t loop_length) noexcept
The length a pass repeats with in a loop of loop_length frames.
Definition PassStack.hpp:209
Definition Switches.hpp:380
Definition Switches.hpp:358
Definition Switches.hpp:407
The grid a change of mode waits for. The Quantif of older scores.
Definition Switches.hpp:232
Definition Switches.hpp:318
Definition Switches.hpp:363
Definition Switches.hpp:398
Definition Switches.hpp:448
Definition Switches.hpp:439
Definition score-plugin-fx/Fx/Looper/Transport.hpp:166
Definition Switches.hpp:850
Definition Switches.hpp:194
Definition Switches.hpp:329
Definition Switches.hpp:385
Definition Switches.hpp:778
int seen_passes
Passes when Layer was last made to follow them.
Definition Switches.hpp:558
Definition TakeWriter.hpp:219
static std::shared_ptr< take_writer > make(const score::DocumentContext &ctx, std::string_view prefix, std::string_view extension)
Main thread only.
Definition TakeWriter.hpp:70
void taking(LoopMode m) noexcept
Called by the looper whenever it records or overdubs.
Definition score-plugin-fx/Fx/Looper/Transport.hpp:336
void end_recording(AfterRecord after) noexcept
Definition score-plugin-fx/Fx/Looper/Transport.hpp:350
void play_captured(int64_t position) noexcept
Definition score-plugin-fx/Fx/Looper/Transport.hpp:464
Definition LooperView.hpp:77
Definition MIDISync.hpp:149
Definition DocumentContext.hpp:18