Loading...
Searching...
No Matches
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
23namespace Execution
24{
25
26inline std::pair<std::optional<ossia::tempo_curve>, Scenario::TempoProcess*>
27tempoCurve(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}
59inline ossia::time_signature_map
60timeSignatureMap(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
70inline 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
82inline 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
103inline 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;
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
209template <typename T>
211{
212 T& component;
213 std::weak_ptr<ossia::graph_node> fw_node;
214
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;
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:13
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