2 #include <Fx/MathGenerator.hpp>
6 template <
typename State>
9 static void store_output(
State&
self,
const ossia::value& v)
13 case ossia::val_type::NONE:
15 case ossia::val_type::FLOAT:
16 self.po = *v.target<
float>();
18 case ossia::val_type::VEC2F: {
19 auto& vec = *v.target<ossia::vec2f>();
20 self.pov.assign(vec.begin(), vec.end());
23 case ossia::val_type::VEC3F: {
24 auto& vec = *v.target<ossia::vec3f>();
25 self.pov.assign(vec.begin(), vec.end());
28 case ossia::val_type::VEC4F: {
29 auto& vec = *v.target<ossia::vec4f>();
30 self.pov.assign(vec.begin(), vec.end());
33 case ossia::val_type::LIST: {
34 auto& arr = *v.target<std::vector<ossia::value>>();
39 self.pov.push_back(ossia::convert<float>(v));
49 static void exec_scalar(int64_t timestamp,
State&
self, ossia::value_port& output)
51 auto res =
self.expr.result();
54 store_output(
self, res);
56 output.write_value(res, timestamp);
59 static void exec_array(
60 int64_t timestamp,
State&
self, ossia::value_port& output,
61 bool vector_size_did_change)
66 if(vector_size_did_change)
68 self.expr.remove_vector(
"xv");
69 self.expr.add_vector(
"xv",
self.xv);
70 self.expr.recompile();
73 auto res =
self.expr.result();
74 store_output(
self, res);
78 bool old_prev =
self.pxv.size();
79 self.pxv.assign(
self.xv.begin(),
self.xv.end());
80 bool new_prev =
self.pxv.size();
82 if(old_prev != new_prev)
84 self.expr.remove_vector(
"pxv");
85 self.expr.add_vector(
"pxv",
self.pxv);
86 self.expr.recompile();
90 output.write_value(std::move(res), timestamp);
93 static void run_scalar(
94 const ossia::value_port& input, ossia::value_port& output,
95 const ossia::token_request& tk, ossia::exec_state_facade st,
State&
self)
97 auto ratio = st.modelToSamples();
98 auto parent_dur = tk.parent_duration.impl * ratio;
99 for(
const ossia::timed_value& v : input.get_data())
101 int64_t new_time = tk.prev_date.impl * ratio + v.timestamp;
102 setMathExpressionTiming(
self, new_time,
self.last_value_time, parent_dur);
103 self.last_value_time = new_time;
105 switch(v.value.get_type())
107 case ossia::val_type::NONE:
109 case ossia::val_type::IMPULSE:
111 case ossia::val_type::INT:
112 self.x = *v.value.target<
int>();
114 case ossia::val_type::FLOAT:
115 self.x = *v.value.target<
float>();
117 case ossia::val_type::BOOL:
118 self.x = *v.value.target<
bool>() ? 1.f : 0.f;
120 case ossia::val_type::STRING:
121 self.x = ossia::convert<float>(v.value);
123 case ossia::val_type::VEC2F:
124 self.x = (*v.value.target<ossia::vec2f>())[0];
126 case ossia::val_type::VEC3F:
127 self.x = (*v.value.target<ossia::vec3f>())[0];
129 case ossia::val_type::VEC4F:
130 self.x = (*v.value.target<ossia::vec4f>())[0];
132 case ossia::val_type::LIST: {
133 auto& arr = *v.value.target<std::vector<ossia::value>>();
135 self.x = ossia::convert<float>(arr[0]);
140 GenericMathMapping::exec_scalar(v.timestamp,
self, output);
144 static void run_array(
145 const ossia::value_port& input, ossia::value_port& output,
146 const ossia::token_request& tk, ossia::exec_state_facade st,
State&
self)
148 auto ratio = st.modelToSamples();
149 auto parent_dur = tk.parent_duration.impl * ratio;
150 for(
const ossia::timed_value& v : input.get_data())
152 int64_t new_time = tk.prev_date.impl * ratio + v.timestamp;
153 setMathExpressionTiming(
self, new_time,
self.last_value_time, parent_dur);
154 self.last_value_time = new_time;
156 auto array_run_scalar = [&](
float in) {
157 auto old_size =
self.xv.size();
158 self.xv.assign(1, in);
160 GenericMathMapping::exec_array(v.timestamp,
self, output, old_size != new_size);
163 switch(v.value.get_type())
165 case ossia::val_type::NONE:
167 case ossia::val_type::IMPULSE:
168 GenericMathMapping::exec_array(v.timestamp,
self, output,
false);
170 case ossia::val_type::INT:
171 array_run_scalar(*v.value.target<
int>());
173 case ossia::val_type::FLOAT:
174 array_run_scalar(*v.value.target<
float>());
176 case ossia::val_type::BOOL:
177 array_run_scalar(*v.value.target<
bool>() ? 1.f : 0.f);
179 case ossia::val_type::STRING:
180 array_run_scalar(ossia::convert<float>(v.value));
182 case ossia::val_type::VEC2F: {
183 auto& arr = *v.value.target<ossia::vec2f>();
184 auto old_size =
self.xv.size();
185 self.xv.assign(arr.begin(), arr.end());
187 GenericMathMapping::exec_array(
188 v.timestamp,
self, output, old_size != new_size);
191 case ossia::val_type::VEC3F: {
192 auto& arr = *v.value.target<ossia::vec3f>();
193 auto old_size =
self.xv.size();
194 self.xv.assign(arr.begin(), arr.end());
196 GenericMathMapping::exec_array(
197 v.timestamp,
self, output, old_size != new_size);
200 case ossia::val_type::VEC4F: {
201 auto& arr = *v.value.target<ossia::vec4f>();
202 auto old_size =
self.xv.size();
203 self.xv.assign(arr.begin(), arr.end());
205 GenericMathMapping::exec_array(
206 v.timestamp,
self, output, old_size != new_size);
209 case ossia::val_type::LIST: {
210 auto& arr = *v.value.target<std::vector<ossia::value>>();
211 auto old_size =
self.xv.size();
212 self.xv.resize(arr.size());
213 auto new_size = arr.size();
214 for(std::size_t i = 0; i < arr.size(); i++)
216 self.xv[i] = ossia::convert<float>(arr[i]);
218 GenericMathMapping::exec_array(
219 v.timestamp,
self, output, old_size != new_size);
227 namespace MathMapping
233 static const constexpr
auto prettyName =
"Expression Value Filter";
234 static const constexpr
auto objectKey =
"MathMapping";
235 static const constexpr
auto category =
"Control/Mappings";
236 static const constexpr
auto author =
"ossia score, ExprTK (Arash Partow)";
237 static const constexpr
auto kind = Process::ProcessCategory::Mapping;
238 static const constexpr
auto description
239 =
"Applies a math expression to an input.\n"
240 "Available variables: a,b,c, t (samples), dt (delta), pos (position "
241 "in parent), x (value)\n"
242 "See the documentation at http://www.partow.net/programming/exprtk";
243 static const constexpr
auto tags = std::array<const char*, 0>{};
244 static const uuid_constexpr
auto uuid
245 = make_uuid(
"ae84e8b6-74ff-4259-aeeb-305d95cdfcab");
247 static const constexpr value_in value_ins[]{value_in{
"in",
false}};
248 static const constexpr value_out value_outs[]{
"out"};
250 static const constexpr
auto controls = tuplet::make_tuple(
263 expr.add_vector(
"xv", xv);
264 expr.add_vector(
"pxv", pxv);
265 expr.add_vector(
"pov", pov);
267 expr.add_variable(
"x", x);
268 expr.add_variable(
"px", px);
269 expr.add_variable(
"po", po);
271 expr.add_variable(
"t", cur_time);
272 expr.add_variable(
"dt", cur_deltatime);
273 expr.add_variable(
"pos", cur_pos);
274 expr.add_variable(
"fs", fs);
276 expr.add_variable(
"a", a);
277 expr.add_variable(
"b", b);
278 expr.add_variable(
"c", c);
279 expr.add_variable(
"pa", pa);
280 expr.add_variable(
"pb", pb);
281 expr.add_variable(
"pc", pc);
283 expr.add_variable(
"m1", m1);
284 expr.add_variable(
"m2", m2);
285 expr.add_variable(
"m3", m3);
286 expr.add_constants();
288 expr.register_symbol_table();
290 std::vector<double> xv;
291 std::vector<double> pxv;
292 std::vector<double> pov;
299 double cur_deltatime{};
303 double a{}, b{}, c{};
304 double pa{}, pb{}, pc{};
306 double m1{}, m2{}, m3{};
308 ossia::math_expression expr;
309 int64_t last_value_time{};
314 using control_policy = ossia::safe_nodes::last_tick;
316 run(
const ossia::value_port& input,
const std::string& expr,
float a,
float b,
float c,
317 ossia::value_port& output, ossia::token_request tk, ossia::exec_state_facade st,
320 if(!
self.expr.set_expression(expr))
326 self.fs = st.sampleRate();
328 if(
self.expr.has_variable(
"xv"))
338 template <
typename... Args>
339 static void item(Args&&... args)
341 Nodes::mathItem(Metadata::controls, std::forward<Args>(args)...);
346 namespace MathAudioFilter
352 static const constexpr
auto prettyName =
"Expression Audio Filter";
353 static const constexpr
auto objectKey =
"MathAudioFilter";
354 static const constexpr
auto category =
"Audio/Utilities";
355 static const constexpr
auto author =
"ossia score, ExprTK (Arash Partow)";
356 static const constexpr
auto tags = std::array<const char*, 0>{};
357 static const constexpr
auto kind = Process::ProcessCategory::AudioEffect;
358 static const constexpr
auto description
359 =
"Applies a math expression to an audio input.\n"
360 "Available variables: a,b,c, t (samples), fs (sampling frequency), "
362 "x (value), px (previous value)\n"
363 "See the documentation at http://www.partow.net/programming/exprtk";
364 static const uuid_constexpr
auto uuid
365 = make_uuid(
"13e1f4b0-1c2c-40e6-93ad-dfc91aac5335");
367 static const constexpr audio_in audio_ins[]{
"in"};
368 static const constexpr audio_out audio_outs[]{
"out"};
370 static const constexpr
auto controls = tuplet::make_tuple(
372 "Expression (ExprTK)",
375 "for (var i := 0; i < n; i += 1) {\n"
376 " var dist := tan(x[i]*log(1 + 200 * a));\n"
377 " out[i] := clamp(-1, dist, 1);\n"
401 expr.add_vector(
"x", cur_in);
402 expr.add_vector(
"out", cur_out);
403 expr.add_vector(
"px", prev_in);
404 expr.add_variable(
"t", cur_time);
405 expr.add_variable(
"a", p1);
406 expr.add_variable(
"b", p2);
407 expr.add_variable(
"c", p3);
408 expr.add_vector(
"m1", m1);
409 expr.add_vector(
"m2", m2);
410 expr.add_vector(
"m3", m3);
411 expr.add_variable(
"fs", fs);
412 expr.add_constants();
414 expr.register_symbol_table();
417 void reset_symbols(std::size_t N)
419 if(N == cur_in.size())
422 expr.remove_vector(
"x");
423 expr.remove_vector(
"out");
424 expr.remove_vector(
"px");
425 expr.remove_vector(
"m1");
426 expr.remove_vector(
"m2");
427 expr.remove_vector(
"m3");
436 expr.add_vector(
"x", cur_in);
437 expr.add_vector(
"out", cur_out);
438 expr.add_vector(
"px", prev_in);
439 expr.add_vector(
"m1", m1);
440 expr.add_vector(
"m2", m2);
441 expr.add_vector(
"m3", m3);
443 expr.update_symbol_table();
446 std::vector<double> cur_in{};
447 std::vector<double> cur_out{};
448 std::vector<double> prev_in{};
450 double p1{}, p2{}, p3{};
451 std::vector<double> m1, m2, m3;
453 ossia::math_expression expr;
457 using control_policy = ossia::safe_nodes::last_tick;
459 run(
const ossia::audio_port& input,
const std::string& expr,
float a,
float b,
float c,
460 ossia::audio_port& output, ossia::token_request tk, ossia::exec_state_facade st,
463 if(tk.date > tk.prev_date)
465 self.fs = st.sampleRate();
466 if(!
self.expr.set_expression(expr))
469 const auto samplesRatio = st.modelToSamples();
470 const auto [tick_start, count] = st.timings(tk);
476 = std::min((int64_t)input.channel(0).size() - tick_start, count);
478 const int chans = input.channels();
479 self.reset_symbols(chans);
480 output.set_channels(chans);
482 for(
int j = 0; j < chans; j++)
484 auto& out = output.channel(j);
485 out.resize(st.bufferSize(), boost::container::default_init);
491 const auto start_sample = (tk.prev_date * samplesRatio).impl;
492 for(int64_t i = 0; i < min_count; i++)
494 for(
int j = 0; j < chans; j++)
496 self.cur_in[j] = input.channel(j)[tick_start + i];
498 self.cur_time = start_sample + i;
504 for(
int j = 0; j < chans; j++)
506 output.channel(j)[tick_start + i] =
self.cur_out[j];
508 std::swap(
self.cur_in,
self.prev_in);
513 template <
typename... Args>
514 static void item(Args&&... args)
516 Nodes::mathItem(Metadata::controls, std::forward<Args>(args)...);
521 namespace MicroMapping
527 static const constexpr
auto prettyName =
"Micromap";
528 static const constexpr
auto objectKey =
"MicroMapping";
529 static const constexpr
auto category =
"Control/Mappings";
530 static const constexpr
auto author =
"ossia score, ExprTK (Arash Partow)";
531 static const constexpr
auto kind = Process::ProcessCategory::Mapping;
532 static const constexpr
auto description =
"Applies a math expression to an input.";
533 static const constexpr
auto tags = std::array<const char*, 0>{};
534 static const uuid_constexpr
auto uuid
535 = make_uuid(
"25c64b87-a44a-4fed-9f60-0a48906fd3ec");
537 static const constexpr value_in value_ins[]{value_in{
"in",
false}};
538 static const constexpr value_out value_outs[]{
"out"};
540 static const constexpr
auto controls
550 expr.add_vector(
"xv", xv);
551 expr.add_vector(
"pxv", pxv);
552 expr.add_vector(
"pov", pov);
554 expr.add_variable(
"x", x);
555 expr.add_variable(
"px", px);
556 expr.add_variable(
"po", po);
558 expr.add_variable(
"t", cur_time);
559 expr.add_variable(
"dt", cur_deltatime);
560 expr.add_variable(
"pos", cur_pos);
561 expr.add_constants();
563 expr.register_symbol_table();
566 std::vector<double> xv;
567 std::vector<double> pxv;
568 std::vector<double> pov;
575 double cur_deltatime{};
578 ossia::math_expression expr;
579 int64_t last_value_time{};
584 using control_policy = ossia::safe_nodes::last_tick;
587 run(
const ossia::value_port& input,
const std::string& expr, ossia::value_port& output,
588 const ossia::token_request& tk, ossia::exec_state_facade st,
State&
self)
590 if(!
self.expr.set_expression(expr))
593 if(
self.expr.has_variable(
"xv"))
599 template <
typename... Args>
600 static void item(Args&&... args)
602 Nodes::miniMathItem(Metadata::controls, std::forward<Args>(args)...);
615 struct HasCustomUI<Nodes::MathAudioGenerator::Node> : std::true_type
Utilities for OSSIA data structures.
Definition: DeviceInterface.hpp:33
Definition: score-lib-process/Control/Widgets.hpp:77
Definition: score-plugin-engine/Engine/Node/Layer.hpp:25
Definition: score-lib-process/Control/Widgets.hpp:417
Definition: MathMapping.hpp:8
Definition: MathMapping.hpp:349
Definition: MathMapping.hpp:230
Definition: MathMapping.hpp:524