aboutsummaryrefslogtreecommitdiffstats
path: root/alv-lib
diff options
context:
space:
mode:
authors-ol <s+removethis@s-ol.nu>2021-01-30 23:01:51 +0000
committers-ol <s+removethis@s-ol.nu>2021-01-30 23:10:34 +0000
commitdbdfb1364c91d4905d3f0c947bf150d25ce0c817 (patch)
treec612d986abe729a5c99e4dad08986a8d1d5a7b60 /alv-lib
parentfix array builtin (diff)
downloadalive-dbdfb1364c91d4905d3f0c947bf150d25ce0c817.tar.gz
alive-dbdfb1364c91d4905d3f0c947bf150d25ce0c817.zip
lib: switch to losc
Diffstat (limited to 'alv-lib')
-rw-r--r--alv-lib/_osc.moon33
-rw-r--r--alv-lib/osc.moon69
-rw-r--r--alv-lib/sc.moon83
3 files changed, 105 insertions, 80 deletions
diff --git a/alv-lib/_osc.moon b/alv-lib/_osc.moon
new file mode 100644
index 0000000..43297df
--- /dev/null
+++ b/alv-lib/_osc.moon
@@ -0,0 +1,33 @@
+import new_message from require 'losc'
+import opairs from require 'alv.util'
+import T, Array, Struct from require 'alv.base'
+
+add_item = (message, type, val) ->
+ switch type.__class
+ when Array
+ -- message\add '['
+ for i=1,type.size
+ add_item message, type.type, val[i]
+ -- message\add ']'
+ when Struct
+ -- message\add '['
+ for key, subtype in opairs type.types
+ -- message\add '['
+ message\add 's', key
+ add_item message, subtype, val[key]
+ -- message\add ']'
+ -- message\add ']'
+ else
+ ts = switch type
+ when T.num then 'f'
+ when T.str, T.sym then 's'
+ when T.bool, T.bang
+ if val then 'T' else 'F'
+ else
+ error "unknown primitive type"
+ message\add ts, val
+
+{
+ :new_message
+ :add_item
+}
diff --git a/alv-lib/osc.moon b/alv-lib/osc.moon
index e0dddba..cf802b7 100644
--- a/alv-lib/osc.moon
+++ b/alv-lib/osc.moon
@@ -1,5 +1,5 @@
-import Op, Constant, SigStream, Input, T, sig, evt from require 'alv.base'
-import pack from require 'oscpack'
+import Op, PureOp, Constant, SigStream, Input, T, sig, evt from require 'alv.base'
+import new_message, add_item from require 'alv-lib._osc'
import dns, udp from require 'socket'
unpack or= table.unpack
@@ -29,56 +29,41 @@ connect = Constant.meta
send = Constant.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.
+ summary: "Send an OSC message."
+ examples: { '(osc/send [socket] path val…)' }
+ description: "Sends an OSC message to `path` with `val…` as arguments.
- `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 = -sig['udp/socket'] + sig.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
+- the arguments can be any type:
+ - `num` will be sent as `f`
+ - `str` will be sent as `s`
+ - `bool` will be sent as `T`/`F`
+ - `bang` will be sent as `T`
+ - arrays will be unwrapped
+ - structs will be sent as a series of key/value tuples
- tick: =>
- { :socket, :path, :value } = @unwrap_all!
- if value
- msg = pack path, if 'table' == type value then unpack value else value
- socket\send msg
+This is a pure op, so between the values at most one !-stream input is allowed."
-sync = Constant.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.
+ value: class extends PureOp
+ pattern: (evt! / sig!)^0
-- `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 = -sig['udp/socket'] + sig.str + sig!
+ full_pattern = -sig['udp/socket'] + sig.str + (evt! / sig!)^0
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
+ { socket, path, values } = full_pattern\match inputs
+ super values, scope, {
+ socket: Input.cold socket or scope\get '*sock*'
+ path: Input.cold path
+ }
tick: =>
- { :socket, :path, :value } = @unwrap_all!
- msg = pack path, if 'table' == type value then unpack value else value
- socket\send msg
+ args = @unwrap_all!
+ { :socket, :path } = args
+ msg = new_message path
+ for i=1,#args
+ add_item msg, @inputs[i]\type!, args[i]
+ socket\send msg.pack msg.content
Constant.meta
meta:
diff --git a/alv-lib/sc.moon b/alv-lib/sc.moon
index fbc4588..16d8fa0 100644
--- a/alv-lib/sc.moon
+++ b/alv-lib/sc.moon
@@ -1,81 +1,88 @@
-import Op, Constant, Input, sig, evt from require 'alv.base'
-import pack from require 'oscpack'
-import dns, udp from require 'socket'
+import Op, Constant, Input, Array, Struct, T, sig, evt from require 'alv.base'
+import new_message, add_item from require 'alv-lib._osc'
unpack or= table.unpack
-play = Constant.meta
+validate_ctrls = (type) ->
+ switch type.__class
+ when Array
+ assert (type.type == T.num) or (type.type == T.str),
+ "synthdef control values have to be either num or str"
+ when Struct
+ for k, t in pairs type.types
+ assert (t == T.num) or (t == T.str),
+ "synthdef control value '#{k}' has to be either num or str"
+
+play_ = Constant.meta
meta:
- name: 'play'
+ name: 'play!'
summary: 'Play a SuperCollider SynthDef on bangs.'
- examples: { '(play [socket] synth trig [param val…])' }
+ examples: { '(play [socket] synth trig ctrls)' }
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."
+- `trig` is the trigger signal. It should be a !-stream of bang-events.
+- `ctrls` is a struct of synthdef controls. It should be a ~-stream."
value: class extends Op
- pattern = -sig['udp/socket'] + sig.str + evt.bang + (sig.str + sig.num)\rep 0
+ pattern = -sig['udp/socket'] + sig.str + evt.bang + sig!
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
+ validate_ctrls ctrls\type!
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]
+ ctrls: Input.cold 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
+ { :socket, :synth, :ctrls } = @unwrap_all!
+ msg = new_message '/s_new'
+ msg\add 's', synth
+ msg\add 'i', -1
+ msg\add 'i', 0
+ msg\add 'i', 1
+ add_item msg, @inputs.ctrls\type!, ctrls
+ socket\send msg.pack msg.content
-play_ = Constant.meta
+
+play = Constant.meta
meta:
- name: 'play!'
+ name: 'play'
summary: 'Play a SuperCollider SynthDef on events.'
- examples: { '(play [socket] synth [param evt/val…])' }
+ examples: { '(play [socket] synth ctrls)' }
description: "
-Plays the synth `synth` on the `udp/socket` `socket` whenever any `evt` is live.
+Plays the synth `synth` on the `udp/socket` `socket` whenever an event arrives.
- `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."
+- `ctrls` is a struct of synthdef controls. It should be a !-stream."
value: class extends Op
- pattern = -sig['udp/socket'] + sig.str + (sig.str + (sig.num / evt.num))\rep 0
+ pattern = -sig['udp/socket'] + sig.str + evt!
setup: (inputs, scope) =>
- { socket, synth, trig, ctrls } = pattern\match inputs
+ { socket, synth, 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
+ validate_ctrls ctrls\type!
super
socket: Input.cold socket or scope\get '*sock*'
synth: Input.cold synth
- ctrls: flat
+ ctrls: Input.hot ctrls
tick: =>
{ :socket, :synth, :ctrls } = @unwrap_all!
- msg = pack '/s_new', synth, -1, 0, 1, unpack ctrls
- socket\send msg
+ msg = new_message '/s_new'
+ msg\add 's', synth
+ msg\add 'i', -1
+ msg\add 'i', 0
+ msg\add 'i', 1
+ add_item msg, @inputs.ctrls\type!, ctrls
+ socket\send msg.pack msg.content
Constant.meta
meta: