鳴っているのはすべてその場で合成した波形で、音声ファイルは1つも読み込んでいない。短い単発のタップ、上へ駆け上がる成功音、下へ沈むエラー音——形の違いだけで、達成感と違和感が描き分けられている。
エコーといっても、鳴らしている実体は一瞬の音がひとつだけ。DelayNodeの出力を自分の入力へ戻す(フィードバック)と、それが減衰しながら繰り返し、反響になる。空間の広がりも、録音素材ではなくノードの結線から生み出せるわけだ。
Web Audio APIの基本構造
音声ファイルを一切使わず、OscillatorNode(波形発生器)・GainNode(音量)・BiquadFilterNode(音色調整)をつなぎ合わせるだけで効果音・BGMをコード上で合成できる。ノードを数珠つなぎにする発想が基本構造で、最後にスピーカー出力(destination)へつなぐ。
倍音をたっぷり含んだのこぎり波でも、BiquadFilterNode(ローパス)のカットオフを下げるほど高い成分が削られ、音がこもっていく。グラフの特性カーブは、Web Audioが内部で使う設計式(RBJ係数)から実際に計算したもの。だから耳で聴く変化と、線の動きがぴたりと重なる。
StereoPannerNodeを1つ挟むだけで、音を左右のどこにでも置ける。面白いのは中央でも左右がそれぞれ約71%になること。単純な足し引きなら50%ずつのはずだ。合計の音圧を一定に保つ「等パワー」のパン則が働いていて、これはクロスフェードとまったく同じ理屈になる。
効果音の合成パターン(タップ・成功・エラー音)
タップ音は短い高音のsine波を数十ミリ秒だけ鳴らすだけで成立する。成功音は音程を上昇させる(周波数を時間とともに上げる)と「達成」の印象が出て、エラー音は逆に低く濁った音(矩形波やノイズを混ぜる)にすると「よくない」と直感的に伝わる。いずれも波形の種類より「音量の立ち上がり・減衰カーブ」が印象を大きく左右する。
音の高さも波形も、ずっと同じC5のまま動かしていない。それでもAttackを1msまで詰めれば「カチッ」としたタップ音になり、Releaseを伸ばせばベルのような余韻が残る。印象を決めているのは、音そのものより音量の時間変化(エンベロープ)のほうだ。
同じ440Hzを2つ重ね、片方を数十セント(半音の1/100が1セント)だけずらす。すると「ワンワン」と音量が周期的に波打つ。これがうなりだ。合成音に厚みや高級感を足せる一方、ずらしすぎると濁って聴こえる。うなりの速さは2音の周波数差そのもので、グラフの節(●)の間隔がその周期を表している。
BGMのループ設計とクロスフェード
ループの継ぎ目でプツッと音が切れないよう、ループ開始点と終了点の波形をなめらかに繋ぐ(あるいは短いフェードを両端にかける)のが基本。BGMを切り替える際は、旧トラックの音量を下げながら新トラックを上げる「クロスフェード」を1〜2秒かけて行うと違和感が消える。
「線形」のまま中央を通すと、全体の音量がふっと凹むのが見て取れる。人の耳は音圧で大きさを感じるので、この凹みはそのまま「音が引っ込む」違和感になる。だから実際の切り替えでは、合成音量(点線)が凹まない等パワーカーブを使う。
基準とスライダーを切り替えても、50%ではほとんど小さく感じない。ゲイン0.5は約-6dBで、耳に届く大きさは約66%までしか下がらないからだ(「10dBで体感2倍」の経験則)。音量UIをそのまま線形で作ると「絞ったのに静かにならない」と言われる。半分の大きさに感じさせたいなら、目盛りは30%あたりまで落とす必要がある。
モバイルの自動再生制約と対処
iOS・Androidともに、ユーザーの明示的な操作(タップ等)なしに音声を自動再生することはできない。最初のユーザー操作(ボタンタップ・画面タップ)のタイミングでAudioContextを生成・resumeする実装にしておくと、以降は制約なく鳴らせるようになる。
- まず「音を鳴らす」を押してみてください(まだ鳴りません)
操作前のAudioContextはsuspendedのまま。play()を呼んでコードは走っても、出力がつながらず無音になる。ユーザーの操作でresume()してrunningへ移った瞬間から、普通に鳴りだす。モバイルの自動再生制約が求めているのは、この最初の1タップだけだ。
ゲインを一気に0へ落とすと、波形にストンと段差ができる。この段差がスピーカーを叩き、「プチッ」というクリックノイズになる。短いランプ(setTargetAtTime)で無音へ寄せれば段差は消え、耳に触らない。ミュートも音量変更も、ゲインは一瞬ではなく少し時間をかけて動かすのが鉄則だ。
AIに投げるプロンプト例
Webアプリのボタンにタップ音・成功音・エラー音を追加したいです。 音声ファイルは使わず、Web Audio APIでコード合成してください。 - タップ音は短く軽い印象、成功音は上昇する音程、エラー音は低く濁った音 - iOS/Androidの自動再生制約に対応し、初回のユーザー操作でAudioContextを初期化する - 音量は控えめにし、prefers-reduced-motion相当の「音を消す」設定も用意してほしい