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 * 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 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 std::vector<double> cur_out{};
97 double cur_time{};
98 double a{}, b{}, c{};
99 double pa{}, pb{}, pc{};
100 std::vector<double> m1, m2, m3;
101 double fs{44100};
102 ossia::math_expression expr;
103 bool ok = false;
104 } state;
105
106 halp::setup setup;
107 static constexpr int chans = 2; // FIXME
108 void prepare(halp::setup s)
109 {
110 setup = s;
111 outputs.audio.request_channels(chans);
112 state.reset_symbols(chans);
113 }
114
115 using tick = halp::tick_flicks;
116 void operator()(const tick& tk)
117 {
118 auto& self = state;
119 // if(tk.forward())
120 {
121 self.fs = setup.rate;
122 if(!self.expr.set_expression(inputs.expr))
123 return;
124
125 self.reset_symbols(chans);
126 self.a = this->inputs.a;
127 self.b = this->inputs.b;
128 self.c = this->inputs.c;
129 for(int64_t i = 0; i < tk.frames; i++)
130 {
131 self.cur_time = i;
132
133 // Compute the value
134 self.expr.value();
135
136 // Apply the output
137 auto& channels = this->outputs.audio.samples;
138 for(int j = 0; j < std::min(chans, outputs.audio.channels); j++)
139 {
140 channels[j][i] = self.cur_out[j];
141 }
142 }
143 self.pa = self.a;
144 self.pb = self.b;
145 self.pc = self.c;
146 }
147 }
148
149 struct ui
150 {
151 halp_meta(layout, halp::layouts::vbox)
152 struct
153 {
154 halp_meta(layout, halp::layouts::hbox)
155 halp::control<&ins::a> a;
156 halp::control<&ins::b> b;
157 halp::control<&ins::c> c;
158 } controls;
159
160 struct : halp::control<&ins::expr>
161 {
162 halp_flag(dynamic_size);
163 } expr;
164 };
165};
166}
167}
Utilities for OSSIA data structures.
Definition DeviceInterface.hpp:33
Definition MathAudioGenerator.hpp:150
Definition MathAudioGenerator.hpp:16