本記事は、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ネイティブコードプログラミングのおさらいです。

  1. Visual Studio 2005 or 2008でWindows Mobile 6.5.3 DTKターゲットのDLLプロジェクトで、普通のCOMコンポーネントを作る要領でコードを書く(参考)。
  2. Visual Studio 2010でWindows Phone OS 7.1プロジェクトを作る。
  3. VS2010のプロジェクトに1.でビルドしたDLLとWPInteropManifest.xmlを追加する(参考:Windows Phone 7.5 ネイティブコードプログラミング – ななふぉ)。
  4. 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)

スポンサード リンク

この記事のカテゴリ

  • ⇒ libtta++を使ってTTAを再生する(Windows Phoneで)
  • ⇒ libtta++を使ってTTAを再生する(Windows Phoneで)
  • ⇒ libtta++を使ってTTAを再生する(Windows Phoneで)
  • ⇒ libtta++を使ってTTAを再生する(Windows Phoneで)