aboutsummaryrefslogtreecommitdiffstats
path: root/alv-lib/sc.moon
blob: 16d8fa090bdc206a5b62ab716a6c89b39bc00805 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
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

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!'
    summary: 'Play a SuperCollider SynthDef on bangs.'
    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.
- `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!
    setup: (inputs, scope) =>
      { socket, synth, trig, ctrls } = pattern\match inputs

      validate_ctrls ctrls\type!

      super
        trig:   Input.hot trig
        socket: Input.cold socket or scope\get '*sock*'
        synth:  Input.cold synth
        ctrls:  Input.cold ctrls

    tick: =>
      { :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
  meta:
    name: 'play'
    summary: 'Play a SuperCollider SynthDef on events.'
    examples: { '(play [socket] synth ctrls)' }
    description: "
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.
- `ctrls` is a struct of synthdef controls. It should be a !-stream."
  value: class extends Op
    pattern = -sig['udp/socket'] + sig.str + evt!
    setup: (inputs, scope) =>
      { socket, synth, ctrls } = pattern\match inputs

      validate_ctrls ctrls\type!

      super
        socket: Input.cold socket or scope\get '*sock*'
        synth:  Input.cold synth
        ctrls:  Input.hot ctrls

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

Constant.meta
  meta:
    name: 'sc'
    summary: "SuperCollider integration."

  value:
    :play
    'play!': play_