← ジョン・ドウ レポートEnglish
MCPLAYER · 技術資料

MICRO CABIN MUSIC PLAYER 技術説明

使い方は配布物の README.txt を見てください。ここでは、ツールとプレーヤーの作りを説明します。

全体の流れ

  1. tools/extract_disks.py がディスクイメージから曲(MCM)を取り出し、データベース tools/mcm_db.csv を元にプレイリスト player/playlist.txt を作る。
  2. player/build_rom.py がプレイリストの曲・曲名・CG と、ディスクイメージから取り出したゲームのドライバと表(音色など)を ROM(ASCII16 メガロム)にまとめる。
  3. ROM の中のプレーヤー(player/player.asm)が、曲ごとにそのゲームのドライバを RAM へ写して鳴らす。

曲の取り出し(extract_disks.py)

データベース(mcm_db.csv)

UTF-8(BOM 付き)の CSV で、1 行が「あるゲームの 1 曲」です。曲は中身(MD5)で見分けるので、ファイル名やディスク上の位置が違っても、中身が同じなら同じ曲です。同じデータを別のゲームでも使っているときは、ゲームごとに 1 行ずつ持てるので、曲名もゲームごとに付けられます(例: 同じデータが Xak II では「ボローズの森」、ガゼルの塔では「森」)。

欄内容
id行の番号(S0001 など)
game / game_enゲーム名 / 英語のゲーム名
orderゲームの中の並び
title / title_en曲名 / 英語の曲名
exclude除外の理由(空なら収録)
loopsループ回数(空なら既定)
folder / fileこの曲に使うファイル(disk_image のフォルダ名とファイル名)
md5 ほか照合用の値、見つかった場所

管理用のコマンド(tools/mcm_db.py):

python tools/mcm_db.py sync          # 詳しい形式の playlist.txt の曲名などをデータベースに反映
python tools/mcm_db.py playlist      # データベース + data -> playlist.txt
python tools/mcm_db.py find ファイル  # ファイルがどの曲か調べる (チャンネル単位で似た曲も出す)

extract_disks.py --full は、詳しい形式(曲名などの欄も書いたもの)のプレイリストを作ります。

プレイリストの書式

# コメント
@startup ../data/CABIN/CABI112.MCM | タイトル | Title   # 起動時に鳴らす曲 (曲のリストには出ない)
@startup_cg ../data/cabin.png                          # 起動時に表示する CG
@game Xak | Xak                                        # 以降の曲のゲーム名 | 英語のゲーム名
@cg ../data/xak.png                                    # このゲームの CG
../data/XAK/XAK201.MCM                           # 曲名を省略するとデータベースの曲名
../data/XAK/XAK202.MCM | 教会                     # 曲名を指定
../data/XAK/XAK202.MCM | 教会 |  |  | Church      # 5 番目の欄は英語の曲名
@song_cg ../data/xak_botu.png                    # 前の行の曲を鳴らしている間だけの CG
../data/ILLUSION/ILLU110.MCM | City | 1          # ループ回数を指定
../data/FFANTASY/FFAN101.MCM |      | 0          # 0 = 自然に終わるか最大演奏時間までループ

ドライバ(ゲームごと)

曲は、その曲を取ったゲーム自身のサウンドドライバで鳴らします。ROM を作るとき、曲ファイルのフォルダと同じ名前の disk_image のフォルダのディスクイメージからドライバを取り出して手を入れ、ROM に入れます。曲を鳴らす前に、そのドライバを元の番地(RAM)へ写します。

版(drivers.json)ゲーム置く番地
PMAKERプリンセスメーカーCE00h
RISK2キャンペーン版大戦略IICCC0h
CABIN_CD00The Tower of Cabin(ディスク 1・2)CCC0h
XAKII / GAZZELXak II、ガゼルの塔CE00h
CABIN_CF00FRAY(MSX2)、The Tower of Cabin(ディスク 3)CE00h
FRAY_TRFRAY(turboR)CE00h
ILLUSION幻影都市8000h
XAKXakD000h
FFANTASYファイナルファンタジー752Fh(ページ1。ワークは BD00h〜)

ROM を作るとき、ドライバに次の手を入れます(build_rom.py の Drivers)。

ファイナルファンタジーのドライバ(ページ1)

FF のドライバはゲーム本体(4000h〜)の中にあり、ページ1で動きます。ページ1はこの ROM なので、ドライバはページ1の裏の RAM(ページ3と同じスロットの RAM)に置き、呼ぶ間だけページ1を RAM に切り替えます(割込みを止めて A8h と拡張スロットのレジスタを切り替え、終わったら ROM に戻す)。そのため、ドライバから呼ばれるフック(HookLoop・HookNote)と切り替えの処理はページ3の RAM(RamHooks)に置いています。

ゲームごとの表(音色など)

エンベロープ・ビブラート・エフェクト・FM 音色(ソフト音色 32 個)の表(0x1E0 バイト)はゲームごとに違います。ROM を作るとき、ディスクイメージから表を集めて ROM に入れ、曲を鳴らす前にその曲の表をページ2の RAM へ写します。

動き

CG

画面

SCREEN 2(256×192)に、漢字・かなは k8x12(8×12 ドット)、英数字は k6x8 の全角の英数字(6×8 ドット。12 ドットの行の上から 2 ドット目に置く)で文字を描きます。ASCII のうち " ' - ~ は全角の字がないので、似た字(” ’ − 〜)で代用しています。文字の位置は 2 ドット単位で、半角は 6 ドット、全角は 8 ドット進めます。名前表を 0〜255 の連番にしてビットマップとして使うので、1 画面に出せる漢字の種類に制限はありません。1 行は 12 ドットで、画面は 16 行です。

行左右
0タイトルレベルメーター(12 本: PSG 3 + FM 9)
1音源〃
2TRACK・LOOP(何周目か / ループ回数)〃
3TIME・再生モードチャンネル名(PSG は A B C、FM は 1〜9。リズムモードの曲は FM の最後の 3 つが B S H。使うチャンネルは白、使わないチャンネルは灰色)
4演奏中の「ゲーム名 / 曲名」(止まっているときは STOP)
5前のゲーム <- 【選んでいるゲーム】 -> 次のゲーム
6〜15選んでいるゲームの曲リスト(10 曲)

ROM の構成(ASCII16)

バンク配置内容
04000h-7FFFhプログラム、ドライバの情報(DrvDir: 1 つ 40 バイト、最大 12)、ドライバと表の組(SetDir: 最大 32 組)、プレイリスト表(1 曲 12 バイト)、ゲームの情報(CG の場所とゲーム名)、半角フォント
1〜読み出すときだけページ1に出すゲームのドライバ(1 つ約 3KB)、ゲームの表、曲名(日本語と英語)、曲データ(バンク境界をまたがないように詰める)、CG(バンクの先頭から続けて置く)
最後〃全角フォント(曲名・ゲーム名で使う文字だけ。1 字 16 バイト)

プレイリスト表の 1 曲(12 バイト): 曲データのバンク・アドレス・長さ、曲名のバンク・アドレス、ループ回数、ドライバと表の組の番号(SetDir の 1 から)、ゲームの情報のアドレス。

メモリ

場所内容
ページ1の裏の RAM 752Fh-7FAFhファイナルファンタジーのドライバ(呼ぶ間だけページ1を RAM にする)
ページ2の RAM 8000h-8D76h幻影都市のドライバ
8F00h-9FFFhゲームの表(曲を始めるたびにコピー。番地はドライバごと)
A000h-BFFFh演奏中の曲データ(曲を始めるたびにコピー)。FF のドライバのときは BD00h からがそのワーク
C000h-プレーヤーのワーク、RAM に置くルーチン(バンク読み出し・CG の展開・フック)
-CCBFhスタック
CCC0h-DDFFhゲームのドライバ(番地はドライバごと。後ろはドライバのワーク)

確かめたこと

フォント

門真 なむ氏の「k8x12」と「k6x8」(英数字)を使っています。どちらも自由に利用・改変・再配布できます(font/misaki_12x8/k8x12.txt、font/k6x8/k6x8.txt を参照)。