Opusとは?
Opusとは、低レンテンシで遅延を抑えることができる非可逆圧縮の音声フォーマットです。
又、Opusをカバーする既知の特許は全てロイヤリティーフリーのライセンスとされています。
今回はこのOpusの読み込みと再生を前回の『サウンドの再生』のWaveを置き換えるような形で説明していこうかと思います。
Opusの使用準備
Opusを読み込むには次のライブラリが必要となります。
- libopus
- opusfile
- libogg
『libopus』と『opusfile』については下記のURLからダウンロードできます。
http://opus-codec.org/downloads/
『libogg』は下記のURLです。
https://xiph.org/downloads/
先ず、事前準備としてこれらのライブラリをダウンロードしてビルドする必要があります。
ビルド後に各ヘッダーと出力されたlibなどを自身のプログラム内で使用します。
ここまでできれば準備は完了です。
Opusの読み込み
本来、Opusはストリーミング再生するべきデータではあります。
ですが今回は説明の為に前回のWaveと同様でオンメモリー再生としていきます。
先ず、使う際は下記のようにヘッダとライブラリのリンクを行う必要があります。
ライブラリの使用準備
#include <opusfile.h>
// libopusとopusfileをリンク
#pragma comment(lib, "opus.lib")
#pragma comment(lib, "opusfile.lib")
// liboggをリンク
#pragma comment(lib, "libogg_static.lib")
事前にヘッダやライブラリのパスを通すようにしている必要があります。
※ライブラリの名前については各々のビルドした環境によって名前が違う可能性もあります。
これでopusfileの関数が使用できるようになりました。
opusファイルを開く
int ret;
OggOpusFile* of = op_open_file(filename, &ret);
これだけでopusファイルのオープンは完了です。
波形フォーマットの取得
// Opusのヘッダを取得
const OpusHead* pHead = op_head(of, -1);
if (!pHead) {
return false;
}
WAVEFORMATEX wfex{};
// PCMなので固定
wfex.wFormatTag = WAVE_FORMAT_PCM;
// チャンネル数(モノラル:1 ステレオ:2など)
wfex.nChannels = pHead->channel_count;
// サンプリングレート(opusは48000固定)
wfex.nSamplesPerSec = 48000;
// サンプル当たりのビット数(16bit)
wfex.wBitsPerSample = 16;
// ブロックサイズ(16bitのステレオなら 2*2=4)
wfex.nBlockAlign = wfex.nChannels * wfex.wBitsPerSample / 8;
// データ速度(秒間当たりのデータ量)
wfex.nAvgBytesPerSec = wfex.nSamplesPerSec * wfex.nBlockAlign;
これで再生する波形のフォーマットが取得できます。
いくつか数値を設定していますが、opusは固定値の部分があるので指定しています。
波形サイズの取得
ogg_int64_t decodedSize = op_pcm_total(of, -1) * wfex.nBlockAlign;
これでop_pcm_totalで総サンプル数を取得してからブロックサイズ分を考慮してサイズを出しています。
後はこのサイズ分のバッファを確保して読み込めば完了です!
波形データの読み込み
//必要なメモリ確保
char* pDecodedBuf = (char*)malloc(decodedSize);
char* pBuf = pDecodedBuf;
// 波形データの読み込み(デコード)
int readSize;
while ((readSize = op_read(of, (opus_int16*)pBuf, 8096, NULL)) > 0) {
pBuf += readSize * wfex.nBlockAlign;
}
これで確保したメモリに対して波形データが読み込まれる形となります。
op_readでサンプル数が帰ってくるのでBlockAlignで実際のバイト数に変換してずらしています。
ファイルを閉じる
op_free(of);
これでファイルを閉じたら全て完了です!
Opusファイルの再生関数
再生まで一気に行うPlayOpus関数の例です。
IXAudio2SourceVoice* PlayOpus(const char* filename)
{
int ret;
//ファイル開く
OggOpusFile* of = op_open_file(filename, &ret);
if (of == NULL) {
return nullptr;
}
//波形情報の取得
const OpusHead* pHead = op_head(of, -1);
if (!pHead) {
return nullptr;
}
WAVEFORMATEX wfex{};
//PCMなので固定
wfex.wFormatTag = WAVE_FORMAT_PCM;
//チャンネル数(モノラル:1 ステレオ:2)
wfex.nChannels = pHead->channel_count;
//サンプリングレート(48000固定)
wfex.nSamplesPerSec = 48000;
//サンプル当たりのビット数(8bit:8 16bit:16)
wfex.wBitsPerSample = 16;
//ブロックサイズ(16bit ステレオなら 2*2=4)
wfex.nBlockAlign = wfex.nChannels * wfex.wBitsPerSample / 8;
//データ速度(秒間当たりのデータ量 channel*sample*bit/8)
wfex.nAvgBytesPerSec = wfex.nSamplesPerSec * wfex.nBlockAlign;
// 合計サイズの取得
ogg_int64_t decodedSize = op_pcm_total(of, -1) * wfex.nBlockAlign;
//必要なメモリ確保
char* pDecodedBuf = (char*)malloc(decodedSize);
char* pBuf = pDecodedBuf;
int readSize;
while ((readSize = op_read(of, (opus_int16*)pBuf, 8096, NULL)) > 0) {
pBuf += readSize * wfex.nBlockAlign;
}
op_free(of);
// 波形フォーマットを元にSourceVoiceの生成
IXAudio2SourceVoice* pSourceVoice = nullptr;
if (FAILED(pXAudio->CreateSourceVoice(&pSourceVoice, &wfex))) {
free(pDecodedBuf);
return nullptr;
}
// 再生する波形データの設定
XAUDIO2_BUFFER buf{};
buf.pAudioData = (BYTE*)pDecodedBuf;
buf.Flags = XAUDIO2_END_OF_STREAM;
buf.AudioBytes = decodedSize;
// 波形データの再生
pSourceVoice->SubmitSourceBuffer(&buf);
pSourceVoice->Start();
return pSourceVoice;
}
これでOpusの読み込みと再生は完了です。
Opusはストリーミング再生をした際に真価を発揮するフォーマットです。
なので今回はオンメモリ再生となっていますが、将来的にはストリーミング再生についても記載していこうかと思います。