デジタル画像の正体なら、多くの方が知っています。写真を拡大していくと四角いピクセルの並びが現れて、1枚の絵は結局「色を表す数の並び」だった、というあれです。では、音はどうでしょう。スマホから流れる音楽、ゲームの効果音、プログラムで鳴らす「ピー」という音。あれの正体を数で言い切れる人は、画像に比べるとぐっと少なくなります。
答えは画像と同じくらい単純です。スピーカーは、1秒に44100回、「いま膜をどれだけ押し出すか」という数を受け取って、そのとおりに膜を動かしているだけ。音の正体は、この数の列です。
スピーカーの中では、紙やフィルムでできた薄い膜が前後に動いて空気を押したり引いたりしています。この空気の振動が耳に届いたものが音です。そして膜の動きを指示しているのが、図の左上に並んだ数の列。+の数が来たら押し出し、−の数が来たら引っ込める。指示は1秒に44100回のペースで途切れなく届きます。録音した曲の再生も、プログラムがその場で作る合成音も、最後は必ずこの形になってスピーカーへ渡ります。裏を返せば、この数の列さえ自分で作れれば、どんな音でも鳴らせるということです。
この記事では、その一番小さな実例として、サイン波を数式から作って鳴らすところまでをやります。ここで連載の案内を少しだけ。当ブログでは、楽器の音をプログラムで作る仕組みを音の鳴るデモつきで紹介するシリーズを続けていて、エンベロープ やカープラス・ストロング の回では、今回の「音=数の列」を毎回さらっと前提にしてきました。今回はその土台を一本で正面から扱います。筆者は個人で音感トレーニングアプリ Harmonize を開発しており、アプリで鳴るピアノもオルガンも、録音ではなく、鳴らすたびにプログラムが計算したこの数の列です。
なめらかな波も、拡大すると点の列
音の教科書を開くと、まず出てくるのはなめらかな波の絵です。ところがコンピューターの中の音を拡大していくと、画像のピクセルとまったく同じことが起きます。
なめらかに見えていた波は、実は1/44100秒おきに置かれた点の列です。この一粒一粒をサンプルと呼びます。本物の空気の振動は切れ目なく連続していますが、コンピューターはそれを1秒あたり44100回のスナップショットで代表させている、というわけです。この「1秒を何個の数で表すか」をサンプリング周波数と呼び、44100Hz(44.1kHz)はCDが採用して以来の標準的な細かさです。人間に聞こえるいちばん高い音(およそ2万Hz)の揺れを描き取るのに足りるだけの細かさとして選ばれた数字です。なぜその2倍強で足りるのかは面白い話なので、この連載のエイリアシング(ナイキストの壁)の回であらためて取り上げます。さしあたっては「1秒=44100個の数」とだけ覚えれば十分です。
つまりプログラムで音を出す仕事とは、44100分の1秒ごとに数をひとつ決めて、スピーカーへ送り続けることです。では、その数をどんな式で決めれば「ラの音」が鳴るのでしょうか。
どう実現するか ── 位相をぐるぐる回す
鳴らしたいのは、たとえば440Hzのサイン波だとします。440Hzとは「1秒に440回、押し引きをくり返す」という意味です。ここで、1回のくり返しを円の1周にたとえるのが定石です。円の上を回る点を思い浮かべて、その角度を$\varphi$(ファイ)と書き、位相と呼びます。1周は$2\pi$。1秒に440周してほしくて、数を書き出すチャンスは1秒に44100回あるのですから、1サンプルあたりに進むべき角度は決まっています。
$$\Delta\varphi = \frac{2\pi f}{f_s} \qquad (f = 440,\ f_s = 44100)$$
あとは、1サンプルごとに$\varphi$をこの$\Delta\varphi$だけ進めて、その瞬間の高さ$\sin\varphi$を数として書き出すだけです。
書き出した数を時間順に並べると、それがそのままサイン波の点列になっています。この「回しては書き出す」の小さなループを、サウンドプログラミングではオシレータ(発振器、音の源になる部品)と呼びます。コードにするとこれだけです。
/* サイン波オシレータ(C風の擬似コード) */
double phase = 0.0;
double dphi = 2.0 * M_PI * f0 / fs; /* 1サンプルぶんの角度 */
for (n = 0; n < length; n++) {
output[n] = amp * sin(phase); /* いまの高さを数として書き出す */
phase += dphi; /* 位相を進める */
if (phase >= 2.0 * M_PI) phase -= 2.0 * M_PI; /* 1周したら戻す(値が育ちすぎないように) */
}
ここで、$\sin(2\pi f t)$と時刻$t$から直接計算すればいいのに、なぜわざわざ位相を足し込んでいくのか、と思うかもしれません。両者は同じ波を作りますが、差が出るのは周波数を途中で変えた瞬間です。時刻から直接計算する式で$f$を差し替えると、波の高さがいきなり別の場所へジャンプして「プチッ」という雑音が鳴ります。位相を積み上げる方式なら、$\Delta\varphi$を差し替えても$\varphi$自体は連続なので、波はなめらかにつながったまま音程だけが変わる。実用のシンセサイザーがそろってこの方式なのは、それが理由です。
ついでに自作アプリの紹介を。このオシレータをそのまま1本のiPhoneアプリに仕立てた「波動 Hysteric Oscillator」というものも個人で開発しています。音を鳴らしながら波形を画面で確かめられる小さな道具で、この記事の内容を手のひらで試すのにちょうどいい一本です。
ブラウザで試すなら、Web Audio APIにこのループを1秒ぶん回して詰めたバッファを渡すのが手軽です。心臓部は実質この数行で、このあとのデモも同じ作りです。
const fs = ctx.sampleRate, buf = ctx.createBuffer(1, fs, fs);
const data = buf.getChannelData(0);
let phase = 0, dphi = 2 * Math.PI * 440 / fs;
for (let n = 0; n < fs; n++) { data[n] = 0.3 * Math.sin(phase); phase += dphi; }
const src = ctx.createBufferSource();
src.buffer = buf; src.loop = true;
src.connect(ctx.destination); src.start();
矩形波もノコギリ波も、数の作り方が違うだけ
オシレータの骨組みが「位相を回して、数を書き出す」だと分かると、面白いことに気づきます。変えられるのは「書き出す数の決め方」の一行だけで、そこを差し替えるといろいろな音色の素が生まれるのです。
位相が円の前半にいる間は+1、後半にいる間は−1と、二値だけを書き出すと矩形波になります。角がカクカクの波で、昔のゲーム機のピコピコ音はほぼこれです。位相の進み具合をそのまま高さに写して、1周ごとに−1から+1へまっすぐ登っては急降下する形にするとノコギリ波。ブザーのようにジリジリした、成分の豊かな音がします。そして位相を使うのをやめて、毎サンプルでたらめな乱数を書き出すとノイズです。周期がないので音の高さがなく、「ザーッ」という砂嵐になります。同じ44100個/秒の数の列でも、数の作り方ひとつで、これだけ性格の違う音になる。どの波にどんな倍音(音色の成分)が含まれるかという話はそれだけで一本の記事になるので、この連載で改めて取り上げます。
ちなみにHarmonizeのソフトシンセも、心臓部にあるのはまさにこの4種類の数の作り方を束ねた小さなオシレータ部品で、ピアノも尺八も、元をたどればそこが書き出す数の列から組み立てられています。
触ってみる
ここまでの話を、耳と目で確かめられるデモを用意しました。再生ボタンで音を出しながら、周波数のつまみで位相の回る速さを変えて、波形ボタンで数の作り方を切り替えられます。いちばんの見せ場はズームのつまみです。左いっぱいでは教科書どおりのなめらかな波が、右へ回していくと点の列にほどけていき、いちばん右では点の一つ一つに実際の数値が現れます。この数がそのまま、いまスピーカーへ送られている指示です。
うまく表示されないときは、デモを別タブで開く 。
鳴りっぱなしのサイン波は、体温計のような素っ気ない「ピー」です。ここから先が音作りの本番で、この「ピー」に音量の輪郭をかぶせて楽器の顔を与えるのがADSRエンベロープの回 、数の列を輪に閉じ込めて回すと弦の音が生まれるのがカープラス・ストロングの回 です。今回導入した位相という道具を、フィルタの世界でもっと数学寄りに掘った周波数応答の記事 もあります。どの記事でも、今日の数の列がすべての出発点になっています。
参考文献
- 青木直史『サウンドプログラミング入門――音響合成の基本とC言語による実装 』技術評論社(2013)。サンプリングとサイン波の合成という本記事の内容は、この本の最初の数章にあたります。C言語の実装つきで学べる数少ない日本語の定番書。
- Wikipedia: 44,100 Hz 。CDのサンプリング周波数がこの半端な数字になった経緯。
- デモの実装には Web Audio API を使用。位相アキュムレータで生成した波形を AudioBuffer に詰めてループ再生しています。
1秒に44100個の数。それが音のすべての出発点です。まずはデモをいちばん右までズームして、波が数の列にほどける瞬間を見てみてください。
