Excel VBAでファイル解析(MP3ファイル編)

2024-01-05

■MP3ファイルの概要

MP3(MPEG-1 Audio Layer-3)は音響データの圧縮に関する規格の1つで、MP3で圧縮された音声データを格納しているファイルの拡張子は「.mp3」です。
MP3本体の規格は難易度が高いため、本稿ではID3タグを中心に記載します。

(参考)日本規格協会のサイトで以下の規格書を購入可能ですが、価格は28,314円(税込み)です。

  • ISO/IEC 11172-3:1993
  • 情報技術-1,5 Mbit/s以下のデジタル記録媒体のための映画及び関連オーディオの符号化-第3部:オーディオ
  • Information technology — Coding of moving pictures and associated audio for digital storage media at up to about 1,5 Mbit/s — Part 3: Audio

ID3タグは、MP3ファイルの中にアーティスト・作成年・曲名等の付加的な情報を書き込むための規格ですが、v1とv2で規格の内容が大きく異なり、さらにv2の中にもv2.1、v2.2、v2.3、v2.4といったバージョンが存在します。
全てのバージョンに対応するのはなかなか大変なので、本稿ではv2.3とv2.4に限定したうえ、「アルバム名」「年」「トラック番号」「アーティスト名」「曲名」「添付画像」を取出すことに目的を絞って説明します。
⇒ID3タグの詳細はID3.orgのサイト(id3 v2.3.0、id3 v2.4.0)を参照して下さい。

ID3v2タグの詳細

ID3v2タグはMP3ファイルの先頭にあり、下表の通り、ID3v2ヘッダ、拡張ヘッダ、フレームデータから構成されています。
ID3v2ヘッダと拡張ヘッダは1つだけ存在しますが、フレームデータは複数存在し、フレームの種類によって格納されている内容が異なります。

ID3v2ヘッダ
拡張ヘッダ
フレームデータ
TALB(Album/Movie/Show title)
TYER(Year)
TRCK(Track number/Position in set)
TPE1(Lead artist(s)/Lead performer(s)/Soloist(s)/Performing group)
TIT2(Title/songname/content description)
APIC(Attached picture)

ID3v2ヘッダのフォーマット

ID3v2ヘッダは10バイト固定となっており、内容は下表の通りです。

オフセット 長さ 説明
0 3 マジックナンバー
(“ID3″固定)
3 2 バージョン
(v2.3:0300、v2.4:0400)
5 1 フラグ
(左から2ビット目が1の時、拡張ヘッダ有)
6 4 サイズ(※)
(ID3タグ全体の長さ – 10バイト)

(※)ID3タグの数値はビッグ・エンディアン(MSB(最上位バイト) first)で格納されていますが、v2.4ではSyncsafe Integerと呼ばれる「各バイトの下位7bit のみが有効となっている形式」になっているため、注意が必要です。
例えば、4バイトの「サイズ」を1バイトずつ取り出して計算する場合、v2.3とv2.4で下図のように計算方法が異なります。

  • (v2.3) サイズ = 1バイト目 * 16777216 + 2バイト目 * 65536 + 3バイト目 * 256 + 4バイト目
  • (v2.4) サイズ = 1バイト目 * 2097152 + 2バイト目 * 16384 + 3バイト目 * 128 + 4バイト目

拡張ヘッダのフォーマット

拡張ヘッダのフォーマットは、v2.3とv2.4で異なっており、内容は下表の通りです。

(拡張ヘッダ(v2.3))

オフセット 長さ 説明
0 4 この拡張ヘッダのサイズ
4 2 フラグ
6 4 パディング領域のサイズ
10 可変長 拡張ヘッダのデータ

(拡張ヘッダ(v2.4))

オフセット 長さ 説明
0 4 この拡張ヘッダのサイズ
4 1 フラグ長(常に1)
5 1 フラグ
6 可変長 拡張ヘッダのデータ

各フレームの共通フォーマット

各フレームは下表の形式になっており、「フレームID」「フレームサイズ」「フラグ」を合せてフレームヘッダと呼びます。
(フレームヘッダは10バイト固定です)

オフセット 長さ 説明
0 4 フレームID
(種別1バイト + ネーム3バイト)
4 4 フレームサイズ
(フレームデータ全体の長さ – 10バイト)
8 2 フレームヘッダフラグ
(1バイト目:ステータス、2バイト目:フォーマット)
10 可変長 フレームデータ
(フレームID毎に内容が異なる)

テキスト情報フレームのフォーマット

データをテキストで保有するフレーム(Text information frames)のフレームデータは、下表の形式になっています。
本稿で取り上げるフレームのうち、「アルバム名(TALB)」「年(TYER)」「トラック番号(TRCK)」「アーティスト名(TPE1)」「曲名(TIT2)」は、この形式です。

オフセット 長さ 説明
0 1 エンコーディング
00h:ISO-8859-1
01h:UTF-16/BOMあり
02h:UTF-16BE/BOMなし(id3v2.4)
03h:UTF-8(id3v2.4)
1 可変長 フレーム内容
(NULL終端テキスト)
終端文字は以下のいずれか
“00h"(ISO-8859-1,UTF-8)
“00h 00h"(UTF-16)

添付画像フレームのフォーマット

画像データを保有するフレーム(Attached picture frame)のフレームデータは、下表の形式になっています。
本稿で取り上げるフレームのうち、「添付画像(APIC)」は、この形式です。

オフセット 長さ 説明
0 1 Text encoding
1 可変長 MIME type(NULL終端テキスト)
可変 1 Picture type(下表参照)
可変 可変長 Description(NULL終端テキスト)
可変 可変長 Picture data(バイナリ・データ)

(Picture type)

内容
00 Other
01 32×32 pixels 'file icon'(PNG only)
02 Other file icon
03 Cover(front)
04 Cover(back)
05 Leaflet page
06 Media(e.g. lable side of CD)
07 Lead artist/lead performer/soloist
08 Artist/performer
09 Conductor
0A Band/Orchestra
0B Composer
0C Lyricist/text writer
0D Recording Location
0E During recording
0F During performance
10 Movie/video screen capture
11 A bright coloured fish
12 Illustration
13 Band/artist logotype
14 Publisher/Studio logotype

■MP3ファイルのID3タグ情報をExcelシートに表示する処理

MP3ファイルのID3タグ情報を読み込み、Excelシートに表示するプログラムです。
⇒サンプル・プログラムで使用している、Binary Fileクラスの詳細については、Excel VBAでファイル解析(事前準備編)を参照して下さい。

処理の概要

処理の流れは以下の通りです。
①Binary Fileオブジェクトをインスタンス化し、MP3ファイルを読み込み
②MP3ファイルのID3タグを先頭から順に解析し、必要な情報を取得してExcelシートにセット
③使用済のオブジェクトを破棄

サンプル・プログラム

行番号10でBinary Fileオブジェクトをインスタンス化し、行番号11でMP3ファイルを読み込んでいます。
行番号14~37はID3v2ヘッダの処理で、「ファイル識別子」「バージョン」「フラグ」「サイズ」を取得しています。
行番号39~51は拡張ヘッダの処理で、拡張ヘッダが存在した場合は読み飛ばしています。
行番号53~87はフレームデータの処理で、行番号65~69で「アルバム名」「アーティスト名」「曲名」、行番号71~75で「年」「トラック番号」、行番号77~83で「添付画像」のデータを取得し、行番号85でそれ以外のフレームを読み飛ばしています。
行番号81のGetDataNullメソッドで取得しているデータは、前掲した表の「MIME type」という項目ですが、実際には『image/jpeg』のような文字列が入っています。

(注)テキスト情報については、エンコードの値によって処理を分けるのが本来の姿ですが、このサンプル・プログラムでは「アルバム名」「アーティスト名」「曲名」をUTF-16、「年」「トラック番号」をISO-8859-1として処理しています。
「アルバム名」「アーティスト名」「曲名」がUTF-8で格納されている場合は、行番号69のGetDataUTF16メソッドをGetDataUTF8メソッドに置換えて下さい。

(補記)wcntはGetDataNullメソッドの引数に使用している変数ですが、行番号3で他の変数と一緒に定義しておいたところ、実行時にエラーが発生したため、行番号4で「Dim wcnt As Long」と定義したものです。

  1. Dim sht, bf As Object
  2. Dim wVer, wStr As String
  3. Dim wLoc, wID, wSize, wExtSize, wLen, i, lcnt As Long
  4. Dim wcnt As Long
  5. Dim wFlag As Byte
  6. Private Sub Sample1()
  7.     Set sht = ActiveSheet
  8.     sht.Cells.NumberFormatLocal = “@"
  9.     Set bf = New BinaryFile
  10.     bf.InputFile (“C:\work\xxx.mp3")
  11.     lcnt = 0
  12.     lcnt = lcnt + 1
  13.     sht.Cells(lcnt, 1) = bf.GetPositionHex()
  14.     sht.Cells(lcnt, 2) = “ファイル識別子"
  15.     sht.Cells(lcnt, 3) = bf.GetDataChar(3)
  16.     lcnt = lcnt + 1
  17.     sht.Cells(lcnt, 1) = bf.GetPositionHex()
  18.     sht.Cells(lcnt, 2) = “バージョン"
  19.     wVer = bf.GetDataHex(2)
  20.     sht.Cells(lcnt, 3) = wVer
  21.     lcnt = lcnt + 1
  22.     sht.Cells(lcnt, 1) = bf.GetPositionHex()
  23.     sht.Cells(lcnt, 2) = “フラグ"
  24.     wFlag = bf.GetData(1)
  25.     sht.Cells(lcnt, 3) = Right(“0" & Hex(wFlag), 2)
  26.     lcnt = lcnt + 1
  27.     sht.Cells(lcnt, 1) = bf.GetPositionHex()
  28.     sht.Cells(lcnt, 2) = “サイズ"
  29.     wStr = bf.GetDataHex(4)
  30.     sht.Cells(lcnt, 3) = wStr
  31.     If wVer = “0400" Then
  32.         wSize = CLng(“&H" & Mid(wStr, 1, 2)) * 2097152 + CLng(“&H" & Mid(wStr, 3, 2)) * 16384 + CLng(“&H" & Mid(wStr, 5, 2)) * 128 + CLng(“&H" & Mid(wStr, 7, 2))
  33.     Else
  34.         wSize = CLng(“&H" & Mid(wStr, 1, 2)) * 16777216 + CLng(“&H" & Mid(wStr, 3, 2)) * 65536 + CLng(“&H" & Mid(wStr, 5, 2)) * 256 + CLng(“&H" & Mid(wStr, 7, 2))
  35.     End If
  36.     If (wFlag And &H40) = &H40 Then
  37.         lcnt = lcnt + 1
  38.         sht.Cells(lcnt, 1) = bf.GetPositionHex()
  39.         sht.Cells(lcnt, 2) = “拡張ヘッダサイズ"
  40.         wStr = bf.GetDataHex(4)
  41.         sht.Cells(lcnt, 3) = wStr
  42.         If wVer = “0400" Then
  43.             wExtSize = CLng(“&H" & Mid(wStr, 1, 2)) * 2097152 + CLng(“&H" & Mid(wStr, 3, 2)) * 16384 + CLng(“&H" & Mid(wStr, 5, 2)) * 128 + CLng(“&H" & Mid(wStr, 7, 2))
  44.         Else
  45.             wExtSize = CLng(“&H" & Mid(wStr, 1, 2)) * 16777216 + CLng(“&H" & Mid(wStr, 3, 2)) * 65536 + CLng(“&H" & Mid(wStr, 5, 2)) * 256 + CLng(“&H" & Mid(wStr, 7, 2))
  46.         End If
  47.         bf.SkipData (wExtSize – 4)
  48.     End If
  49.     Do While bf.CurrentPosition < wSize + 10
  50.         wLoc = bf.GetPositionHex()
  51.         wID = bf.GetDataChar(4)
  52.         wStr = bf.GetDataHex(4)
  53.         If wVer = “0400" Then
  54.             wLen = CLng(“&H" & Mid(wStr, 1, 2)) * 2097152 + CLng(“&H" & Mid(wStr, 3, 2)) * 16384 + CLng(“&H" & Mid(wStr, 5, 2)) * 128 + CLng(“&H" & Mid(wStr, 7, 2))
  55.         Else
  56.             wLen = CLng(“&H" & Mid(wStr, 1, 2)) * 16777216 + CLng(“&H" & Mid(wStr, 3, 2)) * 65536 + CLng(“&H" & Mid(wStr, 5, 2)) * 256 + CLng(“&H" & Mid(wStr, 7, 2))
  57.         End If
  58.         bf.SkipData (2)
  59.         Select Case wID
  60.             Case “TALB", “TPE1", “TIT2"
  61.                 lcnt = lcnt + 1
  62.                 sht.Cells(lcnt, 1) = wLoc
  63.                 sht.Cells(lcnt, 2) = wID
  64.                 bf.SkipData (1)
  65.                 sht.Cells(lcnt, 3) = bf.GetDataUTF16(CLng(wLen) – 1)
  66.             Case “TYER", “TRCK"
  67.                 lcnt = lcnt + 1
  68.                 sht.Cells(lcnt, 1) = wLoc
  69.                 sht.Cells(lcnt, 2) = wID
  70.                 bf.SkipData (1)
  71.                 sht.Cells(lcnt, 3) = bf.GetDataChar(CLng(wLen) – 1)
  72.             Case “APIC"
  73.                 lcnt = lcnt + 1
  74.                 sht.Cells(lcnt, 1) = wLoc
  75.                 sht.Cells(lcnt, 2) = wID
  76.                 bf.SkipData (1)
  77.                 sht.Cells(lcnt, 3) = bf.GetDataNull(wcnt)
  78.                 sht.Cells(lcnt, 4) = bf.GetDataHex(1)
  79.                 bf.SkipData (CLng(wLen) – wcnt – 1)
  80.             Case Else
  81.                 bf.SkipData (CLng(wLen))
  82.         End Select
  83.     Loop
  84.     Set bf = Nothing
  85. End Sub

■MP3ファイルのID3タグ情報から画像データを抽出する処理

MP3ファイルのID3タグ情報を読み込み、画像データをファイルに出力するプログラムです。
⇒サンプル・プログラムで使用している、Binary Fileクラスの詳細については、Excel VBAでファイル解析(事前準備編)を参照して下さい。

処理の概要

処理の流れは以下の通りです。
①Binary Fileオブジェクトをインスタンス化し、MP3ファイルを読み込み
②MP3ファイルのID3タグを先頭から順に解析し、画像データを取得してファイルに出力
③使用済のオブジェクトを破棄

サンプル・プログラム

行番号9でBinary Fileオブジェクトをインスタンス化し、行番号10でMP3ファイルを読み込んでいます。
行番号13~21はID3v2ヘッダの処理で、「ファイル識別子」「バージョン」「フラグ」「サイズ」を取得しています。
行番号23~31は拡張ヘッダの処理で、拡張ヘッダが存在した場合は読み飛ばしています。
行番号33~51はフレームデータの処理で、行番号43~47で「添付画像」のフレームを処理し、行番号49で他のフレームを読み飛ばしています。
行番号46のTransferDataメソッドでバイナリ・データを出力エリアに転送し、行番号47のOutputFileメソッドでJPEGファイルを出力しています。

「添付画像」のフレーム(フレームID:APIC)の場合、規格上は「Picture Type」の後ろに「Description」を設定できますが、このサンプル・プログラムでは「Description」が存在しない前提で処理しています。

  1. Dim sht, bf As Object
  2. Dim wVer, wStr As String
  3. Dim wLoc, wID, wSize, wExtSize, wLen, wPos, i, lcnt As Long
  4. Dim wcnt As Long
  5. Dim wFlag As Byte
  6. Private Sub Sample2()
  7.     Set sht = ActiveSheet
  8.     Set bf = New BinaryFile
  9.     bf.InputFile (“C:\work\xxx.mp3")
  10.     lcnt = 0
  11.     wStr = bf.GetDataChar(3)
  12.     wVer = bf.GetDataHex(2)
  13.     wFlag = bf.GetData(1)
  14.     wStr = bf.GetDataHex(4)
  15.     If wVer = “0400" Then
  16.         wSize = CLng(“&H" & Mid(wStr, 1, 2)) * 2097152 + CLng(“&H" & Mid(wStr, 3, 2)) * 16384 + CLng(“&H" & Mid(wStr, 5, 2)) * 128 + CLng(“&H" & Mid(wStr, 7, 2))
  17.     Else
  18.         wSize = CLng(“&H" & Mid(wStr, 1, 2)) * 16777216 + CLng(“&H" & Mid(wStr, 3, 2)) * 65536 + CLng(“&H" & Mid(wStr, 5, 2)) * 256 + CLng(“&H" & Mid(wStr, 7, 2))
  19.     End If
  20.     If (wFlag And &H40) = &H40 Then
  21.         wStr = bf.GetDataHex(4)
  22.         If wVer = “0400" Then
  23.             wExtSize = CLng(“&H" & Mid(wStr, 1, 2)) * 2097152 + CLng(“&H" & Mid(wStr, 3, 2)) * 16384 + CLng(“&H" & Mid(wStr, 5, 2)) * 128 + CLng(“&H" & Mid(wStr, 7, 2))
  24.         Else
  25.             wExtSize = CLng(“&H" & Mid(wStr, 1, 2)) * 16777216 + CLng(“&H" & Mid(wStr, 3, 2)) * 65536 + CLng(“&H" & Mid(wStr, 5, 2)) * 256 + CLng(“&H" & Mid(wStr, 7, 2))
  26.         End If
  27.         bf.SkipData (wExtSize – 4)
  28.     End If
  29.     Do While bf.CurrentPosition < wSize + 10
  30.         wID = bf.GetDataChar(4)
  31.         wStr = bf.GetDataHex(4)
  32.         If wVer = “0400" Then
  33.             wLen = CLng(“&H" & Mid(wStr, 1, 2)) * 2097152 + CLng(“&H" & Mid(wStr, 3, 2)) * 16384 + CLng(“&H" & Mid(wStr, 5, 2)) * 128 + CLng(“&H" & Mid(wStr, 7, 2))
  34.         Else
  35.             wLen = CLng(“&H" & Mid(wStr, 1, 2)) * 16777216 + CLng(“&H" & Mid(wStr, 3, 2)) * 65536 + CLng(“&H" & Mid(wStr, 5, 2)) * 256 + CLng(“&H" & Mid(wStr, 7, 2))
  36.         End If
  37.         bf.SkipData (2)
  38.         If wID = “APIC" Then
  39.             bf.SkipData (1)
  40.             wStr = bf.GetDataNull(wcnt)
  41.             bf.SkipData (2)
  42.             bf.TransferData (wLen – wcnt – 2)
  43.             bf.OutputFile (“C:\work\xxx.jpg")
  44.         Else
  45.             bf.SkipData (CLng(wLen))
  46.         End If
  47.     Loop
  48.     Set bf = Nothing
  49. End Sub

 

国本温子(著),緑川吉行(著),できるシリーズ編集部(著)
出版社:インプレス
発売日:2022/3/23
単行本(ソフトカバー):A5判/912ページ

大村あつし(著),古川順平(著)
出版社:技術評論社
発売日:2021/1/9
単行本(ソフトカバー):A5判/800ページ

高橋宣成(著)
出版社:技術評論社
発売日:2019/11/25
単行本(ソフトカバー):B5変形判/576ページ

ファイル解析

Posted by hides