Loading...
Searching...
No Matches
Metro_v2.hpp
1#pragma once
2#include <Fx/Types.hpp>
3
4#include <halp/audio.hpp>
5#include <halp/callback.hpp>
6#include <halp/controls.hpp>
7#include <halp/meta.hpp>
8
9#include <cmath>
10
11namespace Nodes::Metro::v2
12{
13struct Node
14{
15 halp_meta(name, "Free metronome")
16 halp_meta(c_name, "Metro")
17 halp_meta(category, "Timing/Control")
18 halp_meta(author, "ossia score")
19 halp_meta(manual_url, "https://ossia.io/score-docs/processes/control-utilities.html#free-metronome")
20 halp_meta(description, "Metronome which is not synced to the parent quantization settings")
21
22 halp_meta(uuid, "6e001674-d4a5-478f-9f7e-d7ad1bdcee2b")
23
24 struct
25 {
28 halp::time_chooser<"Period", halp::range{0.001, 60., 0.25}> period;
29 } inputs;
30 struct
31 {
32 halp::timed_callback<"out"> out;
33 } outputs;
34
35 halp::setup setup;
36 void prepare(halp::setup s) { setup = s; }
37
38 using tick = halp::tick_musical;
39 void operator()(const halp::tick_musical& tk)
40 {
41 if(tk.start_position_in_quarters >= tk.end_position_in_quarters || tk.frames <= 0)
42 return;
43 const double period = inputs.period.value;
44 if(!(period > 0.))
45 return;
46
47 if(inputs.period.sync)
48 {
49 // On the musical grid: every period, counted in quarter notes from the
50 // start of the timeline.
51 const double q0 = tk.start_position_in_quarters;
52 const double q1 = tk.end_position_in_quarters;
53 const double step = period * tk.tempo / 60.;
54 if(!(step > 0.))
55 return;
56 // Grid point k is k * step in every tick, computed the same way, so that
57 // the one sitting on the boundary of two ticks goes out exactly once.
58 auto k = int64_t(std::ceil(q0 / step));
59 while(double(k - 1) * step >= q0)
60 --k;
61 while(double(k) * step < q0)
62 ++k;
63 for(double q = double(k) * step; q < q1; q = double(++k) * step)
64 outputs.out(std::clamp<int64_t>(
65 halp::musical_to_frame(q, q0, q1, tk.frames), 0, tk.frames - 1));
66 }
67 else
68 {
69 // Every period of samples since playback started.
70 const int64_t p = std::max<int64_t>(1, std::llround(period * setup.rate));
71 const int64_t pos = tk.position_in_frames;
72 for(int64_t t = ((pos + p - 1) / p) * p; t < pos + tk.frames; t += p)
73 outputs.out(t - pos);
74 }
75 }
76};
77}
Definition Metro_v2.hpp:14