# 機能設計書 46-レーザーエフェクト

## 概要

本ドキュメントは、K-ShootMania のプレイ画面におけるレーザーエフェクト機能の設計を記述する。レーザーノブの位置に連動したPeaking Filter（帯域強調フィルター）とCompressorをリアルタイムに適用し、プレイヤーのレーザー操作に応じた音響効果を楽曲に付与する機能である。

### 本機能の処理概要

**業務上の目的・背景**：K-ShootManiaではL/Rの2つのアナログレーザーノブが存在し、プレイヤーがレーザーを操作することで楽曲にリアルタイムのオーディオエフェクトが適用される。レーザーの位置（0-1000のアナログ値）に応じてフィルターの周波数やゲインが変化し、インタラクティブな音楽体験を実現する。

**機能の利用シーン**：プレイ画面でpeffect=1（レーザーフィルターエフェクト有効）の場合に、レーザーの位置値（pdstat: 0.0-1.0）に基づいてPeaking Filterの周波数・ゲイン・帯域幅パラメータがリアルタイムに更新される。

**主要な処理内容**：
1. 譜面読み込み時にPeaking Filter（hPeakFX/hPeakFX2）を各チャンネルに設定（BASS_ChannelSetFXタイプ0x10013）
2. BitCrusher（hBitCFX）も予備エフェクトとして各チャンネルに設定
3. 毎フレーム、レーザー位置（panalognow/analogpos）からpdstatを計算
4. pdstat値に基づいてBASS_FXSetParametersでPeaking Filterのパラメータを更新
5. filtertype変数（0: デフォルト, 1: LowPass風, 3: HighPass風, 5: BitCrusher）に応じたフィルター特性の切替
6. Compressor（hCompFX）の動的生成・適用によるサイドチェイン的な音圧制御

**関連システム・外部連携**：BASS Audio Library（bass.dll/bass_fx.dll）、bass_vst.dll（BitCrusher用）

**権限による制御**：特になし。peffect=1の場合に自動的に有効化。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 5 | ゲームプレイ画面 | 主画面 | レーザー位置連動のPeaking Filter・Compressorリアルタイムエフェクト適用 |

## 機能種別

リアルタイムオーディオエフェクト処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| peffect | 整数 | Yes | レーザーフィルターエフェクト有効フラグ | 0または1 |
| pdstat | 浮動小数点 | Yes | レーザー位置正規化値（0.0-1.0） | 0.0以上1.0以下 |
| filtertype | 整数 | Yes | フィルタータイプ（0=デフォルト, 1=LP風, 3=HP風, 5=BitCrusher, 100+=カスタム） | - |
| canagain | 整数 | No | レーザーエフェクトゲイン値（0-50） | 0以上 |
| pstat2 | 整数 | No | レーザー直角付近フラグ | 0または1 |

### 入力データソース

- ゲームロジック: レーザー位置追跡（analognow/analogpos変数）からpdstatを算出
- 譜面ファイル: filtertypeの指定

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| pfilter | 整数配列 | BASS_FXSetParametersに渡すPeaking Filterパラメータ |
| hPeakFX/hPeakFX2 | 整数配列 | Peaking FilterのFXハンドル |
| hCompFX | 整数配列 | CompressorのFXハンドル |

### 出力先

- BASSオーディオエンジンのFXパラメータ

## 処理フロー

### 処理シーケンス

```
1. 譜面読み込み時のFXハンドル生成
   └─ BASS_ChannelSetFX(mid.cnt, 0x10013, 2/3) で2つのPeaking Filter設定
   └─ BASS_VST_ChannelSetDSP(mid.cnt, bitc.dll) でBitCrusher設定
2. レーザー位置値（pdstat）の計算
   └─ L/Rレーザーの位置値（panalognow）から正規化値を算出
   └─ pdstat = max(L位置, 1000-R位置) / 1000.0
3. フィルタータイプ別パラメータ計算
   └─ filtertype=0: Peaking Filter（デフォルト、pdstat連動の周波数・ゲイン制御）
   └─ filtertype=1: LowPass風フィルター
   └─ filtertype=3: HighPass風フィルター
   └─ filtertype=5: BitCrusher（pdstat*30/128）
   └─ filtertype>=100: カスタムフィルター（ユーザー定義）
4. BASS_FXSetParametersでパラメータ適用
   └─ 全mid配列とmid_sw配列のFXハンドルに対して同一パラメータを適用
5. Compressor動的生成
   └─ アクティブなトラック（mnow/swaudionow_result）にのみCompressorを付与
```

### フローチャート

```mermaid
flowchart TD
    A[毎フレーム: レーザー位置取得] --> B[pdstat計算]
    B --> C{peffect=1 かつ ts_bass閾値?}
    C -->|No| Z[スキップ]
    C -->|Yes| D{filtertype}
    D -->|0| E[デフォルトPeaking Filter]
    D -->|1| F[LowPass風]
    D -->|3| G[HighPass風]
    D -->|5| H[BitCrusher]
    D -->|>=100| I[カスタムフィルター]
    E --> J[BASS_FXSetParameters]
    F --> J
    G --> J
    H --> K[BASS_VST_SetParam_R BitCrusher]
    I --> L[ユーザー定義パラメータ適用]
    J --> M[Compressor動的生成判定]
    K --> M
    L --> M
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-46-01 | pdstat算出 | L/Rレーザーの位置からmax(L*peffstata.0, (1000-R)*peffstata.1)/1000で算出 | peffect=1 |
| BR-46-02 | フィルター更新条件 | ts_bass > max(updateperiod/5, 1)の場合のみ更新 | パフォーマンス制御 |
| BR-46-03 | シュワ効果 | レーザー直角時にshuwat変数で追加ゲイン効果 | disableshuwa=0 |
| BR-46-04 | Compressor適用 | アクティブなチャンネルにのみCompressorを動的生成 | hCompFX.cnt=-1の場合 |

### 計算ロジック

- デフォルトフィルター（filtertype=0）のPeaking Filter周波数:
  `3000*(max(pdstat,0.8)-0.8)/0.2 + 10000 - 9950*(cos(pdstat)*4 + cos(pdstat)^2*5)/9`
- デフォルトフィルターのゲイン:
  `min(max(14*min(pdstat,0.15)/0.15 + 3*(1-|pdstat-0.35|/0.35) - 3.5*(max(pdstat,0.8)-0.8)/0.2, 0), 18) * canagain/50`
- BitCrusher（filtertype=5）: `pdstat * 30.0 / 128.0`

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

本機能ではデータベース操作は発生しない。

## エラー処理

### エラーケース一覧

該当なし。エフェクトパラメータは常にminf/maxfで範囲制限されるため、不正値による異常は発生しない。

### リトライ仕様

該当なし。

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

該当なし。

## パフォーマンス要件

- ts_bass > max(updateperiod/5, 1) の条件でフレームスキップを行い、過剰な更新を防止する
- Peaking Filterパラメータの更新は毎フレーム行われるが、BASSの内部バッファに依存するため実効更新はバッファ長単位

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

特になし。

## 備考

- Peaking Filter FXタイプ0x10013はBASS_FX_BFX_PEAKINGEQに対応する
- Compressor FXタイプ0x10011はBASS_FX_BFX_COMPRESSORに対応する
- Volume FXタイプ0x10003はBASS_FX_BFX_VOLUMEに対応する
- pfilter配列のフォーマット: {fxType, fCenter(float), fGain(float), fBandwidth(float), 0, 0, channel}

---

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

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

### 推奨読解順序

#### Step 1: FXハンドル生成を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | play_chart_load.hsp | `src/scene/play/play_chart_load.hsp` | 各チャンネルへのPeaking Filter/BitCrusher FX設定 |

**主要処理フロー**:
- **593-606行目**: `BASS_ChannelSetFX(mid.cnt, 0x10013, 2)` でhPeakFX設定、`BASS_ChannelSetFX(mid.cnt, 0x10013, 3)` でhPeakFX2設定、`BASS_VST_ChannelSetDSP(mid.cnt, bitc.dll)` でhBitCFX設定

#### Step 2: pdstat算出を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | play_audio_effects.hsp | `src/scene/play/play_audio_effects.hsp` | pdstat計算ロジック |

**主要処理フロー**:
- **820-842行目**: panalognow/analogpos/analognowからpdstat算出。L/R各レーザーの追跡精度判定とpeffstata判定

#### Step 3: フィルターパラメータ適用を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | play_audio_effects.hsp | `src/scene/play/play_audio_effects.hsp` | filtertype別のパラメータ計算と適用 |

**主要処理フロー**:
- **897-996行目**: filtertype=0のデフォルトフィルター: pfilter配列の計算とBASS_FXSetParameters呼び出し
- **951-968行目**: filtertype=1,3のLP/HP風フィルター
- **983-996行目**: filtertype=5のBitCrusher

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

```
start_play
    +-- loadKSHChartFile
    |       +-- BASS_ChannelSetFX -> hPeakFX, hPeakFX2, hBitCFX
    |
    +-- on_update_play (毎フレーム)
            +-- processAudioEffects
                    +-- pdstat計算（レーザー位置から）
                    +-- filtertype別パラメータ計算
                    +-- BASS_FXSetParameters(hPeakFX, pfilter)
                    +-- BASS_FXSetParameters(hPeakFX2, pfilter)
                    +-- BASS_VST_SetParam_R(hBitCFX, 0, pdstat*30/128)
                    +-- Compressor動的生成(hCompFX)
```

### データフロー図

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

レーザー位置                pdstat算出                       Peaking Filterパラメータ
  panalognow[0,1] -------> max(L, 1000-R)/1000 ----------> pfilter配列
  analogpos[0,1]                                            +-- fCenter (Hz)
                                                            +-- fGain (dB)
filtertype                  パラメータ計算                   +-- fBandwidth
  0/1/3/5/100+ ----------> cos/sin/min/max式 ------------> BASS_FXSetParameters
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| play_audio_effects.hsp | `src/scene/play/play_audio_effects.hsp` | ソース | processAudioEffects内のレーザーフィルター処理 |
| play_chart_load.hsp | `src/scene/play/play_chart_load.hsp` | ソース | FXハンドルの初期設定 |
| bass.as | `src/bass.as` | ソース | BASS_ChannelSetFX, BASS_FXSetParameters APIバインディング |
| bass_vst.as | `src/bass_vst.as` | ソース | BASS_VST_ChannelSetDSP, BASS_VST_SetParam_R APIバインディング |
