IntervalExecutionHelpers.hpp
1 #pragma once
2 #include <Process/Dataflow/Port.hpp>
3 #include <Process/ExecutionContext.hpp>
4 #include <Process/ExecutionSetup.hpp>
5 #include <Process/ExecutionTransaction.hpp>
6 #include <Process/Process.hpp>
7 
8 #include <Curve/CurveConversion.hpp>
9 
10 #include <Scenario/Document/Interval/IntervalModel.hpp>
11 #include <Scenario/Document/ScenarioDocument/ScenarioDocumentModel.hpp>
12 #include <Scenario/Document/Tempo/TempoProcess.hpp>
13 
14 #include <ossia/dataflow/graph/graph_interface.hpp>
15 #include <ossia/dataflow/graph_edge.hpp>
16 #include <ossia/dataflow/graph_node.hpp>
17 #include <ossia/dataflow/port.hpp>
18 #include <ossia/detail/pod_vector.hpp>
19 #include <ossia/editor/curve/curve.hpp>
20 #include <ossia/editor/scenario/time_interval.hpp>
21 #include <ossia/editor/scenario/time_process.hpp>
22 
23 namespace Execution
24 {
25 
26 inline std::pair<std::optional<ossia::tempo_curve>, Scenario::TempoProcess*>
27 tempoCurve(const Scenario::IntervalModel& itv, const Execution::Context& ctx)
28 {
29  // TODO
30  if(auto proc = itv.tempoCurve())
31  {
32  auto& curve = proc->curve();
33  // TODO recompute whenever tempo changes
34  const auto defaultdur = itv.duration.defaultDuration().msec();
35  auto scale_x = [&ctx, defaultdur](double val) -> int64_t {
36  return ctx.time(TimeVal::fromMsecs(val * defaultdur)).impl;
37  };
38  auto scale_y = [=](double val) -> double {
39  using namespace Scenario;
40  return val * (TempoProcess::max - TempoProcess::min) + TempoProcess::min;
41  };
42 
43  ossia::tempo_curve t;
44 
45  auto segt_data = curve.sortedSegments();
46  if(segt_data.size() != 0)
47  {
48  t = std::move(*Engine::score_to_ossia::curve<int64_t, double>(
49  scale_x, scale_y, segt_data, {}));
50  }
51 
52  return {std::optional<ossia::tempo_curve>{std::move(t)}, proc};
53  }
54  else
55  {
56  return {};
57  }
58 }
59 inline ossia::time_signature_map
60 timeSignatureMap(const Scenario::IntervalModel& itv, const Execution::Context& ctx)
61 {
62  ossia::time_signature_map ret;
63  for(const auto& [time, sig] : itv.timeSignatureMap())
64  {
65  ret[ctx.time(time)] = sig;
66  }
67  return ret;
68 }
69 
70 inline auto propagatedOutlets(const Process::Outlets& outlets) noexcept
71 {
72  ossia::pod_vector<std::size_t> propagated_outlets;
73  for(std::size_t i = 0; i < outlets.size(); i++)
74  {
75  if(auto o = qobject_cast<Process::AudioOutlet*>(outlets[i]))
76  if(o->propagate())
77  propagated_outlets.push_back(i);
78  }
79  return propagated_outlets;
80 }
81 
82 inline void connectPropagated(
83  const ossia::node_ptr& process_node, const ossia::node_ptr& interval_node,
84  ossia::graph_interface& g,
85  const ossia::pod_vector<std::size_t>& propagated_outlets) noexcept
86 {
87  const auto& outs = process_node->root_outputs();
88  for(std::size_t propagated : propagated_outlets)
89  {
90  if(propagated >= outs.size())
91  continue;
92 
93  if(outs[propagated]->which() == ossia::audio_port::which)
94  {
95  auto cable = g.allocate_edge(
96  ossia::immediate_glutton_connection{}, outs[propagated],
97  interval_node->root_inputs()[0], process_node, interval_node);
98  g.connect(cable);
99  }
100  }
101 }
102 
103 inline void updatePropagated(
104  const ossia::node_ptr& process_node, const ossia::node_ptr& interval_node,
105  ossia::graph_interface& g, std::size_t port_idx, bool is_propagated) noexcept
106 {
107  const auto& outs = process_node->root_outputs();
108 
109  if(port_idx >= outs.size())
110  return;
111 
112  const ossia::outlet& outlet = *outs[port_idx];
113 
114  if(!outlet.target<ossia::audio_port>())
115  return;
116 
117  // Remove cables if depropagated, add cables if repropagated
118  if(is_propagated)
119  {
120  for(const ossia::graph_edge* edge : outlet.targets)
121  {
122  if(edge->in_node == interval_node)
123  return;
124  }
125 
126  auto cable = g.allocate_edge(
127  ossia::immediate_glutton_connection{}, outs[port_idx],
128  interval_node->root_inputs()[0], process_node, interval_node);
129  g.connect(cable);
130  }
131  else
132  {
133  for(ossia::graph_edge* edge : outlet.targets)
134  {
135  if(edge->in_node == interval_node)
136  {
137  g.disconnect(edge);
138  return;
139  }
140  }
141  }
142 }
143 
145 {
146  // Note : this looks a bit wtf, it is to handle RawPtrExecution
147  std::shared_ptr<ossia::time_interval> cst;
148  ossia::time_interval* cst_ptr{};
149  std::weak_ptr<ossia::time_process> oproc_weak;
150  std::weak_ptr<ossia::graph_interface> g_weak;
151  ossia::pod_vector<std::size_t> propagated_outlets;
152 
153  void operator()() const noexcept
154  {
155  auto oproc = oproc_weak.lock();
156  if(!oproc)
157  return;
158 
159  auto g = g_weak.lock();
160  if(!g)
161  return;
162 
163  cst_ptr->add_time_process(oproc);
164  if(!oproc->node)
165  return;
166 
167  connectPropagated(oproc->node, cst_ptr->node, *g, propagated_outlets);
168  }
169 };
170 
172 {
173  const Execution::Context& system;
174  Process::ProcessModel& proc;
175  std::weak_ptr<ossia::graph_node> cst_node_weak;
176  std::weak_ptr<ossia::time_process> oproc_weak;
177  std::weak_ptr<ossia::graph_interface> g_weak;
178  Process::Outlet* outlet{};
179 
180  void operator()(bool propagate) const noexcept
181  {
182 
183  // TODO find a better way !
184  auto port_index
185  = std::distance(proc.outlets().begin(), ossia::find(proc.outlets(), outlet));
186 
187  system.executionQueue.enqueue(
188  [cst_node_weak = this->cst_node_weak, g_weak = this->g_weak,
189  oproc_weak = this->oproc_weak, port_index, propagate] {
190  const auto g = g_weak.lock();
191  if(!g)
192  return;
193 
194  const auto cst_node = cst_node_weak.lock();
195  if(!cst_node)
196  return;
197 
198  const auto oproc = oproc_weak.lock();
199  if(!oproc)
200  return;
201 
202  const auto& proc_node = oproc->node;
203 
204  updatePropagated(proc_node, cst_node, *g, port_index, propagate);
205  });
206  }
207 };
208 
209 template <typename T>
211 {
212  T& component;
213  std::weak_ptr<ossia::graph_node> fw_node;
214 
215  Process::ProcessModel& proc;
216  std::weak_ptr<ossia::time_process> oproc_weak;
217 
218  std::weak_ptr<ossia::graph_interface> g_weak;
219 
220  void operator()() const noexcept
221  {
222  for(Process::Outlet* outlet : proc.outlets())
223  {
224  if(auto o = qobject_cast<Process::AudioOutlet*>(outlet))
225  {
226  QObject::disconnect(
227  o, &Process::AudioOutlet::propagateChanged, &component, nullptr);
228  QObject::connect(
229  o, &Process::AudioOutlet::propagateChanged, &component,
231  component.system(), proc, fw_node, oproc_weak, g_weak, outlet});
232  }
233  }
234  }
235 };
236 
238 {
239  std::weak_ptr<ossia::graph_node> cst_node_weak;
240  std::weak_ptr<ossia::time_process> oproc_weak;
241  std::weak_ptr<ossia::graph_interface> g_weak;
242  Process::ProcessModel& proc;
243 
244  void operator()(
245  const ossia::node_ptr& old_node, const ossia::node_ptr& new_node,
246  Execution::Transaction* commands) const noexcept
247  {
248 
249  commands->push_back(
250  [cst_node_weak = this->cst_node_weak, g_weak = this->g_weak,
251  propagated = propagatedOutlets(proc.outlets()), old_node, new_node] {
252  auto cst_node = cst_node_weak.lock();
253  if(!cst_node)
254  return;
255  auto g = g_weak.lock();
256  if(!g)
257  return;
258 
259  // Remove edges from the old node
260  if(old_node)
261  {
262  ossia::graph_node& n = *old_node;
263  for(auto& outlet : n.root_outputs())
264  {
265  auto targets = outlet->targets;
266  for(auto e : targets)
267  {
268  if(e->in_node.get() == cst_node.get())
269  {
270  g->disconnect(e);
271  }
272  }
273  }
274  }
275 
276  // Add edges to the new node
277  if(new_node)
278  {
279  connectPropagated(new_node, cst_node, *g, propagated);
280  }
281  });
282  }
283 };
284 
285 }
Definition: Port.hpp:273
The Process class.
Definition: score-lib-process/Process/Process.hpp:61
Definition: IntervalModel.hpp:50
Components used for the execution of a score.
Definition: ProcessComponent.cpp:12
Main plug-in of score.
Definition: score-plugin-dataflow/Dataflow/PortItem.hpp:14
Definition: IntervalExecutionHelpers.hpp:145
Definition: ExecutionContext.hpp:76
ExecutionCommandQueue & executionQueue
Definition: ExecutionContext.hpp:91
Execution::time_function time
Definition: ExecutionContext.hpp:87
Definition: IntervalExecutionHelpers.hpp:238
Definition: IntervalExecutionHelpers.hpp:172
Definition: IntervalExecutionHelpers.hpp:211
Definition: ExecutionTransaction.hpp:18
Definition: PortForward.hpp:27