60 halp_meta(name,
"Arpeggiator")
61 halp_meta(c_name,
"Arpeggiator")
62 halp_meta(category,
"Midi")
63 halp_meta(author,
"ossia score")
66 "https://ossia.io/score-docs/processes/midi-utilities.html#arpeggiator")
67 halp_meta(description,
"Arpeggiator")
68 halp_meta(uuid,
"0b98c7cd-f831-468f-81e3-706d6a97d705")
73 halp::midi_bus<
"in", libremidi::message> midi;
75 halp::hslider_i32<
"Octave", halp::irange{1, 7, 1}> octave;
77 halp::hslider_i32<
"Repeat", halp::irange{1, 8, 1}> repeat;
78 halp::hslider_i32<
"Quantification", halp::irange{1, 32, 8}> quantification;
82 halp::midi_out_bus<
"out", libremidi::message> midi;
85 using byte =
unsigned char;
86 using chord = ossia::small_vector<std::pair<byte, byte>, 5>;
88 ossia::flat_map<byte, byte> notes;
89 ossia::small_vector<chord, 10> arpeggio;
90 std::array<int8_t, 128> in_flight{};
92 int previous_octave{};
93 int previous_octave_mode{};
94 int previous_repeat{};
95 int previous_arpeggio{};
98 std::random_device d{};
106 switch(previous_arpeggio)
113 std::reverse(arpeggio.begin(), arpeggio.end());
117 duplicate_vector(arpeggio);
118 std::reverse(arpeggio.begin() + notes.size(), arpeggio.end());
122 duplicate_vector(arpeggio);
123 std::reverse(arpeggio.begin(), arpeggio.begin() + notes.size());
129 for(std::pair note : notes)
131 arpeggio[0].push_back(note);
133 for(
int i = 1; i < previous_octave; i++)
136 if(previous_octave_mode != 2)
138 int up = note.first + 12 * i;
140 arpeggio[0].push_back({
static_cast<byte>(up), note.second});
142 if(previous_octave_mode != 1)
144 int down = note.first - 12 * i;
146 arpeggio[0].push_back({
static_cast<byte>(down), note.second});
158 if(previous_repeat > 1)
160 decltype(arpeggio) repeated;
161 repeated.reserve(arpeggio.size() * previous_repeat);
162 for(
auto& c : arpeggio)
164 for(
int r = 0; r < previous_repeat; r++)
165 repeated.push_back(c);
167 arpeggio = std::move(repeated);
170 const std::size_t orig_size = arpeggio.size();
174 if(previous_octave_mode != 2)
176 for(
int i = 1; i < previous_octave; i++)
177 octavize(orig_size, i);
179 if(previous_octave_mode != 1)
181 for(
int i = 1; i < previous_octave; i++)
182 octavize(orig_size, -i);
186 void arpeggiate(
int size_mult)
189 arpeggio.reserve(notes.size() * size_mult);
190 for(std::pair note : notes)
192 arpeggio.push_back(chord{note});
196 void octavize(std::size_t orig_size,
int i)
198 for(std::size_t j = 0; j < orig_size; j++)
200 auto copy = arpeggio[j];
201 for(
auto it = copy.begin(); it != copy.end();)
204 int res = note.first + 12 * i;
205 if(res >= 0.f && res <= 127.f)
216 arpeggio.push_back(std::move(copy));
220 using tick = halp::tick_musical;
221 void operator()(
const halp::tick_musical& tk)
225 auto& midi = this->inputs.midi;
226 auto& out = this->outputs.midi;
227 const auto& msgs = midi;
228 const int octave = inputs.octave;
229 const int octave_mode = inputs.octave_mode.value;
230 const int repeat = inputs.repeat;
231 const int arpeggio_mode = inputs.arpeggios.value;
236 for(
auto& note : msgs)
238 if(note.get_message_type() == libremidi::message_type::NOTE_ON)
240 self.notes.insert({note.bytes[1], note.bytes[2]});
242 else if(note.get_message_type() == libremidi::message_type::NOTE_OFF)
244 self.notes.erase(note.bytes[1]);
250 const bool mustUpdateArpeggio = msgs.size() > 0 || octave != self.previous_octave
251 || octave_mode != self.previous_octave_mode
252 || repeat != self.previous_repeat
253 || arpeggio_mode != self.previous_arpeggio;
254 self.previous_octave = octave;
255 self.previous_octave_mode = octave_mode;
256 self.previous_repeat = repeat;
257 self.previous_arpeggio = arpeggio_mode;
259 if(mustUpdateArpeggio)
264 if(self.arpeggio.empty())
266 for(
int k = 0; k < 128; k++)
268 while(self.in_flight[k] > 0)
270 out.note_off(1, k, 0).timestamp = 0;
277 if(self.index >= self.arpeggio.size())
282 tk.get_quantification_date_with_bars(inputs.quantification.value))
284 if(date >= tk.frames)
288 for(
int k = 0; k < 128; k++)
290 while(self.in_flight[k] > 0)
292 out.note_off(1, k, 0).timestamp = date;
298 std::size_t play_index;
299 if(arpeggio_mode == 5)
301 std::uniform_int_distribution<std::size_t> dist(0, self.arpeggio.size() - 1);
302 play_index = dist(rng);
306 play_index = self.index;
307 self.index = (self.index + 1) % self.arpeggio.size();
311 auto& chord = self.arpeggio[play_index];
313 for(
auto& note : chord)
315 self.in_flight[note.first]++;
316 out.note_on(1, note.first, note.second).timestamp = date;