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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
|
import Registry, Value, IO, Op, ValueInput, IOInput, match
from require 'core.base'
import monotime from require 'system'
class Clock extends IO
new: (@frametime) =>
@last = monotime!
@dt = 0
@is_dirty = false
tick: =>
time = monotime!
@dt = time - @last
@is_dirty = if @dt >= @frametime
@last = time
true
else
false
dirty: => @is_dirty
class clock extends Op
@doc: "(clock [fps]) - a clock source
IO that triggers other operators at a fixed frame rate.
fps defaults to 60 and has to be an eval-time constant"
new: => super 'clock'
setup: (inputs) =>
{ fps } = match 'num?', inputs
super fps: ValueInput fps or Value.num 60
tick: =>
if @inputs.fps\dirty!
@out\set Clock 1 / @inputs.fps!
class lfo extends Op
@doc: "(lfo [clock] freq [wave]) - low-frequency oscillator
oscillates between 0 and 1 at the frequency freq.
wave selects the wave shape from the following:
- sin (default)
- saw
- tri"
new: =>
super 'num'
@phase = 0
default_wave = Value.str 'sin'
setup: (inputs, scope) =>
{ clock, freq, wave } = match 'clock? num any?', inputs
super
clock: IOInput clock or scope\get '*clock*'
freq: ValueInput freq
wave: ValueInput wave or default_wave
tau = math.pi * 2
tick: =>
if @inputs.clock\dirty!
{ :clock, :freq, :wave } = @unwrap_all!
@phase += clock.dt * freq
@out\set switch wave
when 'sin' then .5 + .5 * math.cos @phase * tau
when 'saw' then @phase % 1
when 'tri' then math.abs (2*@phase % 2) - 1
else error "unknown wave type"
class ramp extends Op
@doc: "(ramp [clock] period [max]) - sawtooth lfo
ramps from 0 to max (default same as ramp) once every period seconds."
new: =>
super 'num'
@phase = 0
setup: (inputs, scope) =>
{ clock, period, max } = match 'clock? num num?', inputs
super
clock: IOInput clock or scope\get '*clock*'
period: ValueInput period
max: max and ValueInput max
tick: =>
clock_dirty = @inputs.clock\dirty!
if clock_dirty
{ :clock, :period, :max } = @unwrap_all!
max or= period
@phase += clock.dt / period
while @phase >= 1
@phase -= 1
if clock_dirty or (@inputs.max and @inputs.max\dirty!)
@out\set @phase * max
class tick extends Op
@doc: "(tick [clock] period) - count ticks
counts upwards by one every period seconds and returns the number of completed ticks."
new: =>
@phase, @count = 0, 0
super 'num', @count
setup: (inputs, scope) =>
{ clock, period } = match 'clock? num', inputs
super
clock: IOInput clock or scope\get '*clock*'
period: ValueInput period
tick: =>
if @inputs.clock\dirty!
{ :clock, :period, :max } = @unwrap_all!
@phase += clock.dt / period
while @phase >= 1
@phase -= 1
@count += 1
@out\set @count
class every extends Op
@doc: "(every [clock] period) - trigger every period seconds
returns true once every period seconds."
new: =>
super 'bang'
@phase = 0
setup: (inputs, scope) =>
{ clock, period } = match 'clock? num', inputs
super
clock: IOInput clock or scope\get '*clock*'
period: ValueInput period
tick: =>
if @inputs.clock\dirty!
{ :clock, :period, :max } = @unwrap_all!
@phase += clock.dt / period
while @phase >= 1
@phase -= 1
@out\set true
{
:clock
:lfo
:ramp
:tick
:every
}
|