• OpenSL ES でのMIDI再生

    2011年05月15日 00時49分
    OpenSL ESでMIDIの再生について聞かれましたので簡単に書いておきます。
    簡単にというのも、詳しく説明するほと知らないからです。

    MIDIは仕様上イベントを保持していたり、再生状態を制御したり出来るらしく、
    OpenSL ESもそれを扱うことが出来るようですが
    私の用途ではそこまで必要ではないため再生しか試していません。


    単純に再生する方法については、サンプルコードがドキュメントに書いてあります。
    VIVID Runtime SDKではドキュメントは「documentation/api/khronos/opensles1.0.20090316.pdf」にあり、
    MIDIの再生については「APPENDIX B.3」にあります。

    サンプルコードがそのまま乗っていますので、一連の流れが確認出来ます。
    ポイントはSLDataFormatの値で、
    mimeTypeに「audio/x-midi」を、containerTypeに「SL_CONTAINERTYPE_SMF」を設定します。


    VIVID Runtime SDK 1.3に付属のimplementation_notes.xlsを見ると
    MIDIの場合はMIMEに「audio/midi」と「audio/mobile-xmf」を使いなさいと書いて有るので
    こちらでも動くかもしれません。


    簡単に動作を試すならば、VIVID Runtime SDK付属の「simple3d」サンプルを改変すればよさそうです。
    ファイル名とファイルフォーマットの設定を変えれば動くのではないでしょうか。(未確認)

    変更前
    1uri.URI            = (SLchar *) "synth_22kHz_16b.wav";
    2
    3    mime.formatType    = SL_DATAFORMAT_MIME;
    4    mime.mimeType      = (SLchar *) "audio/x-wav";
    5    mime.containerType = SL_CONTAINERTYPE_WAV;



    変更後
    1uri.URI            = (SLchar *) "hoge.mid";
    2
    3    mime.formatType    = SL_DATAFORMAT_MIME;
    4    mime.mimeType      = (SLchar *) "audio/x-midi";
    5    mime.containerType = SL_CONTAINERTYPE_SMF;


  • OpenSL ES での複数音源再生

    2011年03月23日 04時56分
    以前の記事で、MIDIを複数再生するとおかしくなると書きましたが、使い方が悪かったようです。

    EngineとOutput Mixが1対1で、Output MixとPlayerが1対Nだと思っていましたが、
    正しくはEngineとOutput Mixが1対Nで、Output MixとPlayerが1対1のようです。

    リファレンスにもきちんと書いてありました。
    7.9 Output Mix
    Description
    The output mix object represents a set of audio output devices to which one audio output
    stream is sent. The application retrieves an output mix object from the engine and may
    specify that output mix as the sink for a media object. The engine must support at least
    one output mix, though it may support more. The API does not provide a direct audio
    output IO-device as a sink for media objects.

    実際そのように修正したところ、エミュレータ上の動作は正常になりました。

    ただ、Output Mixの数は最低1つが保証されているのみで、
    それ以上もたぶんあるんじゃないの的な記述なのが少々気になります。

    実際に使える数の上限は不明です。
    とりあえずエミュレータ上で2音まで確認しました。

    ランタイムの実装依存だとは思いますが、もしかしたら実機依存かもしれません。
  • OpenSL ES Tips (On VIVID Runtime)

    2011年03月09日 23時35分
    OpenSL ES自体はサンプルとリファレンス見ながら
    なんとなく使えるとは思います。

    なので、何点か引っかかったとこだけ記しておこうと思います。

    MIDI再生を使用していたときに調べたことなので、
    基本的にMIDI再生に関することだと思ってください。
    WaveとかMP3も当てはまるかもしれませんが未検証です。

    また、対象のVIVID Runtime SDKのバージョンは1.1です。
    最近1.2が出ているので、そちらでは改善されているかもしれません。

    音量について

    SLVolumeItfのSetVolumeLevelで設定するわけですが、
    この引数が「SL_MILLIBEL_MIN ~ 端末のサポートする最大値(多くの場合は0)」と書いてあるのですが、
    SL_MILLIBEL_MINを指定するとエラーが返ってきます。
    (エミュレータとXperiaで確認)

    エラーが出ない数値を探ると-2000でした。
    なので、-2000 ~ 0の間で指定しましょう。

    端末によってはこの数値も怪しいかもしれません。

    あと、SL_MILLIBEL_MAXというのが定義されていまして、
    これが最大値っぽいですが全然違うので気をつけましょう。

    プレイヤーの解放について

    MIDIのプレイヤーはCreateMidiPlayerで作成するわけですが、
    これを解放する前には手動でSLPlayItfのステータスをSL_PLAYSTATE_STOPPEDにしなければなりません。

    SL_PLAYSTATE_PAUSEDのままDestroyしてしまうと
    どうもきちんと解放されないようです。
    (実機が落ちたり、動作が不安定になりました。)

    MIDIの複数再生について

    CreateMidiPlayerで再生オブジェクトを2個作ると
    何故か再生速度が速くなります。

    2個作ってはいけないのかもしれません。

    CreateMidiPlayer & CreateAudioPlayerで2個作ると
    Xperiaは大丈夫でしたがエミュレータだと同じ現象です。

    これは未だ解決方法不明です。
  • VIVID Runtimeはじめました Ogg vorbis編

    2011年03月07日 23時00分
    VIVID Runtimeは音声再生にOpenALとOpenSL ESがありますが、
    公式にはOpenSL ESの方をプッシュしてきます。

    だったら最初から片方だけにしとけばいいんじゃとか思わないでもないですが、
    複雑な事情があるのでしょう。


    私は素直な人間なので、お勧めされるがままにOpenSL ESを使いました。

    しかしこのOpenSL ESですが、全く普及している気配がありません。
    私などは今回初めてこの単語を目にしたくらいです。

    ネット上を調べてみても情報がさっぱり出てきません。

    一応Kronos公式ドキュメントがSDKに含まれるので
    なんとかなるといえばなるのですが・・・
    たまに実装とドキュメントが違うこともあるので気が抜けません。



    今回ゲームのBGMにOgg vorbisを使えないかという相談を受けました。
    しかしOpenSL ESは対応していないようです。

    どうもOpenSL ES 1.1ならば対応している気配があるのですが、
    VIVID Runtime SDKに含まれるのは1.0です。

    1.0でもMP3ならば再生出来るのですが、MP3だとライセンス料が半端ないので使いにくいです。
    もしかしたらVIVID Runtime側でライセンス処理をしてるかもしれませんが、その辺り不明です。

    そこで今回はVIVID Runtime上で頑張ってOgg vorbisを再生してみます。


    そもそもWaveの再生はあるのです。
    SDKのサンプルにplaystreamというのがあり、これがメモリ上のWaveデータを再生しています。

    ということは、vorbisデータをデコードして
    このバッファにぶち込んでやれば再生出来るということになります。

    そこで早速libogg-1.2.2とlibvorbis-1.3.2を入手しました。

    私は未だにconfigureとかmakeとかよくわからんのですが、
    要はCコードをVIVID Runtime SDKに含まれるクロスコンパイル環境でコンパイルしてやればいいと思うのです。

    例えばoggならばこんな感じです。
    "C:\vivid_runtime_sdk_1_1\tools\gcc_toolchain\bin\arm-runtime-eabi-gcc.exe" -I include -c -fpic -mno-thumb-interwork -Wall -O3 src\framing.c -o framing.o
    "C:\vivid_runtime_sdk_1_1\tools\gcc_toolchain\bin\arm-runtime-eabi-gcc.exe" -I include -c -fpic -mno-thumb-interwork -Wall -O3 src\bitwise.c -o bitwise.o
    
    "C:\vivid_runtime_sdk_1_1\tools\gcc_toolchain\bin\arm-runtime-eabi-ar.exe" rcs libogg.a framing.o bitwise.o

    ※config_types.hにconfigureでOS判定して埋め込む部分があったのでそこだけは手動で解決しています。

    同じ感じでvorbisの方も作成します。


    作成したライブラリとヘッダを次のフォルダに配置します。
    $VIVID_RUNTIME_SDK\tools\gcc_toolchain\arm-runtime-eabi\usr

    ※$VIVID_RUNTIME_SDKはVIVID Runtime SDKを展開したフォルダ


    こうするとビルド時に参照することが出来ます。


    あとはサンプルのコードにvorbisのデコード処理を入れて完了です。

    で、実行してみたのですが、デコードが追いつきません。
    エミュレータとはいえ、Phenom II 3GHzで足りないという状態です。
    中でどんな処理してるんだろう・・・


    これはもう少しなんとかならんかと調べてみたのですが、
    Tremorという整数演算で高速デコードするバージョンがありました。
    しかもARM用に最適化してあったりします。

    これをチェックアウトしてきておりゃおりゃっとビルドします。
    "C:\vivid_runtime_sdk_1_1\tools\gcc_toolchain\bin\arm-runtime-eabi-gcc.exe" -I include -c -fpic -mno-thumb-interwork -Wall -O3 mdct.c -o mdct.o
    "C:\vivid_runtime_sdk_1_1\tools\gcc_toolchain\bin\arm-runtime-eabi-gcc.exe" -I include -c -fpic -mno-thumb-interwork -Wall -O3 block.c -o block.o
    "C:\vivid_runtime_sdk_1_1\tools\gcc_toolchain\bin\arm-runtime-eabi-gcc.exe" -I include -c -fpic -mno-thumb-interwork -Wall -O3 window.c -o window.o
    "C:\vivid_runtime_sdk_1_1\tools\gcc_toolchain\bin\arm-runtime-eabi-gcc.exe" -I include -c -fpic -mno-thumb-interwork -Wall -O3 synthesis.c -o synthesis.o
    "C:\vivid_runtime_sdk_1_1\tools\gcc_toolchain\bin\arm-runtime-eabi-gcc.exe" -I include -c -fpic -mno-thumb-interwork -Wall -O3 info.c -o info.o
    "C:\vivid_runtime_sdk_1_1\tools\gcc_toolchain\bin\arm-runtime-eabi-gcc.exe" -I include -c -fpic -mno-thumb-interwork -Wall -O3 floor1.c -o floor1.o
    "C:\vivid_runtime_sdk_1_1\tools\gcc_toolchain\bin\arm-runtime-eabi-gcc.exe" -I include -c -fpic -mno-thumb-interwork -Wall -O3 floor0.c -o floor0.o
    "C:\vivid_runtime_sdk_1_1\tools\gcc_toolchain\bin\arm-runtime-eabi-gcc.exe" -I include -c -fpic -mno-thumb-interwork -Wall -O3 vorbisfile.c -o vorbisfile.o
    "C:\vivid_runtime_sdk_1_1\tools\gcc_toolchain\bin\arm-runtime-eabi-gcc.exe" -I include -c -fpic -mno-thumb-interwork -Wall -O3 res012.c -o res012.o
    "C:\vivid_runtime_sdk_1_1\tools\gcc_toolchain\bin\arm-runtime-eabi-gcc.exe" -I include -c -fpic -mno-thumb-interwork -Wall -O3 mapping0.c -o mapping0.o
    "C:\vivid_runtime_sdk_1_1\tools\gcc_toolchain\bin\arm-runtime-eabi-gcc.exe" -I include -c -fpic -mno-thumb-interwork -Wall -O3 registry.c -o registry.o
    "C:\vivid_runtime_sdk_1_1\tools\gcc_toolchain\bin\arm-runtime-eabi-gcc.exe" -I include -c -fpic -mno-thumb-interwork -Wall -O3 codebook.c -o codebook.o
    "C:\vivid_runtime_sdk_1_1\tools\gcc_toolchain\bin\arm-runtime-eabi-gcc.exe" -I include -c -fpic -mno-thumb-interwork -Wall -O3 sharedbook.c -o sharedbook.o
    
    "C:\vivid_runtime_sdk_1_1\tools\gcc_toolchain\bin\arm-runtime-eabi-ar.exe" rcs libvorbisidec.a mdct.o block.o window.o synthesis.o info.o floor1.o floor0.o vorbisfile.o res012.o mapping0.o registry.o codebook.o sharedbook.o

    ※os.hのエンディアンの設定がよろしくないので調整しています。


    出来たlibvorbisidec.aでデコードしてみたところなんとか再生できました。
    本当になんとか・・・といった感じで、稀にデコードが追いついていません。

    あとはFPUを使って最適化でなんとかならんかなと思うのですが、
    ARMのFPUを使ったデコーダは見つけられませんでした。
    さすがに自分で書く気も起きません。


    エミュレータで厳しくても実機ならいけるんじゃないか?と思わなくもないのですが、
    今は手元に実機がないんですよねぇ・・・。Xperia arcでも買おうかしら。


    今回使ったファイル