aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authors-ol <s-ol@users.noreply.github.com>2020-02-23 22:16:25 +0000
committers-ol <s-ol@users.noreply.github.com>2020-02-28 12:22:25 +0000
commit0b284ac60916142cadb8b65fa5ca9f9cffcfc200 (patch)
tree07fc75330d813d54751f42a2f55b979398929814
parentmerge Const and Stream into Value; Dataflow logic (diff)
downloadalive-0b284ac60916142cadb8b65fa5ca9f9cffcfc200.tar.gz
alive-0b284ac60916142cadb8b65fa5ca9f9cffcfc200.zip
lots of fixes
-rw-r--r--core/base.moon4
-rw-r--r--core/builtin.moon4
-rw-r--r--core/invoke.moon4
-rw-r--r--core/parsing.moon2
-rw-r--r--core/value.moon1
-rw-r--r--lib/math.moon44
-rw-r--r--lib/midi/init.moon4
-rw-r--r--lib/midi/launchctl.moon101
-rw-r--r--lib/osc.moon7
-rw-r--r--lib/sc.moon37
-rw-r--r--lib/time.moon16
-rw-r--r--lib/util.moon12
12 files changed, 141 insertions, 95 deletions
diff --git a/core/base.moon b/core/base.moon
index 60ee460..422e631 100644
--- a/core/base.moon
+++ b/core/base.moon
@@ -34,6 +34,10 @@ class Op
assert_types: (...) =>
num = select '#', ...
assert #@inputs >= num, "argument count mismatch"
+ @assert_first_types ...
+
+ assert_first_types: (...) =>
+ num = select '#', ...
for i = 1, num
expect = select i, ...
assert @inputs[i].type == expect, "expected argument #{i} of #{@} to be of type #{expect} but found #{@inputs[i]}"
diff --git a/core/builtin.moon b/core/builtin.moon
index 6abcbd9..5dd296a 100644
--- a/core/builtin.moon
+++ b/core/builtin.moon
@@ -12,9 +12,9 @@ prints the docstring for sym in the console"
eval: (scope, tail) =>
assert #tail == 1, "'doc' takes exactly one parameter"
- def = L\push tail[1]\eval, scope
+ result = L\push tail[1]\eval, scope
with Result children: { def }
- def = def.value\const!\unwrap!
+ def = result\const!\unwrap!
L\print "(doc #{tail[1]\stringify!}):\n#{def.doc}\n"
class def extends Action
diff --git a/core/invoke.moon b/core/invoke.moon
index a3932f8..da82d00 100644
--- a/core/invoke.moon
+++ b/core/invoke.moon
@@ -10,13 +10,15 @@ class op_invoke extends Action
def = head\unwrap 'opdef', "cant op-invoke #{@head}"
@head, @op = head, def!
+ @first = true
true
eval: (scope, tail) =>
children = L\push -> [L\push expr\eval, scope for expr in *tail]
@op\setup [child.value for child in *children]
- @op\tick true
+ @op\tick @first
+ @first = nil
Result :children, value: @op.out, op: @op
diff --git a/core/parsing.moon b/core/parsing.moon
index 03ef85c..0123469 100644
--- a/core/parsing.moon
+++ b/core/parsing.moon
@@ -24,7 +24,7 @@ str = strd + strq
int = digit^1
float = (digit^1 * '.' * digit^0) + (digit^0 * '.' * digit^1)
-num = (float + int) / Value\parse 'num'
+num = ((P '-')^-1 * (float + int)) / Value\parse 'num'
atom = num + sym + str
diff --git a/core/value.moon b/core/value.moon
index 986c846..6fbda65 100644
--- a/core/value.moon
+++ b/core/value.moon
@@ -98,6 +98,7 @@ class Value
-- @value - Lua value - access through :unwrap()
new: (@type, @value, @raw) =>
@updated = 0
+ pcall @\set, @value
dirty: => @updated == Registry.active!.tick
diff --git a/lib/math.moon b/lib/math.moon
index 68dae3a..ca965be 100644
--- a/lib/math.moon
+++ b/lib/math.moon
@@ -1,23 +1,21 @@
-import Stream, Op, Const from require 'core'
+import Op, Value from require 'core'
unpack or= table.unpack
class BinOp extends Op
- new: (...) =>
- super ...
- @out = Stream 'num', 0
+ new: =>
+ super 'num', 0
- setup: (...) =>
- @children = { ... }
- assert #@children >= 2, "#{@} needs at least two parameters"
- @out
+ setup: (params) =>
+ super params
+ assert #@inputs >= 2, "#{@} needs at least two parameters"
class add extends BinOp
@doc: "(+ a b [c]...)
(add a b [c]...) - add values"
- update: (dt) =>
+ tick: =>
value = 0
- for child in *@children
+ for child in *@inputs
value += child\unwrap 'num'
@out\set value
@@ -27,9 +25,9 @@ class sub extends BinOp
subtracts all other arguments from a"
- update: (dt) =>
- value = @children[1]\unwrap 'num'
- for child in *@children[2,]
+ tick: =>
+ value = @inputs[1]\unwrap 'num'
+ for child in *@inputs[2,]
value -= child\unwrap 'num'
@out\set value
@@ -37,9 +35,9 @@ class mul extends BinOp
@doc: "(* a b [c]...)
(mul a b [c]...) - multiply values"
- update: (dt) =>
+ tick: =>
value = 1
- for child in *@children
+ for child in *@inputs
value *= child\unwrap 'num'
@out\set value
@@ -49,9 +47,9 @@ class div extends BinOp
divides a by all other arguments"
- update: (dt) =>
- value = @children[1]\unwrap 'num'
- for child in *@children[2,]
+ tick: =>
+ value = @inputs[1]\unwrap 'num'
+ for child in *@inputs[2,]
value /= child\unwrap 'num'
@out\set value
@@ -61,7 +59,7 @@ evenodd_op = (name, remainder) ->
@out = Stream 'bool'
@out
- update: (dt) =>
+ tick: =>
a, divi = (@a\unwrap 'num'), @div\unwrap 'num'
@out\set (a % divi) == remainder
@@ -73,15 +71,15 @@ div defaults to 2"
func_op = (name, arity, func) ->
k = class extends Op
+ new: =>
+ super 'num'
+
setup: (...) =>
@params = { ... }
if arity != '*'
assert #@params == arity, "#{@} needs exactly #{arity} parameters"
- @out = Stream 'num'
- @out
-
- update: (dt) =>
+ tick: =>
@out\set func unpack [p\unwrap 'num' for p in *@params]
k.__name = name
diff --git a/lib/midi/init.moon b/lib/midi/init.moon
index 03f5115..b0f2f6a 100644
--- a/lib/midi/init.moon
+++ b/lib/midi/init.moon
@@ -44,7 +44,9 @@ range can be one of:
super params
@inputs[3] or= Value.num -1
@inputs[4] or= Value.str 'uni'
- @assert_types 'midi/port', 'num', 'num', 'str'
+ assert #@inputs == 4
+ assert @inputs[4].type == 'num' or @inputs[4].type == 'str'
+ @assert_types 'midi/port', 'num', 'num'
@impulses = { @inputs[1]\unwrap! }
if not @out\unwrap!
diff --git a/lib/midi/launchctl.moon b/lib/midi/launchctl.moon
index c0d5e24..aab20bd 100644
--- a/lib/midi/launchctl.moon
+++ b/lib/midi/launchctl.moon
@@ -27,28 +27,36 @@ range can be one of:
@inputs[5] or= Value.num 8
@inputs[6] or= Value.str 'uni'
- @assert_types 'midi/port', 'num', 'num', 'num', 'num', 'str'
+ assert #@inputs == 6
+ assert @inputs[6].type == 'num' or @inputs[6].type == 'str'
+ @assert_first_types 'midi/port', 'num', 'num', 'num', 'num'
@impulses = { @inputs[1]\unwrap! }
if not @out\unwrap!
@out\set apply_range @inputs[6], 0
- tick: =>
- port, i, start, chan, steps = unpack [i\unwrap! for i in *@inputs]
+ tick: (first) =>
port = @inputs[1]\unwrap!
_, i, start, chan, steps = unpack @inputs
+ if first or @inputs[5]\dirty!
+ steps = @inputs[5]!
+ while steps > #@steps
+ table.insert @steps, 0
+ while steps < #@steps
+ table.remove @steps
+
curr_i = i\unwrap! % #@steps
changed = false
for msg in port\receive!
- if msg.status == 'control-change' and msg.chan == chan
- i = msg.a - start
- if i < #@steps
- @steps[i+1] = msg.b
- changed = i == curr_i
+ if msg.status == 'control-change' and msg.chan == chan!
+ rel_i = msg.a - start!
+ if rel_i >= 0 and rel_i < #@steps
+ @steps[rel_i+1] = msg.b
+ changed = rel_i == curr_i
- if changed or i\dirty! or start\dirty! or chan\dirty! or steps\diry!
+ if changed or i\dirty! or start\dirty! or chan\dirty! or steps\dirty!
@out\set apply_range @inputs[6], @steps[curr_i+1]
class gate_seq extends Op
@@ -57,46 +65,17 @@ class gate_seq extends Op
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: =>
+ super 'bool', false
@steps = {}
- @out = Stream 'bool'
-
- setup: (@i, start, chan, steps=(Const.num 8)) =>
- launch\detach @mask if @mask
-
- 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
-
- 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\unwrap 'num') % #@steps
- @display i, i == curr_i
+ setup: (params) =>
+ super params
- display: (i, active) =>
- launch\send 'note-on', @chan, (@start + i), light @steps[i+1], active
+ @inputs[5] or= Value.num 8
+ @inputs[6] or= Value.str 'uni'
+ @assert_types 'midi/port', 'num', 'num', 'num', 'num', 'str'
+ @impulses = { @inputs[1]\unwrap! }
light = (set, active) ->
set = if set then 'S' else ' '
@@ -106,17 +85,35 @@ steps defaults to 8."
when ' A' then 1, 1
when 'S ' then 1, 0
when 'SA' then 3, 1
+ display: (i, active) =>
+ port, _, start, chan = @unwrap_inputs!
+ port\send 'note-on', chan, (start + i), light @steps[i+1], active
+
+ tick: (first) =>
+ port, curr_i, start, chan, steps = @unwrap_inputs!
+
+ if first or @inputs[5]\dirty!
+ while steps > #@steps
+ table.insert @steps, false
+ while steps < #@steps
+ table.remove @steps
- update: (dt) =>
- launch\tick!
+ curr_i = curr_i % #@steps
+
+ for msg in port\receive!
+ if msg.status == 'note-on' and msg.chan == chan
+ rel_i = msg.a - start
+ if rel_i >= 0 and rel_i < #@steps
+ @steps[rel_i+1] = not @steps[rel_i+1]
+ @display rel_i, rel_i == curr_i
- curr_i = (@i\unwrap 'num') % #@steps
- prev_i = (curr_i - 1) % #@steps
+ if @inputs[2]\dirty!
+ prev_i = (curr_i - 1) % #@steps
- @display curr_i, true
- @display prev_i, false
+ @display curr_i, true
+ @display prev_i, false
- @out\set @steps[curr_i+1]
+ @out\set @steps[curr_i+1]
{
'gate-seq': gate_seq
diff --git a/lib/osc.moon b/lib/osc.moon
index 3bac3f1..bced72f 100644
--- a/lib/osc.moon
+++ b/lib/osc.moon
@@ -1,4 +1,4 @@
-import Stream, Op from require 'core'
+import Op from require 'core'
import pack, unpack from require 'osc'
import dns, udp from require 'socket'
@@ -19,7 +19,7 @@ class addr extends Op
@out\set { :ip, :port }
class out extends Op
- @doc: "(out host port path val) - send a value via OSC"
+ @doc: "(out remote path val) - send a value via OSC"
new: (...) =>
@@udp or= udp!
@@ -29,8 +29,9 @@ class out extends Op
assert @inputs[3], "need a value"
@assert_types 'udp/remote', 'str', @inputs[3].type
- update: (dt) =>
+ tick: =>
remote, path, value = @unwrap_inputs!
+ { :ip, :port } = remote
msg = pack path, value
@@udp\sendto msg, ip, port
diff --git a/lib/sc.moon b/lib/sc.moon
new file mode 100644
index 0000000..7ffd16c
--- /dev/null
+++ b/lib/sc.moon
@@ -0,0 +1,37 @@
+import Op, Value, Scope from require 'core'
+import pack from require 'osc'
+import dns, udp from require 'socket'
+
+class play extends Op
+ @doc: "(sc/play remote synth trigger [name-str val]...) - play a SC SynthDef"
+
+ new: =>
+ super!
+ @@udp or= udp!
+
+ setup: (params) =>
+ super params
+ @assert_first_types 'udp/remote', 'str', 'bool'
+
+ assert #@inputs % 2 == 1, "parameters need to be specified as pairs"
+ for key in *@inputs[4,,2]
+ assert key.type == 'str', "ony strings are supported as control names"
+ for val in *@inputs[5,,2]
+ assert val.type == 'num', "only numbers are supported as control values"
+
+ tick: =>
+ { remote, synth, trig, p } = @inputs
+
+ if trig\dirty! and trig!
+ controls = {}
+ for i = 4, #@inputs, 2
+ table.insert controls, @inputs[i]!
+ table.insert controls, @inputs[i+1]!
+ msg = pack '/s_new', synth!, -1, 0, 1, unpack controls
+
+ { :ip, :port } = remote!
+ @@udp\sendto msg, ip, port
+
+{
+ :play
+}
diff --git a/lib/time.moon b/lib/time.moon
index c49a7d7..a726af3 100644
--- a/lib/time.moon
+++ b/lib/time.moon
@@ -87,19 +87,22 @@ class tick extends Op
counts upwards by one every period seconds and returns the number of completed ticks."
new: =>
- super 'num'
+ super 'num', 0
@phase = 0
setup: (params) =>
+ super params
@assert_types 'num', 'num'
- update: (dt) =>
+ tick: (first) =>
-- if clock is dirty
- if @inputs[1].dirty
+ if first or @inputs[1].dirty
dt, period = @unwrap_inputs!
@phase += dt / period
- @out\set math.floor @phase
+ next_num = math.floor @phase
+ if next_num != @.out!
+ @out\set next_num
class every extends Op
@doc: "(every clock period) - trigger every period seconds
@@ -110,11 +113,12 @@ returns true once every period seconds."
@phase = 0
setup: (@period) =>
+ super params
@assert_types 'num', 'num'
- update: (dt) =>
+ tick: (first) =>
-- if clock is dirty
- if @inputs[1].dirty
+ if first or @inputs[1].dirty
dt, period = @unwrap_inputs!
@phase += dt / period
diff --git a/lib/util.moon b/lib/util.moon
index 04d012f..747cb0d 100644
--- a/lib/util.moon
+++ b/lib/util.moon
@@ -1,4 +1,4 @@
-import Op from require 'core'
+import Value, Op from require 'core'
class switch_ extends Op
@doc: "(switch i v0 [v1 v2...]) - switch between multiple inputs
@@ -15,9 +15,9 @@ when i is a num, it is (floor)ed and the matching argument (starting from 0) is
for inp in *@inputs[3,]
assert inp.type == first.type, "not all values have the same type: #{first.type} != #{inp.type}"
- @out = Stream first.type
+ @out = Value first.type, first!
- update: (dt) =>
+ tick: =>
i = @inputs[1]\unwrap!
active = switch i
when true
@@ -44,7 +44,7 @@ when i is a num, it is (floor)ed and the matching argument (starting from 0) is
-- @out = Stream typ
-- @out
--
--- update: (dt) =>
+-- tick: =>
-- i = @i\unwrap!
-- active = switch i
-- when true
@@ -68,7 +68,7 @@ class edge extends Op
super params
@assert_types 'bool'
- update: (dt) =>
+ tick: =>
now = @params[1]\unwrap!
if now and not @last
@out\set true
@@ -85,7 +85,7 @@ default defaults to zero."
{ i, init } = @inputs
@out = Value i.type, default and init\unwrap!
- tick =>
+ tick: =>
if next = @params[1]\unwrap!
@out\set next