2#include <Fx/Looper/AudioLayers.hpp>
3#include <Fx/Looper/LooperNode.hpp>
6#include <ossia/dataflow/exec_state_facade.hpp>
7#include <ossia/dataflow/nodes/sound.hpp>
8#include <ossia/dataflow/token_request.hpp>
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>
22inline ossia::audio_stretch_mode stretch_mode(
FollowTempo f)
noexcept
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:
36 return ossia::audio_stretch_mode::None;
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:
55 return halp::clip_stretch::none;
60namespace Nodes::AudioLooper
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")
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);
78 static constexpr std::array<int, 1>
removed_inlets() noexcept {
return {16}; }
80 using LoopMode = Looper::LoopMode;
85 halp::dynamic_audio_bus<
"in",
double> audio;
87 struct : halp::enum_t<LoopMode,
"Mode">
89 using halp::enum_t<LoopMode,
"Mode">::operator=;
90 static constexpr std::string_view former_name()
noexcept {
return "Loop"; }
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(); }
108 using enum_combobox::operator=;
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.")
117 struct : halp::spinbox_i32<
"Record bars", halp::irange{0, 64, 4}>
119 static constexpr std::string_view former_name()
noexcept {
return "Bars"; }
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.")
129 struct : halp::impulse_button<
"Undo">
133 "Undoes the last pass, erase or mute. Undoing the first recording "
136 struct : halp::impulse_button<
"Redo">
138 halp_meta(description,
"Redoes what Undo took back")
140 struct : halp::impulse_button<
"Clear">
142 halp_meta(description,
"Empties the loop and forgets every pass")
145 struct : halp::knob_f32<
"Feedback", halp::range{0., 1., 1.}>
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.")
153 struct : halp::spinbox_i32<
"Late stop (ms)", halp::irange{0, 500, 120}>
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.")
161 struct : halp::spinbox_i32<
"Latency (ms)", halp::irange{0, 500, 0}>
165 "How late the input reaches the looper: what was recorded is moved "
166 "this much earlier in the loop.")
169 struct : halp::spinbox_i32<
"Max length (s)", halp::irange{1, 3600, 60}>
173 "Longest loop. The memory is reserved when playback starts, so a "
174 "change applies from the next start.")
177 struct : halp::spinbox_i32<
"Max layers", halp::irange{2, 32, 8}>
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.")
185 struct : halp::spinbox_i32<
"Channels", halp::irange{1, 16, 2}>
189 "Channels recorded; the input's other channels are not. Applies from "
193 struct : halp::spinbox_i32<
"Keep last (s)", halp::irange{0, 600, 0}>
197 "Seconds of input kept at all times, for Capture. Zero keeps none. "
198 "Applies from the next start.")
201 struct : halp::spinbox_i32<
"Capture bars", halp::irange{1, 64, 4}>
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.")
209 struct : halp::impulse_button<
"Capture">
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. "
223 struct : halp::toggle<
"Engine latency">
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 "
233 struct : halp::soundfile_port<
"Loop file">
237 "A sound file to loop: dropping one on the looper replaces the loop "
238 "with it, up to Max length.")
243 using enum_combobox::operator=;
244 static constexpr std::string_view former_name()
noexcept {
return "Takes"; }
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.")
257 using enum_combobox::operator=;
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.")
268 using enum_combobox::operator=;
271 std::string_view values[5]
272 = {
"Off",
"Repitch",
"Repitch fast",
"Timestretch",
"Timestretch percussive"};
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.")
286 struct : halp::spinbox_i32<
"Layer", halp::irange{1, 32, 1}>
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 "
295 std::function<void(
int)> update_controller;
298 struct : halp::toggle<
"Reverse">
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;
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;
322 using enum_combobox::operator=;
325 std::string_view values[2] = {
"Whole",
"Per cycle"};
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.")
362 halp::mimic_audio_bus<
"out", &ins::audio> audio;
363 struct : halp::val_port<
"Phase",
float>
365 halp_meta(description,
"Position in the loop, from 0 to 1")
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);
384 std::function<void(Looper::view_message)> send_message;
393 ossia::exec_state_facade ossia_state;
396 std::shared_ptr<Looper::take_writer> writer;
397 std::shared_ptr<Looper::export_buffer> export_audio;
406 stop_take = std::make_shared<Looper::audio_stop_take>();
409 void prepare(halp::setup s)
411 const double rate = s.rate > 0 ? s.rate : 48000.;
413 inputs.channels.value, inputs.max_layers.value,
414 int64_t(inputs.max_seconds.value * rate));
416 && (export_audio->channels != layers.channels
417 || export_audio->capacity != layers.capacity))
419 allocate_ring(layers.channels, int64_t(inputs.keep.value * rate));
422 if(ossia_document_context)
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;
446 if(m_stretch_mode != ossia::audio_stretch_mode::None)
448 struct silence_source
450 void fetch_audio(int64_t, int64_t n,
float** out)
const noexcept
452 for(std::size_t c = 0; c < chans; c++)
453 std::fill_n(out[c], n, 0.f);
455 void fetch_audio(int64_t, int64_t n,
double** out)
const noexcept
457 for(std::size_t c = 0; c < chans; c++)
458 std::fill_n(out[c], n, 0.);
460 void fetch_audio_backward(int64_t s, int64_t n,
float** out)
const noexcept
462 fetch_audio(s, n, out);
464 void fetch_audio_backward(int64_t s, int64_t n,
double** out)
const noexcept
466 fetch_audio(s, n, out);
470 ossia::token_request tk;
471 tk.prev_date = ossia::time_value{0};
472 tk.date = ossia::time_value{int64_t(longest)};
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.);
485 if(channels == m_ring_channels && frames == m_ring_capacity)
488 m_ring.shrink_to_fit();
489 m_ring_channels = channels;
490 m_ring_capacity = std::max<int64_t>(0, frames);
492 std::size_t(m_ring_channels) * std::size_t(m_ring_capacity),
493 boost::container::default_init);
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)
503 const int64_t end = std::max<int64_t>(0, layers.
length - frames);
504 m_carried_span += layers.
length - end;
506 if(
auto* l = layers.top())
507 l->written = layers.
length;
510 void operator()(
const tick& tk)
512 if(tk.date == tk.prev_date)
515 send_view(ossia_state.timings(tk).length);
523 halp_meta(layout, halp::layouts::hbox)
524 halp_meta(background, halp::colors::background_dark)
527 halp_meta(layout, halp::layouts::vbox)
530 halp_meta(layout, halp::layouts::vbox)
534 halp_meta(layout, halp::layouts::hbox)
535 halp::item<&ins::quantif> quantif;
536 halp::item<&ins::exported> exported;
541 halp_meta(name,
"Settings")
542 halp_meta(layout, halp::layouts::tabs)
543 halp_meta(background, halp::colors::background_darker)
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;
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;
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;
593 halp_meta(layout, halp::layouts::container)
594 halp_meta(background, halp::colors::background_mid)
609 self.view.view.receive(msg);
616 const float* layer_data(
int layer,
int chan)
const noexcept
618 return layers.data(layers.
layers[layer].slot, chan);
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
640 void pass_dropped() noexcept { }
641 void begin_overdub(int64_t start,
bool oldest,
int replaced)
644 m_pass_closed =
false;
647 m_pass_in_place =
false;
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); }
659 auto& top = *layers.top();
671 if(m_head_from >= 0 && !m_lapped)
672 layers.
open_seam(top,
false, m_head_from);
676 m_tail_open = top.slot;
680 void tick_started(
const tick& tk)
682 m_in_chans = std::min<int>(inputs.audio.channels, layers.channels);
684 m_write_shift = std::llround(
double(latency_frames()) *
m_speed);
686 void prepare_loop() { load_file(); }
687 void forget_carried() noexcept { m_carried_span = 0; }
688 void tick_finished(
const tick& tk)
690 keep_input(ossia_state.timings(tk).length);
695 void close_recording(int64_t bars);
701 bool cut_after(int64_t end)
const noexcept
703 return layers.
layers[layers.
count - 1].start >= end;
705 void cut_pass_dropped() noexcept { m_pass_closed =
true; }
706 void trim_top_pass(int64_t end)
noexcept
708 auto& top = *layers.top();
709 top.
written = std::clamp<int64_t>(end - top.start, 0, top.written);
711 void head_moved(int64_t)
noexcept { }
714 double rate_for(LoopMode m)
const noexcept
716 return by_quarters() && m != LoopMode::Overdub
720 bool by_quarters() const noexcept
722 return m_stretch_mode != ossia::audio_stretch_mode::None &&
m_loop_tempo > 0.;
724 void set_head(
double y, int64_t len)
noexcept
727 m_stretch_ready =
false;
729 int64_t capture_clock() const noexcept {
return m_ring_written; }
730 int64_t capture_limit() const noexcept
732 return m_ring_capacity > 0 ? std::min(m_ring_capacity, layers.capacity) : 0;
734 void capture_into(int64_t end, int64_t n);
735 void captured() noexcept { }
738 bool capture_layer_ready(
const Looper::capture_window&)
noexcept
740 if(m_ring_capacity <= 0)
745 void capture_layer_into(
const Looper::capture_window& w);
746 void stopping() noexcept { }
747 void close_on_stop(
bool recording)
752 bool export_ready() const noexcept
754 return !m_flattening && !export_audio->in_use && export_audio->capacity >= layers.
length
755 && export_audio->channels >= layers.channels;
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
770 bool view_full() const noexcept {
return m_full; }
771 bool view_writing() const noexcept {
return m_flattening || m_writing; }
775 Looper::transport::timeline_point m_tick_start{};
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;
793 ossia::resampler m_stretcher;
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;
802 double m_cycle_ratio{1.};
803 bool m_stretch_ready{};
804 int64_t m_expected_pos{};
807 double m_stretch_speed{1.};
808 bool m_stretch_reverse{};
809 void play_stretched(int64_t first_pos, int64_t samples);
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{};
824 int64_t m_pass_frames{};
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
845 const int64_t w = (k - (m_reverse ? -m_write_shift : m_write_shift)) % len;
846 return w < 0 ? w + len : w;
851 int64_t m_fresh_k{-1};
852 std::array<float, Looper::audio_layers::max_channels> m_fresh_delta{};
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{};
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
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;
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{};
886 template <
typename T>
889 const int64_t len = layers.
length;
890 if(len > 0 && (m_stretch_speed != 1. || m_stretch_reverse))
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)))
902 for(
int c = 0; c < layers.channels; c++)
904 int64_t k = len > 0 ? start % len : 0;
905 for(int64_t j = 0; j < frames; j++)
907 out[c][j] = len > 0 ? T(layers.
mix(c, k)) : T(0);
916 template <
typename T>
917 void fetch_audio_backward(int64_t, int64_t frames, T** out)
noexcept
919 for(
int c = 0; c < layers.channels; c++)
920 std::fill_n(out[c], frames, T(0));
926 std::array<float, Looper::view_message::max_lanes * Looper::view_message::bins>
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);
938 const float** m_file_data{};
939 int64_t m_file_frames{};
940 int64_t m_file_pos{};
941 int64_t m_file_target{};
943 void keep_input(int64_t frames);
944 void fade_edges(
int slot,
bool end =
true);
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);
957 const Looper::audio_layer* passes,
int count,
int item, int64_t len, int64_t from,
959 void copy_open_pass();
960 void write_stop_take(
bool recording,
double date, int64_t pos);
966 int64_t m_copy_pos{};
967 int64_t m_copy_left{};
968 int64_t m_copy_period{};
970 void send_view(int64_t frames);
971 void fill_message(Looper::view_message& v);
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);
982inline int64_t Node::looper_run(int64_t start, int64_t length)
984 const int64_t done = run_mode(start, length);
986 layers.
now = m_clock;
990inline int64_t Node::run_mode(int64_t start, int64_t length)
992 layers.
now = m_clock;
995 if(m_tail_open >= 0 && transport.actualMode != LoopMode::Overdub)
999 if(transport.actualMode != LoopMode::Play)
1000 m_stretch_ready =
false;
1001 if(transport.playbackPos != m_head_pos)
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)
1011 case LoopMode::Play:
1013 echo_otherwise ? through(start, length) : silence(start, length);
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);
1021 play(start, length);
1023 mix_input(start, length);
1026 case LoopMode::Stop:
1027 echo_otherwise ? through(start, length) : silence(start, length);
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);
1040inline void Node::close_recording(int64_t bars)
1042 auto* top = layers.top();
1043 if(!top || layers.
length <= 0)
1049 m_seamless = transport.actualMode == LoopMode::Overdub;
1050 fade_edges(top->slot, !m_seamless);
1052 top->written = layers.
length;
1053 if(
const int64_t latency = latency_frames(); latency > 0)
1059 m_tail_open = top->slot;
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);
1069 top->written = layers.
length;
1072inline int64_t Node::latency_frames() const noexcept
1074 return int64_t(inputs.latency.value * m_rate / 1000.)
1075 + (inputs.engine_latency.value
1076 ? int64_t(ossia_state.inputLatency()) + ossia_state.outputLatency()
1083inline void Node::shift_pass(Looper::audio_layer& l)
1085 const int64_t latency = latency_frames();
1088 const int64_t positions = std::llround(
double(latency) *
m_speed);
1089 layers.
shift_earlier(l, l.backwards ? -positions : positions);
1094inline void Node::cancel_export() noexcept
1096 m_flattening =
false;
1099 m_export_cancelled =
true;
1105inline bool Node::continue_seam()
1107 const int from = std::exchange(m_tail_open, -1);
1108 auto* top = layers.top();
1109 if(from < 0 || !top)
1111 const int s = layers.
resolve(from);
1116 l.tail.partner = top->slot;
1117 l.tail.meet = top->start;
1129inline void Node::fade_out_written()
1131 auto* top = layers.top();
1134 const int n = m_last_n;
1135 for(
int i = 0; i < n; i++)
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;
1146inline void Node::end_open_tail()
1149 const int from = std::exchange(m_tail_open, -1);
1152 const int s = layers.
resolve(from);
1155 l.tail.partner = -1;
1161inline void Node::fade_edges(
int slot,
bool end)
1163 for(
int c = 0; c < layers.channels; c++)
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));
1170 float f = 1.f / min_n;
1172 for(int64_t i = 0; i < min_n; i++)
1179 for(int64_t i = samples - min_n; i < samples; i++)
1188inline void Node::keep_input(int64_t frames)
1190 if(m_ring_capacity > 0)
1192 auto& in = inputs.audio;
1193 for(
int c = 0; c < m_ring_channels; c++)
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++)
1199 ring[k] = c < in.channels ? float(in.samples[c][j]) : 0.f;
1200 if(++k == m_ring_capacity)
1205 m_ring_written += frames;
1209inline void Node::capture_into(int64_t end, int64_t n)
1214 const int slot = layers.
layers[0].slot;
1215 for(
int c = 0; c < layers.channels; c++)
1217 float* dst = layers.data(slot, c);
1218 if(c >= m_ring_channels)
1220 std::fill_n(dst, n, 0.f);
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++)
1226 const float v = ring[(end - n + i) % m_ring_capacity];
1228 layers.note_peak(slot, i, v);
1232 layers.
layers[0].written = n;
1242inline void Node::capture_layer_into(
const Looper::capture_window& w)
1246 auto* top = layers.top();
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)
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];
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));
1265 for(int64_t i = 0; i < positions; i++)
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++)
1274 const float v = input(c, t) * ramp;
1275 layers.data(top->slot, c)[k] = v;
1276 layers.note_peak(top->slot, k, v);
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));
1289inline void Node::load_file()
1291 const auto& f = inputs.file.soundfile;
1292 if(f.data != m_file_data || f.frames != m_file_frames)
1294 m_file_data = f.data;
1295 m_file_frames = f.frames;
1298 if(!inputs.file || transport.is_taking())
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)
1308 m_switches.soloed.forget();
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++)
1324 float* dst = layers.data(slot, c);
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++)
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);
1335 layers.note_peak(slot, k, v);
1339 if(m_file_pos < m_file_target)
1344 layers.
length = m_file_target;
1345 layers.
layers[0].written = m_file_target;
1355inline void Node::play_stretched(int64_t first_pos, int64_t samples)
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]))
1362 play(first_pos, samples);
1365 if(!m_stretch_ready || transport.playbackPos % len != m_expected_pos
1366 || m_stretch_speed !=
m_speed || m_stretch_reverse != m_reverse)
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);
1376 m_stretch_ready =
true;
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));
1382 ossia::token_request tk;
1383 tk.prev_date = ossia::time_value{0};
1384 tk.date = ossia::time_value{samples};
1387 const double ratio = m_stretcher.stretch() ? m_cycle_ratio : 1.;
1389 *
this, tk, ossia_state, m_cycle_ratio, 1., std::size_t(chans), len, samples,
1390 samples, 0, m_stretch_span);
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.;
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)
1410 transport.playbackPos = int64_t(m_heard) % len;
1412 m_head_pos = transport.playbackPos;
1416 set_head_y(std::fmod(m_heard * m_stretch_speed,
double(len)), len);
1418 m_expected_pos = transport.playbackPos;
1423inline double Node::head_y(int64_t len)
const noexcept
1425 const double h = double(transport.playbackPos % len) + m_frac;
1426 double y = m_reverse ? double(len) - h : h;
1427 if(y >=
double(len))
1434inline void Node::set_head_y(
double y, int64_t len)
noexcept
1436 double h = m_reverse ? double(len) - y : y;
1437 h = std::fmod(h,
double(len));
1440 const double whole = std::floor(h);
1441 transport.playbackPos = int64_t(whole) % len;
1444 if(m_frac >= 1. - 1e-9)
1446 transport.playbackPos = (transport.playbackPos + 1) % len;
1449 m_head_pos = transport.playbackPos;
1455inline float Node::read_span(
int c,
double y,
double s, int64_t len)
const noexcept
1459 const int n = int(std::lround(s));
1460 const auto k0 = int64_t(y);
1462 for(
int i = 0; i < n; i++)
1463 sum += tape(c, (k0 + i) % len, len);
1464 return sum / float(n);
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;
1472 const float a = tape(c, k, len);
1475 return a + float(f) * (tape(c, (k + 1) % len, len) - a);
1479inline void Node::play_tape(int64_t first_pos, int64_t samples)
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;
1487 double y = head_y(len);
1492 for(int64_t j = first_pos; j < last; j++)
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);
1498 while(y >=
double(len))
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.;
1508inline void Node::play(int64_t first_pos, int64_t samples)
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;
1517 for(
int i = 0; i < loop_chans; i++)
1519 auto& out = p2.samples[i];
1523 for(int64_t j = first_pos; j < last; j++)
1525 layers.
now = m_clock + (j - first_pos);
1526 out[j] = layers.
mix(i, k);
1533 for(
int i = loop_chans; i < out_chans; i++)
1535 auto& out = p2.samples[i];
1536 for(int64_t j = first_pos; j < last; j++)
1541 transport.playbackPos = (start + samples) % len;
1546inline void Node::silence(int64_t first_pos, int64_t samples)
1548 auto& p2 = outputs.audio;
1549 const int64_t last = first_pos + samples;
1550 for(
int i = 0; i < p2.channels; i++)
1552 auto& out = p2.samples[i];
1553 for(int64_t j = first_pos; j < last; j++)
1558inline void Node::mix_input(int64_t first_pos, int64_t samples)
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++)
1566 auto& in = p1.samples[i];
1567 auto& out = p2.samples[i];
1568 for(int64_t j = first_pos; j < last; j++)
1573inline void Node::through(int64_t first_pos, int64_t samples)
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++)
1581 auto& in = p1.samples[i];
1582 auto& out = p2.samples[i];
1583 for(int64_t j = first_pos; j < last; j++)
1586 for(
int i = chans; i < p2.channels; i++)
1588 auto& out = p2.samples[i];
1589 for(int64_t j = first_pos; j < last; j++)
1594inline int64_t Node::record(int64_t first_pos, int64_t samples,
bool echo)
1596 auto& p1 = inputs.audio;
1597 if(!transport.is_taking())
1604 m_switches.soloed.forget();
1606 transport.playbackPos = 0;
1607 m_export_pending =
false;
1611 transport.
taking(LoopMode::Record);
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);
1619 for(
int c = 0; c < layers.channels; c++)
1621 float* dst = layers.data(base.slot, c) + pos;
1624 auto& in = p1.samples[c];
1625 for(int64_t j = 0; j < n; j++)
1627 const float v = float(in[first_pos + j]);
1629 layers.note_peak(base.slot, pos + j, v);
1634 std::fill_n(dst, n, 0.f);
1638 base.written = layers.
length;
1639 transport.playbackPos = layers.
length;
1641 echo ? through(first_pos, n) : silence(first_pos, n);
1649 transport.playbackPos = 0;
1657inline void Node::write_tape(int64_t y,
const float* v,
float feedback)
1667 begin_pass(written_at(m_reverse ? layers.
length - 1 - y : y, layers.length));
1668 m_pass_in_place =
true;
1672 m_pass_frames = continue_seam() ? Looper::audio_layers::fade_frames : 0;
1674 auto* t = layers.top();
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;
1683 = m_pass_frames < fade ? float(m_pass_frames) / fade : 1.f;
1686 for(
int c = 0; c < layers.channels; c++)
1688 float& d = layers.data(top.slot, c)[k];
1689 const float before = first_time ? 0.f : d;
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;
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;
1709inline bool Node::cycle_end(int64_t& len,
bool extend,
float feedback)
1725 int64_t(std::ceil(
double(Looper::audio_layers::fade_frames) / std::max(1e-3,
m_speed))));
1735inline void Node::begin_pass_carried(int64_t len)
1737 const int64_t span = m_carried_span;
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;
1749 begin_pass(written_at(carried ? 0 : k, len));
1750 m_pass_in_place =
true;
1755 auto* top = layers.top();
1756 if(!carried || !top || layers.
count != 2)
1758 const auto& base = layers.
layers[0];
1759 for(int64_t i = 0; i < span; i++)
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++)
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);
1769 layers.
cover(*top, at);
1771 m_pass_frames = std::max<int64_t>(m_pass_frames, span);
1774inline void Node::overdub(int64_t first_pos, int64_t samples,
bool echo)
1776 auto& p1 = inputs.audio;
1777 auto& p2 = outputs.audio;
1778 const int64_t last = first_pos + samples;
1783 echo ? through(first_pos, samples) : silence(first_pos, samples);
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;
1793 int64_t len = layers.
length;
1794 if(!transport.is_taking())
1797 begin_pass_carried(len);
1806 for(
int c = 0; c < layers.channels; c++)
1809 m_prev_in[c] = input(c, first_pos);
1812 transport.
taking(LoopMode::Overdub);
1819 const float feedback = std::clamp(inputs.feedback.value, 0.f, 1.f);
1821 double y = head_y(len);
1824 const int steps = s >= 1. ? int(std::lround(s)) : 1;
1825 std::array<float, Looper::audio_layers::max_channels> v{};
1827 for(int64_t j = first_pos; j < last; j++)
1829 layers.
now = m_clock + (j - first_pos);
1830 m_hide_fresh =
true;
1831 for(
int c = 0; c < layers.channels; c++)
1833 const float in = input(c, j);
1834 const float before = read_span(c, y, s, len);
1836 p2.samples[c][j] = echo ? before + in : before;
1838 m_hide_fresh =
false;
1839 for(
int c = layers.channels; c < out_chans; c++)
1840 p2.samples[c][j] = 0.;
1846 auto w = int64_t(y);
1847 for(
int i = 0; i < steps; i++)
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))
1862 for(
int c = 0; c < layers.channels; c++)
1863 m_acc[c] += input(c, j);
1865 const auto k = int64_t(y);
1867 if(y >=
double(k + 1) - 1e-9)
1869 for(
int c = 0; c < layers.channels; c++)
1871 v[c] = m_acc[c] / float(m_acc_n);
1875 write_tape(k, v.data(), feedback);
1876 if(k + 1 == len && cycle_end(len, extend, feedback))
1880 for(
int c = 0; c < layers.channels; c++)
1881 m_prev_in[c] = input(c, j);
1886inline void Node::start_export_item(
int item)
1888 m_export_item = item;
1889 m_flattening =
true;
1895inline void Node::start_export(
int passes,
bool open,
bool recording)
1897 m_export_length = layers.
length;
1898 m_export_channels = layers.channels;
1901 m_export_count = passes;
1902 std::copy_n(layers.
layers.begin(), layers.
count, m_export_snapshot.begin());
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)
1911inline void Node::continue_export()
1918 const int64_t n = std::min(
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++)
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++)
1930 if(q >= m_copy_period)
1933 q = m_copy_period - 1;
1936 m_copy_pos = (m_copy_pos + m_copy_dir * n) % m_copy_period;
1938 m_copy_pos += m_copy_period;
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);
1951 m_export_snapshot.data(), m_export_count, m_export_item, m_export_length,
1952 m_flatten_pos, end);
1953 m_flatten_pos = end;
1955 if(m_flatten_pos < m_export_length)
1958 m_flattening =
false;
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));
1979inline void Node::flatten(
1980 const Looper::audio_layer* passes,
int count,
int item, int64_t len, int64_t from,
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++)
1986 float* dst = export_audio->channel(c);
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)
2008inline void Node::copy_open_pass()
2010 auto& l = m_export_snapshot[m_export_count - 1];
2012 for(
int s = 0; s < layers.buffers() && spare < 0; s++)
2013 if(!layers.slot_used(s) && !layers.is_reserved(s))
2016 if(spare < 0 || period <= 0)
2018 layers.
reserved |= uint64_t(1) << spare;
2019 m_copy_from = l.slot;
2022 m_copy_period = period;
2023 m_copy_left = period;
2024 m_copy_dir = m_reverse ? -1 : 1;
2026 = written_at(transport.playbackPos % std::max<int64_t>(1, m_export_length), std::max<int64_t>(1, m_export_length))
2028 const int64_t behind = std::min<int64_t>(period / 2, 8192);
2029 m_copy_pos = ((head - m_copy_dir * behind) % period + period) % period;
2037inline void Node::write_stop_take(
bool recording,
double date, int64_t)
2040 if(!writer || layers.empty() || s.in_use)
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;
2056 Looper::take_job job;
2057 job.writer = writer;
2059 job.slot = claim_take_slot();
2061 job.channels = layers.channels;
2062 job.frames = layers.
length;
2063 job.rate = int(m_rate);
2065 job.meter_numerator = m_signature.upper;
2066 job.meter_denominator = m_signature.lower;
2068 worker.request(std::move(job));
2071inline void Node::send_view(int64_t frames)
2075 fill_message(m_view);
2076 send_message(m_view);
2081inline void Node::fill_message(Looper::view_message& v)
2084 v.max_seconds = float(layers.capacity / m_rate);
2088 v.lanes = m_view.lanes;
2089 v.peaks = m_view.peaks;
2097inline void Node::scan_peaks(
bool whole)
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)
2106 m_scan_count = count;
2107 m_scan_length = len;
2108 m_scan_changes = layers.
changes;
2111 std::fill(m_scan_peaks.begin(), m_scan_peaks.end(), 0.f);
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)
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;
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);
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++)
2132 const int b = int(m * bins / micro);
2133 dst[b] = std::max(dst[b], p[m % own] * gain);
2135 budget -= end - m_scan_pos;
2137 if(m_scan_pos >= micro)
2144 if(m_scan_layer < count)
2146 m_view.lanes = lanes;
2147 m_view.peaks = m_scan_peaks;
2152 std::fill(m_scan_peaks.begin(), m_scan_peaks.end(), 0.f);
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
An enumeration shown as a combobox: compact where the choices are many.
Definition Switches.hpp:59
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: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
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
The grid a change of mode waits for. The Quantif of older scores.
Definition Switches.hpp:232
Definition score-plugin-fx/Fx/Looper/Transport.hpp:166
Definition Switches.hpp:850
Definition Switches.hpp:194
Definition Switches.hpp:329
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