# 機能設計書 61-一時停止・再開

## 概要

本ドキュメントは、K-Shoot MANIA のプレイ画面における一時停止(Pause)・再開(Resume)機能の設計を記述する。プレイ中に Ctrl+Enter または MediaStop キーを押すことで楽曲の再生を一時停止し、再度同じ操作を行うことで再開する機能である。

### 本機能の処理概要

**業務上の目的・背景**：リズムゲームのプレイ中に、プレイヤーが一時的にゲームを中断する必要がある場面（電話への対応、休憩、操作ミスの確認等）に対応するため、楽曲の再生と判定処理を一時停止する機能が必要である。再開時には音楽の再生位置を正確に同期させることで、中断前の状態からシームレスにプレイを継続可能にする。

**機能の利用シーン**：ゲームプレイ画面（SCENE_PLAY）において、プレイヤーが Ctrl+Enter キーまたはキーボードの MediaStop キー（仮想キーコード 179）を押下した際に発動する。プレイ開始から1500ms以上経過していることが条件であり、誤操作防止のため連続入力のガード処理が設けられている。

**主要な処理内容**：
1. Ctrl+Enter キーまたは MediaStop キーの押下を検出
2. 一時停止処理：現在の再生位置を記録し、全オーディオチャンネル（メイントラック・Switch Audio トラック）を停止
3. 再開処理：全オーディオチャンネルのボリュームを0にリセット後、再生を開始し、デュアルトラック間の再生位置を精密に同期（最大10回のループ補正）
4. 再開後のゲームタイマー（hgsettime）を停止位置に合わせてリセット

**関連システム・外部連携**：BASS Audio Library（bass.dll）を使用してオーディオチャンネルの制御を行う。KSHLib の Switch Audio 機能と連携して、複数の音声トラックを同期的に停止・再開する。

**権限による制御**：特にない。全プレイヤーが同一の操作で利用可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 5 | ゲームプレイ画面 | 主画面 | processPlaybackControlInput による Ctrl+Enter/MediaStop での一時停止・再開処理 |

## 機能種別

入力制御 / オーディオ同期制御

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| enter_key | int | Yes | Enter キー状態（0/1） | getkey 関数で取得 |
| ctrl_key | int | Yes | Ctrl キー状態（0/1） | getkey 関数（仮想キーコード 17）で取得 |
| stat1 (VK179) | int | Yes | MediaStop キー状態（0/1） | getkey 関数（仮想キーコード 179）で取得 |
| t | int | Yes | 現在のプレイ時間（ms） | 1500ms 以上であること |
| mstop | int | Yes | 現在の停止状態フラグ（0=再生中, 1=停止中） | 0 または 1 |
| stat179p | int | Yes | 前フレームの MediaStop/Ctrl+Enter 状態（連打防止） | 0 または 1 |

### 入力データソース

キーボード入力（getkey 関数）、ジョイスティック入力（getjoykeystat 関数）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| mstop | int | 停止状態フラグ（0=再生中, 1=停止中） |
| stoppos | int | 一時停止時の再生位置（ms） |
| stat179p | int | 前回のキー状態（連打防止用） |

### 出力先

内部変数（mstop, stoppos）による状態管理。オーディオチャンネルへの制御コマンド送出。

## 処理フロー

### 処理シーケンス

```
1. ウィンドウアクティブ判定 (ginfo2()=0)
   └─ 非アクティブ時は処理をスキップ
2. Enter キー・Ctrl キー・MediaStop キーの状態を取得
   └─ ジョイスティック Start ボタン(ID:11)との OR 合成
3. 一時停止/再開トリガー判定
   └─ 条件: (MediaStop=1 OR Ctrl+Enter=2) AND t>1500 AND stat179p=0 AND ginfo2()=0
4. mstop=0（再生中）の場合 → 一時停止処理
   4-1. 現在の再生位置を stoppos に記録 (BASS_ChannelGetPosition_ms)
   4-2. メイントラック(mid配列)の各チャンネルを BASS_ChannelStop で停止
   4-3. Switch Audio トラック(mid_sw配列)があれば同様に停止
   4-4. mstop = 1 に設定
5. mstop=1（停止中）の場合 → 再開処理
   5-1. 全チャンネルのボリュームを 0.0 に設定 (BASS_ChannelSetAttribute)
   5-2. 全チャンネルの再生を開始 (BASS_ChannelPlay)
   5-3. デュアルトラック時は BASS_ChannelUpdate で同期
   5-4. 最大10回のループで再生位置を stoppos に精密合わせ (BASS_ChannelSetPosition_ms)
   5-5. ゲームタイマーをリセット (hgsettime t_mo+stoppos, INT_MAX)
   5-6. mstop = 0 に設定
6. キー状態の前フレーム記録 (stat179p) を更新
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{ウィンドウアクティブ?}
    B -->|No| Z[return]
    B -->|Yes| C[Enter/Ctrl/MediaStop キー取得]
    C --> D{トリガー条件成立?}
    D -->|No| G[stat179p 更新]
    D -->|Yes| E{mstop の状態}
    E -->|mstop=0| F1[再生位置を記録]
    F1 --> F2[全チャンネル停止]
    F2 --> F3[mstop=1 に設定]
    F3 --> G
    E -->|mstop=1| H1[全チャンネルのボリュームを0に]
    H1 --> H2[全チャンネル再生開始]
    H2 --> H3[再生位置の精密同期ループ 最大10回]
    H3 --> H4[ゲームタイマーリセット]
    H4 --> H5[mstop=0 に設定]
    H5 --> G
    G --> Z
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-61-1 | 発動タイミング制限 | プレイ開始から1500ms以上経過後にのみ一時停止可能 | t > 1500 |
| BR-61-2 | 連打防止 | 前フレームで同キーが押されていた場合はトリガーしない | stat179p = 0 |
| BR-61-3 | ウィンドウフォーカス | ウィンドウが非アクティブの場合は処理しない | ginfo2() = 0 |
| BR-61-4 | デュアルトラック同期 | 2チャンネル構成時はチャンネル間の再生位置誤差を3ms以内に補正 | length(mid) = 2 |

### 計算ロジック

再開時のデュアルトラック同期ループ:
```
stat0 = 0
最大10回繰り返し:
  mid.0 の再生位置 = stoppos - stat0 * 0 / max(length(mid)-1, 1)
  mid.1 の再生位置 = stoppos - stat0 * 1 / max(length(mid)-1, 1)
  mid_sw の再生位置 = stoppos - stat0
  stat0 += mid[last].pos - mid[0].pos  (チャンネル間の位置差)
  stat1 = mid[last].pos - mid[0].pos
  abs(stat1) < 3 + cnt/2 で収束したらbreak
```

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

### 操作別データベース影響一覧

本機能にデータベース操作はない。全てメモリ上の変数とオーディオエンジンAPIの操作で完結する。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 再生位置同期失敗 | デュアルトラック間の位置差が10回のループで収束しない | ループ上限の10回で打ち切り、最後の位置で再開 |
| - | チャンネル操作失敗 | BASS_ChannelStop/Play が失敗 | BASS Audio Library の内部エラー処理に委任 |

### リトライ仕様

再生位置の精密同期において、最大10回のリトライループが組み込まれている。収束条件は `abs(stat1) < 3 + cnt/2`（ms単位の誤差閾値）である。

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

該当なし。

## パフォーマンス要件

再開時の同期ループは最大10回であり、1フレーム内で完了する。音声の再生位置補正は数ms以内の精度で行われる。

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

該当なし。

## 備考

- MediaStop キー（仮想キーコード 179）はマルチメディアキーボードに搭載されている停止ボタンに対応する
- 再開時にボリュームを0にリセットしてから再生するのは、再生位置補正中にノイズが出力されることを防止するためと推測される
- mlinkfailed 変数が 0 の場合はメイントラックのみを操作し、0 でない場合は Switch Audio トラックも含めて操作する

---

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

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

### 推奨読解順序

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

一時停止・再開機能で使用される主要変数を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | play_game_logic.hsp | `src/scene/play/play_game_logic.hsp` | **14行目**: `mstop=0` - 停止状態フラグの初期化。0が再生中、1が停止中 |
| 1-2 | play_game_logic.hsp | `src/scene/play/play_game_logic.hsp` | **15行目**: `mshift=0` - 曲送り用変数の初期化 |

**読解のコツ**: HSP では変数宣言と初期化が分離されていることが多い。`mstop` は `initGamePlayVariables` 関数内で初期化され、`processPlaybackControlInput` 関数内で読み書きされる。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | play_key_input.hsp | `src/scene/play/play_key_input.hsp` | `processPlaybackControlInput` 関数（1行目から定義）が一時停止・再開処理のエントリーポイント |

**主要処理フロー**:
1. **2行目**: `ginfo2()=0` - ウィンドウがアクティブかどうかの判定
2. **3-4行目**: Enter キーとジョイスティック Start ボタンの取得・合成
3. **5-7行目**: Ctrl キー、Alt キー、MediaStop キー（VK179）の取得
4. **8行目**: 一時停止/再開のトリガー条件判定
5. **9-20行目**: mstop=0 の場合の一時停止処理（再生位置記録 → チャンネル停止）
6. **21-59行目**: mstop=1 の場合の再開処理（ボリュームリセット → 再生開始 → 位置同期 → タイマーリセット）

#### Step 3: 一時停止処理の詳細を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | play_key_input.hsp | `src/scene/play/play_key_input.hsp` | **10行目**: `BASS_ChannelGetPosition_ms(mid.0)` で現在の再生位置を取得して stoppos に保存 |
| 3-2 | play_key_input.hsp | `src/scene/play/play_key_input.hsp` | **11-18行目**: `foreach mid` ループと Switch Audio ループで全チャンネルを停止 |

#### Step 4: 再開処理と同期ループの詳細を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | play_key_input.hsp | `src/scene/play/play_key_input.hsp` | **22-27行目**: 全チャンネルのボリュームを0.0に設定（ノイズ防止） |
| 4-2 | play_key_input.hsp | `src/scene/play/play_key_input.hsp` | **28-36行目**: 全チャンネルの再生を開始 |
| 4-3 | play_key_input.hsp | `src/scene/play/play_key_input.hsp` | **37-45行目**: デュアルトラック時の ChannelUpdate による同期 |
| 4-4 | play_key_input.hsp | `src/scene/play/play_key_input.hsp` | **46-57行目**: 最大10回の精密同期ループ。位置差が `3+cnt/2` ms 以内になるまで繰り返す |
| 4-5 | play_key_input.hsp | `src/scene/play/play_key_input.hsp` | **58行目**: `hgsettime t_mo+stoppos, INT_MAX` でゲームタイマーを停止位置に合わせてリセット |

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

```
play_update (メインループ)
    |
    +-- processPlaybackControlInput
    |       |
    |       +-- getkey (Enter/Ctrl/Alt/MediaStop)
    |       +-- getjoykeystat(11) (Start ボタン)
    |       |
    |       +-- [一時停止時]
    |       |       +-- BASS_ChannelGetPosition_ms(mid.0)
    |       |       +-- BASS_ChannelStop(mid.cnt)
    |       |       +-- BASS_ChannelStop(mid_sw.cnt)
    |       |
    |       +-- [再開時]
    |               +-- BASS_ChannelSetAttribute(mid.cnt, 2, 0.0)
    |               +-- BASS_ChannelPlay(mid.cnt)
    |               +-- BASS_ChannelUpdate(mid.cnt)
    |               +-- BASS_ChannelSetPosition_ms(mid.cnt, stoppos)
    |               +-- hgsettime(t_mo+stoppos, INT_MAX)
    |
    +-- processKeyInput
    +-- processHiSpeedChangeInput
    +-- processSyncValueManualChangeInput
```

### データフロー図

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

キーボード入力         processPlaybackControlInput
  Ctrl+Enter    ───>   ┌──────────────────────┐
  MediaStop             |  トリガー判定         |
                        |  ├─ 一時停止:        |      mstop=1
ジョイスティック  ───>  |  |  位置記録          |  ──> stoppos (ms)
  Start ボタン          |  |  チャンネル停止     |      BASS チャンネル停止
                        |  └─ 再開:            |
状態変数               |     ボリューム0       |      mstop=0
  mstop         ───>   |     再生開始          |  ──> BASS チャンネル再生
  t (プレイ時間)        |     位置同期ループ    |      ゲームタイマーリセット
                        └──────────────────────┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| play_key_input.hsp | `src/scene/play/play_key_input.hsp` | ソース | 一時停止・再開の主処理（processPlaybackControlInput 関数） |
| play_game_logic.hsp | `src/scene/play/play_game_logic.hsp` | ソース | mstop 等の状態変数の初期化（initGamePlayVariables 関数） |
| play_audio.hsp | `src/scene/play/play_audio.hsp` | ソース | BASS Audio Library によるオーディオ制御の基盤処理 |
| bass.as | `src/bass.as` | ソース | BASS Audio Library の HSP バインディング定義 |
| kshlib.as | `src/kshlib.as` | ソース | Switch Audio 関連の DLL バインディング |
