読者です 読者をやめる 読者になる 読者になる

防水MP3プレーヤーとPerlの関係

 iriverSpeedo ブランドで作っている Aquabeat (asin:B001BRDFA8) という防水 MP3 プレーヤーを使ってみている。最初はスポーツクラブで借りて使ったのだが、この時はどうもイヤーピースの具合が悪かった。Amazon で購入したものは写真とは違って、レーザーレーサーモデルとして販売しているものと同じヘッドセットが付いている。これにして、普通のイヤーピースにするといくらかマシにはなるが、まだイマイチなのがちょっと残念だ。別の防水ヘッドフォンを探してみた方がいいかもしれない。音質を要求するわけではないが、ヘッドセットがイマイチなので、まだ快適に音楽を聴きながら優雅に泳ぐという感じにはならない。とはいえ、何十分もプールの底を見つめながら泳ぐ退屈さを考えると、音楽プレーヤーが使えるというのは画期的だ。落語を一席聴くとちょうどいい感じだが、落語と水泳のマッチングは未検証。

 Mac からは普通の USB ストレージとして見えるので、mp3 ファイルをコピーしてやれば再生はできる。iTunes で曲を選んで、そのままドラッグ&ドロップすればいい。問題は曲順だ。メモリ容量は 1G で、手元の曲だと約150曲が入る。どうせ適当にランダムに選んだ曲を突っ込むので、曲順をどうこうする必要はないが、ランダムでないと具合が悪い。iTunes のファイルは先頭にアルバム中の曲順が付いている。Aquabeat はファイル名の順番に再生するので、アルバムの先頭に入っている曲が優先的に再生されてしまう。

 というわけで、ファイル名をランダムにするスクリプトを書いた。プログラムを書くのは久しぶりなので、配列要素をランダムに並び替える方法を探してみると、インデックスを走査して、ランダムに選んだ要素と交換する方法が多い。これだとツーパス必要だし、ちょっと処理も無駄な気がしたので、結局最初にこんなスクリプトを書いた。

my @file = @ARGV;
for (my $i = 0; @file; $i++) {
    my $old = splice(@file, int(rand(@file)), 1);
    my $new = sprintf("[%03d] %s", $i, $old);
    print "$old -> $new\n";
    rename($old, $new);
}

 残っているファイルからランダムに1つを選び出して、連番を頭にふっているだけだ。芸がないので、いわゆるシュワルツ変換を使ってみるかと思うとこんな風になった。

for my $old (map {$_->[0]} sort {$a->[1] <=> $b->[1]} map {[$_, rand(1)]} @ARGV) {
    my $new = sprintf("[%03d] %s", $i++, $old);
    print "$old -> $new\n";
    rename($old, $new) or die "$!";;
}

 ここで「律儀に連番を振ってやる必要があるのか?」という疑問が湧いた。そもそもプレーヤーにディスプレイなんか付いてないし、あったところでファイル名なんか表示しないだろうから、ファイル名はどんなものでも構わない。だったら、名前そのものをランダムにしてやればいい。というわけで、これでも十分機能する。

perl -e 'map{rename$_,rand().$_}@ARGV' -- *.mp3

 さすがにこれでは見栄えが悪いので、ちょっと手を入れてこんなところか。

perl -e 'map{rename($_,sprintf("[%04d] %s",rand(10000),$_))}@ARGV' -- *.mp3

 どうやら、よいこの正解は List::Util の shuffle を使うことらしい。これがどんな風に実装されてのか興味が湧いたので見てみた。

sub shuffle (@) {
    my @a=\(@_);
    my $n;
    my $i=@_;
    map {
        $n = rand($i--);
        (${$a[$n]}, $a[$n] = $a[$i])[0];
    } @_;
}

 ちょっと難しいが、よく読んでみると最初の方法と処理量はだいたい同じだ。splice なんか使うとリスト操作の手間が増えちゃうので、そこを1回の代入で済ませているところが秀逸だ。

iriver speedoブランド水深3m利用可能防水プレーヤー Aquabeat 1GB ブラック 防水イヤホン付 AQB-1GB-BLK

iriver speedoブランド水深3m利用可能防水プレーヤー Aquabeat 1GB ブラック 防水イヤホン付 AQB-1GB-BLK