diff options
| author | s-ol <s-ol@users.noreply.github.com> | 2020-04-14 09:21:00 +0000 |
|---|---|---|
| committer | s-ol <s-ol@users.noreply.github.com> | 2020-04-14 09:21:00 +0000 |
| commit | 5faab5d81cc5ed36824a52a273e83eb20240cb2e (patch) | |
| tree | dba10fadf4cdad0f5524df642fab83f6310a8574 /lib | |
| parent | move spec out of spec/core (diff) | |
| download | alive-5faab5d81cc5ed36824a52a273e83eb20240cb2e.tar.gz alive-5faab5d81cc5ed36824a52a273e83eb20240cb2e.zip | |
move lib to alv-lib module
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/logic.moon | 153 | ||||
| -rw-r--r-- | lib/math.moon | 192 | ||||
| -rw-r--r-- | lib/midi.moon | 99 | ||||
| -rw-r--r-- | lib/midi/core.moon | 122 | ||||
| -rw-r--r-- | lib/midi/launchctl.moon | 194 | ||||
| -rw-r--r-- | lib/osc.moon | 87 | ||||
| -rw-r--r-- | lib/pilot.moon | 90 | ||||
| -rw-r--r-- | lib/random.moon | 85 | ||||
| -rw-r--r-- | lib/sc.moon | 83 | ||||
| -rw-r--r-- | lib/string.moon | 18 | ||||
| -rw-r--r-- | lib/time.moon | 285 | ||||
| -rw-r--r-- | lib/util.moon | 112 |
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 -} |
