# 機能設計書 44-Switch Audio

## 概要

本ドキュメントは、K-ShootMania のプレイ画面における Switch Audio 機能の設計を記述する。特定のタイミングで音楽ファイルをシームレスに切り替える機能であり、FXロングノートやレーザーフィルターと連動してメインの楽曲音声から別の音声ファイル（mid_sw配列）へ切り替えを行う。

### 本機能の処理概要

**業務上の目的・背景**：K-ShootManiaの譜面フォーマットでは、`#define_fx`/`#define_filter`ディレクティブでSwitch Audio型のカスタムエフェクトを定義できる。これにより、FXロングノートの押下やレーザー操作時に、メインの楽曲音声から全く異なる音声ファイルへシームレスに切り替えることで、高度な音楽演出を実現する。

**機能の利用シーン**：譜面ファイルに`#define_fx`/`#define_filter`でtype=SwitchAudioが定義されている場合に使用される。FXロングノート押下中やレーザー操作中に、対応するSwitch Audio音声ファイルへ切り替わる。

**主要な処理内容**：
1. initCustomAudioEffects関数で`#define_fx`/`#define_filter`を解析し、SwitchAudio型エフェクトを検出する
2. loadAudioFilesForSwitchAudio関数でKSHLib_SwitchAudioOpenにより音声ファイルをmid_sw配列に読み込む
3. 読み込んだSwitch Audioチャンネルをmid.0とBASS_ChannelSetLinkで同期リンクする
4. processAudioEffects関数で、feffectnow_real変数に基づきSwitch Audioの有効/無効を判定する
5. swaudionow/swaudionow_filter変数でアクティブなSwitch Audioを決定し、BASS_ChannelSetAttributeでボリュームを制御する

**関連システム・外部連携**：kshlib.dll（KSHLib_SwitchAudioOpen/Free API）、BASS Audio Library

**権限による制御**：特になし。譜面で定義されている場合に自動的に有効化。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 5 | ゲームプレイ画面 | 主画面 | KSHLib経由の特定タイミングでの音楽ファイルシームレス切替(mid_sw配列) |

## 機能種別

リアルタイムオーディオ制御処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| swaudio | 文字列配列 | Yes | Switch Audio用の音声ファイルパス | ファイル存在確認（exist命令） |
| swaudionum | 整数 | Yes | Switch Audioファイル数 | 0-31（最大31個） |
| feffectnow_real | 整数配列 | No | L/R各レーザーの現在有効FXエフェクトID | - |
| filtertype2 | 整数 | No | レーザーフィルターのエフェクトID | 0以上 |

### 入力データソース

- 譜面ファイル（.ksh）の`#define_fx`/`#define_filter`セクションで定義されたSwitchAudioエフェクト
- play_utils.hsp 450-451行目でswaudio配列とswaudionumが設定される

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| mid_sw | 整数配列 | Switch Audio用BASSチャンネルハンドル |
| swaudionow | 整数 | FXエフェクトによるアクティブSwitch AudioインデックスまたはA-1 |
| swaudionow_filter | 整数 | レーザーフィルターによるアクティブSwitch Audioインデックスまたは-1 |
| swaudionow_result | 整数 | 最終的なアクティブSwitch Audio（-1=メイントラック再生） |

### 出力先

- BASSオーディオエンジンへの音声出力

## 処理フロー

### 処理シーケンス

```
1. 譜面解析時のSwitch Audioファイル名登録
   └─ play_utils.hspでswaudio配列にファイル名を格納、swaudionum++
2. カスタムエフェクト初期化（initCustomAudioEffects）
   └─ FXDEF_FXTYPE_AUDIの検出とuserfx_swaudiomidへの対応付け
3. Switch Audio音声ファイル読み込み（loadAudioFilesForSwitchAudio）
   └─ KSHLib_SwitchAudioOpenで各音声ファイルをオープン、mid_sw配列に格納
4. チャンネルリンク設定
   └─ BASS_ChannelSetLink(mid.0, mid_sw.cnt)で同期リンク
5. エフェクト設定
   └─ Peaking Filter、BitCrusherエフェクトをSwitch Audioチャンネルにも設定
6. 毎フレームのSwitch Audio切替（processAudioEffects内）
   └─ feffectnow_real/filtertype2からswaudionow/swaudionow_filterを決定
   └─ swaudionow_result >= 0の場合: mid.0をミュートし、mid_sw.swaudionow_resultにボリューム設定
   └─ swaudionow_result < 0の場合: mid.0にボリューム設定し、全mid_swをミュート
```

### フローチャート

```mermaid
flowchart TD
    A[譜面解析: #define_fx/filter] --> B{SwitchAudio型?}
    B -->|Yes| C[swaudio配列にファイル名登録]
    B -->|No| D[他のエフェクト処理]
    C --> E[KSHLib_SwitchAudioOpen]
    E --> F[mid_sw配列に格納]
    F --> G[BASS_ChannelSetLink mid.0, mid_sw]
    G --> H[毎フレーム: エフェクト状態判定]
    H --> I{FXエフェクト有効?}
    I -->|Yes| J[swaudionow = userfx_swaudiomid]
    I -->|No| K[swaudionow = -1]
    H --> L{レーザーフィルター有効?}
    L -->|Yes| M[swaudionow_filter = userfx_swaudiomid]
    L -->|No| N[swaudionow_filter = -1]
    J --> O[swaudionow_result決定]
    K --> O
    M --> O
    N --> O
    O --> P{swaudionow_result >= 0?}
    P -->|Yes| Q[mid.0ミュート, mid_sw音量ON]
    P -->|No| R[mid.0音量ON, mid_sw全ミュート]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-44-01 | Switch Audio最大数 | Switch Audioファイルは最大31個まで | swaudionum >= 31 でエラーダイアログ表示 |
| BR-44-02 | リンク同期 | Switch AudioチャンネルはメイントラックとBASS_ChannelSetLinkで同期 | loadAudioFilesForSwitchAudio実行時 |
| BR-44-03 | FX優先ルール | swaudionow_filterとswaudionowの両方が有効な場合、swaudionowが優先される | swaudionow != -1 の場合 |
| BR-44-04 | パフォーマンス制限 | Switch Audioにはユーザー定義VSTエフェクトは適用しない | loadAudioFilesForSwitchAudio内コメント参照 |

### 計算ロジック

- swaudionow_result決定ロジック:
  ```
  swaudionow_result = -1
  if swaudionow_filter != -1: swaudionow_result = swaudionow_filter
  if swaudionow != -1: swaudionow_result = swaudionow
  ```

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ファイル上限超過 | swaudionum >= 31 | エラーダイアログ「Error: Too many "Switch Audio" Effects」を表示 |
| - | ファイル不在 | exist命令でstrsize<=0 | エラーダイアログ「Error: Could not find SwitchAudio file」を表示 |
| BASS_ErrorGetCode()!=0 | リンクエラー | BASS_ChannelSetLinkが失敗した場合 | mlinkfailed=1を設定 |

### リトライ仕様

該当なし。

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

該当なし。

## パフォーマンス要件

- Switch Audioの切替はフレーム単位で即座に反映されること
- パフォーマンス重視のため、Switch Audioチャンネルにはユーザー定義VSTエフェクトを適用しない

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

特になし。

## 備考

- KSHLib_SwitchAudioOpenの第3引数0x20000はBASS_STREAM_DECODEフラグに対応し、デコード専用ストリームとして生成される
- Switch AudioチャンネルにもPeaking Filter（hPeakFX_sw）、BitCrusher（hBitCFX_sw）、Compressor（hCompFX_sw）は設定される
- KSHLib_SwitchAudioFreeで解放処理を行う

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | kshlib.as | `src/kshlib.as` | KSHLib_SwitchAudioOpen/Freeの関数宣言 |

**読解のコツ**: KSHLib_SwitchAudioOpenは第1引数がインデックス、第2引数がファイルパス、第3引数がフラグ。戻り値はBASSチャンネルハンドル。

#### Step 2: Switch Audio定義の解析を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | play_audio_effects.hsp | `src/scene/play/play_audio_effects.hsp` | initCustomAudioEffects関数（1-183行目） |

**主要処理フロー**:
- **47-53行目**: fxdef_type=FXDEF_FILENAMEの場合、swaudionum>=31チェック後にuserfx_swaudiomidにインデックスを設定
- **180-181行目**: loadAudioFilesForSwitchAudioを呼び出し

#### Step 3: 音声ファイル読み込みを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | play_audio_effects.hsp | `src/scene/play/play_audio_effects.hsp` | loadAudioFilesForSwitchAudio関数（185-213行目） |

**主要処理フロー**:
- **186行目**: `dim mid_sw,swaudionum` でSwitch Audioチャンネル配列を確保
- **190行目**: `KSHLib_SwitchAudioOpen(cnt,swaudio.cnt,0x20000)` でファイルオープン
- **199行目**: `BASS_ChannelSetLink mid.0,mid_sw.cnt` でメイントラックとリンク
- **206-212行目**: PeakingFilter、BitCrusherエフェクトをSwitch Audioチャンネルに設定

#### Step 4: 毎フレームの切替処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | play_audio_effects.hsp | `src/scene/play/play_audio_effects.hsp` | processAudioEffects内のSwitch Audio切替（568-896行目） |

**主要処理フロー**:
- **569-589行目**: feffectnow_real変数の変化を検出し、FXDEF_FXTYPE_AUDIの場合swaudionowを更新
- **871-896行目**: swaudionow_filter/swaudionow/swaudionow_resultを決定し、BASS_ChannelSetAttributeでボリューム制御

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

```
start_play (play_init.hsp)
    |
    +-- initCustomAudioEffects (play_audio_effects.hsp)
    |       +-- #define_fx/filter解析
    |       +-- FXDEF_FXTYPE_AUDI検出 -> userfx_swaudiomid設定
    |       +-- loadAudioFilesForSwitchAudio
    |               +-- KSHLib_SwitchAudioOpen -> mid_sw配列
    |               +-- BASS_ChannelSetLink(mid.0, mid_sw)
    |               +-- エフェクトハンドル設定
    |
    +-- on_update_play (毎フレーム)
            +-- processAudioEffects
                    +-- feffectnow_real変化検出
                    +-- swaudionow/swaudionow_filter/swaudionow_result決定
                    +-- BASS_ChannelSetAttribute (ボリューム切替)
```

### データフロー図

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

譜面#define_fx/filter         initCustomAudioEffects            userfx_swaudiomid
  type=SwitchAudio -------->  FXDEF_FXTYPE_AUDI検出

音声ファイル                  loadAudioFilesForSwitchAudio      mid_sw配列
  swaudio配列 ------------->  KSHLib_SwitchAudioOpen

FXエフェクト状態              processAudioEffects               音声出力
  feffectnow_real --------->  swaudionow_result決定 --------->  メイン or Switch Audio
  filtertype2 ------------->  BASS_ChannelSetAttribute
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| play_audio_effects.hsp | `src/scene/play/play_audio_effects.hsp` | ソース | initCustomAudioEffects, loadAudioFilesForSwitchAudio, processAudioEffects |
| play_utils.hsp | `src/scene/play/play_utils.hsp` | ソース | swaudio配列への音声ファイルパス登録 |
| kshlib.as | `src/kshlib.as` | ソース | KSHLib_SwitchAudioOpen/Free APIバインディング |
| bass.as | `src/bass.as` | ソース | BASS API バインディング |
| play_init.hsp | `src/scene/play/play_init.hsp` | ソース | Volume FXのSwitch Audio適用 |
