# 機能設計書 57-カスタムエフェクト

## 概要

本ドキュメントは、K-ShootMania（KSM）のプレイ画面におけるカスタムエフェクト機能の設計を記述する。カスタムエフェクトは、KSH譜面ファイルの`#define_fx`および`#define_filter`ディレクティブによりユーザーが独自にパラメータを定義したオーディオエフェクトの初期化・適用を行う機能である。

### 本機能の処理概要

カスタムエフェクト機能は、譜面ファイル内の`#define_fx`（FXノート用）と`#define_filter`（レーザーフィルター用）の定義を解析し、既存の11種類のエフェクトタイプ（Retrigger, Gate, Flanger, PitchShift, BitCrusher, Phaser, Wobble, TapeStop, Echo, SideChain, SwitchAudio）のパラメータをカスタマイズしたエフェクトインスタンスを生成・管理する。

**業務上の目的・背景**：譜面制作者がデフォルトのエフェクトパラメータでは実現できない独自の音響効果を定義するために必要な機能である。例えば、デフォルトとは異なるfeedbackLevel値のEchoや、特定のloFreq/hiFreq値のWobbleなどを定義できる。

**機能の利用シーン**：KSH譜面ファイルに`#define_fx`または`#define_filter`が含まれる場合に自動的に解析・初期化される。FXノートまたはレーザーフィルターとしてプレイ中に適用される。

**主要な処理内容**：
1. `#define_fx`定義の解析（userfx_name/userfx_params配列への展開）
2. `#define_filter`定義の解析（userfilter_name/userfilter_params配列への展開）
3. パラメータの文字列パース（"type=XXX;param1=val1;param2=val2"形式）
4. 値範囲指定の解析（"min>max"形式、"min-max"形式）
5. VSTプラグインインスタンスの動的生成（hFX_User配列）
6. ByPass制御によるON/OFF切替
7. リアルタイムパラメータ更新（userchprm配列による手動パラメータ変更）
8. SwitchAudio型カスタムエフェクトの音声ファイル読み込み

**関連システム・外部連携**：BASS Audio Library、各VSTプラグインDLL（bitc/flan/phas/pitc/regawo/sich/tstp）。

**権限による制御**：特になし。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 5 | ゲームプレイ画面 | 主画面 | ユーザー定義#defineによるカスタムオーディオエフェクトの初期化・適用 |

## 機能種別

データ解析処理 / リアルタイム音声処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| fxdefbuf_fx | notesel buffer | Yes | #define_fx定義の行バッファ | 存在チェック |
| fxdefbuf_filter | notesel buffer | Yes | #define_filter定義の行バッファ | 存在チェック |
| feffect | int | Yes | カスタムFXエフェクト使用フラグ（0 or 1） | - |

### 入力データソース

- KSH譜面ファイルの`#define_fx`ディレクティブ
- KSH譜面ファイルの`#define_filter`ディレクティブ
- fxdef.hspのエフェクト定義テーブル

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| userfx_name | string[] | ユーザー定義FXエフェクト名配列 |
| userfx_params | double[][] | ユーザー定義FXパラメータ配列 |
| userfx_params_enable | double[][] | エフェクト有効時のパラメータ値 |
| userfilter_name | string[] | ユーザー定義フィルター名配列 |
| userfilter_params | double[][] | ユーザー定義フィルターパラメータ配列 |
| userfilter_params_min | double[][] | フィルターパラメータ最小値 |
| userfilter_params_max | double[][] | フィルターパラメータ最大値 |
| hFX_User | int[] | ユーザー定義VSTエフェクトハンドル配列 |
| userfxnum | int | ユーザー定義FXの総数 |
| userfilternum | int | ユーザー定義フィルターの数 |

### 出力先

インメモリ配列およびオーディオ出力デバイス

## 処理フロー

### 処理シーケンス

```
1. 譜面読み込みフェーズ（play_chart_load.hsp）
   └─ #define_fx / #define_filter 行をfxdefbuf_fx/fxdefbuf_filterに蓄積
2. カスタムエフェクト初期化（initCustomAudioEffects）
   └─ feffect=1の場合のみ実行
   a. fxdefbuf_fxの各行を解析
      └─ "type=XXX"でエフェクトタイプを特定
      └─ 各パラメータを解析しuserfx_params配列に格納
      └─ ">"区切りで通常値/有効値を分離
   b. fxdefbuf_filterの各行を解析
      └─ 同様にuserfilter_params/min/max配列に格納
      └─ "-"区切りでmin/max範囲を分離
   c. SwitchAudio型の音声ファイル読み込み（loadAudioFilesForSwitchAudio）
3. VSTプラグイン動的生成（applyVSTEffects）
   └─ userfx_fl配列でフラグが立っているものだけDLLをロード
   └─ 各パラメータをVSTプラグインに設定
   └─ ByPass(param29)=1.0で初期状態は無効
4. リアルタイム処理（processAudioEffects）
   └─ FXノート/レーザーフィルターに基づくByPass切替
   └─ userchprm配列による手動パラメータ変更の適用
   └─ BPM連動パラメータの自動更新
   └─ トリガー同期処理（Retrigger/Gate/Wobble/Echo/SideChain型）
```

### フローチャート

```mermaid
flowchart TD
    A[譜面読み込み] --> B{#define_fx/filter あり?}
    B -->|Yes| C[initCustomAudioEffects]
    B -->|No| D[カスタムエフェクト未使用]
    C --> E[エフェクトタイプ特定]
    E --> F[パラメータ解析]
    F --> G{SwitchAudio型?}
    G -->|Yes| H[音声ファイル読み込み]
    G -->|No| I[applyVSTEffects]
    H --> I
    I --> J[VSTプラグイン動的生成]
    J --> K[processAudioEffects]
    K --> L{FXノート区間?}
    L -->|Yes| M[ByPass=0, パラメータ適用]
    L -->|No| N[ByPass=1]
    M --> K
    N --> K
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-57-1 | エフェクトタイプ制限 | 既存11種類のエフェクトタイプのみ使用可能 | #define解析時 |
| BR-57-2 | SwitchAudio上限 | SwitchAudioは最大31個まで | swaudionum>=31でエラー |
| BR-57-3 | パラメータ範囲分離 | ">"で通常値/有効値、"-"でmin/maxを分離 | #define_filter解析時 |
| BR-57-4 | ByPass制御 | FXノート区間外はparam29=1.0（無効）、区間内はparam29=0.0（有効） | processAudioEffects |
| BR-57-5 | BPM連動自動更新 | FXDEF_LENGTH型パラメータはBPM変化時に自動再計算 | bpmfx!=bpmfxp |
| BR-57-6 | 未知パラメータ警告 | 解析時に未知のパラメータ名が出現した場合は警告ダイアログ表示 | "Warning: Unknown paramater" |
| BR-57-7 | 未知エフェクト型エラー | 解析時に未知のエフェクトタイプが出現した場合はエラーダイアログ表示 | "Error: Unknown effect type" |

### 計算ロジック

- **パラメータ文字列解析**: `fxdef_str2param(value_string, type)` 関数で型に応じた変換
- **BPM連動更新**: `maxf(minf(userfx_params.cnt.cnt * 60*4*1000/bpmfx/10, 1.0), 0.0)`
- **フィルター補間**: `min*(1-pdstat) + max*pdstat` （レーザー位置による線形補間）

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

本機能はデータベースを使用しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 未知エフェクト型 | "type=XXX"で未知のタイプ名 | ダイアログ表示し当該定義をスキップ |
| - | 未知パラメータ | パラメータ名がテーブルに存在しない | 警告ダイアログ表示し当該パラメータをスキップ |
| - | SwitchAudio上限超過 | swaudionum>=31 | エラーダイアログ表示 |
| - | 不正なフォーマット | "key=value"形式でない | 警告ダイアログ表示 |
| - | DLLロード失敗 | 対応するDLLが存在しない | エフェクト未適用で続行 |

### リトライ仕様

リトライ処理は行わない。

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

不要。

## パフォーマンス要件

- ユーザー定義エフェクト数に比例してVSTプラグインインスタンスが増加
- SwitchAudioのパフォーマンス影響が大きいため、ユーザー定義エフェクトにはSwitchAudio適用を除外

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

- 譜面ファイルから任意のパラメータを読み込むため、不正な値による予期しない動作に注意
- SwitchAudioでは外部音声ファイルを読み込むため、ファイルパスの検証が必要

## 備考

- feffect=0の場合、カスタムFXエフェクトは使用不可（レーザーフィルターのみ使用）
- feffectnow値が100以上の場合、ユーザー定義エフェクト（feffectnow-100がインデックス）
- userfxnum-userfilternumがFX専用エフェクト数、userfilternumがフィルター数

---

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

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

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | fxdef.hsp | `src/audio/fxdef.hsp` | 11種類のエフェクトタイプ定義テーブル全体 |

**読解のコツ**: カスタムエフェクトは既存のエフェクトタイプをベースにパラメータをオーバーライドする仕組み。fxdef_name配列の各エフェクトのパラメータ名を把握することが重要。

- **36-48行目**: FXDEF_FXTYPE_* 定数（0=RETR, 1=GATE, ..., 10=AUDI）
- **24-34行目**: FXDEF_* パラメータ型定数
- **64-206行目**: 全エフェクトのパラメータテーブル

#### Step 2: カスタムエフェクト初期化

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

**主要処理フロー**:
1. **1-77行目**: `#define_fx`の解析（userfx_name/params配列への展開）
2. **78-178行目**: `#define_filter`の解析（userfilter_name/params/min/max配列への展開）
3. **185-213行目**: SwitchAudio音声ファイルの読み込みとリンク

**読解のコツ**:
- `fxdefstat.0`がエフェクト名、`fxdefstat.1`がパラメータ文字列
- セミコロン区切りでパラメータを分割、イコール区切りでキー=値を分離
- ">"は通常値>有効値の区切り、"-"はmin-max範囲の区切り

#### Step 3: VSTプラグイン動的生成

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | play_audio_effects.hsp | `src/scene/play/play_audio_effects.hsp` | applyVSTEffectsでのユーザー定義エフェクトロード |

- **290-313行目**: userfx_fl配列に基づくDLLの動的ロードとパラメータ設定

#### Step 4: リアルタイム処理

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | play_audio_effects.hsp | `src/scene/play/play_audio_effects.hsp` | processAudioEffectsでのByPass制御・パラメータ更新 |

- **374-399行目**: フィルター型カスタムエフェクトのリアルタイムパラメータ更新
- **498-506行目**: ByPass制御（FXノート区間内/外）
- **508-567行目**: userchprm配列による手動パラメータ変更
- **742-770行目**: ON時のカスタムエフェクトパラメータ適用

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

```
play_init
    |
    +-- loadKSHChartFile
    |       +-- #define_fx行をfxdefbuf_fxに蓄積
    |       +-- #define_filter行をfxdefbuf_filterに蓄積
    |
    +-- initCustomAudioEffects
    |       +-- fxdefbuf_fx解析 -> userfx_name/params
    |       +-- fxdefbuf_filter解析 -> userfilter_name/params/min/max
    |       +-- loadAudioFilesForSwitchAudio
    |
    +-- applyVSTEffects
    |       +-- hFX_User[i] = BASS_VST_ChannelSetDSP(DLL)
    |       +-- 各パラメータ設定 + ByPass=1
    |
    +-- processAudioEffects
            +-- ByPass制御（FXノート区間ON/OFF）
            +-- userchprm手動パラメータ変更
            +-- BPM連動自動更新
            +-- トリガー同期（RETR/GATE/WOBB/ECHO/SICH型）
```

### データフロー図

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

#define_fx行 ----------> initCustomAudioEffects ---------> userfx_name/params
#define_filter行 ------> 文字列パース -----------------> userfilter_params/min/max
                              |
fxdef.hspテーブル -----> エフェクトタイプ特定 ----------> userfx_params.*.0 (型ID)
                              |
SwitchAudioファイル ---> loadAudioFilesForSwitchAudio --> mid_sw配列
                              |
FXノート区間 ----------> applyVSTEffects/process -------> hFX_User配列
BPMデータ -------------> BPM連動更新 ------------------> VSTパラメータ
レーザー位置 ----------> フィルター補間 ----------------> VSTパラメータ
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| fxdef.hsp | `src/audio/fxdef.hsp` | ソース | 全エフェクトタイプのパラメータ定義テーブル |
| play_audio_effects.hsp | `src/scene/play/play_audio_effects.hsp` | ソース | カスタムエフェクトの初期化・VSTロード・リアルタイム処理 |
| play_chart_load.hsp | `src/scene/play/play_chart_load.hsp` | ソース | #define_fx/#define_filter行の蓄積 |
| regawo.dll | `lib/regawo.dll` | 外部DLL | Retrigger/Gate/Wobble/Echo用VSTプラグイン |
| bitc.dll | `lib/bitc.dll` | 外部DLL | BitCrusher VSTプラグイン |
| flan.dll | `lib/flan.dll` | 外部DLL | Flanger VSTプラグイン |
| phas.dll | `lib/phas.dll` | 外部DLL | Phaser VSTプラグイン |
| pitc.dll | `lib/pitc.dll` | 外部DLL | PitchShift VSTプラグイン |
| sich.dll | `lib/sich.dll` | 外部DLL | SideChain Compressor VSTプラグイン |
| tstp.dll | `lib/tstp.dll` | 外部DLL | TapeStop VSTプラグイン |
