🫥

iTunes の ALAC を FLAC に変換する

2023/10/29に公開

https://zenn.dev/plesio/articles/aa2ef82431d6f6

この記事はシングルスレッドのスクリプトなので、
実用に耐えられるレベルのスクリプトが欲しい人は無視して上の続編をよんでくだしあ

Windows XP 位の時から、時にはOSを跨ぎながらも何代も渡り歩いてきた iTunes フォルダ。これの中にあるALACをピンポイントで抜いてFLACに変換する話です。

TL;DR

  1. iTunes Mediaのファイルサイズをクローンしても耐えられるディスクを用意する
  2. FFmpegをインストールしてPowerShellから呼べるようにする
  3. PowerShellのターミナルから自作の変換スクリプトを実行する

背景・動機

Xperia 5Vが登場したため、購入した。

MicroSDに対応しているため、iPod Classicを所有していたころに戻って、手持ちの音楽データをいっぱい持ち出そうと思ってiTunesのデータをXperiaにいくつか突っ込んでも、再生できない...
調べてみると、公式MUSICアプリにはALAC対応という文字がない。FLACなら対応している。

じゃあ、変換するしかないじゃんと思い、「そういう変換プログラムならごまんとあるだろ」と思って調べてみると、FLAC→ALACの記事ばっかりで、困ってしまった。
(あとMP3やAACが混在していると単純なアプリでのFLAC変換も面倒になった)

なので変換バッチを自作することにした。

愚痴

元々、Pixel 7aがぱっと見良さそうだったので、発売と同時に購入してたのだけれど。(わざわざXiaomi 11T Proを捨ててまで)
性能はそこそこなのは許容範囲だったが、スピーカー性能が貧弱すぎるうえ、カメラ音が気持ち悪くて、非機能要件周りがゴミクズすぎて、「早く何か別なAndroidにしなければ...!」と決意しなおした。
というか、Xiaomi 11T Pro が値段の割に非機能要件も良い感じに満たしてくれていて、強いて言えばサイズが一回りでかいこと、重量があること、DP Altに非対応なことくらいが不満くらいだったのだけれど、それと比較してしまったが故に、何もかもがダメダメに見えてしまった。

そうして、数ヶ月後、Pixel 8 (Pro) と、Xperia 5Vが出てきた。
Pixelはめっちゃ値上げしたうえに、相変わらず非機能要件周りは貧弱のように見え、一方でマルチメディアにも強いと謳うXperiaが非常に魅力的に見えた。結果それは正解だった。

――その一方、Xperiaは、OS/SWのサポート期間が短すぎるのは時代錯誤で非常に良くないので、SONYは早く方針転換をするべき。

今回のゴール

  1. アップルロスレスやWAVの音源を、片っ端から Xperia 5V で再生できる FLAC に変換する。
    • MP3やAACをFLACにすると非常にやっかいなので、その場合はスルーする処理も入れる。
  2. 変換した音源をMicroSDに突っ込んで、Xperia 5Vに認識させて再生する。

環境

  • Windows 11 / Desktop
    • ディスク容量は十分に大きなものを用意しておくこと
  • FFmpeg 6
  • PowerShell
    • PowerShell 7.3.8 を今回は使用。
      • Windows 11 デフォルト内蔵Verではないので注意。
  • 音源を利用する端末(e.g. Xperia 5V)
    • および、端末のデータストレージへアクセスする手段(今回はMicroSDに入れるのでUSB3.0対応のSDカードリーダーを用意することを推奨:理由は後述)

作業

FFmpeg のインストール

ダウンロードしてきても良いが、単純にChocolateyからインストールすることにする。

管理者権限状態のコンソール
choco install ffmpeg

正しくインストールが終われば、PowerShell で ffmpeg をたたけば何かしらでてくるはず。

iTunes に入れている音源のロケーション状態などの調査

まずは、iTunes Media ディレクトリがどこに格納されているか調べる。
私のは、物理的に別のドライブに格納することで、マシンを何台も渡り歩いてきたので、どこにあるか知っているが、デフォルトで引越しをしたことがない場合、iTunesの設定からパスを参照することができる。

ディレクトリに統合する設定になってない場合

音源の実態を別の場所に置いたままiTunesへ認識させて使うモードがあり、恐らくデフォルトでは有効になっている。
この場合、ドラッグアンドドロップで登録した音源がiTunesMedia内にないため、統合を実行して全てiTunes Mediaの中にまとめておかないと、今回の変換プログラムの対象にはならないため注意。

ディレクトリ構造を確認する

問題なければ、

アーティスト名>アルバム名>曲名ファイル

の構造になっているはず。
なんらかの理由でそうなってない場合は今回用意したプログラムは使えない。

特に、なんらかの理由で「不明なアーティスト」にごちゃまぜにされてしまっている場合、対策のしようがない。
登録時のメタデータがなかったり、アーティスト名がディレクトリ名に使えない名前になってる?とか、なんらかの理由でそこに突っ込まれるのだが、そのあたりの仕様に詳しくないので、割愛。

とはいえ、ある程度はアーティストフォルダで分類されているはずのため、一度この作業をやった後、個別にデータを取り出してフォルダを切りわけ→変換バッチをしかければ良いと思われる。

変換先のディレクトリを用意する

変換先のディレクトリを空で用意しておく。

後述の今回用意したサンプルは、重複したらスキップor上書きかを指定するするオプションだとかをつけていないコードになっているため
2回目以降実行するときは一度ディレクトリごと削除しないとならない。すまない。

変換プログラムを用意

仕様は以下の通り

  • アーティスト名で処理するか絞る。
  • ALAC or WAV (拡張子で判断) が来たら、FLAC変換する。
    • 未来の自分に良かれと思ってWAVに対応したのは失敗だった(理由は後述)
  • それ以外の形式が来た場合、スルーしてコピーだけする。
    • 想定ではAACかMP3しか違う拡張子が入ってないはずなので!

コード

以下のプログラムを、例えば「convert.ps1」というファイル名で用意する。
また、以下の変数は、各環境ごとに書き換えること

  • srcDir
  • dstDir
  • allowedArtists
    • 変換 or コピーを許容するフォルダを制限するために使う。
    • 聞かない or 持ち出せない音源が入ってたりするので!!
      • 決して昔好きだったけど今クソがつくほど嫌いなアーティストの話をしているわけじゃない。
convert.ps1
# アーティスト名のリスト
$allowedArtists = @(
"@Plesio_'s Mastery Puppetz",
"BOaT", 
...
)
# 元のフォルダと格納先のフォルダを指定
$srcDir = "E:\MUSIC\iTunes Media\Music"
$dstDir = "E:\TO_XPERIA_FLAC"

# ソースディレクトリ内のファイルを再帰的に取得
$files = Get-ChildItem -Path $srcDir -File -Recurse

# ファイルごとに処理
foreach ($file in $files) {
    # ファイルの拡張子を取得
    $extension = $file.Extension.ToLower()

    # ファイルの親ディレクトリを取得
    $fileParentDir = [System.IO.Path]::GetDirectoryName($file.FullName)

    # アルバムの親ディレクトリを取得
    $albumParentDir = [System.IO.Path]::GetDirectoryName($fileParentDir)

    # アルバムの親ディレクトリからアーティスト名を抽出
    $artist = (Split-Path -Path $albumParentDir -Leaf)

    if (-not ($allowedArtists -contains $artist)){
        continue
    }

    if ($extension -eq ".m4a" -or $extension -eq ".wav") {
        # 拡張子が.m4aまたは.wavの場合、変換処理を実行
        $dstFilePath = $file.FullName.Replace($srcDir, $dstDir) -replace [regex]::Escape($extension), ".flac"
        $dstDirPath = [System.IO.Path]::GetDirectoryName($dstFilePath)

        # 出力ディレクトリが存在しない場合、作成
        if (-not (Test-Path -Path $dstDirPath)) {
            New-Item -Path $dstDirPath -ItemType Directory
        }

        # ffmpegコマンドで変換
        $ffmpegCommand = "ffmpeg -i `"$($file.FullName)`" -acodec flac -vcodec copy `"$dstFilePath`""
        Invoke-Expression $ffmpegCommand
    } else {
        # それ以外の場合、単にコピー
        $dstFilePath = $file.FullName.Replace($srcDir, $dstDir)
        $dstDirPath = [System.IO.Path]::GetDirectoryName($dstFilePath)

        # 出力ディレクトリが存在しない場合、作成
        if (-not (Test-Path -Path $dstDirPath)) {
            New-Item -Path $dstDirPath -ItemType Directory
        }

        Copy-Item -Path $file.FullName -Destination $dstFilePath
    }
}

Write-Host "処理が完了しました。"

たいしたコードじゃないので、各自好きにいじってください。
(というかChatGPTにPowerShellの分岐処理の大枠を作らせて、細かいFFmpegやコピー周りを自作で調整した程度です。関数名からなにやってるかはだいたい想像がつきますが、じゃあ具体的にどのコードが何をしているのか答えろと言われてもそれは答えられないです... ChatGPTに聞いてやってください。)

変換処理の実行

あとは、PowerShellのターミナルを開いて、変換処理をかけていくだけ。

.\convert.ps1

大分気長に待つこと。

ファイル数が300GB近かったため、私は14時間待たされた。

マシンのCPU Coreが10くらいあるので、頑張れば並列くらい余裕のはずだし、FFmpeg実行周りは、並列処理にしておけばもっと早く終わった。
PowerShell でそういうコードが組めるほど精通してないので、そんなことできるかよくわかってないけど。

結果のコピー

あとは、単純に変換結果をXperia 5VのMicroSDにコピーする。
――のだが、横着して、Xperia 5VにUSB接続してそれ経由でコピーしたら、USB2.0相当の速度しかでないわ、予定完了時間12時間後とか出るわ、10分くらいで接続が瞬断してコピーがなかったことになるわで1日溶けた。

絶対に MicroSD or SDカードリーダーを使うこと!!
それでも予定完了時間が2時間くらいかかる。結構、お高めのスペック買っても性能的にはUSB3.0のフルスピードが出ないのはそりゃあそうという話(12時間よりはマシ)

終わったら、Xperia 5V上のMUSICアプリを起動してSD領域の音源を表示・再生できていれば完成。

あ、WAVってタグないじゃん!!!

全て終わってから、WAVファイルにタグがないから、不明なアーティストの音源と化していることに気づいた。
WAVを変換した場合は、アーティスト名、アルバム名を変数にFLACタグを編集する必要があったのだ・・・
(どれだけのWAVが無のFLACになったことか・・・・

終わりに

同じことに困っている人がいたら、実装の参考になればと思います。

今回は、ディレクトリ構造などを意識したり、ALAC/WAV以外を弾いたりすることが必要だった関係で、世の中のオーディオコンバーター系のアプリを頼れなかっただけで、本当に手持ちがALACだけなら、オーディオコンバーターを使った方が並列処理とか良い感じでもっと早く終わります。

非可逆圧縮同士の変換なので、音質劣化はあまり考えにくいですが、そのあたりの精度がどこまで信用できるのか、についてはまた別のお話かなと思います。

もう少し踏み込んで、iTunes側のメタデータを解析して、音源のロケーションとか(Wavなど音源側に付与できない系の)タグデータを取り出しつつ処理するプログラム書いてGUI付きexeを作るとか?良いのかもしれない。

とりあえず、再生できたからヨシ

Discussion