「moreover lwjgl」 12 oggを流す
速報?ですが、LWJGLのバージョン3.0.0が6/3に正式にリリースされていました。VulkanやらNanoVGやらだけでなく、が追加されており、ただのラッパーではなくなってきているのかな?という感じです。
それでは本題…いままでのOpenGLの流れをぶっちぎってしまって急にOpenALに入って変な感じになってしまいますが…
OpenALはクリエイティブテクノロジーというところが作った音声に関するオープンライセンスなライブラリーです。
じつは最新の更新が5年前(古い…)という状態のOpenALですが、OpenAL Softなるものもありまして、これはオープンソースで、更新も5ヶ月前とのことです。LWJGLはOpenAL Softもありますが、OpenALもちゃんと使えるのでそっちを使っています。
そして、そのOpenALを使って今回は、".ogg"ファイル(OGG Vorbis)をデコード、再生してみたいと思います。なぜ".mp3"ではなく、".ogg"にしたのかというと、".mp3"はLWJGLで標準的に開くことが出来ませんが、".ogg"はLWJGLでもデコードやデータを渡してくれるライブラリー(STB)があるからです。また、".mp3"にはちょっとしたライセンス問題もあるようですので、あまり使いたくないです。
とりあえず、起動したら曲がふつうに再生されるようなソースコードを…
解説(OpenAL/ALCは茶色、STBは青色で)
20行目 : 再生したいoggファイルのパスです。
22,23行目 : 音声を流すデバイスとopenALのコンテキストです。これは、OpenGLの時とおんなじ感じです。
25行目 : 曲のソースと、曲のバッファーを識別する変数を宣言しています。
26行目 : 読み込んだoggファイルの情報を受け取るSTBVorbisInfoの宣言です。
32~40行目 : プログラムの主な流れです。
ここからOpenALの話
43行目 : 音声を流すデバイスに接続します。
OpenGLの時と同じように、引数にnull(ByteBufferの)を指定すれば、標準のデバイスに接続されます。また、その戻り値がNULL(=0)の場合はちゃんとデバイスに接続できなかったということになります。
47行目 : Capabilitiesによって、ALCのメソッド類といった機能がすべて使えるようになります。
49行目 : 指定したデバイスと属性のALCコンテキストを作成します。
属性というのは、このコンテキストが生成された時の設定などを入れます。今回は特に何も指定しないので、null(IntBufferで)に指定しています。
50行目 : 作成したコンテキストを現在のコンテキストに指定します。
51行目 : ALCのCapabilitiesを使って、OpenALの機能を全て使えるようにします。
ALC(ALC API)は、OpenALがどの環境でも動くようにするものです。OpenGLで言うと、GLFW的なものかな?
55行目 : 音声のデータ(音源)を入れた「バッファー」(オーディオバッファー)を生成します。
バッファーは、IDによって区別され、ここでは、IDを返り値にしています。
56行目 : 音声に関する情報が入る「ソース」を生成します。
バッファーと同じくIDを返り値にしています。
58行目 : STBVorbisInfoをmalloc(メモリーに場所をとる)しています。
60行目 : STBVorbisを使って、oggファイルを開き、かつ、デコードしています。
CharSequenceでファイルのパスを指定し、エラーを受け取るバッファーとAllocation(ふつうはnullでいいのかな?)さえ渡せば、Allocationにデコードした音声を入れておき、それを操作するハンドルが返ってきます。便利ですね~。ちなみに、メモリーから参照するメソッドも用意されてます。
64行目 : 曲データに関する情報(Info)を受け取ります。
66行目 : Infoから曲のチャンネルを受け取ります。チャンネルは、基本的に2です。
67行目 : Infoから曲の長さを受け取ります。
69行目 : 曲の長さの2倍の大きさで、PCMデータ(サンプルデータ)を入れるShortBufferを作ります。2倍になったのは、チャンネルが2だからだと思います。(長さそのままだと半分でぶちっと切れる)
71行目 : デコードしたoggファイルのデータをチャンネルなど踏まえて、インターリービングにサンプルデータのShortBufferに入れます。
72行目 : デコードしたデータを開放し、STBVorbisを終えます。
74行目 : サンプルデータをバッファーに入れます。
第1引数でバッファーを。第2引数でオーディオファイルの形式(ステレオの16bitか、モノラルの8bitかなど)
第3引数で実際のサンプルデータを。第4引数では、サンプリング周波数を指定します。
76,77行目 : ソースの属性(ALCの方とは違って、ソースの設定としての)を変更します。
76行目では、ソースのオーディオバッファーとして、サンプルデータの入ったバッファーを指定しています。
77行目では、ソースを再生するときに、ループをしないように指定しています。
これで、再生までの準備は整いました。
実際にここまでで、OpenAL内はこうなっています。(一例です)
バッファーは曲のサンプルデータが入っています。そして、それを入れたソースには、様々な属性が付いていることがわかると思います。
また、サンプリング周波数やPCMなどの説明は こちら で…
81行目 : ソースをふつうに再生します。
今回は、ストリーミングではないので、後から曲をいじることは出来ません。
82~87行目 : ソースがプレイ中かどうかを確認し、プレイ中ならJavaのスレッドで10ミリ秒待ち、また確認します。プレイ中でなくなったら、次に進めます。
82,86行目 : ソースが状態を受け取る関数です。
89行目 : ソースの再生を止めます。
一度再生中か確認するループがないと、再生した途端に、停止させてしまいます。(このループが良いとはいえませんが…)
93行目 : ソースをメモリーから消します。
バッファーとのつながりも切れます。
94行目 : バッファーをメモリーから消します。
一度消すと元に戻せません。
95行目 : デバイスを指定のコンテキストのものにします。
これは、複数デバイスを一度まとめるためです。つまり、今回はあまりいらないです。
96行目 : コンテキストを現在のものから解除します。これをしてからでないと、コンテキストを消せません。
97行目 : コンテキストを消しています。
98行目 : デバイスを消しています。
おわり
これを再生すれば、自分が好きな曲を流せます。(oggファイルで)
ただ、ストリーミングでもなく、一時停止も音量変化も、そして一番の楽しみの立体音響ですら出来ないので、今度それらもやってみたいと思います。