OggVorbisライブラリをVS2013で使う

OggVorbisはパテントフリーの音声圧縮形式です。
オープンソースである上、MP3よりも一般に音質が良いことで定評があります。

ライブラリの導入も比較的簡単です。
MP3のパテントが切れる頃にはOggVorbisが主流になっているのではないか・・・と勝手に予想しております。

今回はOggVorbisライブラリをVisualStudio2013に導入して使ってみました。

■環境構築

1.ライブラリのダウンロード
OggVorbisのライブラリのダウンロードは以下サイトより行います。

http://www.xiph.org/downloads/

上記サイト内のlibogglibvorbisがOggVorbisを使う上で必要になります。
最新バージョンをダウンロードしてください。

ダウンロードしたら、適当な場所に解凍します。

2.liboggのビルド
ライブラリをVS2013でビルドします。
以下ファイルをVS2013で開きます。

 (展開先フォルダ)libogg-1.3.1win32VS2010libogg_static.sln
 (展開先フォルダ)libogg-1.3.1win32VS2010libogg_dynamic.sln

開いたらソリューション全体をビルドします。
初期状態ではDebugビルドとなっているためDebug版のバイナリがビルドされます。
必要ならReleaseビルドも行います。

ビルドされたバイナリは(展開先フォルダ)libogg-1.3.1win32VS2010Win32以下に生成されます。

3.libvorbisのビルド
liboggと同じようにlibvorbisもビルドを行います。

まず、以下ファイルをVS2013で開きます。

 (展開先フォルダ)libvorbis-1.3.4win32VS2010vorbis_static.sln

開くとソリューションの下に4つプロジェクトがあることが確認できます。
これらのプロジェクトすべてをビルドします。

しかし、このままビルドすると「liboggのパスが無いよ!」と怒られてしまうため、
liboggのパスを設定する必要があります。

プロジェクト各々に対し、「プロパティ」→「構成プロパティ」→「VC++ ディレクトリ」画面を開き、以下パスを設定します。

インクルード ディレクトリ:
 (展開先フォルダ)libogg-1.3.1include

ライブラリ ディレクトリ(Debug版の場合):
 (展開先フォルダ)libogg-1.3.1win32VS2010Win32Debug
ライブラリ ディレクトリ(Release版の場合):
 (展開先フォルダ)libogg-1.3.1win32VS2010Win32Release

上記設定の後、ビルドします。
Debug/Release版両方をビルドする場合は合計8回の設定を行う必要がありますが、根気で頑張って下さい(笑)

3.プロジェクトの設定
ここからは実際にOggVorbisライブラリを使用するための設定になります。
ライブラリを使用するプロジェクトの準備が出来たら、プロジェクトの「プロパティ」→「構成プロパティ」→「VC++ ディレクトリ」を開き、以下パスを設定します。

インクルード ディレクトリ:
 (展開先フォルダ)libogg-1.3.1include
 (展開先フォルダ)libvorbis-1.3.4include

ライブラリ ディレクトリ(Debug版の場合):
 (展開先フォルダ)libogg-1.3.1win32VS2010Win32Debug
 (展開先フォルダ)libvorbis-1.3.4win32VS2010Win32Debug
ライブラリ ディレクトリ(Release版の場合):
 (展開先フォルダ)libogg-1.3.1win32VS2010Win32Release
 (展開先フォルダ)libvorbis-1.3.4win32VS2010Win32Release

また、libcmt.libを除外するために、プロジェクトの「プロパティ」→「構成プロパティ」→「C/C++」→「リンカー」→「コマンド ライン」を選択し、
「追加のオプション(D)」に以下を追加します。

 /NODEFAULTLIB:libcmt.lib

これでビルド時に競合エラーが発生しなくなります。

■OggVorbisを使ってみる
準備が出来たため、簡単なOggVorbisファイルをデコードするプログラムをテストしてみます。
今回はスタティックリンクで使ってみます。

Windowsアプリケーションのプロジェクトを作成し、
以下ソースを丸ごとコピペしてビルドが通れば成功です。

#include <windows.h>
#include <stdexcept>
#include <vorbis/codec.h>
#include <vorbis/vorbisfile.h>

#pragma comment(lib, "libogg_static.lib")
#pragma comment(lib, "libvorbis_static.lib")
#pragma comment(lib, "libvorbisfile_static.lib")

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    OggVorbis_File vf;
    bool isOpened = false;
    char* playBuf = NULL;

    try {
        LPCSTR fileName = "test.ogg";

        // OggVorbisファイルを開く
        if ( ov_fopen(const_cast<lpstr>(fileName), &vf) )
            throw std::runtime_error("ファイルオープンに失敗しました。");

        isOpened = true;

        // OggVorbisファイルの情報を取得する
        vorbis_info *vi = ov_info(&vf, -1);

        if ( vi == NULL )
            throw std::runtime_error("OggVorbisファイルの情報取得に失敗しました。");

        // WAVEFORMATEX構造体へのデータの書き込み
        WAVEFORMATEX wf;
        wf.wFormatTag = WAVE_FORMAT_PCM;
        wf.nChannels = vi->channels;
        wf.nSamplesPerSec = vi->rate;
        wf.nAvgBytesPerSec = vi->rate * vi->channels * 2;
        wf.nBlockAlign = vi->channels * 2;
        wf.wBitsPerSample = 16;
        wf.cbSize = sizeof(WAVEFORMATEX);

        // デコード後のデータサイズの取得
        DWORD decodeSize = static_cast<dword>(ov_pcm_total(&vf, -1)) * vi->channels * 2;


        // 再生用バッファの作成
        playBuf = new char[decodeSize];

        DWORD totalReadSize = 0;
        INT bitstream;
        bool result = true;

        while ( totalReadSize < decodeSize ) {
            // データのデコード
            LONG readSize = ov_read(
                &vf,
                playBuf + totalReadSize,
                decodeSize - totalReadSize,
                0,
                2,
                1,
                &bitstream
                );

            if ( readSize == 0 ) {      // ファイルの終端まで読み込んだ
                result = true;
                break;
            }
            else if ( readSize < 0 ) {  // エラー発生
                result = false;
                break;
            }

            totalReadSize += readSize;
        }


        // ファイル読み込みの成否チェック
        if ( !result )
            throw std::runtime_error("OggVorbisファイルの読み込みに失敗しました。");


        // OggVorbisファイルを閉じる
        ov_clear(&vf);

        // バッファ開放
        delete[] playBuf;


    } catch ( std::exception& e ) {
        if ( isOpened )
            ov_clear(&vf);

        delete[] playBuf;

        MessageBoxA(NULL, e.what(), NULL, MB_OK | MB_ICONERROR);
        return -1;
    }

    MessageBox(NULL, TEXT("OggVorbisファイルのデコードに成功しました。"), TEXT("OK"), MB_OK | MB_ICONINFORMATION);

    return 0;
}

ソリューションディレクトリにtest.oggファイルを置くとファイルを開いてデコードし、デコードに成功すればその旨のメッセージが表示されます。

ライブラリのリファレンスは以下サイトにまとめられています。

http://www.xiph.org/doc/

すべて英語ですが、ここを見て理解できればもうバッチリでしょう。
使い方はワンパターンなので、クラス化して使うのが良いと思います。