本文へスキップ

ラウドネス ​

createLoudness は、マイクの音量をゲームから読める 0〜3 のレベルに変えます。音声はアナライザーまでしか届きません。Earshot は音声を録音、送信、再生しません。

マイク入力 ​

ts
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" の間はそれを表示してください。

部屋の状況が変わったら、測り直します。

ts
await loud.recalibrate(); // 先にプレイヤーへ静かにするよう伝えます。
loud.overFloorDb; // ノイズフロアから何 dB 上か。調整済みのマイクがなければ null

レベル ​

レベルはノイズフロアを基準にするので、部屋の騒がしさによらず同じように動きます。

レベルノイズフロアからの差
010 dB 未満
110 dB 以上
220 dB 以上
330 dB 以上
オプション意味デフォルト
stepsレベル 1、2、3 のノイズフロアからの dB[10, 20, 30]
attackMsレベルが上がるまでに大きな音が続くべき時間150
releaseMsレベルが下がるまでに静かな状態が続くべき時間400
hysteresisDb音がしきい値をこの dB だけ下回るまで、レベルを保ちます5

loud.level はマイクと press の大きいほうです。onLevel は値が変わったときだけ呼ばれ、コールバックを外す関数を返します。

自分の読み取り値を渡すなら、同じ処理をマイクなしで使える createLevelDetector があります。

ts
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 がちょうどよく感じられました。

ts
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 引数に渡してください。

ts
heardDb(loud.level, mix, [-Infinity, 6, 12, 18]);

アクセシビリティのルール ​

  • press() を使うキーかボタンを必ず用意してください。
  • 言葉や長時間の発声を必須にしないでください。
  • マイクの用途をプレイヤーに伝えてから許可を求めてください。

press は次に変えるまでレベルを保ちます。マイクでできることは、すべてマイクなしでもできます。

ts
addEventListener("keydown", (e) => { if (e.code === "KeyF") loud.press(2); });
addEventListener("keyup", (e) => { if (e.code === "KeyF") loud.press(0); });