こんなとこでいいかな〜^〜^

Notify()&GetCurrentPosition()両方方式(id:parlin:20051216)でライブラリかきかき完了。多重再生もおっけだし、これで〆かな^〜^
以下ソースコードなり。


/// <summary>
/// サウンドクラスDSoundWrapper用の列挙体です。
/// </summary>
#region "Enums:"
/// <summary>
/// 再生セッティングフラグです。
/// </summary>
//フラグとして扱うときはフラグ属性をつける!
[Flags()]
public enum SoundPlaySettings : int
{
None = 0x0,
PlaySync = 0x1,
PlayAsync = 0x2,
PlayWithExternalFile = 0x10,
PlayWithEmbeddedFile = 0x20
}

/// <summary>
/// サウンドバッファ位置の列挙体です。
/// </summary>
public enum SoundBufferPosition : int
{
FirstHalf = 0x0,
SecondHalf = 0x1
}

/// <summary>
/// イベントシグナルの列挙体です。
/// </summary>
public enum EventSignal : int
{
OffsetStart = 0x0,
OffsetHalfBufferSize = 0x1,
OffsetStop = 0x2
}
#endregion

/// <summary>
/// サウンドクラスDSoundWrapperです。
/// </summary>
public class DSoundWrapper
{
/// <summary>
/// フィールドです。
/// </summary>
#region "Field:"
//DirectSound再生用
Device device;
BufferDescription desc;
SecondaryBuffer sound;
//waveファイル用ストリーム
Stream stream;
//waveファイルのフォーマット
WaveFormat wFormat;
//waveDataの情報
int waveDataSize;
long waveDataStartPosition;

//バッファは何秒分?
const int BufferSecond = 2;
//全&半バッファのサイズ
int FullBufferSize;
int HalfBufferSize;

//監視スレッドを別スレッドにする為のdelegate
//同期監視メソッドのポインタ記録に使用する
delegate void WatcherDelegate();

//再生中であるかどうかの通知用
AutoResetEvent[] autoEvents;
int numberOfAutoEvents;
int numberOfSoundBufferPosition;
BufferPositionNotify[] myBufferPositionNotify;
Notify myDirectSoundNotify;
bool lastWriteDone;
bool stopperFlag;
SoundBufferPosition myNextSoundBufferPosition;
int playCursorPosition, writeCursorPosition;

const string myResourceFileName = "DSoundWrapperException";
ResourceManager stringManager;
#endregion

/// <summary>
/// コンストラクタです。
/// (外部or埋め込みの)ファイルからWaveデータを読み込み、再生します。
/// 再生終了後リソースは破棄します。
/// </summary>
#region "Constructor:"
public DSoundWrapper(Control myControl, string soundFileName, SoundPlaySettings soundPlaySettings)
{
//現在実行中のアセンブリを取得
Assembly thisExe = Assembly.GetExecutingAssembly();
string assemblyName = thisExe.GetName().Name;
stringManager = new ResourceManager(assemblyName + "." + myResourceFileName, thisExe);

Console.WriteLine( "サウンドフラグは、{0} です。", soundPlaySettings );
Console.WriteLine( "サウンドファイルは、{0} です。", soundFileName );

//SecondaryBuffer作成
//外部ファイルから?
if((soundPlaySettings & SoundPlaySettings.PlayWithExternalFile) != SoundPlaySettings.None)
{
//外部ファイルからバッファ作成
stream = new FileStream(soundFileName, FileMode.Open, FileAccess.Read, FileShare.Read);
}
else
{
//埋め込みファイルからバッファ作成
//埋め込みファイルのストリームを取得
stream = thisExe.GetManifestResourceStream(assemblyName + "." + soundFileName);
}

//waveファイルの情報をstreamから取得じゃ
GetWaveFormatFromStream(stream, out wFormat, out waveDataSize, out waveDataStartPosition);

//バッファサイズを確定
FullBufferSize = wFormat.AverageBytesPerSecond * BufferSecond;
HalfBufferSize = FullBufferSize / 2;

//Device取得
device = new Device();
device.SetCooperativeLevel(myControl, CooperativeLevel.Normal);
//BufferDescription設定
desc = new BufferDescription(wFormat);
desc.ControlPan = true;
//バッファ内でのポジション通知アリ
desc.CanGetCurrentPosition = true;
//Notify通知アリ
desc.ControlPositionNotify = true;
//フォーカスにかかわらず音を出そう
desc.GlobalFocus = true;
desc.BufferBytes = FullBufferSize;

//ストリームからバッファ作成
sound = new SecondaryBuffer(desc, device);

//待機ハンドルを使ってイベント処理しますかの
autoEvents = new AutoResetEvent[] {new AutoResetEvent(false), new AutoResetEvent(false), new AutoResetEvent(false)};
//イベントの数はautoEvent.Length個ですの
numberOfAutoEvents = autoEvents.Length;
myBufferPositionNotify = new BufferPositionNotify[numberOfAutoEvents];

//SoundBufferPositionの数は(イベント数 - 1)ですの
numberOfSoundBufferPosition = numberOfAutoEvents - 1;

//再生バッファポジションが先頭
myBufferPositionNotify[(int)EventSignal.OffsetStart].Offset = 0;
myBufferPositionNotify[(int)EventSignal.OffsetStart].EventNotifyHandle = autoEvents[0].Handle;
//再生バッファポジションが半分の位置
myBufferPositionNotify[(int)EventSignal.OffsetHalfBufferSize].Offset = HalfBufferSize;
myBufferPositionNotify[(int)EventSignal.OffsetHalfBufferSize].EventNotifyHandle = autoEvents[1].Handle;
//再生バッファポジションが最終の位置(非ループ)もしくは停止の場合
myBufferPositionNotify[(int)EventSignal.OffsetStop].Offset = (int)PositionNotifyFlag.OffsetStop;
myBufferPositionNotify[(int)EventSignal.OffsetStop].EventNotifyHandle = autoEvents[2].Handle;

//通知メソッドにセットじゃ
myDirectSoundNotify = new Notify(sound);
myDirectSoundNotify.SetNotificationPositions(myBufferPositionNotify);

//チェック用
//Console.WriteLine("呼び出しスレッド:" + Thread.CurrentThread.Name);

//waveデータの先頭位置にシークじゃ
stream.Seek(waveDataStartPosition, SeekOrigin.Begin);

/*
//チェック用
double playTime = (double)waveDataSize / wFormat.AverageBytesPerSecond;
int finalPosition = waveDataSize%HalfBufferSize;
int hoge = ((int)Math.Floor((double)waveDataSize / HalfBufferSize) + 1)%2;
int finalBlockPosition = hoge * HalfBufferSize;

Console.WriteLine("playTime = {0}; finalPosition = {1:x}; finalBlockPosition = {2:x}", playTime, finalPosition, finalBlockPosition);
*/

if(waveDataSize > HalfBufferSize)
{
//waveのデータサイズが大きいので固定バッファにしてループ演奏しよう
//とりあえずバッファサイズの半分書き込む
sound.Write(0, stream, HalfBufferSize, LockFlag.None);
//最終書き込みではないのです
lastWriteDone = false;
//固定バッファサイズなのでループ演奏
sound.Play(0, BufferPlayFlags.Looping);
}
else
{
//waveのデータサイズが小さい(HalfBufferSize未満)のでデータサイズ分書き込み
sound.Write(0, stream, waveDataSize, LockFlag.None);
//残りの部分を無音にする
FillBufferWithSilence(sound, waveDataSize, HalfBufferSize - waveDataSize);
//最終書き込みしましたぞ
lastWriteDone = true;
//ループするほどデータはないので非ループ演奏
sound.Play(0, BufferPlayFlags.Default);
}

//次に書き込む位置を指定
myNextSoundBufferPosition = SoundBufferPosition.SecondHalf;

//再生フラグは同期?
if((soundPlaySettings & SoundPlaySettings.PlaySync) != SoundPlaySettings.None)
{
//同期でした
WatchSync();
}
else
{
//非同期でした
WatchAsync();
}

}
#endregion

/// <summary>
/// メソッドです。
/// </summary>
#region "Method:"
/// <summary>
/// Method: waveフォーマットのチャンクを読み込みます。
/// </summary>
/// <param name="reader"></param>
/// <returns></returns>
static private string ReadChunk(BinaryReader reader)
{
byte[] chunk = new byte[4];
reader.Read(chunk, 0, chunk.Length);
return System.Text.Encoding.ASCII.GetString(chunk, 0, chunk.Length);
}

/// <summary>
/// Method: Streamからwaveフォーマットを取得します。
/// </summary>
/// <param name="stream"></param>
/// <param name="wFormat"></param>
/// <param name="waveDataSize"></param>
/// <param name="waveDataStartPosition"></param>
private void GetWaveFormatFromStream(Stream stream, out WaveFormat wFormat, out int waveDataSize, out long waveDataStartPosition)
{
//streamの先頭に情報が書いてあるんだな
stream.Seek(0, SeekOrigin.Begin);

BinaryReader RiffReader = new BinaryReader(stream);

//"RIFF"
if(ReadChunk(RiffReader) != "RIFF")
{
throw new WaveFormatException(stringManager.GetString("NoRiff"));
}
//(ファイルのバイト数)-8の数字が書いてある
RiffReader.ReadInt32();
//"WAVE"
if (ReadChunk(RiffReader) != "WAVE")
{
throw new WaveFormatException(stringManager.GetString("NoWave"));
}
//"fmt "
if (ReadChunk(RiffReader) != "fmt ")
{
throw new WaveFormatException(stringManager.GetString("NoFmt"));
}
//WaveFormat情報のバイト数
int lengthWaveFormatInformation = RiffReader.ReadInt32();
long positionWaveFormatInformation = stream.Position;
long positionNextToWaveFormatInformation = positionWaveFormatInformation + (long)lengthWaveFormatInformation;
//Console.WriteLine("WaveFormat情報のバイト数: " + lengthWaveFormatInformation.ToString());

//WaveFormat情報を順次セット
wFormat = new WaveFormat();
wFormat.FormatTag = (WaveFormatTag)RiffReader.ReadInt16();
wFormat.Channels = (short)RiffReader.ReadInt16();
wFormat.SamplesPerSecond = (int)RiffReader.ReadInt32();
wFormat.AverageBytesPerSecond = (int)RiffReader.ReadInt32();
wFormat.BlockAlign = (short)RiffReader.ReadInt16();
wFormat.BitsPerSample = (short)RiffReader.ReadInt16();
//チェック用
//Console.WriteLine(wFormat.ToString());

stream.Seek(positionNextToWaveFormatInformation, SeekOrigin.Begin);

while(GetDistance(stream) >= 0 && ReadChunk(RiffReader) != "data")
{
}
if (GetDistance(stream) < 0)
{
throw new WaveFormatException(stringManager.GetString("NoData"));
}

waveDataSize = RiffReader.ReadInt32();
waveDataStartPosition = stream.Position;

if(wFormat.FormatTag != WaveFormatTag.Pcm)
{
throw new WaveFormatException(stringManager.GetString("OnlyPcm"));
}
//忘れがちなので、streamの先頭に戻っておく
stream.Seek(0, SeekOrigin.Begin);
}

/// <summary>
/// Method: Streamの現在位置と終了位置との距離を計算します。
/// </summary>
/// <returns></returns>
static private long GetDistance(Stream myStream)
{
return myStream.Length - myStream.Position;
}

/// <summary>
/// Method: 同期監視を行ないます。
/// </summary>
private void WatchSync()
{
string currentThreadName = Thread.CurrentThread.Name;
//Console.WriteLine("呼び出されスレッド:" + currentThreadName);

//バッファ監視
WatchSecondaryBuffer();
}

/// <summary>
/// Method: 非同期監視を行ないます。
/// 別スレッドでWatchSync()を動作させます。
/// </summary>
private void WatchAsync()
{
StartWatcherThread(new WatcherDelegate(WatchSync));
}

/// <summary>
/// Method: 監視スレッドを作成し実行します。
/// </summary>
/// <param name="watcherDelegate"></param>
static private void StartWatcherThread(WatcherDelegate watcherDelegate)
{
System.Threading.Thread t =
new System.Threading.Thread(
new System.Threading.ThreadStart(watcherDelegate));
t.IsBackground = true;
t.Name = "ワーカ君";
t.Start();
}

/// <summary>
/// Method: SecondaryBufferを監視してバッファの更新を制御します。
/// </summary>
private void WatchSecondaryBuffer()
{
try
{
while (true)
{
EventSignal soundEventSignal = (EventSignal)WaitHandle.WaitAny(autoEvents);
//チェック用
//Console.WriteLine("case {0}", soundEventSignal);

switch (soundEventSignal)
{
//再生バッファポジションが先頭
case EventSignal.OffsetStart:
//再生バッファポジションがバッファサイズの半分の位置
case EventSignal.OffsetHalfBufferSize:
//このイベントがこのインスタンスが生成したものかチェックしなくては!
//現在位置の取得
sound.GetCurrentPosition(out playCursorPosition, out writeCursorPosition);
//GetCurrentPosition()の書き込みカーソルによる現在位置
SoundBufferPosition mySoundBufferPositionByGetCurrentPosition = (SoundBufferPosition)(writeCursorPosition / HalfBufferSize);
//今回通知があった位置
SoundBufferPosition mySoundBufferPositionBySoundEventSignal = (SoundBufferPosition)((int)soundEventSignal);
//次に書き込む位置と現在の位置の距離を計測
int PositionDistance = (myNextSoundBufferPosition - mySoundBufferPositionByGetCurrentPosition);
if(PositionDistance < 0)
{
PositionDistance += numberOfSoundBufferPosition;
}

/*
//チェック用
Console.WriteLine("mySoundBufferPositionByGetCurrentPosition {0}", mySoundBufferPositionByGetCurrentPosition);
Console.WriteLine("mySoundBufferPositionBySoundEventSignal {0}", mySoundBufferPositionBySoundEventSignal);
Console.WriteLine("myNextSoundBufferPosition {0}", myNextSoundBufferPosition);
*/

//シグナルイベントによる位置とGetCurrentPosition()による位置が等しい&
//次の書き込み位置とは距離が1つ離れているならば、このインスタンス作成のイベントが通知された事が確定する
if(mySoundBufferPositionByGetCurrentPosition == mySoundBufferPositionBySoundEventSignal &&
PositionDistance == 1)
{
if(stopperFlag == true)
{
sound.Stop();
}
else
{
SoundBufferPosition mySoundBufferPosition = myNextSoundBufferPosition;
//サウンドバッファ書き込み
SoundBufferWrite(mySoundBufferPosition);
//次に書き込む位置は今回の位置の1つ先
//固定バッファをループして使用しているので書き込む位置もループを考慮
myNextSoundBufferPosition = (SoundBufferPosition)(((int)mySoundBufferPosition + 1) % numberOfSoundBufferPosition);
}
}
break;
//再生バッファポジションが最終の位置or停止の場合
case EventSignal.OffsetStop:
Console.WriteLine("再生完了!");
return;
default:
Console.WriteLine("ここにきちゃだめなはず");
return;
}
}
}
finally
{
//リソース開放!
myDispose();
}
}

/// <summary>
/// Method: 指定されたバッファ位置にstream内容をHalfBufferSizeだけ書き込みます。
/// 最終書き込みはHalfBufferSizeよりも小さくなるので無音を追加します。
/// </summary>
/// <param name="mySoundBufferPositionFlag"></param>
private void SoundBufferWrite(SoundBufferPosition mySoundBufferPosition)
{
//今まで読み込んだ位置とファイル終了位置の距離
long distance = GetDistance(stream);
//今からここに書き込むのだ
int myPosition = HalfBufferSize * (int)mySoundBufferPosition;

if( distance >= HalfBufferSize )
{
//通常書き込み
sound.Write(myPosition, stream, HalfBufferSize, LockFlag.None);
}
else
{
//最終書き込みは既にやったかな?
if(lastWriteDone == true)
{
//最終書き込みは既にやりましたぞ
//Stop()してもしばらくplayカーソルが動いてしまうので、このブロックも無音にする
FillBufferWithSilence(sound, myPosition + (int)distance, HalfBufferSize - (int)distance);
//Stop()してちょ
stopperFlag = true;
}
else
{
//まだ最終書き込みしてないので最終書き込み
sound.Write(myPosition, stream, (int)distance, LockFlag.None);
//残りの部分を無音にする
FillBufferWithSilence(sound, myPosition + (int)distance, HalfBufferSize - (int)distance);
//最終書き込みしましたぞ
lastWriteDone = true;
}
}
}

/// <summary>
/// Method: 指定されたメモリブロック全体に、指定された値を書き込みます。
/// FillMemoryのC#版です。
/// </summary>
/// <param name="myArray"></param>
/// <param name="mySize"></param>
/// <param name="myUnit"></param>
static private void FillMemory(byte[] myArray, int mySize, byte myUnit)
{
for(int i = 0; i < mySize; i++)
{
myArray[i] = myUnit;
}
}

/// <summary>
/// Method: サウンドバッファを無音で埋め尽くします。
/// </summary>
/// <param name="myBuffer"></param>
/// <param name="startingPosition"></param>
/// <param name="fillingSize"></param>
static private void FillBufferWithSilence(Microsoft.DirectX.DirectSound.Buffer myBuffer, int startingPosition, int fillingSize)
{
//無音配列を作成
byte[] silenceArray = new byte[fillingSize];
if(myBuffer.Format.BitsPerSample == 8)
{
//8bitサウンドの時だけ無音は0x80
FillMemory(silenceArray, fillingSize, 0x80);
}
else
{
//それ以外の時は無音は0x00
FillMemory(silenceArray, fillingSize, 0x00);
}
//バッファに書き込み
myBuffer.Write(startingPosition, silenceArray, LockFlag.None);
//無音配列を開放
silenceArray = null;
}

/// <summary>
/// Method: 演奏用に確保したリソースを開放します。
/// </summary>
private void myDispose()
{
//ストリームを閉じる!
stream.Close();

//なるべく自分でメモリをきれいきれいしよう
sound.Dispose();
sound = null;
desc.Dispose();
desc = null;
device.Dispose();
device = null;

myDirectSoundNotify.Dispose();
myDirectSoundNotify = null;
myBufferPositionNotify = null;
autoEvents = null;
}
#endregion

}


/// <summary>
/// サウンドクラス用例外クラスです。
/// </summary>
#region "Exception Classes"
/// <summary>
/// BufferUnderRun例外クラスです。
/// </summary>
[Serializable()]
public class BufferUnderRunException : Exception
{
public BufferUnderRunException()
{
}

public BufferUnderRunException(string message)
: base(message)
{
}
public BufferUnderRunException(string message, Exception innerException)
: base (message, innerException)
{
}
protected BufferUnderRunException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
}

/// <summary>
/// WaveFormat例外クラスです。
/// </summary>
[Serializable()]
public class WaveFormatException : Exception
{
public WaveFormatException()
{
}

public WaveFormatException(string message)
: base(message)
{
}
public WaveFormatException(string message, Exception innerException)
: base (message, innerException)
{
}
protected WaveFormatException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
}


#endregion