包絡で波形を整形する
包絡は1本の遅い曲線で、立ち上がり(attack)のあいだ 0 から 1 へ直線で上がり、そこを過ぎたら指数で 0 へ減っていく。時刻 e を入れると 0..1 の音量が返る。
// 立ち上がりは直線、あとは指数で減衰
const ampEnv = (e) => {
const attack = 14
if (e < attack) return e / attack
return Math.exp(-(e - attack) * 0.012)
}ampEnv を左から右へ並べると、鋭く立ち上がってから尾を引いて沈む音量の輪郭になる。
e < attack の枝が直線の立ち上がり、それを過ぎた枝が指数の減衰。attack が立ち上がりの長さ、0.012 の係数が尾の落ちる速さになる。
波形 sin の値そのものを別の遅い信号で掛けるのが振幅変調(amplitude modulation)。掛ける側の遅い信号が音量の輪郭で、エンベロープ(包絡)にあたる。実楽器の音量はゼロから立ち上がってほぼ指数で減衰するので、減衰部に exp(-kt) を使うと撥弦や打鍵の音に近い形になる。WebAudio では GainNode.gain を linearRampToValueAtTime / exponentialRampToValueAtTime で動かすと、この掛け算をオーディオグラフ上で実現できる。波形が音の高さと音色を、包絡がいつ鳴っていつ消えるかを担い、二つは互いに独立した因子になる。
速い sin に ampEnv を掛けると、鳴って消える一発になる。波形 × 包絡 のうち、波形が音の高さと音色を、包絡が鳴り始めと消え際を決める。
掛けた波形が、上下対称に置いた薄い包絡の輪郭にぴたりと収まる。attack を大きくすると立ち上がりが鈍り、減衰の係数を上げると尾が短くなる。carrier の 0.5 を変えると、輪郭はそのままで中の振動だけが細かくなる。波形と包絡は別々に決まり、片方を取り替えてももう片方は動かない。