arbol 0.0.2
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/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
|