第2回 DirectSound(バッファ作成・後処理)


バッファ作成前夜(?)

・なんでか2回目にして新たにファイルの追加が必要みたいです。(汗
こんなことなら最初に書いておけって話やねw
とこれでなんとかなるでしょう♪
↑の2つはWidows上でのファイル操作用のヘッダとライブラリのはずです。よく覚えていませんがなんとかなるでしょう。f(--;

 いきなりなんですが、DirectSoundのバッファ構造はちょっと複雑というか経る過程が長すぎるので1つの音に対してどのようなデータが必要かっていうのを考えておきます。
{
    CHAR                szFName[DSB_FILE_NAME_MAX];         // ファイル名
    LPDIRECTSOUNDBUFFER lpDirectSoundBuffer[DSB_NUM_MAX];   // 音格納バッファ
    INT                 nCurrent;                           // バッファカレント位置
}
やっぱ、こういう書き方駄目かな〜(笑
いきなりデータを示されてもわかんないよね?
でも、さすがに途中で構造体が出てくるのも分かり難いので最初に↑みたいに持っとくんだなぐらいに思っといてくださると良いんですがねw

ファイル操作に関して…

 さすがにいきなりAPIとかが出てきても分かりづらいと思うので、ファイル操作ぐらいのAPIのプロトタイプぐらいは書いおきます。
//      ファイルオープン
//  @param  ファイル名
//  @param  ???(基本的にNULL)
//  @param  フラグ(MMIO_READ etc...)
//  @retval ハンドル    成功
//  @retval NULL        失敗
HMMIO       mmioOpen(LPSTR ,LPMMIOINFO , DWORD);

//      ファイルリード
//  @param  ハンドル
//  @param  読み込み先
//  @param  読み込むサイズ
//  @retval !(-1)       成功(読み込んだサイズ)
//  @retval -1          エラー
LONG        mmioRead(HMMIO, HPSTR, LONG);

//      ファイルライト
//  @param  ハンドル
//  @param  書き込みデータ先
//  @param  サイズ
//  @retval !(-1)       成功(書き込んだサイズ)
//  @retval -1          エラー
LONG        mmioWrite(HMMIO, const char*, LONG);

//      ファイルシーク
//  @param  ハンドル
//  @param  シーク位置オフセット
//  @param  シーク方法
//  @retval !(-1)       成功
//  @retval -1          エラー
LONG        mmioSeek(HMMIO, LONG, int);

//      ファイルクローズ
//  @param  ハンドル
//  @param  フラグ(0でOK)
//  @retval 0           正常終了
//  @retval !(0)        異常終了
MMRESULT    mmioClose(HMMIO, UINT);
 あ〜、やべ〜今更ながらこんなことヘルプ見りゃあ済むのにわざわざ書いてたからどんどん時間が過ぎてる気が…。
次からは飛ばしとこうw

まだなのかバッファ作成!?

 はい、実はまだなんです(■.■)y--oO
ホント一服したくなります(管理人は吸いませんがw
バッファはデータはサウンドカードさんが余裕があればサウンドカード上に置いてくれて余裕が無いときは普通にメモリに保存されるらしいんですが、何せ最初のデータはファイルになってるためどんだけメモリ必要なのかサッパリ分かりません(爆
だからぁ〜、最初にファイルのヘッダ読まなくちゃならんのだよチミ→
なんか段々壊れてきたが木の精です。気のせいではありません(ぇ

じゃあ、面倒なのは嫌いなのでサクッ(?)とプログラムやっちゃいましょうか(ぇ
あ〜、その前にプロトタイプだよね☆なんかあれ書くとちゃんとやった感じになるから(笑
// DirectSoundBuffer作成
INT     CreateDSB(DSB_DATA* pDSB);

// DirectSoundBuffer後処理
void    ReleaseDSB(DSB_DATA* pDSB);
まぁ、いかにありきたりかは皆さんがお分かりでしょう(汗
私がどんだけ考えらずに作っているか…(ボソボソ
アルゴリズムも含め考えてません(殴
まぁ、そこらへんは後々できればよいかな〜ってことで…。
少なくとも関数にしておけばなんとかなるでしょう。

やっとソースできました♪

 さすがに酒飲みながら組んだので微妙かもしれませんがご勘弁を(笑

INT CreateDSB(DSB_DATA* pDSB);

    INT             ret     = 0;        // return値
    INT             i;
    HMMIO           hmmio    = NULL;    // ファイルハンドル
    MMCKINFO        ciParent, ciSub;    // チャンク操作作業用
    WAVEFORMATEX    wavfmtex;           // WAVEデータ形式読み込み用
    
    DSBUFFERDESC    dssc;               // 作業用
    HRESULT         hr;                 // メソッド結果
    
    CHAR*           pSoundMem   = NULL; // サウンドカードの格納場所
    CHAR*           pMainMem    = NULL; // メインメモリの格納場所
    DWORD           soundLen;           // サウンドカードの格納量
    DWORD           mainLen;            // メインメモリの格納量
    
    // ファイルオープン
    hmmio = mmioOpen(pDSB->szFName, NULL, MMIO_READ);
    if (hmmio == NULL) {
        ret = -1;
        goto DS_CREATEDSB_ERR;
    }
    
    // チャンクヘッダ読み込み
    ciParent.fccType = mmioFOURCC('W', 'A', 'V', 'E');
    if (mmioDescend(hmmio, &ciParent, NULL, MMIO_FINDRIFF) != 0) {
        ret = -2;
        goto DS_CREATEDSB_ERR;
    }
    
    // チャンクfmt へ入る
    ciSub.ckid = mmioFOURCC('f', 'm', 't', ' ');
    if (mmioDescend(hmmio, &ciSub, &ciParent, MMIO_FINDCHUNK) != 0) {
        ret = -3;
        goto DS_CREATEDSB_ERR;
    }
    
    // WAVEFORMAT構造体のサイズチェック
    if (ciSub.cksize == 0) {
        ret = -4;
        goto DS_CREATEDSB_ERR;
    }
    
    // WAVE形式読み込み
    if (mmioRead(hmmio, (HPSTR)&wavfmtex, sizeof(PCMWAVEFORMAT)) == -1) {
        ret = -5;
        goto DS_CREATEDSB_ERR;
    }
    
    // チャンクから出る
    if (mmioAscend(hmmio, &ciSub, 0) != 0) {
        ret = -6;
        goto DS_CREATEDSB_ERR;
    }
    
    // チャンクdataへ入る
    ciSub.ckid = mmioFOURCC('d', 'a', 't', 'a');
    if (mmioDescend(hmmio, &ciSub, &ciParent, MMIO_FINDCHUNK) != 0) {
        ret = -7;
        goto DS_CREATEDSB_ERR;
    }
    
    // データサイズチェック
    if (ciSub.cksize == 0) {
        ret = -8;
        goto DS_CREATEDSB_ERR;
    }
    
    // DSBUFFERDESC構造体初期化
    ZeroMemory(&dssc, sizeof(dssc));
    dssc.dwSize         = sizeof(dssc);
    dssc.dwFlags        = DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_STATIC;
    dssc.dwBufferBytes  = ciSub.cksize;
    dssc.lpwfxFormat    = &wavfmtex;
    
    // DirectSoundBuffer作成
    hr = g_lpDirectSound->CreateSoundBuffer(&dssc,
                &(pDSB->lpDirectSoundBuffer[0]), NULL);
    if (FAILED(hr)) {
        ret = -9;
        goto DS_CREATEDSB_ERR;
    }
    
    // バッファロック
    hr = pDSB->lpDirectSoundBuffer[0]->Lock(0, ciSub.cksize,
                (void**)(&pSoundMem), &soundLen,
                (void**)(&pMainMem), &mainLen, 0);
    if (FAILED(hr)) {
        ret = -10;
        goto DS_CREATEDSB_ERR;
    }
    
    // WAVEデータ読み込み
    if (mmioRead(hmmio, pSoundMem, soundLen) == -1) {
        ret = -11;
        goto DS_CREATEDSB_ERR;
    }
    
    // メインメモリへの読み込み
    if (mainLen != 0) {
        if (mmioRead(hmmio, pMainMem, mainLen) == -1) {
            ret = -12;
            goto DS_CREATEDSB_ERR;
        }
    }
    
    // 複数のバッファ作成
    for (i = 1; i < DSB_NUM_MAX; i++) {
        hr = g_lpDirectSound->DuplicateSoundBuffer(pDSB->lpDirectSoundBuffer[0],
                    &(pDSB->lpDirectSoundBuffer[i]));
        if (FAILED(hr)) {
        	ret = -13;
        	goto DS_CREATEDSB_ERR;
        }
    }
    
    
DS_CREATEDSB_ERR:
    
    // バッファアンロック
    hr = pDSB->lpDirectSoundBuffer[0]->Unlock(pSoundMem, soundLen,
                pMainMem, mainLen);
    if (FAILED(hr)) {
        ret = -13;
    }
    
    // ファイルクローズ
    if (hmmio != NULL) {
        mmioClose(hmmio, 0);
    }
    
    return ret;
}
エラー時の終わり方を考えていたらこうなってしまいました…。
致し方ないと妥協w

void ReleaseDSB(DSB_DATA* pDSB);

{
    INT	i;

    for (i = 0; i < DSB_NUM_MAX; i++) {
        if (pDSB->lpDirectSoundBuffer[i] != NULL) {
            pDSB->lpDirectSoundBuffer[i]->Release();
        }
    }
}
複数バッファ作ったので一応全部解放してます。
んで、今回のサンプルはこちらです。
なんか考えてみたらバッファ作成とWAVE読み込みは一緒だったみたいです。こってり忘れてました。
したがって、次回からDirectDrawでも…。
再生なんて
DirectSoundBuffer->Play(0, 0, 0);
でおしまいだろ(ぉぃ