Wizard Notes

Python, JavaScript を使った音楽信号分析の技術録、作曲活動に関する雑記

Python: Mutagenで複数のAAC (.m4a) 音源からタグ・メタ情報を抽出

はじめに

音楽分析を行う時には、音響信号だけでなく、大量の音源からのメタデータの抽出・編集・読み込み・書き込みが必要となることがあります。

手動でメタデータを管理する場合、 Mp3tag のようなソフトウェアを使うのが楽ですが、大量の音源のメタデータを処理しようとすると手動では管理しづらいです

そこで、今回は Python の Mutagen を用いたメタデータの抽出方法を紹介します。

MP3 の抽出は Mutagen の Example にサンプルコードがあるため、この記事ではMutagen を使って AAC (.m4a) 音源からメタデータを抽出してみます。

f:id:Kurene:20191019155237p:plain
図1: メタデータの抽出

1. あるディレクトリの楽曲を全て捜索する

dirpath に音源が入ったディレクトリのパスを入れることで、そのディレクトリの中の全ての m4a 音源のパスを逐次的に読み込みます。

ext = "m4a"
dirpath = "music_data"
for filepath in glob.glob(f"{dirpath}/*.{ext}"):
    print(filepath)

2. Mutagen で楽曲のメタデータを抽出する

Mutagen を使います。

今回は AAC (.m4a) のみを対象としているため、mutagen.mp4.MP4 クラスを使います。

mutagen.mp4.MP4.infoフィールドには、ビットレートのようなコーデックに関する情報が含まれています。 mutagen.mp4.MP4.tags にはアーティスト情報のようなメタデータ辞書型で入っています。 各メタデータを抽出するキーについては、Mutagen のドキュメントを参考にしてください。今回は、よく使いそうなメタデータのみ利用しています。

import glob
from mutagen.mp4 import MP4

dirpath = "music_data"
ext = "m4a"
for filepath in glob.glob(f"{dirpath}/*.{ext}"):
    # Extract meta data
    # Refer to https://buildmedia.readthedocs.org/media/pdf/mutagen/latest/mutagen.pdf
    mp4 = MP4(filepath)
    track_title     = mp4.tags["\xa9nam"][0]
    album           = mp4.tags["\xa9alb"][0]
    artist          = mp4.tags["\xa9ART"][0]
    year            = mp4.tags["\xa9day"][0]
    #composer        = mp4.tags["\xa9wrt"][0]
    #grouping        = mp4.tags["\xa9grp"][0]
    #genre           = mp4.tags["\xa9gen"][0]
    bitrate         = mp4.info.bitrate
    length          = mp4.info.length
    channels        = mp4.info.channels
    sample_rate     = mp4.info.sample_rate
    bits_per_sample = mp4.info.bits_per_sample
    codec           = mp4.info.codec

3. pandas で表の作成+CSVを書き出す

Python でデータの処理をしている人にはお馴染みの pandas (Python Data Analysis Library) を使って、 メタデータを表にまとめ、CSVで書き出しています。

今回は、大量の楽曲を処理するときに列(メタデータ)ごとにデータを管理した方が嬉しいと考え、辞書型から dataframe を作っています。

import pandas as pd

header = ["artist", "album", "year"]
di = {header[0]: [11, 21], header[1]: [12, 22], header[2]: [13, 23]}
df = pd.DataFrame.from_dict(di)
df.to_csv("data.csv", header=header, index=False)

f:id:Kurene:20191019160231p:plain
図2: Pandasによる辞書型の表形式化・CSV書き出し

4. 1~3 をまとめる

# Preparation
ext = "m4a"
dirpath = "music_data"
tags_table = {"track_title": "\xa9nam", 
             "album": "\xa9alb",
             "artist":"\xa9ART", 
             "year": "\xa9day"
            }
tags_list = list(tags_table.keys()
info_list = ["bitrate", "length", "channels", 
             "sample_rate", "bits_per_sample", "codec"]
meta_list = tags_list + info_list
meta_di = {meta: [] for meta in meta_list}
filepath_list = glob.glob(f"{dirpath}/*.{ext}")

# Extract meta-tags for each audiofile
for filepath in filepath_list:
    mp4 = MP4(filepath)
    mp4_info_di = jsons.dump(mp4.info)
    for meta in meta_list:
        if meta in tags_list:
            val = mp4.tags.get(tags_table[meta], "KeyError")[0]
        else:
            val = mp4_info_di[meta]
        meta_di[meta].append(val)

# Make dataframe@pandas and write csv
df = pd.DataFrame.from_dict(meta_di)
df["filepath"] = filepath_list
df.to_csv("data.csv", header=meta_list+["filepath"], index=False, encoding='utf_8_sig')

補足

mutagen.mp4.MP4.tags は、音源によってはメタデータが存在せず KeyError となることがあります。従って、例外処理を入れてください。(例:KeyError の時はval ="<KeyError>"とする)また、Value がリストのため複数の値が入っていることもあります。