tsutsuiの作業記録置き場

NetBSDとかPC-6001とかの作業記録のうち、Twitterの140字では収まらない内容や記事としてまとめるべき内容をとりあえず置いてみる予定

「Tinyみずいろ」にBGMを追加するまで(2)


例によってダレてきてますが、 BGM追加までの続きで今回は Exomizer についてです。
いまさらですが、前回の記事の冒頭の埋め込み動画が間違ってタイニーあぴミクさんのになってたので修正しました。スイマセン

Exomizer

前回の記事 の最後に書いたように、「Tinyみずいろ」に よっしゅさんの PSG音源ドライバ で BGM を追加するためには 15k バイトあるグラフィックデータを少なくとも 2kバイトは縮める必要がありました。

結論としては、動画 の投稿コメント中にも記載しているように Exomizer なる圧縮展開ルーチンを使用したのですが、この Exomizer を知ったのはたまたまというか、 Twitter 上でのやり取りがきっかけでした。前回のエントリの後半で紹介した TINY野郎さん の MML2P6PSGDRV コンパイラ をいじっている最中に bookwormさんP6音源ドライバ を紹介していただいたのがそれです。


この bookwormさんのドライバは MKNさんの「P6音楽事情①」のエントリ でも「現時点で最強のドライバ」として紹介されているように高機能で、「1つのチャンネルに複数のトラックを割り当てて上位のトラックが休符の時に下位トラックの音を鳴らせる」といったところは魅力的でした。が、説明文中のデフォルトの使い方は N60m-BASIC (=mkII 以降) の MODE 5 であったこと、さらに

BASIC との同居も可能なのですが、説明が冗長な割に誰も求めていないと思うので割愛します。

という説明もあり、「とりあえず BGMを鳴らせればいい」という今回の用途にはちょっと手間がかかるかな、ということで Tinyみずいろ向けにはいったん保留という判断になりました。

音源ドライバ自体は見送ってしまったものの、 bookwormさん のページには P6音源ドライバ以外にも PC-8801 の記事もあり、ついつい気になって MML2P6PSGDRV コンパイラ検証が一段落した後に一通り読み耽ってしまったのですが、その中の「落ちつく (落ちものパズルをつくる)」で Exomizer が紹介されていたのでした。

突然ですが Exomizer V2 というツールがあるんですよ。
MSX関連を巡っていて見つけた圧縮ツールの一種なんですが、解凍プログラムが Z80版で用意されているのです。
解凍速度も結構速いし、なにより圧縮率が優れています。解凍用のコードもコンパクト。

記事中の圧縮率比較を見ると、 zip や lzh と比べても引けを取らないどころかむしろ圧縮率としては勝っていて、実際の P6mkII MODE 3 のグラフィック圧縮例でも 50〜70% と十分な感じです。が、

今回は読み込み速度と展開速度を秤にかけて、圧縮は見送り。残念。

ともあり、デモに使うとすれば展開速度次第か? というところでした。

Exomizer 詳細

さっそく Exomizer 2 のページ から最新の 2.0.9 の zip 一式を取ってきて展開して z80 のソースを探すと、 exo20info.txt 中に以下の記載があります。

o Contributed decruncher source
1) forward 6502 decuncher by Krill (exodecrs/krilldecr.s)
2) z80 decrunchers by Metalbrain, Antonio Villena. (rawdecrs/z80/*)
3) 6809 decruncher by Edouard Forler. (rawdecrs/6809/*)

"rawdecrs" は「raw command で圧縮されたファイルを decrunch (展開というか再構成?) するもの」ということで、要は単純展開ルーチンということのようです。

で、 rawdecrs/z80 以下を見ると以下のファイルがあります。

deexo.asm
deexo_b.asm
deexo_simple.asm
deexo_simple_b.asm
readme.txt

この readme.txt がまたそっけない記述なのですが、とりあえず使うには deexo.asm を見ればよさそうです。 _b 付きは逆方向で圧縮されたデータの展開、 _simple 付きはテーブルが 256バイト境界前提のコードっぽい

コードはコメント込みで 113行。サイズは (コメントによれば) コードが 169バイト + ワークエリアとしてのテーブルが 156バイトの合計 325バイトだけあればよい(!?) という驚きのサイズです。

Exomizer による Tinyみずいろ画像圧縮

とりあえず "raw command" で圧縮すればいいらしいということで、実際に Tinyみずいろの画像データを圧縮してみてどれくらいのサイズになるか確認することにしました。

圧縮方法

Exomizer の配布 zip には "win32" というディレクトリがあって、その中の exomizer.exe を使って bookworm さんのページ の説明にあるように

圧縮するには >exomizer raw [source] -o [dest] という感じで指定します。

とすれば良いようです。が、当時の私はせっかちにも説明を読まずにいつもの NetBSD/i386 環境で src ディレクトリ中で make してできた exoraw のバイナリを使用しました。

とりあえず何も読まずに exoraw を引数なしで実行してみます。

% ./exoraw
Error: exactly one input file must be given.
usage: exoraw [option]... infile
-b crunch/decrunch backwards
-r write outfile in reverse order
-d decrunch (instead of crunch)
-c compatibility mode, disables the use of literal sequences
-C enable imprecise rle matching, trades result for speed
-e <encoding> uses the given encoding for crunching
-E don't write the encoding to the outfile
-m <offset> sets the maximum sequence offset, default is 65535
-M <length> sets the maximum sequence length, default is 65535
-p <passes> limits the number of optimization passes, default is 65535
-o <outfile> sets the outfile name, default is "a.out"
-q quiet mode, disables display output
-v displays version and the usage license
-- treats all following arguments as non-options
-? displays this help screen

オプションなしの引数が入力ファイル、 -o で出力ファイル指定、 -d で decrunch なので

  • ./exoraw input_file -o crunched_file で圧縮して出力
  • ./exoraw -d crunched_file -o decrunched_file で圧縮したファイルを復元

でいけそうです。適当なファイルはないか、ということで exoraw のコマンド自身で試してみると

% ./exoraw exoraw -o exoraw.exo
Crunching infile "exoraw" to outfile "exoraw.exo".

Phase 1: Instrumenting file
-----------------------------
Length of indata: 55560 bytes.
[building.directed.acyclic.graph.building.directed.acyclic.graph.]
Instrumenting file, done.

Phase 2: Calculating encoding
-----------------------------
pass 1: optimizing ..
[finding.cheapest.path.finding.cheapest.path.finding.cheapest.pat]
size 210980.0 bits ~26373 bytes
pass 2: optimizing ..
[finding.cheapest.path.finding.cheapest.path.finding.cheapest.pat]
size 209576.0 bits ~26197 bytes
pass 3: optimizing ..
Calculating encoding, done.

Phase 3: Generating output file
------------------------------
Encoding: 2122222123443514,1111,2113334456667788,34445666899ABCEF
Length of crunched data: 26226 bytes.
Literal sequences are not used and the safety offset is 2.
% ./exoraw -d exoraw.exo -o exoraw.bin
Decrunching infile "exoraw.exo" to outfile "exoraw.bin".
Encoding: 2122222123443514,1111,2113334456667788,34445666899ABCEF
% diff exoraw exoraw.bin
%

と、いろいろログが出力されていますが、元ファイルの 55560バイトが 26226バイトに圧縮されて、復元後のファイルが元ファイルと一致していることも確認できました。

グラフィックデータ取り出し

次は Tinyみずいろのグラフィックデータがどれくらい縮まるかなのですが、その確認のためにはまず元プログラムではランレングス圧縮されているデータを VRAM 上の実イメージに復元する必要があります。

理屈としては適当な展開ルーチンを書けばいいのですが、P6エミュの PC6001VW のマニュアルをいろいろ調べると「エミュレータ実行中の本体メモリの内容をそのままホストのファイルとしてセーブする」という "getbin" というコマンドがあるようなので、それを使うことにします。

行きあたりばったりで試したために PC6001VW のバグに微妙にハマったりしましたが、最終的には以下の手順でいけました。

PC6001VW 起動時の「オプション2」の「開発用フォルダ」 (= "getbin" および "setbin" コマンド等で指定するバイナリのデフォルトディレクトリ) を指定


Tinyみずいろを起動して取り込むグラフィックが表示されたところでモニタモードに入る


「モニタモード」の操作説明にあるとおりに [PageUp]/[PageDown] + [L-Ctrl] および [Shift] を駆使して VRAM の E200h を参照


[End]キーを 2回押してビットマップ表示モードに切り替え


さらに [PageUP]+[PageDown] の同時押し×2回 で SCREEN4 表示モードに設定


VRAM のグラフィックデータ自体は E200h〜F9FFh までの 6k バイトなのですが、下の方のメッセージ表示ウインドウ(?)部分のサイズは引いてやる必要があるので、その部分のアドレスを確認します。
BASICリストをちゃんと読めば「画像は 0〜150ラインまで」というのも実はわかるのですが完全な泥縄式だったり

横が 256ドット、 1バイトで 8ドットなので、 32バイトで 1ライン。モニタモードの SCREEN4 表示だとメッセージ枠は F400h 付近っぽいので、そのあたりを表示して [End] キーで表示モードを切り替えると、 F4DFh までが有効データ、つまり E200h〜F4DFh までの 4832バイトが元データサイズということがわかりました。



"?" で出てくるヘルプを見ながら VRAM データを適当にファイルに保存してやります。


これをそれぞれのグラフィックに対して繰り返します。

圧縮結果

こうして 5枚のデータをセーブして、 Exomizer の raw コマンドで圧縮した結果を元のランレングス圧縮のサイズと比べると以下のようになりました。

グラフィック 元画像サイズ ランレングス圧縮 (比率) Exomizer圧縮 (比率)
あいさつ雪希さん 4832 3103 (64.2%) 2553 (52.8%)
なきむし雪希さん 4832 3065 (63.4%) 2346 (48.6%)
おえかき雪希さん 4832 3242 (67.1%) 2689 (55.6%)
しょんぼり雪希さん 4832 2574 (53.5%) 2080 (43.0%)
うれしい雪希さん 4832 3398 (70.3%) 2604 (53.9%)
合計サイズ 24160 15382 (63.7%) 12272 (50.8%)

wma→wav 化後の ビット化けの修復手順 によっては微妙に差が出るかも

というわけで、 Exomizer の展開ルーチンに必要な 325バイトを含めても 15382 - (12272 + 325) = 2785 と、当初の目標(?)であった 2kバイトは十分に確保できそうだというメドが立ちました。


作業当時を思い出しながら書いているせいでつい再現実況状態になってしまい今回も長くなってしまったので、実際の Exomizer ルーチンのクロスアセンブル環境構築等々は次回以降に続きます。