2 using System.Collections.Generic;
\r
4 using System.Diagnostics;
\r
6 using System.Threading;
\r
8 using SharpDX.DirectSound;
\r
12 public class CSoundDeviceDirectSound : ISoundDevice
\r
16 public ESoundDeviceType e出力デバイス
\r
21 public long n実出力遅延ms
\r
26 public long n実バッファサイズms
\r
32 public static readonly BufferFlags DefaultFlags = BufferFlags.Defer | BufferFlags.GetCurrentPosition2 | BufferFlags.GlobalFocus | BufferFlags.ControlVolume | BufferFlags.ControlPan | BufferFlags.ControlFrequency;
\r
34 // CSoundTimer 用に公開しているプロパティ
\r
40 if ( ctimer != null )
\r
42 this.sd経過時間計測用サウンドバッファ.DirectSoundBuffer.GetCurrentPosition( out int n現在位置, out _ );
\r
43 long n現在のシステム時刻ms = this.tmシステムタイマ.nシステム時刻ms;
\r
48 long nシステム時刻での間隔ms = n現在のシステム時刻ms - this.n前に経過時間を測定したシステム時刻ms;
\r
50 while ( nシステム時刻での間隔ms >= n単位繰り上げ間隔ms ) // 前回から単位繰り上げ間隔以上経過してるなら確実にループしている。誤差は大きくないだろうから無視。
\r
53 nシステム時刻での間隔ms -= n単位繰り上げ間隔ms;
\r
56 if ( n現在位置 < this.n前回の位置 ) // 単位繰り上げ間隔以内であっても、現在位置が前回より手前にあるなら1回ループしている。
\r
62 long n経過時間ms = (long) ( ( this.nループ回数 * n単位繰り上げ間隔ms ) + ( n現在位置 * 1000.0 / ( 44100.0 * 2 * 2 ) ) );
\r
67 this.n前に経過時間を測定したシステム時刻ms = n現在のシステム時刻ms;
\r
68 this.n前回の位置 = n現在位置;
\r
74 long nRet = ctimer.nシステム時刻ms - this.n前に経過時間を測定したシステム時刻ms;
\r
75 if ( nRet < 0 ) // カウンタがループしたときは
\r
77 nRet = ( ctimer.nシステム時刻 - long.MinValue ) + ( long.MaxValue - this.n前に経過時間を測定したシステム時刻ms ) + 1;
\r
79 this.n前に経過時間を測定したシステム時刻ms = ctimer.nシステム時刻ms;
\r
85 public long n経過時間を更新したシステム時刻ms
\r
87 get { throw new NotImplementedException(); }
\r
89 public CTimer tmシステムタイマ
\r
95 public int nMasterVolume
\r
110 public CSoundDeviceDirectSound( IntPtr hWnd, long n遅延時間ms )
\r
112 t初期化( hWnd, n遅延時間ms, false );
\r
114 public CSoundDeviceDirectSound( IntPtr hWnd, long n遅延時間ms, bool bUseOSTimer )
\r
116 t初期化( hWnd, n遅延時間ms, bUseOSTimer );
\r
118 private void t初期化( IntPtr hWnd, long n遅延時間ms, bool bUseOSTimer )
\r
120 Trace.TraceInformation( "DirectSound の初期化を開始します。" );
\r
122 this.e出力デバイス = ESoundDeviceType.Unknown;
\r
123 this.n実バッファサイズms = this.n実出力遅延ms = n遅延時間ms;
\r
124 this.tmシステムタイマ = new CTimer( CTimer.E種別.MultiMedia );
\r
126 #region [ DirectSound デバイスを作成する。]
\r
127 //-----------------
\r
128 this.DirectSound = new DirectSound(); // 失敗したら例外をそのまま発出。
\r
130 // デバイスの協調レベルを設定する。
\r
132 bool priority = true;
\r
135 this.DirectSound.SetCooperativeLevel( hWnd, CooperativeLevel.Priority );
\r
139 this.DirectSound.SetCooperativeLevel( hWnd, CooperativeLevel.Normal ); // これでも失敗したら例外をそのまま発出。
\r
145 this.e出力デバイス = ESoundDeviceType.DirectSound;
\r
146 //-----------------
\r
149 if ( !bUseOSTimer )
\r
151 #region [ 経過時間計測用サウンドバッファを作成し、ループ再生を開始する。]
\r
152 //-----------------
\r
154 // 単位繰り上げ間隔[秒]の長さを持つ無音のサウンドを作成。
\r
156 uint nデータサイズbyte = n単位繰り上げ間隔sec * 44100 * 2 * 2;
\r
157 var ms = new MemoryStream();
\r
158 var bw = new BinaryWriter( ms );
\r
159 bw.Write( (uint) 0x46464952 ); // 'RIFF'
\r
160 bw.Write( (uint) ( 44 + nデータサイズbyte - 8 ) ); // ファイルサイズ - 8
\r
161 bw.Write( (uint) 0x45564157 ); // 'WAVE'
\r
162 bw.Write( (uint) 0x20746d66 ); // 'fmt '
\r
163 bw.Write( (uint) 16 ); // バイト数
\r
164 bw.Write( (ushort) 1 ); // フォーマットID(リニアPCM)
\r
165 bw.Write( (ushort) 2 ); // チャンネル数
\r
166 bw.Write( (uint) 44100 ); // サンプリング周波数
\r
167 bw.Write( (uint) ( 44100 * 2 * 2 ) ); // bytes/sec
\r
168 bw.Write( (ushort) ( 2 * 2 ) ); // blockサイズ
\r
169 bw.Write( (ushort) 16 ); // bit/sample
\r
170 bw.Write( (uint) 0x61746164 ); // 'data'
\r
171 bw.Write( (uint) nデータサイズbyte ); // データ長
\r
172 for ( int i = 0; i < nデータサイズbyte / sizeof( long ); i++ ) // PCMデータ
\r
173 bw.Write( (long) 0 );
\r
174 var byArrWaveFleImage = ms.ToArray();
\r
178 this.sd経過時間計測用サウンドバッファ = this.tサウンドを作成する( byArrWaveFleImage );
\r
179 CSound.listインスタンス.Remove( this.sd経過時間計測用サウンドバッファ ); // 特殊用途なのでインスタンスリストからは除外する。
\r
185 this.sd経過時間計測用サウンドバッファ.DirectSoundBuffer.Play( 0, PlayFlags.Looping );
\r
186 this.n前に経過時間を測定したシステム時刻ms = this.tmシステムタイマ.nシステム時刻ms;
\r
187 //-----------------
\r
192 ctimer = new CTimer( CTimer.E種別.MultiMedia );
\r
194 Trace.TraceInformation( "DirectSound を初期化しました。({0})({1})", ( priority ) ? "Priority" : "Normal", bUseOSTimer? "OStimer" : "FDKtimer" );
\r
197 public CSound tサウンドを作成する( string strファイル名 )
\r
199 var sound = new CSound();
\r
200 sound.tDirectSoundサウンドを作成する( strファイル名, this.DirectSound );
\r
203 public CSound tサウンドを作成する( byte[] byArrWAVファイルイメージ )
\r
205 var sound = new CSound();
\r
206 sound.tDirectSoundサウンドを作成する( byArrWAVファイルイメージ, this.DirectSound );
\r
209 public CSound tサウンドを作成する( byte[] byArrWAVファイルイメージ, BufferFlags flags )
\r
211 var sound = new CSound();
\r
212 sound.tDirectSoundサウンドを作成する( byArrWAVファイルイメージ, this.DirectSound, flags );
\r
216 // 既存のインスタンス(生成直後 or Dispose済み)に対してサウンドを生成する。
\r
217 public void tサウンドを作成する( string strファイル名, ref CSound sound )
\r
219 sound.tDirectSoundサウンドを作成する( strファイル名, this.DirectSound );
\r
221 public void tサウンドを作成する( byte[] byArrWAVファイルイメージ, ref CSound sound )
\r
223 sound.tDirectSoundサウンドを作成する( byArrWAVファイルイメージ, this.DirectSound );
\r
225 public void tサウンドを作成する( byte[] byArrWAVファイルイメージ, BufferFlags flags, ref CSound sound )
\r
227 sound.tDirectSoundサウンドを作成する( byArrWAVファイルイメージ, this.DirectSound, flags );
\r
230 #region [ Dispose-Finallizeパターン実装 ]
\r
231 //-----------------
\r
232 public void Dispose()
\r
234 this.Dispose( true );
\r
235 GC.SuppressFinalize( this );
\r
237 protected void Dispose( bool bManagedDispose )
\r
239 this.e出力デバイス = ESoundDeviceType.Unknown; // まず出力停止する(Dispose中にクラス内にアクセスされることを防ぐ)
\r
240 if ( bManagedDispose )
\r
242 #region [ 経緯時間計測用サウンドバッファを解放。]
\r
243 //-----------------
\r
244 if ( this.sd経過時間計測用サウンドバッファ != null )
\r
246 this.sd経過時間計測用サウンドバッファ.tサウンドを停止する();
\r
247 C共通.tDisposeする( ref this.sd経過時間計測用サウンドバッファ );
\r
249 //-----------------
\r
251 #region [ 単位繰り上げ用スレッド停止。]
\r
252 //-----------------
\r
253 if( this.th経過時間測定用スレッド != null )
\r
255 this.th経過時間測定用スレッド.Abort();
\r
256 this.th経過時間測定用スレッド = null;
\r
259 //-----------------
\r
262 C共通.tDisposeする( ref this.DirectSound );
\r
263 C共通.tDisposeする( this.tmシステムタイマ );
\r
265 if ( ctimer != null )
\r
267 C共通.tDisposeする( ref this.ctimer );
\r
270 ~CSoundDeviceDirectSound()
\r
272 this.Dispose( false );
\r
274 //-----------------
\r
277 protected DirectSound DirectSound = null;
\r
278 protected CSound sd経過時間計測用サウンドバッファ = null;
\r
279 protected Thread th経過時間測定用スレッド = null;
\r
280 // protected AutoResetEvent autoResetEvent = new AutoResetEvent( false );
\r
281 protected const uint n単位繰り上げ間隔sec = 1; // [秒]
\r
282 protected const uint n単位繰り上げ間隔ms = n単位繰り上げ間隔sec * 1000; // [ミリ秒]
\r
283 protected int nループ回数 = 0;
\r
285 private long n前に経過時間を測定したシステム時刻ms = CTimer.n未使用;
\r
286 private int n前回の位置 = 0;
\r
288 private CTimer ctimer = null;
\r