diff options
| author | s-ol <s-ol@users.noreply.github.com> | 2020-03-02 14:40:00 +0000 |
|---|---|---|
| committer | s-ol <s-ol@users.noreply.github.com> | 2020-03-02 16:48:09 +0000 |
| commit | 4ebb6f4408600f3c0f2a745b7ed0ba951bf521b3 (patch) | |
| tree | cdf0953fdee07a6c83c510470a7b8ab8d832d25d | |
| parent | update lib.math and lib.logic to new op interface (diff) | |
| download | alive-4ebb6f4408600f3c0f2a745b7ed0ba951bf521b3.tar.gz alive-4ebb6f4408600f3c0f2a745b7ed0ba951bf521b3.zip | |
lift remaining libs to new op interface
| -rw-r--r-- | core/base.moon | 9 | ||||
| -rw-r--r-- | core/init.moon | 5 | ||||
| -rw-r--r-- | lib/envelope.moon | 26 | ||||
| -rw-r--r-- | lib/logic.moon | 4 | ||||
| -rw-r--r-- | lib/midi/core.moon | 1 | ||||
| -rw-r--r-- | lib/midi/init.moon | 32 | ||||
| -rw-r--r-- | lib/midi/launchctl.moon | 1 | ||||
| -rw-r--r-- | lib/osc.moon | 76 | ||||
| -rw-r--r-- | lib/pilot.moon | 56 | ||||
| -rw-r--r-- | lib/random.moon | 77 | ||||
| -rw-r--r-- | lib/sc.moon | 42 | ||||
| -rw-r--r-- | lib/string.moon | 12 | ||||
| -rw-r--r-- | lib/util.moon | 75 |
13 files changed, 279 insertions, 137 deletions
diff --git a/core/base.moon b/core/base.moon index c6ea694..41ddd4c 100644 --- a/core/base.moon +++ b/core/base.moon @@ -27,6 +27,12 @@ class Input cls.__base.__call = @__call cls.__base.__tostring = @__tostring +-- ColdInput scheduling policy +-- +-- never marked dirty +class ColdInput extends Input + dirty: => false + -- ValueInput scheduling policy -- -- during setup, only marked dirty if old and new stream differ in value @@ -210,8 +216,7 @@ class FnDef "(fn (#{table.concat [p\stringify! for p in *@params], ' '}) ...)" { - :ValueInput, :EventInput, :IOInput - :Dispatcher + :ValueInput, :EventInput, :IOInput, :ColdInput :IO :Op :Action diff --git a/core/init.moon b/core/init.moon index 6b5bdd0..6a8c5d4 100644 --- a/core/init.moon +++ b/core/init.moon @@ -1,6 +1,6 @@ L or= setmetatable {}, __index: => -> -import Op, IO, Action, FnDef, EventInput, ValueInput, IOInput +import Op, IO, Action, FnDef, EventInput, ValueInput, IOInput, ColdInput from require 'core.base' import match from require 'core.pattern' @@ -21,7 +21,8 @@ globals = Scope.from_table require 'core.builtin' :Cell, :RootCell :Op, :IO, :Action, :FnDef - :EventInput, :ValueInput, :IOInput, :match + :EventInput, :ValueInput, :IOInput, :ColdInput, + :match :Scope :Registry, :Tag diff --git a/lib/envelope.moon b/lib/envelope.moon deleted file mode 100644 index eb79a64..0000000 --- a/lib/envelope.moon +++ /dev/null @@ -1,26 +0,0 @@ -import Stream, Op, Scope, eval from require 'core' - -class ar_core extends Op - @doc: "(ar-core attack release gate) -((ar attack release) gate) - AR envelope - -goes from 0 to 1 in attack seconds, holds while gate is on, then goes back to 0 in release seconds." - - new: (...) => - super ... - @out = Stream 'num', 0 - - setup: (@a, @r, @gate) => - assert @a, "ar requires an attack value" - assert @r, "ar requires a release value" - assert @gate, "ar requires a gate value" - @out - - update: (dt) => - slope = if (@gate\unwrap 'bool') then (@a\unwrap! or 0.1) else -(@r\unwrap! or 0.5) - - @out\set math.min 1, math.max 0, @out\unwrap! + dt / slope - -scope = Scope.from_table { 'ar-core': ar_core } -scope\set 'ar', eval '(fn (a r) (fn (gate) (ar-core a r gate)))', scope -scope diff --git a/lib/logic.moon b/lib/logic.moon index d2144f6..b4c6cf7 100644 --- a/lib/logic.moon +++ b/lib/logic.moon @@ -5,7 +5,7 @@ all_same = (first, list) -> if v != first return false - true + first tobool = (val) -> switch val @@ -83,9 +83,7 @@ class not_eq extends Op diff = true for a=1, #@inputs-1 for b=a+1, #@inputs - print @inputs[a], @inputs[b] if @inputs[a].stream == @inputs[b].stream - print "found a match #{a} == #{b}" diff = false break diff --git a/lib/midi/core.moon b/lib/midi/core.moon index aeef861..d91fdcb 100644 --- a/lib/midi/core.moon +++ b/lib/midi/core.moon @@ -105,6 +105,7 @@ apply_range = (range, 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 "unknown range #{@range}" elseif range.type == 'num' diff --git a/lib/midi/init.moon b/lib/midi/init.moon index 3bfba48..daf0088 100644 --- a/lib/midi/init.moon +++ b/lib/midi/init.moon @@ -8,14 +8,14 @@ class gate extends Op super 'bool', false setup: (inputs) => - { :port, :note, :chan } = match 'midi/port num num?', inputs + { port, note, chan } = match 'midi/port num num?', inputs super port: IOInput port note: ValueInput note chan: ValueInput chan or Value.num -1 tick: => - { port, note, chan } = @inputs + { :port, :note, :chan } = @inputs if note\dirty! or chan\dirty! @out\set false @@ -28,6 +28,32 @@ class gate extends Op elseif msg.status == 'note-off' @out\set false +class trig extends Op + @doc: "(midi/trig port note [chan]) - gate from note-on and note-off messages" + + new: => + super 'bang', false + + setup: (inputs) => + { port, note, chan } = match 'midi/port num num?', inputs + super + port: IOInput port + note: ValueInput note + chan: ValueInput chan or Value.num -1 + + tick: => + { :port, :note, :chan } = @inputs + + if note\dirty! or chan\dirty! + @out\set false + + if port\dirty! + for msg in port!\receive! + if msg.a == note! and (chan! == -1 or msg.chan == chan!) + if msg.status == 'note-on' + @out\set true + + class cc extends Op @doc: "(midi/cc port cc [chan [range]]) - MIDI CC to number @@ -36,6 +62,7 @@ range can be one of: - 'uni' [ 0 - 1[ (default) - 'bip' [-1 - 1[ - 'rad' [ 0 - tau[ +- 'deg' [ 0 - 360[ - (num) [ 0 - num[" new: => @@ -66,5 +93,6 @@ range can be one of: :output :inout :gate + :trig :cc } diff --git a/lib/midi/launchctl.moon b/lib/midi/launchctl.moon index b3bf5da..1acafdc 100644 --- a/lib/midi/launchctl.moon +++ b/lib/midi/launchctl.moon @@ -16,6 +16,7 @@ range can be one of: - 'uni' [ 0 - 1[ (default) - 'bip' [-1 - 1[ - 'rad' [ 0 - tau[ +- 'deg' [ 0 - 360[ - (num) [ 0 - num[" new: => diff --git a/lib/osc.moon b/lib/osc.moon index bced72f..e73a982 100644 --- a/lib/osc.moon +++ b/lib/osc.moon @@ -1,41 +1,67 @@ -import Op from require 'core' -import pack, unpack from require 'osc' +import Op, ValueInput, EventInput, ColdInput, match from require 'core' +import pack from require 'osc' import dns, udp from require 'socket' -class addr extends Op - @doc: "(remote host port) - UDP remote definition" +unpack or= table.unpack - new: => - super 'udp/remote' - @@udp or= udp! +class connect extends Op + @doc: "(osc/connect host port) - UDP remote definition" - setup: (params) => - super params - @assert_types 'str', 'num' + new: => super 'udp/socket' + + setup: (inputs) => + { host, port } = match 'str num', inputs + super + host: ValueInput host + port: ValueInput port tick: => - host, port = @unwrap_inputs! + { :host, :port } = @unwrap_all! ip = dns.toip host - @out\set { :ip, :port } -class out extends Op - @doc: "(out remote path val) - send a value via OSC" + @out\set with sock = udp! + \setpeername ip, port + +class send extends Op + @doc: "(osc/send socket path val) - send a value via OSC + +sends a message only when val is dirty." + + setup: (inputs) => + { socket, path, value } = match 'udp/socket str any', inputs + super + socket: ColdInput socket + path: ColdInput path + value: EventInput value + + tick: => + if @inputs.value\dirty! + { :socket, :path, :value } = @unwrap_all! + msg = if 'table' == type value + pack path, unpack value + else + pack path, value + socket\send msg + +class send_state extends Op + @doc: "(osc/send! socket path val) - synchronize a value via OSC - new: (...) => - @@udp or= udp! +sends a whenever any parameter changes." - setup: (params) => - super params - assert @inputs[3], "need a value" - @assert_types 'udp/remote', 'str', @inputs[3].type + setup: (inputs) => + { socket, path, value } = match 'udp/socket str any', inputs + super + socket: ValueInput socket + path: ValueInput path + value: ValueInput value tick: => - remote, path, value = @unwrap_inputs! - { :ip, :port } = remote + { :socket, :path, :value } = @unwrap_all! msg = pack path, value - @@udp\sendto msg, ip, port + socket\send msg { - :addr - :out + :connect + :send + 'send!': send_state } diff --git a/lib/pilot.moon b/lib/pilot.moon index 2a7d21a..a442b77 100644 --- a/lib/pilot.moon +++ b/lib/pilot.moon @@ -1,4 +1,4 @@ -import Op from require 'core' +import Op, EventInput, ValueInput, ColdInput, match from require 'core' import udp from require 'socket' conn = udp! @@ -11,32 +11,62 @@ encode = (arg) -> when 'string' then arg else error "invalid type: #{type arg}" -send = (tbl) -> - str = table.concat [encode v for v in *tbl] +send = (...) -> + str = '' + for i = 1, select '#', ... + tbl = select i, ... + str ..= table.concat [encode v for v in *tbl] conn\sendto str, '127.0.0.1', 49161 class play extends Op @doc: "(play trig ch oct note [vel [len]]) - play a note when trig is live" - setup: (@trig, ...) => - @vals = { ... } + setup: (inputs) => + { trig, args } = match 'bang *any', inputs + assert #args < 6, "too many arguments!" + super + trig: EventInput trig + args: [ColdInput a for a in *args] - update: (dt) => - if @trig\unwrap 'bool' - send [c\unwrap! for c in *@vals] + tick: => + { :trig, :args } = @inputs + if trig\dirty! and trig! + send [a! for a in *@inputs.args] + +class play_ extends Op + @doc: "(play! ch oct note [vel [len]]) - play a note when note is live" + + setup: (inputs) => + { chan, octv, note, args } = match 'any any any *any', inputs + assert #args < 3, "too many arguments!" + super + chan: ColdInput chan + octv: ColdInput octv + note: EventInput note + args: [ColdInput a for a in *args] + + tick: => + if @inputs.note\dirty! + { :chan, :oct, :note, :args } = @unwrap_all! + send { chan, oct, note }, args class effect extends Op @doc: "(effect which a b) - set an effect which is one of 'DIS', 'CHO', 'REV' or 'FEE'" - setup: (@which, @a, @b) => + setup: (inputs) => + { which, a, b } = match 'str num num', inputs + super { + ColdInput which + ValueInput a + ValueInput b + } - update: (dt) => - which, a, b = (@which\unwrap 'str'), @a\unwrap!, @b\unwrap! - if which and a and b - send { which, a, b } + tick: => + send @unwrap_all! { :play + 'play!': play_ :effect } diff --git a/lib/random.moon b/lib/random.moon new file mode 100644 index 0000000..9e5e62b --- /dev/null +++ b/lib/random.moon @@ -0,0 +1,77 @@ +import Op, Value, ValueInput, EventInput, match from require 'core' + +apply_range = (range, val) -> + if range\type! == 'str' + switch range\unwrap! + when 'uni' then val + when 'bip' then val * 2 - 1 + when 'rad' then val * 2 * math.pi + when 'deg' then val * 360 + else + error "unknown range #{@range}" + elseif range.type == 'num' + val * range\unwrap! + else + error "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[" + +class num extends Op + @doc: "(random/num [trigger] [range]) - create a random number + +generates a random value in range on create and trigger. +#{range_doc}" + new: => + super 'num' + @gen! + + gen: => @val = math.random! + + setup: (inputs) => + { trig, range } = match 'bang? any?', inputs + super + trig: trig and EventInput trig + range: ValueInput range or Value.str 'uni' + + tick: => + @gen! if @inputs.trig and @inputs.trig\dirty! + @out\set apply_range @inputs.range, @val + +vec_ = (n) -> + class vec extends Op + @doc: "(random/vec#{n} [trigger] [range]) - create a random number + +generates a random vec#{n} on create and trigger. +each component is in range. +#{range_doc}" + new: => + super "vec#{n}" + @gen! + + gen: => @val = for i=1,n do math.random! + + setup: (inputs) => + { trig, range } = match 'bang? any?', inputs + super + trig: trig and EventInput trig + range: ValueInput range or Value.str 'uni' + + tick: => + @gen! if @inputs.trig and @inputs.trig\dirty! + @out\set [apply_range @inputs.range, v for v in *@val] + + vec.__name = "vec#{n}" + vec + +{ + :num + vec2: vec_ 2 + vec3: vec_ 3 + vec4: vec_ 4 +} diff --git a/lib/sc.moon b/lib/sc.moon index 7ffd16c..b30e30d 100644 --- a/lib/sc.moon +++ b/lib/sc.moon @@ -1,36 +1,30 @@ -import Op, Value, Scope from require 'core' +import Op, EventInput, ColdInput, match 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" + @doc: "(sc/play socket synth trigger [name-str val]...) - play a SC SynthDef" - new: => - super! - @@udp or= udp! + setup: (inputs) => + { socket, synth, trig, ctrls } = match 'udp/socket str bang *any?', inputs - setup: (params) => - super params - @assert_first_types 'udp/remote', 'str', 'bool' + assert #ctrls % 2 == 0, "parameters need to be specified as pairs" + for key in *ctrls[1,,2] + assert key\type! == 'str', "ony strings are supported as control names" + for val in *ctrls[2,,2] + assert val\type! == 'num', "only numbers are supported as control values" - 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" + super + socket: ColdInput socket + synth: ColdInput synth + trig: EventInput trig + ctrls: [ColdInput v for v in *ctrls] 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 + 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 diff --git a/lib/string.moon b/lib/string.moon index 6a9b7d7..8c10c5d 100644 --- a/lib/string.moon +++ b/lib/string.moon @@ -1,16 +1,12 @@ -import Stream, Op from require 'core' +import Op, ValueInput from require 'core' class str extends Op @doc: "(str v1 [v2]...) (.. v1 [v2]...) - concatenate/stringify values" + new: => super 'str' - setup: (...) => - @children = { ... } - @out = Stream 'str' - @out - - update: (dt) => - @out\set table.concat [tostring child\unwrap! for child in *@children] + setup: (inputs) => super [ValueInput v for v in *inputs] + tick: => @out\set table.concat [tostring v! for v in *@inputs] { :str, '..': str diff --git a/lib/util.moon b/lib/util.moon index 747cb0d..6ada851 100644 --- a/lib/util.moon +++ b/lib/util.moon @@ -1,4 +1,11 @@ -import Value, Op from require 'core' +import Op, Value, ValueInput, EventInput, ColdInput, match from require 'core' + +all_same = (list) -> + for v in *list[2,] + if v != list[1] + return false + + list[1] class switch_ extends Op @doc: "(switch i v0 [v1 v2...]) - switch between multiple inputs @@ -7,27 +14,29 @@ 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 (floor)ed and the matching argument (starting from 0) is reproduced." - setup: (params) => - super params + setup: (inputs) => + { i, values } = match 'any *any', inputs - { i, first } = @inputs - assert i.type == 'bool' or i.type == 'num', "#{@}: i has to be bool or num" + i_type = i\type! + assert i_type == 'bool' or i_type == 'num', "#{@}: i has to be bool or num" + typ = all_same [v\type! for v in *values] + @out = Value typ - for inp in *@inputs[3,] - assert inp.type == first.type, "not all values have the same type: #{first.type} != #{inp.type}" - @out = Value first.type, first! + super + i: ValueInput i + values: [ValueInput v for v in *values] tick: => - i = @inputs[1]\unwrap! - active = switch i + { :i, :values } = @inputs + active = switch i! when true - @inputs[2] + values[1] when false - @inputs[3] + values[2] else - i = 2 + (math.floor i) % (#@inputs - 1) - @inputs[i] - @out\set active and active\unwrap! + i = 1 + (math.floor i!) % #values + values[i] + @out\set active and active! --class switch_pause extends Op -- @doc: "(switch- i v0 [v1 v2...]) - switch and pause multiple inputs @@ -60,38 +69,40 @@ when i is a num, it is (floor)ed and the matching argument (starting from 0) is class edge extends Op @doc: "(edge bool) - convert rising edges to bangs" + new: => super 'bang' - new: => - super 'bang' - - setup: (params) => - super params - @assert_types 'bool' + setup: (inputs) => + { value } = match 'bool', inputs + super value: EventInput tick: => - now = @params[1]\unwrap! + now = @inputs.value! if now and not @last @out\set true @last = now -class keep extends Op - @doc: "(keep value [init]) - keep the last non-nil value +class default extends Op + @doc: "(default stream default) - provide a default value for an event stream -always reproduces the last non-nil value the input produced or default. +starts out as default but forwards events from stream. default defaults to zero." setup: (params) => - super params - { i, init } = @inputs - @out = Value i.type, default and init\unwrap! + { value, init } = match 'any any', inputs + super + value: EventInput value + init: ColdInput init + + @out = Value value\type! + @out\set @inputs.init\unwrap! tick: => - if next = @params[1]\unwrap! - @out\set next + { :value } = @inputs + if value\dirty! + @out\set value! { 'switch': switch_ --- 'switch-': switch_pause :edge - :keep + :default } |
