libtta++を使ってTTAを再生する(Windows Phoneで)
本記事は、Windows Phone Advent Calendar 2011 : ATNDの7日目の記事です。
True Audio (TTA)という可逆圧縮の音声形式があります。はい、つまりWindows PhoneでTTAの再生ができるかどうかちょっと試してみました。結論から言うと、ハマりどころもなく簡単にできました(まだいろいろと工夫の余地はありますが)。
公式サイトのFree Downloadsを見ると、CとC++で書かれたライブラリがあるようです。迷わずC++版 (libtta++) をダウンロードしました。中身を確認すると、静的LIBを作るVC++プロジェクトとサンプルのコンソールアプリのVC++プロジェクトが入っていました。
ではここで、Windows Phone OS 7.1ネイティブコードプログラミングのおさらいです。
- Visual Studio 2005 or 2008でWindows Mobile 6.5.3 DTKターゲットのDLLプロジェクトで、普通のCOMコンポーネントを作る要領でコードを書く(参考)。
- Visual Studio 2010でWindows Phone OS 7.1プロジェクトを作る。
- VS2010のプロジェクトに1.でビルドしたDLLとWPInteropManifest.xmlを追加する(参考:Windows Phone 7.5 ネイティブコードプログラミング – ななふぉ)。
- VS2010プロジェクト側、C#上で1.で作ったインタフェースやクラスに対応する宣言を書く。RegisterComDllの呼び出しを行う。ネイティブDLLで作ったCOMクラスをnewする。
今回はlibtta++の静的LIBをビルドするプロジェクトを作成、1.のDLLプロジェクトでその静的LIBをリンクするようにしました。
libtta++のビルドは、Visual Studio 2008でやはりWindows Mobile 6.5.3 DTKターゲットの空のプロジェクト(スタティックライブラリ)を新規に作ってやりました。
- そのプロジェクトに、libtta.cppを追加。
- あとconfig.hを開いて、#define CPU_X86の行をコメントアウト。
Releaseビルドしたら、libtta.libが得られました。なお、付属のVC++プロジェクトを開いてWindows Mobile 6.5.3 DTKの構成を追加する方法はリンク時によく分からないエラーがでてどうしようもなかったので諦めました。
次にDLLのプロジェクトです。libtta.libのほか、libtta++からconfig.hとlibtta.hを持ってきて使用しています。最後にソースファイル一式ダウンロードのリンクを置くので、詳しくはそちらを見てください。なんの工夫もなく、libtta++付属サンプルを改造し「TTAデコード→WAVをメモリに書き出す→そのメモリを呼び出し元に返す」というプログラムです。
とりあえず、インタフェースの宣言だけここに載せます。
interface __declspec(uuid("95E19FD5-D011-4979-BBFB-26D9C358BDC0")) IDebug : public IUnknown { virtual HRESULT STDMETHODCALLTYPE WriteLine(BSTR s) = 0; virtual HRESULT STDMETHODCALLTYPE WriteLineW(LPCWSTR s) = 0; }; interface __declspec(uuid("36F21A71-822B-4CD5-9DC9-F1A68FE6AE04")) IDecoder : IUnknown { virtual HRESULT STDMETHODCALLTYPE Init( /*[in]*/ IDebug* debug) = 0; virtual HRESULT STDMETHODCALLTYPE Decode( /*[in]*/ BYTE* source, /*[in]*/ int length, /*[out, ret]*/ SAFEARRAY** dest) = 0; }; |
IDebugについては、OutputDebugStringの代替です(参考:WP7.1ネイティブとOutputDebugString)。
これもReleaseビルドします。CycmNativeという名前のVC++プロジェクトだったので、CycmNative.dllが出来上がります。
いよいよ、Windows Phone OS 7.1プロジェクトの作成です。CycmNative.dllと適当なTTAファイルをプロジェクトに追加します(今回は、TTAファイルを「ビルドアクション:コンテンツ」で埋め込みました)。あと、WPInteropManifest.xmlは以下の内容です。もしかして、空っぽでもイケるんですかね?
<Interop/> |
C#側のメイン部分のコードは短いのですべてここに載っけてしまいます(もちろん、この記事の最後にプロジェクト一式アーカイブのリンクを用意しています)。
public partial class MainPage : PhoneApplicationPage { public MainPage() { InitializeComponent(); } private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e) { ComHelper.Register("cycmnative.dll", typeof(DecoderImpl)); var decoder = new IDecoder(); decoder.Init(new DebugImpl()); var rs = Application.GetResourceStream(new Uri("cycm.tta", UriKind.Relative)); byte[] buf = new byte[rs.Stream.Length]; rs.Stream.Read(buf, 0, buf.Length); var result = decoder.Decode(buf, buf.Length); sound = SoundEffect.FromStream(new MemoryStream(result)); soundInstance = sound.CreateInstance(); SoundEffect.MasterVolume = 1.0f; soundInstance.Play(); } SoundEffect sound; SoundEffectInstance soundInstance; } |
デコードしたらWAVデータが得られるようになっているので、あとはSoundEffectで再生させているだけです。はい、一気にデコードさせるのではなく、デコードしつつ再生するようにしたいですね。たぶん、MediaStreamSourceを使えばできるのだと思います。
以上、大変駆け足でのWidnows Phone OS 7.1ネイティブコードプログラミングでした。ID_CAP_INTEROPSERVICES? 何それ?おいしいの?
- CycmNative.zip(ネイティブ側VC++2008プロジェクト、libtta++にあわせてLGPLv3)
- Cycm.zip(マネージ側VC#2010プロジェクト、MIT Lisence)
スポンサード リンク |