試験運用中なLinux備忘録・旧記事

はてなダイアリーで公開していた2007年5月-2015年3月の記事を保存しています。

mml2nsf.py(2009/12/7版)作成上のメモ

Wine上のppmckで.mmlファイルを.nsfファイルに変換する処理を自動化するPythonスクリプト(2009/12/7版)」のスクリプトを作成した上での幾つかのメモを扱う。

Pythonのshutil

shutilというモジュールを用いると端末シェル上のファイル操作系コマンドのようにPythonで高レベルなファイル操作ができる。
詳しくは
http://www.python.jp/doc/release/lib/module-shutil.html
に載っている。

rmtree()

shutil.rmtree()を用いると引数のディレクトリ以下をまとめて消すことができる。

copy()とcopyfile()

shutil.copy()shutil.copy2()*1を用いると1つ目の引数の場所にあるファイルを

コピーする。この引数の処理の仕方はcpコマンドに近い。「ファイル/ディレクトリの基本的な操作を行うコマンドについて」も参照。
shutil.copyfile()も似ているが、こちらは2つ目の引数にはディレクトリを指定できず(指定すると「Is a directory」のIOErrorが発生)、新しいパス名の指定のみ受け付ける。
ディレクトリ階層をコピーしたい場合はshutil.copytree()が役に立つ。

move()

shutil.move()を用いると1つ目の引数のパス名を2つ目の引数のパス名へ移動もしくは名前変更することができる。

Pythonで一時ディレクトリを扱う

tempfileモジュールのtempfile.mkdtemp()を用いると一時ディレクトリを作成することができ、この戻り値がそのディレクトリのパス名として得られる。

ppmck関係の処理に関して

スクリプト全体の流れ
  1. コマンド行引数(処理する.mmlファイルの場所を指定)のチェック
  2. 入力ファイルの拡張子チェックとファイル名部分の取り出し
  3. 出力ディレクトリとWine環境のチェック、なければ準備
  4. ppmckのチェック、なければurllibモジュールを用いてダウンロードし、zipfileモジュールでZIPファイルを展開
  5. MMLファイルの処理
MMLファイルの処理

ppmck内のmml2nsf.plの真似をして、とりあえず同じように動作するようになってはいるが、もしかするとどこか処理を読み間違えていたりするところがあるかもしれない*3

  1. 一時ディレクトリの作成と移動
  2. ソース(.mmlファイル)を一時ディレクトリにコピー
  3. ppmckc-iオプションにソースを指定して引数(出力ファイル)にsongdata.hという名前の中間ファイルを指定し、この名前で書き出すようにして変換実行
  4. ここで出力ファイルsongdata.hの他にdefine.inc,effect.hの2つのファイルも生成され、define.incnesasmにかけるアセンブリ言語ファイル(temp.asmとする)のベースとして使用(名前変更する)
  5. ppmckの中のnes_includeディレクトリにあるppmck.asmから「effect.h」と「define.inc」のいずれも含まない行だけを一時ファイルtemp.asm(define.incの内容)に追記・「いずれも含まない行」というのはそれぞれのファイルの内容を直接.asmファイルに含めるようにするためで、define.incは既に名前変更で全ての内容を含んでいる
  6. (もう一方の)effect.hの内容を同様に追記するが、「.include songdata.h」の行はsongdata.hの実際の内容に置き換える(別途このファイルを開いて内容を読んでいき、temp.asmに書き込んでいく)
  7. 環境変数NES_INCLUDEにnes_includeディレクトリの場所を指定し、-s -rawオプションを付けて.asmファイルをnesasmで処理・環境変数が設定されないとppmck/sounddrv.hが開けず(「Can not open file!」となる)アセンブル*4できない
  8. 生成された.nesファイルの拡張子を.nsfにして(拡張子より左は元のファイルの名前を利用)出力ディレクトリにコピー
  9. 一時ディレクトリの後始末(一時ディレクトリの作成後、途中で失敗した処理があった場合も例外の仕組みを用いてfinally節で消す)

関連記事:

参考URL:

*1:shutil.copy()にタイムスタンプのコピー機能を追加したもので、属性(パーミッション)はどちらもコピーされる

*2:既存のディレクトリ内の(新しい)名前である必要があり、存在しないディレクトリの中の名前を指定すると「No such file or directory」のエラーとなる

*3:元のスクリプトPerl独自の文法を用いているなど、そのまま簡単に書き換えるというわけにはいかない部分もあるため

*4:ここではnesasmによる.asm->.nes(.nsf)変換を指す