Loading...
Searching...
No Matches
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
11namespace Nodes
12{
13namespace MathAudioGenerator
14{
15struct 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 * sin(m1[0]);\n"
37 "out[1] := b * sin(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 cur_out.resize(N);
87 m1.resize(N);
88 m2.resize(N);
89 m3.resize(N);
90
91 expr.rebase_vector("out", cur_out);
92 expr.rebase_vector("m1", m1);
93 expr.rebase_vector("m2", m2);
94 expr.rebase_vector("m3", m3);
95
96 // The vector sizes are baked into the compiled expression: it has to be
97 // parsed again against the new channel count.
98 expr.recompile();
99 }
100 std::vector<double> cur_out{};
101 double cur_time{};
102 double a{}, b{}, c{};
103 double pa{}, pb{}, pc{};
104 std::vector<double> m1, m2, m3;
105 double fs{44100};
106 ossia::math_expression expr;
107 bool ok = false;
108 } state;
109
110 halp::setup setup;
111 static constexpr int chans = 2; // FIXME
112 void prepare(halp::setup s)
113 {
114 setup = s;
115 outputs.audio.request_channels(chans);
116 state.reset_symbols(chans);
117 }
118
119 using tick = halp::tick_flicks;
120 void operator()(const tick& tk)
121 {
122 auto& self = state;
123 // if(tk.forward())
124 {
125 self.fs = setup.rate;
126 self.expr.set_expression(inputs.expr);
127
128 // May recompile: validity is checked afterwards so that a channel-count
129 // change can rescue an expression that did not compile against the
130 // previous one.
131 self.reset_symbols(chans);
132
133 if(!self.expr.valid())
134 return;
135
136 self.a = this->inputs.a;
137 self.b = this->inputs.b;
138 self.c = this->inputs.c;
139 for(int64_t i = 0; i < tk.frames; i++)
140 {
141 self.cur_time = i;
142
143 // Compute the value
144 self.expr.value();
145
146 // Apply the output
147 auto& channels = this->outputs.audio.samples;
148 for(int j = 0; j < std::min(chans, outputs.audio.channels); j++)
149 {
150 channels[j][i] = self.cur_out[j];
151 }
152 }
153 self.pa = self.a;
154 self.pb = self.b;
155 self.pc = self.c;
156 }
157 }
158
159 struct ui
160 {
161 halp_meta(layout, halp::layouts::vbox)
162 struct
163 {
164 halp_meta(layout, halp::layouts::hbox)
165 halp::control<&ins::a> a;
166 halp::control<&ins::b> b;
167 halp::control<&ins::c> c;
168 } controls;
169
170 struct : halp::control<&ins::expr>
171 {
172 halp_flag(dynamic_size);
173 } expr;
174 };
175};
176}
177}
Utilities for OSSIA data structures.
Definition DeviceInterface.hpp:35
Definition MathAudioGenerator.hpp:160
Definition MathAudioGenerator.hpp:16