git.s-ol.nu alive / b2da01c alv-lib / osc.moon
b2da01c

Tree @b2da01c (Download .tar.gz)

osc.moon @b2da01craw · history · blame

import Op, PureOp, Constant, Input, T, sig, any from require 'alv.base'
import new_message, add_item from require 'alv-lib._osc'
import dns, udp from require 'socket'

unpack or= table.unpack

connect = Constant.meta
  meta:
    name: 'connect'
    summary: "Create a UDP remote."
    examples: { '(osc/connect host port)' }

  value: class extends Op
    pattern = sig.str + sig.num
    setup: (inputs) =>
      { host, port } = pattern\match inputs
      super
        host: Input.hot host
        port: Input.hot port

      @setup_out '~', T['udp/socket']

    tick: =>
      { :host, :port } = @unwrap_all!
      ip = dns.toip host

      @out\set with sock = udp!
        \setpeername ip, port

send = Constant.meta
  meta:
    name: 'send'
    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.
- 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

This is a pure op, so between the values at most one !-stream input is allowed."

  value: class extends PureOp
    pattern: any!^0

    full_pattern = -sig['udp/socket'] + sig.str + any!^0
    setup: (inputs, scope) =>
      { socket, path, values } = full_pattern\match inputs
      super values, scope, {
        socket: Input.cold socket or scope\get '*sock*'
        path:   Input.cold path
      }

    tick: =>
      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

send_arr = Constant.meta
  meta:
    name: 'send-arr'
    summary: "Send an OSC message using arrays."
    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.
- 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 sent as a series of values surrounded by `[…]`
  - structs will be sent as a series of key (`s`)/value tuples surrounded by `[…]`

This is a pure op, so between the values at most one !-stream input is allowed."

  value: class extends PureOp
    pattern: any!^0

    full_pattern = -sig['udp/socket'] + sig.str + any!^0
    setup: (inputs, scope) =>
      { socket, path, values } = full_pattern\match inputs
      super values, scope, {
        socket: Input.cold socket or scope\get '*sock*'
        path:   Input.cold path
      }

    tick: =>
      args = @unwrap_all!
      { :socket, :path } = args
      msg = new_message path
      for i=1,#args
        add_item msg, @inputs[i]\type!, args[i], true
      socket\send msg.pack msg.content

Constant.meta
  meta:
    name: 'osc'
    summary: "OSC integration."

  value:
    :connect
    :send
    :sync