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