MathAudioGenerator.hpp
1 #pragma once
2 
3 #include <Fx/MathMapping_generic.hpp>
4 #include <Fx/Types.hpp>
5 
6 #include <ossia/dataflow/audio_port.hpp>
7 #include <ossia/dataflow/value_port.hpp>
8 
9 #include <halp/layout.hpp>
10 
11 namespace Nodes
12 {
13 namespace MathAudioGenerator
14 {
15 struct Node
16 {
17  halp_meta(name, "Expression Audio Generator")
18  halp_meta(c_name, "MathAudioGenerator")
19  halp_meta(category, "Audio/Utilities")
20  halp_meta(manual_url, "https://ossia.io/score-docs/processes/exprtk.html#exprtk-support")
21  halp_meta(author, "ossia score, ExprTK (Arash Partow)")
22  halp_meta(
23  description,
24  "Generate an audio signal from a math expression.\n"
25  "Available variables: a,b,c, t (samples), fs (sampling frequency)\n"
26  "See the documentation at http://www.partow.net/programming/exprtk")
27  halp_meta(uuid, "eae294b3-afeb-4fba-bbe4-337998d3748a")
28 
29  struct ins
30  {
31  halp::lineedit<
32  "Expression",
33  "var phi := 2 * pi * (20 + a * 500) / fs;\n"
34  "m1[0] += phi;\n"
35  "\n"
36  "out[0] := b * cos(m1[0]);\n"
37  "out[1] := b * cos(m1[0]);\n">
38  expr;
39 
40  halp::hslider_f32<"Param (a)", halp::range{0., 1., 0.5}> a;
41  halp::hslider_f32<"Param (b)", halp::range{0., 1., 0.5}> b;
42  halp::hslider_f32<"Param (c)", halp::range{0., 1., 0.5}> c;
43  } inputs;
44 
45  struct
46  {
47  halp::variable_audio_bus<"out", double> audio;
48  } outputs;
49 
50  struct State
51  {
52  State()
53  {
54  cur_out.reserve(8);
55  m1.reserve(8);
56  m2.reserve(8);
57  m3.reserve(8);
58  cur_out.resize(2);
59  m1.resize(2);
60  m2.resize(2);
61  m3.resize(2);
62 
63  expr.add_vector("out", cur_out);
64  expr.add_variable("t", cur_time);
65  expr.add_variable("a", a);
66  expr.add_variable("b", b);
67  expr.add_variable("c", c);
68  expr.add_variable("pa", pa);
69  expr.add_variable("pb", pb);
70  expr.add_variable("pc", pc);
71  expr.add_vector("m1", m1);
72  expr.add_vector("m2", m2);
73  expr.add_vector("m3", m3);
74  expr.add_variable("fs", fs);
75 
76  expr.add_constants();
77  expr.register_symbol_table();
78  }
79 
80  void reset_symbols(std::size_t N)
81  {
82  // TODO allow to set how many channels
83  if(N == cur_out.size())
84  return;
85 
86  expr.remove_vector("out");
87  expr.remove_vector("m1");
88  expr.remove_vector("m2");
89  expr.remove_vector("m3");
90 
91  cur_out.resize(N);
92  m1.resize(N);
93  m2.resize(N);
94  m3.resize(N);
95 
96  expr.add_vector("out", cur_out);
97  expr.add_vector("m1", m1);
98  expr.add_vector("m2", m2);
99  expr.add_vector("m3", m3);
100 
101  expr.update_symbol_table();
102  }
103  std::vector<double> cur_out{};
104  double cur_time{};
105  double a{}, b{}, c{};
106  double pa{}, pb{}, pc{};
107  std::vector<double> m1, m2, m3;
108  double fs{44100};
109  ossia::math_expression expr;
110  bool ok = false;
111  } state;
112 
113  halp::setup setup;
114  static constexpr int chans = 2; // FIXME
115  void prepare(halp::setup s)
116  {
117  setup = s;
118  outputs.audio.request_channels(chans);
119  state.reset_symbols(chans);
120  }
121 
122  using tick = halp::tick_flicks;
123  void operator()(const tick& tk)
124  {
125  SCORE_ASSERT(outputs.audio.channels == 2);
126  auto& self = state;
127  // if(tk.forward())
128  {
129  self.fs = setup.rate;
130  if(!self.expr.set_expression(inputs.expr))
131  return;
132 
133  self.reset_symbols(chans);
134  self.a = this->inputs.a;
135  self.b = this->inputs.b;
136  self.c = this->inputs.c;
137  for(int64_t i = 0; i < tk.frames; i++)
138  {
139  self.cur_time = i;
140 
141  // Compute the value
142  self.expr.value();
143 
144  // Apply the output
145  auto& channels = this->outputs.audio.samples;
146  for(int j = 0; j < chans; j++)
147  {
148  channels[j][i] = self.cur_out[j];
149  }
150  }
151  self.pa = self.a;
152  self.pb = self.b;
153  self.pc = self.c;
154  }
155  }
156 
157  struct ui
158  {
159  halp_meta(layout, halp::layouts::vbox)
160  struct
161  {
162  halp_meta(layout, halp::layouts::hbox)
163  halp::control<&ins::a> a;
164  halp::control<&ins::b> b;
165  halp::control<&ins::c> c;
166  } controls;
167 
168  struct : halp::control<&ins::expr>
169  {
170  halp_flag(dynamic_size);
171  } expr;
172  };
173 };
174 }
175 }
Utilities for OSSIA data structures.
Definition: DeviceInterface.hpp:33
Definition: MathAudioGenerator.hpp:158
Definition: MathAudioGenerator.hpp:16