昔とった私のHRTF
(Head-Related Transfer Function)のインパルス応答(以降, hrir
: head-related impulse response)を音楽に畳み込みながら再生するアプリを作り始めた。
hrir
はdouble
のバイナリ形式で保存してあったので、ファイルからbyte[]
形式で読み込んでdouble[]
に変換する必要がある。
今回はByteBuffer
を使うことにした。ちなみに、このクラスを使わないとすればbyte[8] -> long -> Double.longBitsToDouble(long)みたいな感じでコツコツ変換していく方法もある。
使い方はざっくり書くとこんなかんじ。
AssetFileDescriptor fd = assets.openFd(string); // バッファサイズは使いながら増やせないので、最初に必要なだけ確保する。 // バイトオーダのデフォルトはビッグエンディアン ByteBuffer byteBuf = ByteBuffer.allocate((int)fd.getLength()) .order(ByteOrder.LITTLE_ENDIAN); // ファイルチャネルから直接読む FileChannel channel = fd.createInputStream().getChannel(); channel.read(byteBuf); // バッファ書き込みから読み出しモードに切り替える byteBuf.flip(); // バッファの中身をdoubleの値として書き出す double[] res = new double[byteBuf.capacity() / (Double.SIZE / 8)]; for (int i = 0; i < res.length; i++) { res[i] = byteBuf.getDouble(); }
最初はres = byteBuf.asDoubleBuffer().array()
としていたが、これだとUnexpectedOperationみたいな例外が飛んできて怒られた。ByteBuffer#asDoubleBuffer()
はdouble[]
をallocateしないということなのだろうか。いろいろ悩んだ挙句最後のfor
文のようにした。
ところで、件のメソッドのテストコードを読んでいると、これでいいのかな、と感じたところがあった。何かのご縁でこのページにやってきた方々にもぜひこのコードを読んでいただき、なんかおかしいような、、、とかいや、これでよいのだというようなことをお教えいただければありがたい。
具体的には、doubleBuffer.remaining()
が0のとき、アサーションを全く通らずにテストが成功してしまうという点。私の上のコードではbyteBuf.asDoubleBuffer().remaining()
が0になるんだよなー…
今回の実装で参考にさせていただきました。ありがとうございました。