# API

0.3.0 の `@debuffjp/earshot` のすべてのエクスポートです。印のないものは 0.2 より前からあります。

## サウンド {#sound}

### createListener {#createlistener}

```ts
function createListener(ctx: BaseAudioContext, options: ListenerOptions): Listener;

interface ListenerOptions {
  output?: AudioNode;
  tile?: number;
  world?: World;
  params?: Partial;
  materials?: Record;
  reverbs?: Record;
  pos(): Point;
}

interface Listener {
  readonly params: Params;
  readonly materials: Record;
  readonly reverbs: Record;
  source(input: AudioNode, options: SourceOptions): Source;
  voice(stream: MediaStream, options: VoiceOptions): Voice;
  update(): void;
  dispose(): void;
}
```

`voice` は 0.2 で追加しました。[リスナー](./sound#listeners)を見てください。

### World {#world}

```ts
interface World {
  wallsBetween?(a: Point, b: Point): readonly string[];
  reverbAt?(p: Point): string | null | undefined;
}
```

座標はタイル単位です。

### Source {#source}

```ts
interface SourceOptions { pos(): Point }

type SourceState = "audible" | "out-of-range" | "muted";

interface Source {
  readonly state: SourceState;
  readonly mix: Mix | null;
  readonly reverb: string | null;
  muted: boolean;
  remove(): void;
}
```

0.3 で変更：新しい音源はフェードインせず、最初からミックスどおりの状態で始まります。

### Point, Material, Reverb, Params {#point-material-reverb-params}

```ts
interface Point { x: number; y: number }
interface Material { hz: number; db: number }
interface Reverb { seconds: number; wetDb: number }

interface Params {
  fullRadius: number;
  silentRadius: number;
  panWidth: number;
  panRange: number;
  smoothing: number;
  multiWall: Material;
}
```

### デフォルト値 {#defaults}

```ts
const DEFAULT_PARAMS: Readonly;
const DEFAULT_MATERIALS: Readonly>;
const DEFAULT_REVERBS: Readonly>;
```

値は[パラメータ](./sound#params)、[素材](./sound#materials)、[リバーブ](./sound#reverbs)にあります。

### wallsOnGrid {#wallsongrid}

```ts
function wallsOnGrid(tiles: ReadonlyArray>, a: Point, b: Point): string[];
```

タイル座標の 2 点の間にある壁を返します。`tiles[y][x]` には素材の名前を入れるか、何も入れません。

### wallsAlong {#wallsalong}

0.3 で追加しました。

```ts
function wallsAlong(at: (x: number, y: number) => string | null | undefined, a: Point, b: Point): string[];
```

入れ子の配列ではないマップ向けの `wallsOnGrid` です。

### distanceGain {#distancegain}

```ts
function distanceGain(d: number, full: number, silent: number): number;
```

`full` の内側で 1、`silent` からちょうど 0、その間は smoothstep です。

### computeMix と Mix {#computemix}

```ts
function computeMix(
  listener: Point,
  source: Point,
  walls: readonly string[],
  params: Params,
  materials: Readonly>,
): Mix;

interface Mix {
  distance: number;
  gain: number;
  cutoff: number;
  pan: number;
  walls: readonly string[];
}
```

判断の全体を数値で返します。座標はタイル単位です。未知の素材の壁が 1 枚だけあると例外を投げます。

## ラウドネス {#loudness}

### createLoudness {#createloudness}

```ts
function createLoudness(ctx: AudioContext, options?: LoudnessOptions): Loudness;

interface LoudnessOptions extends DetectorOptions {
  calibrateMs?: number;
  browserProcessing?: boolean;
}

interface Loudness {
  readonly level: LoudLevel;
  readonly micStatus: MicStatus;
  readonly overFloorDb: number | null;
  readonly applied: MediaTrackSettings | null;
  press(level: LoudLevel): void;
  enableMic(): Promise;
  recalibrate(): Promise;
  disableMic(): void;
  onLevel(callback: (level: LoudLevel) => void): () => void;
}

type LoudLevel = 0 | 1 | 2 | 3;
type MicStatus = "off" | "calibrating" | "on";
interface MicResult { ok: boolean; error?: string }
```

[ラウドネス](./loudness)を見てください。

### createLevelDetector {#createleveldetector}

```ts
function createLevelDetector(options?: DetectorOptions): LevelDetector;

interface DetectorOptions {
  steps?: readonly [number, number, number];
  attackMs?: number;
  releaseMs?: number;
  hysteresisDb?: number;
}

interface LevelDetector {
  readonly floor: number | null;
  readonly level: LoudLevel;
  calibrate(readings: readonly number[]): void;
  update(db: number, dtMs: number): LoudLevel;
}
```

### heardDb {#hearddb}

```ts
function heardDb(level: number, mix: Pick, levelDb?: readonly number[]): number;
```

ある地点での音の大きさを dB で返します。`levelDb` のデフォルトは `[-Infinity, 10, 20, 30]` です。

## ボイス {#voice}

すべて 0.2 で追加しました。[ボイス](./voice)を見てください。

### Voice 型 {#voice-type}

```ts
interface VoiceOptions extends SourceOptions { speakingDb?: number }

interface Voice extends Source {
  readonly levelDb: number;
  readonly speaking: boolean;
}
```

`listener.voice()` が返します。`OfflineAudioContext` では例外を投げます。

### createVoiceMic {#createvoicemic}

```ts
function createVoiceMic(options: VoiceMicOptions): VoiceMic;

interface VoiceMicOptions {
  canUseVoice(): boolean;
  echoCancellation?: boolean | "all" | "remote-only";
  pushToTalk?: boolean;
}

interface VoiceMic {
  readonly stream: MediaStream | null;
  readonly applied: MediaTrackSettings | null;
  readonly live: boolean;
  muted: boolean;
  pushToTalk: boolean;
  talk(held: boolean): void;
  start(): Promise;
  stop(): void;
}
```

### createRoomCode {#createroomcode}

```ts
function createRoomCode(): string;
```

128 ビットの乱数を URL セーフな base64 にしたものです。

### joinVoiceRoom {#joinvoiceroom}

```ts
function joinVoiceRoom(options: VoiceRoomOptions): Promise;

interface VoiceRoomOptions {
  url: string;
  code: string;
  mic: VoiceMic;
  listener: Listener;
  ipPolicy: "relay" | "direct";
  pos(peer: string): Point;
  onPeer?(peer: string, voice: Voice): void;
  onLeave?(peer: string): void;
  onMessage?(peer: string, message: unknown): void;
}

interface VoiceRoom {
  readonly id: string;
  readonly peers: ReadonlyMap;
  connection(peer: string): RTCPeerConnectionState | null;
  send(message: unknown): void;
  leave(): void;
}

type JoinResult = { ok: true; room: VoiceRoom } | (MicResult & { ok: false; error: string });
```

reject しません。[接続とエラー](./voice#connections-and-errors)を見てください。

## 関連記事 {#further-reading}

- [Earshot 0.2 のリリース記事](/ja/blog/earshot-sound-through-walls)
- [壁は音に何をするのか](/ja/research/what-a-wall-does-to-sound)