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  if(size <= 1
204  || (expr.find(":=") != std::string::npos && expr.find("po") != std::string::npos))
205  {
206  resize(expr, self, size);
207 
208  setMathExpressionTiming(
209  self, tk.start_in_flicks, self.last_value_time, tk.relative_position);
210  self.last_value_time = tk.start_in_flicks;
211 
212  GenericMathMapping::exec_polyphonic(self, output);
213 
214  std::vector<ossia::value> res;
215  res.resize(self.expressions.size());
216  for(int i = 0; i < self.expressions.size(); i++)
217  res[i] = (float)self.expressions[i].po;
218  // Combine
219  output(std::move(res));
220  }
221  else
222  {
223  resize(expr, self, 1);
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 
228  std::vector<ossia::value> res;
229  res.resize(size);
230  for(int i = 0; i < size; i++)
231  {
232  auto& e = self.expressions[0];
233  e.instance = i;
234  res[i] = e.expr.result();
235 
236  // po isn't used either store_output(e, res);
237  }
238  output(std::move(res));
239  }
240  }
241 
242  static void run_polyphonic(
243  const ossia::value& value, value_output_callback& output, const std::string& expr,
244  const halp::tick_flicks& tk, State& self)
245  {
246  setMathExpressionTiming(
247  self, tk.start_in_flicks, self.last_value_time, tk.relative_position);
248  self.last_value_time = tk.start_in_flicks;
249  //auto ratio = st.modelToSamples();
250  //auto parent_dur = tk.parent_duration.impl * ratio;
251  //for(const ossia::timed_value& v : input.get_data())
252  //{
253  // auto val = value.target<std::vector<ossia::value>>();
254  // if(!val)
255  // return;
256 
257  // int64_t new_time = tk.prev_date.impl * ratio + timestamp;
258  // setMathExpressionTiming(self, new_time, self.last_value_time, parent_dur);
259  // self.last_value_time = new_time;
260 
261  switch(value.get_type())
262  {
263  case ossia::val_type::NONE:
264  break;
265  case ossia::val_type::IMPULSE:
266  break;
267  case ossia::val_type::INT:
268  if(!resize(expr, self, 1))
269  return;
270  self.expressions[0].x = *value.target<int>();
271  break;
272  case ossia::val_type::FLOAT:
273  if(!resize(expr, self, 1))
274  return;
275  self.expressions[0].x = *value.target<float>();
276  break;
277  case ossia::val_type::BOOL:
278  if(!resize(expr, self, 1))
279  return;
280  self.expressions[0].x = *value.target<bool>() ? 1.f : 0.f;
281  break;
282  case ossia::val_type::STRING:
283  if(!resize(expr, self, 1))
284  return;
285  self.expressions[0].x = ossia::convert<float>(value);
286  break;
287  case ossia::val_type::VEC2F:
288  if(!resize(expr, self, 2))
289  return;
290  self.expressions[0].x = (*value.target<ossia::vec2f>())[0];
291  self.expressions[1].x = (*value.target<ossia::vec2f>())[1];
292  break;
293  case ossia::val_type::VEC3F:
294  if(!resize(expr, self, 3))
295  return;
296  self.expressions[0].x = (*value.target<ossia::vec3f>())[0];
297  self.expressions[1].x = (*value.target<ossia::vec3f>())[1];
298  self.expressions[2].x = (*value.target<ossia::vec3f>())[2];
299  break;
300  case ossia::val_type::VEC4F:
301  if(!resize(expr, self, 4))
302  return;
303  self.expressions[0].x = (*value.target<ossia::vec4f>())[0];
304  self.expressions[1].x = (*value.target<ossia::vec4f>())[1];
305  self.expressions[2].x = (*value.target<ossia::vec4f>())[2];
306  self.expressions[3].x = (*value.target<ossia::vec4f>())[3];
307  break;
308  case ossia::val_type::LIST: {
309  auto& arr = *value.target<std::vector<ossia::value>>();
310  const auto N = std::ssize(arr);
311  if(!resize(expr, self, N))
312  return;
313  for(int i = 0; i < N; i++)
314  self.expressions[i].x = ossia::convert<float>(arr[i]);
315  break;
316  }
317  case ossia::val_type::MAP: {
318  auto& arr = *value.target<ossia::value_map_type>();
319  const auto N = std::ssize(arr);
320  if(!resize(expr, self, N))
321  return;
322  int i = 0;
323  for(auto& [k, v] : arr)
324  self.expressions[i++].x = ossia::convert<float>(v);
325  break;
326  }
327  }
328 
329  GenericMathMapping::exec_polyphonic(self, output);
330 
331  std::vector<ossia::value> res;
332  res.resize(self.expressions.size());
333  for(int i = 0; i < self.expressions.size(); i++)
334  res[i] = (float)self.expressions[i].po;
335 
336  // Combine
337  output(std::move(res));
338  }
339 
340  static void run_array(
341  const ossia::value& value, value_output_callback& output,
342  const halp::tick_flicks& tk, State& self)
343  {
344  //auto ratio = st.modelToSamples();
345  //auto parent_dur = tk.parent_duration.impl * ratio;
346  //for(const ossia::timed_value& v : input.get_data())
347  //{
348  // int64_t new_time = tk.prev_date.impl * ratio + timestamp;
349  // setMathExpressionTiming(self, new_time, self.last_value_time, parent_dur);
350  // self.last_value_time = new_time;
351 
352  auto array_run_scalar = [&](float in) {
353  auto old_size = self.xv.size();
354  self.xv.assign(1, in);
355  auto new_size = 1U;
356  GenericMathMapping::exec_array(self, output, old_size != new_size);
357  };
358 
359  switch(value.get_type())
360  {
361  case ossia::val_type::NONE:
362  break;
363  case ossia::val_type::IMPULSE:
364  GenericMathMapping::exec_array(self, output, false);
365  break;
366  case ossia::val_type::INT:
367  array_run_scalar(*value.target<int>());
368  break;
369  case ossia::val_type::FLOAT:
370  array_run_scalar(*value.target<float>());
371  break;
372  case ossia::val_type::BOOL:
373  array_run_scalar(*value.target<bool>() ? 1.f : 0.f);
374  break;
375  case ossia::val_type::STRING:
376  array_run_scalar(ossia::convert<float>(value));
377  break;
378  case ossia::val_type::VEC2F: {
379  auto& arr = *value.target<ossia::vec2f>();
380  auto old_size = self.xv.size();
381  self.xv.assign(arr.begin(), arr.end());
382  auto new_size = 2U;
383  GenericMathMapping::exec_array(self, output, old_size != new_size);
384  break;
385  }
386  case ossia::val_type::VEC3F: {
387  auto& arr = *value.target<ossia::vec3f>();
388  auto old_size = self.xv.size();
389  self.xv.assign(arr.begin(), arr.end());
390  auto new_size = 3U;
391  GenericMathMapping::exec_array(self, output, old_size != new_size);
392  break;
393  }
394  case ossia::val_type::VEC4F: {
395  auto& arr = *value.target<ossia::vec4f>();
396  auto old_size = self.xv.size();
397  self.xv.assign(arr.begin(), arr.end());
398  auto new_size = 4U;
399  GenericMathMapping::exec_array(self, output, old_size != new_size);
400  break;
401  }
402  case ossia::val_type::LIST: {
403  auto& arr = *value.target<std::vector<ossia::value>>();
404  auto old_size = self.xv.size();
405  self.xv.resize(arr.size());
406  auto new_size = arr.size();
407  for(std::size_t i = 0; i < arr.size(); i++)
408  {
409  self.xv[i] = ossia::convert<float>(arr[i]);
410  }
411  GenericMathMapping::exec_array(self, output, old_size != new_size);
412  break;
413  }
414  case ossia::val_type::MAP: {
415  auto& arr = *value.target<ossia::value_map_type>();
416  auto old_size = self.xv.size();
417  self.xv.resize(arr.size());
418  auto new_size = arr.size();
419  int i = 0;
420  for(const auto& [k, v] : arr)
421  {
422  self.xv[i++] = ossia::convert<float>(v);
423  }
424  GenericMathMapping::exec_array(self, output, old_size != new_size);
425  break;
426  }
427  }
428  //}
429  }
430 };
431 }
Utilities for OSSIA data structures.
Definition: DeviceInterface.hpp:33
Definition: MathMapping_generic.hpp:12