GetCurrentPosition()!

動的ストリーム再生って色々大変ですの〜´〜`固定サイズバッファってのが曲者で

  1. 固定サイズバッファを使用するときはwavファイルから自分でwaveformatを取得しなくちゃいけない
  2. ループ再生になるから終了位置の確認が大変
  3. Notify()メソッドは自分がセットしたイベント以外にも反応する(ありえん!)
  4. GetCurrentPosition()メソッドは分解能がイマイチ>10ms前後分のとびとびの値が帰ってくる
  5. 多重再生するとポーリングが追いつかない事も´〜`>1msで監視しても駄目なケースがある

ここ(http://mowamowa.p.utmc.or.jp/~amedama/cgi-bin/wiki/wiki.cgi)でみつけたame_wlのソース(http://mowamowa.p.utmc.or.jp/~amedama/data/mowa_player/ame_wl_dev1.lzh)をぱくってポーリング版再生ライブラリつくた〜
メモがわりにSecondaryBufferを監視してバッファの更新する部分をはっとこう^〜^

以下ソースコードなり。


/// <summary>
/// Method: SecondaryBufferを監視してバッファの更新を制御します。
/// </summary>
private void WatchSecondaryBuffer()
{
int playCursorPosition, writeCursorPosition;
int writingSizeUnderWatching, distancePlayCursorToWriteCursor, distanceWriteCursorToNextWriteCursor;

//バッファ更新ループ
while(true)
{
//このインターバルでバッファの更新をするのだ
Thread.Sleep(myBufferCheckingInterval);

sound.GetCurrentPosition(out playCursorPosition, out writeCursorPosition);

// 位置関係のチェック
distancePlayCursorToWriteCursor = writeCursorPosition - playCursorPosition;
if(distancePlayCursorToWriteCursor < 0)
{
distancePlayCursorToWriteCursor += blockSize;
}

distanceWriteCursorToNextWriteCursor = writeCursorPosition - nextWriteCursorPosition;
if(distanceWriteCursorToNextWriteCursor < 0)
{
distanceWriteCursorToNextWriteCursor += blockSize;
}

//こんなことになるのはBuffer Underrunのとき´〜`b
if( distancePlayCursorToWriteCursor > distanceWriteCursorToNextWriteCursor )
{
throw new Exception("Buffer Underrun!\r\n監視間隔を短くしてください");
}

//前回playカーソルが移動した分だけ書き込むのだ
writingSizeUnderWatching = playCursorPosition - nextWriteCursorPosition;
if( writingSizeUnderWatching < 0 )
{
writingSizeUnderWatching += blockSize;
}

// writingSizeUnderWatching == 0
// バッファ内の位置関係が | p(nw) w | であることを示す
// 1: 前回データを転送してから何も再生されていない
// 2: p がバッファを一周して、nw においついた
// 後者は判定不可。ただし再生に支障をきたすので聞いて分かるはず
// Sleep とバッファのサイズの兼ね合いから、正常であればならないはず
//
// writingSizeUnderWatching < 0
// バッファ内の位置関係が | p w nw | であることを示す
// 1: nw から、バッファの先頭に戻って p の直前までの領域に書き込める
// 2: p がバッファを一周して、nw を追い抜いた
// 前者では blockSize 分 writingSizeUnderWatching に加算することで
// | nw p w | の状態と同様にすることが可能
// 後者はコードからは判定不可能。ただし、確実に音がおかしくなる
//
// writingSizeUnderWatching > 0
// バッファ内の位置関係が | nw p w | であることを示す
// 1: nw 〜 p の領域に書き込める
// 2: p がバッファを一周して、nw を追い抜いた

if( writingSizeUnderWatching > 0 )
{
long distance = GetDistance(stream);

if( distance >= writingSizeUnderWatching )
{
//普段の書き込み
sound.Write(nextWriteCursorPosition, stream, writingSizeUnderWatching, LockFlag.None);
}
else
{
//最終書き込み
sound.Write(nextWriteCursorPosition, stream, (int)distance, LockFlag.None);
finalCursorPosition = nextWriteCursorPosition + (int)distance;

//Console.WriteLine("最後のかきこ");
//GetAndPrintSoundCursorPositions();

/*
MemoryStream memStream = new MemoryStream();
memStream.SetLength(writingSizeUnderWatching - (int)distance);
sound.Write(nextWriteCursorPosition + (int)distance, memStream, (int)memStream.Length, LockFlag.None);
memStream.Close();
*/

//waveデータを全て書き終わった
break;
}

//writingSizeUnderWatching = playCursorPosition - nextWriteCursorPositionなので
//ループ1回分のplayカーソルの移動距離になりますの^〜^b
nextWriteCursorPosition = (nextWriteCursorPosition + writingSizeUnderWatching) % blockSize;
}
}

//演奏終了チェックループ
while(true)
{
//このインターバルで演奏終了チェックを行なうのだ
//単一演奏だとGetCurrentPosition()の分解能は10くらい
Thread.Sleep(myStopperCheckingInterval);

sound.GetCurrentPosition(out playCursorPosition, out writeCursorPosition);
//PrintSoundCursorPositions(playCursorPosition, writeCursorPosition);

int finalDistanceWrite = finalCursorPosition - writeCursorPosition;
if(finalCursorPosition <= writeCursorPosition)
{
finalDistanceWrite += blockSize;
}

//minimalBlockSize未満の範囲に入ったらもう終了処理に向かう
//最大±0.02秒くらい誤差が出る´〜`b
if(finalDistanceWrite < minimalBlockSize)
{
break;
}
}

//Console.WriteLine("Stop前");
//GetAndPrintSoundCursorPositions();

sound.Stop();

//Console.WriteLine("Stop後");
GetAndPrintSoundCursorPositions();

/*
//チェック用
byte[] hoge1 = new byte[blockSize];
FileStream hogestream1 = new FileStream("hoge1", FileMode.Create, FileAccess.ReadWrite);
sound.Read(0, hogestream1, blockSize, LockFlag.None);
hogestream1.Close();
*/

}