Loading...
Searching...
No Matches
PatternNode.hpp
1#pragma once
2#include <ossia/dataflow/graph_node.hpp>
3#include <ossia/dataflow/node_process.hpp>
4#include <ossia/dataflow/port.hpp>
5#include <ossia/detail/math.hpp>
6#include <ossia/network/value/value_conversion.hpp>
7
8#include <Patternist/PatternModel.hpp>
9#include <libremidi/ump_events.hpp>
10
11#include <algorithm>
12#include <array>
13#include <atomic>
14#include <cmath>
15#include <limits>
16#include <random>
17
18namespace Patternist
19{
20// The model stores channels as 1-16, the wire format as 0-15
21inline uint8_t to_midi_channel(int c) noexcept
22{
23 return std::clamp(c - 1, 0, 15);
24}
25
26class pattern_node : public ossia::nonowning_graph_node
27{
28public:
29 ossia::value_inlet pattern_select;
30 ossia::value_inlet switch_quantification;
31 ossia::value_inlet fill_in;
32 ossia::value_inlet density_in;
33 ossia::value_inlet velocity_in;
34 ossia::value_inlet swing_in;
35 ossia::value_inlet ratchet_in;
36 ossia::value_inlet pace_in;
37 ossia::value_inlet repeat_time_in;
38 ossia::midi_outlet out;
39 ossia::value_outlet accent_out;
40 ossia::value_outlet slide_out;
41
42 // The whole list, so that switching pattern moves an index rather than
43 // copying lanes - which would allocate, on the audio thread.
44 std::vector<Pattern> patterns;
47 std::array<uint8_t, 128> in_flight{};
48
49 int current_pattern{};
53 double switch_rate{1.};
54
55 bool fill{};
56 float density{1.f};
57 float velocity_scale{1.f};
58 float swing{0.f};
60 float ratchet_scale{1.f};
62 float pace_offset{0.f};
65 double repeat_time{0.};
67 ossia::vec2f repeat_time_value{0.f, 0.f};
68 double tempo{120.};
70 static constexpr int max_ratchet = 16;
71
74 double origin = std::numeric_limits<double>::quiet_NaN();
78
81 int current = 0;
84 int64_t main_played{};
88 std::array<bool, Pattern::maxLanes> resync_lane{};
89 bool resync_main{};
90 int last = -1;
91 uint8_t channel{1};
92 // Channel the notes currently in flight were started on: a channel change
93 // must not leave them stranded on the previous one.
94 uint8_t in_flight_channel{1};
95 bool release_pending{};
96 bool mustStop{};
97
98 static constexpr int max_lanes = Pattern::maxLanes;
100 {
102 int64_t played{};
104 int64_t early{-1};
106 int16_t held{-1};
109 double held_on{-std::numeric_limits<double>::infinity()};
111 int64_t last{-1};
114 int64_t shift_for{-1};
115 double shift{};
117 double last_at{};
120 bool slid{};
123 struct decided
124 {
125 int64_t n{-1};
126 float value{};
127 };
128 std::array<decided, 2> decisions{};
129 };
130 std::array<lane_state, max_lanes> lanes{};
131
134 enum class event_kind : uint8_t
135 {
136 accent,
137 note_off,
138 note_on,
139 slide
140 };
142 struct event
143 {
144 double position{};
147 uint32_t order{};
148 event_kind kind{};
149 uint8_t note{};
150 uint8_t velocity{};
151 float value{};
152 };
158 static constexpr int max_events = 4 * max_lanes * (2 * max_ratchet + 1);
159 std::array<event, max_events> queue{};
160 int queue_size{};
161 uint32_t next_order{};
163 std::array<event, 2 * max_lanes> immediate{};
164 int immediate_size{};
165
168 {
169 double position{};
170 int64_t offset{};
171 int division{};
173 bool main{};
174 };
175 static constexpr int max_points = 2048;
176 std::array<grid_point, max_points> points{};
177
178 std::minstd_rand rng{0x5eed};
179
181 std::array<int16_t, max_lanes> control_lanes{};
182 int control_lane_count{};
183
188 {
189 std::atomic<int> pattern{-1};
190 std::atomic<int> pending{-1};
191 std::atomic<int> lane_count{0};
192 std::array<std::atomic<int64_t>, max_lanes> lanes;
193 };
194 display_state shown;
195
197 {
198 for(auto& l : shown.lanes)
199 l.store(-1, std::memory_order_relaxed);
200 m_inlets.push_back(&pattern_select);
201 m_inlets.push_back(&switch_quantification);
202 m_inlets.push_back(&fill_in);
203 m_inlets.push_back(&density_in);
204 m_inlets.push_back(&velocity_in);
205 m_inlets.push_back(&swing_in);
206 m_inlets.push_back(&ratchet_in);
207 m_inlets.push_back(&pace_in);
208 m_inlets.push_back(&repeat_time_in);
209 m_outlets.push_back(&out);
210 m_outlets.push_back(&accent_out);
211 m_outlets.push_back(&slide_out);
212 }
213
214 std::string label() const noexcept override { return "pattern_node"; }
215
216 const Pattern& pattern() const noexcept { return patterns[current_pattern]; }
217
219 void request_pattern(int idx) noexcept
220 {
221 if(patterns.empty())
222 return;
223 idx = std::clamp(idx, 0, int(patterns.size()) - 1);
224 pending_pattern = (idx == current_pattern) ? -1 : idx;
225 }
226
227 void release_all(int64_t timestamp) noexcept
228 {
229 auto& mess = out.target<ossia::midi_port>()->messages;
230 for(int note = 0; note < 128; note++)
231 {
232 if(in_flight[note] == 0)
233 continue;
234 mess.push_back(libremidi::from_midi1::note_off(in_flight_channel, note, 0));
235 mess.back().timestamp = timestamp;
236 in_flight[note] = 0;
237 }
238
239 // What was scheduled belongs to what is being released.
240 queue_size = 0;
241 for(auto& l : lanes)
242 {
243 l.held = -1;
244 l.held_on = -std::numeric_limits<double>::infinity();
245 l.early = -1;
246 l.slid = false;
247 }
248 }
249
250 void reset_lanes() noexcept
251 {
252 for(auto& l : lanes)
253 l = lane_state{};
254 main_played = 0;
255 resync_lane.fill(false);
256 resync_main = false;
257 }
258
260 void replace_patterns(std::vector<Pattern>& list) noexcept
261 {
262 if(ossia::valid_index(current_pattern, patterns)
263 && ossia::valid_index(current_pattern, list))
264 {
265 const Pattern& before = patterns[current_pattern];
266 const Pattern& after = list[current_pattern];
267 const int count_before = std::min(int(before.lanes.size()), max_lanes);
268 const int count_after = std::min(int(after.lanes.size()), max_lanes);
269 for(int i = 0; i < count_after; i++)
270 if(i >= count_before
271 || laneDivision(before, before.lanes[i]) != laneDivision(after, after.lanes[i]))
272 resync_lane[i] = true;
273 if(before.length != after.length || before.division != after.division)
274 resync_main = true;
275 }
276 std::swap(patterns, list);
277 }
278
279 void set_channel(uint8_t c) noexcept
280 {
281 if(c == channel)
282 return;
283 channel = c;
284 // Released from run(), where a timestamp inside the tick is available
285 release_pending = true;
286 }
287
291 static bool finite(float v) noexcept { return std::isfinite(v); }
292 void set_switch_rate(float v) noexcept
293 {
294 if(finite(v))
295 switch_rate = std::clamp(v, 0.f, 64.f);
296 }
297 void set_density(float v) noexcept
298 {
299 if(finite(v))
300 density = std::clamp(v, 0.f, 1.f);
301 }
302 void set_velocity_scale(float v) noexcept
303 {
304 if(finite(v))
305 velocity_scale = std::clamp(v, 0.f, 1.f);
306 }
307 void set_swing(float v) noexcept
308 {
309 if(finite(v))
310 swing = std::clamp(v, 0.f, 1.f);
311 }
312 void set_ratchet_scale(float v) noexcept
313 {
314 if(finite(v))
315 ratchet_scale = std::clamp(v, 1.f, 8.f);
316 }
317 void set_pace_offset(float v) noexcept
318 {
319 if(finite(v))
320 pace_offset = std::clamp(v, -1.f, 1.f);
321 }
322 void set_repeat_time(ossia::vec2f v) noexcept
323 {
324 if(finite(v[0]) && finite(v[1]))
325 repeat_time_value = {std::clamp(v[0], 0.f, 60.f), v[1]};
326 }
327
328 void read_controls() noexcept
329 {
330 if(auto& d = pattern_select->get_data(); !d.empty())
331 request_pattern(ossia::convert<int>(d.back().value));
332 if(auto& d = switch_quantification->get_data(); !d.empty())
333 set_switch_rate(ossia::convert<float>(d.back().value));
334 if(auto& d = fill_in->get_data(); !d.empty())
335 fill = ossia::convert<bool>(d.back().value);
336 if(auto& d = density_in->get_data(); !d.empty())
337 set_density(ossia::convert<float>(d.back().value));
338 if(auto& d = velocity_in->get_data(); !d.empty())
339 set_velocity_scale(ossia::convert<float>(d.back().value));
340 if(auto& d = swing_in->get_data(); !d.empty())
341 set_swing(ossia::convert<float>(d.back().value));
342 if(auto& d = ratchet_in->get_data(); !d.empty())
343 set_ratchet_scale(ossia::convert<float>(d.back().value));
344 if(auto& d = pace_in->get_data(); !d.empty())
345 set_pace_offset(ossia::convert<float>(d.back().value));
346 if(auto& d = repeat_time_in->get_data(); !d.empty())
347 set_repeat_time(ossia::convert<ossia::vec2f>(d.back().value));
348 }
349
351 void transport() noexcept { transport_requested = true; }
352
353 void run(const ossia::token_request& tk, ossia::exec_state_facade st) noexcept override
354 {
355 using namespace ossia;
356
357 // Before every early return below: the inlets are cleared once the node has
358 // run, so a request read later than this is a request lost.
359 read_controls();
360 if(tk.tempo > 0. && std::isfinite(tk.tempo))
361 tempo = tk.tempo;
362 update_repeat_time();
363
364 const double samplesratio = st.modelToSamples();
365 // The magnitude of the speed: dividing by a negative speed while rewinding
366 // turns the tick offset into a negative timestamp, which every consumer
367 // that windows on [tick_start; tick_start + frames[ drops - and a dropped
368 // note-off is a note stuck forever.
369 const double speed = tk.speed != 0. ? std::abs(tk.speed) : 1.;
370 // The span the producer handed us wins over reconstructing it from the
371 // offset, which the flick rounding can miss by a sample. Reconstruction
372 // stays for the tokens that carry no span - and for a null speed, where
373 // the model -> sample map is undefined and token_request asserts.
374 const int64_t tick_start
375 = tk.start_sample >= 0
376 ? int64_t(tk.start_sample)
377 : int64_t(std::floor(tk.offset.impl * samplesratio / speed));
378
379 // Before the empty-tick check: the token requested by stop() is empty.
380 if(mustStop)
381 {
382 release_all(tick_start);
383 mustStop = false;
384 transport_requested = false;
385 return;
386 }
387
388 if(tk.model_read_duration() == 0_tv)
389 return;
390
391 if(tk.end_discontinuous)
392 {
393 // Stamping at 0 puts the message before the beginning of the tick as soon
394 // as the interval does not start on a buffer boundary; every consumer
395 // that windows on [tick_start; tick_start + frames[ then drops it, and
396 // since in_flight is cleared here the note is never released again.
397 release_all(tick_start);
398 return;
399 }
400
401 if(release_pending)
402 {
403 release_all(tick_start);
404 in_flight_channel = channel;
405 release_pending = false;
406 }
407
408 // The list can be replaced while a switch is waiting on it.
409 if(patterns.empty())
410 return;
411 current_pattern = std::clamp(current_pattern, 0, int(patterns.size()) - 1);
412 if(pending_pattern >= int(patterns.size()))
413 pending_pattern = -1;
414 release_removed_lanes(tick_start);
415
416 const bool rewinding = tk.backward();
417 // Without musical time (no tempo anywhere) or going backwards, every lane
418 // takes one step per point of the pattern's grid and plays it at once:
419 // there is no musical position to schedule gates, ratchets or offsets at.
420 const bool timed = !rewinding
421 && tk.musical_end_position > tk.musical_start_position;
422
424 {
425 transport_requested = false;
426 release_all(tick_start);
427 reposition(tk);
428 }
429 if(!std::isfinite(origin) && std::isfinite(tk.musical_start_position))
430 origin = tk.musical_start_position;
431 if(timed)
432 resync(tk);
433
434 constexpr auto never = std::numeric_limits<int64_t>::max();
435 int64_t switch_at = -1;
436 double switch_position{};
437 if(pending_pattern >= 0)
438 {
439 const auto points = tk.get_quantification_dates(switch_rate);
440 // Points come in tick order in both directions, so the first one is the
441 // earliest the switch can happen in this tick.
442 if(!points.empty())
443 {
444 switch_at = tk.physical_position(points.front().position, samplesratio);
445 switch_position = points.front().position;
446 }
447 }
448
449 // The two patterns can have different divisions, so the steps around the
450 // switch are walked on their own grids rather than on a single one.
452 tk, tick_start, samplesratio, rewinding, timed, 0,
453 switch_at < 0 ? never : switch_at);
454
455 if(switch_at >= 0)
456 {
457 if(timed)
458 emit_until(tk, tick_start, samplesratio, switch_position);
459 apply_switch(tick_start + switch_at);
460 origin = switch_position;
461 play_steps(tk, tick_start, samplesratio, rewinding, timed, switch_at, never);
462 }
463
464 if(timed)
465 emit_until(tk, tick_start, samplesratio, tk.musical_end_position);
466 publish();
467 }
468
469 void publish() noexcept
470 {
471 const int count
472 = patterns.empty() ? 0 : std::min(int(pattern().lanes.size()), max_lanes);
473 for(int i = 0; i < count; i++)
474 shown.lanes[i].store(lanes[i].last, std::memory_order_relaxed);
475 shown.lane_count.store(count, std::memory_order_relaxed);
476 shown.pattern.store(patterns.empty() ? -1 : current_pattern, std::memory_order_relaxed);
477 shown.pending.store(pending_pattern, std::memory_order_relaxed);
478 }
479
483 const ossia::token_request& tk, int64_t tick_start, double samplesratio,
484 bool rewinding, bool timed, int64_t from_offset, int64_t to_offset) noexcept
485 {
486 const Pattern& pat = pattern();
487 // The model keeps divisions within range; anything past it would walk a
488 // thousand points a tick.
489 if(pat.length <= 0 || pat.division <= 0 || pat.division > Pattern::maxDivision)
490 return;
491 if(current < 0 || current >= pat.length)
492 current = 0;
493 const int lane_count = std::min(int(pat.lanes.size()), max_lanes);
494 control_lane_count = 0;
495 for(int i = 0; i < lane_count; i++)
496 if(isControlLane(pat.lanes[i]))
497 control_lanes[control_lane_count++] = int16_t(i);
498
499 // Every point of the tick, not just the first: a tick covers more than one
500 // step as soon as the division is small, the buffer large or the tempo
501 // high. Rewinding, the points come in decreasing musical order, and the
502 // pattern walks back the same way. Lanes with a division of their own walk
503 // their own grid, but in time order with the others: what is due goes out
504 // before each point, so nothing pushed later can fall before it.
505 int count = 0;
506 const auto collect = [&](int division, bool main) {
507 tk.for_each_quantification_date(division, [&](const auto& q) {
508 // Through the tick's one musical-position -> sample map, not through
509 // the point's date: the date is truncated to a whole flick, so
510 // flooring it into a sample rounds twice and puts the step a sample
511 // before the metronome click on the same bar line.
512 const int64_t offset = tk.physical_position(q.position, samplesratio);
513 if(offset >= from_offset && offset < to_offset && count < max_points)
514 points[count++] = {q.position, offset, division, main};
515 });
516 };
517 collect(pat.division, true);
518 if(timed)
519 {
520 std::array<bool, Pattern::maxDivision + 1> walked{};
521 walked[std::min(pat.division, Pattern::maxDivision)] = true;
522 for(int i = 0; i < lane_count; i++)
523 {
524 const int div = laneDivision(pat, pat.lanes[i]);
525 if(div > 0 && div <= Pattern::maxDivision && !walked[div])
526 {
527 walked[div] = true;
528 collect(div, false);
529 }
530 }
531 std::sort(
532 points.begin(), points.begin() + count,
533 [](const grid_point& a, const grid_point& b) {
534 if(a.position != b.position)
535 return a.position < b.position;
536 return a.main > b.main;
537 });
538 }
539
540 const bool solo = anySolo(pat);
541 for(int k = 0; k < count; k++)
542 {
543 const grid_point& q = points[k];
544 // The points come in time order, so what goes out here can never be
545 // later than what the points still to come push.
546 if(timed && queue_size >= max_events / 2)
547 emit_until(tk, tick_start, samplesratio, q.position);
548
549 // The accent and slide lanes first, so that the notes they act on
550 // find them on this step.
551 if(!q.main)
552 {
553 for(int first = 1; first >= 0; first--)
554 for(int i = 0; i < lane_count; i++)
555 if(isControlLane(pat.lanes[i]) == bool(first)
556 && laneDivision(pat, pat.lanes[i]) == q.division)
557 play_lane(
558 pat, i, q.position, 4. / q.division, false, true, solo,
559 tick_start + q.offset);
560 continue;
561 }
562
563 // Forward, the step about to play is the current one and the next tick
564 // plays the one after. Rewinding mirrors that: step back first, so going
565 // out and back over the same ground crosses the same steps.
566 if(rewinding)
567 {
568 current = (current + pat.length - 1) % pat.length;
569 main_played = std::max<int64_t>(0, main_played - 1);
570 }
571 last = current;
572 in_flight_channel = channel;
573
574 for(int first = 1; first >= 0; first--)
575 for(int i = 0; i < lane_count; i++)
576 {
577 if(isControlLane(pat.lanes[i]) != bool(first))
578 continue;
579 if(timed && laneDivision(pat, pat.lanes[i]) != pat.division)
580 continue;
581 play_lane(
582 pat, i, q.position, 4. / pat.division, rewinding, timed, solo,
583 tick_start + q.offset);
584 }
585 flush_immediate(tick_start + q.offset);
586
587 if(!rewinding)
588 {
589 current = (current + 1) % pat.length;
590 main_played++;
591 }
592 }
593 }
594
598 static int64_t points_between(
599 double from, double to, double bar_line, double bar, int division) noexcept
600 {
601 if(!(bar > 0.) || division <= 0 || !(to > from))
602 return 0;
603 const double unit = 4. / division;
604 const auto per_bar = int64_t(std::ceil(bar / unit - 1e-9));
605 const auto before = [&](double x) {
606 const double rel = x - bar_line;
607 const double bars = std::floor(rel / bar + 1e-12);
608 const double within = std::max(0., rel - bars * bar);
609 return int64_t(bars) * per_bar
610 + std::min(per_bar, int64_t(std::ceil(within / unit - 1e-9)));
611 };
612 return before(to) - before(from);
613 }
614
617 void reposition(const ossia::token_request& tk) noexcept
618 {
619 reset_lanes();
620 current = 0;
621 const double at = tk.musical_start_position;
622 if(!std::isfinite(origin) || !std::isfinite(at) || patterns.empty())
623 {
624 origin = std::numeric_limits<double>::quiet_NaN();
625 return;
626 }
627 const auto& sig = tk.signature;
628 const double bar = (sig.upper > 0 && sig.lower > 0)
629 ? 4. * sig.upper / sig.lower
630 : 4.;
631 const Pattern& pat = pattern();
632 if(pat.length <= 0 || pat.division <= 0)
633 return;
634 const double bar_line = tk.musical_start_last_bar;
635 const int64_t steps = points_between(origin, at, bar_line, bar, pat.division);
636 main_played = steps;
637 current = int(steps % pat.length);
638 const int lane_count = std::min(int(pat.lanes.size()), max_lanes);
639 for(int i = 0; i < lane_count; i++)
640 lanes[i].played
641 = points_between(origin, at, bar_line, bar, laneDivision(pat, pat.lanes[i]));
642 }
643
647 void resync(const ossia::token_request& tk) noexcept
648 {
649 if(patterns.empty())
650 return;
651 const Pattern& pat = pattern();
652 if(pat.length <= 0 || pat.division <= 0)
653 return;
654 if(resync_main)
655 {
656 resync_main = false;
657 current = int(main_played % pat.length);
658 }
659 const auto& sig = tk.signature;
660 const double bar = (sig.upper > 0 && sig.lower > 0)
661 ? 4. * sig.upper / sig.lower
662 : 4.;
663 const int lane_count = std::min(int(pat.lanes.size()), max_lanes);
664 for(int i = 0; i < lane_count; i++)
665 {
666 if(!resync_lane[i])
667 continue;
668 resync_lane[i] = false;
669 const int div = laneDivision(pat, pat.lanes[i]);
670 auto& ls = lanes[i];
671 ls.played = div == pat.division || !std::isfinite(origin)
674 origin, tk.musical_start_position, tk.musical_start_last_bar,
675 bar, div);
676 ls.early = -1;
677 }
678 for(int i = lane_count; i < max_lanes; i++)
679 resync_lane[i] = false;
680 }
681
683 void release_removed_lanes(int64_t date) noexcept
684 {
685 const int lane_count = std::min(int(pattern().lanes.size()), max_lanes);
686 for(int i = lane_count; i < max_lanes; i++)
687 {
688 auto& ls = lanes[i];
689 if(ls.held >= 0)
690 emit({0., 0, event_kind::note_off, uint8_t(ls.held), 0, 0.f}, date);
691 ls = lane_state{};
692 }
693 }
694
698 const Pattern& pat, int i, double position, double unit, bool rewinding,
699 bool timed, bool solo, int64_t date) noexcept
700 {
701 const Lane& l = pat.lanes[i];
702 auto& ls = lanes[i];
703 const int len = laneLength(pat, l);
704 if(len <= 0)
705 return;
706
707 if(rewinding)
708 ls.played = std::max<int64_t>(0, ls.played - 1);
709 const int64_t n = ls.played;
710 const int step = int(n % len);
711 ls.last = n;
712 ls.last_at = position;
713 if(!rewinding)
714 ls.played++;
715
716 if(!timed)
717 {
718 play_step(pat, i, step, n / len, 0., 0., 0., false, solo, date);
719 return;
720 }
721
722 // Scheduled from the step before, because it plays early.
723 if(ls.early != n)
724 {
725 const double shift = ls.shift_for == n ? ls.shift : note_shift(l, step);
726 play_step(
727 pat, i, step, n / len, position,
728 position + (std::max(0., timing(l, step, shift)) + swing_delay(step)) * unit,
729 unit, true, solo, date);
730 }
731 ls.early = -1;
732
733 // The next step, if it plays early, has to be scheduled now: by the time
734 // its own grid point comes, its notes are already due.
735 const int64_t next = n + 1;
736 const int next_step = int(next % len);
737 ls.shift = note_shift(l, next_step);
738 ls.shift_for = next;
739 if(const double t = timing(l, next_step, ls.shift); t < 0.)
740 {
741 play_step(
742 pat, i, next_step, next / len, position + unit,
743 position + (1. + t + swing_delay(next_step)) * unit, unit, true, solo, date);
744 ls.early = next;
745 }
746 }
747
750 double note_shift(const Lane& l, int step) noexcept
751 {
752 const float r = stepParams(l, step).offsetRandom;
753 if(r <= 0.f || (l.randomPerHit & Lane::TimingPerHit))
754 return 0.;
755 return std::uniform_real_distribution<double>{-r, r}(rng);
756 }
757
759 static double timing(const Lane& l, int step, double shift) noexcept
760 {
761 return std::clamp(stepParams(l, step).offset + shift, -0.5, 0.5);
762 }
763
764 void update_repeat_time() noexcept
765 {
766 const auto [x, mode] = repeat_time_value;
767 if(!(x > 0.f))
768 repeat_time = 0.;
769 else if(mode != 0.f)
770 repeat_time = 4. * x;
771 else
772 repeat_time = x * tempo / 60.;
773 }
774
781 struct hit
782 {
783 double on, off;
784 };
785 template <typename Gate>
786 int hits(
787 const StepParams& p, double unit, bool scheduled, std::array<hit, max_ratchet>& out,
788 Gate&& gate_of) const noexcept
789 {
790 const auto gate = [&](int k) { return std::clamp(gate_of(k), 0.05f, 1.f); };
791 if(!scheduled || unit <= 0.)
792 {
793 out[0] = {0., scheduled ? gate(0) : 1.};
794 return 1;
795 }
796
797 double gap = 1. / (std::max<int>(1, p.ratchet) * ratchet_scale);
798 if(repeat_time > 0. && p.ratchet > 1)
799 gap = repeat_time / ratchet_scale / unit;
800 const int n = std::clamp(int(std::ceil(1. / gap - 1e-6)), 1, max_ratchet);
801
802 const double pace = std::clamp(p.pace + pace_offset, -1.f, 1.f);
803 const double exponent = std::exp2(-2. * pace);
804 const auto bend = [&](double x) { return std::pow(std::min(x, 1.), exponent); };
805 for(int k = 0; k < n; k++)
806 {
807 const double on = bend(k * gap);
808 const double next = k + 1 < n ? bend((k + 1) * gap) : 1.;
809 out[k] = {on, on + gate(k) * (next - on)};
810 }
811 return n;
812 }
813
815 double swing_delay(int step) const noexcept
816 {
817 return (step % 2 == 1) ? swing * 0.5 : 0.;
818 }
819
820 bool condition_holds(const StepParams& p, int64_t pass) const noexcept
821 {
822 switch(p.condition)
823 {
824 case Condition::Always:
825 return true;
826 case Condition::Fill:
827 return fill;
828 case Condition::NotFill:
829 return !fill;
830 case Condition::First:
831 return pass == 0;
832 case Condition::NotFirst:
833 return pass != 0;
834 case Condition::Cycle:
835 return p.cycleB > 0 && (pass % p.cycleB) == (p.cycleA - 1);
836 }
837 return true;
838 }
839
842 float control_value(const Pattern& pat, int i, int64_t n) noexcept
843 {
844 auto& ls = lanes[i];
845 for(const auto& d : ls.decisions)
846 if(d.n == n)
847 return d.value;
848
849 const Lane& l = pat.lanes[i];
850 const int len = laneLength(pat, l);
851 if(len <= 0 || n < 0)
852 return 0.f;
853 const int step = int(n % len);
854 const StepParams& p = stepParams(l, step);
855 float v = 0.f;
856 // The solo of a note lane leaves the accents and slides on it.
857 if(audibleNote(pat, l, step, false) != Note::Rest && condition_holds(p, n / len))
858 {
859 const float chance = p.chance * density;
860 if(chance >= 1.f || std::uniform_real_distribution<float>{0.f, 1.f}(rng) < chance)
861 {
862 if(l.note == accentLane)
863 {
864 const float spread
865 = p.velocityRandom > 0.f
866 ? std::uniform_real_distribution<float>{
868 : 0.f;
869 v = std::clamp(p.velocity + spread, 0.f, 1.f) * std::clamp(l.velocity, 0.f, 1.f);
870 }
871 else
872 {
873 v = std::clamp(p.gate, 0.05f, 1.f);
874 }
875 }
876 }
877 auto& slot = ls.decisions[0].n < ls.decisions[1].n ? ls.decisions[0] : ls.decisions[1];
878 slot = {n, v};
879 return v;
880 }
881
885 {
886 float accent{};
887 bool slide{};
888 };
889 step_controls controls_at(const Pattern& pat, double grid, bool scheduled) noexcept
890 {
892 for(int k = 0; k < control_lane_count; k++)
893 {
894 const int i = control_lanes[k];
895 const Lane& l = pat.lanes[i];
896 const auto& ls = lanes[i];
897 // Played before the note lanes on every point: without a position, the
898 // step it played last is the one.
899 int64_t n = ls.last;
900 if(scheduled && ls.last >= 0)
901 {
902 const double unit = 4. / laneDivision(pat, l);
903 n += int64_t(std::floor((grid - ls.last_at) / unit + 1e-6));
904 }
905 else if(ls.last < 0)
906 n = ls.played;
907 const float v = control_value(pat, i, n);
908 if(l.note == accentLane)
909 c.accent = std::max(c.accent, v);
910 else
911 c.slide |= v > 0.f;
912 }
913 return c;
914 }
915
920 const Pattern& pat, int i, int step, int64_t pass, double grid, double at,
921 double unit, bool scheduled, bool solo, int64_t date) noexcept
922 {
923 const Lane& l = pat.lanes[i];
924 auto& ls = lanes[i];
925 const StepParams& p = stepParams(l, step);
926
927 const auto push = [&](double position, event_kind k, int note, int velocity,
928 float value = 0.f) {
929 push_event(
930 {position, 0, k, uint8_t(note), uint8_t(velocity), value}, scheduled, date);
931 };
932
933 if(isControlLane(l))
934 {
935 const auto kind = l.note == accentLane ? event_kind::accent : event_kind::slide;
936 const float v = control_value(pat, i, pass * laneLength(pat, l) + step);
937 push(at, kind, 0, 0, v);
938 // An accent's gate ends it within the step.
939 if(kind == event_kind::accent && v > 0.f && scheduled && p.gate < 1.f)
940 push(at + std::max(p.gate, 0.05f) * unit, kind, 0, 0, 0.f);
941 return;
942 }
943 if(l.note > 127)
944 return;
945
946 Note kind = audibleNote(pat, l, step, solo);
947 if(kind != Note::Rest)
948 {
949 if(!condition_holds(p, pass))
950 kind = Note::Rest;
951 else if(const float chance = p.chance * density; chance < 1.f)
952 if(std::uniform_real_distribution<float>{0.f, 1.f}(rng) >= chance)
953 kind = Note::Rest;
954 }
955 const step_controls controls = control_lane_count > 0 && kind != Note::Rest
956 ? controls_at(pat, grid, scheduled)
957 : step_controls{};
958
959 // Pitch and velocity spreads: drawn once for the whole note, or by each
960 // hit for itself when the lane says so.
961 const auto draw_pitch = [&] {
962 return p.pitchRandom > 0
963 ? std::uniform_int_distribution<int>{-p.pitchRandom, p.pitchRandom}(rng)
964 : 0;
965 };
966 const auto draw_velocity = [&] {
967 return p.velocityRandom > 0.f
968 ? std::uniform_real_distribution<float>{
970 : 0.f;
971 };
972 const bool pitch_per_hit = l.randomPerHit & Lane::PitchPerHit;
973 const bool velocity_per_hit = l.randomPerHit & Lane::VelocityPerHit;
974 const int note_pitch = kind != Note::Rest && !pitch_per_hit ? draw_pitch() : 0;
975 const float note_velocity
976 = kind != Note::Rest && !velocity_per_hit ? draw_velocity() : 0.f;
977 const auto to_note = [&](int pitch) {
978 return std::clamp(int(l.note) + p.pitch + pitch, 0, 127);
979 };
980 // An accent takes the step's velocity part of the way to the top.
981 const auto to_velocity = [&](float spread) {
982 float v = std::clamp(p.velocity + spread, 0.f, 1.f);
983 v += controls.accent * (1.f - v);
984 return std::clamp(
985 int(std::lround(v * l.velocity * velocity_scale * 127.f)), 1, 127);
986 };
987 // The note and velocity of hit k.
988 const auto strike = [&](int k) {
989 return std::make_pair(
990 to_note(pitch_per_hit ? draw_pitch() : note_pitch),
991 to_velocity(velocity_per_hit ? draw_velocity() : note_velocity));
992 };
993 const int note = to_note(note_pitch);
994
995 const bool gate_per_hit = l.randomPerHit & Lane::GatePerHit;
996 const auto draw_gate = [&] {
997 return p.gateRandom > 0.f ? std::uniform_real_distribution<float>{
998 -p.gateRandom, p.gateRandom}(rng)
999 : 0.f;
1000 };
1001 const float note_gate = kind != Note::Rest && !gate_per_hit ? draw_gate() : 0.f;
1002 const auto gate_of
1003 = [&](int) { return p.gate + (gate_per_hit ? draw_gate() : note_gate); };
1004
1005 // Timing spread of each hit, when each hit draws its own: within its own
1006 // gap, and never before the step for the first one.
1007 const bool timing_per_hit
1008 = scheduled && p.offsetRandom > 0.f && (l.randomPerHit & Lane::TimingPerHit);
1009 const auto hit_shift = [&](const std::array<hit, max_ratchet>& h, int k, int n) {
1010 if(!timing_per_hit)
1011 return 0.;
1012 const double gap = (k + 1 < n ? h[k + 1].on : 1.) - h[k].on;
1013 const double r = p.offsetRandom * gap;
1014 const double d = std::uniform_real_distribution<double>{-r, r}(rng);
1015 return k == 0 ? std::max(0., d) : d;
1016 };
1017
1018 constexpr auto inf = std::numeric_limits<double>::infinity();
1019 // Released where this step starts, or right after it was struck when this
1020 // step starts first.
1021 const auto release_held = [&] {
1022 if(ls.held >= 0)
1023 push(
1024 std::max(at, std::nextafter(ls.held_on, inf)), event_kind::note_off, ls.held,
1025 0);
1026 ls.held = -1;
1027 };
1028 // Slid into: struck at `on` first, the held note released right after;
1029 // the same note just carries on.
1030 const bool slid = ls.slid && ls.held >= 0;
1031 ls.slid = false;
1032 const auto glide_to = [&](double on, int hit_note, int hit_velocity) {
1033 if(ls.held != hit_note)
1034 {
1035 push(on, event_kind::note_on, hit_note, hit_velocity);
1036 push(
1037 std::nextafter(std::max(on, ls.held_on), inf), event_kind::note_off, ls.held,
1038 0);
1039 ls.held_on = on;
1040 }
1041 ls.held = hit_note;
1042 };
1043
1044 switch(kind)
1045 {
1046 case Note::Rest:
1047 release_held();
1048 break;
1049
1050 case Note::Legato: {
1051 // The first hit ties on from the step before; a ratchet strikes the
1052 // others, each released after its gate, and the last is held into the
1053 // next step unless the gate ends it first.
1054 std::array<hit, max_ratchet> h;
1055 const int n = hits(p, unit, scheduled, h, gate_of);
1056 // With a pitch drawn by each hit, the tie holds whatever was struck.
1057 if(slid)
1058 glide_to(at, note, strike(0).second);
1059 else if(ls.held < 0 || (ls.held != note && !pitch_per_hit))
1060 {
1061 release_held();
1062 push(at, event_kind::note_on, note, strike(0).second);
1063 ls.held = note;
1064 ls.held_on = at;
1065 }
1066 int sounding = ls.held;
1067 double off = at + h[0].off * unit;
1068 for(int k = 1; k < n; k++)
1069 {
1070 const double shift = hit_shift(h, k, n);
1071 const auto [hit_note, hit_velocity] = strike(k);
1072 push(off, event_kind::note_off, sounding, 0);
1073 push(at + (h[k].on + shift) * unit, event_kind::note_on, hit_note, hit_velocity);
1074 ls.held = sounding = hit_note;
1075 ls.held_on = at + (h[k].on + shift) * unit;
1076 off = at + (h[k].off + shift) * unit;
1077 }
1078 // A gate under a step ends the tied note there, unless it slides on.
1079 if(h[n - 1].off < 1. && !controls.slide)
1080 {
1081 push(off, event_kind::note_off, sounding, 0);
1082 ls.held = -1;
1083 }
1084 break;
1085 }
1086
1087 case Note::Note: {
1088 if(!slid)
1089 release_held();
1090
1091 std::array<hit, max_ratchet> h;
1092 const int n = hits(p, unit, scheduled, h, gate_of);
1093 for(int k = 0; k < n; k++)
1094 {
1095 const double shift = hit_shift(h, k, n);
1096 const auto [hit_note, hit_velocity] = strike(k);
1097 const double on = at + (h[k].on + shift) * unit;
1098 if(k == 0 && slid)
1099 glide_to(on, hit_note, hit_velocity);
1100 else
1101 push(on, event_kind::note_on, hit_note, hit_velocity);
1102 // The last hit with a full gate, or sliding on, holds until the
1103 // next step.
1104 if(k + 1 == n && (h[k].off >= 1. || controls.slide))
1105 {
1106 if(!(k == 0 && slid && ls.held_on < on))
1107 ls.held_on = on;
1108 ls.held = hit_note;
1109 }
1110 else
1111 {
1112 push(at + (h[k].off + shift) * unit, event_kind::note_off, hit_note, 0);
1113 if(k == 0 && slid)
1114 ls.held = -1;
1115 }
1116 }
1117 break;
1118 }
1119 }
1120 ls.slid = controls.slide && ls.held >= 0;
1121 }
1122
1125 static constexpr int release_reserve = 2 * max_lanes;
1126 void push_event(event e, bool scheduled, int64_t date) noexcept
1127 {
1128 e.order = next_order++;
1129 if(!scheduled)
1130 {
1131 if(immediate_size < int(immediate.size()))
1132 immediate[immediate_size++] = e;
1133 return;
1134 }
1135 // A position that is not a number would never come due.
1136 if(!std::isfinite(e.position))
1137 return;
1138 if(e.kind == event_kind::note_on && queue_size >= max_events - release_reserve)
1139 return;
1140 if(queue_size < max_events)
1141 queue[queue_size++] = e;
1142 }
1143
1145 void flush_immediate(int64_t date) noexcept
1146 {
1147 std::sort(
1148 immediate.begin(), immediate.begin() + immediate_size,
1149 [](const event& a, const event& b) {
1150 if(a.kind != b.kind)
1151 return a.kind < b.kind;
1152 return a.order < b.order;
1153 });
1154 for(int i = 0; i < immediate_size; i++)
1155 emit(immediate[i], date);
1156 immediate_size = 0;
1157 }
1158
1163 const ossia::token_request& tk, int64_t tick_start, double samplesratio,
1164 double end) noexcept
1165 {
1166 const auto due_end = std::partition(
1167 queue.begin(), queue.begin() + queue_size,
1168 [end](const event& e) { return e.position < end - 1e-9; });
1169 std::sort(queue.begin(), due_end, [](const event& a, const event& b) {
1170 if(a.position != b.position)
1171 return a.position < b.position;
1172 if(a.kind != b.kind)
1173 return a.kind < b.kind;
1174 return a.order < b.order;
1175 });
1176
1177 // Late arrivals are stamped at the start of the tick rather than before it,
1178 // where every consumer would drop them.
1179 for(auto it = queue.begin(); it != due_end; ++it)
1180 emit(
1181 *it, tick_start
1182 + tk.physical_position(
1183 std::max(it->position, tk.musical_start_position), samplesratio));
1184
1185 const int remaining = int((queue.begin() + queue_size) - due_end);
1186 std::move(due_end, queue.begin() + queue_size, queue.begin());
1187 queue_size = remaining;
1188 }
1189
1190 void emit(const event& e, int64_t date) noexcept
1191 {
1192 auto& mess = out.target<ossia::midi_port>()->messages;
1193 switch(e.kind)
1194 {
1195 case event_kind::note_off:
1196 if(e.note < 128 && in_flight[e.note] > 0 && --in_flight[e.note] == 0)
1197 {
1198 mess.push_back(libremidi::from_midi1::note_off(in_flight_channel, e.note, 0));
1199 mess.back().timestamp = date;
1200 }
1201 break;
1202 case event_kind::note_on:
1203 if(e.note >= 128)
1204 break;
1205 // Struck again while another lane holds it: the voice restarts.
1206 if(in_flight[e.note] > 0)
1207 {
1208 mess.push_back(libremidi::from_midi1::note_off(in_flight_channel, e.note, 0));
1209 mess.back().timestamp = date;
1210 }
1211 mess.push_back(libremidi::from_midi1::note_on(channel, e.note, e.velocity));
1212 mess.back().timestamp = date;
1213 if(in_flight[e.note] < 255)
1214 in_flight[e.note]++;
1215 in_flight_channel = channel;
1216 break;
1217 case event_kind::accent:
1218 accent_out->write_value(e.value, date);
1219 break;
1220 case event_kind::slide:
1221 slide_out->write_value(e.value, date);
1222 break;
1223 }
1224 }
1225
1226 void apply_switch(int64_t date) noexcept
1227 {
1228 // Everything in flight belongs to the pattern going away: the new one only
1229 // ever releases the notes its own lanes carry, so the rest would hang.
1230 release_all(date);
1231 in_flight_channel = channel;
1232
1233 current_pattern = pending_pattern;
1234 pending_pattern = -1;
1235 current = 0;
1236 reset_lanes();
1237 }
1238
1239 // Writing to the outlet from here would be pointless: this runs outside of a
1240 // tick, and init_outlet() clears every outlet before the node runs again.
1241 void all_notes_off() noexcept override { mustStop = true; }
1242};
1243
1247class pattern_node_process final : public ossia::node_process
1248{
1249public:
1250 using ossia::node_process::node_process;
1251
1252 void stop() override
1253 {
1254 auto& n = *static_cast<pattern_node*>(node.get());
1255 n.request(ossia::token_request{});
1256 n.mustStop = true;
1257 }
1258
1259 void transport_impl(ossia::time_value date) override
1260 {
1261 static_cast<pattern_node*>(node.get())->transport();
1262 }
1263};
1264}
Definition PatternNode.hpp:1248
Definition PatternNode.hpp:27
void release_removed_lanes(int64_t date) noexcept
A lane that is gone cannot release what it held: release it here.
Definition PatternNode.hpp:683
static int64_t points_between(double from, double to, double bar_line, double bar, int division) noexcept
Definition PatternNode.hpp:598
void play_step(const Pattern &pat, int i, int step, int64_t pass, double grid, double at, double unit, bool scheduled, bool solo, int64_t date) noexcept
Definition PatternNode.hpp:919
double repeat_time
Definition PatternNode.hpp:65
void reposition(const ossia::token_request &tk) noexcept
Definition PatternNode.hpp:617
std::array< int16_t, max_lanes > control_lanes
The accent and slide lanes of the pattern playing.
Definition PatternNode.hpp:181
static constexpr int max_events
Definition PatternNode.hpp:158
void emit_until(const ossia::token_request &tk, int64_t tick_start, double samplesratio, double end) noexcept
Definition PatternNode.hpp:1162
int current
Definition PatternNode.hpp:81
static double timing(const Lane &l, int step, double shift) noexcept
Where a step's note starts, in steps from its grid point.
Definition PatternNode.hpp:759
void resync(const ossia::token_request &tk) noexcept
Definition PatternNode.hpp:647
double note_shift(const Lane &l, int step) noexcept
Definition PatternNode.hpp:750
double switch_rate
A token_request rate: 0 switches at the beginning of the tick.
Definition PatternNode.hpp:53
int pending_pattern
Pattern the next quantification point switches to; -1 when nothing waits.
Definition PatternNode.hpp:51
std::array< event, 2 *max_lanes > immediate
What a step without musical time sends, all at the same date.
Definition PatternNode.hpp:163
std::array< uint8_t, 128 > in_flight
Definition PatternNode.hpp:47
void transport() noexcept
The playhead moved somewhere else: the next tick follows it.
Definition PatternNode.hpp:351
std::array< bool, Pattern::maxLanes > resync_lane
Definition PatternNode.hpp:88
static bool finite(float v) noexcept
Definition PatternNode.hpp:291
double swing_delay(int step) const noexcept
Every other step is delayed, by up to half a step.
Definition PatternNode.hpp:815
void flush_immediate(int64_t date) noexcept
Every lane's releases go before any lane strikes.
Definition PatternNode.hpp:1145
int64_t main_played
Definition PatternNode.hpp:84
float control_value(const Pattern &pat, int i, int64_t n) noexcept
Definition PatternNode.hpp:842
void request_pattern(int idx) noexcept
Ask for a pattern: it takes effect at the next quantification point.
Definition PatternNode.hpp:219
bool transport_requested
Definition PatternNode.hpp:77
void play_lane(const Pattern &pat, int i, double position, double unit, bool rewinding, bool timed, bool solo, int64_t date) noexcept
Definition PatternNode.hpp:697
double origin
Definition PatternNode.hpp:74
ossia::vec2f repeat_time_value
The time chooser's value: {seconds, 0} or {whole notes, synced}.
Definition PatternNode.hpp:67
float pace_offset
Added to every step's pace, -1 - 1.
Definition PatternNode.hpp:62
event_kind
Definition PatternNode.hpp:135
static constexpr int release_reserve
Definition PatternNode.hpp:1125
void play_steps(const ossia::token_request &tk, int64_t tick_start, double samplesratio, bool rewinding, bool timed, int64_t from_offset, int64_t to_offset) noexcept
Definition PatternNode.hpp:482
static constexpr int max_ratchet
A step's hits once multiplied, held to what a step can still tell apart.
Definition PatternNode.hpp:70
void replace_patterns(std::vector< Pattern > &list) noexcept
Takes a new list, swapped in so that the old one is freed elsewhere.
Definition PatternNode.hpp:260
float ratchet_scale
Multiplies every step's ratchet, 1 - 8, fractions included.
Definition PatternNode.hpp:60
STL namespace.
Definition PatternModel.hpp:98
uint8_t note
A MIDI note, or accentLane or slideLane.
Definition PatternModel.hpp:101
float velocity
0 - 1.
Definition PatternModel.hpp:109
Definition PatternModel.hpp:139
static const constexpr int maxDivision
Steps per whole note, at most.
Definition PatternModel.hpp:143
Definition PatternModel.hpp:49
float chance
0 - 1, scaled by the Density input.
Definition PatternModel.hpp:56
float gate
0 - 1 of a step; a tie, or 1, holds the note until the next step.
Definition PatternModel.hpp:63
int8_t pitch
Semitones added to the lane's note.
Definition PatternModel.hpp:73
float gateRandom
Definition PatternModel.hpp:66
uint8_t pitchRandom
Definition PatternModel.hpp:76
float velocity
0 - 1, scaled by the lane's velocity and the Velocity input.
Definition PatternModel.hpp:51
float velocityRandom
Definition PatternModel.hpp:54
float offsetRandom
Definition PatternModel.hpp:61
Definition PatternNode.hpp:188
A message waiting for the tick its musical position falls in.
Definition PatternNode.hpp:143
uint32_t order
Definition PatternNode.hpp:147
The grid points of a tick, across the divisions the lanes walk.
Definition PatternNode.hpp:168
bool main
A point of the pattern's own grid, which moves current.
Definition PatternNode.hpp:173
Definition PatternNode.hpp:782
Definition PatternNode.hpp:124
Definition PatternNode.hpp:100
double held_on
Definition PatternNode.hpp:109
int64_t last
Index of the step playing now, counted like played, or -1.
Definition PatternNode.hpp:111
int16_t held
Note the lane holds until its next step, or -1.
Definition PatternNode.hpp:106
int64_t early
A step scheduled ahead because it plays early, or -1.
Definition PatternNode.hpp:104
bool slid
Definition PatternNode.hpp:120
double last_at
Where on its grid the step last is, in quarters.
Definition PatternNode.hpp:117
int64_t shift_for
Definition PatternNode.hpp:114
int64_t played
Steps the lane has started since the pattern started playing.
Definition PatternNode.hpp:102
Definition PatternNode.hpp:885