カーナビ三部作その3:microSDHCにMP3ファイルを書き込む順番で苦労する

id:eel3:20110619:1308413539 の続き。

何やら妙なところで色々と苦労したものの、遂にMP3をmicroSDHCに書き込めるようになった。

なので早速フォルダごとMP3ファイルをコピー……とはいかない。このmicroSDHCはカーナビで使うのだ。カーナビ――そう、相手は組み込み機器。パソコンとは一味違う。

何を言いたいかというと、このカーナビはSDメモリに書き込まれた順でしかディレクトリやファイルを読み出せない。最上位の階層から書き込まれた順にディレクトリツリーを辿っていき、書き込まれた順にファイル情報を取得していく。

実際にはもう少し複雑……というかよく分からない挙動だ。というのも後からファイルやディレクトリを追加/削除したり名前を変更したりすると、そのファイル/ディレクトリはよく分からない順番で読み出される。

ファイルシステム周りは知識が無いのでよく分からないのだが、多分FATのテーブルなりエントリなりの情報を舐めた順番そのままに表示しているのだろう。

正直なところ「せめて名前順にソートしてくれないかなあ」と思わないでもないのだが*1、一方でカーナビではないが組み込みの仕事をしている身として気持ちは理解できる。メモリが足りないのか、応答速度の面で遅くなってしまうのか。どちらもありえそうだ。

発想を変えると、ディレクトリやファイルを書き込む順番を制御することで、自分が望む順番でカーナビにファイルを読み出させることが可能となる。これはこれで、うまく使えばメリットとなる。ただ後でディレクトリやファイルを追加する時に順番を調整しなおしたい場合には一旦ファイル等を削除する必要があるかもしれないが。

今回は、

  • アーティスト名は名前順に並べる。
  • アルバム名は発表順に並べる。
  • 楽曲名はアルバムのトラック順に並べる。

といった条件を満たすような順番でディレクトリやファイルを書き込むことにした。

ところでSDメモリには複数のアーティストの複数のアルバムCDからリッピングしたMP3を書き込む。結構量が多いので、ディレクトリやファイルを指定した順番で書き込むにあたり、作業を自動化したい。

ディレクトリ一覧を作成する

Rhythmboxで取り込んだ音楽データは $HOME/ミュージック 以下に書き込まれる。手元の設定ではこのディレクトリ内に「アーティスト名/アルバム名」という命名規則ディレクトリが作成され、その中に各トラックの音楽データが「トラック番号 - 楽曲名.mp3」という感じの名前で書き込まれる。

SDメモリにデータを書き込む際は、

  • $HOME/ミュージック 内のファイル・ディレクトリを、
  • 名前は変更せず、
  • 先に書いたルールに基づく順番で書き込む。

といったことを行うことになる。

まずは作成するディレクトリの一覧を取得してみた。

cd ~/ミュージック
find . -type d | sort | sed -n 's/^\.\///p' > ../dirlist.txt

大体こんな感じの一覧が取得できる。

Cactus
Cactus/Barely Contained - The Studio Sessions [Disc 1]
Cactus/Barely Contained - The Studio Sessions [Disc 2]
Creedence Clearwater Revival
Creedence Clearwater Revival/Bayou Country
Creedence Clearwater Revival/Creedence Clearwater Revival
Creedence Clearwater Revival/Green River
Creedence Clearwater Revival/Willy And The Poor Boys
Foghat
Foghat/Fool For The City

実際にSDメモリに書き込む内容の一部を抜粋。年齢を疑われる内容かもしれない :)

とりあえずこの一覧を、SDメモリに書き込んでほしい順番に並び替える。この一覧の場合、Creedence Clearwater Revivalのアルバムが微妙に発表順でないので修正する。

Cactus
Cactus/Barely Contained - The Studio Sessions [Disc 1]
Cactus/Barely Contained - The Studio Sessions [Disc 2]
Creedence Clearwater Revival
Creedence Clearwater Revival/Creedence Clearwater Revival
Creedence Clearwater Revival/Bayou Country
Creedence Clearwater Revival/Green River
Creedence Clearwater Revival/Willy And The Poor Boys
Foghat
Foghat/Fool For The City

ディレクトリを書き込む順番はこれでOK。

ファイルの書き込み順はどうするのか? ファイル名は先頭にトラック番号が付いている。トラック番号はゼロパディングされている。少なくともあるディレクトリ直下のファイルに関しては、ワイルドカード * で処理すればトラック順に書き込まれるはずだ。

書き込み処理を行うスクリプトを生成するスクリプトを書く

元データとなりそうなディレクトリ一覧ファイル dirlist.txt が完成した。後はこのファイルを活用してファイルの書き込みを行うだけだ。

ここで頭の良い人ならPerlRubyあたりでワンライナーでさくっと済ませるのだと思うし、普通の人はディレクトリ作成とファイルコピーをする使い捨てスクリプトをささっと拵えてしまうと思うのだが、私は頭の出来がイマイチな部類に入る人なので泥臭くこんなシェルスクリプトを書いてみた。

#!/bin/sh

if [ $# -ne 3 ]; then
    echo "usage: `basename $0` <dirlist_file> <basedir_copy_from> <dir_copy_to>" 1>&2
    exit 1
fi

DIRLIST=$1
COPYFROM=`echo $2 | sed "s/\/$//"`
COPYTO=`echo $3 | sed "s/\/$//"`

sed 's/[][ ;&()|^<>?*$`"'"'"'{}#\\]/\\&/g' $DIRLIST | gawk '
BEGIN {
    print "#!/bin/sh\n"
    print "#rm -rf '"$COPYTO"'/*\n"
}
{
    copyto = "'"$COPYTO"'/" $0
    print "mkdir " copyto
    if ($0 ~ /\//) {
        print "cp '"$COPYFROM"'/" $0 "/* " copyto
    }
}
'

sedgawkの組み合わせ。もしかしたら、これも微妙に年齢を疑われる要素かも。

このスクリプト mkscript.sh を例えば以下のように実行すると、

./mkscript.sh dirlist.txt ./ミュージック/ /media/usbmem/ > copymp3.sh

こんなファイルが生成される。

#!/bin/sh

#rm -rf /media/usbmem/*

mkdir /media/usbmem/Cactus
mkdir /media/usbmem/Cactus/Barely\ Contained\ -\ The\ Studio\ Sessions\ \[Disc\ 1\]
cp ./ミュージック/Cactus/Barely\ Contained\ -\ The\ Studio\ Sessions\ \[Disc\ 1\]/* /media/usbmem/Cactus/Barely\ Contained\ -\ The\ Studio\ Sessions\ \[Disc\ 1\]
mkdir /media/usbmem/Cactus/Barely\ Contained\ -\ The\ Studio\ Sessions\ \[Disc\ 2\]
cp ./ミュージック/Cactus/Barely\ Contained\ -\ The\ Studio\ Sessions\ \[Disc\ 2\]/* /media/usbmem/Cactus/Barely\ Contained\ -\ The\ Studio\ Sessions\ \[Disc\ 2\]
mkdir /media/usbmem/Creedence\ Clearwater\ Revival
mkdir /media/usbmem/Creedence\ Clearwater\ Revival/Creedence\ Clearwater\ Revival
cp ./ミュージック/Creedence\ Clearwater\ Revival/Creedence\ Clearwater\ Revival/* /media/usbmem/Creedence\ Clearwater\ Revival/Creedence\ Clearwater\ Revival
mkdir /media/usbmem/Creedence\ Clearwater\ Revival/Bayou\ Country
cp ./ミュージック/Creedence\ Clearwater\ Revival/Bayou\ Country/* /media/usbmem/Creedence\ Clearwater\ Revival/Bayou\ Country
mkdir /media/usbmem/Creedence\ Clearwater\ Revival/Green\ River
cp ./ミュージック/Creedence\ Clearwater\ Revival/Green\ River/* /media/usbmem/Creedence\ Clearwater\ Revival/Green\ River
mkdir /media/usbmem/Creedence\ Clearwater\ Revival/Willy\ And\ The\ Poor\ Boys
cp ./ミュージック/Creedence\ Clearwater\ Revival/Willy\ And\ The\ Poor\ Boys/* /media/usbmem/Creedence\ Clearwater\ Revival/Willy\ And\ The\ Poor\ Boys
mkdir /media/usbmem/Foghat
mkdir /media/usbmem/Foghat/Fool\ For\ The\ City
cp ./ミュージック/Foghat/Fool\ For\ The\ City/* /media/usbmem/Foghat/Fool\ For\ The\ City

書き込み処理を行うスクリプトだ。後は処理の抜けや順番間違いが無いことを確認して、それからスクリプトを実行するだけだ。

*1:名前順なら、名前の先頭に番号を付けることで表示順を制御できるので。