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,1332 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "ir"
|
|
4
|
+
|
|
5
|
+
module Ruby2Faust
|
|
6
|
+
# DSP wrapper class for building graphs with method chaining.
|
|
7
|
+
class DSP
|
|
8
|
+
attr_reader :node
|
|
9
|
+
|
|
10
|
+
def initialize(node)
|
|
11
|
+
@node = node
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Sequential composition (Faust :)
|
|
15
|
+
def then(other)
|
|
16
|
+
other = DSL.to_dsp(other)
|
|
17
|
+
DSP.new(Node.new(type: NodeType::SEQ, inputs: [node, other.node], channels: other.node.channels))
|
|
18
|
+
end
|
|
19
|
+
alias >> then
|
|
20
|
+
|
|
21
|
+
# Parallel composition (Faust ,)
|
|
22
|
+
def par(other)
|
|
23
|
+
other = DSL.to_dsp(other)
|
|
24
|
+
DSP.new(Node.new(type: NodeType::PAR, inputs: [node, other.node], channels: node.channels + other.node.channels))
|
|
25
|
+
end
|
|
26
|
+
alias | par
|
|
27
|
+
|
|
28
|
+
# Fan-out / split (Faust <:)
|
|
29
|
+
def split(*others)
|
|
30
|
+
others = others.map { |o| DSL.to_dsp(o) }
|
|
31
|
+
total_channels = others.sum { |o| o.node.channels }
|
|
32
|
+
DSP.new(Node.new(type: NodeType::SPLIT, inputs: [node] + others.map(&:node), channels: total_channels))
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Fan-in / merge (Faust :>)
|
|
36
|
+
def merge(other)
|
|
37
|
+
other = DSL.to_dsp(other)
|
|
38
|
+
DSP.new(Node.new(type: NodeType::MERGE, inputs: [node, other.node], channels: other.node.channels))
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Feedback loop (Faust ~)
|
|
42
|
+
def feedback(other)
|
|
43
|
+
other = DSL.to_dsp(other)
|
|
44
|
+
DSP.new(Node.new(type: NodeType::FEEDBACK, inputs: [node, other.node], channels: node.channels))
|
|
45
|
+
end
|
|
46
|
+
alias ~ feedback
|
|
47
|
+
|
|
48
|
+
def channels
|
|
49
|
+
node.channels
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Attach a Faust comment to this node
|
|
53
|
+
# @param text [String] Comment text
|
|
54
|
+
# @return [DSP] New DSP with comment wrapper
|
|
55
|
+
def doc(text)
|
|
56
|
+
DSP.new(Node.new(type: NodeType::DOC, args: [text], inputs: [node], channels: node.channels))
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Multiply / gain (Faust *)
|
|
60
|
+
# @param other [Numeric, DSP, Symbol]
|
|
61
|
+
# @return [DSP]
|
|
62
|
+
def *(other)
|
|
63
|
+
other = DSL.to_dsp(other)
|
|
64
|
+
DSP.new(Node.new(type: NodeType::MUL, inputs: [node, other.node]))
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def to_s
|
|
68
|
+
Emitter.emit(node)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def inspect
|
|
72
|
+
"#<Ruby2Faust::DSP #{to_s}>"
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Add / mix signals (Faust +)
|
|
76
|
+
# @param other [Numeric, DSP, Symbol]
|
|
77
|
+
# @return [DSP]
|
|
78
|
+
def +(other)
|
|
79
|
+
other = DSL.to_dsp(other)
|
|
80
|
+
DSP.new(Node.new(type: NodeType::ADD, inputs: [node, other.node]))
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Subtract signals (Faust -)
|
|
84
|
+
# @param other [Numeric, DSP, Symbol]
|
|
85
|
+
# @return [DSP]
|
|
86
|
+
def -(other)
|
|
87
|
+
other = DSL.to_dsp(other)
|
|
88
|
+
DSP.new(Node.new(type: NodeType::SUB, inputs: [node, other.node]))
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Divide signals (Faust /)
|
|
92
|
+
# @param other [Numeric, DSP, Symbol]
|
|
93
|
+
# @return [DSP]
|
|
94
|
+
def /(other)
|
|
95
|
+
other = DSL.to_dsp(other)
|
|
96
|
+
DSP.new(Node.new(type: NodeType::DIV, inputs: [node, other.node]))
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Negative of signal (Faust 0 - x)
|
|
100
|
+
# @return [DSP]
|
|
101
|
+
def neg
|
|
102
|
+
DSP.new(Node.new(type: NodeType::NEG, inputs: [node]))
|
|
103
|
+
end
|
|
104
|
+
alias -@ neg
|
|
105
|
+
|
|
106
|
+
# Modulo (Faust %)
|
|
107
|
+
# @param other [Numeric, DSP]
|
|
108
|
+
# @return [DSP]
|
|
109
|
+
def %(other)
|
|
110
|
+
other = DSL.to_dsp(other)
|
|
111
|
+
DSP.new(Node.new(type: NodeType::MOD, inputs: [node, other.node]))
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Comparison operators - return DSP nodes for Faust comparisons
|
|
115
|
+
# Note: These return DSP, not boolean, for signal processing
|
|
116
|
+
|
|
117
|
+
# Less than (Faust <)
|
|
118
|
+
def <(other)
|
|
119
|
+
other = DSL.to_dsp(other)
|
|
120
|
+
DSP.new(Node.new(type: NodeType::LT, inputs: [node, other.node]))
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Greater than (Faust >)
|
|
124
|
+
def >(other)
|
|
125
|
+
other = DSL.to_dsp(other)
|
|
126
|
+
DSP.new(Node.new(type: NodeType::GT, inputs: [node, other.node]))
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# Less than or equal (Faust <=)
|
|
130
|
+
def <=(other)
|
|
131
|
+
other = DSL.to_dsp(other)
|
|
132
|
+
DSP.new(Node.new(type: NodeType::LE, inputs: [node, other.node]))
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Greater than or equal (Faust >=)
|
|
136
|
+
def >=(other)
|
|
137
|
+
other = DSL.to_dsp(other)
|
|
138
|
+
DSP.new(Node.new(type: NodeType::GE, inputs: [node, other.node]))
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Equal (Faust ==) - named method since Ruby == must return boolean
|
|
142
|
+
def eq(other)
|
|
143
|
+
other = DSL.to_dsp(other)
|
|
144
|
+
DSP.new(Node.new(type: NodeType::EQ, inputs: [node, other.node]))
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Not equal (Faust !=)
|
|
148
|
+
def neq(other)
|
|
149
|
+
other = DSL.to_dsp(other)
|
|
150
|
+
DSP.new(Node.new(type: NodeType::NEQ, inputs: [node, other.node]))
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Bitwise AND (Faust &)
|
|
154
|
+
def &(other)
|
|
155
|
+
other = DSL.to_dsp(other)
|
|
156
|
+
DSP.new(Node.new(type: NodeType::BAND, inputs: [node, other.node]))
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Bitwise XOR (Faust xor)
|
|
160
|
+
def ^(other)
|
|
161
|
+
other = DSL.to_dsp(other)
|
|
162
|
+
DSP.new(Node.new(type: NodeType::XOR, inputs: [node, other.node]))
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# Bitwise OR - use method name to avoid conflict with parallel composition
|
|
166
|
+
def bor(other)
|
|
167
|
+
other = DSL.to_dsp(other)
|
|
168
|
+
DSP.new(Node.new(type: NodeType::BOR, inputs: [node, other.node]))
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
# DSL module with comprehensive Faust library primitives.
|
|
173
|
+
module DSL
|
|
174
|
+
module_function
|
|
175
|
+
|
|
176
|
+
def to_dsp(value)
|
|
177
|
+
case value
|
|
178
|
+
when DSP then value
|
|
179
|
+
when Numeric then literal(value.to_s)
|
|
180
|
+
when String then literal(value)
|
|
181
|
+
when Symbol then literal(value.to_s)
|
|
182
|
+
else raise ArgumentError, "Cannot convert #{value.class} to DSP"
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
# =========================================================================
|
|
187
|
+
# COMMENTS / DOCUMENTATION
|
|
188
|
+
# =========================================================================
|
|
189
|
+
|
|
190
|
+
# Line comment (appears on its own line in Faust output)
|
|
191
|
+
# @param text [String] Comment text
|
|
192
|
+
# @return [DSP] Comment node
|
|
193
|
+
def doc(text)
|
|
194
|
+
DSP.new(Node.new(type: NodeType::COMMENT, args: [text], channels: 0))
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
# =========================================================================
|
|
198
|
+
# OSCILLATORS (os.)
|
|
199
|
+
# =========================================================================
|
|
200
|
+
|
|
201
|
+
def osc(freq = wire)
|
|
202
|
+
freq = to_dsp(freq)
|
|
203
|
+
DSP.new(Node.new(type: NodeType::OSC, inputs: [freq.node]))
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def saw(freq = wire)
|
|
207
|
+
freq = to_dsp(freq)
|
|
208
|
+
DSP.new(Node.new(type: NodeType::SAW, inputs: [freq.node]))
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
def square(freq = wire)
|
|
212
|
+
freq = to_dsp(freq)
|
|
213
|
+
DSP.new(Node.new(type: NodeType::SQUARE, inputs: [freq.node]))
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def triangle(freq = wire)
|
|
217
|
+
freq = to_dsp(freq)
|
|
218
|
+
DSP.new(Node.new(type: NodeType::TRIANGLE, inputs: [freq.node]))
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def phasor(tablesize, freq)
|
|
222
|
+
tablesize = to_dsp(tablesize)
|
|
223
|
+
freq = to_dsp(freq)
|
|
224
|
+
DSP.new(Node.new(type: NodeType::PHASOR, inputs: [tablesize.node, freq.node]))
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
def lf_saw(freq)
|
|
228
|
+
freq = to_dsp(freq)
|
|
229
|
+
DSP.new(Node.new(type: NodeType::LF_SAW, inputs: [freq.node]))
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
def lf_triangle(freq)
|
|
233
|
+
freq = to_dsp(freq)
|
|
234
|
+
DSP.new(Node.new(type: NodeType::LF_TRIANGLE, inputs: [freq.node]))
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
def lf_square(freq)
|
|
238
|
+
freq = to_dsp(freq)
|
|
239
|
+
DSP.new(Node.new(type: NodeType::LF_SQUARE, inputs: [freq.node]))
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
def imptrain(freq = wire)
|
|
243
|
+
freq = to_dsp(freq)
|
|
244
|
+
DSP.new(Node.new(type: NodeType::IMPTRAIN, inputs: [freq.node]))
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
def pulsetrain(freq, duty)
|
|
248
|
+
freq = to_dsp(freq)
|
|
249
|
+
duty = to_dsp(duty)
|
|
250
|
+
DSP.new(Node.new(type: NodeType::PULSETRAIN, inputs: [freq.node, duty.node]))
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
# =========================================================================
|
|
254
|
+
# NOISE (no.)
|
|
255
|
+
# =========================================================================
|
|
256
|
+
|
|
257
|
+
def noise
|
|
258
|
+
DSP.new(Node.new(type: NodeType::NOISE))
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
def pink_noise
|
|
262
|
+
DSP.new(Node.new(type: NodeType::PINK_NOISE))
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
# =========================================================================
|
|
266
|
+
# FILTERS (fi.)
|
|
267
|
+
# =========================================================================
|
|
268
|
+
|
|
269
|
+
def lp(freq = wire, order: 1)
|
|
270
|
+
freq = to_dsp(freq)
|
|
271
|
+
DSP.new(Node.new(type: NodeType::LP, args: [order], inputs: [freq.node]))
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
def hp(freq = wire, order: 1)
|
|
275
|
+
freq = to_dsp(freq)
|
|
276
|
+
DSP.new(Node.new(type: NodeType::HP, args: [order], inputs: [freq.node]))
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
def bp(freq = wire, q: 1)
|
|
280
|
+
freq = to_dsp(freq)
|
|
281
|
+
q = to_dsp(q)
|
|
282
|
+
DSP.new(Node.new(type: NodeType::BP, inputs: [freq.node, q.node]))
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
def resonlp(freq, q, gain = 1)
|
|
286
|
+
freq = to_dsp(freq)
|
|
287
|
+
q = to_dsp(q)
|
|
288
|
+
gain = to_dsp(gain)
|
|
289
|
+
DSP.new(Node.new(type: NodeType::RESONLP, inputs: [freq.node, q.node, gain.node]))
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
def resonhp(freq, q, gain = 1)
|
|
293
|
+
freq = to_dsp(freq)
|
|
294
|
+
q = to_dsp(q)
|
|
295
|
+
gain = to_dsp(gain)
|
|
296
|
+
DSP.new(Node.new(type: NodeType::RESONHP, inputs: [freq.node, q.node, gain.node]))
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
def resonbp(freq, q, gain = 1)
|
|
300
|
+
freq = to_dsp(freq)
|
|
301
|
+
q = to_dsp(q)
|
|
302
|
+
gain = to_dsp(gain)
|
|
303
|
+
DSP.new(Node.new(type: NodeType::RESONBP, inputs: [freq.node, q.node, gain.node]))
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
def allpass(maxdelay, delay, feedback)
|
|
307
|
+
maxdelay = to_dsp(maxdelay)
|
|
308
|
+
delay = to_dsp(delay)
|
|
309
|
+
feedback = to_dsp(feedback)
|
|
310
|
+
DSP.new(Node.new(type: NodeType::ALLPASS, inputs: [maxdelay.node, delay.node, feedback.node]))
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
def dcblock
|
|
314
|
+
DSP.new(Node.new(type: NodeType::DCBLOCK))
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
def peak_eq(freq, q, gain_db)
|
|
318
|
+
freq = to_dsp(freq)
|
|
319
|
+
q = to_dsp(q)
|
|
320
|
+
gain_db = to_dsp(gain_db)
|
|
321
|
+
DSP.new(Node.new(type: NodeType::PEAK_EQ, inputs: [freq.node, q.node, gain_db.node]))
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
# SVF (State Variable Filter) filters
|
|
325
|
+
|
|
326
|
+
def svf_lp(freq, q)
|
|
327
|
+
freq = to_dsp(freq)
|
|
328
|
+
q = to_dsp(q)
|
|
329
|
+
DSP.new(Node.new(type: NodeType::SVF_LP, inputs: [freq.node, q.node]))
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
def svf_hp(freq, q)
|
|
333
|
+
freq = to_dsp(freq)
|
|
334
|
+
q = to_dsp(q)
|
|
335
|
+
DSP.new(Node.new(type: NodeType::SVF_HP, inputs: [freq.node, q.node]))
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
def svf_bp(freq, q)
|
|
339
|
+
freq = to_dsp(freq)
|
|
340
|
+
q = to_dsp(q)
|
|
341
|
+
DSP.new(Node.new(type: NodeType::SVF_BP, inputs: [freq.node, q.node]))
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
def svf_notch(freq, q)
|
|
345
|
+
freq = to_dsp(freq)
|
|
346
|
+
q = to_dsp(q)
|
|
347
|
+
DSP.new(Node.new(type: NodeType::SVF_NOTCH, inputs: [freq.node, q.node]))
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
def svf_ap(freq, q)
|
|
351
|
+
freq = to_dsp(freq)
|
|
352
|
+
q = to_dsp(q)
|
|
353
|
+
DSP.new(Node.new(type: NodeType::SVF_AP, inputs: [freq.node, q.node]))
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
def svf_bell(freq, q, gain)
|
|
357
|
+
freq = to_dsp(freq)
|
|
358
|
+
q = to_dsp(q)
|
|
359
|
+
gain = to_dsp(gain)
|
|
360
|
+
DSP.new(Node.new(type: NodeType::SVF_BELL, inputs: [freq.node, q.node, gain.node]))
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
def svf_ls(freq, q, gain)
|
|
364
|
+
freq = to_dsp(freq)
|
|
365
|
+
q = to_dsp(q)
|
|
366
|
+
gain = to_dsp(gain)
|
|
367
|
+
DSP.new(Node.new(type: NodeType::SVF_LS, inputs: [freq.node, q.node, gain.node]))
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
def svf_hs(freq, q, gain)
|
|
371
|
+
freq = to_dsp(freq)
|
|
372
|
+
q = to_dsp(q)
|
|
373
|
+
gain = to_dsp(gain)
|
|
374
|
+
DSP.new(Node.new(type: NodeType::SVF_HS, inputs: [freq.node, q.node, gain.node]))
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
# Convenience alias for svf_ls (low shelf)
|
|
378
|
+
def svfLowShelf(freq, q, gain = 1)
|
|
379
|
+
svf_ls(freq, q, gain)
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
# Other filter types
|
|
383
|
+
|
|
384
|
+
def lowpass3e(freq)
|
|
385
|
+
freq = to_dsp(freq)
|
|
386
|
+
DSP.new(Node.new(type: NodeType::LOWPASS3E, inputs: [freq.node]))
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
def highpass3e(freq)
|
|
390
|
+
freq = to_dsp(freq)
|
|
391
|
+
DSP.new(Node.new(type: NodeType::HIGHPASS3E, inputs: [freq.node]))
|
|
392
|
+
end
|
|
393
|
+
|
|
394
|
+
def lowpass6e(freq)
|
|
395
|
+
freq = to_dsp(freq)
|
|
396
|
+
DSP.new(Node.new(type: NodeType::LOWPASS6E, inputs: [freq.node]))
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
def highpass6e(freq)
|
|
400
|
+
freq = to_dsp(freq)
|
|
401
|
+
DSP.new(Node.new(type: NodeType::HIGHPASS6E, inputs: [freq.node]))
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
def bandstop(order, freq, q)
|
|
405
|
+
order = to_dsp(order)
|
|
406
|
+
freq = to_dsp(freq)
|
|
407
|
+
q = to_dsp(q)
|
|
408
|
+
DSP.new(Node.new(type: NodeType::BANDSTOP, inputs: [order.node, freq.node, q.node]))
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
def notchw(freq, width)
|
|
412
|
+
freq = to_dsp(freq)
|
|
413
|
+
width = to_dsp(width)
|
|
414
|
+
DSP.new(Node.new(type: NodeType::NOTCHW, inputs: [freq.node, width.node]))
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
def low_shelf(freq, q, gain)
|
|
418
|
+
freq = to_dsp(freq)
|
|
419
|
+
q = to_dsp(q)
|
|
420
|
+
gain = to_dsp(gain)
|
|
421
|
+
DSP.new(Node.new(type: NodeType::LOW_SHELF, inputs: [freq.node, q.node, gain.node]))
|
|
422
|
+
end
|
|
423
|
+
|
|
424
|
+
def high_shelf(freq, q, gain)
|
|
425
|
+
freq = to_dsp(freq)
|
|
426
|
+
q = to_dsp(q)
|
|
427
|
+
gain = to_dsp(gain)
|
|
428
|
+
DSP.new(Node.new(type: NodeType::HIGH_SHELF, inputs: [freq.node, q.node, gain.node]))
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
def peak_eq_cq(freq, q, gain)
|
|
432
|
+
freq = to_dsp(freq)
|
|
433
|
+
q = to_dsp(q)
|
|
434
|
+
gain = to_dsp(gain)
|
|
435
|
+
DSP.new(Node.new(type: NodeType::PEAK_EQ_CQ, inputs: [freq.node, q.node, gain.node]))
|
|
436
|
+
end
|
|
437
|
+
|
|
438
|
+
def fi_pole(p)
|
|
439
|
+
p = to_dsp(p)
|
|
440
|
+
DSP.new(Node.new(type: NodeType::FI_POLE, inputs: [p.node]))
|
|
441
|
+
end
|
|
442
|
+
|
|
443
|
+
def fi_zero(z)
|
|
444
|
+
z = to_dsp(z)
|
|
445
|
+
DSP.new(Node.new(type: NodeType::FI_ZERO, inputs: [z.node]))
|
|
446
|
+
end
|
|
447
|
+
|
|
448
|
+
def tf1(b0, b1, a1)
|
|
449
|
+
b0 = to_dsp(b0)
|
|
450
|
+
b1 = to_dsp(b1)
|
|
451
|
+
a1 = to_dsp(a1)
|
|
452
|
+
DSP.new(Node.new(type: NodeType::TF1, inputs: [b0.node, b1.node, a1.node]))
|
|
453
|
+
end
|
|
454
|
+
|
|
455
|
+
def tf2(b0, b1, b2, a1, a2)
|
|
456
|
+
b0 = to_dsp(b0)
|
|
457
|
+
b1 = to_dsp(b1)
|
|
458
|
+
b2 = to_dsp(b2)
|
|
459
|
+
a1 = to_dsp(a1)
|
|
460
|
+
a2 = to_dsp(a2)
|
|
461
|
+
DSP.new(Node.new(type: NodeType::TF2, inputs: [b0.node, b1.node, b2.node, a1.node, a2.node]))
|
|
462
|
+
end
|
|
463
|
+
|
|
464
|
+
def tf1s(b0, b1, a1)
|
|
465
|
+
b0 = to_dsp(b0)
|
|
466
|
+
b1 = to_dsp(b1)
|
|
467
|
+
a1 = to_dsp(a1)
|
|
468
|
+
DSP.new(Node.new(type: NodeType::TF1S, inputs: [b0.node, b1.node, a1.node]))
|
|
469
|
+
end
|
|
470
|
+
|
|
471
|
+
def tf2s(b0, b1, b2, a1, a2)
|
|
472
|
+
b0 = to_dsp(b0)
|
|
473
|
+
b1 = to_dsp(b1)
|
|
474
|
+
b2 = to_dsp(b2)
|
|
475
|
+
a1 = to_dsp(a1)
|
|
476
|
+
a2 = to_dsp(a2)
|
|
477
|
+
DSP.new(Node.new(type: NodeType::TF2S, inputs: [b0.node, b1.node, b2.node, a1.node, a2.node]))
|
|
478
|
+
end
|
|
479
|
+
|
|
480
|
+
def iir(bcoeffs, acoeffs)
|
|
481
|
+
bcoeffs = to_dsp(bcoeffs)
|
|
482
|
+
acoeffs = to_dsp(acoeffs)
|
|
483
|
+
DSP.new(Node.new(type: NodeType::IIR, inputs: [bcoeffs.node, acoeffs.node]))
|
|
484
|
+
end
|
|
485
|
+
|
|
486
|
+
def fir(coeffs)
|
|
487
|
+
coeffs = to_dsp(coeffs)
|
|
488
|
+
DSP.new(Node.new(type: NodeType::FIR, inputs: [coeffs.node]))
|
|
489
|
+
end
|
|
490
|
+
|
|
491
|
+
def conv(impulse, size)
|
|
492
|
+
impulse = to_dsp(impulse)
|
|
493
|
+
size = to_dsp(size)
|
|
494
|
+
DSP.new(Node.new(type: NodeType::CONV, inputs: [impulse.node, size.node]))
|
|
495
|
+
end
|
|
496
|
+
|
|
497
|
+
def fbcombfilter(maxdel, del, fb)
|
|
498
|
+
maxdel = to_dsp(maxdel)
|
|
499
|
+
del = to_dsp(del)
|
|
500
|
+
fb = to_dsp(fb)
|
|
501
|
+
DSP.new(Node.new(type: NodeType::FBCOMBFILTER, inputs: [maxdel.node, del.node, fb.node]))
|
|
502
|
+
end
|
|
503
|
+
|
|
504
|
+
def ffcombfilter(maxdel, del)
|
|
505
|
+
maxdel = to_dsp(maxdel)
|
|
506
|
+
del = to_dsp(del)
|
|
507
|
+
DSP.new(Node.new(type: NodeType::FFCOMBFILTER, inputs: [maxdel.node, del.node]))
|
|
508
|
+
end
|
|
509
|
+
|
|
510
|
+
# =========================================================================
|
|
511
|
+
# DELAYS (de.)
|
|
512
|
+
# =========================================================================
|
|
513
|
+
|
|
514
|
+
def delay(maxdelay, d)
|
|
515
|
+
maxdelay = to_dsp(maxdelay)
|
|
516
|
+
d = to_dsp(d)
|
|
517
|
+
DSP.new(Node.new(type: NodeType::DELAY, inputs: [maxdelay.node, d.node]))
|
|
518
|
+
end
|
|
519
|
+
|
|
520
|
+
def fdelay(maxdelay, d)
|
|
521
|
+
maxdelay = to_dsp(maxdelay)
|
|
522
|
+
d = to_dsp(d)
|
|
523
|
+
DSP.new(Node.new(type: NodeType::FDELAY, inputs: [maxdelay.node, d.node]))
|
|
524
|
+
end
|
|
525
|
+
|
|
526
|
+
def sdelay(maxdelay, interp, d)
|
|
527
|
+
maxdelay = to_dsp(maxdelay)
|
|
528
|
+
interp = to_dsp(interp)
|
|
529
|
+
d = to_dsp(d)
|
|
530
|
+
DSP.new(Node.new(type: NodeType::SDELAY, inputs: [maxdelay.node, interp.node, d.node]))
|
|
531
|
+
end
|
|
532
|
+
|
|
533
|
+
# =========================================================================
|
|
534
|
+
# ENVELOPES (en.)
|
|
535
|
+
# =========================================================================
|
|
536
|
+
|
|
537
|
+
def ar(attack, release, gate)
|
|
538
|
+
attack = to_dsp(attack)
|
|
539
|
+
release = to_dsp(release)
|
|
540
|
+
gate = to_dsp(gate)
|
|
541
|
+
DSP.new(Node.new(type: NodeType::AR, inputs: [attack.node, release.node, gate.node]))
|
|
542
|
+
end
|
|
543
|
+
|
|
544
|
+
def asr(attack, sustain_level, release, gate)
|
|
545
|
+
attack = to_dsp(attack)
|
|
546
|
+
sustain_level = to_dsp(sustain_level)
|
|
547
|
+
release = to_dsp(release)
|
|
548
|
+
gate = to_dsp(gate)
|
|
549
|
+
DSP.new(Node.new(type: NodeType::ASR, inputs: [attack.node, sustain_level.node, release.node, gate.node]))
|
|
550
|
+
end
|
|
551
|
+
|
|
552
|
+
def adsr(attack, decay, sustain, release, gate)
|
|
553
|
+
attack = to_dsp(attack)
|
|
554
|
+
decay = to_dsp(decay)
|
|
555
|
+
sustain = to_dsp(sustain)
|
|
556
|
+
release = to_dsp(release)
|
|
557
|
+
gate = to_dsp(gate)
|
|
558
|
+
DSP.new(Node.new(type: NodeType::ADSR, inputs: [attack.node, decay.node, sustain.node, release.node, gate.node]))
|
|
559
|
+
end
|
|
560
|
+
|
|
561
|
+
def adsre(attack, decay, sustain, release, gate)
|
|
562
|
+
attack = to_dsp(attack)
|
|
563
|
+
decay = to_dsp(decay)
|
|
564
|
+
sustain = to_dsp(sustain)
|
|
565
|
+
release = to_dsp(release)
|
|
566
|
+
gate = to_dsp(gate)
|
|
567
|
+
DSP.new(Node.new(type: NodeType::ADSRE, inputs: [attack.node, decay.node, sustain.node, release.node, gate.node]))
|
|
568
|
+
end
|
|
569
|
+
|
|
570
|
+
# =========================================================================
|
|
571
|
+
# MATH (primitives + ma.)
|
|
572
|
+
# =========================================================================
|
|
573
|
+
|
|
574
|
+
def gain(x)
|
|
575
|
+
x = to_dsp(x)
|
|
576
|
+
DSP.new(Node.new(type: NodeType::GAIN, inputs: [x.node]))
|
|
577
|
+
end
|
|
578
|
+
|
|
579
|
+
def add
|
|
580
|
+
DSP.new(Node.new(type: NodeType::ADD))
|
|
581
|
+
end
|
|
582
|
+
|
|
583
|
+
def mul
|
|
584
|
+
DSP.new(Node.new(type: NodeType::MUL))
|
|
585
|
+
end
|
|
586
|
+
|
|
587
|
+
def sub
|
|
588
|
+
DSP.new(Node.new(type: NodeType::SUB))
|
|
589
|
+
end
|
|
590
|
+
|
|
591
|
+
def div
|
|
592
|
+
DSP.new(Node.new(type: NodeType::DIV))
|
|
593
|
+
end
|
|
594
|
+
|
|
595
|
+
def neg
|
|
596
|
+
DSP.new(Node.new(type: NodeType::NEG))
|
|
597
|
+
end
|
|
598
|
+
|
|
599
|
+
def abs_
|
|
600
|
+
DSP.new(Node.new(type: NodeType::ABS))
|
|
601
|
+
end
|
|
602
|
+
|
|
603
|
+
def min_(a, b)
|
|
604
|
+
a = to_dsp(a)
|
|
605
|
+
b = to_dsp(b)
|
|
606
|
+
DSP.new(Node.new(type: NodeType::MIN, inputs: [a.node, b.node]))
|
|
607
|
+
end
|
|
608
|
+
|
|
609
|
+
def max_(a, b)
|
|
610
|
+
a = to_dsp(a)
|
|
611
|
+
b = to_dsp(b)
|
|
612
|
+
DSP.new(Node.new(type: NodeType::MAX, inputs: [a.node, b.node]))
|
|
613
|
+
end
|
|
614
|
+
|
|
615
|
+
def clip(min_val, max_val)
|
|
616
|
+
min_val = to_dsp(min_val)
|
|
617
|
+
max_val = to_dsp(max_val)
|
|
618
|
+
DSP.new(Node.new(type: NodeType::CLIP, inputs: [min_val.node, max_val.node]))
|
|
619
|
+
end
|
|
620
|
+
|
|
621
|
+
def pow(base, exponent)
|
|
622
|
+
base = to_dsp(base)
|
|
623
|
+
exponent = to_dsp(exponent)
|
|
624
|
+
DSP.new(Node.new(type: NodeType::POW, inputs: [base.node, exponent.node]))
|
|
625
|
+
end
|
|
626
|
+
|
|
627
|
+
def sqrt_
|
|
628
|
+
DSP.new(Node.new(type: NodeType::SQRT))
|
|
629
|
+
end
|
|
630
|
+
|
|
631
|
+
def exp_
|
|
632
|
+
DSP.new(Node.new(type: NodeType::EXP))
|
|
633
|
+
end
|
|
634
|
+
|
|
635
|
+
def log_
|
|
636
|
+
DSP.new(Node.new(type: NodeType::LOG))
|
|
637
|
+
end
|
|
638
|
+
|
|
639
|
+
def log10_
|
|
640
|
+
DSP.new(Node.new(type: NodeType::LOG10))
|
|
641
|
+
end
|
|
642
|
+
|
|
643
|
+
def sin_
|
|
644
|
+
DSP.new(Node.new(type: NodeType::SIN))
|
|
645
|
+
end
|
|
646
|
+
|
|
647
|
+
def cos_
|
|
648
|
+
DSP.new(Node.new(type: NodeType::COS))
|
|
649
|
+
end
|
|
650
|
+
|
|
651
|
+
def tan_
|
|
652
|
+
DSP.new(Node.new(type: NodeType::TAN))
|
|
653
|
+
end
|
|
654
|
+
|
|
655
|
+
def tanh_
|
|
656
|
+
DSP.new(Node.new(type: NodeType::TANH))
|
|
657
|
+
end
|
|
658
|
+
|
|
659
|
+
def sinh_
|
|
660
|
+
DSP.new(Node.new(type: NodeType::SINH))
|
|
661
|
+
end
|
|
662
|
+
|
|
663
|
+
def cosh_
|
|
664
|
+
DSP.new(Node.new(type: NodeType::COSH))
|
|
665
|
+
end
|
|
666
|
+
|
|
667
|
+
def asinh_
|
|
668
|
+
DSP.new(Node.new(type: NodeType::ASINH))
|
|
669
|
+
end
|
|
670
|
+
|
|
671
|
+
def acosh_
|
|
672
|
+
DSP.new(Node.new(type: NodeType::ACOSH))
|
|
673
|
+
end
|
|
674
|
+
|
|
675
|
+
def atanh_
|
|
676
|
+
DSP.new(Node.new(type: NodeType::ATANH))
|
|
677
|
+
end
|
|
678
|
+
|
|
679
|
+
def asin_
|
|
680
|
+
DSP.new(Node.new(type: NodeType::ASIN))
|
|
681
|
+
end
|
|
682
|
+
|
|
683
|
+
def acos_
|
|
684
|
+
DSP.new(Node.new(type: NodeType::ACOS))
|
|
685
|
+
end
|
|
686
|
+
|
|
687
|
+
def atan_
|
|
688
|
+
DSP.new(Node.new(type: NodeType::ATAN))
|
|
689
|
+
end
|
|
690
|
+
|
|
691
|
+
def atan2(y, x)
|
|
692
|
+
y = to_dsp(y)
|
|
693
|
+
x = to_dsp(x)
|
|
694
|
+
DSP.new(Node.new(type: NodeType::ATAN2, inputs: [y.node, x.node]))
|
|
695
|
+
end
|
|
696
|
+
|
|
697
|
+
def floor_
|
|
698
|
+
DSP.new(Node.new(type: NodeType::FLOOR))
|
|
699
|
+
end
|
|
700
|
+
|
|
701
|
+
def ceil_
|
|
702
|
+
DSP.new(Node.new(type: NodeType::CEIL))
|
|
703
|
+
end
|
|
704
|
+
|
|
705
|
+
def rint_
|
|
706
|
+
DSP.new(Node.new(type: NodeType::RINT))
|
|
707
|
+
end
|
|
708
|
+
|
|
709
|
+
def fmod(x, y)
|
|
710
|
+
x = to_dsp(x)
|
|
711
|
+
y = to_dsp(y)
|
|
712
|
+
DSP.new(Node.new(type: NodeType::FMOD, inputs: [x.node, y.node]))
|
|
713
|
+
end
|
|
714
|
+
|
|
715
|
+
def int_
|
|
716
|
+
DSP.new(Node.new(type: NodeType::INT))
|
|
717
|
+
end
|
|
718
|
+
|
|
719
|
+
def float_
|
|
720
|
+
DSP.new(Node.new(type: NodeType::FLOAT))
|
|
721
|
+
end
|
|
722
|
+
|
|
723
|
+
# =========================================================================
|
|
724
|
+
# CONVERSION (ba.)
|
|
725
|
+
# =========================================================================
|
|
726
|
+
|
|
727
|
+
def db2linear(x)
|
|
728
|
+
x = to_dsp(x)
|
|
729
|
+
DSP.new(Node.new(type: NodeType::DB2LINEAR, inputs: [x.node]))
|
|
730
|
+
end
|
|
731
|
+
|
|
732
|
+
def linear2db(x)
|
|
733
|
+
x = to_dsp(x)
|
|
734
|
+
DSP.new(Node.new(type: NodeType::LINEAR2DB, inputs: [x.node]))
|
|
735
|
+
end
|
|
736
|
+
|
|
737
|
+
def samp2sec(x)
|
|
738
|
+
x = to_dsp(x)
|
|
739
|
+
DSP.new(Node.new(type: NodeType::SAMP2SEC, inputs: [x.node]))
|
|
740
|
+
end
|
|
741
|
+
|
|
742
|
+
def sec2samp(x)
|
|
743
|
+
x = to_dsp(x)
|
|
744
|
+
DSP.new(Node.new(type: NodeType::SEC2SAMP, inputs: [x.node]))
|
|
745
|
+
end
|
|
746
|
+
|
|
747
|
+
def midi2hz(x)
|
|
748
|
+
x = to_dsp(x)
|
|
749
|
+
DSP.new(Node.new(type: NodeType::MIDI2HZ, inputs: [x.node]))
|
|
750
|
+
end
|
|
751
|
+
|
|
752
|
+
def hz2midi(x)
|
|
753
|
+
x = to_dsp(x)
|
|
754
|
+
DSP.new(Node.new(type: NodeType::HZ2MIDI, inputs: [x.node]))
|
|
755
|
+
end
|
|
756
|
+
|
|
757
|
+
def tau2pole(tau)
|
|
758
|
+
tau = to_dsp(tau)
|
|
759
|
+
DSP.new(Node.new(type: NodeType::TAU2POLE, inputs: [tau.node]))
|
|
760
|
+
end
|
|
761
|
+
|
|
762
|
+
def pole2tau(pole)
|
|
763
|
+
pole = to_dsp(pole)
|
|
764
|
+
DSP.new(Node.new(type: NodeType::POLE2TAU, inputs: [pole.node]))
|
|
765
|
+
end
|
|
766
|
+
|
|
767
|
+
def ba_if(cond, then_val, else_val)
|
|
768
|
+
cond = to_dsp(cond)
|
|
769
|
+
then_val = to_dsp(then_val)
|
|
770
|
+
else_val = to_dsp(else_val)
|
|
771
|
+
DSP.new(Node.new(type: NodeType::BA_IF, inputs: [cond.node, then_val.node, else_val.node]))
|
|
772
|
+
end
|
|
773
|
+
|
|
774
|
+
def selector(n, sel, *inputs)
|
|
775
|
+
sel = to_dsp(sel)
|
|
776
|
+
inputs = inputs.map { |i| to_dsp(i) }
|
|
777
|
+
DSP.new(Node.new(type: NodeType::SELECTOR, args: [n], inputs: [sel.node] + inputs.map(&:node)))
|
|
778
|
+
end
|
|
779
|
+
|
|
780
|
+
def ba_take(idx, tuple)
|
|
781
|
+
idx = to_dsp(idx)
|
|
782
|
+
tuple = to_dsp(tuple)
|
|
783
|
+
DSP.new(Node.new(type: NodeType::BA_TAKE, inputs: [idx.node, tuple.node]))
|
|
784
|
+
end
|
|
785
|
+
|
|
786
|
+
# =========================================================================
|
|
787
|
+
# SMOOTHING (si.)
|
|
788
|
+
# =========================================================================
|
|
789
|
+
|
|
790
|
+
def smooth(tau)
|
|
791
|
+
tau = to_dsp(tau)
|
|
792
|
+
DSP.new(Node.new(type: NodeType::SMOOTH, inputs: [tau.node]))
|
|
793
|
+
end
|
|
794
|
+
|
|
795
|
+
def smoo
|
|
796
|
+
DSP.new(Node.new(type: NodeType::SMOO))
|
|
797
|
+
end
|
|
798
|
+
|
|
799
|
+
# =========================================================================
|
|
800
|
+
# SELECTORS
|
|
801
|
+
# =========================================================================
|
|
802
|
+
|
|
803
|
+
def select2(condition, a, b)
|
|
804
|
+
condition = to_dsp(condition)
|
|
805
|
+
a = to_dsp(a)
|
|
806
|
+
b = to_dsp(b)
|
|
807
|
+
DSP.new(Node.new(type: NodeType::SELECT2, inputs: [condition.node, a.node, b.node], channels: a.node.channels))
|
|
808
|
+
end
|
|
809
|
+
|
|
810
|
+
def selectn(n, index, *signals)
|
|
811
|
+
index = to_dsp(index)
|
|
812
|
+
signals = signals.map { |s| to_dsp(s) }
|
|
813
|
+
DSP.new(Node.new(type: NodeType::SELECTN, args: [n], inputs: [index.node] + signals.map(&:node), channels: signals.first&.node&.channels || 1))
|
|
814
|
+
end
|
|
815
|
+
|
|
816
|
+
# =========================================================================
|
|
817
|
+
# ROUTING (si./ro.)
|
|
818
|
+
# =========================================================================
|
|
819
|
+
|
|
820
|
+
def bus(n)
|
|
821
|
+
DSP.new(Node.new(type: NodeType::BUS, args: [n], channels: n))
|
|
822
|
+
end
|
|
823
|
+
|
|
824
|
+
def block(n)
|
|
825
|
+
DSP.new(Node.new(type: NodeType::BLOCK, args: [n], channels: 0))
|
|
826
|
+
end
|
|
827
|
+
|
|
828
|
+
# =========================================================================
|
|
829
|
+
# REVERBS (re.)
|
|
830
|
+
# =========================================================================
|
|
831
|
+
|
|
832
|
+
def freeverb(fb1, fb2, damp, spread)
|
|
833
|
+
fb1 = to_dsp(fb1)
|
|
834
|
+
fb2 = to_dsp(fb2)
|
|
835
|
+
damp = to_dsp(damp)
|
|
836
|
+
spread = to_dsp(spread)
|
|
837
|
+
DSP.new(Node.new(type: NodeType::FREEVERB, inputs: [fb1.node, fb2.node, damp.node, spread.node]))
|
|
838
|
+
end
|
|
839
|
+
|
|
840
|
+
def zita_rev(rdel, f1, f2, t60dc, t60m, fsmax)
|
|
841
|
+
DSP.new(Node.new(type: NodeType::ZITA_REV, args: [rdel, f1, f2, t60dc, t60m, fsmax], channels: 2))
|
|
842
|
+
end
|
|
843
|
+
|
|
844
|
+
def jpverb(t60, damp, size, early_diff, mod_depth, mod_freq, low, mid, high, low_cut, high_cut)
|
|
845
|
+
DSP.new(Node.new(type: NodeType::JPVERB, args: [t60, damp, size, early_diff, mod_depth, mod_freq, low, mid, high, low_cut, high_cut], channels: 2))
|
|
846
|
+
end
|
|
847
|
+
|
|
848
|
+
# =========================================================================
|
|
849
|
+
# COMPRESSORS (co.)
|
|
850
|
+
# =========================================================================
|
|
851
|
+
|
|
852
|
+
def compressor(ratio, thresh, attack, release)
|
|
853
|
+
ratio = to_dsp(ratio)
|
|
854
|
+
thresh = to_dsp(thresh)
|
|
855
|
+
attack = to_dsp(attack)
|
|
856
|
+
release = to_dsp(release)
|
|
857
|
+
DSP.new(Node.new(type: NodeType::COMPRESSOR, inputs: [ratio.node, thresh.node, attack.node, release.node]))
|
|
858
|
+
end
|
|
859
|
+
|
|
860
|
+
def limiter
|
|
861
|
+
DSP.new(Node.new(type: NodeType::LIMITER))
|
|
862
|
+
end
|
|
863
|
+
|
|
864
|
+
# =========================================================================
|
|
865
|
+
# SPATIAL (sp.)
|
|
866
|
+
# =========================================================================
|
|
867
|
+
|
|
868
|
+
def panner(pan)
|
|
869
|
+
pan = to_dsp(pan)
|
|
870
|
+
DSP.new(Node.new(type: NodeType::PANNER, inputs: [pan.node], channels: 2))
|
|
871
|
+
end
|
|
872
|
+
|
|
873
|
+
# =========================================================================
|
|
874
|
+
# UI CONTROLS
|
|
875
|
+
# =========================================================================
|
|
876
|
+
|
|
877
|
+
# Build Faust metadata string from kwargs
|
|
878
|
+
def self.build_metadata(name, order: nil, style: nil, unit: nil, tooltip: nil, scale: nil, **_)
|
|
879
|
+
meta = ""
|
|
880
|
+
meta += "[#{order}]" if order
|
|
881
|
+
meta += "[style:#{style}]" if style
|
|
882
|
+
meta += "[unit:#{unit}]" if unit
|
|
883
|
+
meta += "[tooltip:#{tooltip}]" if tooltip
|
|
884
|
+
meta += "[scale:#{scale}]" if scale
|
|
885
|
+
# If name already has metadata, append; otherwise prefix
|
|
886
|
+
name.to_s.include?("[") ? name.to_s : "#{meta}#{name}"
|
|
887
|
+
end
|
|
888
|
+
|
|
889
|
+
def slider(name, init:, min:, max:, step: 0.01, **meta)
|
|
890
|
+
full_name = DSL.build_metadata(name, **meta)
|
|
891
|
+
DSP.new(Node.new(type: NodeType::SLIDER, args: [full_name, init, min, max, step]))
|
|
892
|
+
end
|
|
893
|
+
|
|
894
|
+
def vslider(name, init:, min:, max:, step: 0.01)
|
|
895
|
+
DSP.new(Node.new(type: NodeType::VSLIDER, args: [name, init, min, max, step]))
|
|
896
|
+
end
|
|
897
|
+
|
|
898
|
+
def nentry(name, init:, min:, max:, step: 1)
|
|
899
|
+
DSP.new(Node.new(type: NodeType::NENTRY, args: [name, init, min, max, step]))
|
|
900
|
+
end
|
|
901
|
+
|
|
902
|
+
def button(name)
|
|
903
|
+
DSP.new(Node.new(type: NodeType::BUTTON, args: [name]))
|
|
904
|
+
end
|
|
905
|
+
|
|
906
|
+
def checkbox(name)
|
|
907
|
+
DSP.new(Node.new(type: NodeType::CHECKBOX, args: [name]))
|
|
908
|
+
end
|
|
909
|
+
|
|
910
|
+
def hgroup(name, content = nil, &block)
|
|
911
|
+
content = block.call if block_given?
|
|
912
|
+
raise ArgumentError, "hgroup requires content or a block" if content.nil?
|
|
913
|
+
content = to_dsp(content)
|
|
914
|
+
DSP.new(Node.new(type: NodeType::HGROUP, args: [name], inputs: [content.node], channels: content.node.channels))
|
|
915
|
+
end
|
|
916
|
+
|
|
917
|
+
def vgroup(name, content = nil, &block)
|
|
918
|
+
content = block.call if block_given?
|
|
919
|
+
raise ArgumentError, "vgroup requires content or a block" if content.nil?
|
|
920
|
+
content = to_dsp(content)
|
|
921
|
+
DSP.new(Node.new(type: NodeType::VGROUP, args: [name], inputs: [content.node], channels: content.node.channels))
|
|
922
|
+
end
|
|
923
|
+
|
|
924
|
+
def tgroup(name, content = nil, &block)
|
|
925
|
+
content = block.call if block_given?
|
|
926
|
+
raise ArgumentError, "tgroup requires content or a block" if content.nil?
|
|
927
|
+
content = to_dsp(content)
|
|
928
|
+
DSP.new(Node.new(type: NodeType::TGROUP, args: [name], inputs: [content.node], channels: content.node.channels))
|
|
929
|
+
end
|
|
930
|
+
|
|
931
|
+
# =========================================================================
|
|
932
|
+
# ITERATION
|
|
933
|
+
# =========================================================================
|
|
934
|
+
|
|
935
|
+
# Parallel iteration: par(i, n, expr)
|
|
936
|
+
# @param count [Integer] Number of iterations
|
|
937
|
+
# @yield [DSP] Block receiving iteration index as DSP param
|
|
938
|
+
# @example fpar(4) { |i| osc(i * 100) }
|
|
939
|
+
# @example fpar(4) { osc(it * 100) } # Ruby 3.4+ implicit it
|
|
940
|
+
# @return [DSP]
|
|
941
|
+
def fpar(count, &block)
|
|
942
|
+
raise ArgumentError, "fpar requires a block" unless block_given?
|
|
943
|
+
var = block.parameters.first&.last || :it
|
|
944
|
+
DSP.new(Node.new(type: NodeType::FPAR, args: [var, count, block], channels: count))
|
|
945
|
+
end
|
|
946
|
+
|
|
947
|
+
# Sequential iteration: seq(i, n, expr)
|
|
948
|
+
# @param count [Integer] Number of iterations
|
|
949
|
+
# @yield [DSP] Block receiving iteration index as DSP param
|
|
950
|
+
# @return [DSP]
|
|
951
|
+
def fseq(count, &block)
|
|
952
|
+
raise ArgumentError, "fseq requires a block" unless block_given?
|
|
953
|
+
var = block.parameters.first&.last || :it
|
|
954
|
+
DSP.new(Node.new(type: NodeType::FSEQ, args: [var, count, block]))
|
|
955
|
+
end
|
|
956
|
+
|
|
957
|
+
# Summation iteration: sum(i, n, expr)
|
|
958
|
+
# @param count [Integer] Number of iterations
|
|
959
|
+
# @yield [DSP] Block receiving iteration index as DSP param
|
|
960
|
+
# @return [DSP]
|
|
961
|
+
def fsum(count, &block)
|
|
962
|
+
raise ArgumentError, "fsum requires a block" unless block_given?
|
|
963
|
+
var = block.parameters.first&.last || :it
|
|
964
|
+
DSP.new(Node.new(type: NodeType::FSUM, args: [var, count, block]))
|
|
965
|
+
end
|
|
966
|
+
|
|
967
|
+
# Product iteration: prod(i, n, expr)
|
|
968
|
+
# @param count [Integer] Number of iterations
|
|
969
|
+
# @yield [DSP] Block receiving iteration index as DSP param
|
|
970
|
+
# @return [DSP]
|
|
971
|
+
def fprod(count, &block)
|
|
972
|
+
raise ArgumentError, "fprod requires a block" unless block_given?
|
|
973
|
+
var = block.parameters.first&.last || :it
|
|
974
|
+
DSP.new(Node.new(type: NodeType::FPROD, args: [var, count, block]))
|
|
975
|
+
end
|
|
976
|
+
|
|
977
|
+
# =========================================================================
|
|
978
|
+
# LAMBDA
|
|
979
|
+
# =========================================================================
|
|
980
|
+
|
|
981
|
+
# Lambda expression: \(x).(body)
|
|
982
|
+
# @param params [Array<Symbol>] Parameter names
|
|
983
|
+
# @yield Block that receives parameters and returns body expression
|
|
984
|
+
# @return [DSP]
|
|
985
|
+
def flambda(*params, &block)
|
|
986
|
+
raise ArgumentError, "flambda requires a block" unless block_given?
|
|
987
|
+
DSP.new(Node.new(type: NodeType::LAMBDA, args: [params, block]))
|
|
988
|
+
end
|
|
989
|
+
|
|
990
|
+
# Parameter reference within a lambda
|
|
991
|
+
# @param name [Symbol] Parameter name
|
|
992
|
+
# @return [DSP]
|
|
993
|
+
def param(name)
|
|
994
|
+
DSP.new(Node.new(type: NodeType::PARAM, args: [name]))
|
|
995
|
+
end
|
|
996
|
+
|
|
997
|
+
# =========================================================================
|
|
998
|
+
# TABLES
|
|
999
|
+
# =========================================================================
|
|
1000
|
+
|
|
1001
|
+
# Read-only table: rdtable(n, init, ridx)
|
|
1002
|
+
# @param size [Integer, DSP] Table size
|
|
1003
|
+
# @param init [DSP] Initialization signal
|
|
1004
|
+
# @param ridx [DSP] Read index
|
|
1005
|
+
# @return [DSP]
|
|
1006
|
+
def rdtable(size, init, ridx)
|
|
1007
|
+
size = to_dsp(size)
|
|
1008
|
+
init = to_dsp(init)
|
|
1009
|
+
ridx = to_dsp(ridx)
|
|
1010
|
+
DSP.new(Node.new(type: NodeType::RDTABLE, inputs: [size.node, init.node, ridx.node]))
|
|
1011
|
+
end
|
|
1012
|
+
|
|
1013
|
+
# Read/write table: rwtable(n, init, widx, wsig, ridx)
|
|
1014
|
+
# @param size [Integer, DSP] Table size
|
|
1015
|
+
# @param init [DSP] Initialization signal
|
|
1016
|
+
# @param widx [DSP] Write index
|
|
1017
|
+
# @param wsig [DSP] Write signal
|
|
1018
|
+
# @param ridx [DSP] Read index
|
|
1019
|
+
# @return [DSP]
|
|
1020
|
+
def rwtable(size, init, widx, wsig, ridx)
|
|
1021
|
+
size = to_dsp(size)
|
|
1022
|
+
init = to_dsp(init)
|
|
1023
|
+
widx = to_dsp(widx)
|
|
1024
|
+
wsig = to_dsp(wsig)
|
|
1025
|
+
ridx = to_dsp(ridx)
|
|
1026
|
+
DSP.new(Node.new(type: NodeType::RWTABLE, inputs: [size.node, init.node, widx.node, wsig.node, ridx.node]))
|
|
1027
|
+
end
|
|
1028
|
+
|
|
1029
|
+
# Waveform constant table: waveform{v1, v2, ...}
|
|
1030
|
+
# @param values [Array<Numeric>] Table values
|
|
1031
|
+
# @return [DSP]
|
|
1032
|
+
def waveform(*values)
|
|
1033
|
+
DSP.new(Node.new(type: NodeType::WAVEFORM, args: values))
|
|
1034
|
+
end
|
|
1035
|
+
|
|
1036
|
+
# =========================================================================
|
|
1037
|
+
# ADDITIONAL ROUTING
|
|
1038
|
+
# =========================================================================
|
|
1039
|
+
|
|
1040
|
+
# Route signals: route(ins, outs, connections)
|
|
1041
|
+
# @param ins [Integer] Number of inputs
|
|
1042
|
+
# @param outs [Integer] Number of outputs
|
|
1043
|
+
# @param connections [Array<Array<Integer>>] Connection pairs [[from, to], ...]
|
|
1044
|
+
# @return [DSP]
|
|
1045
|
+
def route(ins, outs, connections)
|
|
1046
|
+
DSP.new(Node.new(type: NodeType::ROUTE, args: [ins, outs, connections], channels: outs))
|
|
1047
|
+
end
|
|
1048
|
+
|
|
1049
|
+
# 3-way selector: select3(sel, a, b, c)
|
|
1050
|
+
# @param sel [DSP] Selector (0, 1, or 2)
|
|
1051
|
+
# @param a [DSP] First signal
|
|
1052
|
+
# @param b [DSP] Second signal
|
|
1053
|
+
# @param c [DSP] Third signal
|
|
1054
|
+
# @return [DSP]
|
|
1055
|
+
def select3(sel, a, b, c)
|
|
1056
|
+
sel = to_dsp(sel)
|
|
1057
|
+
a = to_dsp(a)
|
|
1058
|
+
b = to_dsp(b)
|
|
1059
|
+
c = to_dsp(c)
|
|
1060
|
+
DSP.new(Node.new(type: NodeType::SELECT3, inputs: [sel.node, a.node, b.node, c.node], channels: a.node.channels))
|
|
1061
|
+
end
|
|
1062
|
+
|
|
1063
|
+
# =========================================================================
|
|
1064
|
+
# UTILITY
|
|
1065
|
+
# =========================================================================
|
|
1066
|
+
|
|
1067
|
+
def wire
|
|
1068
|
+
DSP.new(Node.new(type: NodeType::WIRE))
|
|
1069
|
+
end
|
|
1070
|
+
|
|
1071
|
+
def cut
|
|
1072
|
+
DSP.new(Node.new(type: NodeType::CUT, channels: 0))
|
|
1073
|
+
end
|
|
1074
|
+
|
|
1075
|
+
def mem
|
|
1076
|
+
DSP.new(Node.new(type: NodeType::MEM))
|
|
1077
|
+
end
|
|
1078
|
+
|
|
1079
|
+
def literal(expr, channels: 1)
|
|
1080
|
+
DSP.new(Node.new(type: NodeType::LITERAL, args: [expr], channels: channels))
|
|
1081
|
+
end
|
|
1082
|
+
|
|
1083
|
+
# Wrap a numeric value as a DSP node (constant signal)
|
|
1084
|
+
# Useful when composing with >> which would otherwise be Ruby's bit-shift
|
|
1085
|
+
def num(value)
|
|
1086
|
+
DSP.new(Node.new(type: NodeType::LITERAL, args: [value.to_s]))
|
|
1087
|
+
end
|
|
1088
|
+
|
|
1089
|
+
# =========================================================================
|
|
1090
|
+
# CONSTANTS
|
|
1091
|
+
# =========================================================================
|
|
1092
|
+
|
|
1093
|
+
def sr
|
|
1094
|
+
DSP.new(Node.new(type: NodeType::SR))
|
|
1095
|
+
end
|
|
1096
|
+
|
|
1097
|
+
def pi
|
|
1098
|
+
DSP.new(Node.new(type: NodeType::PI))
|
|
1099
|
+
end
|
|
1100
|
+
|
|
1101
|
+
def tempo
|
|
1102
|
+
DSP.new(Node.new(type: NodeType::TEMPO))
|
|
1103
|
+
end
|
|
1104
|
+
|
|
1105
|
+
# =========================================================================
|
|
1106
|
+
# ANTIALIASING (aa.)
|
|
1107
|
+
# =========================================================================
|
|
1108
|
+
|
|
1109
|
+
def aa_tanh1
|
|
1110
|
+
DSP.new(Node.new(type: NodeType::AA_TANH1))
|
|
1111
|
+
end
|
|
1112
|
+
|
|
1113
|
+
def aa_tanh2
|
|
1114
|
+
DSP.new(Node.new(type: NodeType::AA_TANH2))
|
|
1115
|
+
end
|
|
1116
|
+
|
|
1117
|
+
def aa_arctan
|
|
1118
|
+
DSP.new(Node.new(type: NodeType::AA_ARCTAN))
|
|
1119
|
+
end
|
|
1120
|
+
|
|
1121
|
+
def aa_softclip
|
|
1122
|
+
DSP.new(Node.new(type: NodeType::AA_SOFTCLIP))
|
|
1123
|
+
end
|
|
1124
|
+
|
|
1125
|
+
def aa_hardclip
|
|
1126
|
+
DSP.new(Node.new(type: NodeType::AA_HARDCLIP))
|
|
1127
|
+
end
|
|
1128
|
+
|
|
1129
|
+
def aa_parabolic
|
|
1130
|
+
DSP.new(Node.new(type: NodeType::AA_PARABOLIC))
|
|
1131
|
+
end
|
|
1132
|
+
|
|
1133
|
+
def aa_sin
|
|
1134
|
+
DSP.new(Node.new(type: NodeType::AA_SIN))
|
|
1135
|
+
end
|
|
1136
|
+
|
|
1137
|
+
def aa_cubic1
|
|
1138
|
+
DSP.new(Node.new(type: NodeType::AA_CUBIC1))
|
|
1139
|
+
end
|
|
1140
|
+
|
|
1141
|
+
def aa_cubic2
|
|
1142
|
+
DSP.new(Node.new(type: NodeType::AA_CUBIC2))
|
|
1143
|
+
end
|
|
1144
|
+
|
|
1145
|
+
# Analyzers (an.)
|
|
1146
|
+
def amp_follower(t)
|
|
1147
|
+
DSP.new(Node.new(type: NodeType::AMP_FOLLOWER, args: [t]))
|
|
1148
|
+
end
|
|
1149
|
+
|
|
1150
|
+
def amp_follower_ar(attack, release)
|
|
1151
|
+
DSP.new(Node.new(type: NodeType::AMP_FOLLOWER_AR, args: [attack, release]))
|
|
1152
|
+
end
|
|
1153
|
+
|
|
1154
|
+
def amp_follower_ud(up, down)
|
|
1155
|
+
DSP.new(Node.new(type: NodeType::AMP_FOLLOWER_UD, args: [up, down]))
|
|
1156
|
+
end
|
|
1157
|
+
|
|
1158
|
+
def rms_envelope_rect(period)
|
|
1159
|
+
DSP.new(Node.new(type: NodeType::RMS_ENVELOPE_RECT, args: [period]))
|
|
1160
|
+
end
|
|
1161
|
+
|
|
1162
|
+
def rms_envelope_tau(tau)
|
|
1163
|
+
DSP.new(Node.new(type: NodeType::RMS_ENVELOPE_TAU, args: [tau]))
|
|
1164
|
+
end
|
|
1165
|
+
|
|
1166
|
+
def abs_envelope_rect(period)
|
|
1167
|
+
DSP.new(Node.new(type: NodeType::ABS_ENVELOPE_RECT, args: [period]))
|
|
1168
|
+
end
|
|
1169
|
+
|
|
1170
|
+
def abs_envelope_tau(tau)
|
|
1171
|
+
DSP.new(Node.new(type: NodeType::ABS_ENVELOPE_TAU, args: [tau]))
|
|
1172
|
+
end
|
|
1173
|
+
|
|
1174
|
+
def ms_envelope_rect(period)
|
|
1175
|
+
DSP.new(Node.new(type: NodeType::MS_ENVELOPE_RECT, args: [period]))
|
|
1176
|
+
end
|
|
1177
|
+
|
|
1178
|
+
def ms_envelope_tau(tau)
|
|
1179
|
+
DSP.new(Node.new(type: NodeType::MS_ENVELOPE_TAU, args: [tau]))
|
|
1180
|
+
end
|
|
1181
|
+
|
|
1182
|
+
def peak_envelope(t)
|
|
1183
|
+
DSP.new(Node.new(type: NodeType::PEAK_ENVELOPE, args: [t]))
|
|
1184
|
+
end
|
|
1185
|
+
|
|
1186
|
+
# Effects (ef.)
|
|
1187
|
+
def cubicnl(drive, offset)
|
|
1188
|
+
DSP.new(Node.new(type: NodeType::CUBICNL, args: [drive, offset]))
|
|
1189
|
+
end
|
|
1190
|
+
|
|
1191
|
+
def gate_mono(thresh, attack, hold, release)
|
|
1192
|
+
DSP.new(Node.new(type: NodeType::GATE_MONO, args: [thresh, attack, hold, release]))
|
|
1193
|
+
end
|
|
1194
|
+
|
|
1195
|
+
def gate_stereo(thresh, attack, hold, release)
|
|
1196
|
+
DSP.new(Node.new(type: NodeType::GATE_STEREO, args: [thresh, attack, hold, release], channels: 2))
|
|
1197
|
+
end
|
|
1198
|
+
|
|
1199
|
+
def ef_compressor_mono(ratio, thresh, attack, release)
|
|
1200
|
+
DSP.new(Node.new(type: NodeType::EF_COMPRESSOR_MONO, args: [ratio, thresh, attack, release]))
|
|
1201
|
+
end
|
|
1202
|
+
|
|
1203
|
+
def ef_compressor_stereo(ratio, thresh, attack, release)
|
|
1204
|
+
DSP.new(Node.new(type: NodeType::EF_COMPRESSOR_STEREO, args: [ratio, thresh, attack, release], channels: 2))
|
|
1205
|
+
end
|
|
1206
|
+
|
|
1207
|
+
def ef_limiter_1176_mono
|
|
1208
|
+
DSP.new(Node.new(type: NodeType::EF_LIMITER_1176_MONO))
|
|
1209
|
+
end
|
|
1210
|
+
|
|
1211
|
+
def ef_limiter_1176_stereo
|
|
1212
|
+
DSP.new(Node.new(type: NodeType::EF_LIMITER_1176_STEREO, channels: 2))
|
|
1213
|
+
end
|
|
1214
|
+
|
|
1215
|
+
def echo(maxdel, del, fb)
|
|
1216
|
+
DSP.new(Node.new(type: NodeType::ECHO, args: [maxdel, del, fb]))
|
|
1217
|
+
end
|
|
1218
|
+
|
|
1219
|
+
def transpose(w, x, s)
|
|
1220
|
+
DSP.new(Node.new(type: NodeType::TRANSPOSE, args: [w, x, s]))
|
|
1221
|
+
end
|
|
1222
|
+
|
|
1223
|
+
def flanger_mono(dmax, delay_freq, level, feedback, invert)
|
|
1224
|
+
DSP.new(Node.new(type: NodeType::FLANGER_MONO, args: [dmax, delay_freq, level, feedback, invert]))
|
|
1225
|
+
end
|
|
1226
|
+
|
|
1227
|
+
def flanger_stereo(dmax, delay_freq, level, feedback, invert, lfsr, lfsf)
|
|
1228
|
+
DSP.new(Node.new(type: NodeType::FLANGER_STEREO, args: [dmax, delay_freq, level, feedback, invert, lfsr, lfsf], channels: 2))
|
|
1229
|
+
end
|
|
1230
|
+
|
|
1231
|
+
def phaser2_mono(nstages, freq, speed, depth, feedback, spread)
|
|
1232
|
+
DSP.new(Node.new(type: NodeType::PHASER2_MONO, args: [nstages, freq, speed, depth, feedback, spread]))
|
|
1233
|
+
end
|
|
1234
|
+
|
|
1235
|
+
def phaser2_stereo(nstages, freq, speed, depth, feedback, spread)
|
|
1236
|
+
DSP.new(Node.new(type: NodeType::PHASER2_STEREO, args: [nstages, freq, speed, depth, feedback, spread], channels: 2))
|
|
1237
|
+
end
|
|
1238
|
+
|
|
1239
|
+
def wah4(fr)
|
|
1240
|
+
DSP.new(Node.new(type: NodeType::WAH4, args: [fr]))
|
|
1241
|
+
end
|
|
1242
|
+
|
|
1243
|
+
def auto_wah(level)
|
|
1244
|
+
DSP.new(Node.new(type: NodeType::AUTO_WAH, args: [level]))
|
|
1245
|
+
end
|
|
1246
|
+
|
|
1247
|
+
def crybaby(wah)
|
|
1248
|
+
DSP.new(Node.new(type: NodeType::CRYBABY, args: [wah]))
|
|
1249
|
+
end
|
|
1250
|
+
|
|
1251
|
+
def vocoder(bands, range)
|
|
1252
|
+
DSP.new(Node.new(type: NodeType::VOCODER, args: [bands, range]))
|
|
1253
|
+
end
|
|
1254
|
+
|
|
1255
|
+
def speakerbp(flo, fhi)
|
|
1256
|
+
DSP.new(Node.new(type: NodeType::SPEAKERBP, args: [flo, fhi]))
|
|
1257
|
+
end
|
|
1258
|
+
|
|
1259
|
+
def dry_wet_mixer(mix)
|
|
1260
|
+
DSP.new(Node.new(type: NodeType::DRY_WET_MIXER, args: [mix]))
|
|
1261
|
+
end
|
|
1262
|
+
|
|
1263
|
+
def dry_wet_mixer_cp(mix)
|
|
1264
|
+
DSP.new(Node.new(type: NodeType::DRY_WET_MIXER_CP, args: [mix]))
|
|
1265
|
+
end
|
|
1266
|
+
|
|
1267
|
+
# Constant aliases for those who prefer the capitalized look
|
|
1268
|
+
SR = DSP.new(Node.new(type: NodeType::SR))
|
|
1269
|
+
PI = DSP.new(Node.new(type: NodeType::PI))
|
|
1270
|
+
TEMPO = DSP.new(Node.new(type: NodeType::TEMPO))
|
|
1271
|
+
end
|
|
1272
|
+
|
|
1273
|
+
# Program-level metadata for Faust declarations
|
|
1274
|
+
class Program
|
|
1275
|
+
attr_reader :process, :declarations, :imports
|
|
1276
|
+
|
|
1277
|
+
def initialize(process = nil, &block)
|
|
1278
|
+
@declarations = {}
|
|
1279
|
+
@imports = ["stdfaust.lib"]
|
|
1280
|
+
if block_given?
|
|
1281
|
+
extend DSL
|
|
1282
|
+
@process = instance_eval(&block)
|
|
1283
|
+
else
|
|
1284
|
+
@process = process
|
|
1285
|
+
end
|
|
1286
|
+
end
|
|
1287
|
+
|
|
1288
|
+
def declare(key, value)
|
|
1289
|
+
@declarations[key] = value
|
|
1290
|
+
self
|
|
1291
|
+
end
|
|
1292
|
+
|
|
1293
|
+
def import(lib)
|
|
1294
|
+
@imports << lib unless @imports.include?(lib)
|
|
1295
|
+
self
|
|
1296
|
+
end
|
|
1297
|
+
end
|
|
1298
|
+
end
|
|
1299
|
+
|
|
1300
|
+
# Numeric extensions for audio conversions
|
|
1301
|
+
# These return DSP nodes that can be used in signal chains
|
|
1302
|
+
class Numeric
|
|
1303
|
+
# MIDI note number to Hz
|
|
1304
|
+
# 60.midi => ba.midikey2hz(60)
|
|
1305
|
+
def midi
|
|
1306
|
+
Ruby2Faust::DSL.midi2hz(self)
|
|
1307
|
+
end
|
|
1308
|
+
|
|
1309
|
+
# dB to linear gain
|
|
1310
|
+
# -6.db => ba.db2linear(-6)
|
|
1311
|
+
def db
|
|
1312
|
+
Ruby2Faust::DSL.db2linear(self)
|
|
1313
|
+
end
|
|
1314
|
+
|
|
1315
|
+
# Seconds to samples
|
|
1316
|
+
# 0.1.sec => ba.sec2samp(0.1)
|
|
1317
|
+
def sec
|
|
1318
|
+
Ruby2Faust::DSL.sec2samp(self)
|
|
1319
|
+
end
|
|
1320
|
+
|
|
1321
|
+
# Milliseconds to samples
|
|
1322
|
+
# 100.ms => ba.sec2samp(0.1)
|
|
1323
|
+
def ms
|
|
1324
|
+
Ruby2Faust::DSL.sec2samp(self / 1000.0)
|
|
1325
|
+
end
|
|
1326
|
+
|
|
1327
|
+
# Hz (pass-through for clarity)
|
|
1328
|
+
# 440.hz => 440
|
|
1329
|
+
def hz
|
|
1330
|
+
Ruby2Faust::DSL.literal(self.to_s)
|
|
1331
|
+
end
|
|
1332
|
+
end
|