score-plugin-engine/Engine/Node/Executor.hpp
1 #pragma once
2 #include <Process/Execution/ProcessComponent.hpp>
3 #include <Process/ExecutionContext.hpp>
4 
5 #include <Explorer/DeviceList.hpp>
6 #include <Explorer/DocumentPlugin/DeviceDocumentPlugin.hpp>
7 
8 #include <Engine/Node/Process.hpp>
9 #include <Engine/Node/TickPolicy.hpp>
10 
11 #include <score/tools/Bind.hpp>
12 
13 #include <ossia/dataflow/safe_nodes/executor.hpp>
14 
15 #include <QTimer>
16 
17 namespace Control
18 {
19 
20 template <typename Info_T, typename Node_T, typename Element>
22 {
23  Element& element;
24  const Execution::Context& ctx;
25  const std::shared_ptr<Node_T>& node_ptr;
26  QObject* parent;
27 
28  template <typename Idx_T>
30  {
31  const Execution::Context& ctx;
32  std::weak_ptr<Node_T> weak_node;
33  void operator()(const ossia::value& val)
34  {
35  using namespace ossia::safe_nodes;
36  constexpr auto idx = Idx_T::value;
37 
38  using control_type =
39  typename std::tuple_element<idx, decltype(Info_T::Metadata::controls)>::type;
40  using control_value_type = typename control_type::type;
41 
42  if(auto node = weak_node.lock())
43  {
44  constexpr const auto ctrl = tuplet::get<idx>(Info_T::Metadata::controls);
45  if(auto v = ctrl.fromValue(val))
46  ctx.executionQueue.enqueue(control_updater<control_value_type>{
47  tuplet::get<idx>(node->controls), std::move(*v)});
48  }
49  }
50  };
51 
52  template <typename Idx_T>
54  {
55  const Execution::Context& ctx;
56  std::weak_ptr<Node_T> weak_node;
57  void operator()(const ossia::value& val)
58  {
59  using namespace ossia::safe_nodes;
60  constexpr auto idx = Idx_T::value;
61 
62  using control_type =
63  typename std::tuple_element<idx, decltype(Info_T::Metadata::controls)>::type;
64  using control_value_type = typename control_type::type;
65 
66  if(auto node = weak_node.lock())
67  {
68  constexpr const auto ctrl = tuplet::get<idx>(Info_T::Metadata::controls);
69  ctx.executionQueue.enqueue(control_updater<control_value_type>{
70  tuplet::get<idx>(node->controls), ctrl.fromValue(val)});
71  }
72  }
73  };
74 
75  template <typename T>
76  void operator()(T)
77  {
78  using namespace ossia::safe_nodes;
79  using Info = Info_T;
80  constexpr int idx = T::value;
81 
82  constexpr const auto ctrl = tuplet::get<idx>(Info_T::Metadata::controls);
83  constexpr const auto control_start = info_functions<Info>::control_start;
84  using control_type =
85  typename std::tuple_element<idx, decltype(Info_T::Metadata::controls)>::type;
86  auto inlet
87  = static_cast<Process::ControlInlet*>(element.inlets()[control_start + idx]);
88 
89  auto& node = *node_ptr;
90  std::weak_ptr<Node_T> weak_node = node_ptr;
91 
92  if constexpr(control_type::must_validate)
93  {
94  if(auto res = ctrl.fromValue(element.control(idx)))
95  tuplet::get<idx>(node.controls) = *res;
96 
97  QObject::connect(
98  inlet, &Process::ControlInlet::valueChanged, parent,
99  con_validated<T>{ctx, weak_node});
100  }
101  else
102  {
103  tuplet::get<idx>(node.controls) = ctrl.fromValue(element.control(idx));
104 
105  QObject::connect(
106  inlet, &Process::ControlInlet::valueChanged, parent,
107  con_unvalidated<T>{ctx, weak_node});
108  }
109  }
110 };
111 
112 template <typename Info, typename Element, typename Node_T>
114 {
115  typename Node_T::controls_values_type& arr;
116  Element& element;
117 
118  template <typename T>
119  void operator()(T)
120  {
121  using namespace ossia::safe_nodes;
122  using namespace std;
123  using namespace tuplet;
124  constexpr const auto ctrl = tuplet::get<T::value>(Info::Metadata::controls);
125 
126  element.setControl(T::value, ctrl.toValue(get<T::value>(arr)));
127  }
128 };
129 
130 template <typename Info, typename Element, typename Node_T>
132 {
133  typename Node_T::control_outs_values_type& arr;
134  Element& element;
135 
136  template <typename T>
137  void operator()(T)
138  {
139  using namespace ossia::safe_nodes;
140  using namespace std;
141  using namespace tuplet;
142  constexpr const auto ctrl = tuplet::get<T::value>(Info::Metadata::control_outs);
143 
144  element.setControlOut(T::value, ctrl.toValue(get<T::value>(arr)));
145  }
146 };
147 
148 template <typename Info, typename Node_T, typename Element_T>
150 {
151  std::weak_ptr<Node_T> weak_node;
152  Element_T& element;
153 
154  void handle_controls(Node_T& node) const noexcept
155  {
156  using namespace ossia::safe_nodes;
157  // TODO disconnect the connection ? it will be disconnected shortly
158  // after...
159  typename Node_T::controls_values_type arr;
160  bool ok = false;
161  while(node.cqueue.try_dequeue(arr))
162  {
163  ok = true;
164  }
165  if(ok)
166  {
167  constexpr const auto control_count = info_functions<Info>::control_count;
168 
169  ossia::for_each_in_range<control_count>(
171  }
172  }
173 
174  void handle_control_outs(Node_T& node) const noexcept
175  {
176  using namespace ossia::safe_nodes;
177  // TODO disconnect the connection ? it will be disconnected shortly
178  // after...
179  typename Node_T::control_outs_values_type arr;
180  bool ok = false;
181  while(node.control_outs_queue.try_dequeue(arr))
182  {
183  ok = true;
184  }
185  if(ok)
186  {
187  constexpr const auto control_out_count = info_functions<Info>::control_out_count;
188 
189  ossia::for_each_in_range<control_out_count>(
191  }
192  }
193 
194  void operator()() const noexcept
195  {
196  using namespace ossia::safe_nodes;
197  if(auto node = weak_node.lock())
198  {
199  if constexpr(info_functions<Info>::control_count > 0)
200  handle_controls(*node);
201 
202  if constexpr(info_functions<Info>::control_out_count > 0)
203  handle_control_outs(*node);
204  }
205  }
206 };
207 
208 template <typename Info, typename Node_T, typename Element_T>
209 void setup_node(
210  const std::shared_ptr<Node_T>& node_ptr, Element_T& element,
211  const Execution::Context& ctx, QObject* parent)
212 {
213  using namespace ossia::safe_nodes;
214 
215  (void)parent;
216  if constexpr(info_functions<Info>::control_count > 0)
217  {
218  // Initialize all the controls in the node with the current value.
219  //
220  // And update the node when the UI changes
221  ossia::for_each_in_range<info_functions<Info>::control_count>(
222  setup_Impl0<Info, Node_T, Element_T>{element, ctx, node_ptr, parent});
223  }
224 
225  if constexpr(
226  info_functions<Info>::control_count > 0
227  || info_functions<Info>::control_out_count > 0)
228  {
229  // Update the value in the UI
230  std::weak_ptr<Node_T> weak_node = node_ptr;
231  con(ctx.doc.coarseUpdateTimer, &QTimer::timeout, parent,
232  ExecutorGuiUpdate<Info, Node_T, Element_T>{weak_node, element},
233  Qt::QueuedConnection);
234  }
235 }
236 
237 template <typename Info>
238 class Executor final
239  : public Execution::ProcessComponent_T<ControlProcess<Info>, ossia::node_process>
240 {
241 public:
242  static Q_DECL_RELAXED_CONSTEXPR UuidKey<score::Component> static_key() noexcept
243  {
244  return Info::Metadata::uuid;
245  }
246 
247  UuidKey<score::Component> key() const noexcept final override { return static_key(); }
248 
249  bool key_match(UuidKey<score::Component> other) const noexcept final override
250  {
251  return static_key() == other || Execution::ProcessComponent::base_key_match(other);
252  }
253 
254  Executor(
255  ControlProcess<Info>& element, const ::Execution::Context& ctx, QObject* parent)
257  element, ctx, "Executor::ControlProcess<Info>", parent}
258  {
259  std::shared_ptr<ossia::safe_nodes::safe_node<Info>> n{
260  new ossia::safe_nodes::safe_node<Info>};
261  n->prepare(*ctx.execState.get());
262  this->node = n;
263  this->m_ossia_process = std::make_shared<ossia::node_process>(this->node);
264 
265  setup_node<Info>(n, element, ctx, this);
266  }
267 
268  ~Executor() { }
269 };
270 }
Definition: score-plugin-engine/Engine/Node/Process.hpp:319
Definition: score-plugin-engine/Engine/Node/Executor.hpp:240
Definition: score-lib-process/Process/Dataflow/Port.hpp:202
Definition: UuidKey.hpp:343
Definition: score-plugin-engine/Engine/Node/Executor.hpp:150
Definition: score-plugin-engine/Engine/Node/Executor.hpp:54
Definition: score-plugin-engine/Engine/Node/Executor.hpp:30
Definition: score-plugin-engine/Engine/Node/Executor.hpp:22
Definition: score-plugin-engine/Engine/Node/Executor.hpp:132
Definition: score-plugin-engine/Engine/Node/Executor.hpp:114
Definition: ExecutionContext.hpp:75
ExecutionCommandQueue & executionQueue
Definition: ExecutionContext.hpp:90
Definition: Process/Execution/ProcessComponent.hpp:89