# サウンドリファレンス — 大学物語

本ゲームで使用するサウンド (ナレーション + 効果音) の命名規則と用途一覧。
音声アセットは全て Roblox Open Cloud Assets API 経由でアップロード済み、
ID は `src/shared/AudioManifest.lua` に記録されている。

## 1. 読み上げ音声 (ナレーション) — 70 ファイル

問題文と 4 択選択肢を 1 つのファイルにまとめた事前生成 TTS。
ファイル命名: `<科目プレフィックス>_<連番2桁>.wav/mp3`

| 科目 | ファイル名 | 内容 | 生成ツール |
|------|----------|------|----------|
| 国語 | `kokugo_01` 〜 `kokugo_10` | 現代文/古文/漢文 10問 | VOICEVOX (speaker=3 春日部つむぎ) |
| 数学I・A | `math1a_01` 〜 `math1a_10` | 数と式/場合の数・確率/図形 10問 | VOICEVOX |
| 数学II・B・C | `math2bc_01` 〜 `math2bc_10` | 関数/ベクトル/数列 10問 | VOICEVOX |
| 英語 | `english_01` 〜 `english_10` | R 5問 + L 5問 | **VOICEVOX + edge-tts バイリンガル** |
| 物理 | `physics_01` 〜 `physics_10` | 力学/電磁気/波動 10問 | VOICEVOX |
| 化学 | `chemistry_01` 〜 `chemistry_10` | 理論/無機/有機 10問 | VOICEVOX |
| 公共・政経 | `society_01` 〜 `society_10` | 政治/経済/倫理 10問 | VOICEVOX |

> **英語だけ例外**: 英単語・英文を日本語音声で読ませると「エイチ イー…」とスペル読みになるため、
> `scripts/generate-tts-english.mjs` が文章を言語セグメントに分割し、
> 日本語部分は VOICEVOX、英語部分は edge-tts (en-US-JennyNeural) で個別に合成、
> ffmpeg で連結している。

## 2. 効果音 (SFX) — 9 ファイル

全て `scripts/gen-sfx.mjs` による純 JavaScript の波形合成。
出力先: `assets/audio/sfx/*.wav` (44.1kHz 16bit mono)。

| サウンド名 | 長さ | 音の特徴 | 再生タイミング | 実装関数 |
|----------|-----|--------|--------------|---------|
| `sfx_question_start` | 0.7s | 柔らかい 2 音ベル (E5→G5) | 問題出題開始時 | `genQuestionStart()` |
| `sfx_tick` | 0.08s | 乾いたクリック音 (1.8kHz) | カウントダウン残り 3,2,1 秒 | `genTick()` |
| `sfx_timeup` | 0.9s | 低音ブザー (250Hz 矩形波 + 12Hz AM) | **時間切れ時のみ** (スキップ時は鳴らさない) | `genTimeUp()` |
| `sfx_walls_close` | 1.0s | 重い金属音 (50→30Hz サブ + 220/440Hz メタル) | 仕切り壁が閉鎖される瞬間 | `genWallsClose()` |
| `sfx_correct` | 0.65s | 上昇アルペジオ (C5→E5→G5→C6) | 正解者に個別再生 | `genCorrect()` |
| `sfx_wrong` | 0.85s | 下降矩形波 (B4→A4→G4) | 不正解者に個別再生 | `genWrong()` |
| `sfx_subject_pass` | 0.95s | 5音上昇ファンファーレ (C5→E5→G5→C6→E6) | 科目クリア時 | `genSubjectPass()` |
| `sfx_subject_fail` | 1.8s | 4音下降和音 (G4→Eb4→C4→G3) | 足きり時 | `genSubjectFail()` |
| `sfx_game_clear` | 2.2s | 7音勝利ファンファーレ + 終和音 | 東大合格エンディング | `genGameClear()` |

## 3. 重要な音の識別と混同注意

### `sfx_timeup` vs `sfx_wrong` ⚠

- `sfx_timeup`: 250Hz の低音ブザー (機械的)
- `sfx_wrong`: B4→A4→G4 の下降矩形波 (音楽的)

両方とも「低音 + 矩形波系」で**似て聞こえる**ため、
「今すぐ解答する」ボタンでスキップした場合は `sfx_timeup` を鳴らさない。
(スキップ直後に `sfx_correct`/`sfx_wrong` が鳴るため、`sfx_timeup` が被ると判別しづらい)

以下のルールが適用されている (`src/server/GameLoop.server.lua`):

```lua
if timedOut then
    Remotes.PlaySfx:FireAllClients("sfx_timeup")  -- 時間切れ時のみ
end
-- sfx_walls_close はスキップ時も鳴らす (視覚的に壁が閉まるため)
```

### `sfx_subject_fail` vs `sfx_wrong`

- `sfx_subject_fail`: 1.8 秒の重い 4 音下降 (科目終了の重み)
- `sfx_wrong`: 0.85 秒の 3 音軽い下降 (1 問単位)

長さとトーンで区別可能。

## 4. 再生箇所早見表

```
[問題開始]
  └→ sfx_question_start 🔔

[TTS 読み上げ中]
  └→ <subject>_<NN> 🗣️  (読み上げ / スキップで即停止)

[カウントダウン残り 3,2,1 秒]
  └→ sfx_tick ⏱️ × 3

[時間切れ]        [スキップ]
  ├→ sfx_timeup 📯  (なし)
  └→ sfx_walls_close 💥  sfx_walls_close 💥

[0.3秒後: 正解発表]
  ├→ sfx_correct 🎵 (正解者)
  └→ sfx_wrong 🎵 (不正解者)

[科目終了]
  ├→ sfx_subject_pass 🎺  (70%以上)
  └→ sfx_subject_fail 😢  (70%未満)

[全科目満点クリア]
  └→ sfx_game_clear 🎊
```

## 5. 音を差し替えたい場合

1. `scripts/gen-sfx.mjs` の該当関数 (`genCorrect`, `genWrong` など) を編集
2. `npm run sfx:force` で WAV 再生成
3. `npm run convert` で MP3 変換
4. `src/shared/AudioManifest.lua` の該当 `sfx_*` 行を削除
5. `npm run upload` で新しい ID を取得 → manifest 再生成
6. `npm run build:rbxl && npm run publish`

読み上げ音声 (TTS) を差し替えたい場合:
- 全科目: `npm run tts:force`
- 英語のみ: `npm run tts:english`
- あとは convert / manifest 削除 / upload / publish の流れ
