2#include <Fx/Looper/Transport.hpp>
64template <
typename Store,
typename Pass,
int MaxLayers>
73 std::array<Pass, max_passes + 1>
layers{};
110 merge_log merged_passes;
112 bool empty() const noexcept {
return count == 0 ||
length == 0; }
117 static int64_t
period_in(
const Pass& l, int64_t loop_length)
noexcept
119 return l.period > 0 ? l.period : loop_length;
121 int64_t period_of(
const Pass& l)
const noexcept {
return period_in(l,
length); }
127 const int64_t p = std::max(period_of(a), period_of(b));
128 return p ==
length ? 0 : p;
135 bool extend(int64_t unit, int64_t max_length,
bool top_open =
true) noexcept
137 if(
count == 0 || unit <= 0 || length + unit > max_length)
139 for(
int i = 0; i <
count - (top_open ? 1 : 0); i++)
154 self().passes_changed();
158 void clear() noexcept
160 unmerge.valid =
false;
166 self().passes_changed();
190 self().passes_changed();
198 const bool keep_aside = aside.valid && !aside.
returned;
199 self().redo_dropped(keep_aside);
204 self().passes_changed();
214 self().aside_forgotten();
220 if(std::exchange(unmerge.valid,
false))
221 self().unmerge_dropped();
228 if(k < 0 || k >=
count ||
count < 2 || !self().may_remove(k))
255 const int k = aside.at;
261 self().aside_returned(k);
262 for(
int i =
total; i > k; i--)
268 self().passes_changed();
277 if(unmerge.valid && unmerge.at ==
count - 1)
280 const int at = unmerge.at;
281 unmerge.valid =
false;
284 layers[at + 1] = unmerge.b;
286 length = unmerge.b.loop_before;
288 self().passes_changed();
302 self().passes_changed();
315 const int by = aside.
by;
322 self().passes_changed();
331 if(k < 0 || k >=
count ||
count < 2 || !self().may_remove(k))
338 self().passes_changed();
354 void merged(
int at,
const Pass&
merged,
bool undoable,
const Pass& a,
const Pass& b)
noexcept
357 unmerge =
unmerge_state{.valid =
true, .at = at, .a = a, .b = b};
359 for(
int i = at + 1; i + 1 <
count; i++)
363 merged_passes.add(at);
364 self().passes_changed();
374 m.loop_after = b.loop_after;
375 m.muted = a.muted && b.muted;
383 bool replaced(uint64_t by,
int self_pass,
bool taking)
const noexcept
385 for(uint64_t m = by; m != 0; m &= m - 1)
387 const int q = std::countr_zero(m);
397 Store& self() noexcept {
return static_cast<Store&
>(*this); }
399 void shift_down(
int k)
noexcept
401 for(
int i = k; i + 1 <
total; i++)
407 void move_aside(
int k)
noexcept
414 self().aside_taken(k);
416 self().passes_changed();
424 const uint64_t low = m & ((uint64_t(1) << k) - 1);
425 return low | ((m >> (k + 1)) << k);
432 const uint64_t low = m & ((uint64_t(1) << k) - 1);
433 return low | ((m >> k) << (k + 1));
454template <
int MaxPasses>
457 static constexpr int aside_pass = MaxPasses;
458 static constexpr int lost_pass = MaxPasses + 1;
459 static_assert(lost_pass < 64);
460 static constexpr uint64_t bit(
int k)
noexcept {
return uint64_t(1) << k; }
462 template <
typename T>
463 static void erase(T& e,
int k)
noexcept
470 template <
typename T>
471 static void set_aside(T& e,
int k)
noexcept
473 const bool by_k = e.replaced_by & bit(k);
476 e.replaced_by |= bit(aside_pass);
478 e.pass = uint8_t(aside_pass);
483 template <
typename T>
484 static void put_back(T& e,
int k)
noexcept
486 const bool by_aside = e.replaced_by & bit(aside_pass);
487 e.replaced_by =
with_room_at(e.replaced_by & ~bit(aside_pass), k);
489 e.replaced_by |= bit(k);
490 if(e.pass == aside_pass)
500 template <
typename T>
501 static void merge(T& e,
int a,
bool lost_a,
bool lost_b)
noexcept
504 const bool had_a = e.replaced_by & bit(a);
505 const bool had_b = e.replaced_by & bit(b);
509 uint64_t r = e.replaced_by & ~(bit(a) | bit(b));
510 if((had_a && !lost_a) || (had_b && !lost_b))
513 if((e.pass == a && lost_a) || (e.pass == b && lost_b))
514 e.pass = uint8_t(lost_pass);
515 else if(e.pass >= b && e.pass < aside_pass)
520 template <
typename T>
530 if(e.pass == lost_pass || (e.merged &
from_upper))
531 e.pass = uint8_t((e.merged &
from_upper) ? b : a);
547template <
typename Store,
typename Pass,
int MaxLayers>
559 int64_t pass_start{};
560 int64_t pass_written{};
570 void passes_changed() noexcept {
edits++; }
571 bool may_remove(
int k)
const noexcept {
return !(taking && k == this->
count - 1); }
572 void muting(
int)
noexcept { }
573 void removing(
int)
noexcept { }
574 void erased(
int k)
noexcept
576 store().remove_material([k](
const auto& e) {
return e.pass == k; });
577 store().for_each_material([k](
auto& e) { tags::erase(e, k); });
579 void aside_taken(
int k)
noexcept
581 store().for_each_material([k](
auto& e) { tags::set_aside(e, k); });
583 void aside_returned(
int k)
noexcept
585 store().for_each_material([k](
auto& e) { tags::put_back(e, k); });
587 void aside_forgotten() noexcept
589 store().remove_material([](
const auto& e) {
return e.pass ==
aside_pass; });
590 store().for_each_material([](
auto& e) { e.replaced_by &= ~tags::bit(
aside_pass); });
592 void redo_dropped(
bool keep_aside)
noexcept
594 const int heard_passes = this->
count;
595 store().remove_material([heard_passes, keep_aside](
const auto& e) {
596 return e.pass >= heard_passes && !(keep_aside && e.pass ==
aside_pass);
599 = this->
count >= 64 ? ~uint64_t(0) : (uint64_t(1) << this->
count) - 1;
602 store().for_each_material([kept](
auto& e) { e.replaced_by &= kept; });
604 void unmerge_dropped() noexcept
606 store().remove_material([](
const auto& e) {
return e.pass == tags::lost_pass; });
608 void unmerged(
int at)
noexcept
610 store().for_each_material([at](
auto& e) {
tags::unmerge(e, at); });
612 void cleared() noexcept
615 store().clear_material();
617 void undoing() noexcept { }
624 if(pass_written >= this->
length)
626 int64_t d = k - pass_start;
629 return d < pass_written;
639 void begin_recording() noexcept
651 int replace = -1) noexcept
660 while(this->
count >= max)
666 while(this->
count > max)
670 begin_pass_state(start);
677 void merge(
int at,
bool undoable =
false) noexcept
679 const int a = at, b = at + 1;
680 if(a < 0 || b >= this->
count)
683 const Pass was_a = this->
layers[a], was_b = this->
layers[b];
684 const bool lost_a = was_a.muted && !was_b.muted;
685 const bool lost_b = was_b.muted && !was_a.muted;
686 store().for_each_material([=](
auto& e) {
tags::merge(e, a, lost_a, lost_b); });
690 void begin_pass_state(int64_t start)
noexcept
697 store().pass_state_begun();
705 const auto written = int64_t(std::floor(
pass_progress + 1e-6));
706 if(backwards && this->
length > 0)
708 pass_start = (pass_start - (written - pass_written)) % this->
length;
710 pass_start += this->
length;
713 pass_written = written;
720 this->
count = o.count;
721 this->
total = o.total;
724 this->unmerge = o.unmerge;
725 this->aside = o.aside;
727 pass_start = o.pass_start;
728 pass_written = o.pass_written;
736 int64_t
distance(int64_t from, int64_t to)
const noexcept
739 return std::max<int64_t>(1, to - from);
740 int64_t d = (to - from) % this->
length;
747 Store& store() noexcept {
return static_cast<Store&
>(*this); }
Definition AudioLayers.hpp:14
merge_mark
Definition PassStack.hpp:439
@ replaced_by_upper
The upper pass replaced it.
Definition PassStack.hpp:442
@ from_upper
It is of the upper pass.
Definition PassStack.hpp:440
@ replaced_by_lower
The lower pass replaced it.
Definition PassStack.hpp:441
constexpr uint64_t with_room_at(uint64_t m, int k) noexcept
Definition PassStack.hpp:430
constexpr uint64_t without_pass(uint64_t m, int k) noexcept
Definition PassStack.hpp:422
Definition PassStack.hpp:99
bool returned
Definition PassStack.hpp:103
int by
The pass that replaced it.
Definition PassStack.hpp:106
Definition PassStack.hpp:88
Definition PassStack.hpp:66
bool set_muted(int k, bool m) noexcept
Mutes or unmutes pass k, k being heard.
Definition PassStack.hpp:147
int total
Passes kept, the ones past count being what redo brings back.
Definition PassStack.hpp:77
static constexpr int max_layers
Most layers kept: Max layers is at most this.
Definition PassStack.hpp:68
void drop_unmerge() noexcept
Undo is not to take the last merge apart: what it kept for that goes.
Definition PassStack.hpp:218
void forget_aside() noexcept
Forgets the layer set aside.
Definition PassStack.hpp:208
int64_t length
Frames in the loop.
Definition PassStack.hpp:79
Pass & push_pass() noexcept
Adds a pass over the ones heard, room having been made for it.
Definition PassStack.hpp:180
int64_t merged_period(const Pass &a, const Pass &b) const noexcept
The period two passes merged into one repeat with.
Definition PassStack.hpp:125
int count
Passes heard.
Definition PassStack.hpp:75
int leaves_on_redo() const noexcept
Definition PassStack.hpp:245
void merged(int at, const Pass &merged, bool undoable, const Pass &a, const Pass &b) noexcept
Definition PassStack.hpp:354
bool extend(int64_t unit, int64_t max_length, bool top_open=true) noexcept
Definition PassStack.hpp:135
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
bool erase(int k) noexcept
Definition PassStack.hpp:329
static int64_t period_in(const Pass &l, int64_t loop_length) noexcept
The length a pass repeats with in a loop of loop_length frames.
Definition PassStack.hpp:117
Pass merged_pass(const Pass &a, const Pass &b) const noexcept
Definition PassStack.hpp:370
int returns_on_undo() const noexcept
Undoing the top pass puts back the layer it replaced: where it goes.
Definition PassStack.hpp:237
void begin_merge() noexcept
A merge is about to be worked out: what it would make stale goes.
Definition PassStack.hpp:343
void drop_redo() noexcept
Definition PassStack.hpp:196
uint64_t pushes
Definition PassStack.hpp:82
Pass & begin_first_pass() noexcept
Forgets every pass for a recording: its pass, the first one.
Definition PassStack.hpp:170
void put_back() noexcept
Definition PassStack.hpp:253
void set_aside(int k) noexcept
Definition PassStack.hpp:226
static constexpr int max_passes
A pass past Max layers is one more until it is merged.
Definition PassStack.hpp:70
Definition PassStack.hpp:456
static void merge(T &e, int a, bool lost_a, bool lost_b) noexcept
Definition PassStack.hpp:501
static void unmerge(T &e, int a) noexcept
The merge of a and a + 1 is undone.
Definition PassStack.hpp:521
Definition PassStack.hpp:549
void merge(int at, bool undoable=false) noexcept
Definition PassStack.hpp:677
void assign_passes(const tagged_pass_stack &o) noexcept
Definition PassStack.hpp:718
void advance_pass(double frames, bool backwards=false) noexcept
Definition PassStack.hpp:702
void begin_overdub(int64_t start, int max=stack::max_layers, bool oldest=true, int replace=-1) noexcept
Definition PassStack.hpp:649
uint64_t edits
Changes each time what is heard of the loop may have changed.
Definition PassStack.hpp:556
bool pass_backwards
Definition PassStack.hpp:566
double pass_progress
Definition PassStack.hpp:563
static constexpr int aside_pass
Where the material of a pass set aside is, past every pass there can be.
Definition PassStack.hpp:553
int64_t distance(int64_t from, int64_t to) const noexcept
Definition PassStack.hpp:736
bool replacing() const noexcept
Definition PassStack.hpp:634
bool in_pass(int64_t k) const noexcept
Position k is in what the pass being taken in went over.
Definition PassStack.hpp:620
What a loop whose material is kept apart keeps of a pass besides it.
Definition PassStack.hpp:15
bool muted
Definition PassStack.hpp:24
int64_t period
Definition PassStack.hpp:18
int64_t loop_before
Length of the loop before and after the pass, for undo and redo.
Definition PassStack.hpp:20