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,96 @@
|
|
1
|
+
class Phasor < Base
|
2
|
+
Arbol.add_mapped_class(
|
3
|
+
'phasor',
|
4
|
+
Phasor,
|
5
|
+
%{void phasor(long mils, long cycle[3], long out[3]) {
|
6
|
+
out[0] = long_div((mils % cycle[0]), cycle[0]);
|
7
|
+
out[1] = long_div((mils % cycle[1]), cycle[1]);
|
8
|
+
out[2] = long_div((mils % cycle[2]), cycle[2]);
|
9
|
+
}}
|
10
|
+
)
|
11
|
+
attr_accessor :cycles
|
12
|
+
|
13
|
+
def param_keys
|
14
|
+
[:cycles]
|
15
|
+
end
|
16
|
+
|
17
|
+
def arduino_code
|
18
|
+
unless @frame_optimized
|
19
|
+
[
|
20
|
+
"phasor(mils, #{@cycles.name}, #{@name});"
|
21
|
+
]
|
22
|
+
else
|
23
|
+
[]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def cycle_level_arduino_code
|
28
|
+
if @frame_optimized
|
29
|
+
[
|
30
|
+
"phasor(mils, #{@cycles.name}, #{@name});"
|
31
|
+
]
|
32
|
+
else
|
33
|
+
[]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def top_level_scope_code
|
38
|
+
[
|
39
|
+
"long #{@name}[3];"
|
40
|
+
]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
module Arbol
|
45
|
+
class Documentation
|
46
|
+
|
47
|
+
def phasor
|
48
|
+
%{--
|
49
|
+
### phasor(cycle_ms)
|
50
|
+
|
51
|
+
* **cycle_ms**
|
52
|
+
|
53
|
+
Outputs a ramp wave from 0-~1.0 over a period of cycle_ms milliseconds.
|
54
|
+
|
55
|
+
`phasor` is very important because it highlights a key way to bring motion into
|
56
|
+
the system. There are many ways of using phasor.
|
57
|
+
|
58
|
+
```
|
59
|
+
# go from 0-~1.0 over a period of 10 seconds:
|
60
|
+
phasor(10000)
|
61
|
+
|
62
|
+
# each of the three channels goes from 0-~1.0 at different millisecond intervals:
|
63
|
+
phasor([1000, 1100, 1200])
|
64
|
+
|
65
|
+
# phasor is input into a triangle function, which then creates a triangle
|
66
|
+
# wave that goes from 0-~1.0-0 over a period of 5 seconds specified
|
67
|
+
# to the phasor
|
68
|
+
tri = triangle(phasor(5000))
|
69
|
+
|
70
|
+
# multiple two triangles together to to get a pointy triangle
|
71
|
+
tri_squared = tri * tri
|
72
|
+
|
73
|
+
# using `lamp_phase` function in conjunction with `add_constrain` you can
|
74
|
+
# create motion in the lamps.
|
75
|
+
|
76
|
+
strip(
|
77
|
+
512, # 512 pixels
|
78
|
+
0, # attached to pin 0
|
79
|
+
add_constrain(
|
80
|
+
lamp_phase,
|
81
|
+
phasor([1000, 1200, 1300])
|
82
|
+
)
|
83
|
+
```
|
84
|
+
|
85
|
+
}
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def phasor(cycles)
|
92
|
+
h = ArbolHash.new
|
93
|
+
h[:type] = 'phasor'
|
94
|
+
h[:cycles] = resolve(cycles)
|
95
|
+
h
|
96
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class Ref < Base
|
2
|
+
Arbol.add_mapped_class('ref', Ref, nil)
|
3
|
+
attr_accessor :identifier
|
4
|
+
attr_accessor :ref_name
|
5
|
+
|
6
|
+
def initialize(params)
|
7
|
+
super(params)
|
8
|
+
@identifier = params[:identifier]
|
9
|
+
if $refs.has_key?(@identifier)
|
10
|
+
@ref_name = $refs[@identifier]
|
11
|
+
@frame_optimized = $refs_frame_optimized[@identifier]
|
12
|
+
else
|
13
|
+
raise "non-existant ref #{@identifier}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def arduino_code
|
18
|
+
[
|
19
|
+
]
|
20
|
+
end
|
21
|
+
|
22
|
+
def top_level_scope_code
|
23
|
+
[
|
24
|
+
"long *#{@name} = #{@ref_name};"
|
25
|
+
]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def ref(identifier)
|
30
|
+
h = ArbolHash.new
|
31
|
+
h[:type] = 'ref'
|
32
|
+
h[:identifier] = identifier
|
33
|
+
h
|
34
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
class Scale < Base
|
2
|
+
Arbol.add_mapped_class(
|
3
|
+
'scale',
|
4
|
+
Scale,
|
5
|
+
%{void scale(long input[3], long lo_in[3], long hi_in[3], long lo_out[3], long hi_out[3], long out[3]) {
|
6
|
+
out[0] = map(input[0], lo_in[0], hi_in[0], lo_out[0], hi_out[0]);
|
7
|
+
out[1] = map(input[1], lo_in[1], hi_in[1], lo_out[1], hi_out[1]);
|
8
|
+
out[2] = map(input[2], lo_in[2], hi_in[2], lo_out[2], hi_out[2]);
|
9
|
+
}}
|
10
|
+
)
|
11
|
+
|
12
|
+
attr_accessor :input
|
13
|
+
attr_accessor :lo_in
|
14
|
+
attr_accessor :hi_in
|
15
|
+
attr_accessor :lo_out
|
16
|
+
attr_accessor :hi_out
|
17
|
+
|
18
|
+
def param_keys
|
19
|
+
[:input, :lo_in, :hi_in, :lo_out, :hi_out]
|
20
|
+
end
|
21
|
+
|
22
|
+
def arduino_code
|
23
|
+
unless @frame_optimized
|
24
|
+
[
|
25
|
+
"scale(#{@input.name}, #{@lo_in.name}, #{@hi_in.name}, #{@lo_out.name}, #{@hi_out.name}, #{@name});"
|
26
|
+
]
|
27
|
+
else
|
28
|
+
[]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def cycle_level_arduino_code
|
33
|
+
if @frame_optimized
|
34
|
+
[
|
35
|
+
"scale(#{@input.name}, #{@lo_in.name}, #{@hi_in.name}, #{@lo_out.name}, #{@hi_out.name}, #{@name});"
|
36
|
+
]
|
37
|
+
else
|
38
|
+
[]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def top_level_scope_code
|
43
|
+
[
|
44
|
+
"long #{@name}[3];"
|
45
|
+
]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
module Arbol
|
50
|
+
class Documentation
|
51
|
+
|
52
|
+
def scale
|
53
|
+
%{--
|
54
|
+
### scale needs doc
|
55
|
+
|
56
|
+
}
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def scale(input, lo_in, hi_in, lo_out, hi_out)
|
63
|
+
h = ArbolHash.new
|
64
|
+
h[:type] = 'scale'
|
65
|
+
h[:input] = resolve(input)
|
66
|
+
h[:lo_in] = resolve(lo_in)
|
67
|
+
h[:hi_in] = resolve(hi_in)
|
68
|
+
h[:lo_out] = resolve(lo_out)
|
69
|
+
h[:hi_out] = resolve(hi_out)
|
70
|
+
h
|
71
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class ArbolTable
|
2
|
+
attr_accessor :table
|
3
|
+
|
4
|
+
def initialize(tbl)
|
5
|
+
@table = tbl
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
|
10
|
+
# really this is just a pass through for arrays
|
11
|
+
# used in lookup table creation
|
12
|
+
def table(contents)
|
13
|
+
if contents.class == Array
|
14
|
+
ArbolTable.new(contents)
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
class Times < Base
|
2
|
+
Arbol.add_mapped_class(
|
3
|
+
'times',
|
4
|
+
Times,
|
5
|
+
%{void times(long op1[3], long op2[3], long out[3]) {
|
6
|
+
out[0] = long_mult(op1[0], op2[0]);
|
7
|
+
out[1] = long_mult(op1[1], op2[1]);
|
8
|
+
out[2] = long_mult(op1[2], op2[2]);
|
9
|
+
}}
|
10
|
+
)
|
11
|
+
|
12
|
+
attr_accessor :op1
|
13
|
+
attr_accessor :op2
|
14
|
+
|
15
|
+
def param_keys
|
16
|
+
[:op1, :op2]
|
17
|
+
end
|
18
|
+
|
19
|
+
def arduino_code
|
20
|
+
unless @frame_optimized
|
21
|
+
[
|
22
|
+
"times(#{@op1.name}, #{@op2.name}, #{@name});"
|
23
|
+
]
|
24
|
+
else
|
25
|
+
[]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def cycle_level_arduino_code
|
30
|
+
if @frame_optimized
|
31
|
+
[
|
32
|
+
"times(#{@op1.name}, #{@op2.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 times
|
50
|
+
%{--
|
51
|
+
### times(operator1, operator2)
|
52
|
+
|
53
|
+
* **operator1**
|
54
|
+
* **operator2**
|
55
|
+
|
56
|
+
Multiplication of the two operators. Can also be used with the form `operator1 * operator2`.
|
57
|
+
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def times(op1, op2)
|
65
|
+
h = ArbolHash.new
|
66
|
+
h[:type] = 'times'
|
67
|
+
h[:op1] = resolve(op1)
|
68
|
+
h[:op2] = resolve(op2)
|
69
|
+
h
|
70
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
class PhaseTriangle < Base
|
2
|
+
Arbol.add_mapped_class(
|
3
|
+
'triangle',
|
4
|
+
PhaseTriangle,
|
5
|
+
%{//long twice_int_scale_vec[3] = {long(INTEGER_SCALE * 2), long(INTEGER_SCALE * 2), long(INTEGER_SCALE * 2)};
|
6
|
+
void triangle(long mils, long phase[3], long out[3]) {
|
7
|
+
long times_result[3];
|
8
|
+
times(phase, twice_int_scale_vec, times_result);
|
9
|
+
if(times_result[0] > INTEGER_SCALE) { out[0] = (twice_int_scale_vec[0] - times_result[0]); } else { out[0] = times_result[0]; }
|
10
|
+
if(times_result[1] > INTEGER_SCALE) { out[1] = (twice_int_scale_vec[1] - times_result[1]); } else { out[1] = times_result[1]; }
|
11
|
+
if(times_result[2] > INTEGER_SCALE) { out[2] = (twice_int_scale_vec[2] - times_result[2]); } else { out[2] = times_result[2]; }
|
12
|
+
}}
|
13
|
+
)
|
14
|
+
attr_accessor :phase
|
15
|
+
|
16
|
+
def param_keys
|
17
|
+
[:phase]
|
18
|
+
end
|
19
|
+
|
20
|
+
def arduino_code
|
21
|
+
unless @frame_optimized
|
22
|
+
[
|
23
|
+
"triangle(mils, #{@phase.name}, #{@name});"
|
24
|
+
]
|
25
|
+
else
|
26
|
+
[]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def cycle_level_arduino_code
|
31
|
+
if @frame_optimized
|
32
|
+
[
|
33
|
+
"triangle(mils, #{@phase.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 triangle
|
51
|
+
%{--
|
52
|
+
### triangle(phase)
|
53
|
+
|
54
|
+
* **phase**
|
55
|
+
|
56
|
+
`phase` input 0.0-1.0 input is transformed into a triangle.
|
57
|
+
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def triangle(phase)
|
65
|
+
h = ArbolHash.new
|
66
|
+
h[:type] = 'triangle'
|
67
|
+
h[:phase] = resolve(phase)
|
68
|
+
h
|
69
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
#include <malloc.h>
|
2
|
+
#include <Thread.h>
|
3
|
+
#include <Adafruit_NeoPixel_ZeroDMA.h>
|
4
|
+
|
5
|
+
#define INTEGER_SCALE <%= integer_scale %>
|
6
|
+
#define PIXEL_COUNT <%= pixels %>
|
7
|
+
|
8
|
+
long long_div(long numerator, long denominator)
|
9
|
+
{
|
10
|
+
return (numerator * INTEGER_SCALE) / denominator;
|
11
|
+
}
|
12
|
+
|
13
|
+
long long_mult(long op1, long op2)
|
14
|
+
{
|
15
|
+
return op1 * op2 / INTEGER_SCALE;
|
16
|
+
}
|
17
|
+
|
18
|
+
byte byte_mult(byte op1, byte op2)
|
19
|
+
{
|
20
|
+
return (byte)((uint16_t)op1 * (uint16_t)op2 / (uint16_t)INTEGER_SCALE);
|
21
|
+
}
|
22
|
+
|
23
|
+
int neoPixelPin = <%= pin %>;
|
24
|
+
int pixelCount = PIXEL_COUNT;
|
25
|
+
|
26
|
+
|
27
|
+
<%= code %>
|
28
|
+
|
29
|
+
//END OF ARBOL LIBRARY
|
30
|
+
|
31
|
+
// Instatiate the NeoPixel from the library
|
32
|
+
Adafruit_NeoPixel_ZeroDMA strip = Adafruit_NeoPixel_ZeroDMA(pixelCount, neoPixelPin, NEO_GRB + NEO_KHZ800);
|
33
|
+
|
34
|
+
Thread calculate_strip_thread = Thread();
|
35
|
+
|
36
|
+
void setup() {
|
37
|
+
analogReadResolution(12);
|
38
|
+
|
39
|
+
calculate_strip_thread.setInterval(33);
|
40
|
+
calculate_strip_thread.onRun(calculate_strip);
|
41
|
+
strip.begin();
|
42
|
+
}
|
43
|
+
|
44
|
+
void loop() {
|
45
|
+
if(calculate_strip_thread.shouldRun()) calculate_strip_thread.run();
|
46
|
+
}
|
47
|
+
|
48
|
+
// beginning of top level scope definition
|
49
|
+
|
50
|
+
<%= tls %>
|
51
|
+
|
52
|
+
// end of top level scope definition
|
53
|
+
|
54
|
+
void calculate_strip() {
|
55
|
+
long mils = millis();
|
56
|
+
for (int i=0; i < pixelCount; i++) {
|
57
|
+
long this_phase = long_div(i, pixelCount - 1);
|
58
|
+
if(i == 0) {
|
59
|
+
// beginning of code that executes once per frame
|
60
|
+
|
61
|
+
<%= cycle %>
|
62
|
+
|
63
|
+
//
|
64
|
+
}
|
65
|
+
// beginning of code that executes for every pixel
|
66
|
+
|
67
|
+
<%= body %>
|
68
|
+
|
69
|
+
// end of generated code
|
70
|
+
}
|
71
|
+
strip.show();
|
72
|
+
}
|
73
|
+
|
74
|
+
|
75
|
+
|
metadata
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: arbol
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- jeremy winters
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-07-07 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: define DSP-like function chains for your lights
|
14
|
+
email: jeremyranierwinters@gmail.com
|
15
|
+
executables:
|
16
|
+
- arbol
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- bin/arbol
|
21
|
+
- lib/arbol.rb
|
22
|
+
- lib/base.rb
|
23
|
+
- lib/builder.rb
|
24
|
+
- lib/documentation.rb
|
25
|
+
- lib/dsl.rb
|
26
|
+
- lib/functions/add.rb
|
27
|
+
- lib/functions/add_constrain.rb
|
28
|
+
- lib/functions/add_modulo.rb
|
29
|
+
- lib/functions/analog_pin.rb
|
30
|
+
- lib/functions/choose.rb
|
31
|
+
- lib/functions/const.rb
|
32
|
+
- lib/functions/create_lookup.rb
|
33
|
+
- lib/functions/create_ref.rb
|
34
|
+
- lib/functions/crossfade.rb
|
35
|
+
- lib/functions/divide.rb
|
36
|
+
- lib/functions/feedback.rb
|
37
|
+
- lib/functions/feedback_offset.rb
|
38
|
+
- lib/functions/gamma.rb
|
39
|
+
- lib/functions/greater_than.rb
|
40
|
+
- lib/functions/greater_than_equals.rb
|
41
|
+
- lib/functions/lamp_phase.rb
|
42
|
+
- lib/functions/less_than.rb
|
43
|
+
- lib/functions/less_than_equals.rb
|
44
|
+
- lib/functions/lfo_square.rb
|
45
|
+
- lib/functions/lfo_triangle.rb
|
46
|
+
- lib/functions/lookup.rb
|
47
|
+
- lib/functions/max.rb
|
48
|
+
- lib/functions/min.rb
|
49
|
+
- lib/functions/minus.rb
|
50
|
+
- lib/functions/modulo.rb
|
51
|
+
- lib/functions/noise.rb
|
52
|
+
- lib/functions/noise_pixel.rb
|
53
|
+
- lib/functions/phasor.rb
|
54
|
+
- lib/functions/ref.rb
|
55
|
+
- lib/functions/scale.rb
|
56
|
+
- lib/functions/table.rb
|
57
|
+
- lib/functions/times.rb
|
58
|
+
- lib/functions/triangle.rb
|
59
|
+
- lib/templates/arduino_library.ino.erb
|
60
|
+
homepage: https://www.github.com
|
61
|
+
licenses:
|
62
|
+
- MIT
|
63
|
+
metadata: {}
|
64
|
+
post_install_message:
|
65
|
+
rdoc_options: []
|
66
|
+
require_paths:
|
67
|
+
- lib
|
68
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
69
|
+
requirements:
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: '2.4'
|
73
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
requirements: []
|
79
|
+
rubyforge_project:
|
80
|
+
rubygems_version: 2.6.13
|
81
|
+
signing_key:
|
82
|
+
specification_version: 4
|
83
|
+
summary: functional streams for neopixel strips
|
84
|
+
test_files: []
|