# 機能設計書 120-PositionalAudio

## 概要

本ドキュメントは、Three.jsにおける`PositionalAudio`クラスの機能設計を記述する。PositionalAudioは、3D空間内の位置に応じて音量・パンが変化する位置依存オーディオオブジェクトを表現する。

### 本機能の処理概要

PositionalAudioクラスは、Audioクラスを継承し、Web Audio APIのPannerNodeを使用して3D空間内での音源の位置と向きを管理する。リスナー（聴取者）との距離と角度に応じて音量とステレオパンが自動的に調整される。

**業務上の目的・背景**：3Dゲームやインタラクティブアプリケーションにおいて、オブジェクトから発せられる音が空間的にリアルに聞こえることは没入感を高める重要な要素である。PositionalAudioは、オブジェクトに音を付加し、プレイヤーの位置に応じた自然な3Dオーディオ体験を提供する。

**機能の利用シーン**：
- 3Dゲームのオブジェクト効果音（敵の足音、環境音など）
- VR/ARアプリケーションでの空間オーディオ
- インタラクティブ3Dシーンでの位置依存サウンド
- シミュレーションでのリアルな音響効果

**主要な処理内容**：
1. PannerNodeによる3D空間オーディオ処理
2. 距離モデル（linear, inverse, exponential）の設定
3. 参照距離、ロールオフファクター、最大距離の制御
4. 指向性コーン（内角、外角、外ゲイン）の設定
5. 位置・向きの自動更新（updateMatrixWorld）

**関連システム・外部連携**：AudioListenerと連携してオーディオグラフを構築。Audioクラスを継承し、再生制御機能を引き継ぐ。Object3Dを継承しているため、3Dオブジェクトに追加可能。

**権限による制御**：特になし（ブラウザのオートプレイポリシーに従う）

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 25 | WebAudioサンプル | 主機能 | 3D位置オーディオの再生 |

## 機能種別

位置依存オーディオ / 3D空間オーディオ / PannerNode制御

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| listener | AudioListener | Yes | グローバルオーディオリスナー | - |

### 入力データソース

- AudioLoaderでロードされたAudioBuffer（Audioクラスから継承）
- Object3D（親オブジェクト）のワールドマトリクス

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| panner | PannerNode | 3D空間オーディオ制御ノード |
| refDistance | number | 参照距離 |
| rolloffFactor | number | ロールオフファクター |
| distanceModel | string | 距離モデル |
| maxDistance | number | 最大距離 |

### 出力先

- PannerNode経由でAudioListenerに接続

## 処理フロー

### 処理シーケンス

```
1. コンストラクタ
   └─ super(listener)でAudio初期化
   └─ createPanner()でPannerNode作成
   └─ panningModel = 'HRTF'
   └─ panner.connect(gain)

2. 空間パラメータ設定
   └─ setRefDistance() - 参照距離
   └─ setRolloffFactor() - 減衰率
   └─ setDistanceModel() - 距離モデル
   └─ setMaxDistance() - 最大距離
   └─ setDirectionalCone() - 指向性コーン

3. updateMatrixWorld() - 位置更新
   └─ matrixWorldからposition/quaternion取得
   └─ orientationベクトル計算
   └─ pannerに位置・向き設定
```

### フローチャート

```mermaid
flowchart TD
    A[PositionalAudio生成] --> B[super/listener/Audio初期化]
    B --> C[createPanner]
    C --> D[panningModel='HRTF']
    D --> E[panner.connect/gain]
    E --> F{操作}
    F -->|setRefDistance| G[panner.refDistance設定]
    F -->|setRolloffFactor| H[panner.rolloffFactor設定]
    F -->|setDistanceModel| I[panner.distanceModel設定]
    F -->|setMaxDistance| J[panner.maxDistance設定]
    F -->|setDirectionalCone| K[coneInner/Outer/Gain設定]
    F -->|updateMatrixWorld| L[matrixWorld分解]
    L --> M[position/orientation計算]
    M --> N{positionX存在?}
    N -->|Yes| O[linearRampToValueAtTime]
    N -->|No| P[setPosition/setOrientation]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-120-01 | HRTFパンニング | デフォルトでHRTF（頭部伝達関数）パンニングモデル使用 | コンストラクタ時 |
| BR-120-02 | 再生中のみ更新 | hasPlaybackControl=true かつ isPlaying=falseなら位置更新スキップ | updateMatrixWorld時 |
| BR-120-03 | 距離モデル | linear/inverse/exponentialの3種類から選択 | setDistanceModel時 |

### 計算ロジック

**距離モデル別の減衰計算**:

- **linear**: `1 - rolloffFactor * (distance - refDistance) / (maxDistance - refDistance)`
- **inverse**: `refDistance / (refDistance + rolloffFactor * (distance - refDistance))`
- **exponential**: `pow(distance / refDistance, -rolloffFactor)`

**向きベクトルの計算**:
```javascript
_orientation.set(0, 0, 1).applyQuaternion(_quaternion)
```

## データベース操作仕様

該当なし

## エラー処理

### エラーケース一覧

Audioクラスから継承したエラーハンドリング（再生中のplay()警告など）

### リトライ仕様

該当なし

## トランザクション仕様

該当なし

## パフォーマンス要件

- HRTF処理によるCPU負荷考慮
- 非再生時の位置更新スキップによる最適化
- linearRampToValueAtTimeによるスムーズな位置補間

## セキュリティ考慮事項

- ブラウザのオートプレイポリシーに準拠（Audioから継承）

## 備考

- Audioクラスを継承し、再生制御機能をすべて引き継ぐ
- getOutput()はpannerを返す（Audioのgainではなく）
- PannerNodeのデフォルトパンニングモデルはHRTF（高品質な3Dオーディオ）

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: クラス構造を理解する

PositionalAudioクラスの継承関係とプロパティを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | PositionalAudio.js | `src/audio/PositionalAudio.js` | コンストラクタ（47-62行目） |

**読解のコツ**: 主要プロパティ
- Audioを継承（super(listener)で初期化）
- `panner`: createPanner()で作成（58行目）
- panningModel: 'HRTF'に設定（59行目）
- panner.connect(this.gain)で接続（60行目）

#### Step 2: オーバーライドメソッドを理解する

Audioクラスからのオーバーライドメソッドを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | PositionalAudio.js | `src/audio/PositionalAudio.js` | connect()（64-72行目） |
| 2-2 | PositionalAudio.js | `src/audio/PositionalAudio.js` | disconnect()（74-82行目） |
| 2-3 | PositionalAudio.js | `src/audio/PositionalAudio.js` | getOutput()（84-88行目） |

**主要処理フロー**:
- **64-72行目**: connect() - super.connect()後にpanner.connect(gain)
- **74-82行目**: disconnect() - super.disconnect()後にpanner.disconnect(gain)
- **84-88行目**: getOutput() - pannerを返す（Audioはgainを返す）

#### Step 3: 距離パラメータを理解する

距離減衰に関するパラメータ設定を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | PositionalAudio.js | `src/audio/PositionalAudio.js` | setRefDistance()（109-115行目） |
| 3-2 | PositionalAudio.js | `src/audio/PositionalAudio.js` | setRolloffFactor()（134-140行目） |
| 3-3 | PositionalAudio.js | `src/audio/PositionalAudio.js` | setDistanceModel()（163-169行目） |
| 3-4 | PositionalAudio.js | `src/audio/PositionalAudio.js` | setMaxDistance()（191-197行目） |

**主要処理フロー**:
- **109-115行目**: setRefDistance() - 減衰開始距離
- **134-140行目**: setRolloffFactor() - 減衰率
- **163-169行目**: setDistanceModel() - 'linear'/'inverse'/'exponential'
- **191-197行目**: setMaxDistance() - 最大減衰距離（linear用）

#### Step 4: 指向性とワールド更新を理解する

指向性コーンと位置更新を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | PositionalAudio.js | `src/audio/PositionalAudio.js` | setDirectionalCone()（207-215行目） |
| 4-2 | PositionalAudio.js | `src/audio/PositionalAudio.js` | updateMatrixWorld()（217-249行目） |

**主要処理フロー**:
- **207-215行目**: setDirectionalCone() - 内角/外角/外ゲイン設定
- **219行目**: super.updateMatrixWorld()呼び出し
- **221行目**: 非再生時は位置更新スキップ
- **223-225行目**: matrixWorldからposition/quaternion/orientation取得
- **229-240行目**: Chrome向けlinearRampToValueAtTime
- **242-245行目**: レガシー向けsetPosition/setOrientation

### プログラム呼び出し階層図

```
PositionalAudio (extends Audio)
    │
    ├─ constructor(listener)
    │      ├─ super(listener)
    │      ├─ context.createPanner()
    │      ├─ panner.panningModel = 'HRTF'
    │      └─ panner.connect(this.gain)
    │
    ├─ connect()
    │      ├─ super.connect()
    │      └─ panner.connect(this.gain)
    │
    ├─ disconnect()
    │      ├─ super.disconnect()
    │      └─ panner.disconnect(this.gain)
    │
    ├─ getOutput()
    │      └─ return this.panner
    │
    ├─ setRefDistance(value)
    │      └─ panner.refDistance = value
    │
    ├─ setRolloffFactor(value)
    │      └─ panner.rolloffFactor = value
    │
    ├─ setDistanceModel(value)
    │      └─ panner.distanceModel = value
    │
    ├─ setMaxDistance(value)
    │      └─ panner.maxDistance = value
    │
    ├─ setDirectionalCone(inner, outer, gain)
    │      ├─ panner.coneInnerAngle = inner
    │      ├─ panner.coneOuterAngle = outer
    │      └─ panner.coneOuterGain = gain
    │
    └─ updateMatrixWorld(force)
           ├─ super.updateMatrixWorld(force)
           ├─ if (!isPlaying && hasPlaybackControl) return
           ├─ matrixWorld.decompose(_position, _quaternion, _scale)
           ├─ _orientation.set(0, 0, 1).applyQuaternion(_quaternion)
           └─ panner.positionX.linearRampToValueAtTime() または
              panner.setPosition() / setOrientation()
```

### データフロー図

```
[入力]                    [処理]                         [出力]

AudioBuffer ────────────▶ setBuffer() ─────────────────▶ this.buffer (Audioから継承)
                                │
                                ▼ (autoplay)
                          play()
                                │
                                ▼
オーディオグラフ:
BufferSource → [Filters] → PannerNode → GainNode → AudioListener → destination
                               │                         │
                               ▼                         ▼
                          3D位置処理               マスターボリューム
                          (距離減衰、パンニング)

親Object3D.matrixWorld ──▶ updateMatrixWorld() ────────▶ panner
                                │                       position/orientation
                                ▼
                          matrixWorld分解
                                │
                                ▼
                          orientation計算
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| PositionalAudio.js | `src/audio/PositionalAudio.js` | ソース | メインクラス定義 |
| Audio.js | `src/audio/Audio.js` | ソース | 基底クラス（再生制御） |
| AudioListener.js | `src/audio/AudioListener.js` | ソース | オーディオリスナー |
| AudioContext.js | `src/audio/AudioContext.js` | ソース | AudioContextシングルトン |
| AudioLoader.js | `src/loaders/AudioLoader.js` | ソース | オーディオファイルローダー |
| Object3D.js | `src/core/Object3D.js` | ソース | 基底クラス |
| Vector3.js | `src/math/Vector3.js` | ソース | 位置・向きベクトル |
| Quaternion.js | `src/math/Quaternion.js` | ソース | 回転クォータニオン |
