C#でiTunes COM SDKを叩いて曲情報を表示したりアートワークを埋め込んだりしてみる

s1

普段の音楽プレーヤーはiTunesだけどスマホはXperiaとかを使っていて、音楽データを他のソフトにエクスポートするような人は気付くと思うんですが、iTunesで自動的に取得されるアートワークって曲自体には埋め込まれていないんですよね。
で、エクスポートしたり他のソフトで再生しようとしたときにアートワークが表示されなくて、せっかくiTunes上では格好良くアートワークが並んだ状態なのにどこか残念さを感じたりするわけです。

まぁもともとiTunesから拾えるアートワークなんてたかが知れてる(J-POPは少々弱い)ので、Windows使いならCDをリッピングする度にBroadwayとかを使ってネット上のファイルからアートワークを追加してしまえば、iTunesでも曲自体にアートワークを埋め込むことができるんですが、とはいえもともと取ってこれる画像だってそこそこ綺麗だし、ひょっとするとネット検索で出てくるアートワークよりも高画質なことだってあるわけです。

というわけで、Windows版iTunesは外部アプリからプレーヤを制御したり楽曲情報を取得することができるiTunes COM SDKが存在するので、これを使ってiTunesを制御するついでにアートワークの埋め込みについてもチャレンジしてみました。

プロジェクト設定

iTunes COM SDK自体はCOMなので、VBScript経由で叩くことも、今回のようにC++やC#から叩くこともできます。昔の記事を見るとAppleからSDKを落としてきて云々と書かれている記事が多いですが、こういうことをする人のマシンには既にiTunesが入っているでしょうから、

  1. VisualStudioからソリューションエクスプローラーの「参照設定」を右クリック
  2. 参照の追加を選択
  3. 「COM」タブをクリックすると現れるコンポーネント名一覧から「iTunes 1.13 Type Library」を選択
    1
  4. 使用するソースコードで「using iTunesLib;」を宣言

するだけでSDKが使えます。超お手軽。

サンプルアプリ

今回作成したWindows Formアプリのソースコードを抜粋して紹介します。

画面描画系の処理がやっつけになっているのはサクッと試してみたかったせいだという点でご容赦頂きたいところですが、本質的な処理はiTunes COM SDKが比較的よくできているおかげで実装はかなりシンプルです。

気をつけるべき点としては、

  • 終了時にdisconnectCOMメソッドで行っているようなハンドラの削除とCOMオブジェクトの解放を行わないと、iTunes終了時に以下のようなメッセージが出ます。
    2
  • アートワークは一度ファイルに落とす必要があります。バイナリとして取得することはSDKを使用する上では無理そうです(Broadwayも一時ファイルにアートワークを保存しているっぽい)

といったところでしょうか。

アートワークの埋め込み

iTunes側では、Broadwayのように外部からファイルで設定されたアートワークについてはきちんと楽曲自体に埋め込まれます。
また、SDKには「アートワークがiTunesからダウンロードされたものであるかどうか」を示すフラグが用意されていますので、これをもとにアートワークが埋め込まれているかいないかを判定します。

先述の通り、アートワークはバイナリとして読み取るのではなくSDK側でファイルに書き込んでくれるので、これを使用します。パスは適当に変更してもよいのですが、ここでは実行ディレクトリ直下に保存し、埋め込みを行う場合はこの画像パスを渡すことで元のiTunesで取得されたアートワークを楽曲データに埋め込んでいます。

ちなみに、最近始まったiTunes MUSICの楽曲データについては、トラック名などの情報は取得でき、もちろんプレーヤー自体の制御もできるのですが、アートワークについては存在しない扱いになっているため取得できませんでした。まぁ、当たり前っちゃ当たり前ですね。

さいごに

今時こうやってiTunes SDKを触る人も珍しいと思いますが、これとmbedやArduinoを使用して自作のコントローラを作成したり、NowPlayingをつぶやくプラグインなどが作成できると思いますので、そういった場合の参考になれば幸いです。

References   [ + ]

1. MethodInvoker)delegate { this.AlbumNameLabel.Text = AlbumName; this.TrackNumberLabel.Text = TrackInfo; this.ArtistLabel.Text = Artist; this.TitleLabel.Text = TrackName; }); } //再生イベント時に呼び出されるメソッド void iTunes_OnPlayerPlayEvent(object iTrack) { //再生中のトラック情報を取得 IITTrack track = (IITTrack)iTrack; //ラベル用テキストを設定 AlbumName = track.Album; TrackInfo = track.TrackNumber + " / " + track.TrackCount; Artist = track.Artist; TrackName = track.Name; //アートワークコレクションを取得 IITArtworkCollection artwork = track.Artwork; if (artwork != null && artwork.Count != 0) { int artworkCount = 0; foreach (IITArtwork a in artwork) { //ぶっちゃけアートワークは1個でいいので先頭だけを使用 artworkCount++; if (artworkCount > 1) break; //フォーマットに応じて保存先パスの拡張子を変更 if(a.Format == ITArtworkFormat.ITArtworkFormatJPEG) ArtworkPath = Environment.CurrentDirectory + "\\artwork.jpg"; else if(a.Format == ITArtworkFormat.ITArtworkFormatBMP) ArtworkPath = Environment.CurrentDirectory + "\\artwork.bmp"; else if (a.Format == ITArtworkFormat.ITArtworkFormatPNG) ArtworkPath = Environment.CurrentDirectory + "\\artwork.png"; else //フォーマット不明であればこの後の処理は行わない(稀) { ArtworkPath = null; break; } //アートワークを取得して保存 a.SaveArtworkToFile(ArtworkPath); //保存したアートワークを取得(ファイルに落とさないと取れないから) Bitmap AlbumArtContent = new Bitmap(ArtworkPath); //スケールを計算 float scale_w = ((float)AlbumArtContent.Size.Width / ArtworkImageBox.Width), scale_h = ((float)AlbumArtContent.Size.Height / ArtworkImageBox.Height); float scale = (scale_w > scale_h) ? (1 / scale_w) : (1 / scale_h); //描画用に大きい方のスケールに合わせてリサイズ Bitmap canvas = new Bitmap(ArtworkImageBox.Width, ArtworkImageBox.Height); Graphics g = Graphics.FromImage(canvas); g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; g.DrawImage(AlbumArtContent, 0, 0, (AlbumArtContent.Size.Width * scale), (AlbumArtContent.Size.Height * scale