Music.app (iTunes) が MP3 ファイルを最後まで再生できずに勝手にスキップしていくバグをなんとかする

結論から書きます (2023/12/13 更新):

  • 掲題のようなバグが Music.app (旧 iTunes) にあると思っています。記事を最初に執筆した2019年から、最終更新時点でも筆者の環境で一貫して再現しています
    • macOS Sonoma 14.2, Music.app 1.4.2
    • 記事執筆時点から今に至るまで、定期的に Music.app に MP3 ファイルを取り込んでおり、その度に挙動を確認しています
  • おそらく、MP3 ファイルを複数同時にインポートしたときのギャップレス再生用の情報を計算するあたりの処理に不具合があり、確率的にデタラメなギャップが記録されてしまい、そのときにインポートした MP3 の曲がめちゃくちゃ早く終わる扱いになってしまう、というようなことが起こっていそうです
  • 回避策は……
    • 新たに MP3 ファイルをインポートするときは、複数同時にインポートしない。インポートするごとに、ギャップレス再生用の情報の計算が終了するまで待ってからインポートする
    • 既存の曲については https://github.com/megabulk/Fix-for-iTunes-file-truncation にある Apple Script を用いてなんとかする
      • これを実行すると唯一 date added (Music.app にこのファイルを取り込んだ日付) のメタデータが消失します。これを保持したければ、Mac のシステム時刻をいじったうえでこれを実行したりしましょう (最悪)

インポートするごとに、ギャップレス再生用の情報の計算が終了するまで待ってからインポートする……ってめんどくさすぎないか、と思うわけですが、パソコンオタク向け情報としては、インポートしたい MP3 ファイルを入れたフォルダで

find . -type f -name '*.mp3' -exec open -a Music {} \; -exec sleep 30 \;

みたいなコマンドを実行することでお茶を濁して欲しい……。

以下は経緯。


このバグに何年も悩まされている気がするけど、ようやくだいぶマシな回避策を見つけられて嬉しい 意外とあんまり解決してない!!!!!!、という話です。どういうバグかというと、

  • 一部の MP3 ファイルが最後まで再生できない。5分とかある曲でも、3:01 とか、2:39 あたりで最後まで再生されたことになって (?) 否応なしに次の曲の再生が始まってしまう
    • iTunes の再生時間を変更できる設定とはまったく関係なく発生する
    • たぶん取り込み時のなんらか処理がぶっ壊れていて、一度そういうものとして取り込まれてしまったファイルは常にこのような挙動でしか再生されない
    • 最後まで再生されたことになる地点は、ファイルごとに固有? であり、常にその地点で最後まで再生されたことになる
      • 手動でその地点より先までシークすると、そこから先は本当に最後まで再生できる。その地点を通過しようとするときになんかおかしくなる、という雰囲気
    • iPhone などにその曲を同期してもこの壊れ方は引き継がれる
      • ビットレートが指定よりも高ければこのビットレートの AAC に変換する、的な機能を有効にしていると、最初からそのぶっ壊れた地点までの AAC ファイルが iPhone に転送されてくる (3:01 とか 2:39 とかの AAC ファイルが iPhone に同期される)
        • 同期時に iTunes 内で変換してるときにやはりおかしくなっているっぽい
    • この症状が起こる MP3 ファイルは、iTunes 以外のあらゆるソフトウェアでは普通に最後まで再生できる
      • Traktor, rekordbox, VLC Media Player, ffplay (ffmpeg), ブラウザの audio タグとかで試した
      • 同じデコーダを使ってるのではないかという気がする QuickTime でも最後まで再生できる!!!
    • メタデータとかの雰囲気はあまり関係なさそうで、問題が起こるファイルの ID3 タグを全部剥ぎ取った状態で iTunes に取り込んでみても再現することがあった気がする
    • なぜなのかは全然わからないけど、Beatport で買った MP3 ファイルでは高確率で再現する

当然というかなんというか、英語圏でもこのバグは普通に起こっていて、Apple のフォーラムとかで無限に質問されている。"iTunes music cut off" とか、"iTunes song skips too early" とかでググるとこういうのをひたすら見ることができる。

これといった解決策はあんまり存在しないと思っていて、ライブラリファイルを再構築したらよいという説もあるけど、それをやると最初に曲をライブラリに追加した日時が全部吹っ飛んでしまうのでなるべくやりたくない。もっとも雑に回避するには、別のところで MP3 ファイルを AAC とかに変換してから取り込むとよいんだけど、本来必要なかった再エンコードで微妙に音質は悪くなるはずだし、MP3 から AAC にメタデータを完璧にマッピングするというのは全然自明なことではないのでとにかくこれもやらなくて済むならそれに越したことはない。

で、無駄に消耗しまくってたんだけど、ついにかなりマシな解決策を見つけた。これ。

github.com

このレポジトリに含まれる Fix Truncated Tracks.scpt を、ぶっ壊れた曲を iTunes で選択した状態で実行するとよい (Catalina だと 6 行目を contains "iTunes" then から contains "Music" then に書き換える必要がある *1 )。なんでこれで治るのかはさっぱりわからん……。

注意点としては、

  • 最初に曲をライブラリに追加した日時 は吹っ飛ぶ
    • ライブラリ全部のそれが吹っ飛ぶよりは2億倍マシなので許容できる
  • プレイリストに追加されていた情報も吹っ飛んでいる気がする
    • 一旦曲を消して、再びライブラリに追加したあとに、もともと追加されていたプレイリストの末尾に入れ直す、ということをやっているように見えるけど、なんかちゃんと動いてない?

何もわからない…… これでずっと治ればいいんだけど。


追記 (2020-01-06)

なんか ↑ の方法で微妙に治ってない気がする!!!!!! で更にまた調べてたけど、ギャップレス再生の時間を決めてるところがぶっ壊れてるのではないかという話をしてる人がいた。疲れる…………

Song playback cut off early - Apple Community


こういう感じだと行ける気がする (本当に最悪)

  1. MP3 ファイル (α) をどこかにバックアップし、もとのライブラリのディレクトリからはファイルを完全に消す
  2. バックアップした MP3 ファイルを AIFF にエンコードし (β)、さらにそれに Kid3 とかでメタデータをコピーする
  3. 消したファイルの曲を Music.app で再生し、曲が見つかりません的なダイアログから 再配置 → 2. で生成した AIFF ファイル (β) を指定し、MP3 (α) が AIFF (β) に入れ替わった的な状態を作り出す
  4. バックアップしておいた MP3 ファイル (α) について、さらにバックアップを作り、Kid3 で以下のような作業を施す:
    1. メタデータ (ID3v2 タグ) をコピーする
    2. メタデータを全部消して一旦保存
    3. コピーしておいたメタデータをペーストし、また保存
    4. メタデータを Kid3 で一度書き直した的な MP3 ファイル (γ) が出来上がる
  5. AIFF ファイル (β) を削除し、また削除したファイルの曲を再生、再配置ダイアログで MP3 ファイル (γ) を指定する
  6. おわり
    • MP3 ファイルは (α) から (γ) に入れ替わっているが、Kid3 は自分が保持したいメタデータのタグをたぶん完全に取り扱えているので、事実上ファイルのメタデータタグの欠損は起こっていない
    • 最初から最後まで一貫して、ライブラリ上から曲を削除はしていない (実体であるファイルを消しているだけ) なので、Persistent ID や Date Added のような Music.app 外から操作しようがない Music.app 内のメタデータや、プレイリストへの追加状態も完全に保持される
    • MP3 ファイル (α) と (γ) の音声ストリーム部分はまったく同一であるはずなので、音質の劣化も発生しないはず

めっちゃ頑張れば自動化できる気がするけど API 用意されてる AppleScript だけじゃなくて UI 操作自動化的なやつをやらないといけない気がする?それともこういうのとシェルスクリプトをうまく組み合わせたらなんとかなるのか……?

macos - Changing the path to a file in iTunes with AppleScript - Stack Overflow

あとここまでやっても iOS デバイスに同期して反映されるのかは結構微妙っぽくて、一旦同期済みのファイルをふっとばしてから再同期させたりするひつようがある……?

*1:scpt ファイルは微妙にプレーンテキストじゃないので p-r とか送ってもなという感じがする、、