aboutsummaryrefslogtreecommitdiffstats
path: root/lib/util.moon
blob: a2c65ba98ef0eb228be4c4bba8b43f17421581d9 (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
95
96
97
98
99
100
101
102
103
104
105
106
import Op, Value, Input, Error, match from require 'core.base'

all_same = (list) ->
  for v in *list[2,]
    if v != list[1]
      return false

  list[1]

switch_ = Value.meta
  meta:
    name: 'switch'
    summary: "Switch between multiple inputs."
    examples: { '(switch i v0 [v1 v2…])' }
    description: "
- 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 [math/floor][]ed and the matching argument
  (indexed starting from 0) is reproduced."

  value: class extends Op
    setup: (inputs) =>
      { i, values } = match 'any *any', inputs

      i_type = i\type!
      assert i_type == 'bool' or i_type == 'num', Error 'argument', "i has to be bool or num"
      typ = all_same [v\type! for v in *values]
      @out = Value typ if not @out or typ != @out.type

      super
        i: Input.value i
        values: [Input.value v for v in *values]

    tick: =>
      { :i, :values } = @inputs
      active = switch i!
        when true
          values[1]
        when false
          values[2]
        else
          i = 1 + (math.floor i!) % #values
          values[i]
      @out\set active and active!

route = Value.meta
  meta:
    name: 'route'
    summary: "Route between multiple inputs."
    examples: { '(route i v0 [e1 e2…])' }
    description: "
- when `i` is `true`, the first event stream is reproduced.
- when `i` is `false`, the second event stream is reproduced.
- when `i` is a `num`, it is [math/floor][]ed and the matching argument
  (indexed starting from 0) is reproduced."

  value: class extends Op
    setup: (inputs) =>
      { i, values } = match 'any *any', inputs

      i_type = i\type!
      assert i_type == 'bool' or i_type == 'num', Error 'argument', "i has to be bool or num"
      typ = all_same [v\type! for v in *values]
      @out = Value typ if not @out or typ != @out.type

      super
        i: Input.value i
        values: [Input.value v for v in *values]

    tick: =>
      { :i, :values } = @inputs
      active = switch i!
        when true
          values[1]
        when false
          values[2]
        else
          i = 1 + (math.floor i!) % #values
          values[i]
      if active and active\dirty!
        @out\set active!

route = Value.meta
  meta:
    name: 'edge'
    summary: "Convert rising edges to bangs."
    examples: { '(edge bool)' }

  value: class extends Op
    new: => super 'bang'

    setup: (inputs) =>
      { value } = match 'bool', inputs
      super value: Input.value value

    tick: =>
      now = @inputs.value!
      if now and not @state.last
        @out\set true
        @state.last = now

{
  'switch': switch_
  :route
  :edge
}