カクタスソフトウェア
カクタスソフトウェア
サウンド MIDI マルチメディア アプリケーション

再生処理の流れ

再生関連コマンドには、以下の種類が考えられます。

これらのコマンドを支援するために必要なパラメータを紹介します。

演奏状態

現在の演奏状態を示す変数です。再生中・停止中・ポーズ中などの状態を示します。この変数は、プレイボタンや停止ボタンが2度以上クリックされたとき、不必要な動作が起こらないよう制御するために用います。また画面に演奏中などの表示を行うための問い合わせに利用することもできます。

enum tPlayState
{
    StateStopped,
    StatePaused,
    StateRunning
} PLAYSTATE;
PLAYSTATE   m_playState;

例えば、以下の様な実装を行います。

BOOL Play(void)
{
    if (m_playState == StateRunning)    return FALSE;
    // 演奏開始処理
    m_playState = StateRunning;
    return TRUE;
}

演奏位置

m_dwPlayProgressは、演奏がどこまで進んでいるかを保持します。DirectSoundシステムは、演奏すべき曲の長さを知りません。そのため、この数値とサウンドデータのサイズを比較し、曲が終わったかどうかを判断します。演奏が終わったら、停止コマンドを実行し、ユーザーに曲が終わったことを知らせます。

m_dwLastPlayCursorは、前回の更新でセカンダリーバッファのどの位置まで演奏が進んだかを示すオフセットです。今回の値から差分を求め、m_dwPlayProgressに加算します。

DWORD       m_dwPlayProgress;
DWORD       m_dwLastPlayCursor;

バッファ書き込み位置

m_dwWriteOffsetは、次にセカンダリーバッファに書き込むべきオフセットを示します。この位置からサウンドデータを書き込み、書き込んだサイズだけ加算します。バッファのつなぎ目をまたいだときの処理を忘れずに行います。

DWORD       m_dwWriteOffset;

バッファサイズ

セカンダリバッファ全体のサイズと更新領域のサイズを記録しておきます。これらは、演奏位置やバッファ書き込み位置を更新するときに利用します。

DWORD       m_dwBufferSize;
DWORD       m_dwPageSize;

ループ演奏

ループ再生を支援するときは、ループ区間の始めと終わりの位置を記録します。ループ回数を設定できるようにしたときは、ループ回数と現在ループが何回目かを示す変数が必要です。

DWORD       m_dwFromPos;
DWORD       m_dwThruPos;
long        m_lNumLoop;
long        m_lCurLoop;

Play

演奏を開始します。

バッファを更新するためにタイマー割り込みを使っているときは、タイマーを起動します。

セカンダリーバッファをリングバッファとして運用するので、Play()コマンドにDSBPLAY_LOOPINGフラグを設定します。

BOOL bRestored;
HRESULT hr = RestoreBuffer(&bRestored);
if (FAILED(hr))         return hr;

if (bRestored)
{
    hr = FillBufferWithSound();
    if (FAILED(hr))     return hr;
}
return m_pDSBuffer->Play(
    0,                  // 使用しない
    0,                  // 優先順位
    DSBPLAY_LOOPING);   // フラグ

Stop, Pause

演奏を停止します。

バッファを更新するためにタイマー割り込みを使っているときは、タイマーを停止します。

停止した後、カレント位置を保存すればポーズコマンドとして機能します。また停止した後、巻き戻しを実行すればストップコマンドとして機能します。ポーズからの復帰は、カレント位置から改めて演奏を開始するという実装にしても構いません。

m_pDSBuffer->Stop();

Rewind

巻き戻しを行います。

HRESULT hr = m_pDSBuffer->Stop();
if (FAILED(hr))     return hr;

waveInstance.Rewind();
FillBufferWithSound();  // サウンドバッファの更新

m_dwWriteOffset = 0;
m_pDSBuffer->SetCurrentPosition(0);

Seek

任意の位置から演奏を開始します。

巻き戻しと同じ処理を行います。異なる点は、ウェーブファイルの読み出し位置を指定されたオフセットにすることだけです。

waveInstance.Seek(演奏開始位置);
FillBufferWithSound();  // サウンドバッファの更新

Loop

任意区間をループ再生します。

ループ機能の実装には、いくつか方法が考えられます。

セカンダリーバッファ更新機能にループ機能を付加する

ループ終了位置までサウンドデータを読み出したら、ウェーブファイルの読み出し位置をループ開始位置にシークします。ループ終了位置までに何バイト読み出せば良いかをヒントにすると良いでしょう。

ウェーブファイルサービスクラスにループ機能を付加する

これは、ウェーブファイルサービスクラスをバージョンアップする方法です。サウンドデータ読み出しコマンドで、ループ区間を考慮したサウンドデータを戻します。詳しくはセクション「ウェーブデータの供給」を参照して下さい。

セカンダリーバッファをループ再生する

ループ時間がそれほど長くなければ、ループ区間と同じ長さのセカンダリーバッファを用意する方法があります。ループ区間全体をセカンダリーバッファにセットし、バッファの更新を行わずに演奏します。ループ区間が固定している場合や、もっぱらループ再生が目的の場合に適します。

タイマーコマンドで制御する

ループ終了の時刻になったら、ループ更新サービスが実行される仕組みを作ります。ループ更新サービスでは、以下のコマンドを実行します。

前者3つの実装に比べコマンドによる制御は、ループのつなぎ目が一定しない、無音区間が生じる恐れがある、などの欠点があります。この方法はオーバーヘッドが大きいため短時間区間のループには適しません。

ウェーブ以外のファイルへの対応

ここで用いたウェーブファイルサービスクラスと同じ仕様のサービスクラスを用意すれば、別のファイル形式を演奏することができます。例えばmp3ファイルサービスクラスなどと差し替えれば、mp3ファイルを演奏することができます。mp3ファイルの演奏についてはセクション「Mpeg3ファイルの解析とDirectSoundによる再生プログラム」で解説していますので参照して下さい。

スロー再生と早送り再生

DirectSoundは、スロー再生や早送り再生を支援していません。スロー再生や早送り再生を行いたいときは、別途データ加工を行うプログラムを追加するか、メディアプレーヤーなどの高レベルAPIの利用をお勧めします。

早送りについては、音が飛び飛びになりますが、再生位置をどんどん先送りする方法があります。

ドキュメントの先頭へ

カクタスソフトウェア 技術協力 資料室 資料室の広場 SourceForge.jp お問い合わせ