当方、現在DirectXを勉強中の者です。
さて表題の件についてなのですが、
アプリケーションがウィンドウモードの時に、位置を変えようとタイトルバーを持ってドラッグさせた際
BGMが思ったように再生されない問題に突き当たっています。
具体的には、バッファの更新が為されない、つまりドラッグ中は延々と更新されないバッファ内をループし続けているというものです。
四聖龍神録や東方Project作品などではこの症状は見られず、曲ループもドラッグ中の再生も問題はありません。
ドラッグ時間が短ければ問題はないのですが、長くなってくると曲の再生に影響が出る可能性があるので不安要素は消しておきたかったのですが、
どうにも解決されないため質問いたしました。
DirectSound/Notify使用 ->実質自己検証なし。ネットからDLしてきたサンプルではドラッグを離すと位置修正がかかるが、ドラッグ中はバッファ内ループ。
DirectSound/Notify不使用 ->現在暫定的に使っている再生方法。ドラッグ中は更新されないバッファ内でループ再生を続けている。
XAudio ->ポーリング方式で検証。再生が一時的に止まる。ドラッグを離すとその地点から再開する。
PlatformSDK(DirectShow) ->ドラッグ中も問題なく再生は続く。ただし曲ループの際に音が若干途切れる。
以上が当方で現在確認できている状態です。
即ち、DirectShowではループの際に音が途切れる以外は問題がなく、
逆にそれ以外ではドラッグ中に問題が起きる以外は正常であるということです。こちらでは曲ループはスムーズにいきます。
こんな場合、解決策はあるのでしょうか。
どなたか判る方いましたら、ご教授のほどお願いします。
ちなみにBGMはWAVファイルを使っています。
一応現在使っているバッファの書き換えプログラムも併せて記載しておきます。
bool Music::GetCurrentPos(){
HRESULT hr;
const static long sign = (16 / 8) * 2 * 44100 * 2 / 4; //確保するバッファは2秒分、それを4分割
static long bufaddr = sign * 4; //予めバッファに読み込んである分を加算
DWORD pos,sw;
static bool flag[4] = {false,false,false,true}; //書き換えられるかのフラグ
LPVOID lpWrite[2] = {NULL};
DWORD dwLength[2] = {NULL};
pSndBuf->GetCurrentPosition(&pos,NULL); //現在のカーソル位置を取得
sw = pos / sign; //カーソルがあるブロックを計算
switch(sw){
case 0:
if(flag[3] == false){ //書き換えられるなら
hr = pSndBuf->Lock(sign * 3,sign,&lpWrite[0],&dwLength[0],&lpWrite[1],&dwLength[1],0);
if(DSERR_Check(hr))break; //エラーが出たらすぐに処理から抜ける
fread_s(lpWrite[0],dwLength[0],dwLength[0],1,fh);
if(lpWrite[1] != NULL)fread_s(lpWrite[1],dwLength[1],dwLength[1],1,fh);
pSndBuf->Unlock(lpWrite[0],dwLength[0],lpWrite[1],dwLength[1]);
flag[2] = false; flag[3] = true; //書き換えたブロックを上書き不能にしてその1コ前のブロックに許可を出す
bufaddr += sign; //ブロック分を加算
}
break;
default:
if(flag[sw - 1] == false){
hr = pSndBuf->Lock(sign * (sw - 1),sign,&lpWrite[0],&dwLength[0],&lpWrite[1],&dwLength[1],0);
if(DSERR_Check(hr))break;
fread_s(lpWrite[0],dwLength[0],dwLength[0],1,fh);
if(lpWrite[1] != NULL)fread_s(lpWrite[1],dwLength[1],dwLength[1],1,fh);
pSndBuf->Unlock(lpWrite[0],dwLength[0],lpWrite[1],dwLength[1]);
flag[(((sw - 2) == -1) ? 3 : sw - 2)] = false; flag[sw - 1] = true;
bufaddr += sign;
}
break;
}
if(bufaddr + sign > (long)EndPos){ //現在位置+ブロック分が曲の終端を超えていたら
fseek(fh,-((long)(EndPos - LoopPos)),SEEK_CUR); //ファイル位置をループ地点まで戻す
bufaddr -= (EndPos - LoopPos);
}
return true;
}
※2 DSERR_Check関数はどのエラーに該当するか調べてメッセージボックスで表示する自作関数です。