# 機能設計書 108-AudioLoader

## 概要

本ドキュメントは、Three.jsライブラリにおける音声ファイル読み込み機能「AudioLoader」の設計について記述する。AudioLoaderは、音声ファイルを読み込み、Web Audio APIで使用可能なAudioBufferに変換するローダークラスである。

### 本機能の処理概要

**業務上の目的・背景**：3Dアプリケーションにおいて、BGM、効果音、環境音などの音声は重要な要素である。AudioLoaderは、音声ファイルをブラウザのAudioContextでデコードし、Three.jsのAudioシステムで使用可能な形式に変換する機能を提供する。

**機能の利用シーン**：
- BGM、効果音の読み込み
- 3D空間オーディオ用サウンドの準備
- 環境音、アンビエントサウンドの読み込み
- ゲームやインタラクティブアプリケーションの音声プリロード

**主要な処理内容**：
1. FileLoaderを使用して音声ファイルをArrayBufferとして読み込み
2. バッファのコピーを作成（decodeAudioDataがバッファをdetachするため）
3. AudioContext.decodeAudioData()でAudioBufferに変換
4. AudioBufferをコールバックに渡す

**関連システム・外部連携**：
- FileLoader: 音声ファイルの読み込み
- AudioContext: ブラウザのWeb Audio API
- Audio/PositionalAudio: AudioBufferを使用する音声オブジェクト
- LoadingManager: 読み込み進捗管理

**権限による制御**：特になし（ブラウザの自動再生ポリシーに依存）

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 直接関連する画面なし |

## 機能種別

データ読み込み / 音声ローダー / メディア変換

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| url | string | Yes | 読み込む音声ファイルのパス/URL | なし |
| onLoad | function(AudioBuffer) | No | 読み込み完了時のコールバック | なし |
| onProgress | function | No | 進捗コールバック | なし |
| onError | function | No | エラー発生時のコールバック | なし |
| manager | LoadingManager | No | ローディングマネージャー | なし |

### 入力データソース

サポート形式（ブラウザ依存）：
- MP3 (.mp3)
- OGG Vorbis (.ogg)
- WAV (.wav)
- AAC (.aac, .m4a)
- WebM Audio (.webm)

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| audioBuffer | AudioBuffer | デコードされた音声バッファ（Web Audio API） |

### 出力先

- onLoadコールバック関数への引数として渡される

## 処理フロー

### 処理シーケンス

```
1. load()メソッド呼び出し
2. FileLoader設定
   └─ responseType = 'arraybuffer'
3. FileLoader.load()で音声ファイル取得
4. バッファのコピー作成（buffer.slice(0)）
5. AudioContext.getContext()でコンテキスト取得
6. context.decodeAudioData()でデコード
7. デコード成功時: onLoadコールバック実行
8. デコード失敗時: handleError()でエラー処理
```

### フローチャート

```mermaid
flowchart TD
    A[load開始] --> B[FileLoader設定]
    B --> C[responseType = arraybuffer]
    C --> D[FileLoader.load]
    D --> E[buffer.slice でコピー作成]
    E --> F[AudioContext.getContext]
    F --> G[decodeAudioData]
    G --> H{デコード成功?}
    H -->|Yes| I[onLoad実行]
    H -->|No| J[handleError]
    J --> K[onError実行]
    J --> L[manager.itemError]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-108-1 | バッファコピー | decodeAudioDataがバッファをdetachするためコピーを作成 | 常時 |
| BR-108-2 | 共有AudioContext | AudioContext.getContext()でグローバルコンテキストを使用 | 常時 |
| BR-108-3 | Promise対応 | decodeAudioDataはPromiseを返す（.catch対応） | 常時 |

### 計算ロジック

特になし

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

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ファイル読み込みエラー | ネットワークエラー、ファイル不存在 | onErrorコールバック実行 |
| - | デコードエラー | 非対応形式、破損ファイル | handleError()でonErrorコールバック実行、manager.itemError() |

### リトライ仕様

自動リトライ機能なし

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

該当なし

## パフォーマンス要件

- バッファのコピーによるメモリ使用量増加に注意
- 大きな音声ファイルはメモリを圧迫する可能性

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

- CORSに対応（crossOrigin設定）
- ブラウザの自動再生ポリシーにより、ユーザーインタラクション前の再生は制限される場合がある

## 備考

- decodeAudioData()はバッファを「detach」するため、再利用のためにコピーが必要
- AudioContextはシングルトンとして共有される（AudioContext.getContext()）
- ブラウザによってサポートされる音声形式が異なる

---

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

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

### 推奨読解順序

#### Step 1: AudioContextの構造を理解する

Three.jsのAudioContextラッパーを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | AudioContext.js | `src/audio/AudioContext.js` | getContext()でシングルトン取得 |

**読解のコツ**: AudioContextはブラウザのWeb Audio APIをラップし、グローバルに共有されるコンテキストを提供する。

#### Step 2: ファイル読み込みフローを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | AudioLoader.js | `src/loaders/AudioLoader.js` | 45-93行目: load()メソッド |

**主要処理フロー**:
- **49行目**: new FileLoader(this.manager)
- **50行目**: loader.setResponseType('arraybuffer') - バイナリ取得
- **54行目**: FileLoader.load()開始
- **58-60行目**: バッファのコピー作成
- **62行目**: AudioContext.getContext()
- **63-67行目**: decodeAudioData()でデコード

#### Step 3: エラー処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | AudioLoader.js | `src/loaders/AudioLoader.js` | 77-91行目: handleError関数 |

**主要処理フロー**:
- **79-87行目**: onErrorがあれば実行、なければerror()
- **89行目**: manager.itemError(url)

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

```
AudioLoader.load(url, onLoad, onProgress, onError)
    │
    ├─ FileLoader.setResponseType('arraybuffer')
    │
    ├─ FileLoader.load(url)
    │      └─ ArrayBuffer取得
    │
    ├─ buffer.slice(0) [バッファコピー]
    │
    ├─ AudioContext.getContext()
    │
    └─ context.decodeAudioData(bufferCopy)
           │
           ├─ success: onLoad(audioBuffer)
           │
           └─ error: handleError(e)
                      ├─ onError(e) [if defined]
                      └─ scope.manager.itemError(url)
```

### データフロー図

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

Audio File ──▶ FileLoader ──▶ ArrayBuffer
(mp3,ogg,wav)        │             │
                     │             ▼
                     │      buffer.slice(0) [コピー]
                     │             │
                     │             ▼
                     │      AudioContext.getContext()
                     │             │
                     │             ▼
                     │      decodeAudioData(bufferCopy)
                     │             │
                     │             ▼
                     └──────▶ AudioBuffer
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| AudioLoader.js | `src/loaders/AudioLoader.js` | ソース | 音声ローダー本体（99行） |
| FileLoader.js | `src/loaders/FileLoader.js` | ソース | バイナリファイル取得 |
| AudioContext.js | `src/audio/AudioContext.js` | ソース | Web Audio APIラッパー |
| Audio.js | `src/audio/Audio.js` | ソース | 音声再生オブジェクト |
| PositionalAudio.js | `src/audio/PositionalAudio.js` | ソース | 3D音声オブジェクト |
| Loader.js | `src/loaders/Loader.js` | ソース | ローダー基底クラス |
