【ダウンロード可】MP3(ID3)タグ編集プログラムを作ってみた(C#ソースコード、Taglibの使い方も解説)

当ページのリンクには広告が含まれています。

MP3タグ(ID3)の編集が面倒くさいと思ったことはありませんか?

そこでTagLibというフリーのライブラリを使って、自分の好きなようにMP3タグ編集できるツールを作りました。

この記事では、ツールの紹介、Taglibの使い方をプログラミング初心者に向けてコード付きで解説しています。

プログラミングの勉強としてではなく、単にツールとしてご利用になりたい方は自由に使っていただいて結構ですが、あくまでも自己責任でお願いします。

実際の利用に際しては、必ずオリジナルのMP3をバックアップしておくことをお忘れなく。

目次

実行ファイルのダウンロードと使い方

実際の実行ファイルは下記からダウンロードできます。

ZIPファイルで圧縮していますので、任意のフォルダに解凍後、Mp3TagEditor.exe を実行して下さい。

実際に操作しながら読み進めて頂くと、より理解しやすいかと思います。

尚、動作確認で用いるMP3ファイルは、ファイル名やタグが書き変わっても良いものをご用意ください。

画面レイアウト

次回の記事に掲載されているソースコードを読むときの前提知識となりますので、一通りの使い方は理解しておいて下さい。

まず画面レイアウトは次の通りです。

基本操作

MP3のあるフォルダ、又はMP3ファイルを一覧部分に直接ドラッグ&ドロップすることで、ファイル名(拡張子は省略)とMP3タグが表示されます。

フォルダの下にサブフォルダが有る場合、そのサブフォルダも含めた全てのMP3ファイルが表示されます。

基本操作としては

  1. 一覧部分に表示されている内容に対して、「絞り込み条件」で絞り込みを行う
  2. 対象項目に対してフォーマットに記載したルールで文字列を書き込むか、文字列の置換を行う
  3. タグ更新ボタンをクリックして編集内容をMP3ファイルに適用する

の3ステップになります。

絞り込み検索

絞り込み検索は「簡易」と「詳細」の2つのモードがあり、起動時は「簡易」にチェックが入っています。

「簡易」にチェックが入っている場合、項目名(列名)とキーワードを入力することで、その項目にキーワードが含まれている行だけ絞り込みを行います。

画面の例では ”アーティスト いきものがかり” と入力されていますので、アーテイスト列に ”いきものがかり” というキーワードが含まれている行が絞り込まれます。

複数項目を指定したい場合、”アーティスト いきものがかり タイトル よ “ とすると、アーティストに ”いきものがかり” が含まれていて、さらに タイトルに ”よ” の文字が含まれている行が絞り込まれます。

「簡易」のチェックが外れている場合、DataGridView に指定できる絞り込み条件の記述方法が利用できます。

例えば、アーティストが ”いきものがかり” で、タイトルが ”心” 以外から始まる行を絞り込みたい場合、 ”アーティスト = ‘いきものがかり’ and タイトル not like ‘心%’ ” という記述が出来ます。

詳しくは、こちら をご参照ください。

フォーマットを使った文字列のセット

対象項目のコンボボックスで選んだ項目に対して、指定したフォーマットの文字列をセットします。

フォーマットには、固定文字列の他に任意のタグ名や連番を指定できます。

画面の例では “{連番}.{アルバム名}_{アーティスト}” と記載されていますが、仮にアルバム名が ”いきものばかり ~メンバーズBESTセレクション” だとすると、次のようになります。

01.いきものばかり ~メンバーズBESTセレクション~_いきものがかり

また、連番部分のフォーマットは、連番書式で指定することが可能です。

画面の例では “0#” になっていますので、2桁で先頭を0で埋める指定になっています。

もし3桁で0埋めをしない場合、 “###” という指定ができます。

単純置換と正規表現による置換

対象項目に対して「置換」をしたい場合、置換前の文字列と置換後の文字列を指定します。

「置換」には「正規表現」と「単純」の2モードがあり、初期値は「正規表現」モードになっています。

正規表現はすこし分かり難いので、こちら のサイトを参考にして頂ければと思います。

画面の例では “^.*?[-. ]” となっていますが、これは「先頭から数えて最初にハイフンかピリオドか半角スペースのいずれかが見つかるまで」という指定になります。

置換後の入力欄は未入力になっていますので、「上記の指定に一致する部分を消去する」という動作になります。

これは何をしているかというと、例えばファイル名などの先頭に連番が振られている場合、連番部分だけ抹消するという動作になります。

「正規表現」のチェックを外すと「単純」モードになりますが、こちらは単に置換前文字列を置換後文字列に置換するというものです。

ソースコード(プロジェクト)一式のダウンロードと解説

プロジェクト一式(TagLib含む)は下記からダウンロードが可能です。

プロジェクトを任意のフォルダに解答の上、Mp3TagEditor.sln をダブルクリックするとVisual Studio 2019 が立ち上がり、ソースコードが表示されると思います。

もしTagLibの参照でエラーになるようなら、一旦TagLibをアンインストールの上、再度NuGetからインストールすることで解決します。

ここからは、ダウンロードして頂いたソースコードに対するカスタマイズや、皆さんのソースコードへの流用のヒントになるような観点で、ポイントを解説していきます。

コンストラクタとフォームロード処理

コンストラクタにはドロップダウンをMainFormの表示位置を設定するコードを書いています。

これらはVisual Studio のプロパティでも設定することが出来ますので、好みに合わせてもらえればOKです。

フォームロード(MainForm_Load)も

という記述がありますが、これらはコンストラクタに記述しても良いですし、 Visual Studio のプロパティを設定しても構いません。

フォームロードはコンストラクタの後に呼び出されるイベントで、画面が表示されるタイミングで呼び出されますので、

this.StartPosition = FormStartPosition.CenterScreen;

だけはフォームロードの前(つまりコンストラクタが実行される時)に設定しておく必要があります。

フォームロードでは、DataGridViewにドラッグ&ドロップの受付と行番号の表示に対応させるため、次の2行のコードを記述しています。

これらは他のプログラムで再利用しやすいように、メソッド化しています。

SetDragDropメソッド

任意のコントロールにドラッグ&ドロップの機能を付加するメソッドで、DataGridViewを指定しています(17行目と20行目)。

DataGridViewに対してDragEnterとDragDropのイベントハンドラを作成する書き方も多いですが、再利用を考えてメソッドの中でイベントハンドラを追加するようにしました。

SetLineNumberメソッド

DataGridViewに行番号を付加する部分です。

これはGoogle検索で見つかったソースコードをそのまま掲載しています。

少し改造すると行番号の色を変えたり、別のセルに別の文字列を表示することも出来そうですが、単に行番号を表示したいというだけなら、このまま利用できます。

ShowDataメソッド

これはDataGridViewの体裁を整えつつ、DataTableの内容を表示するメソッドです。

引数に表示したDataTableを渡す仕様になっていて、8行目にDataGridViewのDataSourceプロパティに引数を代入しています。

これは8行目である必要はなく、メソッドの先頭に記述しても構いません。

ただ、列幅や列のReadOnly属性、列の入れ替え許可などの設定は、列が存在しないと出来ません。

逆に言うと、DataSourceにDataTableを代入した時点で新たな列が作られるため、その列に対して設定する必要があるので、ここだけは順番を気にする必要があります。

また、列幅やReadOnlyは設定したい値を配列に持たせて、Enumerable.Range を使ってuxMp3List.Columns[i] に代入していますが、これは好みの問題です。

以下の様に全ての列に対して、インデックス番号や列名を使って値を代入する方法もあります。

分かりやすさを優先するなら列名を使って個々の列を設定する方法が良いと思いますが、ソースコードの行数が長くなるので今回は採用しませんでした。

CreateDataTableメソッド

これはuxMp3List に表示するDataTableを作るためだけのメソッドです。

ShowDataメソッドで列幅を設定した時のように、列名を配列にしてEnumerable.Rangeで列を追加していく方法も出来ますが、別のソースコードに(列名を書き換えて)流用する際、Columnsの第2引数に変数の型を指定したい場合もあるため、今回はこのようにしました。

DataTableを作る部分をわざわざメソッドにしている理由は、フォームロードとドラッグ&ドロップの2か所で呼び出す必要があるからです。

プログラム起動時、uxMp3List に何も表示されないと寂しいので、せめて列名だけでも表示させたいと考えた時、フォームロードにも同じことを記述する必要が生じます。

それを避けるためメソッド化しました。

GetMp3Tagメソッド

SetDragDropメソッドの中で呼ばれていますが、ドラッグ&ドロップで受け取ったファイル名のMP3タグを読み出し、DataTableに格納して返すメソッドです。

最初にCreateDataTableメソッドでDataTableを作成しています。

次に、引数として渡されたファイル名の配列からファイル名を取り出し、 filelist に追加しています。

何故 filelist に追加しているかと言うと、渡されたファイル名が実はフォルダだった場合、そのフォルダ以下のファイルを全て取り出したかったからです。

その為、渡されたファイル名がフォルダか否かをチェックし、フォルダだったら配下のファイルを全て取り出して filelist に追加しています。

こうやってドラッグ&ドロップで渡されたファイルを全て取り出し、ループ処理にて1ファイルずつMP3タグを抽出、DataTableに追加しています。

メソッドの最後(リターンの直前)にAcceptChangesメソッドを読んでいます。

DataTableの各行(DataRow)はステータス(RowStat)を持っていて、その行が追加(Added)されたのか、変更(Modified)されたが分かるようになっています。

後にMP3ファイルに編集内容を書き戻す時、タグを編集したものだけを特定する際にRowStateが使えそうですが、そこには少しだけ工夫が必要です。

直前のforeach ループでMP3タグをDataTableに追加した訳ですから、今の RowState は追加状態(Added)になっています。

この状態でDataRowに変更を加えても、RowStat は Addedが優先されてModifiedにはならないのです。

このRowStateをリセットするメソッドが AcceptChanges であり、このメソッドを呼ぶことでDataTableに登録されている全てのDataRowのRowStateが リセット(Unchanged)されます。

こうすることで、以降このDataTableに対して変更を加えると、RowState が Modified になってくれます。

SetMp3Tag

引数で渡されたDataTableの内容(タグ情報)をMP3ファイルに書き込むメソッドです。

ポイントとしては、 foreach でループしながら DataRow を取り出し、RowStateが変更状態(Modified)である場合のみ、MP3ファイルにタグを書き戻すようにしている点です。

実際のMP3ファイルにタグを書き戻すには、Save メソッドを呼ぶだけで完了します。

タグを書き戻した次の処理は、ファイル名の変更処理です。

1列目のタイトル列と、最終列のファイルパスの内容を比較して、違っていたらタイトル列の内容でファイル名を変更しています。

ファイル名の変更はMoveメソッドを使います。

Moveメソッドはファイルの移動を行うメソッドですが、フォルダを同じにしておけば、ファイル名の変更になります。

変更後のファイル名を作るため、現在のフルパスからディレクトリ(フォルダ)と拡張子を取り出しているので、少々ややこしい記述になっています。

UTF2Jisメソッド

文字コードがShift-JISか否かを判定し、Shift-JISでなければ Shift-JISに変換するメソッドです。

MP3タグのタイトル、アーティスト名、アルバム名、コメントなどは日本語が登録できるのですが、MP3タグにもバージョンがあって、SHIFT-JIS で入っていたりUTF16で入っていたりと統一されていません。

これに対応するため、SHIFT-JISか否かを判定し、SHIFT-JIS でなければ SHIFT-JIS に文字コードを変換するようにしています。

具体的には、文字コードを一旦バイトの配列に変換して、再び SHIFT-JIS に変換し直した結果と、元々の文字列を比較しています。

もし元々の文字列がSHIFT-JISなら元に戻るはずなので、この方法で元に戻らなければ少なくともSHIFT-JISではなかったと判断できます。

もしSHIFT-JISでないと判断した場合、UNICODE から 一旦バイト配列に変換後、SHIFT-JIS に変換し直すという手順を踏むわけですが、バイト配列に変換すると1バイトごとに0x00 が付加されてしまいます。

このままだとSHIFT-JIS に正しく変換できないので、苦肉の策で 0x00を取り除く処理を入れています。

約1000ファイルの様々なMP3ファイルで試したところ、有名どころのフリーのMP3タグと同じ結果が得られたので、多分これで問題無いと判断しました。

フィルター実行ボタンイベントハンドラ

絞り込み処理は、簡易モード(uxIsEasy)にチェックが入っている場合、入力された文字から絞り込み条件を作る処理を行い、チェックが入っていなければ、入力された文字をそのまま絞り込み条件として使っています。

DataTableには DefaulView クラスがプロパティとして公開されており、RowFilterプロパティに条件を入れることで、DataTableの中身を絞り込んでくれます。

DataGridVIew(uxMp3List)のDataSource には DataTable が入っていますが、DataSourceはオブジェクト型なので、型変換を行ってDefaultViewのプロパティにアクセスしています。

簡易モードの時は、半角又は全角で分割し、「列名1」、「値1」、「列名2」、「値2」・・・という前提で2個ずつ取り出し、曖昧検索になるような条件式を作り出しています。

置換ボタン

ここは大きく2つの処理に分かれています。

1つは、フォーマット(uxFormat)の中身を展開しながら指定された列の全ての行に値をセットしていく処理、もう1つは入力されたフォーマットをドロップダウンリストに登録する処理です。

まず、指定された列の全ての行に値をセットしている処理を見てみましょう。

ここでは、DataGridView から 行(DataGridViewRow)を順番に取り出し、{列名} の文字列を、その列の値で置き換えているだけです。

ちなみに、DataGirdViewRowではなく、DataSourceからDataTableを取り出して、DataRowに対して変更を加えても良いのですが、DataGridViewのヘッダをクリックしてソートが行われると、DataGridViewとDataTableの行の並びが一致しなくなるので、ここではあえてDataGirdViewRowを使っています。

replace はこのメソッドの中で使うローカル関数です。

では、ローカル関数の中身を見ていきましょう。

第1引数はDataGridViewの列を保持しているコレクションクラス、第2引数は DataGridViewRow、第3引数は文字列ですが、ここは uxFormat.Text の値がセットされています。

そして、全ての列に対して以下の3ステップの処理を行うというのが、このローカル関数の役割になります。

  • DataGridViewColumnCollection から列名を取り出して前後を “{“、 “}” で挟み、置換前の文字列を作る
  • 次に、DataGridViewRow から 列名でセルを特定し、そのセルの値から置換後の文字列を作る
  • 第3引数で渡された文字列(uxFormat.Textの値)に対して、Replaceメソッドを使って文字列置換を行う

次はドロップダウンリストへの登録処理を見ていきましょう。

uxFormat.Text の値がドロップダウンリストに含まれているかを確認し、含まれていれば一旦削除してから、ドロップダウンの先頭に挿入しています。

こうすることにより、最新のフォーマット(最後に入力された uxFormat.Textの内容)が常にドロップダウンの先頭に来るようにしています。

文字列置換の実行イベントハンドラ

正規表現チェックボックス(uxUseRegular.Checked)にチェックが入っていると正規表現を使った文字列置換を行い、チェックが無ければ単純な文字列置換を行っています。

格安MP3プレーヤーの中には、曲の再生順がファイル名のソート順というケースがあります。

この場合、ファイル名の先頭に連番を付ける事が多いのですが、付けるのは簡単ですが、抹消するのは少々厄介です。

というのは、連番と曲名の間がピリオドだったりアンダーバーだったり、半角スペースだったりする可能性がありますし、桁も1桁~3桁混在していたり、先頭に0が付加されていたりと様々なパターンが考えられます。

これらのパターンに対応するには、正規表現を使うのが一番手っ取り早いのです。

ただ、正規表現はとっつき難く、複雑な条件を書くのは難易度が高いのが難点です。

でも、簡単な条件であれば少し勉強すれば使える様になりますし、使えると何かと便利なので、ここで少しだけ使ってみることにしました。

ちなみに、ここでも DataTable ではなく、DataGridViewに対して文字列置換を行っています。

フォームロード処理のところで、以下の様に初期値を設定しています。

最初の ‘^’ は、先頭を表しています。

次に ピリオド ‘.’ がありますが、これは任意の1文字を表し、アスタリスク ’*’ は直前の文字が0個以上繰り返し、はてな ‘?’ は直前の文字が0か1回あるという意味になります。

”[ -. ]” は、ハイフンかピリオドか半角スペースのいずれかという意味になります。

つまり、「先頭から数えて、任意の文字が1個以上連続で続いていて、ハイフンかピリオドか半角スペースのいずれかが1つ登場するまで」という意味になります。

 もし ‘?’ を抜いて “^.*[-. ]” と書くと、「任意の文字が1個以上連続で続いていてハイフンかピリオドか半角スペースが終わるまで」という意味になります。

ちょっとややこしいですが、”.*?” というパターンは良く使いますので、頭の片隅にでも入れておいていただければ、次に役立つと思います。

今回公開したソースコードを自分様にカスタマイズしたり、あるいは皆さんのソースコードに流用する時のヒントになるような観点で、ポイントとなる部分を解説していきましょう。

今回公開したソースコードを自分様にカスタマイズしたり、あるいは皆さんのソースコードに流用する時のヒントになるような観点で、ポイントとなる部分を解説していきましょう。

TagLibの使い方

MP3のタグを編集する用途では、「TagLib」が広く使われていて安心感がありますが、日本語の場合は文字化けすることがあります。

この文字化け対策についても対応策を後ほど紹介します。

インストール方法

TagLib は Visual StudioのNuGetから簡単に自分のプロジェクトに取り込むことが出来ます。

具体的には、Visual Studio のパッケージ管理機能 NuGetとは? の記事に記載していますが、以下の様に画面をクリックしていくことで、インストール(自分のプロジェクトへの取り込み)が行えます。

タグの読み出し

まず、静的クラスである Taglib.FileクラスのCreate メソッドを呼んで、TagLib.Fileクラスのインスタンスを生成します。

以降は、インスタンスのプロパティを通して、MP3タグにアクセスできます。

主なタグは次の様に記述することで取得できます。

以下は主なタグ名とTagLibのプロパティの対応表です。

実際にはこれ以外にもありますが、ほとんど馴染みがないものばかりです。

MP3タグの名前対応するプロパティ名
タイトルstringTitle
アーティストstring[]Artists
アルバムアーティストstring[]AlbumArtists
アルバム名stringTag.Album
作曲家string[]Composers
uintYear
トラック番号uintTrack
ディスク番号 uintDisc
ジャンルstring[]Genres
長さ(再生時間)TimeSmanProperties.Duration
ビットレート(Kbps)intProperties.AudioBitrate
タグstringTagTypes
コメントstringComment

ちなみに、TagLibの長さ(再生時間)やビットレートについては、正しく取得できない場合がありました。

たとえば、5分の曲が30分で表示されたり、128kbps が 32kbps で表示されるようなパターンです。

エクスプローラーからファイルを右クリックしてプロパティを表示してみると、そちらは正しく表示されていました。

有名どころのMP3編集ソフトとTagLibの取得結果は同じだったので、そもそもMP3タグの値がおかしいのだろうと思います。

MP3に埋め込まれた画像の取得

MP3には画像を埋め込むことが出来ますが、その画像は Tag.Pictureプロパティにバイト配列(byte[])で格納されています。

PictureBoxコントロールを用いて画面に表示するには Image 型に変換する必要がありますが、それはFromStream メソッドを使います。

尚、画像は複数格納できるように配列型になっているため、Length プロパティを使って画像が埋め込まれているかを判定できます。

以上のことを踏まえ、画像が埋め込まれている時のみ pictureBox1 に画像を表示するサンプルは次の様になります。

埋め込まれている画像は必ずしも小さな画像とは限らないため、サンプルでは縦横200ドットのサムネイルを作成し、それをpictureBox1.Image に渡しています。

サムネイルを作成せず、pictureBox1のSizeModeプロパティを使って適切なサイズ時自動縮小して表示する方法もあります。

タグの書き込み

タグの書き込みは、読み込みと同様 Createメソッドで Fileクラスを作成し、Tagクラスのプロパティに値を設定していき、最後に Saveメソッドを呼ぶだけです。

MP3ファイルへの画像の埋め込み

Pictureクラスのコンストラクタにimageデータを渡すことで、TagLibで取り扱えるデータに変換できます。

それを TagクラスのPictures プロパティに配列形式で渡した後、Saveメソッドを呼ぶだけで埋め込むことが出来ます。

文字化け対応

さて、TagLibで一番問題になるのは漢字の文字化けです。

文字化けする場合としない場合があるのですが、これはMP3タグのバージョンによって文字コードが異なることと、その規則を無視してシフトJISを書き込んでしまうMP3エンコーダーが横行していることが原因のようです。

理由はともかく、私が試したところによるとTagLibで正しく日本語が表示される場合と文字化けする場合があったので、それを解決する手段を思考錯誤しました。

最終的にたどり着いたのが次のソースコードになります。

有名どころのMP3タグ編集ソフトで表示される結果と、この方法で変換した結果を約1000ファイルに渡って比較したところ、両者は一致したので、おそらくこれが正解なんだろうと思ってます。

考え方としては、元の文字列をシフトJISと仮定して一旦バイト列に変換後、再びシフト列に変換してあげると、もしシフトJISであったなら元の文字列に戻るはずです。

この考え方を使ってシフトJISか否かを判断し、シフトJISでなければシフトJISに変換してあげるという事をやっています。

シフトJISに変換する際、一旦バイト列に変換する必要があるのですが、その時1バイトごとに0x00が付加されていますので、これを取り除いています。

私はMP3タグについて詳しく無いので、何故こうなるか理由は分かりませんので、もし分かる方がいれば是非教えて頂きたいと思います。

参考:Shell32.dllを使ったタグの読み出し

参考情報として、Shell32.dll を使ったタグの読み出しについても軽く紹介しておきます。

Google検索して見つけた内容なので、原文はこちらの記事をご覧下さい。

方法は、Shell32.dll をプロジェクト参照してから、数行プログラムを書くことで、プロパティが取得できます。

参照設定の方法

Visual Studio のソリューションエクスプローラーから、「参照」→「参照の追加」→「参照マネージャ」→「COM」と選択していきます。

次に、「Microsoft Shell Controls And Automation 」を探してチェックを入れ、「OK」ボタンをクリックすると完了です。

「参照」の一覧に Sell32 が表示されたと思いますので、これをクリックし、「相互運用型の埋め込み」をFalseに設定します。

初期値はTrueなのですが、Trueのままだとエラーになります。

タグ読み出しのソースコード

参照した Shell32 を使ってタグを読み出す方法は次の通りです。

GetDetailsOfメソッドの第2引数にタグ番号を代入すると、そのタグ番号に登録されている値が取得できます。

実験的に、0~300までタグ番号を変えて値を取得するプログラムを作って、どんな値が返ってくるのか調べてみました。

0010(タグ番号10)は私の端末名とユーザー名が表示されていたので、あえてボカしました。

原文にもタグ番号と内容の一覧が記載されていますが、WindowsXP時代のもののようで、Windows10の場合は次の様になりました。

タグ番号内容
0ファイル名
1ファイル容量
2MP3 形式サウンド
3更新日時
4作成日時
5アクセス日時
9ファイルの種類(オーディオ、ビデオ等)
10所有者
11音楽
13アーティスト
14アルバム名
15
16ジャンル
19評価なし
20アーティスト
21タイトル
24コメント
26トラック番号
27長さ(再生時間)
28ビットレート
194フルパス
196ファイル形式(MP3 形式サウンド、MP4ファイルなど)
215サブタイトル
237アルバムアーティスト
243作曲家
248雰囲気
249ディスク番号

まとめ

今回はC#、WindowsForm、TagLibを使って、MP3タグを編集するプログラムを作成したので、EXEファイルのダウンロード方法、プログラムの使い方、ソースコード解説、TagLibの使い方について解説しました。

今回作成したプログラムは、MP3ファイルが格納されているフォルダを本ツールにドラッグ&ドロップし、編集対象項目を選び、フォーマットや置換の機能を用いてタグを設定したり、ファイル名を変更するという単純なものですが、再利用を考慮して極力関数化していますので、プログラム作り方について参考になるかと思います。

今回採用したTagLibは文字化けという問題はあるものの、本記事で紹介した対策を使えば回避可能なため、十分重宝すると思います。

もしMP3タグを編集する機会が有れば、是非この記事を参考にして頂ければと思います。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

目次