aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authors-ol <s-ol@users.noreply.github.com>2020-04-14 09:21:00 +0000
committers-ol <s-ol@users.noreply.github.com>2020-04-14 09:21:00 +0000
commit5faab5d81cc5ed36824a52a273e83eb20240cb2e (patch)
treedba10fadf4cdad0f5524df642fab83f6310a8574 /lib
parentmove spec out of spec/core (diff)
downloadalive-5faab5d81cc5ed36824a52a273e83eb20240cb2e.tar.gz
alive-5faab5d81cc5ed36824a52a273e83eb20240cb2e.zip
move lib to alv-lib module
Diffstat (limited to 'lib')
-rw-r--r--lib/logic.moon153
-rw-r--r--lib/math.moon192
-rw-r--r--lib/midi.moon99
-rw-r--r--lib/midi/core.moon122
-rw-r--r--lib/midi/launchctl.moon194
-rw-r--r--lib/osc.moon87
-rw-r--r--lib/pilot.moon90
-rw-r--r--lib/random.moon85
-rw-r--r--lib/sc.moon83
-rw-r--r--lib/string.moon18
-rw-r--r--lib/time.moon285
-rw-r--r--lib/util.moon112
12 files changed, 0 insertions, 1520 deletions
diff --git a/lib/logic.moon b/lib/logic.moon
deleted file mode 100644
index 62de1c1..0000000
--- a/lib/logic.moon
+++ /dev/null
@@ -1,153 +0,0 @@
-import Op, ValueStream, Input, Error, val from require 'alv.base'
-
-all_same = (first, list) ->
- for v in *list
- if v != first
- return false
-
- first
-
-tobool = (val) ->
- switch val
- when false, nil, 0
- false
- else
- true
-
-class ReduceOp extends Op
- pattern = val! + val! * 0
- setup: (inputs) =>
- @out or= ValueStream 'bool'
- { first, rest } = pattern\match inputs
- super
- first: Input.hot first
- rest: [Input.hot v for v in *rest]
-
- tick: =>
- { :first, :rest } = @unwrap_all!
- accum = tobool first
- for val in *rest
- accum = @.fn accum, tobool val
-
- @out\set accum
-
-eq = ValueStream.meta
- meta:
- name: 'eq'
- summary: "Check for equality."
- examples: { '(== a b [c]…)', '(eq a b [c]…)' }
- description: "`true` if the types and values of all arguments are equal."
-
- value: class extends Op
- pattern = val! + val! * 0
- setup: (inputs) =>
- @out or= ValueStream 'bool', false
- { first, rest } = pattern\match inputs
- same = all_same first\type!, [i\type! for i in *rest]
-
- super if same
- {
- first: Input.hot first
- rest: [Input.hot v for v in *rest]
- }
- else
- {}
-
- tick: =>
- if not @inputs.first
- @out\set false
- return
-
- { :first, :rest } = @unwrap_all!
-
- equal = true
- for other in *rest
- if first != other
- equal = false
- break
-
- @out\set equal
-
-not_eq = ValueStream.meta
- meta:
- name: 'not-eq'
- summary: "Check for inequality."
- examples: { '(!= a b [c]…)', '(not-eq a b [c]…)' }
- description: "`true` if types or values of any two arguments are different."
-
- value: class extends Op
- setup: (inputs) =>
- @out or= ValueStream 'bool', false
- assert #inputs > 1, Error 'argument', "need at least two values"
- super [Input.hot v for v in *inputs]
-
- tick: =>
- if not @inputs[1]
- @out\set true
- return
-
- diff = true
- for a=1, #@inputs-1
- for b=a+1, #@inputs
- if @inputs[a].stream == @inputs[b].stream
- diff = false
- break
-
- break unless diff
-
- @out\set diff
-
-and_ = ValueStream.meta
- meta:
- name: 'and'
- summary: "Logical AND."
- examples: { '(and a b [c…])' }
- value: class extends ReduceOp
- fn: (a, b) -> a and b
-
-or_ = ValueStream.meta
- meta:
- name: 'or'
- summary: "Logical OR."
- examples: { '(or a b [c…])' }
- value: class extends ReduceOp
- fn: (a, b) -> a or b
-
-not_ = ValueStream.meta
- meta:
- name: 'not'
- summary: "Logical NOT."
- examples: { '(not a)' }
-
- value: class extends Op
- new: => super 'bool'
-
- setup: (inputs) =>
- { value } = match 'any', inputs
- super value: Input.hot value
-
- tick: => @out\set not tobool @inputs.value!
-
-bool = ValueStream.meta
- meta:
- name: 'bool'
- summary: "Cast value to bool."
- examples: { '(bool a)' }
- description: "`false` if a is `false`, `nil` or `0`, `true` otherwise."
-
- value: class extends Op
- setup: (inputs) =>
- @out or= ValueStream 'bool'
- { value } = val!\match inputs
- super value: Input.hot value
-
- tick: => @out\set tobool @inputs\value!
-
-{
- :eq, '==': eq
- 'not-eq': not_eq, '!=': not_eq
- and: and_
- or: or_
- not: not_
- :bool
-}
diff --git a/lib/math.moon b/lib/math.moon
deleted file mode 100644
index 6f5f3fb..0000000
--- a/lib/math.moon
+++ /dev/null
@@ -1,192 +0,0 @@
-import Op, ValueStream, Error, Input, val from require 'alv.base'
-unpack or= table.unpack
-
-class ReduceOp extends Op
- pattern = val.num + val.num*0
- setup: (inputs) =>
- @out or= ValueStream 'num'
- { first, rest } = pattern\match inputs
- super
- first: Input.hot first
- rest: [Input.hot v for v in *rest]
-
- tick: =>
- { :first, :rest } = @unwrap_all!
- accum = first
- for val in *rest
- accum = @.fn accum, val
- @out\set accum
-
-func_op = (func, pattern) ->
- class extends Op
-
- setup: (inputs) =>
- @out or= ValueStream 'num'
- params = pattern\match inputs
- super [Input.hot p for p in *params]
-
- tick: => @out\set func unpack @unwrap_all!
-
-func_def = (name, args, func, summary, pattern) ->
- ValueStream.meta
- meta:
- :name
- :summary
- examples: { "(#{name} #{args})" }
- value: func_op func, pattern or val.num\rep 1, 1
-
-evenodd_op = (remainder) ->
- class extends Op
- pattern = val.num + -val.num
- setup: (inputs) =>
- @out or= ValueStream 'bool'
- { val, div } = pattern\match inputs
- super
- val: Input.hot val
- div: Input.hot div or ValueStream.num 2
-
- tick: =>
- { :val, :div } = @unwrap_all!
- @out\set (val % div) == remainder
-
-add = ValueStream.meta
- meta:
- name: 'add'
- summary: "Add values."
- examples: { '(+ a b [c…])', '(add a b [c…])' }
- description: "Sum all arguments."
- value: class extends ReduceOp
- fn: (a, b) -> a + b
-
-sub = ValueStream.meta
- meta:
- name: 'sub'
- summary: "Subtract values."
- examples: { '(- a b [c…])', '(sub a b [c…])' }
- description: "Subtract all other arguments from `a`."
- value: class extends ReduceOp
- fn: (a, b) -> a - b
-
-mul = ValueStream.meta
- meta:
- name: 'mul'
- summary: "Multiply values."
- examples: { '(* a b [c…])', '(mul a b [c…])' }
- value: class extends ReduceOp
- fn: (a, b) -> a * b
-
-div = ValueStream.meta
- meta:
- name: 'div'
- summary: "Divide values."
- examples: { '(/ a b [c…])', '(div a b [c…])' }
- description: "Divide `a` by all other arguments."
- value: class extends ReduceOp
- fn: (a, b) -> a / b
-
-pow = ValueStream.meta
- meta:
- name: 'pow'
- summary: "Raise to a power."
- examples: { '(^ base exp)', '(pow base exp' }
- description: "Raise `base` to the power `exp`."
- value: class extends ReduceOp
- fn: (a, b) -> a ^ b
-
-mod = ValueStream.meta
- meta:
- name: 'mod'
- summary: 'Modulo operator.'
- examples: { '(% num div)', '(mod num div)' }
- description: "Calculate remainder of division by `div`."
- value: func_op 2, (a, b) -> a % b
-
-even = ValueStream.meta
- meta:
- name: 'even'
- summary: 'Check whether val is even.'
- examples: { '(even val [div])' }
- description: "`true` if dividing `val` by `div` has remainder zero.
-`div` defaults to 2."
- value: evenodd_op 0
-
-odd = ValueStream.meta
- meta:
- name: 'odd'
- summary: 'Check whether val is odd.'
- examples: { '(odd val [div])' }
- description: "`true` if dividing `val` by `div` has remainder one.
-`div` defaults to 2."
- value: evenodd_op 1
-
-mix = ValueStream.meta
- meta:
- name: 'mix'
- summary: 'Linearly interpolate.'
- examples: { '(mix a b i)' }
- description: "Interpolate between `a` and `b` using `i` in range 0-1."
- value: func_op 3, (a, b, i) -> i*b + (1-i)*a
-
-min = ValueStream.meta
- meta:
- name: 'min'
- summary: "Find the minimum."
- examples: { '(min a b [c…])' }
- description: "Return the lowest of arguments."
- value: func_op '*', math.min
-
-max = ValueStream.meta
- meta:
- name: 'max'
- summary: "Find the maximum."
- examples: { '(max a b [c…])' }
- description: "Return the highest of arguments."
- value: func_op '*', math.min
-
-cos = func_def 'cos', 'alpha', math.cos, "Cosine function (radians)."
-sin = func_def 'sin', 'alpha', math.sin, "Sine function (radians)."
-tan = func_def 'tan', 'alpha', math.tan, "Tangent function (radians)."
-acos = func_def 'acos', 'cos', math.acos, "Inverse cosine function (radians)."
-asin = func_def 'asin', 'sin', math.asin, "Inverse sine function (radians)."
-atan = func_def 'atan', 'tan', math.atan, "Inverse tangent function (radians)."
-atan2 = func_def 'atan2', 'y x', math.atan2, "Inverse tangent function (two argument version).", val.num\rep(2, 2)
-cosh = func_def 'cosh', 'alpha', math.cosh, "Hyperbolic cosine function (radians)."
-sinh = func_def 'sinh', 'alpha', math.sinh, "Hyperbolic sine function (radians)."
-tanh = func_def 'tanh', 'alpha', math.tanh, "Hyperbolic tangent function (radians)."
-
-floor = func_def 'floor', 'val', math.floor, "Round towards negative infinity."
-ceil = func_def 'ceil', 'val', math.ceil, "Round towards positive infinity."
-abs = func_def 'abs', 'val', math.abs, "Get the absolute value."
-
-exp = func_def 'exp', 'exp', math.floor, "*e* number raised to a power."
-log = func_def 'log', 'val [base]', math.log, "Logarithm with given base.", val.num*2
-log10 = func_def 'log10', 'val', math.log10, "Logarithm with base 10."
-sqrt = func_def 'sqrt', 'val', math.sqrt, "Square root function."
-
-{
- :add, '+': add
- :sub, '-': sub
- :mul, '*': mul
- :div, '/': div
- :pow, '^': pow
- :mod, '%': mod
-
- :even, :odd
-
- :mix
- :min, :max
-
- pi: with ValueStream.wrap math.pi
- .meta = summary: 'The pi constant.'
- tau: with ValueStream.wrap math.pi*2
- .meta = summary: 'The tau constant.'
- huge: with ValueStream.wrap math.huge
- .meta = summary: 'Positive infinity constant.'
-
- :sin, :cos, :tan
- :asin, :acos, :atan, :atan2
- :sinh, :cosh, :tanh
-
- :floor, :ceil, :abs
- :exp, :log, :log10, :sqrt
-}
diff --git a/lib/midi.moon b/lib/midi.moon
deleted file mode 100644
index e83b05d..0000000
--- a/lib/midi.moon
+++ /dev/null
@@ -1,99 +0,0 @@
-import ValueStream, EventStream, Op, Input, val, evt from require 'alv.base'
-import input, output, inout, apply_range from require 'lib.midi.core'
-
-gate = ValueStream.meta
- meta:
- name: 'gate'
- summary: "gate from note-on and note-off messages."
- examples: { '(midi/gate [port] note [chan])' }
-
- value: class extends Op
- pattern = -evt['midi/port'] + val.num -val.num
- setup: (inputs, scope) =>
- @out or= ValueStream 'bool'
- { port, note, chan } = pattern\match inputs
- super
- port: Input.hot port or scope\get '*midi*'
- note: Input.hot note
- chan: Input.hot chan or ValueStream.num -1
-
- tick: =>
- { :port, :note, :chan } = @inputs
-
- if note\dirty! or chan\dirty!
- @out\set false
-
- if port\dirty!
- for msg in *port!
- if msg.a == note! and (chan! == -1 or msg.chan == chan!)
- if msg.status == 'note-on'
- @out\set true
- elseif msg.status == 'note-off'
- @out\set false
-
-trig = ValueStream.meta
- meta:
- name: 'trig'
- summary: "`bang`s from note-on messages."
- examples: { '(midi/trig [port] note [chan])' }
-
- value: class extends Op
- pattern = -evt['midi/port'] + val.num -val.num
- setup: (inputs, scope) =>
- @out or= EventStream 'bang'
- { port, note, chan } = pattern\match inputs
- super
- port: Input.hot port or scope\get '*midi*'
- note: Input.cold note
- chan: Input.cold chan or ValueStream.num -1
-
- tick: =>
- { :port, :note, :chan } = @inputs
-
- for msg in *port!
- if msg.a == note! and (chan! == -1 or msg.chan == chan!)
- if msg.status == 'note-on'
- @out\add true
-
-cc = ValueStream.meta
- meta:
- name: 'cc'
- summary: "`num` from cc-change messages."
- examples: { '(midi/cc [port] cc [chan [range]])' }
- description: "
-`range` can be one of:
-- 'raw' [ 0 - 128[
-- 'uni' [ 0 - 1[ (default)
-- 'bip' [-1 - 1[
-- 'rad' [ 0 - tau[
-- 'deg' [ 0 - 360[
-- (num) [ 0 - num["
-
- value: class extends Op
- pattern = -evt['midi/port'] + val.num + -val.num + -val.num
- setup: (inputs, scope) =>
- { port, cc, chan, range } = pattern\match inputs
- super
- port: Input.hot port or scope\get '*midi*'
- cc: Input.cold cc
- chan: Input.cold chan or ValueStream.num -1
- range: Input.cold range or ValueStream.str 'uni'
-
- @out or= ValueStream 'num', apply_range @inputs.range, 0
-
- tick: =>
- { :port, :cc, :chan, :range } = @inputs
- for msg in *port!
- if msg.status == 'control-change' and
- (chan! == -1 or msg.chan == chan!) and
- msg.a == cc!
- @out\set apply_range range, msg.b
-
-{
- :input
- :output
- :inout
- :gate
- :trig
- :cc
-}
diff --git a/lib/midi/core.moon b/lib/midi/core.moon
deleted file mode 100644
index ddb1e8a..0000000
--- a/lib/midi/core.moon
+++ /dev/null
@@ -1,122 +0,0 @@
-import ValueStream, IOStream, Op, Input, Error, val from require 'alv.base'
-import RtMidiIn, RtMidiOut, RtMidi from require 'luartmidi'
-
-bit = do
- ok, bit = pcall require, 'bit32'
- if ok then bit else require 'bit'
-import band, bor, lshift, rshift from bit
-
-MIDI = {
- [0x9]: 'note-on'
- [0x8]: 'note-off'
-
- [0xa]: 'after-key'
- [0xd]: 'after-channel'
-
- [0xb]: 'control-change'
- [0xe]: 'pitch-bend'
- [0xc]: 'program-change'
-}
-
-rMIDI = {v,k for k,v in pairs MIDI}
-
-find_port = (Klass, name) ->
- with Klass RtMidi.Api.UNIX_JACK
- id = nil
- for port=1, \getportcount!
- if name == \getportname port
- id = port
- break
-
- \openport id
-
-class MidiPort extends IOStream
- new: => super 'midi/port'
-
- setup: (inp, out) =>
- @inp = inp and find_port RtMidiIn, inp
- @out = out and find_port RtMidiOut, out
-
- tick: =>
- return unless @inp
- while true
- delta, bytes = @inp\getmessage!
- break unless delta
-
- { status, a, b } = bytes
- chan = band status, 0xf
- status = MIDI[rshift status, 4]
- @add { :status, :chan, :a, :b }
-
- send: (status, chan, a, b) =>
- assert @out, Error 'type', "#{@} is not an output or bidirectional port"
- if 'string' == type 'status'
- status = bor (lshift rMIDI[status], 4), chan
- @out\sendmessage status, a, b
-
-class PortOp extends Op
- new: (...) =>
- super ...
- @out or= MidiPort!
-
- tick: (inp, out) =>
- { :inp, :out } = @unwrap_all!
- @out\setup inp, out
-
-input = ValueStream.meta
- meta:
- name: 'input'
- summary: "Create a MIDI input port."
- examples: { '(midi/input name)' }
-
- value: class extends PortOp
- setup: (inputs) =>
- name = val.str\match inputs
- super inp: Input.hot name
-
-output = ValueStream.meta
- meta:
- name: 'output'
- summary: "Create a MIDI output port."
- examples: { '(midi/output name)' }
-
- value: class extends PortOp
- setup: (inputs) =>
- name = val.str\match inputs
- super out: Input.hot name
-
-inout = ValueStream.meta
- meta:
- name: 'inout'
- summary: "Create a bidirectional MIDI port."
- examples: { '(midi/inout name)' }
-
- value: class extends PortOp
- setup: (inputs) =>
- { inp, out } = (val.str + val.str)\match inputs
- super
- inp: Input.hot inp
- out: Input.hot out
-
-apply_range = (range, val) ->
- if range\type! == 'str'
- switch range!
- when 'raw' then val
- when 'uni' then val / 128
- when 'bip' then val / 64 - 1
- when 'rad' then val / 64 * math.pi
- when 'deg' then val / 128 * 360
- else
- error Error 'argument', "unknown range '#{range!}'"
- elseif range.type == 'num'
- val / 128 * range!
- else
- error Error 'argument', "range has to be a string or number"
-
-{
- :input
- :output
- :inout
- :apply_range
- :bit
-}
diff --git a/lib/midi/launchctl.moon b/lib/midi/launchctl.moon
deleted file mode 100644
index 42837f0..0000000
--- a/lib/midi/launchctl.moon
+++ /dev/null
@@ -1,194 +0,0 @@
-import ValueStream, EventStream, Op, Input, val, evt from require 'alv.base'
-import apply_range, bit from require 'lib.midi.core'
-import bor, lshift from bit
-
-color = (r, g) -> bit.bor 12, r, (bit.lshift g, 4)
-
-cc_seq = ValueStream.meta
- meta:
- name: 'cc-seq'
- summary: "MIDI CC-Sequencer."
- examples: { '(launchctl/cc-seq [port] i start chan [steps [range]])' }
- description: "
-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[
-- 'deg' [ 0 - 360[
-- (num) [ 0 - num["
-
- value: class extends Op
- num = val.num
- pattern = -evt['midi/port'] + num + num + num + -num + -(val.str + num)
- setup: (inputs, scope) =>
- { port, i, start, chan, steps, range } = pattern\match inputs
-
- super
- port: Input.hot port or scope\get '*ctrl*'
- i: Input.hot i
- start: Input.hot start
- chan: Input.hot chan
- steps: Input.hot steps or ValueStream.num 8
- range: Input.hot range or ValueStream.str 'uni'
-
- @state or= {}
- @out or= ValueStream 'num', apply_range @inputs.range, 0
-
- tick: =>
- { :port, :i, :start, :chan, :steps, :range } = @inputs
-
- if steps\dirty!
- while steps! > #@state
- table.insert @state, 0
- while steps! < #@state
- table.remove @state
-
- curr_i = i! % #@state
- if port\dirty!
- changed = false
- for msg in *port!
- if msg.status == 'control-change' and msg.chan == chan!
- rel_i = msg.a - start!
- if rel_i >= 0 and rel_i < #@state
- @state[rel_i+1] = msg.b
- changed = rel_i == curr_i
- @out\set apply_range range, @state[curr_i+1] if changed
- else
- @out\set apply_range range, @state[curr_i+1]
-
-gate_seq = ValueStream.meta
- meta:
- name: 'gate-seq'
- summary: "MIDI Gate-Sequencer."
- examples: { '(launchctl/gate-seq [port] i start chan [steps])' }
- description: "
-Send `true` or `false` for the `i`-th note-button (MIDI-notes starting from
-`start`). `steps` defaults to 8."
-
- value: class extends Op
- pattern = -evt['midi/port'] + val.num + val.num + val.num + -val.num
- setup: (inputs, scope) =>
- @out or= ValueStream 'bool'
- @state or= {}
- { port, i, start, chan, steps } = pattern\match inputs
-
- super
- port: Input.hot port or scope\get '*ctrl*'
- i: Input.hot i
- start: Input.hot start
- chan: Input.hot chan
- steps: Input.hot steps or ValueStream.num 8
-
- 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, 1
- when 'S ' then 1, 0
- when 'SA' then 3, 1
-
- display: (i, active) =>
- start, chan = @inputs.start!, @inputs.chan!
- @inputs.port.stream\send 'note-on', chan, (start + i), light @state[i+1], active
-
- tick: =>
- { :port, :i, :start, :chan, :steps } = @inputs
-
- if steps\dirty!
- while steps! > #@state
- table.insert @state, false
- while steps! < #@state
- table.remove @state
-
- curr_i = i! % #@state
-
- if port\dirty!
- for msg in *port!
- if msg.status == 'note-on' and msg.chan == chan!
- rel_i = msg.a - start!
- if rel_i >= 0 and rel_i < #@state
- @state[rel_i+1] = not @state[rel_i+1]
- @display rel_i, rel_i == curr_i
-
- if i\dirty!
- prev_i = (curr_i - 1) % #@state
-
- @display curr_i, true
- @display prev_i, false
-
- @out\set @state[curr_i+1]
-
-trig_seq = ValueStream.meta
- meta:
- name: 'trig-seq'
- summary: "MIDI Trigger-Sequencer."
- examples: { '(launchctl/trig-seq [port] i start chan [steps])' }
- description: "
-Send bangs for the `i`-th note-button (MIDI-notes starting from `start`).
-`steps` defaults to 8."
-
- value: class extends Op
- pattern = -evt['midi/port'] + val.num + val.num + val.num + -val.num
- setup: (inputs, scope) =>
- @out or= EventStream 'bang'
- @state or= {}
- { port, i, start, chan, steps } = pattern\match inputs
-
- super
- port: Input.hot port or scope\get '*ctrl*'
- i: Input.hot i
- start: Input.hot start
- chan: Input.hot chan
- steps: Input.hot steps or ValueStream.num 8
-
- 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, 1
- when 'S ' then 1, 0
- when 'SA' then 3, 1
-
- display: (i, active) =>
- start, chan = @inputs.start!, @inputs.chan!
- @inputs.port.stream\send 'note-on', chan, (start + i), light @state[i+1], active
-
- tick: =>
- { :port, :i, :start, :chan, :steps } = @inputs
-
- if steps\dirty!
- while steps! > #@state
- table.insert @state, false
- while steps! < #@state
- table.remove @state
-
- curr_i = i! % #@state
-
- if port\dirty!
- for msg in *port!
- if msg.status == 'note-on' and msg.chan == chan!
- rel_i = msg.a - start!
- if rel_i >= 0 and rel_i < #@state
- @state[rel_i+1] = not @state[rel_i+1]
- @display rel_i, rel_i == curr_i
-
- if i\dirty!
- prev_i = (curr_i - 1) % #@state
-
- @display curr_i, true
- @display prev_i, false
-
- if @state[curr_i+1]
- @out\add true
-
-{
- 'cc-seq': cc_seq
- 'gate-seq': gate_seq
- 'trig-seq': trig_seq
-}
diff --git a/lib/osc.moon b/lib/osc.moon
deleted file mode 100644
index b7e25e7..0000000
--- a/lib/osc.moon
+++ /dev/null
@@ -1,87 +0,0 @@
-import Op, ValueStream, Input, val, evt from require 'alv.base'
-import pack from require 'osc'
-import dns, udp from require 'socket'
-
-unpack or= table.unpack
-
-connect = ValueStream.meta
- meta:
- name: 'connect'
- summary: "Create a UDP remote."
- examples: { '(osc/connect host port)' }
-
- value: class extends Op
- pattern = val.str + val.num
- setup: (inputs) =>
- @out or= ValueStream 'udp/socket'
- { host, port } = pattern\match inputs
- super
- host: Input.hot host
- port: Input.hot port
-
- tick: =>
- { :host, :port } = @unwrap_all!
- ip = dns.toip host
-
- @out\set with sock = udp!
- \setpeername ip, port
-
-send = ValueStream.meta
- meta:
- name: 'send'
- summary: "Send events via OSC."
- examples: { '(osc/send [socket] path evt)' }
- description: "Sends an OSC message with `evt` as an argument.
-
-- `socket` should be a `udp/socket` value. This argument can be omitted and the
- value be passed as a dynamic definition in `*sock*` instead.
-- `path` is the OSC path to send the message to. It should be a string-value.
-- `evt` is the argument to send. It should be an event stream."
- value: class extends Op
- pattern = -val['udp/socket'] + val.str + evt!
- setup: (inputs, scope) =>
- { socket, path, value } = pattern\match inputs
- super
- socket: Input.cold socket or scope\get '*sock*'
- path: Input.cold path
- value: Input.hot value
-
- tick: =>
- { :socket, :path, :value } = @unwrap_all!
- for val in *value
- msg = pack path, if 'table' == type val then unpack val else val
- socket\send msg
-
-sync = ValueStream.meta
- meta:
- name: 'sync'
- summary: "Synchronize a value via OSC."
- examples: { '(osc/sync [socket] path val)' }
- description: "sends a message whenever any parameter is dirty."
- description: "Sends an OSC message with `val` as an argument whenever any
-of the arguments change.
-
-- `socket` should be a `udp/socket` value. This argument can be omitted and the
- value be passed as a dynamic definition in `*sock*` instead.
-- `path` is the OSC path to send the message to. It should be a string-value.
-- `val` is the value to Synchronize. It should be a value stream."
-
- value: class extends Op
- pattern = -val['udp/socket'] + val.str + val!
- setup: (inputs, scope) =>
- { socket, path, value } = pattern\match inputs
- super
- socket: Input.hot socket or scope\get '*sock*'
- path: Input.hot path
- value: Input.hot value
-
- tick: =>
- { :socket, :path, :value } = @unwrap_all!
- msg = pack path, value
- socket\send msg
-
-{
- :connect
- :send
- :sync
-}
diff --git a/lib/pilot.moon b/lib/pilot.moon
deleted file mode 100644
index 0d6eefb..0000000
--- a/lib/pilot.moon
+++ /dev/null
@@ -1,90 +0,0 @@
-import Op, ValueStream, Input, val, evt from require 'alv.base'
-import udp from require 'socket'
-
-local conn
-
-hex = "0123456789abcdef"
-encode = (arg) ->
- switch type arg
- when 'number' then
- i = 1 + math.floor arg
- hex\sub i, i
- when 'string' then arg
- else error "invalid type: #{type arg}"
-
-send = (...) ->
- str = ''
- for i = 1, select '#', ...
- tbl = select i, ...
- str ..= table.concat [encode v for v in *tbl]
- conn or= udp!
- conn\sendto str, '127.0.0.1', 49161
-
-arg = val.num / val.str
-
-play = ValueStream.meta
- meta:
- name: 'play'
- summary: "Play a note when a bang arrives."
- examples: { '(pilot/play trig ch oct note [vel [len]])' }
-
- value: class extends Op
- pattern = evt.bang + arg^5
- setup: (inputs) =>
- { trig, args } = pattern\match inputs
- super
- trig: Input.hot trig
- args: [Input.cold a for a in *args]
-
- tick: =>
- { :trig, :args } = @inputs
- for _ in *trig!
- send [a! for a in *@inputs.args]
-
-play_ = ValueStream.meta
- meta:
- name: 'play!'
- summary: "Play a note when a note arrives."
- examples: { '(pilot/play! ch oct note [vel [len]])' }
-
- value: class extends Op
- pattern = arg + arg + (evt.num / evt.str) + arg^2
- setup: (inputs) =>
- { chan, octv, note, args } = pattern\match inputs
- super
- chan: Input.cold chan
- octv: Input.cold octv
- note: Input.hot note
- args: [Input.cold a for a in *args]
-
- tick: =>
- { :chan, :octv, :note, :args } = @inputs
- args = for a in *args do a!
- for note in *note!
- send { chan!, octv!, note }, args
-
-effect = ValueStream.meta
- meta:
- name: 'effect'
- summary: "Set effect parameters."
- examples: { '(pilot/effect which a b)' }
- description: "`effect` should be one of 'DIS', 'CHO', 'REV' or 'FEE'"
-
- value: class extends Op
- pattern = val.str + arg + arg
- setup: (inputs) =>
- { which, a, b } = pattern\match inputs
- super {
- Input.hot which
- Input.hot a
- Input.hot b
- }
-
- tick: =>
- send @unwrap_all!
-
-{
- :play
- 'play!': play_
- :effect
-}
diff --git a/lib/random.moon b/lib/random.moon
deleted file mode 100644
index 8c4d096..0000000
--- a/lib/random.moon
+++ /dev/null
@@ -1,85 +0,0 @@
-import ValueStream, Error, Op, Input, val, evt from require 'alv.base'
-
-apply_range = (range, val) ->
- if range\type! == 'str'
- switch range!
- when 'uni' then val
- when 'bip' then val*2 - 1
- when 'rad' then val*2 * math.pi
- when 'deg' then val * 360
- else
- error Error 'argument', "unknown range '#{range!}'"
- elseif range\type! == 'num'
- val * range!
- else
- error Error 'argument', "range has to be a string or number"
-
-range_doc = "
-range can be one of:
-- 'uni' [ 0 - 1[ (default)
-- 'bip' [-1 - 1[
-- 'rad' [ 0 - tau[
-- 'deg' [ 0 - 360[
-- (num) [ 0 - num["
-
-pattern = -evt.bang + -(val.num / val.str)
-
-num = ValueStream.meta
- meta:
- name: 'num'
- summary: 'Generate a random number.'
- examples: { '(random/num [trigger] [range]))' }
- description: "Generate a random value in `range` when created and on `trig`.
-#{range_doc}"
-
- value: class extends Op
- new: (...) =>
- super ...
- @out or= ValueStream 'num'
- @state or @gen!
-
- gen: => @state = math.random!
-
- setup: (inputs) =>
- { trig, range } = pattern\match inputs
- super
- trig: trig and Input.hot trig
- range: Input.hot range or ValueStream.str 'uni'
-
- tick: =>
- @gen! if @inputs.trig and @inputs.trig\dirty!
- @out\set apply_range @inputs.range, @state
-
-vec = (n) ->
- ValueStream.meta
- meta:
- name: "vec#{n}"
- summary: 'Generate a random vector.'
- examples: { '(random/vec#{n} [trigger] [range]))' }
- description: "Generate a random vec#{n} in `range` when created and on `trig`.
-#{range_doc}"
-
- value: class extends Op
- new: (...) =>
- super ...
- @out or= ValueStream "vec#{n}"
- @state or @gen!
-
- gen: => @state = for i=1,n do math.random!
-
- setup: (inputs) =>
- { trig, range } = pattern\match inputs
- super
- trig: trig and Input.hot trig
- range: Input.hot range or ValueStream.str 'uni'
-
- tick: =>
- @gen! if @inputs.trig and @inputs.trig\dirty!
- @out\set [apply_range @inputs.range, v for v in *@state]
-
-{
- :num
- vec2: vec 2
- vec3: vec 3
- vec4: vec 4
-}
diff --git a/lib/sc.moon b/lib/sc.moon
deleted file mode 100644
index 2857392..0000000
--- a/lib/sc.moon
+++ /dev/null
@@ -1,83 +0,0 @@
-import Op, ValueStream, Input, val, evt from require 'alv.base'
-import pack from require 'osc'
-import dns, udp from require 'socket'
-
-unpack or= table.unpack
-
-play = ValueStream.meta
- meta:
- name: 'play'
- summary: 'Play a SuperCollider SynthDef on bangs.'
- examples: { '(play [socket] synth trig [param val…])' }
- description: "
-Plays the synth `synth` on the `udp/socket` `socket` whenever `trig` is live.
-
-- `socket` should be a `udp/socket` value. This argument can be omitted and the
- value be passed as a dynamic definition in `*sock*` instead.
-- `synth` is the SC synthdef name. It should be a string-value.
-- `trig` is the trigger signal. It should be a stream of bang-events.
-- `param` is the name of a synthdef parameter. It should be a string-value."
- value: class extends Op
- pattern = -val['udp/socket'] + val.str + evt.bang + (val.str + val.num)\rep 0
- setup: (inputs, scope) =>
- { socket, synth, trig, ctrls } = pattern\match inputs
-
- flat_ctrls = {}
- for { key, value } in *ctrls
- table.insert flat_ctrls, key
- table.insert flat_ctrls, value
-
- super
- trig: Input.hot trig
- socket: Input.cold socket or scope\get '*sock*'
- synth: Input.cold synth
- ctrls: [Input.cold v for v in *flat_ctrls]
-
- tick: =>
- if @inputs.trig\dirty! and @inputs.trig!
- { :socket, :synth, :ctrls } = @unwrap_all!
- msg = pack '/s_new', synth, -1, 0, 1, unpack ctrls
- socket\send msg
-
-play_ = ValueStream.meta
- meta:
- name: 'play!'
- summary: 'Play a SuperCollider SynthDef on events.'
- examples: { '(play [socket] synth [param evt/val…])' }
- description: "
-Plays the synth `synth` on the `udp/socket` `socket` whenever any `evt` is live.
-
-- `socket` should be a `udp/socket` value. This argument can be omitted and the
- value be passed as a dynamic definition in `*sock*` instead.
-- `synth` is the SC synthdef name. It should be a string-value.
-- `param` is the name of a synthdef parameter. It should be a string-value.
-- `val` and `evt` are the parameter values to send. They should be number
- streams. Incoming events will cause a note to be played, while value changes
- will not."
- value: class extends Op
- pattern = -val['udp/socket'] + val.str + (val.str + (val.num / evt.num))\rep 0
- setup: (inputs, scope) =>
- { socket, synth, trig, ctrls } = pattern\match inputs
-
- flat = {}
- for { key, value } in *ctrls
- table.insert flat, Input.cold key
- table.insert flat, if value\metatype! == 'event'
- Input.hot value
- else
- Input.cold value
-
- super
- socket: Input.cold socket or scope\get '*sock*'
- synth: Input.cold synth
- ctrls: flat
-
- tick: =>
- { :socket, :synth, :ctrls } = @unwrap_all!
- msg = pack '/s_new', synth, -1, 0, 1, unpack ctrls
- socket\send msg
-
-{
- :play
- 'play!': play_
-}
diff --git a/lib/string.moon b/lib/string.moon
deleted file mode 100644
index faa7ab3..0000000
--- a/lib/string.moon
+++ /dev/null
@@ -1,18 +0,0 @@
-import Op, ValueStream, Input from require 'alv.base'
-
-str = ValueStream.meta
- meta:
- name: 'str'
- summary: "Concatenate/stringify values."
- examples: { '(.. v1 [v2…])', '(str v1 [v2…])' }
- value: class extends Op
- setup: (inputs) =>
- @out or= ValueStream 'string'
- super [Input.hot v for v in *inputs]
-
- tick: =>
- @out\set table.concat [tostring v! for v in *@inputs]
-
-{
- :str, '..': str
-}
diff --git a/lib/time.moon b/lib/time.moon
deleted file mode 100644
index 2589d96..0000000
--- a/lib/time.moon
+++ /dev/null
@@ -1,285 +0,0 @@
-import
- ValueStream, EventStream, IOStream,
- Error, Op, Input, val, evt
-from require 'alv.base'
-import monotime from require 'system'
-
-class Clock extends IOStream
- new: (@frametime) =>
- super 'clock'
-
- return unless monotime
- @last = monotime!
- @dt = 0
- @is_dirty = false
-
- tick: =>
- time = monotime!
- @dt = time - @last
- if @dt >= @frametime
- @add { dt: @dt, :time }
- @last = time
-
-class ScaledClock extends EventStream
- set: (val) => @value
- unwrap: => @value
-
-clock = ValueStream.meta
- meta:
- name: 'clock'
- summary: "Create a clock source."
- examples: { '(clock)', '(clock fps)' }
- description: "Creates a new clock event stream.
-
-The clock event stream is an IO that triggers other operators at a fixed
-frame rate.
-
-- `fps` has to be an eval-time constant and defaults to `60` if omitted."
- value: class extends Op
- new: (...) =>
- super ...
- @out or= Clock!
-
- setup: (inputs) =>
- fps = (-val.num)\match inputs
- super fps: Input.hot fps or ValueStream.num 60
- @out.frametime = 1 / @inputs.fps!
-
- tick: =>
- @out.frametime = 1 / @inputs.fps!
-
-scale_time = ValueStream.meta
- meta:
- name: 'scale-time'
- summary: "Scale clock time."
- examples: { '(scale-time [clock] scale)' }
- description: "Creates a new clock event stream scaled by `scale`.
-
-- `clock` should be a `time/clock` event stream. This argument can be omitted
- and the stream be passed as a dynamic definition in `*clock*` instead.
-- `scale` should be a num-value."
- value: class extends Op
- new: (...) =>
- super ...
- @out or= EventStream 'clock'
-
- pattern = -evt.clock + val.num + -val.str
- setup: (inputs, scope) =>
- { clock, scale } = pattern\match inputs
- super
- clock: Input.hot clock or scope\get '*clock*'
- scale: Input.cold scale
-
- tick: =>
- scale = @inputs.scale!
- for evt in *@inputs.clock!
- @out\add {k, v*scale for k,v in pairs evt}
-
-lfo = ValueStream.meta
- meta:
- name: 'lfo'
- summary: "Low-frequency oscillator."
- examples: { '(lfo [clock] freq [wave])' }
- description: "Oscillates betwen `0` and `1` at the frequency `freq`.
-
-- `clock` should be a `time/clock` event stream. This argument can be omitted
- and the stream be passed as a dynamic definition in `*clock*` instead.
-- `freq` should be a num-value.
-- `wave` selects the wave shape from one of the following:
- - `'sin'` (the default)
- - `'saw'`
- - `'tri'`"
- value: class extends Op
- new: (...) =>
- super ...
- @state or= 0
- @out or= ValueStream 'num'
-
- default_wave = ValueStream.str 'sin'
- pattern = -evt.clock + val.num + -val.str
- setup: (inputs, scope) =>
- { clock, freq, wave } = pattern\match inputs
- super
- clock: Input.hot clock or scope\get '*clock*'
- freq: Input.cold freq
- wave: Input.hot wave or default_wave
-
- tau = math.pi * 2
- tick: =>
- for tick in *@inputs.clock!
- @state += tick.dt * @inputs.freq!
-
- @out\set switch @inputs.wave!
- when 'sin' then .5 + .5 * math.cos @state * tau
- when 'saw' then @state % 1
- when 'tri' then math.abs (2*@state % 2) - 1
- else error Error 'argument', "unknown wave type '#{wave}'"
-
-ramp = ValueStream.meta
- meta:
- name: 'ramp'
- summary: "Sawtooth LFO."
- examples: { '(ramp [clock] period [max])' }
- description: "Ramps from `0` to `max` once every `period` seconds.
-
-- `clock` should be a `time/clock` event stream. This argument can be omitted
- and the stream be passed as a dynamic definition in `*clock*` instead.
-- `period` should be a num-value.
-- `max` should be a num-value and defaults to `period` if omitted."
- value: class extends Op
- new: (...) =>
- super ...
- @state or= 0
- @out or= ValueStream 'num'
-
- pattern = -evt.clock + val.num + -val.num
- setup: (inputs, scope) =>
- { clock, period, max } = pattern\match inputs
- super
- clock: Input.hot clock or scope\get '*clock*'
- period: Input.cold period
- max: max and Input.cold max
-
- tick: =>
- for tick in *@inputs.clock!
- period = @inputs.period!
- max = (@inputs.max or @inputs.period)!
- @phase += tick.dt / period
-
- while @phase >= 1
- @phase -= 1
-
- @out\set @phase * max
-
-tick = ValueStream.meta
- meta:
- name: 'tick'
- summary: "Count ticks."
- examples: { '(tick [clock] period)' }
- description: "Counts upwards by one every `period` seconds.
-
-- `clock` should be a `time/clock` event stream. This argument can be omitted
- and the stream be passed as a dynamic definition in `*clock*` instead.
-- `period` should be a num-value.
-- returns a `num` value that increases by 1 every `period`."
- value: class extends Op
- new: (...) =>
- super ...
- @state or= { phase: 0, count: 0 }
- @out or= ValueStream 'num', @state.count
-
- pattern = -evt.clock + val.num
- setup: (inputs, scope) =>
- { clock, period } = pattern\match inputs
- super
- clock: Input.hot clock or scope\get '*clock*'
- period: Input.cold period
-
- tick: =>
- for tick in *@inputs.clock!
- @state.phase += tick.dt / @inputs.period!
-
- while @state.phase >= 1
- @state.phase -= 1
- @state.count += 1
- @out\set @state.count
-
-every = ValueStream.meta
- meta:
- name: 'every'
- summary: "Emit events regularly."
- examples: { '(every [clock] period [evt])' }
- description: "Emits `evt` as an event once every `period` seconds.
-
-- `clock` should be a `time/clock` event stream. This argument can be omitted
- and the stream be passed as a dynamic definition in `*clock*` instead.
-- `period` should be a num-value.
-- `evt` can be a value of any type. It defaults to `bang`.
-- the return type will be an event stream with the same type as `evt`."
- value: class extends Op
- new: (...) =>
- super ...
- @state or= 0
-
- pattern = -evt.clock + val.num + -val!
- setup: (inputs, scope) =>
- { clock, period, evt } = pattern\match inputs
- super
- clock: Input.hot clock or scope\get '*clock*'
- period: Input.cold period
- evt: Input.cold evt or ValueStream 'bang', true
- @out = EventStream @inputs.evt\type!
-
- tick: =>
- for tick in *@inputs.clock!
- @state += tick.dt / @inputs.period!
-
- while @state >= 1
- @state -= 1
- @out\add @inputs.evt!
-
-sequence = ValueStream.meta
- meta:
- name: 'sequence'
- summary: "Emit a sequence of values as events over time."
- examples: { '(sequence [clock] delay0 evt1 delay1 evt2 delay2…)' }
- description: "
-Emits `evt1`, `evt2`, … as events with delays `delay0`, `delay1`, … in between.
-
-- `clock` should be a `time/clock` event stream. This argument can be omitted
- and the stream be passed as a dynamic definition in `*clock*` instead.
-- `delay0`, `delay1`, … must be num-values.
-- `evt1`, `evt2`, … must be values of the same type.
-- the return type will be an event stream with the same type as the `evt`s."
- value: class extends Op
- new: (...) =>
- super ...
- @state or= { i: 1, t: 0 }
-
- pair = (val! + val.num)\named('value', 'delay')
- pattern = -evt.clock + val.num + pair*0
-
- inputify = (step) ->
- {
- delay: Input.cold step.delay
- value: if step.value then Input.hot step.value
- }
-
- setup: (inputs, scope) =>
- { clock, first, steps } = pattern\match inputs
- @out = EventStream steps[1].value\type!
- table.insert steps, 1, { delay: first }
- super
- clock: Input.hot clock or scope\get '*clock*'
- steps: [inputify step for step in *steps]
-
- tick: =>
- for tick in *@inputs.clock!
- @state.t += tick.dt
-
- change, current = false, nil
- while true
- current = @inputs.steps[@state.i]
- if @state.t >= current.delay!
- @state.t -= current.delay!
- @state.i = 1 + (@state.i % #@inputs.steps)
- change = true
- else
- break
-
- if current.value and (change or current.value\dirty!)
- @out\add current.value!
-
-{
- :clock
- 'scale-time': scale_time
- :lfo
- :ramp
- :tick
- :every
- :sequence
- '*clock*': with Clock 1/60
- .meta =
- name: '*clock*'
- summary: 'Default clock source (60fps).'
-}
diff --git a/lib/util.moon b/lib/util.moon
deleted file mode 100644
index dc133e4..0000000
--- a/lib/util.moon
+++ /dev/null
@@ -1,112 +0,0 @@
-import Op, ValueStream, EventStream, Input, val, evt from require 'alv.base'
-
-all_same = (list) ->
- for v in *list[2,]
- if v != list[1]
- return false
-
- list[1]
-
-switch_ = ValueStream.meta
- meta:
- name: 'switch'
- summary: "Switch between multiple inputs."
- examples: { '(switch i v0 [v1 v2…])' }
- description: "
-- when `i` is `true`, the first value is reproduced.
-- when `i` is `false`, the second value is reproduced.
-- when `i` is a `num`, it is [math/floor][]ed and the matching argument
- (indexed starting from 0) is reproduced."
-
- value: class extends Op
- val_or_evt = (val! / evt!)!
- pattern = (val.num / val.bool) + val_or_evt*0
- setup: (inputs) =>
- { i, values } = pattern\match inputs
-
- @state = values[1].value.__class == ValueStream
-
- @out = if @state
- ValueStream values[1]\type!
- else
- EventStream values[1]\type!
-
- super
- i: Input.hot i
- values: [Input.hot v for v in *values]
-
- tick: =>
- { :i, :values } = @inputs
- active = switch i!
- when true
- values[1]
- when false
- values[2]
- else
- i = 1 + (math.floor i!) % #values
- values[i]
- if @state
- @out\set active and active!
- else
- if active and active\dirty!
- for event in *active!
- @out\add event
-
-edge = ValueStream.meta
- meta:
- name: 'edge'
- summary: "Convert rising edges to bangs."
- examples: { '(edge bool)' }
-
- value: class extends Op
- setup: (inputs) =>
- @out or= EventStream 'bang'
- value = val.bool\match inputs
- super value: Input.hot value
-
- tick: =>
- now = @inputs.value!
- if now and not @state.last
- @out\set true
- @state.last = now
-
-change = ValueStream.meta
- meta:
- name: 'change'
- summary: "Convert value changes to events."
- examples: { '(change val)' }
-
- value: class extends Op
- setup: (inputs) =>
- value = val!\match inputs
- @out or= EventStream value\type!
- super value: Input.hot value
-
- tick: =>
- now = @inputs.value!
- if now != @state
- @out\add @inputs.value!
- @state = now
-
-hold = ValueStream.meta
- meta:
- name: 'hold'
- summary: "Convert events to value changes."
- examples: { '(hold evt)' }
-
- value: class extends Op
- setup: (inputs) =>
- event = evt!\match inputs
- @out or= ValueStream event\type!
- super event: Input.hot event
-
- tick: =>
- for val in *@inputs.event!
- @out\set val
-
-{
- 'switch': switch_
- :edge
- :change
- :hold
-}