# 機能設計書 50-Pitch Shift

## 概要

本ドキュメントは、K-ShootMania のプレイ画面におけるPitch Shift（ピッチシフト）エフェクト機能の設計を記述する。pitc.dllを使用し、FXロングノート押下中に楽曲の音程をリアルタイムで変化させるエフェクトを適用する機能である。

### 本機能の処理概要

**業務上の目的・背景**：Pitch Shiftは楽曲の音程を上げたり下げたりするエフェクトで、EDMのビルドアップやドロップ等でピッチを変化させる演出に使用される。FXロングノートに割り当てられ、プレイヤーのFXボタン操作と連動した音程変化効果を提供する。

**機能の利用シーン**：プレイ画面でFXロングノートにPitch Shiftエフェクト（FX_PITC）が割り当てられている場合、ノート押下中にpitc.dllのVSTプラグインとしてピッチシフトエフェクトが適用される。feffectparamで指定されたピッチ量（半音単位）に基づいて音程が変化する。

**主要な処理内容**：
1. applyVSTEffects関数でfl_Pitc=1の場合、pitc.dllをVSTプラグインとしてロード
2. 初期パラメータ設定: パラメータ0=0.50（ピッチ=0半音、中心値）、パラメータ1=700/44100（ウィンドウサイズ）、パラメータ2=0.80（オーバーラップ）、パラメータ3=0.0（ByPass/ミックス）
3. FXエフェクト開始時: パラメータ0=feffectparam/48/2+0.50（ピッチ量設定）、パラメータ3=1.0（エフェクト有効化）
4. FXエフェクト終了時: パラメータ3=0.0（エフェクト無効化）、パラメータ0をリセット

**関連システム・外部連携**：pitc.dll（VSTプラグイン）、BASS Audio Library、bass_vst.dll

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 5 | ゲームプレイ画面 | 主画面 | pitc.dllによるピッチシフトエフェクト適用 |

## 機能種別

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

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| fl_Pitc | 整数 | Yes | Pitch Shiftエフェクト使用フラグ | 0または1 |
| feffectnow | 整数配列 | Yes | L/R各レーザーの現在FXエフェクトID | FX_PITC |
| feffectparam | 整数配列 | Yes | ピッチ変化量（半音単位、正/負） | 整数値 |

### 入力データソース

- 譜面ファイル（.ksh）のFXロングノート定義

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| hFX_Pitc | 整数 | Pitch ShiftのVSTハンドル |

### 出力先

- BASSオーディオエンジンのVSTエフェクトチェーン

## 処理フロー

### 処理シーケンス

```
1. VSTプラグインロード（applyVSTEffects）
   └─ hFX_Pitc = BASS_VST_ChannelSetDSP(mid.0, pitc.dll, 0, 20)
   └─ パラメータ初期設定: 0=0.50, 1=700/44100, 2=0.80, 3=0.0
2. FXエフェクト開始（feffectnow.cnt = FX_PITC）
   └─ パラメータ0 = feffectparam.cnt / 48.0 / 2.0 + 0.50
   └─ パラメータ3 = 1.0
3. FXエフェクト終了
   └─ パラメータ3 = 0.0
   └─ 他方のレーザーでPitch Shiftが継続する場合: パラメータ0を他方の値に再設定
```

### フローチャート

```mermaid
flowchart TD
    A[applyVSTEffects: pitc.dllロード priority=20] --> B[初期パラメータ設定]
    B --> C[毎フレーム: processAudioEffects]
    C --> D{feffectnow変化?}
    D -->|FX_PITC開始| E[パラメータ0=pitch値, パラメータ3=1.0]
    D -->|FX_PITC終了| F{他レーザーでPitch継続?}
    F -->|Yes| G[パラメータ0を他方の値に再設定]
    F -->|No| H[パラメータ3=0.0, パラメータ0リセット]
    D -->|変化なし| I[次フレームへ]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-50-01 | ピッチ量計算 | pitch = feffectparam / 48.0 / 2.0 + 0.50 | FXエフェクト開始時 |
| BR-50-02 | VSTプライオリティ | Pitch Shiftのプライオリティは20 | applyVSTEffects |
| BR-50-03 | ミックス量制御 | パラメータ3で0.0(OFF)/1.0(ON)を切替 | FXエフェクトON/OFF時 |
| BR-50-04 | ピッチ範囲 | 0.0-1.0の範囲で中心0.50が原音ピッチ | パラメータ0の値域 |
| BR-50-05 | L/R独立制御 | 両方のレーザーがPitch Shiftでない場合のみ無効化 | feffectnow.(1-cnt)!=FX_PITCの条件 |

### 計算ロジック

- Pitchパラメータ（パラメータ0）: `double(feffectparam) / 48.0 / 2.0 + 0.50`
  - feffectparam=12（1オクターブ上）の場合: 12/48/2+0.5 = 0.625
  - feffectparam=-12（1オクターブ下）の場合: -12/48/2+0.5 = 0.375
  - feffectparam=0（原音）の場合: 0/48/2+0.5 = 0.50
- 初期ウィンドウサイズ: 700 / 44100 = 約15.87ms
- 初期オーバーラップ: 0.40 * 2.0 = 0.80

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

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

## エラー処理

BASS_VST_SetParam_Rはエラー時に最大5回リトライする。

### リトライ仕様

BASS_VST_SetParam_R内で最大5回リトライ。

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

該当なし。

## パフォーマンス要件

- VSTプラグインのDSP処理が音切れを起こさないこと
- ピッチシフトは計算負荷が高いため、適切なウィンドウサイズとオーバーラップの設定が重要

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

特になし。

## 備考

- pitc.dllはPitch Shift専用のVSTプラグインである
- パラメータ0の値域は0.0-1.0で、0.50が原音ピッチ（0半音）に対応する。48段階の半音単位で±24半音（2オクターブ）の範囲を表現できる
- パラメータ3はミックス量で、0.0でドライ信号のみ、1.0でウェット信号のみとなる
- ユーザー定義エフェクト（#define_fx）でPitch Shiftを定義する場合、FXDEF_PITCHタイプとして処理される

---

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

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

### 推奨読解順序

#### Step 1: VSTプラグインロードを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | play_audio_effects.hsp | `src/scene/play/play_audio_effects.hsp` | applyVSTEffects関数内のPitch Shift初期化（234-239行目） |

**主要処理フロー**:
- **235行目**: `hFX_Pitc=BASS_VST_ChannelSetDSP(mid.0,dir_default+"\\lib\\pitc.dll",0,20)` でVSTロード
- **236行目**: `BASS_VST_SetParam_R hFX_Pitc,0,0.0f/48.0f/2.0f+0.50f` でピッチ初期値0.50設定
- **237行目**: `BASS_VST_SetParam_R hFX_Pitc,1,700.0f/44100.0f` でウィンドウサイズ設定
- **238行目**: `BASS_VST_SetParam_R hFX_Pitc,2,0.40f*2.0f` でオーバーラップ設定
- **239行目**: `BASS_VST_SetParam_R hFX_Pitc,3,0.0f` でByPass設定

#### Step 2: FXエフェクト切替を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | play_audio_effects.hsp | `src/scene/play/play_audio_effects.hsp` | Pitch Shift ON/OFF処理（599-604行目, 701-703行目） |

**主要処理フロー**:
- **599-604行目**: Pitch Shift終了時: パラメータ3=0、パラメータ0リセット。他方レーザーでPitch継続時はパラメータ0を他方のfeffectparamで再設定
- **701-703行目**: Pitch Shift開始時: `パラメータ0=feffectparam/48/2+0.50`、`パラメータ3=1.00`

#### Step 3: ユーザー定義Pitch Shiftを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | play_audio_effects.hsp | `src/scene/play/play_audio_effects.hsp` | FXDEF_PITCHタイプの処理 |

**主要処理フロー**:
- **305-308行目**: ユーザー定義のPitch Shift FXの場合、`BASS_VST_SetParam_R hFX_User, パラメータ番号, absf(値)` でピッチ設定
- **396-398行目**: フィルターとしてのPitch Shift（レーザー連動）の場合、pdstatに基づくピッチ補間

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

```
start_play
    +-- applyVSTEffects
    |       +-- BASS_VST_ChannelSetDSP(pitc.dll, priority=20) -> hFX_Pitc
    |       +-- パラメータ0-3初期設定
    |
    +-- on_update_play (毎フレーム)
            +-- processAudioEffects
                    +-- feffectnow変化: Pitch Shift ON/OFF
                    +-- パラメータ0=pitch値, パラメータ3=ミックス量
```

### データフロー図

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

譜面FXロングノート          feffectnow判定                   pitc.dll VSTパラメータ
  FX_PITC + param -------->  ON/OFF切替                      パラメータ0(ピッチ量)
                             pitch = param/48/2+0.50          パラメータ3(ミックス量)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| play_audio_effects.hsp | `src/scene/play/play_audio_effects.hsp` | ソース | applyVSTEffects, processAudioEffects |
| bass_vst.as | `src/bass_vst.as` | ソース | BASS_VST_ChannelSetDSP, BASS_VST_SetParam_R APIバインディング |
| pitc.dll | `lib/pitc.dll` | DLL | Pitch Shift VSTプラグイン |
