diff options
| author | s-ol <s-ol@users.noreply.github.com> | 2020-02-16 11:47:24 +0000 |
|---|---|---|
| committer | s-ol <s-ol@users.noreply.github.com> | 2020-02-16 11:47:24 +0000 |
| commit | 2953f1e56b408fc26eb54fa65935505dd128ce82 (patch) | |
| tree | 8c7c513ccf03df06c4e9e2e70ba68031d2d0b7a5 /lib | |
| parent | add ==, mod (diff) | |
| download | alive-2953f1e56b408fc26eb54fa65935505dd128ce82.tar.gz alive-2953f1e56b408fc26eb54fa65935505dd128ce82.zip | |
major refactoring: Const, Stream + ResultNode
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/debug.moon | 6 | ||||
| -rw-r--r-- | lib/envelope.moon | 13 | ||||
| -rw-r--r-- | lib/gui.moon | 9 | ||||
| -rw-r--r-- | lib/logic.moon | 46 | ||||
| -rw-r--r-- | lib/math.moon | 66 | ||||
| -rw-r--r-- | lib/midi/core.moon | 17 | ||||
| -rw-r--r-- | lib/midi/init.moon | 44 | ||||
| -rw-r--r-- | lib/midi/launchctl.moon | 99 | ||||
| -rw-r--r-- | lib/osc.moon | 11 | ||||
| -rw-r--r-- | lib/pilot.moon | 22 | ||||
| -rw-r--r-- | lib/string.moon | 9 | ||||
| -rw-r--r-- | lib/time.moon | 57 | ||||
| -rw-r--r-- | lib/util.moon | 53 |
13 files changed, 270 insertions, 182 deletions
diff --git a/lib/debug.moon b/lib/debug.moon index ece365f..f642c2e 100644 --- a/lib/debug.moon +++ b/lib/debug.moon @@ -3,12 +3,10 @@ import Op from require 'core' class out extends Op @doc: "(out name-str value) - log value to the console" - setup: (name, @chld) => - @name = name\getc! + setup: (@name, @value) => update: (dt) => - @chld\update dt - L\print "@name", @chld\get! + L\print "#{@name\unwrap 'str'}", @value\unwrap! { :out diff --git a/lib/envelope.moon b/lib/envelope.moon index 8e8fafe..eb79a64 100644 --- a/lib/envelope.moon +++ b/lib/envelope.moon @@ -1,4 +1,4 @@ -import Const, Op, Scope, eval from require 'core' +import Stream, Op, Scope, eval from require 'core' class ar_core extends Op @doc: "(ar-core attack release gate) @@ -8,21 +8,18 @@ goes from 0 to 1 in attack seconds, holds while gate is on, then goes back to 0 new: (...) => super ... - @value = 0 + @out = Stream 'num', 0 setup: (@a, @r, @gate) => assert @a, "ar requires an attack value" assert @r, "ar requires a release value" assert @gate, "ar requires a gate value" + @out update: (dt) => - @a\update dt - @r\update dt - @gate\update dt + slope = if (@gate\unwrap 'bool') then (@a\unwrap! or 0.1) else -(@r\unwrap! or 0.5) - slope = if @gate\get! then (@a\get! or 0.1) else -(@r\get! or 0.5) - - @value = math.min 1, math.max 0, @value + dt / slope + @out\set math.min 1, math.max 0, @out\unwrap! + dt / slope scope = Scope.from_table { 'ar-core': ar_core } scope\set 'ar', eval '(fn (a r) (fn (gate) (ar-core a r gate)))', scope diff --git a/lib/gui.moon b/lib/gui.moon index a2fee4b..474de5c 100644 --- a/lib/gui.moon +++ b/lib/gui.moon @@ -12,12 +12,11 @@ display value as a bar" setup: (name, @chld) => @@instances[@name] = nil if @name - @name = name\getc! + @name = name\const!\unwrap! @@instances[@name] = @ update: (dt) => - @chld\update dt - @value = @chld\get! + @value = @chld\unwrap! destroy: => @@instances[@name] = nil @@ -44,9 +43,11 @@ class key extends Op setup: (@key) => assert @key + @out = Stream 'bool', false + @out update: (dt) => - @value = lk.isDown @key\get! + @out\set lk.isDown @key\unwrap! arguments, k = {} for a in *arg diff --git a/lib/logic.moon b/lib/logic.moon index 1c274dd..c476033 100644 --- a/lib/logic.moon +++ b/lib/logic.moon @@ -1,37 +1,36 @@ -import Op from require 'core' +import Stream, Op from require 'core' unpack or= table.unpack class BinOp extends Op + new: (...) => + super ... + @out = Stream 'bool' + setup: (...) => @children = { ... } assert #@children >= 2, "#{@} needs at least two parameters" - - update: (dt) => - for child in *@children - child\update dt + @out class eq extends BinOp @doc: "(eq a b [c]...) (== a b [c]...) - check for equality" update: (dt) => - super\update dt - - @value = true - val = @children[1]\get! + equal = true + val = @children[1]\unwrap! for child in *@children[2,] - @value and= val == child\get! + equal and= val == child\unwrap! + @out\set equal class and_ extends BinOp @doc: "(and a b [c]...) - AND values" update: (dt) => - super\update dt - - @value = true + value = true for child in *@children - @value and= child\get! + value and= child\unwrap! + @out\set value class or_ extends BinOp @doc: "(or a b [c]...) - OR values @@ -39,31 +38,30 @@ class or_ extends BinOp subtracts all other arguments from a" update: (dt) => - super\update dt - - @value = false + value = false for child in *@children - @value or= child\get! + value or= child\unwrap! + @out\set value class not_ extends Op @doc: "(not a) - boolean opposite" setup: (@a) => + @out = Stream 'bool' + @out update: (dt) => - @a\update dt - - @value = not @a\get! + @out\set not @a\unwrap! class bool extends Op @doc: "(bool a) - convert to bool" setup: (@a) => + @out = Stream 'bool' + @out update: (dt) => - @a\update dt - - @value = switch @a\get! + @out\set switch @a\unwrap! when false, nil, 0 false else diff --git a/lib/math.moon b/lib/math.moon index 54d3440..68dae3a 100644 --- a/lib/math.moon +++ b/lib/math.moon @@ -1,25 +1,25 @@ -import Op from require 'core' +import Stream, Op, Const from require 'core' unpack or= table.unpack class BinOp extends Op + new: (...) => + super ... + @out = Stream 'num', 0 + setup: (...) => @children = { ... } assert #@children >= 2, "#{@} needs at least two parameters" - - update: (dt) => - for child in *@children - child\update dt + @out class add extends BinOp @doc: "(+ a b [c]...) (add a b [c]...) - add values" update: (dt) => - super\update dt - - @value = 0 + value = 0 for child in *@children - @value += child\get! + value += child\unwrap 'num' + @out\set value class sub extends BinOp @doc: "(- a b [c]...) @@ -28,22 +28,20 @@ class sub extends BinOp subtracts all other arguments from a" update: (dt) => - super\update dt - - @value = @children[1]\get! + value = @children[1]\unwrap 'num' for child in *@children[2,] - @value -= child\get! + value -= child\unwrap 'num' + @out\set value class mul extends BinOp @doc: "(* a b [c]...) (mul a b [c]...) - multiply values" update: (dt) => - super\update dt - - @value = 1 + value = 1 for child in *@children - @value *= child\get! + value *= child\unwrap 'num' + @out\set value class div extends BinOp @doc: "(/ a b [c]...) @@ -52,11 +50,26 @@ class div extends BinOp divides a by all other arguments" update: (dt) => - super\update dt - - @value = @children[1]\get! + value = @children[1]\unwrap 'num' for child in *@children[2,] - @value /= child\get! + value /= child\unwrap 'num' + @out\set value + +evenodd_op = (name, remainder) -> + class k extends Op + setup: (@a, @div=Const.num 2) => + @out = Stream 'bool' + @out + + update: (dt) => + a, divi = (@a\unwrap 'num'), @div\unwrap 'num' + @out\set (a % divi) == remainder + + k.__name = name + k.doc = "(#{name} a [div]) - check for #{name} divison + +div defaults to 2" + k func_op = (name, arity, func) -> k = class extends Op @@ -65,12 +78,11 @@ func_op = (name, arity, func) -> if arity != '*' assert #@params == arity, "#{@} needs exactly #{arity} parameters" - update: (dt) => - params = for param in *@params - param\update dt - param\get! + @out = Stream 'num' + @out - @value = func unpack params + update: (dt) => + @out\set func unpack [p\unwrap 'num' for p in *@params] k.__name = name k @@ -85,6 +97,8 @@ module = { :mod, '%': mod mix: func_op 'mix', 3, (a, b, i) -> i*b + (1-i)*a + even: evenodd_op 'even', 0 + odd: evenodd_op 'odd', 1 pi: math.pi, huge: math.huge } diff --git a/lib/midi/core.moon b/lib/midi/core.moon index ea49a2c..891de0a 100644 --- a/lib/midi/core.moon +++ b/lib/midi/core.moon @@ -51,8 +51,10 @@ class Input -- register a handler -- mask is { :status, :chan, :a } (all keys optional) + -- returns mask for op convenience attach: (mask, handler) => @listeners[mask] = handler + mask detach: (mask) => @listeners[mask] = nil @@ -83,8 +85,23 @@ class InOut detach: (...) => @inp\detach ... send: (...) => @out\send ... +apply_range = (range, val) -> + if range.type == 'str' + switch range\unwrap! + when 'raw' then val + when 'uni' then val / 128 + when 'bip' then val / 64 - 1 + when 'rad' then val / 64 * math.pi + else + error "unknown range #{@range}" + elseif range.type == 'num' + val / 128 * range\unwrap! + else + error "range has to be a string or number" + { :Input :Output :InOut + :apply_range } diff --git a/lib/midi/init.moon b/lib/midi/init.moon index f522b6c..c9e2476 100644 --- a/lib/midi/init.moon +++ b/lib/midi/init.moon @@ -1,29 +1,29 @@ -import Const, Op from require 'core' -import Input from require 'lib.midi.core' +import Stream, Const, Op from require 'core' +import Input, apply_range from require 'lib.midi.core' -dispatch = Input 'system:midi_capture_6' +dispatch = Input 'system:midi_capture_4' class gate extends Op @doc: "(midi/gate note [chan]) - gate from note-on and note-off messages" - new: (...) => - super ... - destroy: => dispatch\detach @mask if @mask setup: (note, chan) => dispatch\detach @mask if @mask - note = note\getc 'num' - chan = chan and chan\getc 'num' + note = note\const!\unwrap 'num' + chan = chan and chan\const!\unwrap 'num' @value = false @mask = dispatch\attach { :chan, a: note }, (status) -> if status == 'note-on' - @value = true + @out\set true else if status == 'note-off' - @value = false + @out\set false + + @out = Stream 'bool', false + @out update: (dt) => dispatch\tick! @@ -43,26 +43,16 @@ range can be one of: setup: (cc, chan, @range=Const.str'uni') => dispatch\detach @mask if @mask - cc = cc\getc 'num' - chan = chan and chan\getc 'num' + cc = cc\const!\unwrap 'num' + chan = chan and chan\const!\unwrap 'num' - @mask = dispatch\attach { status: 'control-change', :chan, a: cc }, (_, _, _, val) -> @apply val + @mask = dispatch\attach { status: 'control-change', :chan, a: cc }, (_, _, _, val) -> + @out\set apply_range @range, val - update: (dt) => dispatch\tick! + @out = Stream 'num', 0 + @out - apply: (val) => - @value = if @range.type == 'str' - switch @range\get! - when 'raw' then val - when 'uni' then val / 128 - when 'bip' then val / 64 - 1 - when 'rad' then val / 64 * math.pi - else - error "unknown range #{@range}" - elseif @range.type == 'num' - val / 128 * @range\get! - else - error "range has to be a string or number" + update: (dt) => dispatch\tick! { :gate diff --git a/lib/midi/launchctl.moon b/lib/midi/launchctl.moon index c7d7b06..778a724 100644 --- a/lib/midi/launchctl.moon +++ b/lib/midi/launchctl.moon @@ -1,66 +1,127 @@ -import Const, Op from require 'core' -import InOut from require 'lib.midi.core' +import Stream, Const, Op from require 'core' +import InOut, apply_range from require 'lib.midi.core' import bor, lshift from require 'bit32' -launch = InOut 'system:midi_capture_6', 'system:midi_playback_6' +launch = InOut 'system:midi_capture_4', 'system:midi_playback_4' color = (r, g) -> bor 12, r, (lshift g, 4) +class cc_seq extends Op + @doc: "(launctl/cc-seq i start chan [steps [range]]) - CC-Sequencer + +returns the value for the i-th step steps (buttons starting from start). +steps defaults to 8. + +range can be one of: +- 'raw' [ 0 - 128[ +- 'uni' [ 0 - 1[ (default) +- 'bip' [-1 - 1[ +- 'rad' [ 0 - tau[ +- (num) [ 0 - num[" + + destroy: => + launch\detach @mask if @mask + + new: => + @steps = {} + @out = Stream 'num' + + setup: (@i, start, chan, steps=(Const.num 8), @range=Const.str 'uni') => + launch\detach @mask if @mask + + @start = start\const!\unwrap 'num' + @chan = chan\const!\unwrap 'num' + steps = steps\const!\unwrap 'num' + + while steps > #@steps + table.insert @steps, 0 + while steps < #@steps + table.remove @steps + + @mask = launch\attach { status: 'control-change', chan: @chan }, (_, _, cc, val) -> @change cc, val + @out + + change: (cc, val) => + i = cc - @start + if i < #@steps + @steps[i+1] = val + + update: (dt) => + launch\tick! + + curr_i = (@i\unwrap 'num') % #@steps + + @out\set apply_range @range, @steps[curr_i+1] + + class gate_seq extends Op @doc: "(launctl/gate-seq i start chan [steps]) - Gate-Sequencer -returns true or false for the i-th step steps (buttons starting from start)." +returns true or false for the i-th step steps (buttons starting from start). +steps defaults to 8." destroy: => launch\detach @mask if @mask new: => @steps = {} - @value = false + @out = Stream 'bool' setup: (@i, start, chan, steps=(Const.num 8)) => launch\detach @mask if @mask - @start = start\getc 'num' - @chan = chan\getc 'num' - steps = steps\getc 'num' + for i=1, #@steps + launch\send 'note-on', @chan, (@start+i), 0, color 0, 0 + + @start = start\const!\unwrap 'num' + @chan = chan\const!\unwrap 'num' + steps = steps\const!\unwrap 'num' while steps > #@steps table.insert @steps, false while steps < #@steps table.remove @steps - @mask = launch\attach { status: 'note-on', chan: @chan }, (_, _, note, _) -> @toggle note + for i=1, steps + @display i + + @mask = launch\attach { status: 'note-on', chan: @chan }, (_, _, note, _) -> + @toggle note + + @out toggle: (note) => i = note - @start val = @steps[i+1] if val != nil @steps[i+1] = not val - curr_i = (@i\get 'num') % #@steps - launch\send 'note-on', @chan, note, light @steps[i+1], i == curr_i + curr_i = (@i\unwrap 'num') % #@steps + @display i, i == curr_i + + display: (i, active) => + launch\send 'note-on', @chan, (@start + i), light @steps[i+1], active light = (set, active) -> set = if set then 'S' else ' ' active = if active then 'A' else ' ' color switch set .. active when ' ' then 0, 0 - when ' A' then 1, 0 - when 'S ' then 0, 1 - when 'SA' then 0, 3 + when ' A' then 1, 1 + when 'S ' then 1, 0 + when 'SA' then 3, 1 update: (dt) => launch\tick! - @i\update dt - curr_i = (@i\get 'num') % #@steps + curr_i = (@i\unwrap 'num') % #@steps prev_i = (curr_i - 1) % #@steps - launch\send 'note-on', @chan, (@start + curr_i), light @steps[curr_i+1], true - launch\send 'note-on', @chan, (@start + prev_i), light @steps[prev_i+1], false + @display curr_i, true + @display prev_i, false - @value = @steps[curr_i+1] + @out\set @steps[curr_i+1] { 'gate-seq': gate_seq + 'cc-seq': cc_seq } diff --git a/lib/osc.moon b/lib/osc.moon index dae6737..fed1697 100644 --- a/lib/osc.moon +++ b/lib/osc.moon @@ -1,4 +1,4 @@ -import Const, Op, FnDef from require 'core' +import Stream, Op from require 'core' import pack, unpack from require 'osc' import dns, udp from require 'socket' @@ -13,12 +13,9 @@ class out extends Op setup: (@host, @port, @path, @value) => update: (dt) => - for p in *{@host, @port, @path, @value} - L\push p\update, dt - - ip = dns.toip @host\get! - port = @port\get! - msg = pack @path\get!, @value\get! + ip = dns.toip @host\unwrap 'str' + port = @port\unwrap 'num' + msg = pack (@path\unwrap 'str'), @value\unwrap! @@udp\sendto msg, ip, port { diff --git a/lib/pilot.moon b/lib/pilot.moon index 1cbc070..2a7d21a 100644 --- a/lib/pilot.moon +++ b/lib/pilot.moon @@ -1,5 +1,5 @@ -import Const, Op, FnDef from require 'core' -import dns, udp from require 'socket' +import Op from require 'core' +import udp from require 'socket' conn = udp! hex = "0123456789abcdef" @@ -18,17 +18,12 @@ send = (tbl) -> class play extends Op @doc: "(play trig ch oct note [vel [len]]) - play a note when trig is live" - setup: (@trig, @ch, @oct, @note, @vel, @len) => + setup: (@trig, ...) => + @vals = { ... } update: (dt) => - vals = for c in *{@trig, @ch, @oct, @note, @vel, @len } - c\update dt - c\get! - - trig = table.remove vals, 1 - - if trig - send vals + if @trig\unwrap 'bool' + send [c\unwrap! for c in *@vals] class effect extends Op @doc: "(effect which a b) - set an effect @@ -38,10 +33,7 @@ which is one of 'DIS', 'CHO', 'REV' or 'FEE'" setup: (@which, @a, @b) => update: (dt) => - @which\update dt - @a\update dt - @b\update dt - which, a, b = @which\get!, @a\get!, @b\get! + which, a, b = (@which\unwrap 'str'), @a\unwrap!, @b\unwrap! if which and a and b send { which, a, b } { diff --git a/lib/string.moon b/lib/string.moon index 82e9702..6a9b7d7 100644 --- a/lib/string.moon +++ b/lib/string.moon @@ -1,4 +1,4 @@ -import Op from require 'core' +import Stream, Op from require 'core' class str extends Op @doc: "(str v1 [v2]...) @@ -6,12 +6,11 @@ class str extends Op setup: (...) => @children = { ... } + @out = Stream 'str' + @out update: (dt) => - for child in *@children - child\update dt - - @value = table.concat [tostring child\get! for child in *@children] + @out\set table.concat [tostring child\unwrap! for child in *@children] { :str, '..': str diff --git a/lib/time.moon b/lib/time.moon index 89f947e..7ce8b84 100644 --- a/lib/time.moon +++ b/lib/time.moon @@ -1,4 +1,4 @@ -import Const, Op from require 'core' +import Stream, Const, Op from require 'core' class lfo extends Op @doc: "(lfo freq [wave]) - low-frequency oscillator @@ -12,19 +12,19 @@ wave selects the wave shape from the following (default sin): tau = math.pi * 2 new: (...) => super ... + print "creating LFO" + @out = Stream 'num' @phase = 0 default_wave = Const 'str', 'sin' setup: (@freq, @wave=default_wave) => assert @freq, "lfo requires a frequency value" L\trace "setup #{@}, freq=#{@freq}, wave=#{@wave}" + @out update: (dt) => - @freq\update dt - @wave\update dt - - @phase += dt * @freq\get! - @value = switch @wave\get! + @phase += dt * @freq\unwrap 'num' + @out\set switch @wave\unwrap! when 'sin' then .5 + .5 * math.cos @phase * tau when 'saw' then @phase % 1 when 'tri' then math.abs (2*@phase % 2) - 1 @@ -37,45 +37,64 @@ ramps from 0 to max (default same as ramp) once every period seconds" new: (...) => super ... + @out = Stream 'num' @phase = 0 + @out setup: (@period, @max) => assert @period, "tick requires a period value" update: (dt) => - @period\update dt - max = if @max - @max\update dt - @max\get! - else - @period\get! - - @phase += dt / @period\get! + period = @period\unwrap 'num' + max = if @max then @max\unwrap! else period + @phase += dt / period if @phase >= 1 @phase -= 1 - @value = @phase * max + @out\set @phase * max class tick extends Op @doc: "(tick period) - count ticks -counts upwards every period seconds and returns the number of completed ticks." +counts upwards by one every period seconds and returns the number of completed ticks." new: (...) => super ... + @out = Stream 'num' @phase = 0 setup: (@period) => assert @period, "tick requires a period value" + @out update: (dt) => - @period\update dt + @phase += dt / @period\unwrap 'num' + @out\set math.floor @phase + +class every extends Op + @doc: "(every period) - sometimes true - @phase += dt / @period\get! - @value = math.floor @phase +returns true once every period seconds." + new: (...) => + super ... + @out = Stream 'bool' + @phase = 0 + + setup: (@period) => + assert @period, "every requires a period value" + @out + + update: (dt) => + @phase += dt / @period\unwrap 'num' + if @phase > 1 + @phase -= 1 + @out\set true + else + @out\set false { :lfo :ramp :tick + :every } diff --git a/lib/util.moon b/lib/util.moon index af5d8f8..192c489 100644 --- a/lib/util.moon +++ b/lib/util.moon @@ -1,4 +1,4 @@ -import Const, Op from require 'core' +import Stream, Const, Op from require 'core' class switch_ extends Op @doc: "(switch i v0 [v1 v2...]) - switch between multiple inputs @@ -10,14 +10,16 @@ when i is a num, it is (floor)ed and the matching argument (starting from 0) is setup: (@i, ...) => @choices = { ... } - update: (dt) => - @i\update dt - i = @i\get! + typ = @choices[1].type + for inp in *@choices[2,] + assert inp.type == typ, "not all values have the same type: #{typ} != #{inp.type}" - for choice in *@choices - choice\update dt + @out = Stream typ + @out - active = switch @i\get! + update: (dt) => + i = @i\unwrap! + active = switch i when true @choices[1] when false @@ -25,7 +27,7 @@ when i is a num, it is (floor)ed and the matching argument (starting from 0) is else i = 1 + (math.floor i) % #@choices @choices[i] - @value = active and active\get! + @out\set active and active\unwrap! class switch_pause extends Op @doc: "(switch- i v0 [v1 v2...]) - switch and pause multiple inputs @@ -35,10 +37,16 @@ like (switch ...) except that the unused inputs are paused." setup: (@i, ...) => @choices = { ... } + typ = @choices[1].type + for inp in *@choices[2,] + assert inp.type == typ, "not all values have the same type: #{typ} != #{inp.type}" + + @out = Stream typ + @out + update: (dt) => - @i\update dt - i = @i\get! - active = switch @i\get! + i = @i\unwrap! + active = switch i when true @choices[1] when false @@ -47,21 +55,18 @@ like (switch ...) except that the unused inputs are paused." i = 1 + (math.floor i) % #@choices @choices[i] - @value = if active - active\update dt - active\get! + @out\set if active + active\unwrap! class edge extends Op setup: (@i) => - @value = false @last = false + @out = Stream @i.type + @out update: (dt) => - @i\update dt - - now = @i\get! - - @value = not @last and now + now = @i\unwrap! + @out\set not @last and now @last = now class keep extends Op @@ -71,12 +76,12 @@ always reproduces the last non-nil value the input produced or default. default defaults to zero." setup: (@i, @default=Const.num 0) => + @out = Stream @i.type, @default.value + @out update: (dt) => - @i\update dt - - next = @i\get! - @value = next or @value or @default\get! + if next = @i\unwrap! + @out\set next { 'switch': switch_ |
