arbol 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +7 -0
  2. data/bin/arbol +25 -0
  3. data/lib/arbol.rb +45 -0
  4. data/lib/base.rb +397 -0
  5. data/lib/builder.rb +102 -0
  6. data/lib/documentation.rb +19 -0
  7. data/lib/dsl.rb +168 -0
  8. data/lib/functions/add.rb +70 -0
  9. data/lib/functions/add_constrain.rb +70 -0
  10. data/lib/functions/add_modulo.rb +70 -0
  11. data/lib/functions/analog_pin.rb +316 -0
  12. data/lib/functions/choose.rb +74 -0
  13. data/lib/functions/const.rb +63 -0
  14. data/lib/functions/create_lookup.rb +63 -0
  15. data/lib/functions/create_ref.rb +48 -0
  16. data/lib/functions/crossfade.rb +73 -0
  17. data/lib/functions/divide.rb +70 -0
  18. data/lib/functions/feedback.rb +65 -0
  19. data/lib/functions/feedback_offset.rb +69 -0
  20. data/lib/functions/gamma.rb +61 -0
  21. data/lib/functions/greater_than.rb +70 -0
  22. data/lib/functions/greater_than_equals.rb +70 -0
  23. data/lib/functions/lamp_phase.rb +39 -0
  24. data/lib/functions/less_than.rb +70 -0
  25. data/lib/functions/less_than_equals.rb +70 -0
  26. data/lib/functions/lfo_square.rb +68 -0
  27. data/lib/functions/lfo_triangle.rb +72 -0
  28. data/lib/functions/lookup.rb +86 -0
  29. data/lib/functions/max.rb +70 -0
  30. data/lib/functions/min.rb +70 -0
  31. data/lib/functions/minus.rb +70 -0
  32. data/lib/functions/modulo.rb +70 -0
  33. data/lib/functions/noise.rb +49 -0
  34. data/lib/functions/noise_pixel.rb +49 -0
  35. data/lib/functions/phasor.rb +96 -0
  36. data/lib/functions/ref.rb +34 -0
  37. data/lib/functions/scale.rb +71 -0
  38. data/lib/functions/table.rb +16 -0
  39. data/lib/functions/times.rb +70 -0
  40. data/lib/functions/triangle.rb +69 -0
  41. data/lib/templates/arduino_library.ino.erb +75 -0
  42. metadata +84 -0
@@ -0,0 +1,316 @@
1
+ class AnalogPin < Base
2
+ Arbol.add_mapped_class(
3
+ 'analog_pin',
4
+ AnalogPin,
5
+ %{void analog_pin(
6
+ int pin,
7
+ byte scale,
8
+ long in_lo,
9
+ long in_hi,
10
+ long out_lo,
11
+ long out_hi,
12
+ long threshold,
13
+ long window[],
14
+ long& running_total,
15
+ int& current_index,
16
+ long window_size,
17
+ long feedback,
18
+ long& storage,
19
+ long out[3]) {
20
+ long reading = long_mult(long_div(analogRead(pin), 4095), INTEGER_SCALE);
21
+
22
+ // scaling
23
+ if(scale == 1) {
24
+ reading = constrain(
25
+ map(
26
+ reading,
27
+ in_lo,
28
+ in_hi,
29
+ out_lo,
30
+ out_hi
31
+ ),
32
+ out_lo,
33
+ out_hi
34
+ );
35
+ }
36
+
37
+ // apply a threshold
38
+ if(threshold >= 0) {
39
+ if(reading >= threshold) {
40
+ reading = INTEGER_SCALE;
41
+ }
42
+ else {
43
+ reading = 0;
44
+ }
45
+ }
46
+
47
+ // averaging
48
+ if(window_size > 1) {
49
+ // remove the element at current_index from the running total
50
+ running_total -= window[current_index];
51
+
52
+ // store reading to current index for deletion in a later frame
53
+ window[current_index] = reading;
54
+
55
+ // add current reading to running total
56
+ running_total += window[current_index];
57
+
58
+ // calculate the average
59
+ reading = long(float(running_total) / (float(INTEGER_SCALE) * window_size) * INTEGER_SCALE);
60
+
61
+ // increment current_index
62
+ current_index += 1;
63
+
64
+ //set it to zero if we reached window_size
65
+ if(current_index == window_size) { current_index = 0; }
66
+ }
67
+
68
+ if(feedback > 0) {
69
+ reading = max(reading, storage);
70
+ storage = constrain(long_mult(reading, feedback), 0, INTEGER_SCALE);
71
+ }
72
+
73
+ out[0] = reading;
74
+ out[1] = reading;
75
+ out[2] = reading;
76
+ }}
77
+ )
78
+
79
+ def initialize(params)
80
+ @frame_optimized = true
81
+ @name = "#{self.class}_#{SecureRandom.uuid.to_s.gsub('-','')}"
82
+ @pin = params[:pin]
83
+
84
+ @scale = params[:scale]
85
+ @in_lo = params[:in_lo]
86
+ @in_hi = params[:in_hi]
87
+ @out_lo = params[:out_lo]
88
+ @out_hi = params[:out_hi]
89
+
90
+ @threshold = params[:threshold]
91
+ @window = params[:window]
92
+ @feedback = params[:feedback]
93
+ # buildit
94
+ end
95
+
96
+ def depends_on
97
+ []
98
+ end
99
+
100
+ attr_accessor :pin
101
+
102
+ attr_accessor :scale
103
+ attr_accessor :in_lo
104
+ attr_accessor :in_hi
105
+ attr_accessor :out_lo
106
+ attr_accessor :out_hi
107
+
108
+ attr_accessor :threshold
109
+ attr_accessor :window
110
+ attr_accessor :feedback
111
+
112
+ def arduino_code
113
+ unless @frame_optimized
114
+ [
115
+ %{analog_pin(
116
+ #{@pin},
117
+ #{@name}_scale,
118
+ #{@name}_in_lo,
119
+ #{@name}_in_hi,
120
+ #{@name}_out_lo,
121
+ #{@name}_out_hi,
122
+ #{@name}_threshold,
123
+ #{@name}_window,
124
+ #{@name}_running_total,
125
+ #{@name}_current_index,
126
+ #{seconds_to_frames(@window)},
127
+ #{@name}_feedback,
128
+ #{@name}_storage,
129
+ #{@name});}
130
+ ]
131
+ else
132
+ []
133
+ end
134
+ end
135
+
136
+ def cycle_level_arduino_code
137
+ if @frame_optimized
138
+ [
139
+ %{analog_pin(
140
+ #{@pin},
141
+ #{@name}_scale,
142
+ #{@name}_in_lo,
143
+ #{@name}_in_hi,
144
+ #{@name}_out_lo,
145
+ #{@name}_out_hi,
146
+ #{@name}_threshold,
147
+ #{@name}_window,
148
+ #{@name}_running_total,
149
+ #{@name}_current_index,
150
+ #{seconds_to_frames(@window)},
151
+ #{@name}_feedback,
152
+ #{@name}_storage,
153
+ #{@name});}
154
+ ]
155
+ else
156
+ []
157
+ end
158
+ end
159
+
160
+ def top_level_scope_code
161
+ [
162
+ "// pinMode(#{@pin}, INPUT);",
163
+ "long #{@name}[3];",
164
+
165
+ "byte #{@name}_scale = #{@scale};",
166
+ "long #{@name}_in_lo = #{@in_lo};",
167
+ "long #{@name}_in_hi = #{@in_hi};",
168
+ "long #{@name}_out_lo = #{@out_lo};",
169
+ "long #{@name}_out_hi = #{@out_hi};",
170
+
171
+ "long #{@name}_threshold = #{@threshold};",
172
+
173
+ "long #{@name}_window[#{seconds_to_frames(@window)}];",
174
+ "long #{@name}_running_total;",
175
+ "int #{@name}_current_index;",
176
+
177
+ "long #{@name}_feedback = #{@feedback};",
178
+ "long #{@name}_storage;"
179
+ ]
180
+ end
181
+
182
+ def seconds_to_frames(seconds)
183
+ (seconds * 30.0).to_i
184
+ end
185
+ end
186
+
187
+ module Arbol
188
+ class Documentation
189
+
190
+ def analog_pin
191
+ %{--
192
+ ### analog\\_pin(pin, in\\_lo, in\\_hi, out\\_lo, out\\_hi, threshold, window, feedback)
193
+
194
+ * **pin** - arduino pin to use as input.. either a number or A0, A1, etc...
195
+ * **in\\_lo** - scale and constrain.. lo value for input range
196
+ * **in\\_hi** - scale and constrain.. hi value for input range
197
+ * **out\\_lo** - scale and constrain.. lo value for output range
198
+ * **out\\_hi** - scale and constrain.. hi value for output range
199
+ * **threshold** - edge detection.. outputs INTEGER_SCALE if >= threshold.. otherwise zero
200
+ * **window** - input will be averaged by frame across this many seconds
201
+ * **feedback** - feeback amount applied to the input
202
+
203
+ Once per frame the specified pin is sampled, then the data is run through a chain of optional processing to add usefulness to signals that can be noisy, incorrectly offset, or too fast or squirrely.
204
+
205
+ The chain of processing is as follows:
206
+
207
+ * Pin is sampled once per frame.
208
+ * Scale and Constrain - Sampled value is scaled and constrained to the values specified by `in_lo`, `in_hi`, `out_lo`, `out_hi`. This functionality is enabled by specifying any one of these parameters, which default to 0.0, 1.0, 0.0, and 1.0 respectively.
209
+ * Edge detection - If `threshold` is specified, the value outputs 1.0 if >= `threshold` and 0.0 otherwise.
210
+ * Averaging window - Specifying a `window` value (in seconds, as a float) allows for the input to be averaged across the time period. The averages are calculated using a buffer that stores 30 frames for each second specified. Averaging provides a less jerky, slower control signal.
211
+ * Feedback - Specifying `feedback` (float between 0-1) applies a simple feedback calculation. This creates a longer "tail" on the control signal.
212
+
213
+ The above processes are calculated in the order specified above, with each stage feeding into the next.. unless the process is disabled, meaning that no parameter value is specified to enable it.
214
+
215
+ `analog_pin` uses named parameters as shown in the various examples below.
216
+
217
+ ```
218
+ sensor = analog_pin(
219
+ pin: 'A1'
220
+ );
221
+
222
+ sensor = analog_pin(
223
+ pin: 'A1',
224
+ in_lo: 0.1,
225
+ threshold: 0.4
226
+ );
227
+
228
+ sensor = analog_pint(
229
+ pin: 'A1',
230
+ window: 0.5,
231
+ feedback: 0.95
232
+ );
233
+ ```
234
+ }
235
+ end
236
+
237
+ end
238
+ end
239
+
240
+ def analog_pin(
241
+ pin:,
242
+ in_lo: 0,
243
+ in_hi: 1.0,
244
+ out_lo: 0,
245
+ out_hi: 1.0,
246
+ threshold: nil,
247
+ window: nil,
248
+ feedback: nil
249
+ )
250
+
251
+ h = ArbolHash.new
252
+ h[:type] = 'analog_pin'
253
+ h[:pin] = resolve_pin_reference(pin)
254
+
255
+ # set scaling if any of the scale parameters are changed
256
+ h[:scale] = 0
257
+ h[:scale] = 1 if in_lo != 0
258
+ h[:scale] = 1 if in_hi != 1.0
259
+ h[:scale] = 1 if out_lo != 0
260
+ h[:scale] = 1 if out_hi != 1.0
261
+
262
+ h[:in_lo] = resolve_positive_scalar(in_lo)
263
+ h[:in_hi] = resolve_positive_scalar(in_hi)
264
+ h[:out_lo] = resolve_positive_scalar(out_lo)
265
+ h[:out_hi] = resolve_positive_scalar(out_hi)
266
+
267
+ if threshold
268
+ h[:threshold] = resolve_positive_scalar(threshold)
269
+ else
270
+ h[:threshold] = -1
271
+ end
272
+
273
+ if window
274
+ h[:window] = resolve_float(window)
275
+ else
276
+ h[:window] = 0.0
277
+ end
278
+
279
+ if feedback
280
+ h[:feedback] = resolve_positive_scalar(feedback)
281
+ else
282
+ h[:feedback] = 0
283
+ end
284
+ puts(h)
285
+ h
286
+ end
287
+
288
+ =begin
289
+ steps:
290
+
291
+ 1. read pin
292
+
293
+ pin
294
+
295
+ 2. optionally map/constrain
296
+
297
+ scale
298
+ in_low
299
+ in_hi
300
+ out_low
301
+ out_hi
302
+
303
+
304
+ 3. optional threshold
305
+
306
+ threshold
307
+
308
+ 4. optional averaging window
309
+
310
+ window
311
+
312
+ 5. optional feedback
313
+
314
+ feedback
315
+
316
+ =end
@@ -0,0 +1,74 @@
1
+ class Choose < Base
2
+ Arbol.add_mapped_class(
3
+ 'choose',
4
+ Choose,
5
+ %{void choose(long choice[3], long op1[3], long op2[3], long out[3], long threshold) {
6
+ if(choice[0] <= threshold) { out[0] = op1[0];} else { out[0] = op2[0]; }
7
+ if(choice[1] <= threshold) { out[1] = op1[1];} else { out[1] = op2[1]; }
8
+ if(choice[2] <= threshold) { out[2] = op1[2];} else { out[2] = op2[2]; }
9
+ }}
10
+ )
11
+
12
+ attr_accessor :choice
13
+ attr_accessor :op1
14
+ attr_accessor :op2
15
+
16
+ def param_keys
17
+ [:choice, :op1, :op2]
18
+ end
19
+
20
+ def arduino_code
21
+ unless @frame_optimized
22
+ [
23
+ "choose(#{@choice.name}, #{@op1.name}, #{@op2.name}, #{@name}, choose_half_phase);"
24
+ ]
25
+ else
26
+ []
27
+ end
28
+ end
29
+
30
+ def cycle_level_arduino_code
31
+ if @frame_optimized
32
+ [
33
+ "choose(#{@choice.name}, #{@op1.name}, #{@op2.name}, #{@name}, choose_half_phase);"
34
+ ]
35
+ else
36
+ []
37
+ end
38
+ end
39
+
40
+ def top_level_scope_code
41
+ [
42
+ "long choose_half_phase = INTEGER_SCALE / 2 - 1;",
43
+ "long #{@name}[3];"
44
+ ]
45
+ end
46
+ end
47
+
48
+ module Arbol
49
+ class Documentation
50
+
51
+ def choose
52
+ %{--
53
+ ### choose(choice, op1, op2)
54
+
55
+ * **choice** - selects the operator to be returned
56
+ * **op1** - operator1
57
+ * **op2** - operator2
58
+
59
+ Returns operator1 if choice < 0.5.. or operator2 if choice >= 0.5.
60
+
61
+ }
62
+ end
63
+
64
+ end
65
+ end
66
+
67
+ def choose(choice, op1, op2)
68
+ h = ArbolHash.new
69
+ h[:type] = 'choose'
70
+ h[:choice] = resolve(choice)
71
+ h[:op1] = resolve(op1)
72
+ h[:op2] = resolve(op2)
73
+ h
74
+ end
@@ -0,0 +1,63 @@
1
+ class Const < Base
2
+ Arbol.add_mapped_class('const', Const, nil)
3
+ attr_accessor :value
4
+
5
+ def initialize(params)
6
+ super
7
+ @value = params[:value]
8
+ end
9
+
10
+ def arduino_code
11
+ []
12
+ end
13
+
14
+ def top_level_scope_code
15
+ [
16
+ "long #{@name}[3] = {#{@value.join(',')}};"
17
+ ]
18
+ end
19
+ end
20
+
21
+ module Arbol
22
+ class Documentation
23
+
24
+ def const
25
+ %{--
26
+ ### const(value)
27
+
28
+ * **value** - input value to be used as a constant.
29
+
30
+ You can specify a constant explicity:
31
+
32
+ ```
33
+ const(0.4)
34
+
35
+ or
36
+
37
+ const([0.1, 0.2, 0.3])
38
+ ```
39
+
40
+ ..but generally you specify constants directly as values. There is no advantage in using the function.
41
+
42
+
43
+ ```
44
+ 0.4
45
+
46
+ or
47
+
48
+ [0.1, 0.2, 0.3]
49
+ ```
50
+ }
51
+ end
52
+
53
+ end
54
+ end
55
+
56
+
57
+ # given a slightly different name to avoid
58
+ def my_const(value)
59
+ {
60
+ type: "const",
61
+ value: coerce_array(value)
62
+ }
63
+ end