マガジン

音の定位:左右に振るだけで画面の外が分かるか

遊びをつくる

執筆にClaudeを使用しています。

成功、失敗、選択に応じた三種類の音を、異なる形の響きで表したイラスト。
記事のテーマをもとに制作したAI生成イラスト。

画面の右外から敵が近づいてくるゲームを考えてみます。画面にはまだ何も映っていません。足音をステレオの右側から鳴らしたとき、プレイヤーは「右から来る」と分かるでしょうか。さらに「右のかなり端」と「右寄りの中央付近」を聞き分けられるでしょうか。 この問いは、作る側の「たぶん伝わるはず」という感覚では答えが出ません。作者は音の出どころを知っているので、聞こえ方を自分で評価すると甘くなりがちです。そこでこの記事では、左右のパン(音を左右のスピーカーに振り分ける量)だけで位置を伝える小さな実験を作り、どれだけ正確に当てられるかを測る手順を示します。結果は書きません。コードを動かして21回答えれば、自分の環境での答えが数字で手に入る設計です。

この記事の目次
  1. 何を確かめるのか:問いを三つに分ける
  2. 準備するもの
  3. 手順:1セット21試行の進め方
  4. 条件を比べる:変えるのは一度に一つだけ
  5. 結果の読み方:数字を見る順番と判断基準
  6. 起こりやすい誤り
  7. ゲームの設計に戻す
  8. 次の行動
  9. 参考資料

何を確かめるのか:問いを三つに分ける

「分かるか」という問いは大きすぎるので、先に三つに分けます。

  1. 左右の取り違えが起きるか(左の音を右と答えてしまうか)。
  2. 位置の順序が保たれるか(左寄りの音ほど、より左と答えられるか)。
  3. 何段階まで聞き分けられるか(左・中央・右の3区分で足りるのか、7段階の細かさが要るのか)。

ゲームの設計で本当に必要なのは、たいてい1と3です。「画面外のどちら側か」が伝われば十分な作品もあれば、「あと何歩分右か」まで求める作品もあります。実験の前に、自分のゲームがどちらを必要としているかを決めておきます。この判断が、後で結果を読む基準になります。

ステレオのパンだけでは、前後や上下は表現できません。これは一般によく知られた性質です。この実験が確かめるのは左右の軸だけで、前後の判断は対象外です。

準備するもの

  • ヘッドホン(できれば有線)と、可能なら机上のスピーカー。条件の比較に使います。
  • 静かな部屋と、ブラウザが動くパソコン。
  • 下のHTMLファイルを1つ保存します。外部ライブラリは不要で、通信も発生しません。
  • 筆記用具、または記録をコピーするメモ。
  • 協力者を1人以上。作者本人は正解の分布を知っているため、本人の成績だけで判断しないでください。

実験用のページは次のとおりです。7つのパン値を各3回、計21試行をランダムな順で1回ずつ鳴らします。聞こえた位置は、画面のバーをクリックして答えます。バーの左端が左いっぱい、右端が右いっぱいです。

html
<!doctype html>
<meta charset="utf-8">
<button id="go">次の音を鳴らす</button>
<div id="bar" style="position:relative;width:600px;height:40px;background:#ccd;margin-top:12px;cursor:pointer"></div>
<pre id="out"></pre>
<script>
const pans=[-1,-0.6,-0.3,0,0.3,0.6,1];
let queue=[],cur=null,t0=0,rows=[],ctx,started=false;
function shuffle(a){for(let i=a.length-1;i>0;i--){const j=Math.floor(Math.random()*(i+1));[a[i],a[j]]=[a[j],a[i]];}return a;}
function burst(p){
  const sr=ctx.sampleRate,len=Math.floor(sr*0.15);
  const buf=ctx.createBuffer(1,len,sr),d=buf.getChannelData(0);
  for(let i=0;i<len;i++)d[i]=(Math.random()*2-1)*(1-i/len);
  const src=ctx.createBufferSource();src.buffer=buf;
  const pan=ctx.createStereoPanner();pan.pan.value=p;
  const g=ctx.createGain();g.gain.value=0.3;
  src.connect(pan).connect(g).connect(ctx.destination);src.start();
}
go.onclick=()=>{
  ctx=ctx||new AudioContext();
  if(cur!==null)return;
  if(!started){queue=shuffle([...pans,...pans,...pans]);started=true;}
  if(!queue.length){out.textContent+="\n終了";return;}
  cur=queue.pop();burst(cur);t0=performance.now();
};
bar.onclick=e=>{
  if(cur===null)return;
  const r=bar.getBoundingClientRect();
  const ans=((e.clientX-r.left)/r.width)*2-1;
  rows.push([rows.length+1,cur,ans.toFixed(2),(ans-cur).toFixed(2),Math.round(performance.now()-t0)]);
  cur=null;
  out.textContent="trial,target,answer,error,ms\n"+rows.map(x=>x.join(",")).join("\n");
};
</script>

音は0.15秒ほどの短いノイズで、後ろに向けて音量が下がります。再生ボタンを押した後でしか鳴らさないのは、ブラウザが操作前の自動再生を制限しているためです。1回の試行で音を再生できるのは1回きりです。聞き直しを許すと、「何度も聞けば当たる」状態を測ることになってしまいます。

手順:1セット21試行の進め方

  1. ヘッドホンの左右を確認します。左右が逆に付いていると、結果全体が反転します。
  2. OSの音声設定でモノラル出力が有効になっていないか確認します。モノラルだとパンが効かず、何を答えても偶然になります。
  3. 音量は、耳に痛くなく、最も小さい音でも聞き取れる程度に固定します。実験中は触りません。
  4. 「次の音を鳴らす」を押し、音が鳴ったらバーの上の、聞こえた位置をクリックします。
  5. 21回繰り返し、画面に出たCSV形式の記録をテキストにコピーして保存します。

記録する項目は次のとおりです。

  • trial、意味:試行番号、単位:1〜21
  • target、意味:正解のパン値、単位:−1〜+1
  • answer、意味:回答(バー上の位置を−1〜+1に換算)、単位:−1〜+1
  • error、意味:回答 − 正解、単位:同上
  • ms、意味:音から回答までの時間、単位:ミリ秒

1人あたり1条件で21回。条件を変えたら、別のセットとして新しく記録します。

条件を比べる:変えるのは一度に一つだけ

1セットだけでは「この環境ではこうだった」としか言えません。ゲームの作り方に役立てるには、条件を一つだけ変えて比べます。変えやすい順に挙げます。

  • ヘッドホンとスピーカー:スピーカーでは、座る位置や部屋の反響で結果が変わります。座る位置は毎回同じにします。
  • 音の種類:ノイズのような広い帯域の音と、単一の高さの純音を比べます。一般に、広帯域の音は位置が分かりやすいと言われますが、自分の環境で確かめる価値があります。ノイズ生成の1行を、サイン波を入れる処理に差し替えて試せます。
  • 音の長さ:0.15秒を、0.5秒や0.05秒に変えます。
  • 協力者:同じ条件を別の人にも行ってもらいます。

複数を同時に変えると、どの変更が効いたのか分からなくなります。たとえばヘッドホンからスピーカーに替え、同時に音を純音にした場合、差の原因は切り分けられません。

結果の読み方:数字を見る順番と判断基準

CSVが取れたら、次の順に見ます。ここでは、どんな結果が出たらどう判断するかだけを示します。

1. 左右の取り違え(符号の誤り)

正解が−0.6以下、または+0.6以上の試行で、回答の符号が逆だった回数を数えます。1回でも起きたら、まず聞き取りの失敗ではなく、環境の不具合を疑います。ヘッドホンの左右逆、モノラル設定、クリックの位置ずれなどです。環境を直して再度測っても取り違えが続くなら、その条件では左右の判別に頼れないと判断します。

2. 順序が保たれているか

正解ごと(7種類)に3回の回答の平均を出し、−1から+1の順に並べます。数値が左から右へ単調に増えていれば、順序は保たれています。途中で逆転しているなら、その隣り合う2段階は区別できていません。

3. 誤差の大きさと偏り

正解ごとに、絶対誤差(誤差の符号を無視した大きさ)の平均を出します。端と中央で違いがあるかも見ます。全体の誤差の平均(符号つき)も出します。プラスなら右寄りに、マイナスなら左寄りに答える傾向があります。

注意点として、パン値と「バー上の位置」は比例するとは限りません。パンの音量配分は線形ではなく、聞こえる位置の感覚も人によって異なります。ですから「誤差が0に近いか」より、順序が保たれているか、同じ正解への回答が安定しているか(3回の最大と最小の差)を重視します。

4. ゲームに必要な分解能で判断する

最初に決めた必要な分解能に当てはめます。回答を「左(−0.2未満)・中央・右(+0.2より大きい)」の3区分に丸め、正解の区分と一致した割合を出します。区分の境界は実験の前に決めておき、結果を見てから動かさないでください。動かすと、都合のよい数字を作ってしまいます。

  • 3区分の一致が自分の基準を満たすなら、「画面外のどちら側か」を伝える用途ではパンだけで使えます。
  • 7段階の順序まで保たれているなら、距離感の表現にもパンを使う余地があります。
  • どちらも満たさないなら、音量差・音の高さ・視覚的な矢印などを併用します。

基準の数字(たとえば「9割」)は、自分のゲームで外したときの困り方から決めてください。この記事では数値の目安を示しません。

起こりやすい誤り

  • 作者本人だけで測る:正解の分布を知っていると、無意識に補正します。協力者に頼むのが安全です。
  • 試行数が少ない:1正解あたり3回では、ばらつきの大まかな傾向しか見えません。判断が割れたときは、セットを増やします。
  • 練習効果を無視する:後半ほど慣れて成績が上がります。セットの順番を、人によって入れ替えます。
  • 音量や頭の向きが変わる:途中で音量を触らない、顔をバーに向けたままにする、と決めておきます。
  • ブラウザやOSの音声加工:空間オーディオなどの加工が有効だと、パンの効き方が変わります。条件として記録し、無効にしても試せます。
  • 記録に個人情報を残す:協力者の名前は不要です。「A、B」などの符号で管理し、記録は手元に保存します。

ゲームの設計に戻す

結果が出たら、ゲームの設計に戻します。画面外の情報を音だけで伝える設計は、聞こえない人や音を出せない環境のプレイヤーには届きません。左右の位置を視覚的な目印(画面の端の矢印など)と対にしておくと、音の効果を測りながら、どの環境でも成り立つ形にできます。アソバースの公式作品では、たとえば「こだまの森」が音なしでも遊べる作りです。音と視覚のどちらかに依存しすぎない設計の例として、作品を開いて確かめてみてください。

次の行動

まず上のHTMLを保存し、ヘッドホンで21試行を1セット行って、CSVを手元に残してください。次に、協力者1人に同じ条件で行ってもらい、「符号の誤り」「順序」「3区分の一致」の順に見ます。そのうえで自分のゲームの必要な分解能と照らし合わせ、音の使い方を決めます。

参考資料

  • MDN Web Docs「Web Audio API」「StereoPannerNode」