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,255 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "strscan"
|
|
4
|
+
|
|
5
|
+
module Faust2Ruby
|
|
6
|
+
# Lexer for Faust DSP source code.
|
|
7
|
+
# Uses StringScanner for efficient tokenization.
|
|
8
|
+
class Lexer
|
|
9
|
+
# Token struct for lexer output
|
|
10
|
+
Token = Struct.new(:type, :value, :line, :column, keyword_init: true)
|
|
11
|
+
|
|
12
|
+
# Keywords in Faust
|
|
13
|
+
KEYWORDS = %w[
|
|
14
|
+
import declare process with letrec where
|
|
15
|
+
par seq sum prod
|
|
16
|
+
case of
|
|
17
|
+
environment library component
|
|
18
|
+
inputs outputs
|
|
19
|
+
].freeze
|
|
20
|
+
|
|
21
|
+
# Multi-character operators (must check before single-char)
|
|
22
|
+
MULTI_CHAR_OPS = {
|
|
23
|
+
"<:" => :SPLIT,
|
|
24
|
+
":>" => :MERGE,
|
|
25
|
+
"==" => :EQ,
|
|
26
|
+
"!=" => :NEQ,
|
|
27
|
+
"<=" => :LE,
|
|
28
|
+
">=" => :GE,
|
|
29
|
+
"<<" => :LSHIFT,
|
|
30
|
+
">>" => :RSHIFT,
|
|
31
|
+
"=>" => :ARROW,
|
|
32
|
+
}.freeze
|
|
33
|
+
|
|
34
|
+
# Single-character operators and punctuation
|
|
35
|
+
SINGLE_CHAR_OPS = {
|
|
36
|
+
":" => :SEQ,
|
|
37
|
+
"," => :PAR,
|
|
38
|
+
"~" => :REC,
|
|
39
|
+
"+" => :ADD,
|
|
40
|
+
"-" => :SUB,
|
|
41
|
+
"*" => :MUL,
|
|
42
|
+
"/" => :DIV,
|
|
43
|
+
"%" => :MOD,
|
|
44
|
+
"^" => :POW,
|
|
45
|
+
"@" => :DELAY,
|
|
46
|
+
"'" => :PRIME,
|
|
47
|
+
"=" => :DEF,
|
|
48
|
+
";" => :ENDDEF,
|
|
49
|
+
"(" => :LPAREN,
|
|
50
|
+
")" => :RPAREN,
|
|
51
|
+
"{" => :LBRACE,
|
|
52
|
+
"}" => :RBRACE,
|
|
53
|
+
"[" => :LBRACKET,
|
|
54
|
+
"]" => :RBRACKET,
|
|
55
|
+
"<" => :LT,
|
|
56
|
+
">" => :GT,
|
|
57
|
+
"&" => :AND,
|
|
58
|
+
"|" => :OR,
|
|
59
|
+
"!" => :CUT,
|
|
60
|
+
"_" => :WIRE,
|
|
61
|
+
"." => :DOT,
|
|
62
|
+
"\\" => :LAMBDA,
|
|
63
|
+
}.freeze
|
|
64
|
+
|
|
65
|
+
attr_reader :tokens, :errors
|
|
66
|
+
|
|
67
|
+
def initialize(source)
|
|
68
|
+
@source = source
|
|
69
|
+
@scanner = StringScanner.new(source)
|
|
70
|
+
@tokens = []
|
|
71
|
+
@errors = []
|
|
72
|
+
@line = 1
|
|
73
|
+
@line_start = 0
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def tokenize
|
|
77
|
+
until @scanner.eos?
|
|
78
|
+
token = next_token
|
|
79
|
+
@tokens << token if token
|
|
80
|
+
end
|
|
81
|
+
@tokens << Token.new(type: :EOF, value: nil, line: @line, column: current_column)
|
|
82
|
+
@tokens
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
private
|
|
86
|
+
|
|
87
|
+
def current_column
|
|
88
|
+
@scanner.pos - @line_start + 1
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def next_token
|
|
92
|
+
skip_whitespace_and_comments
|
|
93
|
+
|
|
94
|
+
return nil if @scanner.eos?
|
|
95
|
+
|
|
96
|
+
start_line = @line
|
|
97
|
+
start_col = current_column
|
|
98
|
+
|
|
99
|
+
# Try to match each token type
|
|
100
|
+
token = try_string ||
|
|
101
|
+
try_number ||
|
|
102
|
+
try_multi_char_op ||
|
|
103
|
+
try_single_char_op ||
|
|
104
|
+
try_identifier
|
|
105
|
+
|
|
106
|
+
unless token
|
|
107
|
+
# Unknown character - report error and skip
|
|
108
|
+
char = @scanner.getch
|
|
109
|
+
@errors << "Unknown character '#{char}' at line #{start_line}, column #{start_col}"
|
|
110
|
+
return nil
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
token
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def skip_whitespace_and_comments
|
|
117
|
+
loop do
|
|
118
|
+
# Skip whitespace, tracking newlines
|
|
119
|
+
while @scanner.scan(/[ \t]+/) || @scanner.scan(/\r?\n/)
|
|
120
|
+
if @scanner.matched.include?("\n")
|
|
121
|
+
@line += 1
|
|
122
|
+
@line_start = @scanner.pos
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# Skip line comments
|
|
127
|
+
if @scanner.scan(%r{//[^\n]*})
|
|
128
|
+
next
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Skip block comments
|
|
132
|
+
if @scanner.scan(%r{/\*})
|
|
133
|
+
depth = 1
|
|
134
|
+
until depth.zero? || @scanner.eos?
|
|
135
|
+
if @scanner.scan(%r{/\*})
|
|
136
|
+
depth += 1
|
|
137
|
+
elsif @scanner.scan(%r{\*/})
|
|
138
|
+
depth -= 1
|
|
139
|
+
elsif @scanner.scan(/\n/)
|
|
140
|
+
@line += 1
|
|
141
|
+
@line_start = @scanner.pos
|
|
142
|
+
else
|
|
143
|
+
@scanner.getch
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
next
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
break
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def try_string
|
|
154
|
+
start_line = @line
|
|
155
|
+
start_col = current_column
|
|
156
|
+
|
|
157
|
+
# Double-quoted string
|
|
158
|
+
if @scanner.scan(/"/)
|
|
159
|
+
value = String.new
|
|
160
|
+
until @scanner.eos?
|
|
161
|
+
if @scanner.scan(/\\(.)/)
|
|
162
|
+
# Escape sequence
|
|
163
|
+
case @scanner[1]
|
|
164
|
+
when "n" then value << "\n"
|
|
165
|
+
when "t" then value << "\t"
|
|
166
|
+
when "r" then value << "\r"
|
|
167
|
+
when "\\" then value << "\\"
|
|
168
|
+
when '"' then value << '"'
|
|
169
|
+
else value << @scanner[1]
|
|
170
|
+
end
|
|
171
|
+
elsif @scanner.scan(/"/)
|
|
172
|
+
return Token.new(type: :STRING, value: value, line: start_line, column: start_col)
|
|
173
|
+
elsif @scanner.scan(/[^"\\]+/)
|
|
174
|
+
value << @scanner.matched
|
|
175
|
+
else
|
|
176
|
+
break
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
@errors << "Unterminated string at line #{start_line}, column #{start_col}"
|
|
180
|
+
return Token.new(type: :STRING, value: value, line: start_line, column: start_col)
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
nil
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def try_number
|
|
187
|
+
start_line = @line
|
|
188
|
+
start_col = current_column
|
|
189
|
+
|
|
190
|
+
# Float with optional exponent
|
|
191
|
+
if @scanner.scan(/\d+\.\d+([eE][+-]?\d+)?/)
|
|
192
|
+
return Token.new(type: :FLOAT, value: @scanner.matched.to_f, line: start_line, column: start_col)
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
# Float with exponent (no decimal point)
|
|
196
|
+
if @scanner.scan(/\d+[eE][+-]?\d+/)
|
|
197
|
+
return Token.new(type: :FLOAT, value: @scanner.matched.to_f, line: start_line, column: start_col)
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
# Integer
|
|
201
|
+
if @scanner.scan(/\d+/)
|
|
202
|
+
return Token.new(type: :INT, value: @scanner.matched.to_i, line: start_line, column: start_col)
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
nil
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def try_multi_char_op
|
|
209
|
+
start_line = @line
|
|
210
|
+
start_col = current_column
|
|
211
|
+
|
|
212
|
+
MULTI_CHAR_OPS.each do |op, type|
|
|
213
|
+
if @scanner.scan(Regexp.new(Regexp.escape(op)))
|
|
214
|
+
return Token.new(type: type, value: op, line: start_line, column: start_col)
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
nil
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def try_single_char_op
|
|
222
|
+
start_line = @line
|
|
223
|
+
start_col = current_column
|
|
224
|
+
|
|
225
|
+
char = @scanner.peek(1)
|
|
226
|
+
if SINGLE_CHAR_OPS.key?(char)
|
|
227
|
+
@scanner.getch
|
|
228
|
+
return Token.new(type: SINGLE_CHAR_OPS[char], value: char, line: start_line, column: start_col)
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
nil
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def try_identifier
|
|
235
|
+
start_line = @line
|
|
236
|
+
start_col = current_column
|
|
237
|
+
|
|
238
|
+
# Identifiers: start with letter or underscore (but not just _)
|
|
239
|
+
# Allow dots for qualified names like os.osc
|
|
240
|
+
if @scanner.scan(/[a-zA-Z_][a-zA-Z0-9_]*/)
|
|
241
|
+
value = @scanner.matched
|
|
242
|
+
|
|
243
|
+
# Check if it's a keyword
|
|
244
|
+
if KEYWORDS.include?(value)
|
|
245
|
+
type = value.upcase.to_sym
|
|
246
|
+
return Token.new(type: type, value: value, line: start_line, column: start_col)
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
return Token.new(type: :IDENT, value: value, line: start_line, column: start_col)
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
nil
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
end
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Faust2Ruby
|
|
4
|
+
# Maps Faust library function calls to Ruby2Faust NodeTypes and DSL methods.
|
|
5
|
+
module LibraryMapper
|
|
6
|
+
# Mapping from Faust function names to Ruby DSL info
|
|
7
|
+
# Each entry: faust_name => { type: NodeType, dsl: method_name, args: arg_count }
|
|
8
|
+
MAPPINGS = {
|
|
9
|
+
# Oscillators (os.)
|
|
10
|
+
"os.osc" => { dsl: :osc, args: 1 },
|
|
11
|
+
"os.sawtooth" => { dsl: :saw, args: 1 },
|
|
12
|
+
"os.square" => { dsl: :square, args: 1 },
|
|
13
|
+
"os.triangle" => { dsl: :triangle, args: 1 },
|
|
14
|
+
"os.phasor" => { dsl: :phasor, args: 2 },
|
|
15
|
+
"os.lf_sawpos" => { dsl: :lf_saw, args: 1 },
|
|
16
|
+
"os.lf_trianglepos" => { dsl: :lf_triangle, args: 1 },
|
|
17
|
+
"os.lf_squarewavepos" => { dsl: :lf_square, args: 1 },
|
|
18
|
+
"os.lf_imptrain" => { dsl: :imptrain, args: 1 },
|
|
19
|
+
"os.lf_pulsetrain" => { dsl: :pulsetrain, args: 2 },
|
|
20
|
+
|
|
21
|
+
# Noise (no.)
|
|
22
|
+
"no.noise" => { dsl: :noise, args: 0 },
|
|
23
|
+
"no.pink_noise" => { dsl: :pink_noise, args: 0 },
|
|
24
|
+
|
|
25
|
+
# Filters (fi.)
|
|
26
|
+
"fi.lowpass" => { dsl: :lp, args: 2, opts: { order: 0 } },
|
|
27
|
+
"fi.highpass" => { dsl: :hp, args: 2, opts: { order: 0 } },
|
|
28
|
+
"fi.bandpass" => { dsl: :bp, args: 3 },
|
|
29
|
+
"fi.resonlp" => { dsl: :resonlp, args: 3 },
|
|
30
|
+
"fi.resonhp" => { dsl: :resonhp, args: 3 },
|
|
31
|
+
"fi.resonbp" => { dsl: :resonbp, args: 3 },
|
|
32
|
+
"fi.allpass_comb" => { dsl: :allpass, args: 3 },
|
|
33
|
+
"fi.dcblocker" => { dsl: :dcblock, args: 0 },
|
|
34
|
+
"fi.peak_eq" => { dsl: :peak_eq, args: 3 },
|
|
35
|
+
|
|
36
|
+
# SVF (State Variable Filter) (fi.svf.)
|
|
37
|
+
"fi.svf.lp" => { dsl: :svf_lp, args: 2 },
|
|
38
|
+
"fi.svf.hp" => { dsl: :svf_hp, args: 2 },
|
|
39
|
+
"fi.svf.bp" => { dsl: :svf_bp, args: 2 },
|
|
40
|
+
"fi.svf.notch" => { dsl: :svf_notch, args: 2 },
|
|
41
|
+
"fi.svf.ap" => { dsl: :svf_ap, args: 2 },
|
|
42
|
+
"fi.svf.bell" => { dsl: :svf_bell, args: 3 },
|
|
43
|
+
"fi.svf.ls" => { dsl: :svf_ls, args: 3 },
|
|
44
|
+
"fi.svf.hs" => { dsl: :svf_hs, args: 3 },
|
|
45
|
+
|
|
46
|
+
# Other filters (fi.)
|
|
47
|
+
"fi.lowpass3e" => { dsl: :lowpass3e, args: 1 },
|
|
48
|
+
"fi.highpass3e" => { dsl: :highpass3e, args: 1 },
|
|
49
|
+
"fi.lowpass6e" => { dsl: :lowpass6e, args: 1 },
|
|
50
|
+
"fi.highpass6e" => { dsl: :highpass6e, args: 1 },
|
|
51
|
+
"fi.bandstop" => { dsl: :bandstop, args: 3 },
|
|
52
|
+
"fi.notchw" => { dsl: :notchw, args: 2 },
|
|
53
|
+
"fi.low_shelf" => { dsl: :low_shelf, args: 3 },
|
|
54
|
+
"fi.high_shelf" => { dsl: :high_shelf, args: 3 },
|
|
55
|
+
"fi.peak_eq_cq" => { dsl: :peak_eq_cq, args: 3 },
|
|
56
|
+
"fi.pole" => { dsl: :fi_pole, args: 1 },
|
|
57
|
+
"fi.zero" => { dsl: :fi_zero, args: 1 },
|
|
58
|
+
"fi.tf1" => { dsl: :tf1, args: 3 },
|
|
59
|
+
"fi.tf2" => { dsl: :tf2, args: 5 },
|
|
60
|
+
"fi.tf1s" => { dsl: :tf1s, args: 3 },
|
|
61
|
+
"fi.tf2s" => { dsl: :tf2s, args: 5 },
|
|
62
|
+
"fi.iir" => { dsl: :iir, args: 2 },
|
|
63
|
+
"fi.fir" => { dsl: :fir, args: 1 },
|
|
64
|
+
"fi.conv" => { dsl: :conv, args: 2 },
|
|
65
|
+
"fi.fbcombfilter" => { dsl: :fbcombfilter, args: 3 },
|
|
66
|
+
"fi.ffcombfilter" => { dsl: :ffcombfilter, args: 2 },
|
|
67
|
+
|
|
68
|
+
# Delays (de.)
|
|
69
|
+
"de.delay" => { dsl: :delay, args: 2 },
|
|
70
|
+
"de.fdelay" => { dsl: :fdelay, args: 2 },
|
|
71
|
+
"de.sdelay" => { dsl: :sdelay, args: 3 },
|
|
72
|
+
|
|
73
|
+
# Envelopes (en.)
|
|
74
|
+
"en.ar" => { dsl: :ar, args: 3 },
|
|
75
|
+
"en.asr" => { dsl: :asr, args: 4 },
|
|
76
|
+
"en.adsr" => { dsl: :adsr, args: 5 },
|
|
77
|
+
"en.adsre" => { dsl: :adsre, args: 5 },
|
|
78
|
+
|
|
79
|
+
# Conversion (ba.)
|
|
80
|
+
"ba.db2linear" => { dsl: :db2linear, args: 1 },
|
|
81
|
+
"ba.linear2db" => { dsl: :linear2db, args: 1 },
|
|
82
|
+
"ba.samp2sec" => { dsl: :samp2sec, args: 1 },
|
|
83
|
+
"ba.sec2samp" => { dsl: :sec2samp, args: 1 },
|
|
84
|
+
"ba.midikey2hz" => { dsl: :midi2hz, args: 1 },
|
|
85
|
+
"ba.hz2midikey" => { dsl: :hz2midi, args: 1 },
|
|
86
|
+
"ba.selectn" => { dsl: :selectn, args: :variadic },
|
|
87
|
+
"ba.tau2pole" => { dsl: :tau2pole, args: 1 },
|
|
88
|
+
"ba.pole2tau" => { dsl: :pole2tau, args: 1 },
|
|
89
|
+
"ba.if" => { dsl: :ba_if, args: 3 },
|
|
90
|
+
"ba.selector" => { dsl: :selector, args: 3 },
|
|
91
|
+
"ba.selectmulti" => { dsl: :selectmulti, args: :variadic },
|
|
92
|
+
"ba.count" => { dsl: :ba_count, args: :variadic },
|
|
93
|
+
"ba.take" => { dsl: :ba_take, args: 2 },
|
|
94
|
+
|
|
95
|
+
# Smoothing (si.)
|
|
96
|
+
"si.smooth" => { dsl: :smooth, args: 1 },
|
|
97
|
+
"si.smoo" => { dsl: :smoo, args: 0 },
|
|
98
|
+
"si.bus" => { dsl: :bus, args: 1 },
|
|
99
|
+
"si.block" => { dsl: :block, args: 1 },
|
|
100
|
+
|
|
101
|
+
# Reverbs (re.)
|
|
102
|
+
"re.mono_freeverb" => { dsl: :freeverb, args: 4 },
|
|
103
|
+
"re.zita_rev1_stereo" => { dsl: :zita_rev, args: 6 },
|
|
104
|
+
"re.jpverb" => { dsl: :jpverb, args: 11 },
|
|
105
|
+
|
|
106
|
+
# Compressors (co.)
|
|
107
|
+
"co.compressor_mono" => { dsl: :compressor, args: 4 },
|
|
108
|
+
"co.limiter_1176_R4_mono" => { dsl: :limiter, args: 0 },
|
|
109
|
+
|
|
110
|
+
# Spatial (sp.)
|
|
111
|
+
"sp.panner" => { dsl: :panner, args: 1 },
|
|
112
|
+
|
|
113
|
+
# Math (ma.)
|
|
114
|
+
"ma.SR" => { dsl: :sr, args: 0 },
|
|
115
|
+
"ma.PI" => { dsl: :pi, args: 0 },
|
|
116
|
+
"ma.tempo" => { dsl: :tempo, args: 0 },
|
|
117
|
+
"ma.tanh" => { dsl: :tanh_, args: 0 },
|
|
118
|
+
|
|
119
|
+
# Antialiasing (aa.)
|
|
120
|
+
"aa.tanh1" => { dsl: :aa_tanh1, args: 0 },
|
|
121
|
+
"aa.tanh2" => { dsl: :aa_tanh2, args: 0 },
|
|
122
|
+
"aa.arctan" => { dsl: :aa_arctan, args: 0 },
|
|
123
|
+
"aa.softclip" => { dsl: :aa_softclip, args: 0 },
|
|
124
|
+
"aa.hardclip" => { dsl: :aa_hardclip, args: 0 },
|
|
125
|
+
"aa.parabolic" => { dsl: :aa_parabolic, args: 0 },
|
|
126
|
+
"aa.sin" => { dsl: :aa_sin, args: 0 },
|
|
127
|
+
"aa.cubic1" => { dsl: :aa_cubic1, args: 0 },
|
|
128
|
+
"aa.cubic2" => { dsl: :aa_cubic2, args: 0 },
|
|
129
|
+
|
|
130
|
+
# Analyzers (an.)
|
|
131
|
+
"an.amp_follower" => { dsl: :amp_follower, args: 1 },
|
|
132
|
+
"an.amp_follower_ar" => { dsl: :amp_follower_ar, args: 2 },
|
|
133
|
+
"an.amp_follower_ud" => { dsl: :amp_follower_ud, args: 2 },
|
|
134
|
+
"an.rms_envelope_rect" => { dsl: :rms_envelope_rect, args: 1 },
|
|
135
|
+
"an.rms_envelope_tau" => { dsl: :rms_envelope_tau, args: 1 },
|
|
136
|
+
"an.abs_envelope_rect" => { dsl: :abs_envelope_rect, args: 1 },
|
|
137
|
+
"an.abs_envelope_tau" => { dsl: :abs_envelope_tau, args: 1 },
|
|
138
|
+
"an.ms_envelope_rect" => { dsl: :ms_envelope_rect, args: 1 },
|
|
139
|
+
"an.ms_envelope_tau" => { dsl: :ms_envelope_tau, args: 1 },
|
|
140
|
+
"an.peak_envelope" => { dsl: :peak_envelope, args: 1 },
|
|
141
|
+
|
|
142
|
+
# Effects (ef.)
|
|
143
|
+
"ef.cubicnl" => { dsl: :cubicnl, args: 2 },
|
|
144
|
+
"ef.gate_mono" => { dsl: :gate_mono, args: 4 },
|
|
145
|
+
"ef.gate_stereo" => { dsl: :gate_stereo, args: 4 },
|
|
146
|
+
"ef.compressor_mono" => { dsl: :ef_compressor_mono, args: 4 },
|
|
147
|
+
"ef.compressor_stereo" => { dsl: :ef_compressor_stereo, args: 4 },
|
|
148
|
+
"ef.limiter_1176_R4_mono" => { dsl: :ef_limiter_1176_mono, args: 0 },
|
|
149
|
+
"ef.limiter_1176_R4_stereo" => { dsl: :ef_limiter_1176_stereo, args: 0 },
|
|
150
|
+
"ef.echo" => { dsl: :echo, args: 3 },
|
|
151
|
+
"ef.transpose" => { dsl: :transpose, args: 3 },
|
|
152
|
+
"ef.flanger_mono" => { dsl: :flanger_mono, args: 5 },
|
|
153
|
+
"ef.flanger_stereo" => { dsl: :flanger_stereo, args: 7 },
|
|
154
|
+
"ef.phaser2_mono" => { dsl: :phaser2_mono, args: 6 },
|
|
155
|
+
"ef.phaser2_stereo" => { dsl: :phaser2_stereo, args: 6 },
|
|
156
|
+
"ef.wah4" => { dsl: :wah4, args: 1 },
|
|
157
|
+
"ef.auto_wah" => { dsl: :auto_wah, args: 1 },
|
|
158
|
+
"ef.crybaby" => { dsl: :crybaby, args: 1 },
|
|
159
|
+
"ef.vocoder" => { dsl: :vocoder, args: 2 },
|
|
160
|
+
"ef.speakerbp" => { dsl: :speakerbp, args: 2 },
|
|
161
|
+
"ef.dryWetMixer" => { dsl: :dry_wet_mixer, args: 1 },
|
|
162
|
+
"ef.dryWetMixerConstantPower" => { dsl: :dry_wet_mixer_cp, args: 1 },
|
|
163
|
+
}.freeze
|
|
164
|
+
|
|
165
|
+
# Primitive functions that map directly to DSL
|
|
166
|
+
PRIMITIVES = {
|
|
167
|
+
# Math operators (used as functions)
|
|
168
|
+
"abs" => { dsl: :abs_, args: 0 },
|
|
169
|
+
"min" => { dsl: :min_, args: 2 },
|
|
170
|
+
"max" => { dsl: :max_, args: 2 },
|
|
171
|
+
"pow" => { dsl: :pow, args: 2 },
|
|
172
|
+
"sqrt" => { dsl: :sqrt_, args: 0 },
|
|
173
|
+
"exp" => { dsl: :exp_, args: 0 },
|
|
174
|
+
"log" => { dsl: :log_, args: 0 },
|
|
175
|
+
"log10" => { dsl: :log10_, args: 0 },
|
|
176
|
+
"sin" => { dsl: :sin_, args: 0 },
|
|
177
|
+
"cos" => { dsl: :cos_, args: 0 },
|
|
178
|
+
"tan" => { dsl: :tan_, args: 0 },
|
|
179
|
+
"tanh" => { dsl: :tanh_, args: 0 },
|
|
180
|
+
"asin" => { dsl: :asin_, args: 0 },
|
|
181
|
+
"acos" => { dsl: :acos_, args: 0 },
|
|
182
|
+
"atan" => { dsl: :atan_, args: 0 },
|
|
183
|
+
"atan2" => { dsl: :atan2, args: 2 },
|
|
184
|
+
"sinh" => { dsl: :sinh_, args: 0 },
|
|
185
|
+
"cosh" => { dsl: :cosh_, args: 0 },
|
|
186
|
+
"asinh" => { dsl: :asinh_, args: 0 },
|
|
187
|
+
"acosh" => { dsl: :acosh_, args: 0 },
|
|
188
|
+
"atanh" => { dsl: :atanh_, args: 0 },
|
|
189
|
+
"floor" => { dsl: :floor_, args: 0 },
|
|
190
|
+
"ceil" => { dsl: :ceil_, args: 0 },
|
|
191
|
+
"rint" => { dsl: :rint_, args: 0 },
|
|
192
|
+
"fmod" => { dsl: :fmod, args: 2 },
|
|
193
|
+
"int" => { dsl: :int_, args: 0 },
|
|
194
|
+
"float" => { dsl: :float_, args: 0 },
|
|
195
|
+
|
|
196
|
+
# Tables
|
|
197
|
+
"rdtable" => { dsl: :rdtable, args: 3 },
|
|
198
|
+
"rwtable" => { dsl: :rwtable, args: 5 },
|
|
199
|
+
|
|
200
|
+
# Selectors
|
|
201
|
+
"select2" => { dsl: :select2, args: 3 },
|
|
202
|
+
"select3" => { dsl: :select3, args: 4 },
|
|
203
|
+
|
|
204
|
+
# Primitives
|
|
205
|
+
"mem" => { dsl: :mem, args: 0 },
|
|
206
|
+
}.freeze
|
|
207
|
+
|
|
208
|
+
# UI element types
|
|
209
|
+
UI_ELEMENTS = {
|
|
210
|
+
"hslider" => :slider,
|
|
211
|
+
"vslider" => :vslider,
|
|
212
|
+
"nentry" => :nentry,
|
|
213
|
+
"button" => :button,
|
|
214
|
+
"checkbox" => :checkbox,
|
|
215
|
+
}.freeze
|
|
216
|
+
|
|
217
|
+
UI_GROUPS = {
|
|
218
|
+
"hgroup" => :hgroup,
|
|
219
|
+
"vgroup" => :vgroup,
|
|
220
|
+
"tgroup" => :tgroup,
|
|
221
|
+
}.freeze
|
|
222
|
+
|
|
223
|
+
module_function
|
|
224
|
+
|
|
225
|
+
def lookup(name)
|
|
226
|
+
MAPPINGS[name] || PRIMITIVES[name]
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
def ui_element?(name)
|
|
230
|
+
UI_ELEMENTS.key?(name)
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
def ui_group?(name)
|
|
234
|
+
UI_GROUPS.key?(name)
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
def ui_element_method(name)
|
|
238
|
+
UI_ELEMENTS[name]
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
def ui_group_method(name)
|
|
242
|
+
UI_GROUPS[name]
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
def known_function?(name)
|
|
246
|
+
MAPPINGS.key?(name) || PRIMITIVES.key?(name)
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
end
|