frausto 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +45 -0
- data/bin/faust2ruby +124 -0
- data/bin/ruby2faust +129 -0
- data/faust2ruby.md +523 -0
- data/lib/faust2ruby/ast.rb +315 -0
- data/lib/faust2ruby/ir_builder.rb +413 -0
- data/lib/faust2ruby/lexer.rb +255 -0
- data/lib/faust2ruby/library_mapper.rb +249 -0
- data/lib/faust2ruby/parser.rb +596 -0
- data/lib/faust2ruby/ruby_generator.rb +708 -0
- data/lib/faust2ruby/version.rb +5 -0
- data/lib/faust2ruby.rb +82 -0
- data/lib/frausto.rb +8 -0
- data/lib/ruby2faust/dsl.rb +1332 -0
- data/lib/ruby2faust/emitter.rb +599 -0
- data/lib/ruby2faust/ir.rb +285 -0
- data/lib/ruby2faust/live.rb +82 -0
- data/lib/ruby2faust/version.rb +5 -0
- data/lib/ruby2faust.rb +27 -0
- data/ruby2faust.md +334 -0
- metadata +106 -0
|
@@ -0,0 +1,599 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "ir"
|
|
4
|
+
|
|
5
|
+
module Ruby2Faust
|
|
6
|
+
# Emitter generates Faust source code from an IR graph.
|
|
7
|
+
module Emitter
|
|
8
|
+
module_function
|
|
9
|
+
|
|
10
|
+
DEFAULT_IMPORTS = ["stdfaust.lib"].freeze
|
|
11
|
+
|
|
12
|
+
def program(process, imports: nil, declarations: {}, pretty: false)
|
|
13
|
+
if process.is_a?(Program)
|
|
14
|
+
node = process.process.is_a?(DSP) ? process.process.node : process.process
|
|
15
|
+
imports ||= process.imports
|
|
16
|
+
declarations = process.declarations.merge(declarations)
|
|
17
|
+
else
|
|
18
|
+
node = process.is_a?(DSP) ? process.node : process
|
|
19
|
+
imports ||= DEFAULT_IMPORTS
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
lines = []
|
|
23
|
+
declarations.each { |k, v| lines << "declare #{k} \"#{v}\";" }
|
|
24
|
+
lines << "" if declarations.any?
|
|
25
|
+
imports.each { |lib| lines << "import(\"#{lib}\");" }
|
|
26
|
+
lines << ""
|
|
27
|
+
|
|
28
|
+
body = emit(node, pretty: pretty)
|
|
29
|
+
lines << "process = #{body};"
|
|
30
|
+
lines.join("\n") + "\n"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def emit(node, indent: 0, pretty: false)
|
|
34
|
+
sp = " " * indent
|
|
35
|
+
next_sp = " " * (indent + 1)
|
|
36
|
+
|
|
37
|
+
case node.type
|
|
38
|
+
|
|
39
|
+
# === COMMENTS ===
|
|
40
|
+
when NodeType::COMMENT
|
|
41
|
+
"// #{node.args[0]}\n"
|
|
42
|
+
when NodeType::DOC
|
|
43
|
+
# Inline comment wrapped around the inner expression
|
|
44
|
+
"/* #{node.args[0]} */ #{emit(node.inputs[0], indent: indent, pretty: pretty)}"
|
|
45
|
+
|
|
46
|
+
# === OSCILLATORS ===
|
|
47
|
+
when NodeType::OSC
|
|
48
|
+
"os.osc(#{emit(node.inputs[0], indent: indent, pretty: pretty)})"
|
|
49
|
+
when NodeType::SAW
|
|
50
|
+
"os.sawtooth(#{emit(node.inputs[0], indent: indent, pretty: pretty)})"
|
|
51
|
+
when NodeType::SQUARE
|
|
52
|
+
"os.square(#{emit(node.inputs[0], indent: indent, pretty: pretty)})"
|
|
53
|
+
when NodeType::TRIANGLE
|
|
54
|
+
"os.triangle(#{emit(node.inputs[0], indent: indent, pretty: pretty)})"
|
|
55
|
+
when NodeType::PHASOR
|
|
56
|
+
"os.phasor(#{emit(node.inputs[0], indent: indent, pretty: pretty)}, #{emit(node.inputs[1], indent: indent, pretty: pretty)})"
|
|
57
|
+
when NodeType::LF_SAW
|
|
58
|
+
"os.lf_sawpos(#{emit(node.inputs[0], indent: indent, pretty: pretty)})"
|
|
59
|
+
when NodeType::LF_TRIANGLE
|
|
60
|
+
"os.lf_trianglepos(#{emit(node.inputs[0], indent: indent, pretty: pretty)})"
|
|
61
|
+
when NodeType::LF_SQUARE
|
|
62
|
+
"os.lf_squarewavepos(#{emit(node.inputs[0], indent: indent, pretty: pretty)})"
|
|
63
|
+
when NodeType::IMPTRAIN
|
|
64
|
+
"os.lf_imptrain(#{emit(node.inputs[0], indent: indent, pretty: pretty)})"
|
|
65
|
+
when NodeType::PULSETRAIN
|
|
66
|
+
"os.lf_pulsetrain(#{emit(node.inputs[0], indent: indent, pretty: pretty)}, #{emit(node.inputs[1], indent: indent, pretty: pretty)})"
|
|
67
|
+
|
|
68
|
+
# === NOISE ===
|
|
69
|
+
when NodeType::NOISE
|
|
70
|
+
"no.noise"
|
|
71
|
+
when NodeType::PINK_NOISE
|
|
72
|
+
"no.pink_noise"
|
|
73
|
+
|
|
74
|
+
# === FILTERS ===
|
|
75
|
+
when NodeType::LP
|
|
76
|
+
"fi.lowpass(#{node.args[0] || 1}, #{emit(node.inputs[0], indent: indent, pretty: pretty)})"
|
|
77
|
+
when NodeType::HP
|
|
78
|
+
"fi.highpass(#{node.args[0] || 1}, #{emit(node.inputs[0], indent: indent, pretty: pretty)})"
|
|
79
|
+
when NodeType::BP
|
|
80
|
+
"fi.bandpass(1, #{emit(node.inputs[0], indent: indent, pretty: pretty)}, #{emit(node.inputs[1], indent: indent, pretty: pretty)})"
|
|
81
|
+
when NodeType::RESONLP
|
|
82
|
+
"fi.resonlp(#{emit(node.inputs[0], indent: indent, pretty: pretty)}, #{emit(node.inputs[1], indent: indent, pretty: pretty)}, #{emit(node.inputs[2], indent: indent, pretty: pretty)})"
|
|
83
|
+
when NodeType::RESONHP
|
|
84
|
+
"fi.resonhp(#{emit(node.inputs[0], indent: indent, pretty: pretty)}, #{emit(node.inputs[1], indent: indent, pretty: pretty)}, #{emit(node.inputs[2], indent: indent, pretty: pretty)})"
|
|
85
|
+
when NodeType::RESONBP
|
|
86
|
+
"fi.resonbp(#{emit(node.inputs[0], indent: indent, pretty: pretty)}, #{emit(node.inputs[1], indent: indent, pretty: pretty)}, #{emit(node.inputs[2], indent: indent, pretty: pretty)})"
|
|
87
|
+
when NodeType::ALLPASS
|
|
88
|
+
"fi.allpass_comb(#{emit(node.inputs[0], indent: indent, pretty: pretty)}, #{emit(node.inputs[1], indent: indent, pretty: pretty)}, #{emit(node.inputs[2], indent: indent, pretty: pretty)})"
|
|
89
|
+
when NodeType::DCBLOCK
|
|
90
|
+
"fi.dcblocker"
|
|
91
|
+
when NodeType::PEAK_EQ
|
|
92
|
+
"fi.peak_eq(#{emit(node.inputs[0], indent: indent, pretty: pretty)}, #{emit(node.inputs[1], indent: indent, pretty: pretty)}, #{emit(node.inputs[2], indent: indent, pretty: pretty)})"
|
|
93
|
+
|
|
94
|
+
# SVF (State Variable Filter)
|
|
95
|
+
when NodeType::SVF_LP
|
|
96
|
+
"fi.svf.lp(#{emit(node.inputs[0], indent: indent, pretty: pretty)}, #{emit(node.inputs[1], indent: indent, pretty: pretty)})"
|
|
97
|
+
when NodeType::SVF_HP
|
|
98
|
+
"fi.svf.hp(#{emit(node.inputs[0], indent: indent, pretty: pretty)}, #{emit(node.inputs[1], indent: indent, pretty: pretty)})"
|
|
99
|
+
when NodeType::SVF_BP
|
|
100
|
+
"fi.svf.bp(#{emit(node.inputs[0], indent: indent, pretty: pretty)}, #{emit(node.inputs[1], indent: indent, pretty: pretty)})"
|
|
101
|
+
when NodeType::SVF_NOTCH
|
|
102
|
+
"fi.svf.notch(#{emit(node.inputs[0], indent: indent, pretty: pretty)}, #{emit(node.inputs[1], indent: indent, pretty: pretty)})"
|
|
103
|
+
when NodeType::SVF_AP
|
|
104
|
+
"fi.svf.ap(#{emit(node.inputs[0], indent: indent, pretty: pretty)}, #{emit(node.inputs[1], indent: indent, pretty: pretty)})"
|
|
105
|
+
when NodeType::SVF_BELL
|
|
106
|
+
"fi.svf.bell(#{emit(node.inputs[0], indent: indent, pretty: pretty)}, #{emit(node.inputs[1], indent: indent, pretty: pretty)}, #{emit(node.inputs[2], indent: indent, pretty: pretty)})"
|
|
107
|
+
when NodeType::SVF_LS
|
|
108
|
+
"fi.svf.ls(#{emit(node.inputs[0], indent: indent, pretty: pretty)}, #{emit(node.inputs[1], indent: indent, pretty: pretty)}, #{emit(node.inputs[2], indent: indent, pretty: pretty)})"
|
|
109
|
+
when NodeType::SVF_HS
|
|
110
|
+
"fi.svf.hs(#{emit(node.inputs[0], indent: indent, pretty: pretty)}, #{emit(node.inputs[1], indent: indent, pretty: pretty)}, #{emit(node.inputs[2], indent: indent, pretty: pretty)})"
|
|
111
|
+
|
|
112
|
+
# Other filters
|
|
113
|
+
when NodeType::LOWPASS3E
|
|
114
|
+
"fi.lowpass3e(#{emit(node.inputs[0], indent: indent, pretty: pretty)})"
|
|
115
|
+
when NodeType::HIGHPASS3E
|
|
116
|
+
"fi.highpass3e(#{emit(node.inputs[0], indent: indent, pretty: pretty)})"
|
|
117
|
+
when NodeType::LOWPASS6E
|
|
118
|
+
"fi.lowpass6e(#{emit(node.inputs[0], indent: indent, pretty: pretty)})"
|
|
119
|
+
when NodeType::HIGHPASS6E
|
|
120
|
+
"fi.highpass6e(#{emit(node.inputs[0], indent: indent, pretty: pretty)})"
|
|
121
|
+
when NodeType::BANDSTOP
|
|
122
|
+
"fi.bandstop(#{emit(node.inputs[0], indent: indent, pretty: pretty)}, #{emit(node.inputs[1], indent: indent, pretty: pretty)}, #{emit(node.inputs[2], indent: indent, pretty: pretty)})"
|
|
123
|
+
when NodeType::NOTCHW
|
|
124
|
+
"fi.notchw(#{emit(node.inputs[0], indent: indent, pretty: pretty)}, #{emit(node.inputs[1], indent: indent, pretty: pretty)})"
|
|
125
|
+
when NodeType::LOW_SHELF
|
|
126
|
+
"fi.low_shelf(#{emit(node.inputs[0], indent: indent, pretty: pretty)}, #{emit(node.inputs[1], indent: indent, pretty: pretty)}, #{emit(node.inputs[2], indent: indent, pretty: pretty)})"
|
|
127
|
+
when NodeType::HIGH_SHELF
|
|
128
|
+
"fi.high_shelf(#{emit(node.inputs[0], indent: indent, pretty: pretty)}, #{emit(node.inputs[1], indent: indent, pretty: pretty)}, #{emit(node.inputs[2], indent: indent, pretty: pretty)})"
|
|
129
|
+
when NodeType::PEAK_EQ_CQ
|
|
130
|
+
"fi.peak_eq_cq(#{emit(node.inputs[0], indent: indent, pretty: pretty)}, #{emit(node.inputs[1], indent: indent, pretty: pretty)}, #{emit(node.inputs[2], indent: indent, pretty: pretty)})"
|
|
131
|
+
when NodeType::FI_POLE
|
|
132
|
+
"fi.pole(#{emit(node.inputs[0], indent: indent, pretty: pretty)})"
|
|
133
|
+
when NodeType::FI_ZERO
|
|
134
|
+
"fi.zero(#{emit(node.inputs[0], indent: indent, pretty: pretty)})"
|
|
135
|
+
when NodeType::TF1
|
|
136
|
+
"fi.tf1(#{emit(node.inputs[0], indent: indent, pretty: pretty)}, #{emit(node.inputs[1], indent: indent, pretty: pretty)}, #{emit(node.inputs[2], indent: indent, pretty: pretty)})"
|
|
137
|
+
when NodeType::TF2
|
|
138
|
+
"fi.tf2(#{emit(node.inputs[0], indent: indent, pretty: pretty)}, #{emit(node.inputs[1], indent: indent, pretty: pretty)}, #{emit(node.inputs[2], indent: indent, pretty: pretty)}, #{emit(node.inputs[3], indent: indent, pretty: pretty)}, #{emit(node.inputs[4], indent: indent, pretty: pretty)})"
|
|
139
|
+
when NodeType::TF1S
|
|
140
|
+
"fi.tf1s(#{emit(node.inputs[0], indent: indent, pretty: pretty)}, #{emit(node.inputs[1], indent: indent, pretty: pretty)}, #{emit(node.inputs[2], indent: indent, pretty: pretty)})"
|
|
141
|
+
when NodeType::TF2S
|
|
142
|
+
"fi.tf2s(#{emit(node.inputs[0], indent: indent, pretty: pretty)}, #{emit(node.inputs[1], indent: indent, pretty: pretty)}, #{emit(node.inputs[2], indent: indent, pretty: pretty)}, #{emit(node.inputs[3], indent: indent, pretty: pretty)}, #{emit(node.inputs[4], indent: indent, pretty: pretty)})"
|
|
143
|
+
when NodeType::IIR
|
|
144
|
+
"fi.iir(#{emit(node.inputs[0], indent: indent, pretty: pretty)}, #{emit(node.inputs[1], indent: indent, pretty: pretty)})"
|
|
145
|
+
when NodeType::FIR
|
|
146
|
+
"fi.fir(#{emit(node.inputs[0], indent: indent, pretty: pretty)})"
|
|
147
|
+
when NodeType::CONV
|
|
148
|
+
"fi.conv(#{emit(node.inputs[0], indent: indent, pretty: pretty)}, #{emit(node.inputs[1], indent: indent, pretty: pretty)})"
|
|
149
|
+
when NodeType::FBCOMBFILTER
|
|
150
|
+
"fi.fbcombfilter(#{emit(node.inputs[0], indent: indent, pretty: pretty)}, #{emit(node.inputs[1], indent: indent, pretty: pretty)}, #{emit(node.inputs[2], indent: indent, pretty: pretty)})"
|
|
151
|
+
when NodeType::FFCOMBFILTER
|
|
152
|
+
"fi.ffcombfilter(#{emit(node.inputs[0], indent: indent, pretty: pretty)}, #{emit(node.inputs[1], indent: indent, pretty: pretty)})"
|
|
153
|
+
|
|
154
|
+
# === DELAYS ===
|
|
155
|
+
when NodeType::DELAY
|
|
156
|
+
"de.delay(#{emit(node.inputs[0], indent: indent, pretty: pretty)}, #{emit(node.inputs[1], indent: indent, pretty: pretty)})"
|
|
157
|
+
when NodeType::FDELAY
|
|
158
|
+
"de.fdelay(#{emit(node.inputs[0], indent: indent, pretty: pretty)}, #{emit(node.inputs[1], indent: indent, pretty: pretty)})"
|
|
159
|
+
when NodeType::SDELAY
|
|
160
|
+
"de.sdelay(#{emit(node.inputs[0], indent: indent, pretty: pretty)}, #{emit(node.inputs[1], indent: indent, pretty: pretty)}, #{emit(node.inputs[2], indent: indent, pretty: pretty)})"
|
|
161
|
+
|
|
162
|
+
# === ENVELOPES ===
|
|
163
|
+
when NodeType::AR
|
|
164
|
+
"en.ar(#{emit(node.inputs[0], indent: indent, pretty: pretty)}, #{emit(node.inputs[1], indent: indent, pretty: pretty)}, #{emit(node.inputs[2], indent: indent, pretty: pretty)})"
|
|
165
|
+
when NodeType::ASR
|
|
166
|
+
"en.asr(#{emit(node.inputs[0], indent: indent, pretty: pretty)}, #{emit(node.inputs[1], indent: indent, pretty: pretty)}, #{emit(node.inputs[2], indent: indent, pretty: pretty)}, #{emit(node.inputs[3], indent: indent, pretty: pretty)})"
|
|
167
|
+
when NodeType::ADSR
|
|
168
|
+
"en.adsr(#{emit(node.inputs[0], indent: indent, pretty: pretty)}, #{emit(node.inputs[1], indent: indent, pretty: pretty)}, #{emit(node.inputs[2], indent: indent, pretty: pretty)}, #{emit(node.inputs[3], indent: indent, pretty: pretty)}, #{emit(node.inputs[4], indent: indent, pretty: pretty)})"
|
|
169
|
+
when NodeType::ADSRE
|
|
170
|
+
"en.adsre(#{emit(node.inputs[0], indent: indent, pretty: pretty)}, #{emit(node.inputs[1], indent: indent, pretty: pretty)}, #{emit(node.inputs[2], indent: indent, pretty: pretty)}, #{emit(node.inputs[3], indent: indent, pretty: pretty)}, #{emit(node.inputs[4], indent: indent, pretty: pretty)})"
|
|
171
|
+
|
|
172
|
+
# === MATH ===
|
|
173
|
+
when NodeType::GAIN
|
|
174
|
+
"*(#{emit(node.inputs[0], indent: indent, pretty: pretty)})"
|
|
175
|
+
when NodeType::ADD
|
|
176
|
+
node.inputs.count == 2 ? "(#{emit(node.inputs[0], indent: indent, pretty: pretty)} + #{emit(node.inputs[1], indent: indent, pretty: pretty)})" : "+"
|
|
177
|
+
when NodeType::MUL
|
|
178
|
+
node.inputs.count == 2 ? "(#{emit(node.inputs[0], indent: indent, pretty: pretty)} * #{emit(node.inputs[1], indent: indent, pretty: pretty)})" : "*"
|
|
179
|
+
when NodeType::SUB
|
|
180
|
+
node.inputs.count == 2 ? "(#{emit(node.inputs[0], indent: indent, pretty: pretty)} - #{emit(node.inputs[1], indent: indent, pretty: pretty)})" : "-"
|
|
181
|
+
when NodeType::DIV
|
|
182
|
+
node.inputs.count == 2 ? "(#{emit(node.inputs[0], indent: indent, pretty: pretty)} / #{emit(node.inputs[1], indent: indent, pretty: pretty)})" : "/"
|
|
183
|
+
when NodeType::MOD
|
|
184
|
+
"(#{emit(node.inputs[0], indent: indent, pretty: pretty)} % #{emit(node.inputs[1], indent: indent, pretty: pretty)})"
|
|
185
|
+
|
|
186
|
+
# Comparison operators
|
|
187
|
+
when NodeType::LT
|
|
188
|
+
"(#{emit(node.inputs[0], indent: indent, pretty: pretty)} < #{emit(node.inputs[1], indent: indent, pretty: pretty)})"
|
|
189
|
+
when NodeType::GT
|
|
190
|
+
"(#{emit(node.inputs[0], indent: indent, pretty: pretty)} > #{emit(node.inputs[1], indent: indent, pretty: pretty)})"
|
|
191
|
+
when NodeType::LE
|
|
192
|
+
"(#{emit(node.inputs[0], indent: indent, pretty: pretty)} <= #{emit(node.inputs[1], indent: indent, pretty: pretty)})"
|
|
193
|
+
when NodeType::GE
|
|
194
|
+
"(#{emit(node.inputs[0], indent: indent, pretty: pretty)} >= #{emit(node.inputs[1], indent: indent, pretty: pretty)})"
|
|
195
|
+
when NodeType::EQ
|
|
196
|
+
"(#{emit(node.inputs[0], indent: indent, pretty: pretty)} == #{emit(node.inputs[1], indent: indent, pretty: pretty)})"
|
|
197
|
+
when NodeType::NEQ
|
|
198
|
+
"(#{emit(node.inputs[0], indent: indent, pretty: pretty)} != #{emit(node.inputs[1], indent: indent, pretty: pretty)})"
|
|
199
|
+
|
|
200
|
+
# Bitwise operators
|
|
201
|
+
when NodeType::BAND
|
|
202
|
+
"(#{emit(node.inputs[0], indent: indent, pretty: pretty)} & #{emit(node.inputs[1], indent: indent, pretty: pretty)})"
|
|
203
|
+
when NodeType::BOR
|
|
204
|
+
"(#{emit(node.inputs[0], indent: indent, pretty: pretty)} | #{emit(node.inputs[1], indent: indent, pretty: pretty)})"
|
|
205
|
+
when NodeType::XOR
|
|
206
|
+
"(#{emit(node.inputs[0], indent: indent, pretty: pretty)} xor #{emit(node.inputs[1], indent: indent, pretty: pretty)})"
|
|
207
|
+
|
|
208
|
+
when NodeType::NEG
|
|
209
|
+
"0 - #{emit(node.inputs[0], indent: indent, pretty: pretty)}"
|
|
210
|
+
when NodeType::ABS
|
|
211
|
+
"abs"
|
|
212
|
+
when NodeType::MIN
|
|
213
|
+
"min(#{emit(node.inputs[0], indent: indent, pretty: pretty)}, #{emit(node.inputs[1], indent: indent, pretty: pretty)})"
|
|
214
|
+
when NodeType::MAX
|
|
215
|
+
"max(#{emit(node.inputs[0], indent: indent, pretty: pretty)}, #{emit(node.inputs[1], indent: indent, pretty: pretty)})"
|
|
216
|
+
when NodeType::CLIP
|
|
217
|
+
"max(#{emit(node.inputs[0], indent: indent, pretty: pretty)}) : min(#{emit(node.inputs[1], indent: indent, pretty: pretty)})"
|
|
218
|
+
when NodeType::POW
|
|
219
|
+
"pow(#{emit(node.inputs[0], indent: indent, pretty: pretty)}, #{emit(node.inputs[1], indent: indent, pretty: pretty)})"
|
|
220
|
+
when NodeType::SQRT
|
|
221
|
+
"sqrt"
|
|
222
|
+
when NodeType::EXP
|
|
223
|
+
"exp"
|
|
224
|
+
when NodeType::LOG
|
|
225
|
+
"log"
|
|
226
|
+
when NodeType::LOG10
|
|
227
|
+
"log10"
|
|
228
|
+
when NodeType::SIN
|
|
229
|
+
"sin"
|
|
230
|
+
when NodeType::COS
|
|
231
|
+
"cos"
|
|
232
|
+
when NodeType::TAN
|
|
233
|
+
"tan"
|
|
234
|
+
when NodeType::TANH
|
|
235
|
+
"ma.tanh"
|
|
236
|
+
when NodeType::SINH
|
|
237
|
+
"sinh"
|
|
238
|
+
when NodeType::COSH
|
|
239
|
+
"cosh"
|
|
240
|
+
when NodeType::ASINH
|
|
241
|
+
"asinh"
|
|
242
|
+
when NodeType::ACOSH
|
|
243
|
+
"acosh"
|
|
244
|
+
when NodeType::ATANH
|
|
245
|
+
"atanh"
|
|
246
|
+
when NodeType::ASIN
|
|
247
|
+
"asin"
|
|
248
|
+
when NodeType::ACOS
|
|
249
|
+
"acos"
|
|
250
|
+
when NodeType::ATAN
|
|
251
|
+
"atan"
|
|
252
|
+
when NodeType::ATAN2
|
|
253
|
+
"atan2(#{emit(node.inputs[0], indent: indent, pretty: pretty)}, #{emit(node.inputs[1], indent: indent, pretty: pretty)})"
|
|
254
|
+
when NodeType::FLOOR
|
|
255
|
+
"floor"
|
|
256
|
+
when NodeType::CEIL
|
|
257
|
+
"ceil"
|
|
258
|
+
when NodeType::RINT
|
|
259
|
+
"rint"
|
|
260
|
+
when NodeType::FMOD
|
|
261
|
+
"fmod(#{emit(node.inputs[0], indent: indent, pretty: pretty)}, #{emit(node.inputs[1], indent: indent, pretty: pretty)})"
|
|
262
|
+
when NodeType::INT
|
|
263
|
+
"int"
|
|
264
|
+
when NodeType::FLOAT
|
|
265
|
+
"float"
|
|
266
|
+
|
|
267
|
+
# === CONVERSION ===
|
|
268
|
+
when NodeType::DB2LINEAR
|
|
269
|
+
"ba.db2linear(#{emit(node.inputs[0], indent: indent, pretty: pretty)})"
|
|
270
|
+
when NodeType::LINEAR2DB
|
|
271
|
+
"ba.linear2db(#{emit(node.inputs[0], indent: indent, pretty: pretty)})"
|
|
272
|
+
when NodeType::SAMP2SEC
|
|
273
|
+
"ba.samp2sec(#{emit(node.inputs[0], indent: indent, pretty: pretty)})"
|
|
274
|
+
when NodeType::SEC2SAMP
|
|
275
|
+
"ba.sec2samp(#{emit(node.inputs[0], indent: indent, pretty: pretty)})"
|
|
276
|
+
when NodeType::MIDI2HZ
|
|
277
|
+
"ba.midikey2hz(#{emit(node.inputs[0], indent: indent, pretty: pretty)})"
|
|
278
|
+
when NodeType::HZ2MIDI
|
|
279
|
+
"ba.hz2midikey(#{emit(node.inputs[0], indent: indent, pretty: pretty)})"
|
|
280
|
+
when NodeType::TAU2POLE
|
|
281
|
+
"ba.tau2pole(#{emit(node.inputs[0], indent: indent, pretty: pretty)})"
|
|
282
|
+
when NodeType::POLE2TAU
|
|
283
|
+
"ba.pole2tau(#{emit(node.inputs[0], indent: indent, pretty: pretty)})"
|
|
284
|
+
when NodeType::BA_IF
|
|
285
|
+
cond = emit(node.inputs[0], indent: indent, pretty: pretty)
|
|
286
|
+
then_val = emit(node.inputs[1], indent: indent, pretty: pretty)
|
|
287
|
+
else_val = emit(node.inputs[2], indent: indent, pretty: pretty)
|
|
288
|
+
"ba.if(#{cond}, #{then_val}, #{else_val})"
|
|
289
|
+
when NodeType::SELECTOR
|
|
290
|
+
n = node.args[0]
|
|
291
|
+
sel = emit(node.inputs[0], indent: indent, pretty: pretty)
|
|
292
|
+
inputs = node.inputs[1..].map { |i| emit(i, indent: indent, pretty: pretty) }.join(", ")
|
|
293
|
+
"ba.selector(#{n}, #{sel}, #{inputs})"
|
|
294
|
+
when NodeType::BA_TAKE
|
|
295
|
+
idx = emit(node.inputs[0], indent: indent, pretty: pretty)
|
|
296
|
+
tuple = emit(node.inputs[1], indent: indent, pretty: pretty)
|
|
297
|
+
"ba.take(#{idx}, #{tuple})"
|
|
298
|
+
|
|
299
|
+
# === SMOOTHING ===
|
|
300
|
+
when NodeType::SMOOTH
|
|
301
|
+
"si.smooth(ba.tau2pole(#{emit(node.inputs[0], indent: indent, pretty: pretty)}))"
|
|
302
|
+
when NodeType::SMOO
|
|
303
|
+
"si.smoo"
|
|
304
|
+
|
|
305
|
+
# === SELECTORS ===
|
|
306
|
+
when NodeType::SELECT2
|
|
307
|
+
"select2(#{emit(node.inputs[0], indent: indent, pretty: pretty)}, #{emit(node.inputs[1], indent: indent, pretty: pretty)}, #{emit(node.inputs[2], indent: indent, pretty: pretty)})"
|
|
308
|
+
when NodeType::SELECTN
|
|
309
|
+
n = node.args[0]
|
|
310
|
+
idx = emit(node.inputs[0], indent: indent, pretty: pretty)
|
|
311
|
+
signals = node.inputs[1..].map { |i| emit(i, indent: indent, pretty: pretty) }.join(", ")
|
|
312
|
+
"ba.selectn(#{n}, #{idx}, #{signals})"
|
|
313
|
+
|
|
314
|
+
# === ROUTING ===
|
|
315
|
+
when NodeType::BUS
|
|
316
|
+
"si.bus(#{node.args[0]})"
|
|
317
|
+
when NodeType::BLOCK
|
|
318
|
+
"si.block(#{node.args[0]})"
|
|
319
|
+
|
|
320
|
+
# === REVERBS ===
|
|
321
|
+
when NodeType::FREEVERB
|
|
322
|
+
"re.mono_freeverb(#{emit(node.inputs[0], indent: indent, pretty: pretty)}, #{emit(node.inputs[1], indent: indent, pretty: pretty)}, #{emit(node.inputs[2], indent: indent, pretty: pretty)}, #{emit(node.inputs[3], indent: indent, pretty: pretty)})"
|
|
323
|
+
when NodeType::ZITA_REV
|
|
324
|
+
args = node.args.join(", ")
|
|
325
|
+
"re.zita_rev1_stereo(#{args})"
|
|
326
|
+
when NodeType::JPVERB
|
|
327
|
+
args = node.args.join(", ")
|
|
328
|
+
"re.jpverb(#{args})"
|
|
329
|
+
|
|
330
|
+
# === COMPRESSORS ===
|
|
331
|
+
when NodeType::COMPRESSOR
|
|
332
|
+
"co.compressor_mono(#{emit(node.inputs[0], indent: indent, pretty: pretty)}, #{emit(node.inputs[1], indent: indent, pretty: pretty)}, #{emit(node.inputs[2], indent: indent, pretty: pretty)}, #{emit(node.inputs[3], indent: indent, pretty: pretty)})"
|
|
333
|
+
when NodeType::LIMITER
|
|
334
|
+
"co.limiter_1176_R4_mono"
|
|
335
|
+
|
|
336
|
+
# === SPATIAL ===
|
|
337
|
+
when NodeType::PANNER
|
|
338
|
+
"sp.panner(#{emit(node.inputs[0], indent: indent, pretty: pretty)})"
|
|
339
|
+
|
|
340
|
+
# === UI CONTROLS ===
|
|
341
|
+
when NodeType::SLIDER
|
|
342
|
+
name, init, min, max, step = node.args
|
|
343
|
+
"hslider(\"#{name}\", #{init}, #{min}, #{max}, #{step})"
|
|
344
|
+
when NodeType::VSLIDER
|
|
345
|
+
name, init, min, max, step = node.args
|
|
346
|
+
"vslider(\"#{name}\", #{init}, #{min}, #{max}, #{step})"
|
|
347
|
+
when NodeType::NENTRY
|
|
348
|
+
name, init, min, max, step = node.args
|
|
349
|
+
"nentry(\"#{name}\", #{init}, #{min}, #{max}, #{step})"
|
|
350
|
+
when NodeType::BUTTON
|
|
351
|
+
"button(\"#{node.args[0]}\")"
|
|
352
|
+
when NodeType::CHECKBOX
|
|
353
|
+
"checkbox(\"#{node.args[0]}\")"
|
|
354
|
+
when NodeType::HGROUP
|
|
355
|
+
content = emit(node.inputs[0], indent: indent + 1, pretty: pretty)
|
|
356
|
+
if pretty
|
|
357
|
+
"hgroup(\"#{node.args[0]}\",\n#{next_sp}#{content}\n#{sp})"
|
|
358
|
+
else
|
|
359
|
+
"hgroup(\"#{node.args[0]}\", #{content})"
|
|
360
|
+
end
|
|
361
|
+
when NodeType::VGROUP
|
|
362
|
+
content = emit(node.inputs[0], indent: indent + 1, pretty: pretty)
|
|
363
|
+
if pretty
|
|
364
|
+
"vgroup(\"#{node.args[0]}\",\n#{next_sp}#{content}\n#{sp})"
|
|
365
|
+
else
|
|
366
|
+
"vgroup(\"#{node.args[0]}\", #{content})"
|
|
367
|
+
end
|
|
368
|
+
when NodeType::TGROUP
|
|
369
|
+
content = emit(node.inputs[0], indent: indent + 1, pretty: pretty)
|
|
370
|
+
if pretty
|
|
371
|
+
"tgroup(\"#{node.args[0]}\",\n#{next_sp}#{content}\n#{sp})"
|
|
372
|
+
else
|
|
373
|
+
"tgroup(\"#{node.args[0]}\", #{content})"
|
|
374
|
+
end
|
|
375
|
+
|
|
376
|
+
# === ITERATION ===
|
|
377
|
+
when NodeType::FPAR
|
|
378
|
+
var, count, block = node.args
|
|
379
|
+
# Evaluate the block with each index to get the expression
|
|
380
|
+
# For emission, we generate the Faust par() syntax
|
|
381
|
+
body = emit_iteration_body(var, block, indent, pretty)
|
|
382
|
+
"par(#{var}, #{count}, #{body})"
|
|
383
|
+
when NodeType::FSEQ
|
|
384
|
+
var, count, block = node.args
|
|
385
|
+
body = emit_iteration_body(var, block, indent, pretty)
|
|
386
|
+
"seq(#{var}, #{count}, #{body})"
|
|
387
|
+
when NodeType::FSUM
|
|
388
|
+
var, count, block = node.args
|
|
389
|
+
body = emit_iteration_body(var, block, indent, pretty)
|
|
390
|
+
"sum(#{var}, #{count}, #{body})"
|
|
391
|
+
when NodeType::FPROD
|
|
392
|
+
var, count, block = node.args
|
|
393
|
+
body = emit_iteration_body(var, block, indent, pretty)
|
|
394
|
+
"prod(#{var}, #{count}, #{body})"
|
|
395
|
+
|
|
396
|
+
# === LAMBDA ===
|
|
397
|
+
when NodeType::LAMBDA
|
|
398
|
+
params, block = node.args
|
|
399
|
+
param_str = params.map(&:to_s).join(", ")
|
|
400
|
+
# Create param DSP nodes for each parameter
|
|
401
|
+
param_dsps = params.map { |p| DSL.param(p) }
|
|
402
|
+
body = block.call(*param_dsps)
|
|
403
|
+
body = DSL.send(:to_dsp, body)
|
|
404
|
+
"\\(#{param_str}).(#{emit(body.node, indent: indent, pretty: pretty)})"
|
|
405
|
+
when NodeType::PARAM
|
|
406
|
+
node.args[0].to_s
|
|
407
|
+
|
|
408
|
+
# === TABLES ===
|
|
409
|
+
when NodeType::RDTABLE
|
|
410
|
+
size = emit(node.inputs[0], indent: indent, pretty: pretty)
|
|
411
|
+
init = emit(node.inputs[1], indent: indent, pretty: pretty)
|
|
412
|
+
ridx = emit(node.inputs[2], indent: indent, pretty: pretty)
|
|
413
|
+
"rdtable(#{size}, #{init}, #{ridx})"
|
|
414
|
+
when NodeType::RWTABLE
|
|
415
|
+
size = emit(node.inputs[0], indent: indent, pretty: pretty)
|
|
416
|
+
init = emit(node.inputs[1], indent: indent, pretty: pretty)
|
|
417
|
+
widx = emit(node.inputs[2], indent: indent, pretty: pretty)
|
|
418
|
+
wsig = emit(node.inputs[3], indent: indent, pretty: pretty)
|
|
419
|
+
ridx = emit(node.inputs[4], indent: indent, pretty: pretty)
|
|
420
|
+
"rwtable(#{size}, #{init}, #{widx}, #{wsig}, #{ridx})"
|
|
421
|
+
when NodeType::WAVEFORM
|
|
422
|
+
values = node.args.join(", ")
|
|
423
|
+
"waveform{#{values}}"
|
|
424
|
+
|
|
425
|
+
# === ADDITIONAL ROUTING ===
|
|
426
|
+
when NodeType::ROUTE
|
|
427
|
+
ins, outs, connections = node.args
|
|
428
|
+
conn_str = connections.map { |from, to| "(#{from}, #{to})" }.join(", ")
|
|
429
|
+
"route(#{ins}, #{outs}, #{conn_str})"
|
|
430
|
+
when NodeType::SELECT3
|
|
431
|
+
sel = emit(node.inputs[0], indent: indent, pretty: pretty)
|
|
432
|
+
a = emit(node.inputs[1], indent: indent, pretty: pretty)
|
|
433
|
+
b = emit(node.inputs[2], indent: indent, pretty: pretty)
|
|
434
|
+
c = emit(node.inputs[3], indent: indent, pretty: pretty)
|
|
435
|
+
"select3(#{sel}, #{a}, #{b}, #{c})"
|
|
436
|
+
|
|
437
|
+
# === COMPOSITION ===
|
|
438
|
+
when NodeType::SEQ
|
|
439
|
+
left = emit(node.inputs[0], indent: indent + 1, pretty: pretty)
|
|
440
|
+
right = emit(node.inputs[1], indent: indent + 1, pretty: pretty)
|
|
441
|
+
if pretty
|
|
442
|
+
"(\n#{next_sp}#{left}\n#{next_sp}: #{right}\n#{sp})"
|
|
443
|
+
else
|
|
444
|
+
"(#{left} : #{right})"
|
|
445
|
+
end
|
|
446
|
+
when NodeType::PAR
|
|
447
|
+
left = emit(node.inputs[0], indent: indent + 1, pretty: pretty)
|
|
448
|
+
right = emit(node.inputs[1], indent: indent + 1, pretty: pretty)
|
|
449
|
+
if pretty
|
|
450
|
+
"(\n#{next_sp}#{left},\n#{next_sp}#{right}\n#{sp})"
|
|
451
|
+
else
|
|
452
|
+
"(#{left}, #{right})"
|
|
453
|
+
end
|
|
454
|
+
when NodeType::SPLIT
|
|
455
|
+
source = emit(node.inputs[0], indent: indent + 1, pretty: pretty)
|
|
456
|
+
targets = node.inputs[1..].map { |n| emit(n, indent: indent + 1, pretty: pretty) }
|
|
457
|
+
if pretty
|
|
458
|
+
"(\n#{next_sp}#{source}\n#{next_sp}<: #{targets.join(",\n#{next_sp} ")}\n#{sp})"
|
|
459
|
+
else
|
|
460
|
+
"(#{source} <: #{targets.join(", ")})"
|
|
461
|
+
end
|
|
462
|
+
when NodeType::MERGE
|
|
463
|
+
left = emit(node.inputs[0], indent: indent + 1, pretty: pretty)
|
|
464
|
+
right = emit(node.inputs[1], indent: indent + 1, pretty: pretty)
|
|
465
|
+
if pretty
|
|
466
|
+
"(\n#{next_sp}#{left}\n#{next_sp}:> #{right}\n#{sp})"
|
|
467
|
+
else
|
|
468
|
+
"(#{left} :> #{right})"
|
|
469
|
+
end
|
|
470
|
+
when NodeType::FEEDBACK
|
|
471
|
+
left = emit(node.inputs[0], indent: indent + 1, pretty: pretty)
|
|
472
|
+
right = emit(node.inputs[1], indent: indent + 1, pretty: pretty)
|
|
473
|
+
if pretty
|
|
474
|
+
"(\n#{next_sp}#{left}\n#{next_sp}~ #{right}\n#{sp})"
|
|
475
|
+
else
|
|
476
|
+
"(#{left} ~ #{right})"
|
|
477
|
+
end
|
|
478
|
+
|
|
479
|
+
# === UTILITY ===
|
|
480
|
+
when NodeType::WIRE
|
|
481
|
+
"_"
|
|
482
|
+
when NodeType::CUT
|
|
483
|
+
"!"
|
|
484
|
+
when NodeType::MEM
|
|
485
|
+
"mem"
|
|
486
|
+
when NodeType::LITERAL
|
|
487
|
+
node.args[0].to_s
|
|
488
|
+
|
|
489
|
+
# === CONSTANTS ===
|
|
490
|
+
when NodeType::SR
|
|
491
|
+
"ma.SR"
|
|
492
|
+
when NodeType::PI
|
|
493
|
+
"ma.PI"
|
|
494
|
+
when NodeType::TEMPO
|
|
495
|
+
"ma.tempo"
|
|
496
|
+
|
|
497
|
+
# === ANTIALIASING ===
|
|
498
|
+
when NodeType::AA_TANH1
|
|
499
|
+
"aa.tanh1"
|
|
500
|
+
when NodeType::AA_TANH2
|
|
501
|
+
"aa.tanh2"
|
|
502
|
+
when NodeType::AA_ARCTAN
|
|
503
|
+
"aa.arctan"
|
|
504
|
+
when NodeType::AA_SOFTCLIP
|
|
505
|
+
"aa.softclip"
|
|
506
|
+
when NodeType::AA_HARDCLIP
|
|
507
|
+
"aa.hardclip"
|
|
508
|
+
when NodeType::AA_PARABOLIC
|
|
509
|
+
"aa.parabolic"
|
|
510
|
+
when NodeType::AA_SIN
|
|
511
|
+
"aa.sin"
|
|
512
|
+
when NodeType::AA_CUBIC1
|
|
513
|
+
"aa.cubic1"
|
|
514
|
+
when NodeType::AA_CUBIC2
|
|
515
|
+
"aa.cubic2"
|
|
516
|
+
|
|
517
|
+
# Analyzers (an.)
|
|
518
|
+
when NodeType::AMP_FOLLOWER
|
|
519
|
+
"an.amp_follower(#{emit_args(node, indent, pretty)})"
|
|
520
|
+
when NodeType::AMP_FOLLOWER_AR
|
|
521
|
+
"an.amp_follower_ar(#{emit_args(node, indent, pretty)})"
|
|
522
|
+
when NodeType::AMP_FOLLOWER_UD
|
|
523
|
+
"an.amp_follower_ud(#{emit_args(node, indent, pretty)})"
|
|
524
|
+
when NodeType::RMS_ENVELOPE_RECT
|
|
525
|
+
"an.rms_envelope_rect(#{emit_args(node, indent, pretty)})"
|
|
526
|
+
when NodeType::RMS_ENVELOPE_TAU
|
|
527
|
+
"an.rms_envelope_tau(#{emit_args(node, indent, pretty)})"
|
|
528
|
+
when NodeType::ABS_ENVELOPE_RECT
|
|
529
|
+
"an.abs_envelope_rect(#{emit_args(node, indent, pretty)})"
|
|
530
|
+
when NodeType::ABS_ENVELOPE_TAU
|
|
531
|
+
"an.abs_envelope_tau(#{emit_args(node, indent, pretty)})"
|
|
532
|
+
when NodeType::MS_ENVELOPE_RECT
|
|
533
|
+
"an.ms_envelope_rect(#{emit_args(node, indent, pretty)})"
|
|
534
|
+
when NodeType::MS_ENVELOPE_TAU
|
|
535
|
+
"an.ms_envelope_tau(#{emit_args(node, indent, pretty)})"
|
|
536
|
+
when NodeType::PEAK_ENVELOPE
|
|
537
|
+
"an.peak_envelope(#{emit_args(node, indent, pretty)})"
|
|
538
|
+
|
|
539
|
+
# Effects (ef.)
|
|
540
|
+
when NodeType::CUBICNL
|
|
541
|
+
"ef.cubicnl(#{emit_args(node, indent, pretty)})"
|
|
542
|
+
when NodeType::GATE_MONO
|
|
543
|
+
"ef.gate_mono(#{emit_args(node, indent, pretty)})"
|
|
544
|
+
when NodeType::GATE_STEREO
|
|
545
|
+
"ef.gate_stereo(#{emit_args(node, indent, pretty)})"
|
|
546
|
+
when NodeType::EF_COMPRESSOR_MONO
|
|
547
|
+
"ef.compressor_mono(#{emit_args(node, indent, pretty)})"
|
|
548
|
+
when NodeType::EF_COMPRESSOR_STEREO
|
|
549
|
+
"ef.compressor_stereo(#{emit_args(node, indent, pretty)})"
|
|
550
|
+
when NodeType::EF_LIMITER_1176_MONO
|
|
551
|
+
"ef.limiter_1176_R4_mono"
|
|
552
|
+
when NodeType::EF_LIMITER_1176_STEREO
|
|
553
|
+
"ef.limiter_1176_R4_stereo"
|
|
554
|
+
when NodeType::ECHO
|
|
555
|
+
"ef.echo(#{emit_args(node, indent, pretty)})"
|
|
556
|
+
when NodeType::TRANSPOSE
|
|
557
|
+
"ef.transpose(#{emit_args(node, indent, pretty)})"
|
|
558
|
+
when NodeType::FLANGER_MONO
|
|
559
|
+
"ef.flanger_mono(#{emit_args(node, indent, pretty)})"
|
|
560
|
+
when NodeType::FLANGER_STEREO
|
|
561
|
+
"ef.flanger_stereo(#{emit_args(node, indent, pretty)})"
|
|
562
|
+
when NodeType::PHASER2_MONO
|
|
563
|
+
"ef.phaser2_mono(#{emit_args(node, indent, pretty)})"
|
|
564
|
+
when NodeType::PHASER2_STEREO
|
|
565
|
+
"ef.phaser2_stereo(#{emit_args(node, indent, pretty)})"
|
|
566
|
+
when NodeType::WAH4
|
|
567
|
+
"ef.wah4(#{emit_args(node, indent, pretty)})"
|
|
568
|
+
when NodeType::AUTO_WAH
|
|
569
|
+
"ef.auto_wah(#{emit_args(node, indent, pretty)})"
|
|
570
|
+
when NodeType::CRYBABY
|
|
571
|
+
"ef.crybaby(#{emit_args(node, indent, pretty)})"
|
|
572
|
+
when NodeType::VOCODER
|
|
573
|
+
"ef.vocoder(#{emit_args(node, indent, pretty)})"
|
|
574
|
+
when NodeType::SPEAKERBP
|
|
575
|
+
"ef.speakerbp(#{emit_args(node, indent, pretty)})"
|
|
576
|
+
when NodeType::DRY_WET_MIXER
|
|
577
|
+
"ef.dryWetMixer(#{emit_args(node, indent, pretty)})"
|
|
578
|
+
when NodeType::DRY_WET_MIXER_CP
|
|
579
|
+
"ef.dryWetMixerConstantPower(#{emit_args(node, indent, pretty)})"
|
|
580
|
+
|
|
581
|
+
else
|
|
582
|
+
raise ArgumentError, "Unknown node type: #{node.type}"
|
|
583
|
+
end
|
|
584
|
+
end
|
|
585
|
+
|
|
586
|
+
# Helper to emit iteration body for par/seq/sum/prod
|
|
587
|
+
# Creates a symbolic parameter to capture the iterator variable
|
|
588
|
+
def emit_iteration_body(var, block, indent, pretty)
|
|
589
|
+
# Create a context that provides the iterator variable as a symbol
|
|
590
|
+
context = Object.new
|
|
591
|
+
context.extend(DSL)
|
|
592
|
+
# The block receives a symbolic representation of the iterator
|
|
593
|
+
iter_param = DSL.param(var)
|
|
594
|
+
body = block.call(iter_param)
|
|
595
|
+
body = DSL.send(:to_dsp, body)
|
|
596
|
+
emit(body.node, indent: indent, pretty: pretty)
|
|
597
|
+
end
|
|
598
|
+
end
|
|
599
|
+
end
|