OSSIA
Open Scenario System for Interactive Application
metronome.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/editor/curve/curve.hpp>
6 
7 namespace ossia::nodes
8 {
9 class metronome final : public ossia::nonowning_graph_node
10 {
11 public:
12  metronome() { m_outlets.push_back(&value_out); }
13 
14  ~metronome() override = default;
15 
16  [[nodiscard]] std::string label() const noexcept override { return "metronome"; }
17 
18  void set_curve(std::shared_ptr<curve<double, float>> b) { m_curve = std::move(b); }
19 
20  void reset() { m_metroPrevTick = ossia::time_value{}; }
21 
22 private:
23  void run(const ossia::token_request& t, ossia::exec_state_facade e) noexcept override
24  {
25  ossia::value_port& vp = *value_out;
26  const auto date = t.date;
27  const auto pos = t.position();
28 
29  // TODO use a better temporal accuracy ?
30 
31  // Get the "tick speed" at the current position
32  // Compute the date of the next tick with a comparison to the last tick.
33  // If it is before the current time_value, send it, else wait.
34 
35  // cur: Tick speed in time_values.
36  // 1 = 1 tick per time_value. 1000 = 1 tick per 1000 time_value.
37  time_value cur{int64_t(m_curve->value_at(pos))};
38 
39  // TODO we should compute the derivative since the last tick in order to be
40  // precise
41  if(date > t.prev_date)
42  {
43  time_value elapsed = date - t.prev_date;
44  if(m_metroPrevTick + elapsed < cur)
45  {
46  // not yet
47  m_metroPrevTick += elapsed;
48  return;
49  }
50  else
51  {
52  m_metroPrevTick = elapsed - cur;
53  vp.write_value(
54  ossia::impulse{},
55  t.physical_start(e.modelToSamples())); // TODO offset is wrong here
56  }
57  }
58  else if(date < t.prev_date)
59  {
60  time_value elapsed = t.prev_date - date;
61  if(m_metroPrevTick + elapsed < cur)
62  {
63  // not yet
64  m_metroPrevTick += elapsed;
65  return;
66  }
67  else
68  {
69  m_metroPrevTick = elapsed - cur;
70  vp.write_value(
71  ossia::impulse{},
72  t.physical_start(e.modelToSamples())); // TODO offset is wrong here
73  }
74  }
75  }
76 
77  std::shared_ptr<curve<double, float>> m_curve;
78  ossia::value_outlet value_out;
79  time_value m_metroPrevTick{};
80 };
81 
82 class metronome_process final : public ossia::node_process
83 {
84 public:
85  using ossia::node_process::node_process;
86  void start() override { static_cast<ossia::nodes::metronome*>(node.get())->reset(); }
87 };
88 }
The time_value class.
Definition: ossia/editor/scenario/time_value.hpp:28