2 #include <ossia/detail/flat_map.hpp>
3 #include <ossia/detail/small_vector.hpp>
5 #include <halp/audio.hpp>
6 #include <halp/controls.hpp>
7 #include <halp/meta.hpp>
8 #include <halp/midi.hpp>
9 #include <libremidi/message.hpp>
13 static void duplicate_vector(T& vec)
15 const int N = vec.size();
17 for(
int i = 0; i < N; i++)
18 vec.push_back(vec[i]);
24 halp_meta(name,
"Arpeggios");
32 halp::combo_pair<int> values[5]{{
"Forward", 0}, {
"Backward", 1}, {
"F->B", 2}, {
"B->F", 3}, {
"Chord", 4}};
41 halp_meta(name,
"Arpeggiator")
42 halp_meta(c_name,
"Arpeggiator")
43 halp_meta(category,
"Midi")
44 halp_meta(author,
"ossia score")
47 "https://ossia.io/score-docs/processes/midi-utilities.html#arpeggiator")
48 halp_meta(description,
"Arpeggiator")
49 halp_meta(uuid,
"0b98c7cd-f831-468f-81e3-706d6a97d705")
54 halp::midi_bus<
"in", libremidi::message> midi;
56 halp::hslider_i32<
"Octave", halp::irange{1, 7, 1}> octave;
57 halp::hslider_i32<
"Quantification", halp::irange{1, 32, 8}> quantification;
61 halp::midi_out_bus<
"out", libremidi::message> midi;
64 using byte =
unsigned char;
65 using chord = ossia::small_vector<std::pair<byte, byte>, 5>;
67 ossia::flat_map<byte, byte> notes;
68 ossia::small_vector<chord, 10> arpeggio;
69 std::array<int8_t, 128> in_flight{};
71 float previous_octave{};
72 int previous_arpeggio{};
78 switch(previous_arpeggio)
85 std::reverse(arpeggio.begin(), arpeggio.end());
89 duplicate_vector(arpeggio);
90 std::reverse(arpeggio.begin() + notes.size(), arpeggio.end());
94 duplicate_vector(arpeggio);
95 std::reverse(arpeggio.begin(), arpeggio.begin() + notes.size());
100 for(std::pair note : notes)
102 arpeggio[0].push_back(note);
107 const std::size_t orig_size = arpeggio.size();
110 for(
int i = 1; i < previous_octave; i++)
112 octavize(orig_size, i);
114 for(
int i = 1; i < previous_octave; i++)
116 octavize(orig_size, -i);
120 void arpeggiate(
int size_mult)
123 arpeggio.reserve(notes.size() * size_mult);
124 for(std::pair note : notes)
126 arpeggio.push_back(chord{note});
130 void octavize(std::size_t orig_size,
int i)
132 for(std::size_t j = 0; j < orig_size; j++)
134 auto copy = arpeggio[j];
135 for(
auto it = copy.begin(); it != copy.end();)
138 int res = note.first + 12 * i;
139 if(res >= 0.f && res <= 127.f)
150 arpeggio.push_back(std::move(copy));
154 using tick = halp::tick_musical;
155 void operator()(
const halp::tick_musical& tk)
159 auto& midi = this->inputs.midi;
160 auto& out = this->outputs.midi;
161 const auto& msgs = midi;
162 const int octave = inputs.octave;
163 const int arpeggio = inputs.arpeggios.value;
164 self.previous_octave = octave;
165 self.previous_arpeggio = arpeggio;
170 for(
auto& note : msgs)
172 if(note.get_message_type() == libremidi::message_type::NOTE_ON)
174 self.notes.insert({note.bytes[1], note.bytes[2]});
176 else if(note.get_message_type() == libremidi::message_type::NOTE_OFF)
178 self.notes.erase(note.bytes[1]);
184 const bool mustUpdateArpeggio = msgs.size() > 0 || octave !=
self.previous_octave || arpeggio !=
self.previous_arpeggio;
185 if(mustUpdateArpeggio)
190 if(
self.arpeggio.empty())
192 for(
int k = 0; k < 128; k++)
194 while(
self.in_flight[k] > 0)
196 out.note_off(1, k, 0).timestamp = 0;
203 if(
self.index >=
self.arpeggio.size())
208 for(
auto [date, q] : tk.get_quantification_date_with_bars(inputs.quantification.value))
213 if(date >= tk.frames)
217 for(
int k = 0; k < 128; k++)
219 while(
self.in_flight[k] > 0)
221 out.note_off(1, k, 0).timestamp = date;
227 auto& chord =
self.arpeggio[
self.index];
229 for(
auto& note : chord)
231 self.in_flight[note.first]++;
232 out.note_on(1, note.first, note.second).timestamp = date;
236 self.index = (
self.index + 1) % (
self.arpeggio.size());
Definition: Arpeggiator.hpp:31
Definition: Arpeggiator.hpp:23
Definition: Arpeggiator.hpp:40