ちいつる
A-07リファレンス

サウンドデザイン実装ガイド

音声ファイルなしで効果音・BGMをコード合成する手法をリファレンス化する。

触ってみる3つのボタンを押して、音と波形を見比べてみてください

鳴っているのはすべてその場で合成した波形で、音声ファイルは1つも読み込んでいない。短い単発のタップ、上へ駆け上がる成功音、下へ沈むエラー音——形の違いだけで、達成感と違和感が描き分けられている。

触ってみる音をタップし、間隔とフィードバックを変えて反響を聴いてみてください

エコーといっても、鳴らしている実体は一瞬の音がひとつだけ。DelayNodeの出力を自分の入力へ戻す(フィードバック)と、それが減衰しながら繰り返し、反響になる。空間の広がりも、録音素材ではなくノードの結線から生み出せるわけだ。

Web Audio APIの基本構造

音声ファイルを一切使わず、OscillatorNode(波形発生器)・GainNode(音量)・BiquadFilterNode(音色調整)をつなぎ合わせるだけで効果音・BGMをコード上で合成できる。ノードを数珠つなぎにする発想が基本構造で、最後にスピーカー出力(destination)へつなぐ。

触ってみる鳴らしながらカットオフとQを動かし、音色の変化を聴いてください

倍音をたっぷり含んだのこぎり波でも、BiquadFilterNode(ローパス)のカットオフを下げるほど高い成分が削られ、音がこもっていく。グラフの特性カーブは、Web Audioが内部で使う設計式(RBJ係数)から実際に計算したもの。だから耳で聴く変化と、線の動きがぴたりと重なる。

触ってみる音源を左右にドラッグして定位を動かしてください(イヤホン推奨)
L 71%pan = 0.0071% R

StereoPannerNodeを1つ挟むだけで、音を左右のどこにでも置ける。面白いのは中央でも左右がそれぞれ約71%になること。単純な足し引きなら50%ずつのはずだ。合計の音圧を一定に保つ「等パワー」のパン則が働いていて、これはクロスフェードとまったく同じ理屈になる。

効果音の合成パターン(タップ・成功・エラー音)

タップ音は短い高音のsine波を数十ミリ秒だけ鳴らすだけで成立する。成功音は音程を上昇させる(周波数を時間とともに上げる)と「達成」の印象が出て、エラー音は逆に低く濁った音(矩形波やノイズを混ぜる)にすると「よくない」と直感的に伝わる。いずれも波形の種類より「音量の立ち上がり・減衰カーブ」が印象を大きく左右する。

触ってみる4本のスライダーで音量カーブを変えて鳴らしてみてください

音の高さも波形も、ずっと同じC5のまま動かしていない。それでもAttackを1msまで詰めれば「カチッ」としたタップ音になり、Releaseを伸ばせばベルのような余韻が残る。印象を決めているのは、音そのものより音量の時間変化(エンベロープ)のほうだ。

触ってみる2音を鳴らし、デチューン量を変えてうなりの速さを聴いてください
うなり: 3.8Hz周期: 0.26秒

同じ440Hzを2つ重ね、片方を数十セント(半音の1/100が1セント)だけずらす。すると「ワンワン」と音量が周期的に波打つ。これがうなりだ。合成音に厚みや高級感を足せる一方、ずらしすぎると濁って聴こえる。うなりの速さは2音の周波数差そのもので、グラフの節(●)の間隔がその周期を表している。

BGMのループ設計とクロスフェード

ループの継ぎ目でプツッと音が切れないよう、ループ開始点と終了点の波形をなめらかに繋ぐ(あるいは短いフェードを両端にかける)のが基本。BGMを切り替える際は、旧トラックの音量を下げながら新トラックを上げる「クロスフェード」を1〜2秒かけて行うと違和感が消える。

触ってみる再生して、スライダーで2つのBGMをクロスフェードしてみてください
BGM A(低音パッド)BGM B(高音パッド)
再生しながら中央付近で線形と等パワーを切り替えてみる

「線形」のまま中央を通すと、全体の音量がふっと凹むのが見て取れる。人の耳は音圧で大きさを感じるので、この凹みはそのまま「音が引っ込む」違和感になる。だから実際の切り替えでは、合成音量(点線)が凹まない等パワーカーブを使う。

触ってみるスライダーを50%あたりにして、基準とスライダーを切り替えて聴き比べて
線形 0.50-6.0dB体感 66%
鳴らして基準とスライダーを切り替え、耳で聴き比べる

基準とスライダーを切り替えても、50%ではほとんど小さく感じない。ゲイン0.5は約-6dBで、耳に届く大きさは約66%までしか下がらないからだ(「10dBで体感2倍」の経験則)。音量UIをそのまま線形で作ると「絞ったのに静かにならない」と言われる。半分の大きさに感じさせたいなら、目盛りは30%あたりまで落とす必要がある。

モバイルの自動再生制約と対処

iOS・Androidともに、ユーザーの明示的な操作(タップ等)なしに音声を自動再生することはできない。最初のユーザー操作(ボタンタップ・画面タップ)のタイミングでAudioContextを生成・resumeする実装にしておくと、以降は制約なく鳴らせるようになる。

触ってみるまず「音を鳴らす」を押し、次にアンロックしてもう一度試してください
suspended未操作・無音
ユーザー操作
running発音できる
  • まず「音を鳴らす」を押してみてください(まだ鳴りません)

操作前のAudioContextはsuspendedのまま。play()を呼んでコードは走っても、出力がつながらず無音になる。ユーザーの操作でresume()してrunningへ移った瞬間から、普通に鳴りだす。モバイルの自動再生制約が求めているのは、この最初の1タップだけだ。

触ってみる鳴らして瞬時とランプを切り替え、ミュート時の波形の段差を見比べて
ミュートの切り方
鳴らして瞬時とランプを切り替え、ミュートしたときの波形の段差を見比べる

ゲインを一気に0へ落とすと、波形にストンと段差ができる。この段差がスピーカーを叩き、「プチッ」というクリックノイズになる。短いランプ(setTargetAtTime)で無音へ寄せれば段差は消え、耳に触らない。ミュートも音量変更も、ゲインは一瞬ではなく少し時間をかけて動かすのが鉄則だ。

AIに投げるプロンプト例

Webアプリのボタンにタップ音・成功音・エラー音を追加したいです。 音声ファイルは使わず、Web Audio APIでコード合成してください。 - タップ音は短く軽い印象、成功音は上昇する音程、エラー音は低く濁った音 - iOS/Androidの自動再生制約に対応し、初回のユーザー操作でAudioContextを初期化する - 音量は控えめにし、prefers-reduced-motion相当の「音を消す」設定も用意してほしい