2#include <Fx/Looper/PassStack.hpp>
4#include <ossia/network/value/value.hpp>
40 m_value = std::move(o.m_value);
45 void set(
const ossia::value& v) { m_value = v; }
46 void set(ossia::value&& v)
noexcept { m_value = std::move(v); }
48 void reset() noexcept { m_value = ossia::value{}; }
50 const ossia::value& get() const noexcept {
return m_value; }
51 bool empty() const noexcept {
return !m_value.valid(); }
52 bool impulse() const noexcept {
return m_value.get_type() == ossia::val_type::IMPULSE; }
56 static bool same(
const ossia::value& a,
const ossia::value& b)
noexcept
58 return a.get_type() == b.get_type() && a == b;
60 bool same(
const ossia::value& o)
const noexcept {
return same(m_value, o); }
61 bool same(
const value_slot& o)
const noexcept {
return same(m_value, o.m_value); }
118 static constexpr int max_events = 8192;
119 static constexpr int max_stretches = 512;
120 static constexpr int max_touched = 16;
122 std::array<value_event, max_events> events{};
123 std::array<value_stretch, max_stretches> stretches{};
141 std::array<touch, max_touched> touches{};
151 void clear_material() noexcept
153 for(
int i = 0; i < event_count; i++)
154 events[i].value.reset();
160 void pass_state_begun() noexcept
167 void begin_recording() noexcept
169 tagged_pass_stack::begin_recording();
172 template <
typename F>
173 void for_each_material(F&& f)
noexcept
175 for(
int i = 0; i < event_count; i++)
177 for(
int i = 0; i < stretch_count; i++)
180 template <
typename F>
181 void remove_material(F&& gone)
noexcept
185 std::remove_if(stretches.begin(), stretches.begin() + stretch_count, gone)
186 - stretches.begin());
187 for(
int i = 0; i < touch_count; i++)
192 template <
typename F>
196 for(
int i = 0; i < event_count; i++)
201 events[out] = std::move(events[i]);
204 for(
int i = out; i < event_count; i++)
205 events[i].value.reset();
206 if(out != event_count)
213 template <
typename T>
214 bool heard(
const T& e,
bool own_mute =
true) const noexcept
216 return e.pass <
count && !
replaced(e.replaced_by, e.pass,
false)
217 && !(own_mute &&
layers[e.pass].muted);
223 if(!taking ||
count == 0)
225 for(
int i = stretch_count - 1; i >= 0; i--)
226 if(stretches[i].key == key && stretches[i].
serial ==
serial
227 && stretches[i].pass ==
count - 1)
232 const touch* touched(uint16_t key)
const noexcept
234 for(
int i = 0; i < touch_count; i++)
235 if(touches[i].key == key)
242 void touch_key(uint16_t key, int64_t pos, int64_t at,
bool backwards)
noexcept
244 if(touched(key) || touch_count >= max_touched || stretch_count >= max_stretches)
246 auto& s = stretches[stretch_count];
252 .pass = uint8_t(
count - 1),
255 touches[touch_count++] =
touch{key, pos, at, backwards, stretch_count};
267 for(
int i = 0; i < touch_count; i++)
269 const auto& t = touches[i];
272 auto& s = stretches[t.stretch];
273 const int64_t span = std::max<int64_t>(0,
length - t.at);
278 void set_stretch(
value_stretch& s,
const touch& t, int64_t span)
noexcept
280 int64_t from = t.backwards ? t.first - span : t.first;
287 if(s.from != from || s.span != span)
300 for(
int i = 0; i < touch_count; i++)
302 const auto& t = touches[i];
305 auto& s = stretches[t.stretch];
306 const int64_t span =
whole ?
length : pass_written - t.at;
307 set_stretch(s, t, std::min(span,
length));
310 remove_material([](
const auto& e) {
311 if constexpr(
requires { e.span; })
323 int64_t pos, int64_t written, uint16_t key,
const ossia::value& v)
noexcept
325 const bool impulse = v.get_type() == ossia::val_type::IMPULSE;
326 const uint8_t pass = uint8_t(
count - 1);
327 for(
int i = event_count - 1; i >= 0; i--)
330 if(e.pass != pass || e.serial !=
serial)
332 if(e.key == key && e.impulse == impulse)
341 if(event_count >= max_events)
347 auto& e = events[event_count++];
365 if(!taking ||
count == 0 || touch_count == 0 || at <
double(
length))
367 const uint8_t pass = uint8_t(
count - 1);
369 return e.pass == pass && e.serial ==
serial && !e.impulse && e.pos >= lo
370 && e.pos < hi && touched(e.key)
371 && double(e.written +
length) <= at + double(e.pos - lo) + 1e-6;
378 for(
int i = 0; i < o.event_count; i++)
379 events[i] = o.events[i];
380 for(
int i = o.event_count; i < event_count; i++)
381 events[i].value.reset();
382 std::copy_n(o.stretches.begin(), o.stretch_count, stretches.begin());
383 event_count = o.event_count;
384 stretch_count = o.stretch_count;
388 touch_count = o.touch_count;
399 int64_t d = (x - s.from) % period;
405 int64_t period_for(
int pass)
const noexcept
407 return std::clamp<int64_t>(period_of(pass), 1, std::max<int64_t>(1,
length));
416 static constexpr int max_refs = 2 * value_loop::max_events;
423 std::array<ref, max_refs> refs{};
425 std::array<int64_t, max_refs> cuts{};
428 static bool in(
int pass,
int first,
int last)
noexcept
430 return first < 0 || (pass >= first && pass <= last);
439 const int64_t len = loop.length;
442 for(
int i = 0; i < loop.event_count; i++)
444 const auto& e = loop.events[i];
445 if(e.key != key || e.impulse || !loop.heard(e, own_mute))
447 const int64_t period = loop.period_for(e.pass);
448 for(int64_t q = e.pos % period; q < len && count < max_refs; q += period)
449 refs[count++] = {q, e.serial, i};
451 std::sort(refs.begin(), refs.begin() + count, [](
const ref& a,
const ref& b) {
452 if(a.serial != b.serial)
453 return a.serial < b.serial;
455 return a.pos < b.pos;
456 return a.event < b.event;
464 const value_loop& loop, uint16_t key, int64_t x,
int first = -1,
465 int last = -1) const noexcept
469 for(
int s = 0; s < loop.stretch_count; s++)
471 const auto& st = loop.stretches[s];
472 if(st.key != key || !in(st.pass, first, last) || !loop.
heard(st, own_mute)
475 if(!any || st.serial > top)
481 auto lo = std::lower_bound(
482 refs.begin(), refs.begin() + count, top,
483 [](
const ref& r, uint32_t s) { return r.serial < s; });
484 auto hi = std::upper_bound(
485 lo, refs.begin() + count, top, [](uint32_t s,
const ref& r) { return s < r.serial; });
488 auto it = std::upper_bound(lo, hi, x, [](int64_t x,
const ref& r) {
return x < r.pos; });
489 return it == lo ? std::prev(hi)->event : std::prev(it)->event;
501 static constexpr int max_points = held_scratch::max_refs;
508 std::array<point, max_points> points{};
516 int at(int64_t x)
const noexcept
520 auto it = std::upper_bound(
521 points.begin(), points.begin() + count, x,
522 [](int64_t x,
const point& p) { return x < p.pos; });
523 const int i = int(it - points.begin()) - 1;
524 return i >= 0 ? i : count - 1;
527 int before(int64_t x)
const noexcept {
return at(x - 1); }
528 int previous(
int i)
const noexcept {
return i > 0 ? i - 1 : count - 1; }
535 int last = -1,
bool own_mute =
true,
bool force =
false) noexcept
542 const int64_t len = loop.
length;
545 scratch.
prepare(loop, key, own_mute);
549 auto& cuts = scratch.cuts;
551 for(
int i = 0; i < scratch.count && c < held_scratch::max_refs; i++)
552 if(held_scratch::in(loop.events[scratch.refs[i].event].pass, first, last))
553 cuts[c++] = scratch.refs[i].pos;
554 for(
int s = 0; s < loop.stretch_count; s++)
556 const auto& st = loop.stretches[s];
557 if(st.key != key || !held_scratch::in(st.pass, first, last)
558 || !loop.
heard(st, own_mute))
560 const int64_t period = loop.period_for(st.pass);
561 if(st.span >= period)
563 for(int64_t base = 0; base < len && c + 2 <= held_scratch::max_refs; base += period)
564 for(
const int64_t q : {base + st.from % period, base + (st.from + st.span) % period})
570 if(c < held_scratch::max_refs)
572 std::sort(cuts.begin(), cuts.begin() + c);
573 c = int(std::unique(cuts.begin(), cuts.begin() + c) - cuts.begin());
575 for(
int i = 0; i < c; i++)
577 const int e = scratch.
value_at(loop, key, cuts[i], first, last);
580 const int prev = points[count - 1].event;
582 || (prev >= 0 && e >= 0 && loop.events[prev].value.same(loop.events[e].value)))
585 points[count++] = {cuts[i], e};
Definition ValueLoop.hpp:26
void reset() noexcept
Lets go of what it holds.
Definition ValueLoop.hpp:48
static bool same(const ossia::value &a, const ossia::value &b) noexcept
Definition ValueLoop.hpp:56
Definition AudioLayers.hpp:14
Definition ValueLoop.hpp:418
Definition ValueLoop.hpp:415
int value_at(const value_loop &loop, uint16_t key, int64_t x, int first=-1, int last=-1) const noexcept
Definition ValueLoop.hpp:463
void prepare(const value_loop &loop, uint16_t key, bool own) noexcept
Definition ValueLoop.hpp:435
Definition ValueLoop.hpp:503
int event
The value of the loop that holds from there, -1 for none.
Definition ValueLoop.hpp:506
Definition ValueLoop.hpp:500
void update(const value_loop &loop, uint16_t key, held_scratch &scratch, int first=-1, int last=-1, bool own_mute=true, bool force=false) noexcept
Definition ValueLoop.hpp:533
int before(int64_t x) const noexcept
The point that holds just before x.
Definition ValueLoop.hpp:527
int at(int64_t x) const noexcept
Definition ValueLoop.hpp:516
uint64_t edits
What it was worked out from.
Definition ValueLoop.hpp:511
int64_t length
Frames in the loop.
Definition PassStack.hpp:79
int count
Passes heard.
Definition PassStack.hpp:75
std::array< Pass, max_passes+1 > layers
The passes heard, then the ones redo brings back.
Definition PassStack.hpp:73
bool replaced(uint64_t by, int self_pass, bool taking) const noexcept
Definition PassStack.hpp:383
Definition PassStack.hpp:549
void assign_passes(const tagged_pass_stack &o) noexcept
Definition PassStack.hpp:718
uint64_t edits
Changes each time what is heard of the loop may have changed.
Definition PassStack.hpp:556
A value of the loop.
Definition ValueLoop.hpp:69
bool impulse
Fired where it is, rather than held until the next one.
Definition ValueLoop.hpp:82
uint64_t replaced_by
The passes that replace it, a bit each.
Definition ValueLoop.hpp:85
int64_t pos
Loop position, in frames.
Definition ValueLoop.hpp:71
uint32_t serial
Definition ValueLoop.hpp:78
int64_t written
Definition ValueLoop.hpp:74
uint16_t key
What the value is of: one value stream for now, so always 0.
Definition ValueLoop.hpp:80
Definition ValueLoop.hpp:134
Definition ValueLoop.hpp:117
void remove_events(F &&gone) noexcept
The values gone says are let go of.
Definition ValueLoop.hpp:193
uint32_t serial
The serial of the pass being taken in.
Definition ValueLoop.hpp:144
value_event * add_value(int64_t pos, int64_t written, uint16_t key, const ossia::value &v) noexcept
Definition ValueLoop.hpp:322
void assign(const value_loop &o)
Copies what another loop holds, without its unused storage.
Definition ValueLoop.hpp:376
void update_open_stretches() noexcept
Definition ValueLoop.hpp:265
bool whole
Definition ValueLoop.hpp:147
void end_pass() noexcept
Definition ValueLoop.hpp:295
uint32_t next_serial
Numbers the passes in the order they are made.
Definition ValueLoop.hpp:128
static bool holds(const value_stretch &s, int64_t x, int64_t period) noexcept
Whether a stretch holds position x, its pass repeating every period.
Definition ValueLoop.hpp:395
bool heard(const T &e, bool own_mute=true) const noexcept
Definition ValueLoop.hpp:214
void touch_key(uint16_t key, int64_t pos, int64_t at, bool backwards) noexcept
Definition ValueLoop.hpp:242
int find_stretch(uint16_t key) const noexcept
The open stretch the pass being taken in holds key over, -1 for none.
Definition ValueLoop.hpp:221
void write_over(int64_t lo, int64_t hi, double at) noexcept
Definition ValueLoop.hpp:363
Definition ValueLoop.hpp:93