From dbdfb1364c91d4905d3f0c947bf150d25ce0c817 Mon Sep 17 00:00:00 2001 From: s-ol Date: Sun, 31 Jan 2021 00:01:51 +0100 Subject: lib: switch to losc --- README.md | 4 +-- alv-lib/_osc.moon | 33 ++++++++++++++++++++++ alv-lib/osc.moon | 69 ++++++++++++++++++--------------------------- alv-lib/sc.moon | 83 +++++++++++++++++++++++++++++------------------------- dist/release.bat | 1 - dist/release.sh | 1 + docs/gen/shim.moon | 2 +- shell.nix | 24 ++++++++++++++-- 8 files changed, 130 insertions(+), 87 deletions(-) create mode 100644 alv-lib/_osc.moon diff --git a/README.md b/README.md index cd955ad..7e35733 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ processes. For more information, visit the full [online documentation][docs]. - [LPeg][lpeg]*: `luarocks install lpeg` - [socket][socket]: `luarocks install luasocket` - [system][system]: `luarocks install luasystem` -- [oscpack][oscpack]: `luarocks install oscpack` (optional) +- [losc][losc]: `luarocks install losc` (optional) - [lua-rtmidi][rtmidi]: `luarocks install https://raw.githubusercontent.com/s-ol/lua-rtmidi/master/lua-rtmidi-dev-1.rockspec` (optional) - [busted][busted]: `luarocks install busted` (optional, for tests) @@ -54,7 +54,7 @@ development, simply pass the files as arguments: [moonscript]: https://moonscript.org/ [lfs]: https://keplerproject.github.io/luafilesystem/ [lpeg]: http://www.inf.puc-rio.br/~roberto/lpeg/ -[oscpack]: https://github.com/s-ol/lua-oscpack +[losc]: https://github.com/davidgranstrom/losc [system]: https://github.com/o-lim/luasystem [socket]: http://w3.impa.br/~diego/software/luasocket/ [rtmidi]: https://github.com/s-ol/lua-rtmidi/ 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: diff --git a/dist/release.bat b/dist/release.bat index 7224e7a..b8fe7e1 100644 --- a/dist/release.bat +++ b/dist/release.bat @@ -19,7 +19,6 @@ xcopy /E /I dist\win\wrappers\* dist\%BUNDLE%\ cd dist\%BUNDLE%\lua call luarocks install busted -call luarocks install %DEPS%\osc-1.0.1-1.rockspec call luarocks install luarocks-fetch-gitrec call luarocks install luarocks-build-cpp call luarocks install %DEPS%\fltk4lua-0.1-1.rockspec FLTK_LIBDIR=%DEPS%\fltk-1.3.5\lib FLTK_INCDIR=%DEPS%\fltk-1.3.5 diff --git a/dist/release.sh b/dist/release.sh index a9b817a..811ddb2 100755 --- a/dist/release.sh +++ b/dist/release.sh @@ -91,6 +91,7 @@ dependencies = { "luafilesystem", "luasystem", "luasocket", + "losc", } build = { diff --git a/docs/gen/shim.moon b/docs/gen/shim.moon index 2a69f52..46da0ac 100644 --- a/docs/gen/shim.moon +++ b/docs/gen/shim.moon @@ -4,7 +4,7 @@ export require require = do old_require = require - blacklist = {k, true for k in *{'oscpack', 'socket', 'system', 'luartmidi'}} + blacklist = {k, true for k in *{'losc', 'socket', 'system', 'luartmidi'}} (mod, ...) -> return {} if blacklist[mod] old_require mod, ... diff --git a/shell.nix b/shell.nix index 71a8f46..90eff5f 100644 --- a/shell.nix +++ b/shell.nix @@ -35,7 +35,7 @@ let url = "mirror://luarocks//${pname}-${version}.src.rock"; sha256 = "Dp3bKIG4swrD4+1NNtRTgyj68Di2cSUlh1r7Z2Rkzn0="; }; - propagatedBuildInputs = [ pkgs.lua5_3 pkgs.git ]; + propagatedBuildInputs = with pkgs; [ lua5_3 git ]; meta = with pkgs.stdenv.lib; { homepage = "https://github.com/siffiejoe/lua-fltk4lua/"; @@ -52,7 +52,7 @@ let url = "mirror://luarocks//${pname}-${version}.src.rock"; sha256 = "fD31FruqVriMecFcvSV4W7JRia38+bg7j3T5k5pFZec="; }; - buildInputs = with pkgs; [ pkgs.fltk libjpeg ]; + buildInputs = with pkgs; [ fltk libjpeg ]; propagatedBuildInputs = [ pkgs.lua5_3 luarocks-build-cpp luarocks-fetch-gitrec ]; meta = with pkgs.stdenv.lib; { @@ -62,6 +62,24 @@ let }; }; + losc = pkgs.lua53Packages.buildLuarocksPackage rec { + pname = "losc"; + version = "1.0.0-1"; + + src = pkgs.fetchurl { + url = "mirror://luarocks//${pname}-${version}.src.rock"; + sha256 = "MArhj51V1awF5k2zToFYEXpS2c6o8bnNDn4wLhooHos="; + }; + buildInputs = with pkgs; [ stdenv.cc.cc.lib ]; + propagatedBuildInputs = [ pkgs.lua5_3 ]; + + meta = with pkgs.stdenv.lib; { + homepage = "https://github.com/davidgranstrom/losc"; + description = "Open Sound Control (OSC) for lua/luajit with no external dependencies."; + license.fullName = "MIT"; + }; + }; + discount = pkgs.lua53Packages.buildLuarocksPackage { pname = "discount"; version = "0.4-1"; @@ -117,7 +135,7 @@ in pkgs.mkShell { buildInputs = with pkgs; [ (lua5_3.withPackages (p: with p; [ moonscript lpeg - luafilesystem luasocket luasystem fltk4lua bit32 + luafilesystem luasocket luasystem fltk4lua losc bit32 ldoc busted discount ])) ]; -- cgit v1.2.3