14 halp_meta(name,
"Midi quantify (old)")
15 halp_meta(c_name,
"Quantifier")
16 halp_meta(category,
"Midi/Timing")
17 halp_meta(manual_url,
"https://ossia.io/score-docs/processes/midi-utilities.html#quantifier")
18 halp_meta(author,
"ossia score")
19 halp_meta(description,
"Quantifies a MIDI input")
20 halp_flag(deprecated);
21 halp_meta(uuid,
"b8e2e5ad-17e4-43de-8d79-660a29d5c4f4")
25 halp::midi_bus<
"in", libremidi::message> midi;
27 halp::hslider_f32<
"Tightness", halp::range{0.f, 1.f, 0.8f}> tightness;
29 halp::hslider_f32<
"Tempo", halp::range{20., 300., 120.}> tempo;
49 std::vector<NoteIn> to_start;
50 std::vector<NoteIn> running_notes;
54 void prepare(halp::setup s) { setup = s; }
56 using tick = halp::tick_flicks;
57 void sequence(Note new_note, int64_t date)
59 for(
auto note : to_start)
60 if(note.note.pitch == new_note.pitch)
62 for(
auto note : running_notes)
63 if(note.note.pitch == new_note.pitch)
65 to_start.push_back(NoteIn{new_note, date});
67 void operator()(
const tick& tk)
69 double start_q_ratio = inputs.start_quant.value;
70 double precision = inputs.tightness.value;
71 double duration = inputs.duration.value;
72 double tempo = inputs.tempo.value;
75 const auto whole_dur = 240.f / tempo;
76 const auto whole_samples = whole_dur * setup.rate;
78 for(
const libremidi::message& in : inputs.midi)
81 if(!in.is_note_on_or_off())
83 outputs.midi.push_back(in);
87 Note note{in[1], in[2], (uint8_t)in.get_channel()};
89 if(in.get_message_type() == libremidi::message_type::NOTE_ON && note.vel != 0)
91 if(start_q_ratio == 0.f)
93 auto no = libremidi::channel_events::note_on(note.chan, note.pitch, note.vel);
94 no.timestamp = in.timestamp;
96 outputs.midi.push_back(no);
99 auto end = tk.position_in_frames + (int64_t)no.timestamp
100 + (int64_t)(whole_samples * duration);
101 this->running_notes.push_back({note, end});
103 else if(duration == 0.f)
106 auto noff = libremidi::channel_events::note_off(note.chan, note.pitch, note.vel);
107 noff.timestamp = no.timestamp;
108 outputs.midi.push_back(noff);
115 const auto start_q = whole_samples * start_q_ratio;
116 auto perf_date = int64_t(
117 start_q * int64_t(1 + (tk.position_in_frames + in.timestamp) / start_q));
120 int64_t actual_date = perf_date;
122 sequence(note, actual_date);
128 auto noff = libremidi::channel_events::note_off(note.chan, note.pitch, note.vel);
129 noff.timestamp = in.timestamp;
130 outputs.midi.push_back(noff);
132 for(
auto it = running_notes.begin(); it != running_notes.end();)
133 if(it->note.pitch == note.pitch)
134 it = running_notes.erase(it);
142 for(
auto it = this->to_start.begin(); it != this->to_start.end();)
146 if(note.date >= tk.position_in_frames
147 && note.date < (tk.position_in_frames + tk.frames))
149 auto no = libremidi::channel_events::note_on(
150 note.note.chan, note.note.pitch, note.note.vel);
151 no.timestamp = note.date - tk.position_in_frames;
152 outputs.midi.push_back(no);
156 auto end = note.date + (int64_t)(whole_samples * duration);
157 this->running_notes.push_back({note.note, end});
159 else if(duration == 0.f)
162 auto noff = libremidi::channel_events::note_off(note.note.chan, note.note.pitch, note.note.vel);
163 noff.timestamp = no.timestamp;
164 outputs.midi.push_back(noff);
167 it = this->to_start.erase(it);
175 for(
auto it = this->running_notes.begin(); it != this->running_notes.end();)
178 if(note.date >= tk.position_in_frames
179 && note.date < (tk.position_in_frames + tk.frames))
181 auto noff = libremidi::channel_events::note_off(note.note.chan, note.note.pitch, note.note.vel);
182 noff.timestamp = note.date - tk.position_in_frames;
183 outputs.midi.push_back(noff);
184 it = this->running_notes.erase(it);