Mac における MP3 ファイルの文字化けを直してみた

約2年半前、初めて Mac を買ったわけですが、Windows で使っていた MP3 ファイルを持ってくるとメタ情報が文字化けして困ったものです。iTunes のリストなんかは日本語の曲名がさっぱりわかりません。
当時いろいろ調べてみたところ、どうも ID3 タグの文字コードの問題ということまではわかっていたのですが、iTunes で ID3 タグの変換をすると直るとか、EasyTAG を使えばいいだとかの情報があっても結局直せませんでした><

よく考えると、ID3 タグを書き換えれればいいだけなので iTunes や EasyTAG のように情弱には扱いづらいツールを使わなくてもいいんですよね!そう考えると敷居が随分低くなります。
というわけで eyeD3 を使って ID3 タグの文字コードを変えてみました。

文字化けの原因

例として MP3フリー音楽素材・効果音草原をゆく という曲を使わせていただくことにします。

$ wget http://www.hmix.net/music/n/n62.mp3
$ hexdump n62.mp3 | head
0000000 49 44 33 03 00 00 00 00 20 37 54 59 45 52 00 00
0000010 00 05 00 00 00 32 30 31 32 54 50 45 32 00 00 00
0000020 09 00 00 00 8f 48 8e 52 97 54 98 61 54 49 54 32
0000030 00 00 00 0b 00 00 00 91 90 8c b4 82 f0 82 e4 82
0000040 ad 54 43 4f 4e 00 00 00 05 00 00 00 28 31 32 29
0000050 54 41 4c 42 00 00 00 15 00 00 00 89 b9 89 ae 46
0000060 45 53 81 79 97 56 2d 41 73 6f 62 69 2d 81 7a 54
0000070 50 45 31 00 00 00 09 00 00 00 8f 48 8e 52 97 54
0000080 98 61 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

ID3v2 の場合、複数のフレームにメタ情報が格納されており、各フレームは最初の 4 バイトがフレーム ID、次の 2 バイトがフレームサイズ、次の 2 バイトがフラグ(?)、残りがフレームデータから成るようです。
例えば曲名は TIT2 (“\x54\x49\x54\x32”) というフレーム ID に相当しますが、hexdump の結果から、フレームサイズが 0x0b、フレームデータが “\x91\x90\x8c\xb4\x82\xf0\x82\xe4\x82\xad” であることがわかります。1
文字化けの原因はこのフレームデータの文字コードが cp932 という得体の知れない文字コードであることです。

$ python -c 'print "\x91\x90\x8c\xb4\x82\xf0\x82\xe4\x82\xad".decode("cp932")'
草原をゆく

Quick Look で再生してみると盛大に文字化けしていることが確認できます。
20130123063655

eyeD3 のインストール

eyeD3 は Python ツール & ライブラリなので、Python が必要です。Mac にはデフォルトで Python がインストールされていますが、自分の場合は pythonbrew で入れた Python 2.7.1 を使いました。eyeD3 の最新版は 0.7.1 なんですが、0.7.1 だと ImageFrame#render にバグがあり、現在開発されている 0.7.2 では既に修正されていたのでリポジトリから取得したものを使用しました。

$ hg clone https://bitbucket.org/nicfit/eyed3
$ cd eyed3
$ paver install
$ eyeD3 -h
usage: eyeD3 [-h] [--version] [-l LEVEL[:LOGGER]] [--exclude PATTERN] [-L] [-P NAME] [-C FILE]
             [--backup] [-Q] [--fs-encoding ENCODING] [--no-config] [--profile] [--pdb]
             [-a STRING] [-A STRING] [-t STRING] [-n NUM] [-N NUM] [-G GENRE] [-Y YEAR]
             [-c STRING] [--rename PATTERN] [-1] [-2] [--to-v1.1] [--to-v2.3] [--to-v2.4]
             [--release-date DATE] [--orig-release-date DATE] [--recording-date DATE]
             [--encoding-date DATE] [--tagging-date DATE] [--publisher STRING] [--play-count <+>N]
             [--bpm N] [--unique-file-id OWNER_ID:ID] [--add-comment COMMENT[:DESCRIPTION[:LANG]]
             [--remove-comment DESCRIPTION[:LANG]] [--remove-all-comments]
             [--add-lyrics LYRICS_FILE[:DESCRIPTION[:LANG]]] [--remove-lyrics DESCRIPTION[:LANG]]
             [--remove-all-lyrics] [--text-frame FID:TEXT] [--user-text-frame DESC:TEXT]
             [--url-frame FID:URL] [--user-url-frame DESCRIPTION:URL]
             [--add-image IMG_PATH:TYPE[:DESCRIPTION]] [--remove-image DESCRIPTION]
             [--remove-all-images] [--write-images DIR]
             [--add-object OBJ_PATH:MIME-TYPE[:DESCRIPTION[:FILENAME]]]
             [--remove-object DESCRIPTION] [--write-objects DIR] [--remove-all-objects]
             [--add-popularity EMAIL:RATING[:PLAY_COUNT]] [--remove-popularity EMAIL]
             [--remove-v1] [--remove-v2] [--remove-all] [--remove-frame FID]
             [--encoding latin1|utf8|utf16|utf16-be] [--force-update] [-v]
             [PATH [PATH ...]]
...

ID3 タグの文字コードの変換

eyeD3 を使って最終的には次のようなスクリプトを作成しました。

テキストデータは src/eyed3/id3/frames.py で定義されている decodeUnicode 関数によって Unicode 文字列に変換されるため、cp932 に戻すためには一度 latin1 で encode する必要があります。

n62.mp3 の文字コードを変換するには次のように使います。

$ wget https://gist.github.com/raw/4598940/id3conv.py
$ python id3conv.py n62.mp3

再度 Quick Look で再生してみると文字化けが直っていることが確認できます。2
20130123063656

find と xargs を使えば指定したディレクトリ以下の全てのファイルを変換することも可能です。
例えばカレントディレクトリ以下の全ての MP3 ファイルを変換したい場合は次のように実行します。

find . -type f -name "*.mp3" -print0 | xargs -0 python id3conv.py

これで Windows から Mac への移行も安心ですね!

  1. 暗号化や圧縮がされていない場合フレームデータの最初の 1 バイトは Groupd ID というのに使われるようです

  2. 結果が反映されるまでには時間がかかることもあるみたいです

広告
ピュア R で MessagePack for R を作ってみた(unpack のみ) 独立性の仮定と平均場近似の関係
※このエントリーははてなダイアリーから移行したものです。過去のコメントなどはそちらを参照してください