2026-08-22 05:54:36 +00:00
|
|
|
|
# rix-midi —— 《大富翁 2》RIX → MIDI 轉換器(by Qwen 3.8:27B)
|
2026-08-22 05:52:55 +00:00
|
|
|
|
|
|
|
|
|
|
把 DOS 遊戲《大富翁 2》的 `.RIX` 音樂檔,轉成標準 `.MIDI` 樂譜。
|
|
|
|
|
|
可以一次轉單一個、也可以整個資料夾批次轉。
|
|
|
|
|
|
|
|
|
|
|
|
> 同一批 `.RIX` 用 **adplay / AdPlug** 也可以轉成 WAV(純音訊),
|
2026-08-22 05:53:57 +00:00
|
|
|
|
> 這裡只處理「轉成 MIDI 樂譜」這件比較有挑戰的事。
|
2026-08-22 05:52:55 +00:00
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 為什麼 RIX 不能直接「拿出來」當 MIDI?
|
|
|
|
|
|
|
|
|
|
|
|
`.RIX` **不是存音符**的格式。它是 **AdLib OPL 晶片**的「機器碼」:
|
|
|
|
|
|
一段由「時鐘節拍(tick)」驅動的下載程式,每個 tick 告訴 OPL 晶片
|
|
|
|
|
|
要寫哪些「暫存器」(頻率、開聲、音量……)。所以 RIX 裡只有
|
|
|
|
|
|
「要讓硬體發出什麼」的指令,沒有現成的音符——得「還原」出來。
|
|
|
|
|
|
|
|
|
|
|
|
## 原理(我們怎麼還原)
|
|
|
|
|
|
|
|
|
|
|
|
1. **借用 AdPlug** 來 decode + 模擬 OPL 晶片(它已把 RIX 的機器碼
|
|
|
|
|
|
正確地「跑成」一串 OPL 暫存器寫入)。
|
|
|
|
|
|
2. **劫持 OPL 的 write()**:AdPlug 發聲前會走 `Copl::write(reg,val)`,
|
|
|
|
|
|
我們繼承它的模擬器、順手把「每個 tick、每個聲道的 A / B 暫存器」記下。
|
|
|
|
|
|
3. **暫存器 → 頻率 → 音符**(OPL 的標準公式):
|
|
|
|
|
|
```
|
|
|
|
|
|
F-number = A暫存器(低8位) | B暫存器bit0-1(高2位)
|
|
|
|
|
|
block = B暫存器 bit2-4 (決定八度倍頻)
|
|
|
|
|
|
key-on = B暫存器 bit5 (1=開、0=關)
|
|
|
|
|
|
頻率Hz = F-number × 2^block × 3579545 / (72 × 2^24) × 8
|
|
|
|
|
|
MIDI音符 = round( 69 + 12×log2( 頻率 / 440 ) ) # 69 = A4, 60 = 中音C
|
|
|
|
|
|
```
|
|
|
|
|
|
4. **節奏一致**:測出 RIX 是「70 tick / 秒」。把 MIDI 速度設成
|
|
|
|
|
|
`tempo = 1e6 × 96 ÷ 70 ≈ 1,371,428 µs/quat`(96 ticks/quat),
|
|
|
|
|
|
讓 1 個 RIX tick == 1 個 MIDI tick,整首的時值就和原曲一致。
|
|
|
|
|
|
5. **樂器**:OPL 不分旋律/和聲,依每個聲道音高的「中位數」粗略指派
|
|
|
|
|
|
GM 樂器(偏低→貝斯、其餘→方波 Lead)。聽起來像原曲的務實選擇。
|
|
|
|
|
|
|
|
|
|
|
|
### 已驗證
|
|
|
|
|
|
對全部 23 首,**MIDI 時長與同曲 WAV 時長比對:22 首幾乎完全一致(ratio 1.00)**、
|
|
|
|
|
|
1 首(RICHX)因 WAV 尾端多靜音而略短。音高也抽樣驗證正確(中音 C=60)。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 編譯
|
|
|
|
|
|
|
|
|
|
|
|
依賴 **AdPlug**(RIX/OPL)與 **libbinio**。`build.sh` 會自動找/編它們,
|
|
|
|
|
|
再以**靜態連結**產出自給自足的執行檔(不用設 `LD_LIBRARY_PATH`):
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
./build.sh # 在本機 AdPlug=/tmp/AdPlug、libbinio=/tmp/libbinio 的前提下
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
想指定位置:
|
|
|
|
|
|
```bash
|
|
|
|
|
|
ADPLUG=/path/to/AdPlug BINIO=/path/to/libbinio ./build.sh
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## 使用
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
./rix2midi --help
|
|
|
|
|
|
|
|
|
|
|
|
# 單一個 .RIX → 同名 .mid
|
2026-08-22 05:53:57 +00:00
|
|
|
|
./rix2midi ./RICHU.RIX # 產出 RICHU.mid
|
|
|
|
|
|
./rix2midi ./RICHU.RIX 我的.mid # 指定輸出檔名
|
2026-08-22 05:52:55 +00:00
|
|
|
|
|
|
|
|
|
|
# 批次:把「整個資料夾」裡所有 .RIX 轉到「輸出資料夾」
|
|
|
|
|
|
./rix2midi ../ ../mid # ../ 所有 .RIX → ../mid/*.mid
|
|
|
|
|
|
./rix2midi -v ../ ../mid # 加 -v 看 tick 數等詳細訊息
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## 檔案
|
|
|
|
|
|
|
|
|
|
|
|
| 檔案 | 說明 |
|
|
|
|
|
|
|--------------|----------------------------------------|
|
|
|
|
|
|
| `rix2midi.cpp` | 轉換器本體(含完整中文註解) |
|
|
|
|
|
|
| `build.sh` | 一鍵編譯(找/編 AdPlug、靜態連結) |
|
|
|
|
|
|
| `rix2midi` | 編譯出的執行檔 |
|
|
|
|
|
|
|
|
|
|
|
|
## 小限制(MIDI 本質)
|
|
|
|
|
|
|
|
|
|
|
|
- 只能還原 OPL「發聲的音色」層次的音高+時值,是**旋律骨架**,
|
|
|
|
|
|
不是完整編曲(沒有真正的和聲/鼓聲)——這是 RIX/OPL 格式的天花板。
|
|
|
|
|
|
- 樂器指派是「猜」的(依音域),不是原曲精確編配。
|
|
|
|
|
|
- 若你想要「聽起來就等於 DOS 原版」的 WAV,用 adplay 那一套(`../wav/`)。
|