ホーム > DirectMusic > OggVorbisの再生

OggVorbisの再生

目次

  1. OggVorbisとは
  2. 環境設定
  3. ヘッダのインクルードとライブラリのリンク
  4. OggVorbisの情報を取得
  5. メモリの確保
  6. Waveへ変換
  7. ヘッダの書き込み
  8. 終了処理
  9. DirectMusic / 初期化
  10. DirectMusic / 読み込み
  11. DirectMusic / 再生
  12. DirectMusic / 終了処理
  13. サンプル

OggVorbisとは

OggVorbisとはMP3やWMAなどと同じ音声圧縮技術の1つです。この音声圧縮技術の中で現在最も普及しているのはMP3です。しかしMP3は、個人などが非営利目的で利用する場合は無償で利用できるのですが、商用目的で利用した場合、特許ライセンス料を支払わなければなりません。

そこで開発されたのがOggVorbisです。この音声圧縮技術は特許ライセンスを必要とせず、無償で利用できます。また、一般にMP3よりも高音質で高圧縮といわれています。今回はこのOggVorbisを、DirectMusicで利用する方法を紹介します。

環境設定

OggVorbisをWaveに変換するには、OggVorbisWin32SDKが必要です。Vorbis.comで入手できます。入手したファイルを解凍し、適当な場所に展開して、インクルードファイルとライブラリファイルのパスを設定します。下記の例はCドライブに展開した時の例です。

サンプル4
インクルードファイルの設定
サンプル5
ライブラリファイルの設定

ヘッダのインクルードとライブラリのリンク

OggVorbisをWaveへ変換(デコード)するために「vorbis」フォルダにある「codec.h」「vorbisfile.h」をインクルードし「ogg_static.lib」「vorbis_static.lib」「vorbisfile_static.lib」をリンクします。そして、リンクタブにあるプロジェクトオプションに「/nodefaultlib:"LIBCMT"」を追加します。

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

OggVorbisの情報を取得

OggVorbisのファイル情報は「ov_open()」で取得します。第1引数には「fopen()」で取得したファイルポインタ、第2引数にはOggVorbis_File構造体のポインタをします。OggVorbisの情報は取得は「ov_info()」で取得します。第1引数にはOggVorbis_File構造体のポインタを指定します。

// デコードするファイル名
char szName[] = "bgm.ogg";

// ファイルを開く
FILE *lpFile = fopen( szName, "rb" );
if( lpFile == NULL )  return FALSE;

// OggVorbisのファイル情報を取得
OggVorbis_File vf;
if( ov_open( lpFile, &vf, NULL, 0 ) < 0 )
{
  fclose( lpFile );
  return FALSE;
}

// OggVorbisの情報を取得
vorbis_info *vi = ov_info( &vf, -1 );
if( vi == NULL )
{
  ov_clear( &vf );
  return FALSE;
}

メモリの確保

Waveのヘッダを格納する構造体を用意します。

typedef struct{
  char         cRIFF[4];
  int          iSizeRIFF;
  char         cType[4];
  char         cFmt[4];
  int          iSizeFmt;
  WAVEFORMATEX WaveFmt;
  char         cData[4];
  int          iSizeData;
} WAVEFILEHEADER;

Waveのヘッダを格納する構造体のサイズを取得します。「sizeof(WAVEFILEHEADER)」とすると、実際のサイズより大きくなるので、下記のように1つずつサイズを取得します。

WAVEFILEHEADER wh;
LONG lWHSize = sizeof(wh.cRIFF)    + sizeof(wh.iSizeRIFF) +
               sizeof(wh.cType)    + sizeof(wh.cFmt)      +
               sizeof(wh.iSizeFmt) + sizeof(wh.WaveFmt)   +
               sizeof(wh.cData)    + sizeof(wh.iSizeData);

OggVorbisをデコードした時の大きさを求めて、それにヘッダサイズを足し、デコードしたWaveを格納するメモリを確保します。演奏時間は「ov_time_total()」で取得します。

INT iWord = 2;  // 量子化バイト数(1 or 2)

LONG  lDataSize = (LONG)ceil( 
  vi->channels * vi->rate * ov_time_total( &vf,-1 ) * iWord 
);

CHAR* lpWaveData = new CHAR[ lDataSize + lWHSize ];
if( lpWaveData == NULL )
{
  ov_clear( &vf );
  return FALSE;
}

Waveへ変換

OggVorbisをWaveへ変換(デコード)するには「ov_read()」を使用します。第1引数にOggVorbis_File構造体のポインタ、第2引数にバッファのポインタ、第3引数にバッファサイズ、第4引数に0、第5引数に量子化バイト数、第6引数に1、第7引数にint型変数へのポインタを指定します。戻り値はバッファに書き込まれたバイト数です。

INT  iCurrentSection;
LONG lWriteSize;
LONG lReadSize = 0;
while( 1 )
{
  // デコード
  lWriteSize = ov_read( &vf, lpWaveData + lReadSize + lWHSize,
                        lDataSize - lReadSize, 0, iWord, 1,
                        &iCurrentSection );

  // デコード終了
  if( ! lWriteSize )
  {
    break;
  }

  // エラー
  else if ( lWriteSize < 0 )
  {
    /* #define SAFE_RELEASE(p) if(p){p->Release();p=NULL;} */
    SAFE_DELETE( lpWaveData );
    ov_clear( &vf );
    return FALSE;
  }

  // 全てデコードできなかった
  else
  {
    lReadSize += lWriteSize;
  }
}

ヘッダの書き込み

デコードしたWaveのヘッダをメモリ上のヘッダの書き込みます。

// ヘッダの初期化
memcpy( wh.cRIFF, "RIFF", 4 );
wh.iSizeRIFF = lWHSize + lReadSize - 8;
memcpy( wh.cType, "WAVE", 4 );
memcpy( wh.cFmt, "fmt ", 4 );
wh.iSizeFmt = sizeof(WAVEFORMATEX);
wh.WaveFmt.cbSize          = sizeof(WAVEFORMATEX);
wh.WaveFmt.wFormatTag      = WAVE_FORMAT_PCM;
wh.WaveFmt.nChannels       = vi->channels;
wh.WaveFmt.nSamplesPerSec  = vi->rate;
wh.WaveFmt.nAvgBytesPerSec = vi->rate * vi->channels * iWord;
wh.WaveFmt.nBlockAlign     = vi->channels * iWord;
wh.WaveFmt.wBitsPerSample  = iWord * 8;
memcpy( wh.cData, "data", 4 );
wh.iSizeData = lReadSize;

// メモリ上のヘッダの書き込み
int iSize = 0;
memcpy(*lpWaveData,         &wh.cRIFF,     sizeof(wh.cRIFF));
iSize += sizeof(wh.cRIFF);
memcpy(*lpWaveData + iSize, &wh.iSizeRIFF, sizeof(wh.iSizeRIFF));
iSize += sizeof(wh.iSizeRIFF);
memcpy(*lpWaveData + iSize, &wh.cType,     sizeof(wh.cType));
iSize += sizeof(wh.cType);
memcpy(*lpWaveData + iSize, &wh.cFmt,      sizeof(wh.cFmt));
iSize += sizeof(wh.cFmt);
memcpy(*lpWaveData + iSize, &wh.iSizeFmt,  sizeof(wh.iSizeFmt));
iSize += sizeof(wh.iSizeFmt);
memcpy(*lpWaveData + iSize, &wh.WaveFmt,   sizeof(wh.WaveFmt));
iSize += sizeof(wh.WaveFmt);
memcpy(*lpWaveData + iSize, &wh.cData,     sizeof(wh.cData));
iSize += sizeof(wh.cData);
memcpy(*lpWaveData + iSize, &wh.iSizeData, sizeof(wh.iSizeData));

終了処理

OggVorbisのファイル情報を「ov_clear()」でクリアします。この関数でファイルポインタを閉じてくれるので「fclose()」は使用しません。

ov_clear( &vf );

DirectMusic / 初期化

MidiとWaveの再生 / 初期化と同じ処理をします。

DirectMusic / 読み込み

IDirectMusicSegment8を先程デコードしたWaveから作成します。

// 変換したWaveのサイズ
LONG lWaveSize = lReadSize + lWHSize;

// パラメータを設定
DMUS_OBJECTDESC desc;
ZeroMemory( &desc, sizeof(DMUS_OBJECTDESC) );
desc.dwSize      = sizeof(DMUS_OBJECTDESC);
desc.dwValidData = DMUS_OBJ_CLASS |     // guidClass有効
                   DMUS_OBJ_MEMORY;     // メモリ内からセグメント作成
desc.guidClass   = CLSID_DirectMusicSegment;
desc.pbMemData   = (LPBYTE)lpWaveData;  // メモリ内のデータへのポインタ
desc.llMemLength = lWaveSize;           // メモリ内のデータのサイズ

// セグメント作成
IDirectMusicSegment8* g_lpSegment = NULL;
g_lpLoader->GetObject( &desc, IID_IDirectMusicSegment8, (LPVOID*)g_lpSegment );

DirectMusic / 再生

MidiとWaveの再生 / 再生と同じ処理をします。

DirectMusic / 終了処理

MidiとWaveの再生 / 終了処理と同じ処理をし、確保したメモリを解放します。

/* #define SAFE_RELEASE(p) if(p){p->Release();p=NULL;} */
SAFE_DELETE( lpWaveData );

サンプル

ここまでの作業でOggVorbisをWaveに変換することができます。DirectMusicでの再生例のソースを置いておきます。



Last Update 2006/11/24.
Copyright © 2002-2004 Toru All Rights Reserved.
inserted by FC2 system