# 機能設計書: AudioAnalyser（オーディオ周波数解析）

## 1. 機能概要

### 1.1 機能の目的
AudioAnalyserは、Web Audio APIのAnalyserNodeをラップし、three.jsのオーディオシステムにおける周波数解析およびリアルタイムオーディオビジュアライゼーションを実現するためのクラスである。オーディオデータの周波数領域と時間領域の解析を可能にし、音楽に同期したビジュアルエフェクトの実装を支援する。

### 1.2 主な機能
- オーディオソースの周波数データ取得
- 時間領域データ（波形データ）の取得
- 平均周波数値の計算
- FFT（高速フーリエ変換）サイズの設定

### 1.3 関連する画面/コンポーネント
- オーディオビジュアライザー
- 音声反応型エフェクト
- 音楽同期アニメーション

## 2. 機能仕様

### 2.1 データ構造

```javascript
class AudioAnalyser {
    analyser: AnalyserNode;  // Web Audio API AnalyserNode
    data: Uint8Array;         // 周波数データを格納する配列
}
```

### 2.2 プロパティ詳細

| プロパティ名 | 型 | 説明 | デフォルト値 |
|-------------|-----|------|-------------|
| analyser | AnalyserNode | Web Audio APIのAnalyserNodeインスタンス | - |
| data | Uint8Array | 周波数データを格納するバッファ | Uint8Array(fftSize/2) |

### 2.3 メソッド詳細

#### 2.3.1 constructor(audio, fftSize)
```javascript
constructor(audio, fftSize = 2048)
```
**引数:**
- `audio` (Audio): three.jsのAudioまたはAudioインスタンス
- `fftSize` (number): FFTサイズ（2の累乗、32-32768の範囲）

**処理内容:**
1. AudioのgetFilters()[0]を取得し、出力先としてoutputNodeを決定
2. AnalyserNodeを作成し、FFTサイズを設定
3. outputNodeをAnalyserNodeに接続
4. fftSize / 2 サイズのUint8Arrayを作成

#### 2.3.2 getFrequencyData()
```javascript
getFrequencyData(): Uint8Array
```
**戻り値:** 周波数データを含むUint8Array

**処理内容:**
1. AnalyserNodeのgetByteFrequencyData()を呼び出し
2. this.dataに周波数データを格納
3. データを返却

#### 2.3.3 getAverageFrequency()
```javascript
getAverageFrequency(): number
```
**戻り値:** 全周波数成分の平均値（0-255の範囲）

**処理内容:**
1. getFrequencyData()を呼び出して最新データを取得
2. 全データポイントの合計を計算
3. データ配列長で割って平均値を算出
4. 平均値を返却

### 2.4 ビジネスルール
- FFTサイズは2の累乗でなければならない
- データ配列のサイズはfftSize / 2となる（ナイキスト周波数まで）
- 周波数データは0-255の範囲にマッピングされる

### 2.5 状態遷移
AudioAnalyserは状態を持たない。Audioオブジェクトの再生状態に依存し、再生中のみ有効なデータを取得できる。

## 3. 入出力設計

### 3.1 入力データ
| データ項目 | 型 | 必須 | 説明 |
|-----------|-----|------|------|
| audio | Audio | Yes | 解析対象のオーディオオブジェクト |
| fftSize | number | No | FFT解析サイズ（デフォルト2048） |

### 3.2 出力データ
| データ項目 | 型 | 説明 |
|-----------|-----|------|
| frequencyData | Uint8Array | 周波数スペクトルデータ |
| averageFrequency | number | 平均周波数値 |

## 4. 処理フロー

### 4.1 周波数解析フロー
```
[Audioオブジェクト]
      |
      v
[AudioAnalyser生成]
      |
      v
[AnalyserNode作成・接続]
      |
      v
[getFrequencyData()呼び出し]
      |
      v
[周波数データ取得]
      |
      v
[ビジュアライゼーション更新]
```

### 4.2 シーケンス図
```
User           AudioAnalyser      AnalyserNode      Audio
  |                  |                  |              |
  |--new()---------->|                  |              |
  |                  |--getFilters()--->|              |
  |                  |<-outputNode------|              |
  |                  |--createAnalyser--|              |
  |                  |--connect()------>|              |
  |                  |                  |              |
  |--getFrequencyData()--------------->|              |
  |                  |--getByteFrequencyData()------->|
  |<-Uint8Array------|                  |              |
```

## 5. エラーハンドリング

### 5.1 エラー条件
| エラー条件 | エラー種別 | 対処方法 |
|-----------|-----------|---------|
| audioがnull/undefined | TypeError | コンストラクタで有効なaudioオブジェクトを渡す |
| AudioContextが未初期化 | InvalidStateError | ユーザーインタラクション後にAudioを初期化 |
| fftSizeが無効 | IndexSizeError | 2の累乗かつ32-32768の範囲を指定 |

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

### 6.1 推奨読解順序
1. **AudioAnalyser.js** - クラス全体を理解
2. **Audio.js** - オーディオソースの仕組みを理解
3. **AudioListener.js** - オーディオコンテキストの管理を理解

### 6.2 重要な処理の詳細

#### コンストラクタ（8-18行目）
```javascript
constructor( audio, fftSize = 2048 ) {
    this.analyser = audio.context.createAnalyser();
    this.analyser.fftSize = fftSize;
    this.data = new Uint8Array( this.analyser.frequencyBinCount );
    audio.getOutput().connect( this.analyser );
}
```
**8-10行目**: AnalyserNodeの生成とFFTサイズの設定
**11行目**: 周波数ビン数に基づくデータ配列の初期化
**12行目**: オーディオ出力をAnalyserNodeに接続

#### getFrequencyData（27-33行目）
```javascript
getFrequencyData() {
    this.analyser.getByteFrequencyData( this.data );
    return this.data;
}
```
**28行目**: AnalyserNodeから周波数データを取得
**29行目**: データ配列を返却

#### getAverageFrequency（41-55行目）
```javascript
getAverageFrequency() {
    let value = 0;
    const data = this.getFrequencyData();
    for ( let i = 0; i < data.length; i ++ ) {
        value += data[ i ];
    }
    return value / data.length;
}
```
**42-46行目**: 全周波数成分の合計を計算
**47行目**: 平均値を算出して返却

### 6.3 プログラム呼び出し階層図
```
AudioAnalyser
├── constructor()
│   ├── audio.context.createAnalyser()  [Web Audio API]
│   └── audio.getOutput().connect()     [Audio.js]
├── getFrequencyData()
│   └── analyser.getByteFrequencyData() [Web Audio API]
└── getAverageFrequency()
    └── getFrequencyData()              [内部呼び出し]
```

### 6.4 データフロー図
```
[Audio Source]
      |
      | (オーディオストリーム)
      v
[audio.getOutput()]
      |
      | connect()
      v
[AnalyserNode]
      |
      | getByteFrequencyData()
      v
[Uint8Array (周波数データ)]
      |
      | getAverageFrequency()
      v
[number (平均値)]
```

### 6.5 関連ファイル一覧
| ファイルパス | 種別 | 役割 |
|-------------|------|------|
| src/audio/AudioAnalyser.js | メイン | AudioAnalyserクラスの実装 |
| src/audio/Audio.js | 関連 | オーディオソースの管理 |
| src/audio/AudioListener.js | 関連 | AudioContextの提供 |
| src/audio/AudioContext.js | 関連 | AudioContext取得ユーティリティ |

## 7. 使用例

### 7.1 基本的な使用例
```javascript
// オーディオリスナーの作成
const listener = new THREE.AudioListener();
camera.add(listener);

// オーディオソースの作成
const audio = new THREE.Audio(listener);
const audioLoader = new THREE.AudioLoader();

audioLoader.load('music.mp3', (buffer) => {
    audio.setBuffer(buffer);
    audio.play();
});

// アナライザーの作成
const analyser = new THREE.AudioAnalyser(audio, 2048);

// アニメーションループ内で周波数データを使用
function animate() {
    requestAnimationFrame(animate);

    const frequencyData = analyser.getFrequencyData();
    const average = analyser.getAverageFrequency();

    // ビジュアライゼーションの更新
    mesh.scale.y = average / 128;

    renderer.render(scene, camera);
}
```

### 7.2 周波数帯域ごとの解析
```javascript
const analyser = new THREE.AudioAnalyser(audio, 256);

function updateVisualization() {
    const data = analyser.getFrequencyData();

    // 低音域（0-20%）
    const bass = getAverage(data, 0, data.length * 0.2);
    // 中音域（20-60%）
    const mid = getAverage(data, data.length * 0.2, data.length * 0.6);
    // 高音域（60-100%）
    const treble = getAverage(data, data.length * 0.6, data.length);
}
```

## 8. 備考

### 8.1 パフォーマンス考慮事項
- FFTサイズを大きくすると周波数分解能は上がるが、処理負荷も増加
- リアルタイムビジュアライゼーションでは256-2048程度が推奨
- getFrequencyData()は毎フレーム呼び出しても問題ない

### 8.2 ブラウザ互換性
- Web Audio APIをサポートするブラウザで動作
- AudioContextの自動再生ポリシーに注意（ユーザーインタラクションが必要）

### 8.3 制限事項
- クロスオリジンのオーディオソースでは周波数データが取得できない場合がある
- AudioContextは1つのページにつき制限数がある
