プログラムで音を鳴らしたことのある方なら、覚えがあるかもしれません。サイン波を作って、440Hz、音量もほどほどに設定して再生する。すると聞こえてくるのは「ピー」という、体温計の電子音のような味気ない音です。周波数は合っている。音量も合っている。それなのに、どうやっても「楽器の音」に聞こえない。

まず足りないのは、波形の複雑さではありません。じつは同じサイン波のまま、あるひとつの要素を変えるだけで、その「ピー」の性格はがらりと変わり、オルガン風、ピアノ風、ストリングス風と、楽器の「らしさ」の方向がはっきり聞き分けられるようになります。変えるのは音量の時間変化、つまり音の鳴りはじめから消えるまでの「輪郭」です。

本題に入る前に、少しだけこの連載のことを。楽器の音そのものをプログラムで作る技術はサウンドプログラミングと呼ばれますが、書籍も事例も昔からとても少ない分野です。筆者は10年以上前、自作の音感トレーニングアプリ Harmonize にピアノやオルガンの音を持たせる必要に迫られて、数少ないC言語の教科書を頼りにソフトシンセを組み上げました。このアプリで鳴る楽器音は録音の再生ではなく、今もすべてプログラムがその場で合成しています。

そのとき夢中で学んだ仕組みは、いま読み返しても色あせずに面白いので、頭の整理を兼ねて、音の鳴るデモを添えながら少しずつ記事にしていくことにしました。第1回に選んだのは、仕組みの単純さのわりに効果が劇的な、この「輪郭」の話です。

耳は波形より「輪郭」を聴いている

楽器の音をレコーダーで録って波形を眺めると、二つの層が見えます。ひとつは中身の細かい振動。1秒間に数百回も揺れる波そのもので、これが音の高さや音色の成分を担います。もうひとつは、その振動を外側から包む大きなふくらみ、音量の移り変わりです。

同じサイン波に3種類の輪郭をかぶせた図。オルガンは矩形、ピアノは鋭い立ち上がりから減衰、ストリングスはゆっくり膨らんでゆっくり消える

上の図は、中身の波をぜんぶ同じサイン波にそろえて、外側の輪郭だけを取り替えたものです。左は鳴らしている間ずっと同じ大きさを保ち、離した瞬間すっと消える。これはオルガンやリコーダーの鳴り方です。真ん中は叩いた瞬間がいちばん大きく、あとはただ減っていく。鍵盤を押さえたままでも音がだんだん消えていく、ピアノの鳴り方です。右はふわっと立ち上がって、指を離してもふわっと余韻が残る。ストリングスやシンセパッドの鳴り方です。

中身が同じでも、この輪郭が違えば、耳は別の系統の音だと聞き分けます。逆もまた然りで、楽器音の録音から立ち上がりの部分を切り落として聴かせると、何の楽器か当てるのが急に難しくなることが古くから知られています。音色というと倍音の配合、つまり波形の中身を思い浮かべますが、楽器の「顔」の第一印象を決めているのは、それと同じくらい、この音量の時間変化なのです。

ただし、正直に言っておくと、輪郭が担うのは音の顔の半分です。もう半分は、やはり波形の中身、倍音の配合が握っています。サイン波は倍音をひとつも持たない、いわば具のないスープのような素朴きわまりない波なので、輪郭をどれだけ作り込んでも「ピアノらしい鳴り方」「ストリングスらしい鳴り方」という性格までしか近づけません。本物のピアノの太い響きや弦楽器のつやを出すには、ノコギリ波のような倍音たっぷりの波形が要ります。このあとのデモでも、どのプリセットも系統ははっきり聞き分けられるのに、本物と呼ぶには物足りないはずです。その物足りなさの正体が倍音で、これはこの連載で回をあらためて取り上げます。今回は「中身が最弱のサイン波ですら、輪郭だけでここまで性格が変わる」という、輪郭の効きの大きさを確かめるのが主題です。

この輪郭のことを、サウンドプログラミングではエンベロープと呼びます。英語で封筒のことで、波を外から包み込む線だからです。冒頭の「ピー」が楽器に聞こえなかった理由も、これで説明がつきます。あの音にはエンベロープがなかった、正確には「スイッチを入れた瞬間に最大、切った瞬間にゼロ」という長方形の輪郭しかなかったのです。長方形の輪郭を持つ楽器は自然界にほぼ存在しないので、耳は機械の音だと判定します。

輪郭を4つの数で描く ── ADSR

では、その輪郭をプログラムでどう表すか。世界中のシンセサイザーが採用している定番の型があります。頭文字をとって ADSR と呼ばれる、たった4つの数です。

ADSRの構造図。押した瞬間からA(アタック)で最大まで立ち上がり、D(ディケイ)でサステインレベルまで落ち着き、押している間S(サステイン)の高さを保ち、離すとR(リリース)で消える

鍵盤を押すと、音量はゼロから最大まで駆け上がります。この立ち上がりにかける時間がアタック(A)。最大に達したあと、少し落ち着いて巡航高度に降りてくるまでの時間がディケイ(D)。そのまま押し続けている間に保たれる音量がサステイン(S)。そして指を離してから音が消えるまでの余韻の時間がリリース(R)です。

ここでひとつだけ、つまずきやすい点を先に押さえておきます。A・D・R は「時間」ですが、S だけは「高さ」です。サステインは押している間じゅうずっと続くので、何秒という長さを持ちません。持つのは「最大の何割の音量で鳴り続けるか」という水位だけ。ADSR のつまみが4本並んでいるとき、3本は秒数で1本だけパーセントなのは、このためです。

この4つの数で、さきほどの3つの輪郭がそのまま書けます。オルガンはアタックほんの数ミリ秒、サステイン100%。押した瞬間から離す瞬間まで一定で鳴る、ほぼ長方形の輪郭です。ピアノはアタック数ミリ秒、ディケイたっぷり1秒あまり、そしてサステイン0%。押しっぱなしでも行き着く先がゼロなので、音は自然に消えていきます。ストリングスはアタックに数百ミリ秒かけてふわっと入り、サステイン7割ほどで歌い、リリースにもたっぷり時間をとって余韻を残す。輪郭の言葉に翻訳すると、楽器の個性が4つの数字に畳み込まれるのです。

減り方は「まっすぐ」より「割合」が自然

もうひとつ、輪郭の質感を決める隠し味があります。ディケイやリリースで音が減っていくとき、どんなカーブで減るかです。

直線の減衰と指数カーブの減衰の比較。指数カーブは最初にぐっと減って残りを長く引きずる

いちばん素直なのは直線で減らすことですが、これを耳で聴くと、機械がフェーダーを一定速度で下げているような、妙に人工的な感じがします。実際のピアノの弦や鐘の余韻は、毎瞬「いま残っている音量の同じ割合」ずつ減っていきます。最初にぐっと減って、小さくなってからは長々と尾を引く。グラフに描くと上の図の青い線、いわゆる指数カーブです。人間の耳は音量を割合で感じ取る性質があるので、割合で減る音は「一定のペースで静かになっていく」と聞こえて、これが自然に響きます。

冒頭で紹介した Harmonize のソフトシンセも、エンベロープはこの指数カーブで実装しています。さらにピアノ音色では、音量だけでなく音の明るさ(フィルタ)にも同じ形のエンベロープを掛けていて、鳴った瞬間だけ倍音が豊かで、減衰とともにこもっていくという本物のピアノの振る舞いを真似ています。エンベロープは音量専用の道具ではなく、明るさや音程など「時間とともに変わってほしいもの」全般に掛けられる、汎用の輪郭なのです。

プログラムではこう書く

では、これを実際にどう実現するのか。仕組みは拍子抜けするほど単純で、1サンプルごとに、波形の値へエンベロープの値を掛けるだけです。44100分の1秒ごとに $\text{出力} = \text{env} \times \sin(\cdot)$ という掛け算を繰り返す。サウンドプログラミングとしての本体は、この $\text{env}$ という変数(0〜1)を時間とともにどう動かすかに尽きます。

まず「毎瞬、同じ割合で減る」という指数カーブを数式にすると、音量 $V$ は時定数 $\tau$(タウ、減衰の速さを決める秒数)を使って

$$V(t) = V_0 e^{-t/\tau}$$

と書けます。「残っている量に比例して減る」($dV/dt = -V/\tau$)という関係の解が、ちょうどこの形になります。そしてこれをプログラムに落とすときは、指数関数を毎回計算する必要はありません。「目標値との差を、毎サンプル一定の割合だけ詰める」という1行が、そのまま指数カーブになります。

/* 教科書式のエンベロープ処理(C風の擬似コード) */
for (n = 0; n < length; n++) {
    env += (target - env) * coef;                     /* 目標へ指数カーブで近づく */
    output[n] = env * sin(2.0 * M_PI * f0 * n / fs);  /* 波形に掛けるだけ */
}

面白いのは、A・D・S・R の4局面がぜんぶこの同じ1行で回ることです。鍵盤が押されたら target = 1.0(アタック)、最大に達したら target = サステイン値(ディケイ)、離されたら target = 0.0(リリース)。切り替えるのは目標値だけで、カーブの計算は一切変わりません。近づく速さは coef が受け持ち、時定数 $\tau$ とサンプリング周波数 $f_s$ から $\text{coef} = 1 - e^{-1/(f_s \tau)}$ と決めます(小さいほどゆっくり)。なお、立ち上がりだけは直線にする実装もよくあります。アタックは時間が短く、カーブの違いが耳ではほとんど分からないからです。

ブラウザの Web Audio API なら、この仕組みがさらに一段ラップされていて、音量パラメータに「いつ・どの目標へ・どのカーブで」を予約するだけで済みます。このあとのデモの心臓部は、実質この数行です。

const g = gainNode.gain, t = audioCtx.currentTime;
g.setValueAtTime(0, t);
g.linearRampToValueAtTime(1.0, t + A);  // A: 直線で最大へ
g.setTargetAtTime(S, t + A, D / 4);     // D: 指数カーブでサステインへ
// 鍵盤を離した瞬間に
g.setTargetAtTime(0, audioCtx.currentTime, R / 4);  // R: 指数カーブでゼロへ

setTargetAtTime の第3引数がさきほどの時定数 $\tau$ です。指数カーブは理論上いつまでもゼロに着かないので、「体感の秒数の4分の1」を渡すのが定番の目安で、経過時間が $4\tau$ になったところで約98%減衰し、耳にはほぼ消えたと感じられます。デモの D と R もこの換算で動いています。

触ってみる

ここまでの話を、実際に耳で確かめられるデモを用意しました。鳴るのは終始ただの440Hzのサイン波で、変わるのは ADSR の4つのつまみだけです。プリセットをブザー→オルガン→ピアノ→ストリングスと切り替えて、同じ波形の性格が入れ替わるのを聴いてみてください。本物の楽器にはまだ遠いこと、それでも系統ははっきり聞き分けられること、その両方を確かめるのがこのデモの狙いです。いちばん下の欄には、実際に鳴った音量の輪郭がそのまま流れていきます。

うまく表示されないときは、デモを別タブで開く

ピアノのプリセットで押しっぱなしにしたとき、音が勝手に減っていくのがわかるはずです。連打すればそれらしく弾んで聞こえます。ストリングスで一瞬だけ触れると、立ち上がりが間に合わずに小さな音しか出ない ── 本物の弦楽器で速いパッセージが軽く聞こえるのと同じ現象も起きます。そしてブザー(輪郭なし)にすると、鳴りはじめと終わりに「プチッ」というノイズが混ざるのに気づくと思います。音量が一瞬でジャンプすると、波形に段差ができてこの雑音が生まれます。エンベロープには、音を楽器らしくするだけでなく、この段差をなめらかにならして雑音を防ぐという実務的な役割もあるのです。

どこで使われているか

ADSR は1960年代のモーグ・シンセサイザーの頃に定着した型ですが、いまも現役どころか、音の出るソフトウェアのほぼすべてに入っています。DAW のソフトシンセにはまず間違いなく ADSR のつまみが並んでいますし、ゲームエンジンの効果音まわり、スマホの通知音のデザインでも、立ち上がりと余韻の設計がそのまま印象を左右します。曲の終わりのフェードアウトや、動画編集の音のクロスフェードも、大きな時間スケールで掛けたエンベロープの親戚です。「音量を時間の関数として設計する」という考え方ひとつ持っておくと、音を扱う場面のあちこちで顔を出します。

参考文献

  • 青木直史『サウンドプログラミング入門――音響合成の基本とC言語による実装 』技術評論社(2013)。加算合成・アナログシンセサイザ・FM音源といった音作りの方式をC言語の実装つきで解説する、数少ない日本語の定番書。ADSRエンベロープもここで学べます。
  • 青木直史『C言語ではじめる音のプログラミング――サウンドエフェクトの信号処理 』オーム社(2008)。同じ著者による姉妹編で、こちらはディレイ・フィルタ・歪みなどエフェクト側の信号処理を扱います。合わせて読むと音作りの両輪がそろいます。
  • R. A. Moog, “Voltage-Controlled Electronic Music Modules,” Journal of the Audio Engineering Society, vol. 13, no. 3 (1965), pp. 200–206。電圧制御シンセサイザーとエンベロープ・ジェネレーターの古典。概説は Wikipedia: Envelope (music)
  • E. L. Saldanha and J. F. Corso, “Timbre Cues and the Identification of Musical Instruments,” The Journal of the Acoustical Society of America, vol. 36, no. 11 (1964), pp. 2021–2026. DOI: 10.1121/1.1919317 。立ち上がり部分が楽器の聴き分けの重要な手がかりであることを示した実験。
  • デモの実装には Web Audio API を使用。エンベロープは AudioParam.setTargetAtTime (指数カーブ)で掛けています。

数の列に輪郭をひとつかぶせるだけで、ブザーが楽器の顔を持ちはじめる。まずはデモで、その変わりぶりを耳で確かめてみてください。