67 lines
2 KiB
Text
67 lines
2 KiB
Text
// Plucked string (Karplus-Strong), in tune at every pitch: the loop is one
|
|
// period minus the averaging filter's half sample, with the fraction in a
|
|
// first-order allpass; the excitation is a filtered noise burst minus its
|
|
// copy at the pluck position (the comb a real pluck makes); the loop loss
|
|
// gives the same T60 at every pitch.
|
|
let MAX = 4096
|
|
let bright = param(0.6, 0, 1)
|
|
let position = param(0.22, 0.05, 0.5)
|
|
let t60 = param(3.0, 0.2, 12)
|
|
let damp = param(0.15, 0, 0.9)
|
|
let gain = param(0.6, 0, 1)
|
|
|
|
var buf = [0.0; MAX]
|
|
var ex = [0.0; MAX]
|
|
var w = int(0)
|
|
var len = int(1)
|
|
var comb = int(1)
|
|
var t = int(0)
|
|
var ap = Allpass1{}
|
|
var c = 0.0
|
|
var avg = 0.0
|
|
var lp = 0.0
|
|
var loss = 0.99
|
|
var burst = 0.0
|
|
var amp = 1.0
|
|
|
|
fn voice() {
|
|
if trigger {
|
|
// One period, minus the averaging filter's half sample and the
|
|
// damping low-pass's phase delay at the fundamental.
|
|
let w0 = TAU * freq / sample_rate
|
|
let lp_delay = atan2(damp * sin(w0), 1.0 - damp * cos(w0)) / w0
|
|
let p = sample_rate / freq - 0.5 - lp_delay
|
|
let d = p - floor(p)
|
|
len = int(floor(p))
|
|
if d < 0.1 {
|
|
len = len - 1
|
|
d = d + 1.0
|
|
}
|
|
c = (1.0 - d) / (1.0 + d)
|
|
comb = max(int(position * p), 1)
|
|
loss = exp(-3.0 * log(10.0) / (freq * t60))
|
|
t = 0
|
|
amp = 1.0
|
|
}
|
|
let noise = if t < len { rand() } else { 0.0 }
|
|
burst = burst + (noise - burst) * (0.08 + 0.92 * bright * velocity)
|
|
let b = if t < len { burst } else { 0.0 }
|
|
ex[t] = b
|
|
let input = if t < len + comb { b - ex[t - comb] } else { 0.0 }
|
|
t = min(t + 1, MAX)
|
|
let y = allpass1(ap, buf[w - len], c)
|
|
let s = (y + avg) * 0.5
|
|
avg = y
|
|
// Extra damping darkens the tail (a one-pole in the loop).
|
|
lp = lp + (s - lp) * (1.0 - damp)
|
|
let out = lp * loss + input
|
|
buf[w] = out
|
|
w = w + 1
|
|
if gate == 0.0 {
|
|
amp = amp * exp(-1.0 / (0.15 * sample_rate))
|
|
if amp < 0.0001 {
|
|
stop()
|
|
}
|
|
}
|
|
out * amp * gain * (0.4 + 0.6 * velocity)
|
|
}
|