# 機能設計書 23-KSH譜面ファイル読み込み

## 概要

本ドキュメントは、KSHフォーマットの譜面ファイルを解析し、ノート・BPM変化・カメラ制御等のデータを配列に展開する機能の設計を記述する。

### 本機能の処理概要

**業務上の目的・背景**：K-Shoot MANIAの譜面データはKSH形式のテキストファイルで記述される。ゲームプレイ時にこのテキストデータを内部のデータ配列に変換する必要がある。本機能はそのファイル読み込みとデータ構造への初期展開を担う中核的な機能である。

**機能の利用シーン**：プレイ画面のplay_init処理において、選択された楽曲の譜面ファイル(.ksh)を読み込む際に呼び出される。コース結果画面での曲情報表示時や、選曲画面でのCtrl+I（IRページ表示）時にも間接的に利用される。

**主要な処理内容**：
1. initChartVariables: 譜面データを格納する全配列変数を初期化（note, analog, fx, spin, tilt, bpml等）
2. loadKSHChartFile: 譜面ファイルをnoteload命令で読み込み、BOM判定、行単位の配列d[]への分割、小節区切り（"--"）の解析、IR用ハッシュ計算を実行
3. 後続のparseKSHChartParamLines / parseKSHChartBody関数で詳細な譜面パラメータ・ノートデータを解析（別機能No.25で記述）

**関連システム・外部連携**：kshlib.dll経由でMD5ハッシュ計算を行い、IR（インターネットランキング）システムとの連携に使用する。

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 5 | ゲームプレイ画面 | 主画面 | 譜面ファイルの読み込みとデータ配列への展開 |
| 3 | 曲選択画面 | 参照画面 | Ctrl+I時に譜面ファイルの一部読み込み |

## 機能種別

データ読み込み / ファイル解析

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| cnotesfile | str | Yes | 譜面ファイルのパス | ファイルが存在すること |
| notemax | int | Yes | 読み込む最大行数 | 正の整数 |

### 入力データソース

ファイルシステム上のKSH形式テキストファイル（.ksh拡張子）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| d[] | str配列 | 譜面ファイルを1行ずつ格納した配列 |
| div[] | int配列 | 各小節の行数（区切り「--」間の行数） |
| divnum | int | 小節数 |
| csongmd5hash | str | 生ファイル全体のMD5ハッシュ |
| csongmd5hash_ir_chart | str | IR用正規化MD5ハッシュ |
| isutf8 | int | UTF-8判定フラグ（1=UTF-8, 0=Shift-JIS） |
| note[] | int配列 | BTノートデータ（131072x8） |
| analog[] | int配列 | レーザーノートデータ（131072x10） |
| bpml[] | int配列 | BPM変化リスト（131072x3） |

### 出力先

ゲーム内部のグローバル変数群

## 処理フロー

### 処理シーケンス

```
1. initChartVariables
   └─ 全配列変数（note, notefx, analog, shlj, longj, bpml, spin, tilt等）を初期化
2. loadKSHChartFile
   ├─ noteload命令で譜面ファイル全体をbuf変数に読み込み
   ├─ varmd5で生ファイルのMD5ハッシュを計算（csongmd5hash）
   ├─ UTF-8 BOM（0xBFBBEF）の検出と削除
   ├─ noteget命令で1行ずつd[]配列に展開
   ├─ "--"区切りを検出してdiv[]配列に各小節の行数を記録
   ├─ getChartIRHashで正規化ハッシュを計算（csongmd5hash_ir_chart）
   └─ buf変数を解放
```

### フローチャート

```mermaid
flowchart TD
    A[initChartVariables] --> B[全配列変数の初期化]
    B --> C[loadKSHChartFile]
    C --> D[noteload cnotesfile]
    D --> E[varmd5でMD5計算]
    E --> F{BOM存在?}
    F -->|Yes| G[DeleteUTF8BOM]
    F -->|No| H[isutf8=0のまま]
    G --> I[notegetで行配列に展開]
    H --> I
    I --> J[小節区切り解析]
    J --> K[getChartIRHash計算]
    K --> L[bufを解放]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-23-01 | 小節区切り | "--"行を小節の区切りとして認識する | 全譜面ファイル |
| BR-23-02 | BOM判定 | 先頭3バイトが0xBFBBEFならUTF-8として扱う | ファイル読み込み時 |
| BR-23-03 | 配列サイズ | ノート配列は最大131,072要素を確保する | 変数初期化時 |
| BR-23-04 | パラメータ行除外 | 7文字目が"|"でない行、または"="を含む行はノートデータとみなさない | 小節行数計算時 |

### 計算ロジック

小節内行数の計算（275-297行目）:
- "--"行を検出するたびにdivnum配列に行数を記録
- 7文字目が"|"でない行はノートデータ行から除外してカウント

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

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

データベース操作は発生しない。ファイルシステムからの読み取りのみ。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ファイル不存在 | 譜面ファイルが見つからない場合 | noteload命令がエラーとなり、空のデータで処理続行 |

### リトライ仕様

リトライは行わない。

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

トランザクション管理は不要。

## パフォーマンス要件

譜面ファイルのサイズは通常数十KB〜数百KB程度であり、読み込み処理は十分高速に完了する。

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

外部から提供される譜面ファイルを読み込むため、バッファサイズの上限（notemax, 131072）で制限している。

## 備考

- 配列サイズ131,072は通常の譜面で十分な容量である。
- initChartVariablesは関数内でグローバル変数を使用している（コメント1行目に記載）。

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | play_chart_load.hsp | `src/scene/play/play_chart_load.hsp` | initChartVariablesで初期化される全配列変数の構造 |

**読解のコツ**: HSP3のdim命令は多次元配列を定義する。`dim note,131072,8`はnote[131072][8]のint配列を意味する。各次元のインデックスの意味を把握することが重要。

**主要変数**:
- **7行目**: judge[6][2] - 判定結果
- **28行目**: note[131072][8] - BTノートデータ（レーン,小節位置,長さ,タイミング,終了位置,次ノート,FXパラメータ,重み）
- **54行目**: analog[131072][10] - レーザーノートデータ
- **80行目**: bpml[131072][3] - BPM変化リスト

#### Step 2: ファイル読み込み処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | play_chart_load.hsp | `src/scene/play/play_chart_load.hsp` | loadKSHChartFile関数の実装 |

**主要処理フロー**:
1. **254行目**: loadKSHChartFile関数定義
2. **255-256行目**: notesel/noteloadでファイル読み込み
3. **259行目**: varmd5で生データのMD5ハッシュ計算
4. **262-266行目**: UTF-8 BOM判定と削除
5. **269-273行目**: notegetで1行ずつd[]配列に展開
6. **276-297行目**: "--"区切りによる小節行数の計算
7. **300行目**: getChartIRHashでIR用ハッシュ計算

#### Step 3: IR用ハッシュ計算を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ir.hsp | `src/ir.hsp` | getChartIRHash関数 |

**主要処理フロー**:
- **51-68行目**: メタデータ行（title=, artist=, m=等）を除外した正規化データのMD5ハッシュ計算

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

```
play_init (play_update.hspから呼び出し)
    |
    +-- initChartVariables (4-199行目)
    |     +-- dim note, 131072, 8
    |     +-- dim analog, 131072, 10
    |     +-- dim bpml, 131072, 3
    |     +-- ... (全配列初期化)
    |
    +-- loadKSHChartFile (254-305行目)
          +-- noteload cnotesfile        (ファイル読み込み)
          +-- varmd5 csongmd5hash        (MD5計算)
          +-- DeleteUTF8BOM buf          (BOM削除)
          +-- noteget -> d[]             (行配列展開)
          +-- getChartIRHash(buf)        (IR用ハッシュ)
                +-- ignoreList照合
                +-- varmd5 ret           (MD5計算)
```

### データフロー図

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

.kshファイル -----> noteload -----> buf(生データ)
                                    |
                    varmd5 -------> csongmd5hash
                                    |
                    BOM判定 -------> isutf8フラグ
                                    |
                    noteget -------> d[]配列(行データ)
                                    |
                    "--"解析 ------> div[]配列(小節行数)
                                    |
                    getChartIRHash -> csongmd5hash_ir_chart
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| play_chart_load.hsp | `src/scene/play/play_chart_load.hsp` | ソース | 変数初期化とファイル読み込み（1-305行目） |
| ir.hsp | `src/ir.hsp` | ソース | getChartIRHash関数（51-68行目） |
| kshlib.as | `src/kshlib.as` | ソース | KSHLib_GetChartMD5Hash等のDLL関数宣言 |
| play_update.hsp | `src/scene/play/play_update.hsp` | ソース | play_initからの呼び出し元 |
