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,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: []
|