2#include <Fx/Looper/PassStack.hpp>
4#include <Advanced/MidiScaler/MidiCommon/Messages.hpp>
57 uint16_t
key() const noexcept
59 const uint8_t kind = status & 0xF0;
60 const bool indexed = kind == 0xB0 || kind == 0xA0;
61 return uint16_t(status << 8 | (indexed ? data1 : 0));
81 static constexpr int max_notes = 4096;
82 static constexpr int max_controls = 8192;
83 static constexpr int max_touched = 64;
85 std::array<midi_note, max_notes> notes{};
86 std::array<midi_control, max_controls> controls{};
92 std::array<bool, 128> touched_pitches{};
93 std::array<uint16_t, max_touched> touched_keys{};
97 void clear_material()
noexcept
103 void pass_state_begun()
noexcept
105 touched_pitches.fill(
false);
108 template <
typename F>
109 void for_each_material(F&& f)
noexcept
111 for_each_event(std::forward<F>(f));
113 template <
typename F>
114 void remove_material(F&& gone)
noexcept
116 remove_events(std::forward<F>(gone));
119 bool touched(uint16_t key)
const noexcept
121 for(
int i = 0; i < touched_count; i++)
122 if(touched_keys[i] == key)
130 if(n.pass >=
count ||
replaced(n.replaced_by, n.pass, taking)
131 || (own_mute &&
layers[n.pass].muted))
134 && touched_pitches[n.pitch] &&
in_pass(n.start))
141 if(c.pass >=
count ||
replaced(c.replaced_by, c.pass, taking)
142 || (own_mute &&
layers[c.pass].muted))
149 template <
typename F>
150 void remove_events(F&& gone)
noexcept
153 std::remove_if(notes.begin(), notes.begin() + note_count, gone) - notes.begin());
155 std::remove_if(controls.begin(), controls.begin() + control_count, gone)
159 template <
typename F>
160 void for_each_event(F&& f)
noexcept
162 for(
int i = 0; i < note_count; i++)
164 for(
int i = 0; i < control_count; i++)
174 const int pass =
count - 1;
178 const uint64_t bit = uint64_t(1) << pass;
179 for(
int i = 0; i < note_count; i++)
184 n.replaced_by |= bit;
186 for(
int i = 0; i < control_count; i++)
188 auto& c = controls[i];
189 if(c.pass < pass && touched(c.
key()) &&
in_pass(c.pos))
190 c.replaced_by |= bit;
199 std::copy_n(o.notes.begin(), o.note_count, notes.begin());
200 std::copy_n(o.controls.begin(), o.control_count, controls.begin());
201 note_count = o.note_count;
202 control_count = o.control_count;
205 touched_pitches = o.touched_pitches;
206 touched_keys = o.touched_keys;
207 touched_count = o.touched_count;
210 midi_note* add_note(int64_t pos,
int channel,
int pitch,
int velocity)
noexcept
212 if(note_count >= max_notes)
217 touched_pitches[pitch & 127] =
true;
218 auto& n = notes[note_count++];
222 .channel = uint8_t(channel),
223 .pitch = uint8_t(pitch),
224 .velocity = uint8_t(velocity),
225 .pass = uint8_t(
count - 1),
234 for(
int i = 0; i < note_count; i++)
237 if(n.length < 0 && n.channel == channel && n.pitch == pitch)
243 void add_control(int64_t pos, uint8_t status, uint8_t d1, uint8_t d2)
noexcept
245 if(control_count >= max_controls)
251 auto& c = controls[control_count++];
257 .pass = uint8_t(
count - 1),
260 const auto key = c.
key();
261 if(!touched(key) && touched_count < max_touched)
262 touched_keys[touched_count++] = key;
268 if(!touched(key) && touched_count < max_touched)
269 touched_keys[touched_count++] = key;
275 for(
int i = 0; i < note_count; i++)
Definition AudioLayers.hpp:14
HeldNotes
A note still held at the end of the loop.
Definition MidiLoop.hpp:25
@ Wrap
Carries on from the loop's start.
@ Truncate
Ends with the loop.
OverdubMode
What the MIDI looper does with notes of earlier passes under an overdub.
Definition MidiLoop.hpp:17
@ Merge
Every pass is heard.
A controller, pitch bend or pressure value.
Definition MidiLoop.hpp:47
uint16_t key() const noexcept
What two values have in common when they move the same thing.
Definition MidiLoop.hpp:57
Definition MidiLoop.hpp:80
void end_pass(OverdubMode mode) noexcept
Definition MidiLoop.hpp:170
bool heard(const midi_note &n, OverdubMode mode, bool own_mute=true) const noexcept
own_mute false hears a muted pass's events as if it were not muted.
Definition MidiLoop.hpp:128
void close_open_notes(int64_t pos) noexcept
Notes still held when the loop is left get the length they have now.
Definition MidiLoop.hpp:273
void assign(const midi_loop &o) noexcept
Copies what another loop holds, without its unused storage.
Definition MidiLoop.hpp:197
midi_note * open_note(int channel, int pitch) noexcept
The note-off of a held note: the oldest one of that key still open.
Definition MidiLoop.hpp:232
void touch(uint16_t key) noexcept
The pass moves a controller it has no value of yet: it replaces it.
Definition MidiLoop.hpp:266
Definition MidiLoop.hpp:31
int64_t length
Frames until the note-off; -1 while the key is held.
Definition MidiLoop.hpp:35
int64_t start
Loop position of the note-on, in frames.
Definition MidiLoop.hpp:33
uint64_t replaced_by
The passes that replace it, a bit each.
Definition MidiLoop.hpp:41
uint8_t channel
1 - 16
Definition MidiLoop.hpp:36
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
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