-
Notifications
You must be signed in to change notification settings - Fork 0
/
keysampler.go
216 lines (169 loc) · 4.94 KB
/
keysampler.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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
package jlsampler
import (
"errors"
"math"
)
// ----------------------------------------------------------------------------
type KeySampler struct {
controls *Controls // Controls!
Key int // The midi key number.
on bool // True if key is on (down).
layers []*SampleLayer // The sample layers.
// A slice of playing samples. The length is the number of playing samples.
playing []*PlayingSample
}
func NewKeySampler(controls *Controls, key int) *KeySampler {
ks := new(KeySampler)
ks.controls = controls
ks.Key = key
ks.on = false
ks.playing = make([]*PlayingSample, 0, 128)
return ks
}
func (ks *KeySampler) Copy() *KeySampler {
ks2 := NewKeySampler(ks.controls, ks.Key)
for i := 0; i < len(ks.layers); i++ {
ks2.layers = append(ks2.layers, ks.layers[i].Copy())
}
return ks2
}
func (ks *KeySampler) AddLayer() {
ks.layers = append(ks.layers, new(SampleLayer))
}
func (ks *KeySampler) NumLayers() int {
return len(ks.layers)
}
func (ks *KeySampler) AddSample(sample *Sample, layer int) {
ks.layers[layer].AddSample(sample)
}
func (ks *KeySampler) BorrowFrom(ks2 *KeySampler) error {
// Make sure both KeySamplers have the same number of layers.
if len(ks.layers) != len(ks2.layers) {
return errors.New("Borrowing requires the same number of layers.")
}
Println("Borrowing samples:", ks.Key, "<-", ks2.Key)
// Compute the amount of stretching necessary.
semitones := ks.Key - ks2.Key
for i := 0; i < len(ks.layers); i++ {
layer := ks.layers[i]
layer2 := ks2.layers[i]
layer.BorrowFrom(layer2, semitones)
}
return nil
}
func (ks *KeySampler) Transpose(trans int) *KeySampler {
ks2 := new(KeySampler)
ks2.controls = ks.controls
ks2.Key = ks.Key + trans
ks2.layers = make([]*SampleLayer, 0)
for _, layer := range ks.layers {
ks2.layers = append(ks2.layers, layer.Transpose(trans))
}
ks2.playing = make([]*PlayingSample, 0, cap(ks.playing))
return ks2
}
// TODO: Clean up this code.
func (ks *KeySampler) getPlayingSample(velocity float64) *PlayingSample {
if ks.controls.MixLayers {
return ks.getPlayingSampleMix(velocity)
} else {
return ks.getPlayingSampleBasic(velocity)
}
}
func (ks *KeySampler) getPlayingSampleBasic(velocity float64) *PlayingSample {
numLayers := int64(len(ks.layers))
// Get the layer.
layer := int64(
float64(numLayers) * math.Pow(velocity, ks.controls.GammaLayer))
if layer > numLayers-1 {
layer = numLayers - 1
}
// Get a sample from the first layer.
_, sample := ks.layers[layer].GetSample(-1)
// Compute the amplitude of the sample.
amp := ks.controls.CalcAmp(ks.Key, velocity, sample.Rms)
// Compute the pan.
pan := ks.controls.CalcPan(ks.Key)
return NewPlayingSample(ks.controls, sample, nil, amp, 0, pan, 0)
}
func (ks *KeySampler) getPlayingSampleMix(velocity float64) *PlayingSample {
numLayers := int64(len(ks.layers))
layerVal := float32(
float64(numLayers-1) * math.Pow(velocity, ks.controls.GammaLayer))
layer1 := int64(layerVal)
layer2 := layer1 + 1
if layer2 > numLayers-1 {
layer2 = numLayers - 1
}
mix := layerVal - float32(layer1)
// Samples.
sIdx, sample1 := ks.layers[layer1].GetSample(-1)
_, sample2 := ks.layers[layer2].GetSample(sIdx)
// Amps.
amp1 := ks.controls.CalcAmp(ks.Key, velocity, sample1.Rms)
amp2 := ks.controls.CalcAmp(ks.Key, velocity, sample2.Rms)
// Compute pan.
pan := ks.controls.CalcPan(ks.Key)
return NewPlayingSample(ks.controls, sample1, sample2, amp1, amp2, pan, mix)
}
func (ks *KeySampler) NoteOn(velocity float64) {
ks.on = true
// Loop through playing samples. All currently playing samples should
// decay with constant tauCut.
if ks.controls.TauCut != 0 {
for _, ps := range ks.playing {
ps.tau = float32(ks.controls.TauCut)
}
}
// Add a new playing sample.
ks.playing = append(ks.playing, ks.getPlayingSample(velocity))
}
func (ks *KeySampler) NoteOff() {
ks.on = false
// If sustaining, there's nothing to do.
if ks.controls.Sustain {
return
}
// Loop through playing sounds. If any aren't decaying, then
// they need to have tau set.
if ks.controls.Tau != 0 {
for _, ps := range ks.playing {
if ps.tau == 0 {
ps.tau = float32(ks.controls.Tau)
}
}
}
}
func (ks *KeySampler) HasData() bool {
return len(ks.playing) != 0
}
func (ks *KeySampler) WriteOutput(buf *Sound, amp, di []float32) {
var ps *PlayingSample
// Check for sustain pedal depressed.
ps = ks.playing[len(ks.playing)-1]
if ks.controls.Sustain && ps.tau != 0 {
ps.tau = 0
}
iIn := 0
for _, ps = range ks.playing {
// Check for sustain pedal lift.
if !ks.on && !ks.controls.Sustain && ps.tau == 0 {
ps.tau = float32(ks.controls.Tau)
}
if ps.WriteOutput(buf, amp, di) {
ks.playing[iIn] = ps
iIn++
}
}
ks.playing = ks.playing[:iIn]
}
func (ks *KeySampler) UpdateCropThresh(thresh float64) {
for _, sl := range ks.layers {
sl.UpdateCropThresh(thresh)
}
}
func (ks *KeySampler) UpdateRms(rmsTime float64) {
for _, sl := range ks.layers {
sl.UpdateRms(rmsTime)
}
}