スマートフォンの電話アプリで番号を押すと、いまでも「ピ、ポ、パ」と鳴ります。あれは押した感触を出すための効果音ではありません。押したボタンそのものを音に変換した、れっきとしたデータ通信です。だからあの音を録音すれば、あとから何番を押したのか割り出せてしまう。テレビ番組で電話番号を入力する場面の音が伏せられることがあるのは、このためです。
この方式は DTMF(Dual-Tone Multi-Frequency、2つの音を同時に使う多周波信号)と呼ばれ、1963年にアメリカのベル・システムがプッシュホンとともに実用化しました。今回はこの「ピポパ」を材料に、音でデータを送るとはどういうことか、そして受け取った音をどう解読するのかを見ていきます。この連載では音の正体は数の列だ というところから始めて、楽器の音をプログラムで作る話を続けてきましたが、今回は楽器ではなく、音を「文字」として使う回です。
ボタンは音の「座標」でできている
プッシュホンの前の世代、ダイヤルを回す黒電話は、まったく別の方法で番号を伝えていました。ダイヤルが戻るあいだに、回した数字の回数だけ回線を切ったりつないだりする。カチカチという断続そのものが合図で、これはパルス式と呼ばれます。機械的で確実ですが、遅く、そして交換機に向けた「番号選び」専用の合図なので、電話がつながった後の相手には何も伝えられません。
黒電話に触ったことがない世代のために補足すると、ダイヤルは指を穴に差し込んで、金具(指止め)まで回して離す道具です。回すときではなく、バネで戻るあいだに回線が断続します。「1」なら1回、「9」なら9回、「0」は10回。数字が大きいほど戻りが長く、ダイヤルするだけで時間がかかりました。市外局番から順に回していると、それだけで十数秒かかることも珍しくありません。
DTMFの発想は逆で、合図をただの「音」にしてしまいました。音でありさえすれば、電話線でも、空気中でも、録音テープの上でも通ります。つながった後の回線にも当然乗るので、通話の途中でボタン操作を送れる。音声ガイダンスの「〜の方は1を押してください」が今日でも成立しているのは、この性質のおかげです。
では、どんな音にするか。ここがDTMFの核心です。
用意するのは8つの音だけです。低めの4音(697・770・852・941ヘルツ)を「低群」、高めの4音(1209・1336・1477・1633ヘルツ)を「高群」とし、低群から1つ、高群から1つを選んで同時に鳴らす。低群がキーパッドの行を、高群が列を決めるので、2音の組はそのままボタンの座標になります。たとえば「5」は770ヘルツと1336ヘルツの同時再生。この組み合わせは「5」だけのもので、ほかのどのボタンとも重なりません。4×4で16通り、電話機に載っている12個のキーに、業務用などで使う拡張のA〜Dを足した16記号がこれで表せます。
なぜわざわざ2音同時なのでしょうか。1音だけでも「697ヘルツが鳴ったら1」と決めれば済みそうなものです。ところが電話回線には人の声が流れています。声にも口笛にもテレビの音にも、697ヘルツ付近の成分くらいいくらでも含まれるので、1音では「たまたま鳴っていた音」と区別がつきません。一方、離れた2つの決められた周波数が、同時に、それだけで鳴るという状況は、偶然にはまず起きません。しかも8つの周波数は、どれも他の音の整数倍(倍音の関係)にならないよう慎重に選ばれています。回線の歪みで倍音が生まれても、別の目標周波数に化けて誤検出を起こさないための用心です。電話回線が通せる帯域はおおむね300〜3400ヘルツと狭いのですが、8音はきちんとその中に収まっています。
この8つの数字は、ITU-T勧告Q.23として国際的に決められた値です。北米で開発されたTouch-Toneがそのまま国際規格になったので、日本のプッシュホンも、海外の電話機も、同じ周波数を使います。日本の携帯から海外の音声ガイダンスを操作できるのは、このおかげです。
ただし、規格どおりの2音をそのまま合成すると、記憶の中のプッシュ音とは少し違って聞こえます。本物には、決まった周波数のほかに2つの作法があるからです。ひとつはツイスト。電話線は高い音ほど減衰するので、送信側で高群を低群より2〜3デシベル強く鳴らしておきます。もうひとつは帯域。実際の音は300〜3400ヘルツしか通らない回線と、小さな受話器のスピーカーを経由して耳に届きます。純粋な正弦波をそのまま鳴らすと、澄みすぎて、あの少し詰まった感じになりません。下のデモは、この2つを模した状態で鳴らしています。
受ける側は、8ヶ所を聴診するだけ
送る側が「2音を足すだけ」なら、受ける側の仕事も驚くほど少なくて済みます。音に含まれるすべての周波数を調べる必要はありません。知りたいのは、決められた8つの周波数のそれぞれが「鳴っているか、いないか」だけです。
受信側は、届いた波形に対して8つの周波数それぞれのエネルギーを測ります。イメージとしては、8本の聴診器をそれぞれ決まった高さの音だけに当てて、どれが強く響いているかを聞き比べる感じです。低群の4本のうち1本だけ、高群の4本のうち1本だけが突出していれば、行と列が確定してボタンが分かる。どちらかの群で1本も立たない、あるいは2本立ってしまったら、それはDTMFではない(ただの声や雑音だ)として捨てる。判定が白黒はっきりしているのが、この設計の気持ちよさです。
この「特定の周波数だけを効率よく聴診する」計算には、ゲルツェル法(Goertzel algorithm、1958年にGerald Goertzelが発表)という定番のアルゴリズムがあります。周波数分析というとFFTのような大掛かりな変換を思い浮かべますが、知りたい周波数が8つと決まっているなら、その8ヶ所だけを漸化式ひとつで安く測れる。電話交換機のように何百回線も同時に監視する装置では、この安さが効きました。
s[n] = 係数 * s[n-1] - s[n-2] + 入力 のような形になります。再帰と同じ考え方で、実装は素直なループです。音の波形から必要な情報だけを抜き出すという意味では、マイクの音から音程を当てるピッチ検出 も同じ仲間です。あちらは「知らない高さを探す」問題で、こちらは「決まった高さがあるか確かめる」問題。探し物の種類が違うだけで、どちらも音を数の列として受け取り、計算で答えを取り出します。
触ってみる
言葉より押してみるのが早いので、デモを用意しました。キーパッドを押すと、そのキーの2音が実際に鳴ります。そして右上の解読欄に注目してください。ここに出る文字は、ボタンの信号を横流ししたものではなく、いま鳴った音の波形だけを毎フレーム受け取り、8つの周波数のエネルギーを測って復元したものです。エンコードとデコードが、スピーカーとプログラムのあいだで本当に往復しています。
うまく表示されないときは、デモを別タブで開く 。
「じゃま音を混ぜる」で試せること。 2音の組にした理由は、声や雑音と区別するためでした。それを自分で確かめられるように、回線に人の声や雑音が乗った状態を再現するボタンを付けました。押すと、8つのメーターは絶えず揺れ、スペクトラムにも山が立ちます。それでもキーは1つも確定しません。そのまま数字を押せば、じゃま音の上からでもきちんと解読されます。
実は、この機能を足したときに誤検出が出ました。声の代わりに純音を揺らして流していたのですが、たまたま低群と高群の1本ずつが強く出た瞬間に、デコーダが「キーが押された」と判定してしまったのです。これは実際の電話でも「トークオフ」と呼ばれる有名な誤動作で、通話中の声がボタン操作に化ける現象です。対策も実機と同じで、2本の山が8本ぶんのエネルギーの過半を占めていることを条件に加えました。声や雑音はエネルギーが広く散らばるので、この一行で弾けます。
真ん中の「8つの聴診器」で、押すたびに青(低群)と紫(高群)が1本ずつ立ち上がるのを確かめてください。その下のスペクトラム、つまりどの高さの音がどれだけ鳴っているかのグラフでは、どのキーを押しても山がきっかり2本だけ立ちます。音を周波数の軸で眺める見方は、周波数特性の記事 でも扱いました。キー列は「1234」でも「0000」でも、意味のない適当な並びで十分です。
いちばん下のおまけは、後で触れるカセットテープ方式の再現です。短い文字列を0/1のビット列にして、低い音と高い音の「ピーガガガ」で送り、受信側がそれを聴き取って文字に戻します。
どう実現するか
送る側は本当に足し算だけです。キーに対応する低群・高群の周波数でサイン波を2本作り、足して鳴らします。
// 「5」の音: 770 Hz + 1336 Hz
function dtmfSample(n, fs){
const t = n / fs;
return 0.5 * (Math.sin(2 * Math.PI * 770 * t) +
Math.sin(2 * Math.PI * 1336 * t));
}
受ける側の「聴診」も、正体は素朴な掛け算と足し算です。調べたい周波数 $f$ のコサインとサインを波形に掛けて足し込むと、その周波数の成分だけが積み上がり、無関係な成分は打ち消し合ってゼロに近づきます。積み上がった量の2乗和が、その周波数のエネルギーです。
$$E(f) = \Big(\sum_n x[n]\cos\tfrac{2\pi f n}{f_s}\Big)^2 + \Big(\sum_n x[n]\sin\tfrac{2\pi f n}{f_s}\Big)^2$$// 波形 x の中で、周波数 f がどれだけ鳴っているか
function energyAt(x, f, fs){
let re = 0, im = 0;
for (let n = 0; n < x.length; n++){
re += x[n] * Math.cos(2 * Math.PI * f * n / fs);
im += x[n] * Math.sin(2 * Math.PI * f * n / fs);
}
return re * re + im * im;
}
これを8つの周波数について計算し、低群と高群でそれぞれ最大の1本を取り、他を大きく引き離していればキー確定です。ゲルツェル法は、この計算のコサインとサインの呼び出しを漸化式に畳み込んで、1周波数あたり掛け算1回ぶんまで安くした改良版で、やっていることは同じ聴診です。上のデモも、この方式で毎フレーム8ヶ所を測っています。
勘のいい方は気づいたと思いますが、この掛け算と足し算はフーリエ変換そのものです。正確には、離散フーリエ変換(DFT)を1つの周波数についてだけ計算したもの。FFTは、同じ計算を全周波数について一気に片付ける高速アルゴリズムです。つまり両者は別物ではなく、全部いるか、8つでいいかの違いでしかありません。
そして知りたいのが8つだけなら、1点ずつ測るほうが安く済みます。しかもFFTには、測れる周波数が飛び飛びになるという事情があります。標本化周波数8000ヘルツ・512サンプルなら刻みは約15.6ヘルツで、697ヘルツにいちばん近い点は703.1ヘルツ。手元で計算すると、この6ヘルツのずれだけで測定値が1.7倍変わりました。ゲルツェル法なら697ヘルツちょうどを狙えます。
もうひとつの見方もあります。ゲルツェル法の漸化式は、その周波数だけを通す共振フィルタ(2次のIIRフィルタ)と数学的に同じものです。「決めた周波数との相関を取る」と「狭いバンドパスに通してエネルギーを見る」は、同じ計算の言い換えにすぎません。DTMFの受信器が「8個のフィルタを並べたもの」と説明されることがあるのは、この見方によります。
なお、上のデモでFFTを使っているのは「スペクトラム ── 2本の山」の絵を描く部分だけで、キーの判定には一切使っていません。判定側が受け取っているのは、周波数に分解される前の生の波形です。
宣伝を少しだけ。筆者は音感トレーニングのiOSアプリ Harmonize を個人で開発していて、この連載はそこで使っている音づくりの知識の棚卸しでもあります。アプリの中で鳴る楽器の音も、今回のデモと同じく、すべてプログラムがその場で合成した音です。
余談:番号を送る前は、人がつないでいた
パルス式もDTMFも「交換機に番号を伝える」仕組みですが、その交換機が機械になる前は、人が手でつないでいました。電話交換手という職業です。
受話器を上げると交換手につながり、相手を告げると、目の前の交換台からケーブルを引き出して、相手の回線の穴へ差し込む。文字どおり「線をつなぐ」作業でした。写真のように、何十人もが一列に並んで一日中プラグを抜き差ししています。

ベルシステムの国際電話交換台(1943年)。交換手がプラグを抜き差しして回線をつないだ(米国労働省 Women’s Bureau/NARA 1633445。パブリックドメイン, via Wikimedia Commons)
このとき使われたプラグが、いまギターやヘッドホンで使う6.3ミリのフォーンジャックの先祖です。「フォーン」は phone、つまり電話のこと。エフェクターにシールドを挿すたびに、19世紀の交換台の規格をそのまま使っているわけです。
そして、この職業は自動交換機の普及とともに消えていきました。ダイヤルを回して交換機が番号を数える、まさにこの記事で見たパルス式が、その置き換えの実行役です。数字を送る方法が変わったという技術の話は、裏側では大量の職が消えた話でもありました。いまAIに仕事を奪われるという議論を、私たちはずいぶん新しい問題のように語りますが、電話の歴史はとっくに一周しています。
音でデータを送った時代
「音でありさえすれば、どこでも通る」というDTMFの発想は、電話のボタンにとどまりませんでした。
たとえば1980年代前後の家庭用パソコンには、作ったプログラムを保存する装置として、ごくふつうの音楽用カセットテープが使われていました。プログラムは0と1の列ですから、0を低い音、1を高い音と決めて順番に鳴らせば、データは「音」になり、音ならテープに録音できます。読み込むときはテープを再生し、聞こえてくる音の高低を判定して0/1に戻す。ロード中にスピーカーから漏れるあの「ピーーーガガガガ」は、まさにデータそのものの音でした。この方式はFSK(Frequency Shift Keying、周波数の切り替えで0/1を表す変調)と呼ばれ、初期の規格のひとつでは0を1200ヘルツ、1をその倍の2400ヘルツで表していました。デモのおまけは、これを聴き取れる速さまで遅くした再現です。
電話回線でコンピューター同士をつないだモデムも、根っこは同じです。デジタルデータを可聴域の音に変換して電話回線に流し、相手側で音からデータに戻す。ダイヤルアップ接続の冒頭に聞こえた「ピーヒョロロ、ガーッ」という賑やかな音は、双方のモデムが「そちらはどの速度まで話せますか」と音で交渉し合っている声でした。受話器を装置に押し当てて、スピーカーとマイク越しに音を送り合う音響カプラという道具まであって、文字どおり空気中を、データが音として飛んでいたわけです。
その後、通信は専用のデジタル回線に移り、データが音の姿を借りる必要はなくなりました。それでもDTMFは、音声ガイダンスのボタン操作として現役ですし、「マイクとスピーカーさえあれば通信できる」という手軽さから、機器のペアリングなどに音を使うアイデアは今も折にふれて顔を出します。
参考文献
- 青木直史『サウンドプログラミング入門――音響合成の基本とC言語による実装 』技術評論社(2013)。サイン波の合成から周波数分析まで、音の基礎をC言語の実装つきで解説する定番書。
- DTMFの周波数の割り当てと歴史は Wikipedia: DTMF 、特定周波数のエネルギー検出は Wikipedia: Goertzel algorithm が詳しいです。
- デモの実装には Web Audio API を使用。キーの2音は OscillatorNode で合成し、解読側は AnalyserNode から受け取った波形にゲルツェル法を適用しています。
次に音声ガイダンスへ電話をかけたら、ボタンを押すたびに鳴るあの音を少しだけ気にしてみてください。ピポパが、行と列の座標の読み上げに聞こえてくるはずです。
連載「サウンドプログラミング」
← 前回 鳴っていない音が聞こえ続ける
