アカベコマイリ

HEAR NOTHING SEE NOTHING SAY NOTHING

C# で音楽再生 2

あけましておめでとうございます。本年もよろしくお願いします。

2010 年の初記事は帰省中に読んだ FREE の書評を書くつもりだったが、意外と時間がとれずに読了できていないので、年末に書きかけてた記事を仕上げることにした。

というわけで C# で音楽再生するシリーズその 2。

サンプル プログラム

プログラムを実行すると以下のようになる。画像のファイルパスの一部へ個人情報保護のためモザイクをかけている。

サンプル プログラム

スクリーンショットに表示されている曲は TOKYO No.1 SOUL SET の名盤 TRIPLE BARREL から。

今回のテストでひさしぶりに聴いたが、やはり素晴らしい。オクラホマ・スタンピートで聞こえるハープのフレーズはケミカル・ブラザーズのアルバムにも登場するけど、なにか有名な元ネタがあるのだろうか?→後で調べたら Willie Hutch の Brother's Gonna Work It Out という曲だった。

プロジェクト一式は以下となる。

サンプル プロジェクトのビルドには Visual Studio 2008 SP1、プログラムの実行には NET Framework 3.5 SP1 が必要。

今回の変更点

前回は NAudio 標準機能とコーデックを利用していたが今回は WMA の再生と ID3/ASF のメタデータ取得に対応してみる。

Windows Media Format Runtime

WMA 再生とメタデータ取得には Windows Media Format Runtime ( 長いので以降は WMF と呼ぶ ) を使用する。

WMF は COM として公開されているので C# から利用する場合は ComImport で参照する。MSDN を眺めつつ自分でインターフェースを定義しもよいが、面倒なので以下のサイトに公開されているものを土台にさせてもらう。

オーディオ データの読み取り

はじめに WMA から音声を読み取るためのクラスを実装する。音声の出力は NAudio を利用する事になるので NAudio 標準の Mp3FileReaderWaveFileReader と同様に WaveStream 派生クラスとする。

ただし WMA 再生に利用する IWMSyncReader インターフェースには重要な制限事項がある。前述の記事にも警告されているが、これは MTAThread で使用しなければならない。

NAudio では音声の読み取りと出力は複数スレッドをまたぐため STAThread のまま IWMSyncReader で音声を読み込むと例外が発生する。また .NET アプリケーションの標準は STAThread であり、これを MTAThread に書き換えるのは影響が大きすぎるため避けたい。よって以下のように対策する。

  1. IWMSyncReader を使用するクラス WmfReader を実装
  2. WmfReader の生成とデータ読み取りを単一のスレッドで行うための WmfSyncReader を実装
  3. NAudio に渡すインスタンスは WmfSyncReader にする

ソース コードは長いため引用しないが、これを念頭に置いてサンプル プロジェクトの WmfReader/WmfSyncReader を眺めると対策の概念を理解しやいはず。

メタデータの読み取り

WMF のメタデータ読み取りは ASF と ID3v1 ~ v2.4 をサポートしている。

データの読み取りには IWMMetadataEditor2IWMHeaderInfo を使用する。WMCreateEditor 関数の返す IWMMetadataEditor2 を IWMHeaderInfo にキャストするとメタデータ操作オブジェクトを得られる。

メタデータは IWMHeaderInfo.GetAttributeByName から取得できるのだが、返されるデータ型はバイト配列となるため、適宜 String や int に変換すること。ASF なら文字列は常に Unicode になるのだが ID3 の値の文字コードが ANSI でも読み取りは Unicode になるようだ。文字コード判定と変換も実行してくれるのだろうか?

ジャケット画像や歌詞データは構造体になる。今回のサンプルでは文字列と整数、真偽値、GUID だけに対応した。