arbol 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/arbol +25 -0
- data/lib/arbol.rb +45 -0
- data/lib/base.rb +397 -0
- data/lib/builder.rb +102 -0
- data/lib/documentation.rb +19 -0
- data/lib/dsl.rb +168 -0
- data/lib/functions/add.rb +70 -0
- data/lib/functions/add_constrain.rb +70 -0
- data/lib/functions/add_modulo.rb +70 -0
- data/lib/functions/analog_pin.rb +316 -0
- data/lib/functions/choose.rb +74 -0
- data/lib/functions/const.rb +63 -0
- data/lib/functions/create_lookup.rb +63 -0
- data/lib/functions/create_ref.rb +48 -0
- data/lib/functions/crossfade.rb +73 -0
- data/lib/functions/divide.rb +70 -0
- data/lib/functions/feedback.rb +65 -0
- data/lib/functions/feedback_offset.rb +69 -0
- data/lib/functions/gamma.rb +61 -0
- data/lib/functions/greater_than.rb +70 -0
- data/lib/functions/greater_than_equals.rb +70 -0
- data/lib/functions/lamp_phase.rb +39 -0
- data/lib/functions/less_than.rb +70 -0
- data/lib/functions/less_than_equals.rb +70 -0
- data/lib/functions/lfo_square.rb +68 -0
- data/lib/functions/lfo_triangle.rb +72 -0
- data/lib/functions/lookup.rb +86 -0
- data/lib/functions/max.rb +70 -0
- data/lib/functions/min.rb +70 -0
- data/lib/functions/minus.rb +70 -0
- data/lib/functions/modulo.rb +70 -0
- data/lib/functions/noise.rb +49 -0
- data/lib/functions/noise_pixel.rb +49 -0
- data/lib/functions/phasor.rb +96 -0
- data/lib/functions/ref.rb +34 -0
- data/lib/functions/scale.rb +71 -0
- data/lib/functions/table.rb +16 -0
- data/lib/functions/times.rb +70 -0
- data/lib/functions/triangle.rb +69 -0
- data/lib/templates/arduino_library.ino.erb +75 -0
- metadata +84 -0
@@ -0,0 +1,63 @@
|
|
1
|
+
$tables = {}
|
2
|
+
|
3
|
+
class CreateLookup < Base
|
4
|
+
Arbol.add_mapped_class(
|
5
|
+
'create_lookup',
|
6
|
+
CreateLookup,
|
7
|
+
nil
|
8
|
+
)
|
9
|
+
|
10
|
+
attr_accessor :identifier
|
11
|
+
attr_accessor :value
|
12
|
+
|
13
|
+
def initialize(params)
|
14
|
+
super(params)
|
15
|
+
@identifier = params[:identifier]
|
16
|
+
unless $tables.has_key?(@identifier)
|
17
|
+
$tables[@identifier] = params[:value]
|
18
|
+
@value = params[:value]
|
19
|
+
else
|
20
|
+
raise "duplicate table definition #{params[:name]}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def param_keys
|
25
|
+
[]
|
26
|
+
end
|
27
|
+
|
28
|
+
def arduino_code
|
29
|
+
[]
|
30
|
+
end
|
31
|
+
|
32
|
+
def top_level_scope_code
|
33
|
+
[
|
34
|
+
"long #{@identifier}[#{@value.length}][3] = #{table_to_cplusplus_array(@value)};"
|
35
|
+
]
|
36
|
+
end
|
37
|
+
|
38
|
+
def table_to_cplusplus_array(t)
|
39
|
+
"{#{t.map {|f| f.to_s.gsub(/\[/, '{').gsub(/\]/, '}') }.join(',')}}"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
def resolve_lookup(val)
|
45
|
+
puts val
|
46
|
+
puts val.class
|
47
|
+
raise "table definition must be an array" unless val.class == Array
|
48
|
+
val.map do |v|
|
49
|
+
case
|
50
|
+
when [Integer, Float].include?(v.class)
|
51
|
+
then 3.times.map { scale_correctly(v) }
|
52
|
+
when v.class == Array then v.map { |i| scale_correctly(i) }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def create_table_ref(identifier, value)
|
58
|
+
h = ArbolHash.new
|
59
|
+
h[:type] = 'create_lookup'
|
60
|
+
h[:identifier] = identifier
|
61
|
+
h[:value] = resolve_lookup(value)
|
62
|
+
h
|
63
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
$refs = {}
|
2
|
+
$refs_frame_optimized = {}
|
3
|
+
|
4
|
+
class CreateRef < Base
|
5
|
+
Arbol.add_mapped_class('create_ref', CreateRef, nil)
|
6
|
+
attr_accessor :identifier
|
7
|
+
attr_accessor :value
|
8
|
+
|
9
|
+
def initialize(params)
|
10
|
+
super(params)
|
11
|
+
@identifier = params[:identifier]
|
12
|
+
resolve_frame_optimized
|
13
|
+
unless $refs.has_key?(@identifier)
|
14
|
+
$refs[@identifier] = @name
|
15
|
+
$refs_frame_optimized[@identifier] = @frame_optimized
|
16
|
+
else
|
17
|
+
raise "duplicate ref definition #{params[:name]}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def param_keys
|
22
|
+
[:value]
|
23
|
+
end
|
24
|
+
|
25
|
+
def arduino_code
|
26
|
+
[]
|
27
|
+
end
|
28
|
+
|
29
|
+
def top_level_scope_code
|
30
|
+
[
|
31
|
+
"long *#{@name} = #{@value.name};"
|
32
|
+
]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def create_ref(identifier, value)
|
37
|
+
h = ArbolHash.new
|
38
|
+
if value.class == ArbolTable
|
39
|
+
h[:type] = 'create_lookup'
|
40
|
+
h[:identifier] = identifier
|
41
|
+
h[:value] = resolve_lookup(value.table)
|
42
|
+
else
|
43
|
+
h[:type] = 'create_ref'
|
44
|
+
h[:identifier] = identifier
|
45
|
+
h[:value] = resolve(value)
|
46
|
+
end
|
47
|
+
h
|
48
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
class Crossfade < Base
|
2
|
+
Arbol.add_mapped_class(
|
3
|
+
'crossfade',
|
4
|
+
Crossfade,
|
5
|
+
%{void crossfade(long fader[3], long channel1[3], long channel2[3], long out[3]) {
|
6
|
+
out[0] = long_mult(INTEGER_SCALE - 1 - fader[0], channel1[0]) + long_mult(fader[0], channel2[0]);
|
7
|
+
out[1] = long_mult(INTEGER_SCALE - 1 - fader[1], channel1[1]) + long_mult(fader[1], channel2[1]);
|
8
|
+
out[2] = long_mult(INTEGER_SCALE - 1 - fader[2], channel1[2]) + long_mult(fader[2], channel2[2]);
|
9
|
+
}}
|
10
|
+
)
|
11
|
+
|
12
|
+
attr_accessor :fader
|
13
|
+
attr_accessor :channel1
|
14
|
+
attr_accessor :channel2
|
15
|
+
|
16
|
+
def param_keys
|
17
|
+
[:fader, :channel1, :channel2]
|
18
|
+
end
|
19
|
+
|
20
|
+
def arduino_code
|
21
|
+
unless @frame_optimized
|
22
|
+
[
|
23
|
+
"crossfade(#{@fader.name}, #{@channel1.name}, #{@channel2.name}, #{@name});"
|
24
|
+
]
|
25
|
+
else
|
26
|
+
[]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def cycle_level_arduino_code
|
31
|
+
if @frame_optimized
|
32
|
+
[
|
33
|
+
"crossfade(#{@fader.name}, #{@channel1.name}, #{@channel2.name}, #{@name});"
|
34
|
+
]
|
35
|
+
else
|
36
|
+
[]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def top_level_scope_code
|
41
|
+
[
|
42
|
+
"long #{@name}[3];",
|
43
|
+
]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
module Arbol
|
48
|
+
class Documentation
|
49
|
+
|
50
|
+
def crossfade
|
51
|
+
%{--
|
52
|
+
### crossfade(fader, channel1, channel2)
|
53
|
+
|
54
|
+
* **fader** - fade amount between channels
|
55
|
+
* **channel1** - channel1
|
56
|
+
* **channel2** - channel2
|
57
|
+
|
58
|
+
Returns a mix of channels 1 and 2 based on the fader amount between 0-~1.0.
|
59
|
+
|
60
|
+
}
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def crossfade(fader, channel1, channel2)
|
67
|
+
h = ArbolHash.new
|
68
|
+
h[:type] = 'crossfade'
|
69
|
+
h[:fader] = resolve(fader)
|
70
|
+
h[:channel1] = resolve(channel1)
|
71
|
+
h[:channel2] = resolve(channel2)
|
72
|
+
h
|
73
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
class Divide < Base
|
2
|
+
Arbol.add_mapped_class(
|
3
|
+
'divide',
|
4
|
+
Divide,
|
5
|
+
%{void divide(long numerator[3], long denominator[3], long out[3]) {
|
6
|
+
out[0] = long_div(numerator[0], denominator[0]);
|
7
|
+
out[1] = long_div(numerator[1], denominator[1]);
|
8
|
+
out[2] = long_div(numerator[2], denominator[2]);
|
9
|
+
}}
|
10
|
+
)
|
11
|
+
|
12
|
+
attr_accessor :numerator
|
13
|
+
attr_accessor :denominator
|
14
|
+
|
15
|
+
def param_keys
|
16
|
+
[:numerator, :denominator]
|
17
|
+
end
|
18
|
+
|
19
|
+
def arduino_code
|
20
|
+
unless @frame_optimized
|
21
|
+
[
|
22
|
+
"divide(#{@numerator.name}, #{@denominator.name}, #{@name});"
|
23
|
+
]
|
24
|
+
else
|
25
|
+
[]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def cycle_level_arduino_code
|
30
|
+
if @frame_optimized
|
31
|
+
[
|
32
|
+
"divide(#{@numerator.name}, #{@denominator.name}, #{@name});"
|
33
|
+
]
|
34
|
+
else
|
35
|
+
[]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def top_level_scope_code
|
40
|
+
[
|
41
|
+
"long #{@name}[3];"
|
42
|
+
]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
module Arbol
|
47
|
+
class Documentation
|
48
|
+
|
49
|
+
def divide
|
50
|
+
%{--
|
51
|
+
### divide(numerator, denominator)
|
52
|
+
|
53
|
+
* **numerator**
|
54
|
+
* **denominator**
|
55
|
+
|
56
|
+
Division. Also accepts the form `numerator / denominator`.
|
57
|
+
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def divide(numerator, denominator)
|
65
|
+
h = ArbolHash.new
|
66
|
+
h[:type] = 'add'
|
67
|
+
h[:numerator] = resolve(numerator)
|
68
|
+
h[:denominator] = resolve(denominator)
|
69
|
+
h
|
70
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
class Feedback < Base
|
2
|
+
Arbol.add_mapped_class(
|
3
|
+
'feedback',
|
4
|
+
Feedback,
|
5
|
+
%{void feedback(int pixel, long input[3], long feedback[3], long storage[][3], long out[3]) {
|
6
|
+
out[0] = max(input[0], storage[pixel][0]);
|
7
|
+
out[1] = max(input[1], storage[pixel][1]);
|
8
|
+
out[2] = max(input[2], storage[pixel][2]);
|
9
|
+
storage[pixel][0] = constrain(long_mult(out[0], feedback[0]), 0, INTEGER_SCALE);
|
10
|
+
storage[pixel][1] = constrain(long_mult(out[1], feedback[1]), 0, INTEGER_SCALE);
|
11
|
+
storage[pixel][2] = constrain(long_mult(out[2], feedback[2]), 0, INTEGER_SCALE);
|
12
|
+
}}
|
13
|
+
)
|
14
|
+
|
15
|
+
attr_accessor :input
|
16
|
+
attr_accessor :feedback
|
17
|
+
|
18
|
+
def initialize(params)
|
19
|
+
super(params)
|
20
|
+
@frame_optimized = false
|
21
|
+
end
|
22
|
+
|
23
|
+
def param_keys
|
24
|
+
[:input, :feedback]
|
25
|
+
end
|
26
|
+
|
27
|
+
def arduino_code
|
28
|
+
[
|
29
|
+
"feedback(i, #{@input.name}, #{@feedback.name}, #{@name}_storage, #{@name});"
|
30
|
+
]
|
31
|
+
end
|
32
|
+
|
33
|
+
def top_level_scope_code
|
34
|
+
[
|
35
|
+
"long #{@name}[3];",
|
36
|
+
"long #{@name}_storage[PIXEL_COUNT][3];"
|
37
|
+
]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
module Arbol
|
42
|
+
class Documentation
|
43
|
+
|
44
|
+
def feedback
|
45
|
+
%{--
|
46
|
+
### feedback(input, feedback)
|
47
|
+
|
48
|
+
* **input**
|
49
|
+
* **feedback**
|
50
|
+
|
51
|
+
Returns the greatest of the input or the feedback value.
|
52
|
+
|
53
|
+
}
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def feedback(input, feedback)
|
60
|
+
h = ArbolHash.new
|
61
|
+
h[:type] = 'feedback'
|
62
|
+
h[:input] = resolve(input)
|
63
|
+
h[:feedback] = resolve(feedback)
|
64
|
+
h
|
65
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
class FeedbackOffset < Base
|
2
|
+
Arbol.add_mapped_class(
|
3
|
+
'feedback_offset',
|
4
|
+
FeedbackOffset,
|
5
|
+
%{void feedback_offset(int pixel, int pixel_count, long input[3], long feedback[3], long offset[3], long storage[][3], long out[3]) {
|
6
|
+
out[0] = max(input[0], storage[(pixel + long_mult(offset[0], pixel_count)) % pixel_count][0]);
|
7
|
+
out[1] = max(input[1], storage[(pixel + long_mult(offset[1], pixel_count)) % pixel_count][1]);
|
8
|
+
out[2] = max(input[2], storage[(pixel + long_mult(offset[2], pixel_count)) % pixel_count][2]);
|
9
|
+
storage[pixel][0] = constrain(long_mult(out[0], feedback[0]), 0, INTEGER_SCALE);
|
10
|
+
storage[pixel][1] = constrain(long_mult(out[1], feedback[1]), 0, INTEGER_SCALE);
|
11
|
+
storage[pixel][2] = constrain(long_mult(out[2], feedback[2]), 0, INTEGER_SCALE);
|
12
|
+
}}
|
13
|
+
)
|
14
|
+
|
15
|
+
attr_accessor :input
|
16
|
+
attr_accessor :feedback
|
17
|
+
attr_accessor :offset
|
18
|
+
|
19
|
+
def initialize(params)
|
20
|
+
super(params)
|
21
|
+
@frame_optimized = false
|
22
|
+
end
|
23
|
+
|
24
|
+
def param_keys
|
25
|
+
[:input, :feedback, :offset]
|
26
|
+
end
|
27
|
+
|
28
|
+
def arduino_code
|
29
|
+
[
|
30
|
+
"feedback_offset(i, PIXEL_COUNT, #{@input.name}, #{@feedback.name}, #{@offset.name}, #{@name}_storage, #{@name});"
|
31
|
+
]
|
32
|
+
end
|
33
|
+
|
34
|
+
def top_level_scope_code
|
35
|
+
[
|
36
|
+
"long #{@name}[3];",
|
37
|
+
"long #{@name}_storage[PIXEL_COUNT][3];"
|
38
|
+
]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
module Arbol
|
43
|
+
class Documentation
|
44
|
+
|
45
|
+
def feedback_offset
|
46
|
+
%{--
|
47
|
+
### feedback\_offset(input, feedback, offset)
|
48
|
+
|
49
|
+
* **input**
|
50
|
+
* **feedback**
|
51
|
+
* **offset**
|
52
|
+
|
53
|
+
Returns the greatest of the input or the feedback value at the offset (0-~1.0)
|
54
|
+
from the current pixel.
|
55
|
+
|
56
|
+
}
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def feedback_offset(input, feedback, offset)
|
63
|
+
h = ArbolHash.new
|
64
|
+
h[:type] = 'feedback_offset'
|
65
|
+
h[:input] = resolve(input)
|
66
|
+
h[:feedback] = resolve(feedback)
|
67
|
+
h[:offset] = resolve(offset)
|
68
|
+
h
|
69
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
class Gamma < Base
|
2
|
+
Arbol.add_mapped_class(
|
3
|
+
'gamma',
|
4
|
+
Gamma,
|
5
|
+
%{long neopix_gamma[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 4, 5, 6, 7, 8, 9, 10, 12, 13, 15, 16, 18, 20, 22, 24, 26, 28, 31, 33, 36, 39, 42, 45, 48, 51, 55, 59, 62, 66, 71, 75, 79, 84, 89, 94, 99, 104, 110, 116, 122, 128, 134, 140, 147, 154, 161, 168, 176, 184, 192, 200, 208, 217, 225, 234, 244, 253, 263, 273, 283, 293, 304, 315, 326, 338, 349, 361, 373, 386, 398, 411, 425, 438, 452, 466, 480, 495, 510, 525, 541, 556, 572, 589, 605, 622, 640, 657, 675, 693, 712, 730, 750, 769, 789, 809, 829, 850, 871, 892, 914, 936, 959, 981, 1004, 1028, 1052, 1076, 1100, 1125, 1150, 1176, 1202, 1228, 1255, 1282, 1309, 1337, 1365, 1393, 1422, 1452, 1481, 1511, 1542, 1572, 1604, 1635, 1667, 1700, 1733, 1766, 1799, 1833, 1868, 1903, 1938, 1974, 2010, 2046, 2083, 2121, 2158, 2197, 2235, 2274, 2314, 2354, 2394, 2435, 2476, 2518, 2560, 2603, 2646, 2690, 2734, 2778, 2823, 2869, 2915, 2961, 3008, 3055, 3103, 3151, 3200, 3249, 3299, 3349, 3399, 3451, 3502, 3554, 3607, 3660, 3714, 3768, 3823, 3878, 3933, 3990, 4046, 4103, 4161, 4219, 4278, 4337, 4397, 4458, 4518, 4580, 4642, 4704, 4767, 4831, 4895, 4959, 5025, 5090, 5157, 5223, 5291, 5359, 5427, 5496, 5566, 5636, 5707, 5778, 5850, 5922, 5995, 6069, 6143, 6218, 6293, 6369, 6446, 6523, 6601, 6679, 6758, 6837, 6917, 6998, 7079, 7161, 7244, 7327, 7410, 7495, 7580, 7665, 7751, 7838, 7926, 8014, 8102};
|
6
|
+
|
7
|
+
long INTEGER_SCALE_MINUS_ONE = INTEGER_SCALE - 1;
|
8
|
+
void gamma(long input[3], long out[3]) {
|
9
|
+
out[0] = neopix_gamma[map(input[0], 0, INTEGER_SCALE_MINUS_ONE, 0, 255) ];
|
10
|
+
out[1] = neopix_gamma[map(input[1], 0, INTEGER_SCALE_MINUS_ONE, 0, 255) ];
|
11
|
+
out[2] = neopix_gamma[map(input[2], 0, INTEGER_SCALE_MINUS_ONE, 0, 255) ];
|
12
|
+
}}
|
13
|
+
)
|
14
|
+
|
15
|
+
attr_accessor :input
|
16
|
+
|
17
|
+
def initialize(params)
|
18
|
+
super(params)
|
19
|
+
@frame_optimized = false
|
20
|
+
end
|
21
|
+
|
22
|
+
def param_keys
|
23
|
+
[:input]
|
24
|
+
end
|
25
|
+
|
26
|
+
def arduino_code
|
27
|
+
[
|
28
|
+
"gamma(#{@input.name}, #{@name});"
|
29
|
+
]
|
30
|
+
end
|
31
|
+
|
32
|
+
def top_level_scope_code
|
33
|
+
[
|
34
|
+
"long #{@name}[3];"
|
35
|
+
]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
module Arbol
|
40
|
+
class Documentation
|
41
|
+
|
42
|
+
def gamma
|
43
|
+
%{--
|
44
|
+
### gamma(input)
|
45
|
+
|
46
|
+
* **input**
|
47
|
+
|
48
|
+
Returns gamma corrected input. This makes the colors look much better.
|
49
|
+
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def gamma(input)
|
57
|
+
h = ArbolHash.new
|
58
|
+
h[:type] = 'gamma'
|
59
|
+
h[:input] = resolve(input)
|
60
|
+
h
|
61
|
+
end
|