40 lines
1.3 KiB
Text
40 lines
1.3 KiB
Text
// Electric piano from two phase-modulation pairs: a 1:1 body whose index
|
|
// follows velocity (louder is brighter) and a ratio-14 tine ping that dies
|
|
// in ~100 ms; a gentle tremolo and a keyboard-scaled decay.
|
|
let bright = param(1.0, 0, 3)
|
|
let tine = param(0.7, 0, 2)
|
|
let decay = param(2.5, 0.2, 10)
|
|
let release = param(0.3, 0.02, 3)
|
|
let tremolo = param(0.15, 0, 1)
|
|
let gain = param(0.45, 0, 1)
|
|
|
|
var pb = 0.0
|
|
var pm = 0.0
|
|
var pt = 0.0
|
|
var trem = 0.0
|
|
var t = 0.0
|
|
var amp = Adsr{}
|
|
|
|
fn voice() {
|
|
if trigger {
|
|
t = 0.0
|
|
}
|
|
t = t + 1.0 / sample_rate
|
|
let dt = freq / sample_rate
|
|
pb = advance(pb, dt)
|
|
pm = advance(pm, dt)
|
|
pt = advance(pt, dt * 14.0)
|
|
trem = advance(trem, 5.5 / sample_rate)
|
|
// Higher notes decay faster.
|
|
let d = decay * exp2((60.0 - note) / 24.0)
|
|
let body_index = bright * velocity * (0.3 + 1.7 * exp(-t * 3.0))
|
|
let body = sin(TAU * pb + body_index * sin(TAU * pm))
|
|
let ping = sin(TAU * pb + tine * velocity * sin(TAU * pt) * exp(-t * 30.0))
|
|
let e = adsr(amp, 0.001, d, 0.0, release)
|
|
if gate == 0.0 && e == 0.0 {
|
|
stop()
|
|
}
|
|
let x = (body * 0.8 + (ping - body) * 0.35) * e * gain * (0.4 + 0.6 * velocity)
|
|
let tr = 1.0 - tremolo * 0.5 * (1.0 + sin(TAU * trem))
|
|
pan(x * tr, 0.3 * sin(TAU * trem))
|
|
}
|