MathMapping_generic.hpp
1 #pragma once
2 #include <Fx/MathHelpers.hpp>
3 #include <Fx/Types.hpp>
4 
5 #include <ossia/dataflow/value_port.hpp>
6 
7 #include <halp/callback.hpp>
8 namespace Nodes
9 {
10 template <typename State>
12 {
13  static void store_output(auto& self, const ossia::value& v)
14  {
15  switch(v.get_type())
16  {
17  case ossia::val_type::NONE:
18  break;
19  case ossia::val_type::FLOAT:
20  self.po = *v.target<float>();
21  break;
22  case ossia::val_type::VEC2F: {
23  if constexpr(requires { self.pov; })
24  {
25  auto& vec = *v.target<ossia::vec2f>();
26  self.pov.assign(vec.begin(), vec.end());
27  }
28  break;
29  }
30  case ossia::val_type::VEC3F: {
31  if constexpr(requires { self.pov; })
32  {
33  auto& vec = *v.target<ossia::vec3f>();
34  self.pov.assign(vec.begin(), vec.end());
35  }
36  break;
37  }
38  case ossia::val_type::VEC4F: {
39  if constexpr(requires { self.pov; })
40  {
41  auto& vec = *v.target<ossia::vec4f>();
42  self.pov.assign(vec.begin(), vec.end());
43  }
44  break;
45  }
46  case ossia::val_type::LIST: {
47  if constexpr(requires { self.pov; })
48  {
49  auto& arr = *v.target<std::vector<ossia::value>>();
50  if(!arr.empty())
51  {
52  self.pov.clear();
53  for(auto& v : arr)
54  self.pov.push_back(ossia::convert<float>(v));
55  }
56  }
57  break;
58  }
59  // Only these types are used now as per ossia::math_expression::result()
60  default:
61  break;
62  }
63  }
64 
65  static void exec_scalar(State& self, value_output_callback& output)
66  {
67  auto res = self.expr.result();
68 
69  self.px = self.x;
70  store_output(self, res);
71 
72  output(res);
73  }
74 
75  static void exec_polyphonic(State& self, value_output_callback& output)
76  {
77  for(auto& e : self.expressions)
78  {
79  auto res = e.expr.result();
80 
81  if constexpr(requires { e.x; })
82  e.px = e.x;
83 
84  store_output(e, res);
85  }
86  }
87 
88  static void
89  exec_array(State& self, value_output_callback& output, bool vector_size_did_change)
90  {
91  if(self.xv.empty())
92  return;
93 
94  if(vector_size_did_change)
95  {
96  self.expr.remove_vector("xv");
97  self.expr.add_vector("xv", self.xv);
98  self.expr.recompile();
99  }
100 
101  auto res = self.expr.result();
102  store_output(self, res);
103 
104  // Save the previous input
105  {
106  bool old_prev = self.pxv.size();
107  self.pxv.assign(self.xv.begin(), self.xv.end());
108  bool new_prev = self.pxv.size();
109 
110  if(old_prev != new_prev)
111  {
112  self.expr.remove_vector("pxv");
113  self.expr.add_vector("pxv", self.pxv);
114  self.expr.recompile();
115  }
116  }
117 
118  output(std::move(res));
119  }
120 
121  static void run_scalar(
122  const ossia::value& v, value_output_callback& output, const halp::tick_flicks& tk,
123  State& self)
124  {
125  //auto ratio = st.modelToSamples();
126  //auto parent_dur = tk.parent_duration * ratio;
127  //for(const ossia::timed_value& v : input.get_data())
128  //{
129  // int64_t new_time = tk.prev_date.impl * ratio + timestamp;
130  // setMathExpressionTiming(self, new_time, self.last_value_time, parent_dur);
131  // self.last_value_time = new_time;
132 
133  // FIXME
134  // setMathExpressionTiming(self, new_time, self.last_value_time, parent_dur);
135  switch(v.get_type())
136  {
137  case ossia::val_type::NONE:
138  break;
139  case ossia::val_type::IMPULSE:
140  break;
141  case ossia::val_type::INT:
142  self.x = *v.target<int>();
143  break;
144  case ossia::val_type::FLOAT:
145  self.x = *v.target<float>();
146  break;
147  case ossia::val_type::BOOL:
148  self.x = *v.target<bool>() ? 1.f : 0.f;
149  break;
150  case ossia::val_type::STRING:
151  self.x = ossia::convert<float>(v);
152  break;
153  case ossia::val_type::VEC2F:
154  self.x = (*v.target<ossia::vec2f>())[0];
155  break;
156  case ossia::val_type::VEC3F:
157  self.x = (*v.target<ossia::vec3f>())[0];
158  break;
159  case ossia::val_type::VEC4F:
160  self.x = (*v.target<ossia::vec4f>())[0];
161  break;
162  case ossia::val_type::LIST: {
163  auto& arr = *v.target<std::vector<ossia::value>>();
164  if(!arr.empty())
165  self.x = ossia::convert<float>(arr[0]);
166  break;
167  }
168  case ossia::val_type::MAP: {
169  auto& arr = *v.target<ossia::value_map_type>();
170  if(!arr.empty())
171  self.x = ossia::convert<float>(arr.begin()->second);
172  break;
173  }
174  }
175 
176  GenericMathMapping::exec_scalar(self, output);
177  }
178 
179  static bool resize(const std::string& expr, State& self, int sz)
180  {
181  if(std::ssize(self.expressions) == sz && expr == self.last_expression)
182  return true;
183 
184  self.expressions.resize(sz);
185  int i = 0;
186  for(auto& e : self.expressions)
187  {
188  e.init(self.cur_time, self.cur_deltatime, self.cur_pos);
189  e.instance = i++;
190  if(!e.expr.set_expression(expr))
191  return false;
192  e.expr.seed_random(
193  UINT64_C(0xda3e39cb94b95bdb), UINT64_C(0x853c49e6748fea9b) * (1 + i));
194  }
195  self.last_expression = expr;
196  return true;
197  }
198 
199  static void run_polyphonic(
200  int size, value_output_callback& output, const std::string& expr,
201  const halp::tick_flicks& tk, State& self)
202  {
203  resize(expr, self, size);
204 
205  setMathExpressionTiming(
206  self, tk.start_in_flicks, self.last_value_time, tk.relative_position);
207  self.last_value_time = tk.start_in_flicks;
208 
209  GenericMathMapping::exec_polyphonic(self, output);
210 
211  std::vector<ossia::value> res;
212  res.resize(self.expressions.size());
213  for(int i = 0; i < self.expressions.size(); i++)
214  res[i] = (float)self.expressions[i].po;
215 
216  // Combine
217  output(std::move(res));
218  }
219 
220  static void run_polyphonic(
221  const ossia::value& value, value_output_callback& output, const std::string& expr,
222  const halp::tick_flicks& tk, State& self)
223  {
224  setMathExpressionTiming(
225  self, tk.start_in_flicks, self.last_value_time, tk.relative_position);
226  self.last_value_time = tk.start_in_flicks;
227  //auto ratio = st.modelToSamples();
228  //auto parent_dur = tk.parent_duration.impl * ratio;
229  //for(const ossia::timed_value& v : input.get_data())
230  //{
231  // auto val = value.target<std::vector<ossia::value>>();
232  // if(!val)
233  // return;
234 
235  // int64_t new_time = tk.prev_date.impl * ratio + timestamp;
236  // setMathExpressionTiming(self, new_time, self.last_value_time, parent_dur);
237  // self.last_value_time = new_time;
238 
239  switch(value.get_type())
240  {
241  case ossia::val_type::NONE:
242  break;
243  case ossia::val_type::IMPULSE:
244  break;
245  case ossia::val_type::INT:
246  if(!resize(expr, self, 1))
247  return;
248  self.expressions[0].x = *value.target<int>();
249  break;
250  case ossia::val_type::FLOAT:
251  if(!resize(expr, self, 1))
252  return;
253  self.expressions[0].x = *value.target<float>();
254  break;
255  case ossia::val_type::BOOL:
256  if(!resize(expr, self, 1))
257  return;
258  self.expressions[0].x = *value.target<bool>() ? 1.f : 0.f;
259  break;
260  case ossia::val_type::STRING:
261  if(!resize(expr, self, 1))
262  return;
263  self.expressions[0].x = ossia::convert<float>(value);
264  break;
265  case ossia::val_type::VEC2F:
266  if(!resize(expr, self, 2))
267  return;
268  self.expressions[0].x = (*value.target<ossia::vec2f>())[0];
269  self.expressions[1].x = (*value.target<ossia::vec2f>())[1];
270  break;
271  case ossia::val_type::VEC3F:
272  if(!resize(expr, self, 3))
273  return;
274  self.expressions[0].x = (*value.target<ossia::vec3f>())[0];
275  self.expressions[1].x = (*value.target<ossia::vec3f>())[1];
276  self.expressions[2].x = (*value.target<ossia::vec3f>())[2];
277  break;
278  case ossia::val_type::VEC4F:
279  if(!resize(expr, self, 4))
280  return;
281  self.expressions[0].x = (*value.target<ossia::vec4f>())[0];
282  self.expressions[1].x = (*value.target<ossia::vec4f>())[1];
283  self.expressions[2].x = (*value.target<ossia::vec4f>())[2];
284  self.expressions[3].x = (*value.target<ossia::vec4f>())[3];
285  break;
286  case ossia::val_type::LIST: {
287  auto& arr = *value.target<std::vector<ossia::value>>();
288  const auto N = std::ssize(arr);
289  if(!resize(expr, self, N))
290  return;
291  for(int i = 0; i < N; i++)
292  self.expressions[i].x = ossia::convert<float>(arr[i]);
293  break;
294  }
295  case ossia::val_type::MAP: {
296  auto& arr = *value.target<ossia::value_map_type>();
297  const auto N = std::ssize(arr);
298  if(!resize(expr, self, N))
299  return;
300  int i = 0;
301  for(auto& [k, v] : arr)
302  self.expressions[i++].x = ossia::convert<float>(v);
303  break;
304  }
305  }
306 
307  GenericMathMapping::exec_polyphonic(self, output);
308 
309  std::vector<ossia::value> res;
310  res.resize(self.expressions.size());
311  for(int i = 0; i < self.expressions.size(); i++)
312  res[i] = (float)self.expressions[i].po;
313 
314  // Combine
315  output(std::move(res));
316  }
317 
318  static void run_array(
319  const ossia::value& value, value_output_callback& output,
320  const halp::tick_flicks& tk, State& self)
321  {
322  //auto ratio = st.modelToSamples();
323  //auto parent_dur = tk.parent_duration.impl * ratio;
324  //for(const ossia::timed_value& v : input.get_data())
325  //{
326  // int64_t new_time = tk.prev_date.impl * ratio + timestamp;
327  // setMathExpressionTiming(self, new_time, self.last_value_time, parent_dur);
328  // self.last_value_time = new_time;
329 
330  auto array_run_scalar = [&](float in) {
331  auto old_size = self.xv.size();
332  self.xv.assign(1, in);
333  auto new_size = 1U;
334  GenericMathMapping::exec_array(self, output, old_size != new_size);
335  };
336 
337  switch(value.get_type())
338  {
339  case ossia::val_type::NONE:
340  break;
341  case ossia::val_type::IMPULSE:
342  GenericMathMapping::exec_array(self, output, false);
343  break;
344  case ossia::val_type::INT:
345  array_run_scalar(*value.target<int>());
346  break;
347  case ossia::val_type::FLOAT:
348  array_run_scalar(*value.target<float>());
349  break;
350  case ossia::val_type::BOOL:
351  array_run_scalar(*value.target<bool>() ? 1.f : 0.f);
352  break;
353  case ossia::val_type::STRING:
354  array_run_scalar(ossia::convert<float>(value));
355  break;
356  case ossia::val_type::VEC2F: {
357  auto& arr = *value.target<ossia::vec2f>();
358  auto old_size = self.xv.size();
359  self.xv.assign(arr.begin(), arr.end());
360  auto new_size = 2U;
361  GenericMathMapping::exec_array(self, output, old_size != new_size);
362  break;
363  }
364  case ossia::val_type::VEC3F: {
365  auto& arr = *value.target<ossia::vec3f>();
366  auto old_size = self.xv.size();
367  self.xv.assign(arr.begin(), arr.end());
368  auto new_size = 3U;
369  GenericMathMapping::exec_array(self, output, old_size != new_size);
370  break;
371  }
372  case ossia::val_type::VEC4F: {
373  auto& arr = *value.target<ossia::vec4f>();
374  auto old_size = self.xv.size();
375  self.xv.assign(arr.begin(), arr.end());
376  auto new_size = 4U;
377  GenericMathMapping::exec_array(self, output, old_size != new_size);
378  break;
379  }
380  case ossia::val_type::LIST: {
381  auto& arr = *value.target<std::vector<ossia::value>>();
382  auto old_size = self.xv.size();
383  self.xv.resize(arr.size());
384  auto new_size = arr.size();
385  for(std::size_t i = 0; i < arr.size(); i++)
386  {
387  self.xv[i] = ossia::convert<float>(arr[i]);
388  }
389  GenericMathMapping::exec_array(self, output, old_size != new_size);
390  break;
391  }
392  case ossia::val_type::MAP: {
393  auto& arr = *value.target<ossia::value_map_type>();
394  auto old_size = self.xv.size();
395  self.xv.resize(arr.size());
396  auto new_size = arr.size();
397  int i = 0;
398  for(const auto& [k, v] : arr)
399  {
400  self.xv[i++] = ossia::convert<float>(v);
401  }
402  GenericMathMapping::exec_array(self, output, old_size != new_size);
403  break;
404  }
405  }
406  //}
407  }
408 };
409 }
Utilities for OSSIA data structures.
Definition: DeviceInterface.hpp:33
Definition: MathMapping_generic.hpp:12