ラウドネス
createLoudness は、マイクの音量をゲームから読める 0〜3 のレベルに変えます。音声はアナライザーまでしか届きません。Earshot は音声を録音、送信、再生しません。
マイク入力
import { createLoudness } from "@debuffjp/earshot";
const loud = createLoudness(ctx);
const off = loud.onLevel((level) => { if (level >= 2) monster.hear(player); });
// ボタンから呼びます。部屋の音を測る 3 秒間、プレイヤーには静かにしてもらいます。
const { ok, error } = await loud.enableMic();
loud.level; // 0〜3
loud.micStatus; // "off" | "calibrating" | "on"
loud.disableMic();
off();createLoudness には AudioContext が必要です。同じタップやキー入力で resume してください。enableMic() は reject しません。マイクを拒否されると { ok: false, error } が返り、error はブラウザのエラー名です。press はそのまま使えます。
ブラウザは要求を無視することがあるので、実際の設定は loud.applied で確認してください。エコーキャンセル、ノイズ抑制、自動ゲインは音量の差を平らにするため、デフォルトでオフです。要求するなら browserProcessing: true を渡します。
マイクには HTTPS か localhost が必要です。iframe には allow="microphone" も必要です。iPhone ではマイクを開くとゲームの音に影響する場合があります。制限を見てください。
キャリブレーション
enableMic() はマイクを開き、calibrateMs(デフォルトは 3000)の間音を聞いてから完了します。その読み取り値の 20 パーセンタイルがノイズフロアになります。事前にプレイヤーへ静かにするよう伝え、micStatus が "calibrating" の間はそれを表示してください。
部屋の状況が変わったら、測り直します。
await loud.recalibrate(); // 先にプレイヤーへ静かにするよう伝えます。
loud.overFloorDb; // ノイズフロアから何 dB 上か。調整済みのマイクがなければ nullレベル
レベルはノイズフロアを基準にするので、部屋の騒がしさによらず同じように動きます。
| レベル | ノイズフロアからの差 |
|---|---|
| 0 | 10 dB 未満 |
| 1 | 10 dB 以上 |
| 2 | 20 dB 以上 |
| 3 | 30 dB 以上 |
| オプション | 意味 | デフォルト |
|---|---|---|
steps | レベル 1、2、3 のノイズフロアからの dB | [10, 20, 30] |
attackMs | レベルが上がるまでに大きな音が続くべき時間 | 150 |
releaseMs | レベルが下がるまでに静かな状態が続くべき時間 | 400 |
hysteresisDb | 音がしきい値をこの dB だけ下回るまで、レベルを保ちます | 5 |
loud.level はマイクと press の大きいほうです。onLevel は値が変わったときだけ呼ばれ、コールバックを外す関数を返します。
自分の読み取り値を渡すなら、同じ処理をマイクなしで使える createLevelDetector があります。
import { createLevelDetector } from "@debuffjp/earshot";
const detector = createLevelDetector({ steps: [6, 12, 18] });
detector.calibrate([-62, -60, -61, -60]); // 静かな間に取った dB の値
detector.update(-40, 16); // dB と、前回の読み取りからのミリ秒calibrate を呼ぶまで、update は 0 を返します。
heardDb
壁と距離をゲームのルールに反映するには、モンスターのいる場所での音量を求めます。しきい値はゲームに合わせて調整してください。私たちのデモでは 6 dB がちょうどよく感じられました。
import { computeMix, heardDb, wallsOnGrid, DEFAULT_MATERIALS, DEFAULT_PARAMS } from "@debuffjp/earshot";
const walls = wallsOnGrid(tiles, player, monster); // どちらもタイル単位。
const mix = computeMix(player, monster, walls, DEFAULT_PARAMS, DEFAULT_MATERIALS);
if (loud.level >= 2 && heardDb(loud.level, mix) >= 6) monster.wake();heardDb(level, mix) は、レベルの音量にミックスのゲインを dB で加えます。レベル 0 と範囲外のミックスは、どちらも -Infinity になります。steps を変えたときは、レベル 0 を先頭にした同じ値を第 3 引数に渡してください。
heardDb(loud.level, mix, [-Infinity, 6, 12, 18]);アクセシビリティのルール
press()を使うキーかボタンを必ず用意してください。- 言葉や長時間の発声を必須にしないでください。
- マイクの用途をプレイヤーに伝えてから許可を求めてください。
press は次に変えるまでレベルを保ちます。マイクでできることは、すべてマイクなしでもできます。
addEventListener("keydown", (e) => { if (e.code === "KeyF") loud.press(2); });
addEventListener("keyup", (e) => { if (e.code === "KeyF") loud.press(0); });