その4

結局DirectSoundのNotifyメソッドを使うのがらくちんということで待機ハンドルを使ってイベント処理しました。って、昨日の(その3)の方法(id:parlin:20051209)と一緒ですなあ(..;)
動くサンプルがあるとなにかと嬉しいので書いときますかの^〜^
以下ソースコードなり。


using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
//ユーザー追加
using System.IO;
using System.Reflection;
using Microsoft.DirectX.DirectSound;
using System.Threading;

namespace Dsoundtest
{
/// <summary>
/// Form1 の概要の説明です。
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Button button1;
/// <summary>
/// 必要なデザイナ変数です。
/// </summary>
private System.ComponentModel.Container components = null;

public Form1()
{
//
// Windows フォーム デザイナ サポートに必要です。
//
InitializeComponent();

//
// TODO: InitializeComponent 呼び出しの後に、コンストラクタ コードを追加してください。
//
}

/// <summary>
/// 使用されているリソースに後処理を実行します。
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows フォーム デザイナで生成されたコード
/// <summary>
/// デザイナ サポートに必要なメソッドです。このメソッドの内容を
/// コード エディタで変更しないでください。
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// button1
//
this.button1.Dock = System.Windows.Forms.DockStyle.Fill;
this.button1.Font = new System.Drawing.Font("MS UI Gothic", 16.2F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((System.Byte)(128)));
this.button1.Location = new System.Drawing.Point(0, 0);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(200, 56);
this.button1.TabIndex = 55;
this.button1.Text = "自爆スイッチ";
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(7, 15);
this.ClientSize = new System.Drawing.Size(200, 56);
this.Controls.Add(this.button1);
this.Name = "Form1";
this.Text = "Dsoundtest";
this.ResumeLayout(false);

}
#endregion

/// <summary>
/// アプリケーションのメイン エントリ ポイントです。
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}

//再生音の宣言
string soundFileName = "SUCCESS.WAV";

private void button1_Click(object sender, System.EventArgs e)
{
int waitTiming = 1000;
MessageBox.Show(((int)(waitTiming / 1000)).ToString() + "秒後に50回鳴らします!");
Thread.Sleep(waitTiming);

for(int i = 0; i < 50; i++)
{
DSoundWrapper hoge = new DSoundWrapper();
hoge.Play(this, soundFileName, SoundFlags.PlayWithExternalFile | SoundFlags.PlayAsync);
}

Console.WriteLine("全部おわた");
}

}


/// <summary>
/// サウンドクラスDSoundWrapper用のフラグです。
/// </summary>
//フラグとして扱うときはフラグ属性をつける!
[Flags()]
public enum SoundFlags : int
{
None = 0x0,
PlaySync = 0x1,
PlayAsync = 0x2,
PlayWithExternalFile = 0x10,
PlayWithEmbededFile = 0x20
}


public class DSoundWrapper
{
/// <summary>
/// フィールドです。
/// </summary>
#region "Field:"
//DirectSound再生用
Device device = null;
BufferDescription desc = null;
SecondaryBuffer sound = null;
//再生中であるかどうかの通知用
static AutoResetEvent[] autoEvent = null;
BufferPositionNotify[] myBufferPositionNotify = null;
Notify myDirectSoundNotify = null;
#endregion

/// <summary>
/// コンストラクタです。
/// </summary>
#region "Constructor:"
public DSoundWrapper()
{
}
#endregion

/// <summary>
/// メソッドです。
/// </summary>
#region "Method:"
/// <summary>
/// Method: (外部or埋め込みの)ファイルからWaveデータを読み込み、再生します。
/// </summary>
/// <param name="myControl"></param>
/// <param name="soundFileName"></param>
/// <param name="soundFlags"></param>
public void Play(Control myControl, string soundFileName, SoundFlags soundFlags)
{
//using Microsoft.DirectX.DirectSound;
//Device取得
device = new Device();
device.SetCooperativeLevel(myControl, CooperativeLevel.Normal);
//BufferDescription設定
desc = new BufferDescription();
desc.ControlPan = true;
//バッファ内でのポジション通知アリ
desc.ControlPositionNotify = true;
//フォーカスにかかわらず音を出そう
desc.GlobalFocus = true;

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

//SecondaryBuffer作成
//外部ファイルから?
if((soundFlags & SoundFlags.PlayWithExternalFile) != SoundFlags.None)
{
//外部ファイルからバッファ作成
sound = new SecondaryBuffer(soundFileName, desc, device);
}
else
{
//埋め込みファイルからバッファ作成
//using System.Reflection;
//現在実行中のアセンブリを取得
Assembly thisExe = Assembly.GetExecutingAssembly();
string assemblyName = thisExe.GetName().Name;
//埋め込みファイルのストリームを取得
Stream stream = thisExe.GetManifestResourceStream(assemblyName + "." + soundFileName);
//ストリームからバッファ作成
sound = new SecondaryBuffer(stream, desc, device);
//ストリームを閉じる!
stream.Close();
}

//待機ハンドルを使ってイベント処理しますかの
autoEvent = new AutoResetEvent[] {new AutoResetEvent(false)};
//イベントの数はautoEvent.Length個ですの
myBufferPositionNotify = new BufferPositionNotify[autoEvent.Length];
//再生バッファポジションが最終もしくは停止の場合
myBufferPositionNotify[0].Offset = (int)PositionNotifyFlag.OffsetStop;
myBufferPositionNotify[0].EventNotifyHandle = autoEvent[0].Handle;
//通知メソッドにセットじゃ
myDirectSoundNotify = new Notify(sound);
myDirectSoundNotify.SetNotificationPositions(myBufferPositionNotify);

//再生フラグは同期?
if((soundFlags & SoundFlags.PlaySync) != SoundFlags.None)
{
//同期でした
PlaySync();
}
else
{
//非同期でした
PlayAsync();
}
}

/// <summary>
/// Method: 同期再生
/// </summary>
private void PlaySync()
{
//再生じゃ
sound.Play(0, BufferPlayFlags.Default);
//終わったかどうかの監視まん
autoEvent[0].WaitOne();

Console.WriteLine("再生完了!");

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

sound.Dispose();
desc.Dispose();
device.Dispose();
}

/// <summary>
/// Method: 非同期再生(別スレッドでPlaySync()を動作させる)
/// </summary>
private void PlayAsync()
{
//Playメソッドを別のスレッドで実行する
//Threadオブジェクトを作成する
System.Threading.Thread t =
new System.Threading.Thread(
new System.Threading.ThreadStart(PlaySync));
t.IsBackground = true;
//スレッドを開始する
t.Start();
}
#endregion
}

}