鍵盤の重さを音で表現する:強く押した音と弱く押した音
遊びをつくる執筆にClaudeを使用しています。

同じ「ド」の音を、そっと触れたときと、力を込めて叩いたときで、聞こえ方はどう違うでしょうか。ピアノなら、強く弾いた音は大きいだけでなく、明るく硬くなり、弱く弾いた音は丸くこもって聞こえます。ブラウザゲームで鍵盤やパッドを作るとき、音量だけを変えて済ませるか、音色も変えるかで、「重さ」の伝わり方は変わりそうです。 この記事では、その差を自分の耳で確かめる実験を設計します。比べるのは「音量だけ」「音色だけ」「両方」「どちらも変えない」の4条件です。2つの音を続けて聞き、どちらが強く弾かれたかを当てる形式にします。結果は書きません。コードを動かして記録を取れば、自分のゲームに必要な反映のしかたが判断できます。
入力に強さがないとき、何を代わりにするか
実験の前に、前提を一つ確認します。パソコンのキーボードやマウスのクリックには、MIDI鍵盤のような「押す強さ」の値がありません。そこでブラウザゲームでは、強さの代わりになる値を別に用意します。代表的な方法は次のとおりです。
- 鍵盤の押した位置で決める(奥は弱く、手前は強く)
- 押してから離すまでの時間で決める
- 連打の間隔で決める(速いほど強く)
- 「弱・中・強」のボタンで段階を選ぶ
- タッチ画面の筆圧(Pointer Eventsのpressure)を使う。ただし対応していない端末では固定値になることがあります
公式作品の「雨音のピアノ」は、3段階のタッチを選べる設計です。強さの値を取りにくい入力環境でも、段階を選ばせる方法があることを示しています。ただし、3段階で音量・音色・余韻のどこがどう変わるかは、この記事では断定しません。作品を開いて3段階を弾き比べ、自作の試作と同じ観点で聞いてみてください。
以下の試作では、一番手軽な「押した位置」を強さとして使います。入力方法が何であっても、強さを0〜1の数値に直したあとの処理は同じだからです。
準備:最小の試作コード
準備するものは、ブラウザ、ヘッドホン(またはスピーカー)、紙とペンです。次のコードを index.html として保存し、ブラウザで開きます。外部ライブラリもサーバーも不要です。
<!doctype html>
<meta charset="utf-8">
<select id="m">
<option value="both">音量+音色</option>
<option value="vol">音量のみ</option>
<option value="tone">音色のみ</option>
<option value="flat">どちらも固定</option>
</select>
<button id="b">出題</button>
<button id="a">答えを見る</button>
<div id="k" style="width:240px;height:120px;background:#ddd;margin-top:8px;user-select:none;touch-action:none">上ほど弱く、下ほど強く</div>
<pre id="out"></pre>
<script>
let ctx, first;
const m = document.getElementById("m"), k = document.getElementById("k");
const out = document.getElementById("out");
k.addEventListener("pointerdown", e => {
ctx = ctx || new AudioContext();
const r = k.getBoundingClientRect();
play(Math.min(1, Math.max(0, (e.clientY - r.top) / r.height)), m.value);
});
function play(v, mode) {
const vv = (mode === "vol" || mode === "both") ? v : 0.5;
const tv = (mode === "tone" || mode === "both") ? v : 0.5;
const gain = Math.pow(10, (-30 + 24 * vv) / 20);
const cutoff = 400 * Math.pow(2, 4 * tv);
const t = ctx.currentTime;
const o = ctx.createOscillator(), f = ctx.createBiquadFilter(), g = ctx.createGain();
o.type = "sawtooth"; o.frequency.value = 220;
f.type = "lowpass"; f.frequency.value = cutoff;
g.gain.setValueAtTime(gain, t);
g.gain.exponentialRampToValueAtTime(0.0001, t + 1.2);
o.connect(f); f.connect(g); g.connect(ctx.destination);
o.start(t); o.stop(t + 1.3);
}
document.getElementById("b").onclick = () => {
ctx = ctx || new AudioContext();
first = Math.random() < 0.5 ? "強" : "弱";
play(first === "強" ? 0.85 : 0.15, m.value);
setTimeout(() => play(first === "強" ? 0.15 : 0.85, m.value), 1500);
};
document.getElementById("a").onclick = () => { out.textContent += "1音目は" + first + "\n"; };
</script>仕組みを短く説明します。強さ v(0〜1)は2つの経路に分かれます。
- 音量:-30dBから-6dBの範囲に写し、10の(dB/20)乗で実際のゲイン(音の大きさの倍率)に直します。人の耳は音の大きさを対数的に感じるため、dBで直線に動かすほうが、強弱が自然な段差になりやすいからです。
- 音色:ローパスフィルタ(高い周波数を削る仕組み)の境目を、400Hzから6,400Hzまで動かします。境目が高いほど倍音が残って明るく硬い音になり、低いほどこもった音になります。境目を2の累乗で動かすのも、音程と同じく比で感じるためです。
音の高さは220Hzに固定しています。音程が変わると強弱の判断に混ざるためです。「どちらも固定」を選ぶと、v が何であっても同じ音が2回鳴ります。これが実験の対照条件になります。
手順:4条件×10回の聞き比べ
問いは「強さの違いを聞き取れるのは、音量・音色・両方のどれか」です。手順は次のとおりです。
- システム音量を小さめにしてから、「出題」を一度押して音を確認します。急に大きな音が出ないようにするためです。この確認以降は、システム音量とヘッドホンの位置を動かしません。
- 紙に4条件それぞれ10行の記録欄を作り、条件の順序をばらばらにします。「音量のみ」を10回続けるのではなく、サイコロやくじで条件を決めてください。慣れや疲れの影響が特定の条件に偏るのを防ぐためです。
- 条件をセレクトボックスで選び、「出題」を押します。約1.5秒あけて2つの音が鳴ります。
- 答えを見る前に、「1音目のほうが強い」か「2音目のほうが強い」かを紙に書きます。迷っても必ずどちらかを選びます。
- 「答えを見る」を押して正解を確認し、正誤を記録します。
- 全条件を10回ずつ(合計40回)終えるまで繰り返します。1回の休憩を挟み、耳が疲れたら翌日に続けても構いません。
出題する音は、強い音が v=0.85、弱い音が v=0.15 です。差が大きすぎて全部当たる場合は、後で差を小さくします。
記録の取り方
記録は条件ごとの正答数が基本です。加えて、主観の印象を1回ごとに残しておくと、数字だけでは見えない違いが拾えます。
- 音量+音色、試行数:10、正答数:、「重い・力強い」の印象(1〜5):、気づいたこと:
- 音量のみ、試行数:10、正答数:、「重い・力強い」の印象(1〜5):、気づいたこと:
- 音色のみ、試行数:10、正答数:、「重い・力強い」の印象(1〜5):、気づいたこと:
- どちらも固定、試行数:10、正答数:、「重い・力強い」の印象(1〜5):、気づいたこと:
印象の欄は、強い側の音を聞いたときに「力が入っている」と感じたかどうかを、5段階で書きます。「大きいだけ」「うるさいだけ」と感じたら、気づいたこと欄にそのとおり書いてください。正解率が高くても、「強い」ではなく「単に大きい」と聞こえている場合があるからです。
結果の読み方
まず「どちらも固定」の欄を見ます。この条件は2音が同一なので、正答は偶然に左右されます。当てずっぽうでも10回中8回以上当たる確率は、計算上は約5.5%(56/1024)、9回以上なら約1.1%(11/1024)です。つまり10回では、偶然でも6〜7回に偏ることは珍しくありません。
- 固定条件の正答が5回前後:実験は健全です。他の条件の正答を比較に使えます。
- 固定条件で9回以上当たる:同一の音のはずなのに当たっているので、出題の順序を無意識に覚えているか、鳴り始めのわずかな違いなど、強弱以外の手がかりを拾っている可能性があります。日を改めてやり直します。
次に、他の3条件を比べます。判断の目安は次のとおりです。
- 「音量のみ」が高く、「音色のみ」が低い:音量が強弱の主な手がかりです。音色の変化量を増やすか、音量主体で作る判断ができます。
- 「音色のみ」でも高い:音色だけでも強さが伝わっています。小さな音量でも力強さを出したい場面では、音色の反映が役に立ちます。
- 「両方」が単独条件より高い、または印象の点が高い:二重に反映する価値があります。ただし、正答率が同じなら印象の欄を優先して決めます。
- すべて満点に近い:差が大きすぎて条件を区別できていません。次の改良で 0.85 と 0.15 を 0.6 と 0.4 に近づけ、再度試します。
誤りやすい点
一度に二つ変えない。 次の調整では、dBの幅(24)かカットオフの倍率(4)のどちらか一つだけを変えて、再度同じ手順で比べます。同時に動かすと、どちらが効いたのか分からなくなります。
音量は耳で確認する。 音色の境目を動かすと、フィルタが倍音を削るため、同じゲインでも体感の大きさが変わります。「音色のみ」で明るい音のほうが大きく聞こえるのは、起こりうる現象です。これを見落とすと、音色の効果と音量の効果を混同します。
直線のゲインで割り当てない。 ゲインを v に比例させると、弱い側の差が大きく出すぎるなど、段差が不自然になることがあります。試すなら、dB式を gain = v に置き換えて、同じ手順で正答と印象を比べてください。
再生環境を揃える。 イヤホンとスピーカー、あるいはブラウザの違いで、高域の出方は変わります。結果は「自分のこの環境での傾向」であり、プレイヤー全員に当てはまるとは限りません。公開前に別の端末でも聞き直すと安全です。
自動再生の制限。 ブラウザは、クリックなどの操作の前に音を出すことを制限します。コードで AudioContext を操作の中で作っているのはそのためです。自作ゲームに組み込むときも、最初のタップのあとに音を鳴らす設計にしてください。
押した位置は視覚と結びつく。 位置で強さを決める方式は、プレイヤーが「どこを押したか」を目で追えるため、強さを意識的に操作しやすい利点があります。反面、鍵盤の見た目を変えると意味が変わるので、実験では画面のレイアウトも固定しておきます。
次の行動
まずコードを保存して4条件を10回ずつ試し、固定条件で実験が成り立っているかを確認してください。そのあとで「雨音のピアノ」を開き、3段階のタッチを同じ音で弾き比べて、音量・音色・余韻のどこが変わって聞こえるかをメモします。その観察と自分の実験表を並べると、自作ゲームの強弱に何を反映するかの方針が立てやすくなります。
参考資料
- MDN Web Docs「Web Audio API」
- MDN Web Docs「Pointer events」



