linuxで音楽CDのリッピングをしたい場合、abcde 1 が大変便利である。このツールはCDDB 2 からのアルバム情報 (タイトル、発表年、曲名等) の取得、WAVファイルの読取、各種音声フォーマットへのエンコード、ID3タグの付与、等々を一度に自動的に行ってくれる大変便利なものである。また、コンソール上で全て操作できるのがうれしい。

abcde は十分に便利なため、基本的にはそのまま使えば大抵のことはできてしまうはずだが、今回、私は以下の要件が満たしかったため、少しハックして利用することにした。本記事ではそのスクリプトを掲載する。

  1. CDDB情報は自分で1度だけ入力
  2. CDDB情報はCueとして残す
  3. 音楽CDの音声データ全体を1つのファイルとしてFLACファイルにする
  4. トラック毎に分割した音声ファイルも生成する
  5. トラック毎の音声ファイルはFLAC, M4A, Opusエンコードを生成する
  6. 最後は作業ファイルを削除する

そのままの abcde では 3 と 4 を同時に処理できないため、abcde を2回実行するようにした。abcde 音声CDデバイスから音声ファイルを抽出する機能 (abcde -d /dev/cdrom のようにする) の他、その代わりに指定した FLAC ファイルから音声ファイルを読み出す機能 (abcde -d single.flac のようにする) があるため、前者を実行してから後者を実行すればよい。ただし、1回目の実行時のデータを残したまま2回目を実行しても、1回目の実行ログが邪魔して2回目の処理はスキップされてしまう。かと言って1回目の実行後、実行データを消去するようにすると、2回目でまたCDDB情報の入力を求められてしまい、これも面倒。そこで1回目の後、実行ログの一部を強引に書き換えて2回目を行うこととした。

abcde 設定ファイル

abcde の動作はコマンドラインオプションで制御可能だが、設定ファイルによっても変更することができる。設定ファイル名はデフォルトで ~/.abcde.conf が使われるが、今回は2個の設定ファイルを用意したため、1回目用を abcde.single.conf 、2回目用を abcde.tracks.conf とした。これらの設定ファイルは abcde 実行時に -c オプションで指定することができる。

各種ファイルの内容は以下の通り:

abcde.single.conf:

INTERACTIVE=y
ACTIONS=cddb,getalbumart,cue,read,encode,tag,move
CDROM=/dev/cdrom
OUTPUTDIR=/mnt
OUTPUTTYPE=flac
ONETRACKOUTPUTFORMAT='output'
EJECT=y

abcde.tracks.conf:

ACTIONS=cddb,cue,read,encode,tag,move,clean
OUTPUTDIR=/mnt
OUTPUTTYPE=flac,m4a,opus
OUTPUTFORMAT='${ARTISTFILE}/${ALBUMFILE}/${TRACKNUM} - ${TRACKFILE}'

各種設定項目についての説明は面倒臭いから割愛する。 デフォルトの設定は /etc/abcde.conf に書いてある。

abcde を2回実行するスクリプト

ripcd.sh を実行することで2回の abcde 実行を自動化した。また、先に述べた、1回目の実行ログを書き換える処理もこの中で行う:

#!/bin/sh

ABCDE=abcde
SINGLECONF=abcde.single.conf
TRACKSCONF=abcde.tracks.conf
WAV=/mnt/output.flac

help() {
    script=$(basename $0)
    cat <<EOF
Usage: $script [-f flac]
EOF
}

while [ $# != 0 ]; do
    case $1 in
        -f|--flac)
            WAV="$2"
            shift 2
            ;;
        *)
            help
            exit 1
    esac
done

CUE="$WAV".cue

ensure_requirements() {
    if [ ! $(which $ABCDE) ]; then
        echo "Error, $ABCDE needs to be installed."
        exit 1
    fi
}

artist_in_cue() {
    cue=$1
    artist=$(grep PERFORMER $cue | sed -e 's/PERFORMER "\(.*\)"$/\1/')
    echo $artist
}

title_in_cue() {
    cue=$1
    title=$(grep TITLE $cue | sed -e 's/TITLE "\(.*\)"$/\1/' | head -1)
    echo $title
}

ensure_requirements

if [ ! -f "$WAV" ]; then
    $ABCDE -1 -c abcde.single.conf
    if [ $? != 0 ]; then
        echo "Failed to ripping tracks."
        exit
    fi
fi

for f in $(ls abcde.*/status); do
    echo "Reset last status: $f"
    sed -i -e 's/onetrack//g' $f
    sed -i -e 's/.*track-01.*//g' $f
done

$ABCDE -c abcde.tracks.conf -d "$WAV"

if [ $? != 0 ]; then
    echo "Failed to create tracks."
    exit
fi

ARTIST=$(artist_in_cue "$CUE")
TITLE=$(title_in_cue "$CUE")

echo "Ripping done."
echo "    Artist: $ARTIST"
echo "    Title: $TITLE"

if [ -f "$CUE" ]; then
    NEWCUE=$(dirname $CUE)/"$ARTIST - $TITLE.cue"
    mv "$CUE" "$NEWCUE"
fi

NEWWAV=$(dirname "$WAV")/"$ARTIST - $TITLE.flac"
mv "$WAV" "$NEWWAV"

Docker 上で動作させる

さらに、PCの環境を清潔に保つため、Docker コンテナ上で動作するように作成した。 この手のメディア系のプログラムは多くのエンコーダライブラリ等が必要なため、素のOS環境上で実行しようとすると色々とインストールすることになり、作業環境が複雑になるため個人的に好まない。コンテナ様々である。

Dockerfile は以下:

FROM ubuntu:latest

VOLUME ["/mnt"]

ENV DEBIAN_FRONTEND=noninteractive
ENV EDITOR=vim
ENV LANG=C.UTF-8

RUN apt-get -y update
RUN apt-get install -y abcde mkcue flac fdkaac opus-tools eject vim

RUN groupadd -g 11 cdrom2
RUN groupadd -g 1000 user
RUN useradd -u 1000 -g user -G root,cdrom2 -d /home/user -m -s /bin/bash user
WORKDIR /home/user

COPY ripcd.sh .vimrc abcde.single.conf abcde.tracks.conf /home/user/
RUN chown user:user -R /home/user
RUN chmod u+x ripcd.sh

USER user

GID:11, 1000 や UID:1000 は必要に応じ各自ホスト側の環境に合わせる必要がある。 上記の Dockerfile では、ホストの普段使いのユーザーが UID:1000, GID:1000 であるとしている。また、/dev/cdrom のアクセス権限が GID:11 としている。

出力されるファイルが root パーミッションになっても気にしないのならば、RUN groupaddRUN useraddRUN chown user:userUSER userの行を削除すると簡単に動く。

Dockerコンテナ起動スクリプト

Dockerイメージのビルドとコンテナの起動もコマンド一発でできるよう、以下のスクリプトを用意した。

起動スクリプト:

fujii@fg-ryz ~/D/p/ripcd> cat start.sh 
#!/bin/sh

IMAGE=ripcd
REBUILD_IMAGE=0

help() {
    script=$0
    cat <<EOF
$script [-r]

Options:
    -r     Force rebuild docker image
EOF
}

while [ $# != 0 ]; do
    case $1 in
        -r)
            REBUILD_IMAGE=1
            shift
            ;;
        *)
            help
            exit 1
            ;;
    esac
done

if [ $(docker images | grep $IMAGE | wc -l) == 0 ]; then
    REBUILD_IMAGE=1
fi

if [ $REBUILD_IMAGE != 0 ]; then
    docker build -t ripcd .
    if [ $? != 0 ]; then
        echo "Failed build docker image."
        exit 1
    fi
fi

docker run -ti --rm \
       --device /dev/cdrom \
       -v $HOME/Music/rip:/mnt \
       ripcd ./ripcd.sh

実行例:

$ sh start.sh

参考