+++ /dev/null
-using System;\r
-using System.Collections.Generic;\r
-using System.Text;\r
-using System.Diagnostics;\r
-using System.IO;\r
-using System.Threading;\r
-using SharpDX;\r
-using SharpDX.DirectSound;\r
-\r
-namespace FDK\r
-{\r
- public class CSoundDeviceDirectSound : ISoundDevice\r
- {\r
- // プロパティ\r
-\r
- public ESoundDeviceType e出力デバイス\r
- {\r
- get;\r
- protected set;\r
- }\r
- public long n実出力遅延ms\r
- {\r
- get;\r
- protected set;\r
- }\r
- public long n実バッファサイズms\r
- {\r
- get;\r
- protected set;\r
- }\r
-\r
- public static readonly BufferFlags DefaultFlags = BufferFlags.Defer | BufferFlags.GetCurrentPosition2 | BufferFlags.GlobalFocus | BufferFlags.ControlVolume | BufferFlags.ControlPan | BufferFlags.ControlFrequency;\r
-\r
- // CSoundTimer 用に公開しているプロパティ\r
-\r
- public long n経過時間ms\r
- {\r
- get\r
- {\r
- if ( ctimer != null )\r
- {\r
- this.sd経過時間計測用サウンドバッファ.DirectSoundBuffer.GetCurrentPosition( out int n現在位置, out _ );\r
- long n現在のシステム時刻ms = this.tmシステムタイマ.nシステム時刻ms;\r
-\r
-\r
- // ループ回数を調整。\r
-\r
- long nシステム時刻での間隔ms = n現在のシステム時刻ms - this.n前に経過時間を測定したシステム時刻ms;\r
-\r
- while ( nシステム時刻での間隔ms >= n単位繰り上げ間隔ms ) // 前回から単位繰り上げ間隔以上経過してるなら確実にループしている。誤差は大きくないだろうから無視。\r
- {\r
- this.nループ回数++;\r
- nシステム時刻での間隔ms -= n単位繰り上げ間隔ms;\r
- }\r
-\r
- if ( n現在位置 < this.n前回の位置 ) // 単位繰り上げ間隔以内であっても、現在位置が前回より手前にあるなら1回ループしている。\r
- this.nループ回数++;\r
-\r
-\r
- // 経過時間を算出。\r
-\r
- long n経過時間ms = (long) ( ( this.nループ回数 * n単位繰り上げ間隔ms ) + ( n現在位置 * 1000.0 / ( 44100.0 * 2 * 2 ) ) );\r
-\r
-\r
- // 今回の値を次回に向けて保存。\r
-\r
- this.n前に経過時間を測定したシステム時刻ms = n現在のシステム時刻ms;\r
- this.n前回の位置 = n現在位置;\r
-\r
- return n経過時間ms;\r
- }\r
- else\r
- {\r
- long nRet = ctimer.nシステム時刻ms - this.n前に経過時間を測定したシステム時刻ms;\r
- if ( nRet < 0 ) // カウンタがループしたときは\r
- {\r
- nRet = ( ctimer.nシステム時刻 - long.MinValue ) + ( long.MaxValue - this.n前に経過時間を測定したシステム時刻ms ) + 1;\r
- }\r
- this.n前に経過時間を測定したシステム時刻ms = ctimer.nシステム時刻ms;\r
- \r
- return nRet;\r
- }\r
- }\r
- }\r
- public long n経過時間を更新したシステム時刻ms\r
- {\r
- get { throw new NotImplementedException(); }\r
- }\r
- public CTimer tmシステムタイマ\r
- {\r
- get;\r
- protected set;\r
- }\r
-\r
- public int nMasterVolume\r
- {\r
- get\r
- {\r
- return (int) 100;\r
- }\r
- set\r
- {\r
- // 特に何もしない\r
- }\r
- }\r
-\r
-\r
- // メソッド\r
-\r
- public CSoundDeviceDirectSound( IntPtr hWnd, long n遅延時間ms )\r
- {\r
- t初期化( hWnd, n遅延時間ms, false );\r
- }\r
- public CSoundDeviceDirectSound( IntPtr hWnd, long n遅延時間ms, bool bUseOSTimer )\r
- {\r
- t初期化( hWnd, n遅延時間ms, bUseOSTimer );\r
- }\r
- private void t初期化( IntPtr hWnd, long n遅延時間ms, bool bUseOSTimer )\r
- {\r
- Trace.TraceInformation( "DirectSound の初期化を開始します。" );\r
-\r
- this.e出力デバイス = ESoundDeviceType.Unknown;\r
- this.n実バッファサイズms = this.n実出力遅延ms = n遅延時間ms;\r
- this.tmシステムタイマ = new CTimer( CTimer.E種別.MultiMedia );\r
-\r
- #region [ DirectSound デバイスを作成する。]\r
- //-----------------\r
- this.DirectSound = new DirectSound(); // 失敗したら例外をそのまま発出。\r
-\r
- // デバイスの協調レベルを設定する。\r
-\r
- bool priority = true;\r
- try\r
- {\r
- this.DirectSound.SetCooperativeLevel( hWnd, CooperativeLevel.Priority );\r
- }\r
- catch\r
- {\r
- this.DirectSound.SetCooperativeLevel( hWnd, CooperativeLevel.Normal ); // これでも失敗したら例外をそのまま発出。\r
- priority = false;\r
- }\r
-\r
- // デバイス作成完了。\r
-\r
- this.e出力デバイス = ESoundDeviceType.DirectSound;\r
- //-----------------\r
- #endregion\r
-\r
- if ( !bUseOSTimer )\r
- {\r
- #region [ 経過時間計測用サウンドバッファを作成し、ループ再生を開始する。]\r
- //-----------------\r
-\r
- // 単位繰り上げ間隔[秒]の長さを持つ無音のサウンドを作成。\r
-\r
- uint nデータサイズbyte = n単位繰り上げ間隔sec * 44100 * 2 * 2;\r
- var ms = new MemoryStream();\r
- var bw = new BinaryWriter( ms );\r
- bw.Write( (uint) 0x46464952 ); // 'RIFF'\r
- bw.Write( (uint) ( 44 + nデータサイズbyte - 8 ) ); // ファイルサイズ - 8\r
- bw.Write( (uint) 0x45564157 ); // 'WAVE'\r
- bw.Write( (uint) 0x20746d66 ); // 'fmt '\r
- bw.Write( (uint) 16 ); // バイト数\r
- bw.Write( (ushort) 1 ); // フォーマットID(リニアPCM)\r
- bw.Write( (ushort) 2 ); // チャンネル数\r
- bw.Write( (uint) 44100 ); // サンプリング周波数\r
- bw.Write( (uint) ( 44100 * 2 * 2 ) ); // bytes/sec\r
- bw.Write( (ushort) ( 2 * 2 ) ); // blockサイズ\r
- bw.Write( (ushort) 16 ); // bit/sample\r
- bw.Write( (uint) 0x61746164 ); // 'data'\r
- bw.Write( (uint) nデータサイズbyte ); // データ長\r
- for ( int i = 0; i < nデータサイズbyte / sizeof( long ); i++ ) // PCMデータ\r
- bw.Write( (long) 0 );\r
- var byArrWaveFleImage = ms.ToArray();\r
- bw.Close();\r
- ms = null;\r
- bw = null;\r
- this.sd経過時間計測用サウンドバッファ = this.tサウンドを作成する( byArrWaveFleImage );\r
- CSound.listインスタンス.Remove( this.sd経過時間計測用サウンドバッファ ); // 特殊用途なのでインスタンスリストからは除外する。\r
-\r
- // サウンドのループ再生開始。\r
-\r
- this.nループ回数 = 0;\r
- this.n前回の位置 = 0;\r
- this.sd経過時間計測用サウンドバッファ.DirectSoundBuffer.Play( 0, PlayFlags.Looping );\r
- this.n前に経過時間を測定したシステム時刻ms = this.tmシステムタイマ.nシステム時刻ms;\r
- //-----------------\r
- #endregion\r
- }\r
- else\r
- {\r
- ctimer = new CTimer( CTimer.E種別.MultiMedia );\r
- }\r
- Trace.TraceInformation( "DirectSound を初期化しました。({0})({1})", ( priority ) ? "Priority" : "Normal", bUseOSTimer? "OStimer" : "FDKtimer" );\r
- }\r
-\r
- public CSound tサウンドを作成する( string strファイル名 )\r
- {\r
- var sound = new CSound();\r
- sound.tDirectSoundサウンドを作成する( strファイル名, this.DirectSound );\r
- return sound;\r
- }\r
- public CSound tサウンドを作成する( byte[] byArrWAVファイルイメージ )\r
- {\r
- var sound = new CSound();\r
- sound.tDirectSoundサウンドを作成する( byArrWAVファイルイメージ, this.DirectSound );\r
- return sound;\r
- }\r
- public CSound tサウンドを作成する( byte[] byArrWAVファイルイメージ, BufferFlags flags )\r
- {\r
- var sound = new CSound();\r
- sound.tDirectSoundサウンドを作成する( byArrWAVファイルイメージ, this.DirectSound, flags );\r
- return sound;\r
- }\r
-\r
- // 既存のインスタンス(生成直後 or Dispose済み)に対してサウンドを生成する。\r
- public void tサウンドを作成する( string strファイル名, ref CSound sound )\r
- {\r
- sound.tDirectSoundサウンドを作成する( strファイル名, this.DirectSound );\r
- }\r
- public void tサウンドを作成する( byte[] byArrWAVファイルイメージ, ref CSound sound )\r
- {\r
- sound.tDirectSoundサウンドを作成する( byArrWAVファイルイメージ, this.DirectSound );\r
- }\r
- public void tサウンドを作成する( byte[] byArrWAVファイルイメージ, BufferFlags flags, ref CSound sound )\r
- {\r
- sound.tDirectSoundサウンドを作成する( byArrWAVファイルイメージ, this.DirectSound, flags );\r
- }\r
-\r
- #region [ Dispose-Finallizeパターン実装 ]\r
- //-----------------\r
- public void Dispose()\r
- {\r
- this.Dispose( true );\r
- GC.SuppressFinalize( this );\r
- }\r
- protected void Dispose( bool bManagedDispose )\r
- {\r
- this.e出力デバイス = ESoundDeviceType.Unknown; // まず出力停止する(Dispose中にクラス内にアクセスされることを防ぐ)\r
- if ( bManagedDispose )\r
- {\r
- #region [ 経緯時間計測用サウンドバッファを解放。]\r
- //-----------------\r
- if ( this.sd経過時間計測用サウンドバッファ != null )\r
- {\r
- this.sd経過時間計測用サウンドバッファ.tサウンドを停止する();\r
- C共通.tDisposeする( ref this.sd経過時間計測用サウンドバッファ );\r
- }\r
- //-----------------\r
- #endregion\r
- #region [ 単位繰り上げ用スレッド停止。]\r
- //-----------------\r
- if( this.th経過時間測定用スレッド != null )\r
- {\r
- this.th経過時間測定用スレッド.Abort();\r
- this.th経過時間測定用スレッド = null;\r
- \r
- }\r
- //-----------------\r
- #endregion\r
-\r
- C共通.tDisposeする( ref this.DirectSound );\r
- C共通.tDisposeする( this.tmシステムタイマ );\r
- }\r
- if ( ctimer != null )\r
- {\r
- C共通.tDisposeする( ref this.ctimer );\r
- }\r
- }\r
- ~CSoundDeviceDirectSound()\r
- {\r
- this.Dispose( false );\r
- }\r
- //-----------------\r
- #endregion\r
-\r
- protected DirectSound DirectSound = null;\r
- protected CSound sd経過時間計測用サウンドバッファ = null;\r
- protected Thread th経過時間測定用スレッド = null;\r
-// protected AutoResetEvent autoResetEvent = new AutoResetEvent( false );\r
- protected const uint n単位繰り上げ間隔sec = 1; // [秒]\r
- protected const uint n単位繰り上げ間隔ms = n単位繰り上げ間隔sec * 1000; // [ミリ秒]\r
- protected int nループ回数 = 0;\r
-\r
- private long n前に経過時間を測定したシステム時刻ms = CTimer.n未使用;\r
- private int n前回の位置 = 0;\r
-\r
- private CTimer ctimer = null;\r
- }\r
-}\r