音の定位:左右に振るだけで画面の外が分かるか
遊びをつくる執筆にClaudeを使用しています。

画面の右外から敵が近づいてくるゲームを考えてみます。画面にはまだ何も映っていません。足音をステレオの右側から鳴らしたとき、プレイヤーは「右から来る」と分かるでしょうか。さらに「右のかなり端」と「右寄りの中央付近」を聞き分けられるでしょうか。 この問いは、作る側の「たぶん伝わるはず」という感覚では答えが出ません。作者は音の出どころを知っているので、聞こえ方を自分で評価すると甘くなりがちです。そこでこの記事では、左右のパン(音を左右のスピーカーに振り分ける量)だけで位置を伝える小さな実験を作り、どれだけ正確に当てられるかを測る手順を示します。結果は書きません。コードを動かして21回答えれば、自分の環境での答えが数字で手に入る設計です。
この記事の目次
何を確かめるのか:問いを三つに分ける
「分かるか」という問いは大きすぎるので、先に三つに分けます。
- 左右の取り違えが起きるか(左の音を右と答えてしまうか)。
- 位置の順序が保たれるか(左寄りの音ほど、より左と答えられるか)。
- 何段階まで聞き分けられるか(左・中央・右の3区分で足りるのか、7段階の細かさが要るのか)。
ゲームの設計で本当に必要なのは、たいてい1と3です。「画面外のどちら側か」が伝われば十分な作品もあれば、「あと何歩分右か」まで求める作品もあります。実験の前に、自分のゲームがどちらを必要としているかを決めておきます。この判断が、後で結果を読む基準になります。
ステレオのパンだけでは、前後や上下は表現できません。これは一般によく知られた性質です。この実験が確かめるのは左右の軸だけで、前後の判断は対象外です。
準備するもの
- ヘッドホン(できれば有線)と、可能なら机上のスピーカー。条件の比較に使います。
- 静かな部屋と、ブラウザが動くパソコン。
- 下のHTMLファイルを1つ保存します。外部ライブラリは不要で、通信も発生しません。
- 筆記用具、または記録をコピーするメモ。
- 協力者を1人以上。作者本人は正解の分布を知っているため、本人の成績だけで判断しないでください。
実験用のページは次のとおりです。7つのパン値を各3回、計21試行をランダムな順で1回ずつ鳴らします。聞こえた位置は、画面のバーをクリックして答えます。バーの左端が左いっぱい、右端が右いっぱいです。
<!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試行の進め方
- ヘッドホンの左右を確認します。左右が逆に付いていると、結果全体が反転します。
- OSの音声設定でモノラル出力が有効になっていないか確認します。モノラルだとパンが効かず、何を答えても偶然になります。
- 音量は、耳に痛くなく、最も小さい音でも聞き取れる程度に固定します。実験中は触りません。
- 「次の音を鳴らす」を押し、音が鳴ったらバーの上の、聞こえた位置をクリックします。
- 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」



