-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathoperator.go
130 lines (109 loc) · 2.76 KB
/
operator.go
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
package main
import (
"strconv"
"github.com/scgolang/sc"
)
const (
defaultFreq = 440
defaultGain = 1
defaultAmt = 0
defaultAttack = 0.01
defaultDecay = 0.3
defaultSustain = 0.5
defaultRelease = 0.1
)
// Operator is a sine wave signal combined with an envelope generator.
type Operator struct {
// Freq is the oscillator frequency.
Freq sc.Input
// FreqScale is a frequency scaling parameter.
FreqScale sc.Input
// FM is the frequency modulation input.
FM sc.Input
// Amt controls the frequency modulation amount.
Amt sc.Input
// Gain is the output gain.
Gain sc.Input
// A is amp envelope attack (in seconds)
A sc.Input
// D is amp envelope decay (in seconds)
D sc.Input
// S is amp envelope sustain [0, 1]
S sc.Input
// R is amp envelope release (in seconds)
R sc.Input
// Gate trigger the envelope and holds it open while > 0
Gate sc.Input
// Done is the ugen done action
Done int
}
// defaults set default values for an operator.
func (op *Operator) defaults() {
if op.Freq == nil {
op.Freq = sc.C(defaultFreq)
}
if op.FreqScale == nil {
op.FreqScale = sc.C(1)
}
if op.Gain == nil {
op.Gain = sc.C(defaultGain)
}
if op.Amt == nil {
op.Amt = sc.C(defaultAmt)
}
if op.FM == nil {
op.FM = sc.C(0)
}
if op.A == nil {
op.A = sc.C(defaultAttack)
}
if op.D == nil {
op.D = sc.C(defaultDecay)
}
if op.S == nil {
op.S = sc.C(defaultSustain)
}
if op.R == nil {
op.R = sc.C(defaultRelease)
}
if op.Gate == nil {
op.Gate = sc.C(1)
}
}
// Rate creates a new ugen at a specific rate.
// If rate is an unsupported value this method will cause a runtime panic.
func (op Operator) Rate(rate int8) sc.Input {
// Check the rate and set defaults.
sc.CheckRate(rate)
(&op).defaults()
// Amp Envelope
adsr := sc.EnvADSR{A: op.A, D: op.D, S: op.S, R: op.R}
env := sc.EnvGen{
Env: adsr,
Gate: op.Gate,
LevelScale: op.Gain,
Done: op.Done,
}.Rate(sc.AR)
// Modulate carrier frequency with FM input.
freq := op.Freq.MulAdd(op.FreqScale, op.FM.Mul(op.Amt))
// Return the carrier.
return sc.SinOsc{Freq: freq}.Rate(sc.AR).Mul(env)
}
// NewOperator creates an operator with a specific index
// and adds synth params to a synthdef.
func NewOperator(i int, p sc.Params, gate, fm sc.Input) sc.Input {
name := "op" + strconv.Itoa(i)
return Operator{
Gate: gate,
Freq: p.Add(name+"freq", defaultFreq),
FreqScale: p.Add(name+"freqscale", 1),
Gain: p.Add(name+"gain", defaultGain),
FM: fm,
Amt: p.Add(name+"amt", defaultAmt),
A: p.Add(name+"attack", defaultAttack),
D: p.Add(name+"decay", defaultDecay),
S: p.Add(name+"sustain", defaultSustain),
R: p.Add(name+"release", defaultRelease),
Done: sc.FreeEnclosing,
}.Rate(sc.AR)
}