coding, photo, plant and demo

*Linux用mdx再生ツール mdx2wav

mxdrv x68000 tech 20140215 115535

mdx2wav

Raspberry Pi+RuneAudio を試してみて、何故かMPDでMDXを鳴らそうと思って手頃なものを探してみたのだけど、なかなか見つからない。
Generic Decoderで動かすためには、ファイル名を入れたら標準出力にraw pcmやタグを書き出してくれるシンプルなのがあると良いんだけどねえ。なんか無さそう。無いなら作るか、ってことで作ってみました。

ソースやビルド方法、使い方は下記にあります。
https://github.com/mitsuman/mdx2wav

特徴としては

  • ドライバはMXDRVgベース
  • YM2151エミュは標準のfmgenとmameのym2151.cをコマンドラインオプションで切り替え可能
    • 聴き比べて楽しもう

くらいです。
MXDRVgはまじめに62.5kHzでYM2151をサンプリングして44.1kHzや48kHzにダウンサンプルするのですが、mame版も同様のダウンサンプリングを適用しています。

作る上でハマったこと

MXDRVg+fmgenはビルド環境によってはおかしくなります。

変なポインタ操作

たまたま動いていたと思われる変なポインタ操作が特定の環境でおかしくなることがありました。
具体的にはfmgenの下記です。
  1. 1 *p++ = p[-512] / 2;
通常、
  1. 1 *p = p[-512] / 2;
  2. 2 p++;
と解釈されるようなのですが、armv6l(hard-float)版 gcc version 4.8.2 20131219 (prerelease)だと
  1. 1 *p = p[-512 + 1] / 2;
  2. 2 p++;
と解釈されてしまうのか想定外な結果になりました。おそらく、こういった操作は未定義だと思いますのでソースを修正するべきです。

修正コミット
https://github.com/mitsuman/mdx2wav/commit/290bf9a86daacb48d42123d3a2a7d64c5dfec0b3

LP64だとMXDRVgの中でメモリ破壊が起きる。

MXDRVgはX68000実機のmxdrvのバイナリを逆アセンブルして機械語をほぼ1:1でCへ移植したものです。ベタに移植しているのでデータもアドレスも32bit長さのレジスタ(変数)に区別なく入れられます。そしてアドレスはメモリマップとして確保された配列へのインデックスとして使われるのではなく、直接ホストマシンのポインタとして使われます。かなりアグレッシブです。この場合、配置されたアドレスが32bitに収まらないと動きません。これに関しては…まだ実際の問題として直面してないので直してません…。

そしてlongを多用しているのですが、LLP64(longが32bitでlong longとポインタは64bit)しか想定されていないようです。メモリコピーなどがlongの単位で行われ場所があるのですが、LP64なlinuxやmac等はlongは64bitなのでメモリを壊してしまいます。

修正コミット
https://github.com/mitsuman/mdx2wav/commit/de3952a06f641db258abf8d190e5ddfcf5148530

今後の課題

このあたり、-Wallを付けていれば警告されるような話なのですが、如何せんWarningの総量が多すぎて見逃してしまいハマりました。またユニットテストがないため、どこが問題になっているかの特定に手こずりました。ということで、今後の課題としては、

  • Warning撲滅
  • ユニットテスト追加
  • MXDRVgのポインタを生アドレスとして使うのではなく配列のインデックスとする
    • ただし64bit版の安全を保証する代わりに少し遅くなる

あたりがありますが、もういいかという気も(だって需要ないし)。

肝心のMPDのGeneric Decoderのリベースですがこれも動くところまではできてます。とりあえずMPDでMDXのタイトル等を取得してMDXが鳴るところまでは確認しています。ただ、これも公開するなら(あるいはコントリビュートするなら)、もうちょっと仕様を練ったりリファクタリングしないとダメだな、という感じ。

以上、完全に趣味のコーディングでした。