OSDN Git Service

共有モードを選択可能にした。
authorくまかみ工房 <kumakamikoubou@gmail.com>
Sun, 13 Nov 2016 06:55:32 +0000 (15:55 +0900)
committerくまかみ工房 <kumakamikoubou@gmail.com>
Sun, 13 Nov 2016 06:55:32 +0000 (15:55 +0900)
更新間隔 関連のフィールドを整理。

FDK24/Utilities.cs
FDK24/メディア/サウンド/WASAPI/Device.cs
StrokeStyleT/StrokeStyleT.cs
StrokeStyleT/ステージ/曲読込/曲読込ステージ.cs

index 1eb7d0d..6c7e634 100644 (file)
@@ -75,6 +75,15 @@ namespace FDK
                        return ( m * n / Utilities.最大公約数を返す( m, n ) );
                }
 
+               public static double 変換_100ns単位からsec単位へ( long 数値100ns )
+               {
+                       return 数値100ns / ( 10.0 * 1000.0 * 1000.0 );
+               }
+               public static long 変換_sec単位から100ns単位へ( double 数値sec )
+               {
+                       return (long) ( 数値sec * 10.0 * 1000.0 * 1000.0 );
+               }
+
                /// <summary>
                /// このメソッドの 呼び出し元のメソッド名 を返す。デバッグログ用。
                /// </summary>
index 8fdd9e8..28c92dd 100644 (file)
@@ -5,9 +5,9 @@ namespace FDK.メディア.サウンド.WASAPI
 {
        public unsafe class Device : IDisposable
        {
-               public float 遅延ms
+               public double 遅延sec
                {
-                       get { return this.更新間隔ms; }
+                       get { return ( this.更新間隔sec * 1000.0 ); }
                }
                public CSCore.CoreAudioAPI.AudioClock AudioClock
                {
@@ -19,7 +19,7 @@ namespace FDK.メディア.サウンド.WASAPI
                        protected set;
                } = true;
 
-               public void 初期化する( double 希望更新間隔sec = 0.015 )
+               public void 初期化する( CSCore.CoreAudioAPI.AudioClientShareMode 共有モード, double 希望更新間隔sec = 0.015 )
                {
                        int hr = 0;
 
@@ -28,6 +28,8 @@ namespace FDK.メディア.サウンド.WASAPI
                                Trace.Assert( this.Dispose済み );
                                this.Dispose済み = false;
 
+                               this.共有モード = 共有モード;
+
                                #region " AudioClientをアクティベートする。"
                                //-----------------
                                using( var devices = new CSCore.CoreAudioAPI.MMDeviceEnumerator() )
@@ -47,15 +49,26 @@ namespace FDK.メディア.サウンド.WASAPI
                                if( 0 > hr )
                                        System.Runtime.InteropServices.Marshal.ThrowExceptionForHR( hr );
 
-                               var 最小間隔ms = (float) 排他モードでの最小間隔100ns / 10000.0f;
-
-                               // 更新間隔ms を「希望更新間隔とデバイスの最小間隔の大きい方 かつ 最大1秒までの値」にする。
-                               this.更新間隔ms = System.Math.Min( 1000.0f, System.Math.Max( (float) ( 希望更新間隔sec * 1000.0 ), 最小間隔ms ) );
+                               if( 共有モード == CSCore.CoreAudioAPI.AudioClientShareMode.Shared )
+                               {
+                                       this.更新間隔100ns = 共有モードでの間隔100ns;
+                               }
+                               else
+                               {
+                                       this.更新間隔100ns = Math.Max( FDK.Utilities.変換_sec単位から100ns単位へ( 希望更新間隔sec ), 排他モードでの最小間隔100ns );
+                               }
                                //-----------------
                                #endregion
                                #region " デバイスフォーマットを決定する。"
                                //----------------
-                               this.WaveFormat = new CSCore.WaveFormat( 44100, 16, 2, CSCore.AudioEncoding.Pcm );
+                               if( this.共有モード == CSCore.CoreAudioAPI.AudioClientShareMode.Shared )
+                               {
+                                       this.WaveFormat = this.AudioClient.GetMixFormat();
+                               }
+                               else
+                               {
+                                       this.WaveFormat = new CSCore.WaveFormat( 44100, 16, 2, CSCore.AudioEncoding.Pcm );
+                               }
                                //----------------
                                #endregion
                                #region " AudioClient を初期化する。"
@@ -63,20 +76,22 @@ namespace FDK.メディア.サウンド.WASAPI
                                try
                                {
                                        this.AudioClient.Initialize(
-                                               CSCore.CoreAudioAPI.AudioClientShareMode.Exclusive, // 排他モード。
-                                               CSCore.CoreAudioAPI.AudioClientStreamFlags.StreamFlagsEventCallback,    // イベント駆動モード。
-                                               (long) ( this.更新間隔ms * 10000.0f + 0.5f ),   // バッファサイズ。イベント駆動モードでは、更新間隔と同じ値でなければならない。
-                                               (long) ( this.更新間隔ms * 10000.0f + 0.5f ),   // 更新間隔。
-                                               this.WaveFormat, // バッファのフォーマット。
-                                               Guid.Empty );   // この AudioClient = AudioStrem が所属する AudioSession。null ならデフォルトのAudioSessionに登録される。
+                                               this.共有モード,
+                                               CSCore.CoreAudioAPI.AudioClientStreamFlags.StreamFlagsEventCallback,
+                                               // | CSCore.CoreAudioAPI.AudioClientStreamFlags.StreamFlagsNoPersist,   // 音量とミュートを記憶しない → 無効。してください
+                                               this.更新間隔100ns,
+                                               this.更新間隔100ns,
+                                               this.WaveFormat,
+                                               Guid.Empty );   // この AudioClient (= AudioStrem) が所属する AudioSession。null ならデフォルトのAudioSessionに登録される。
                                }
                                catch( CSCore.CoreAudioAPI.CoreAudioAPIException e )
                                {
-                                       // 排他&イベント駆動モードの場合、バッファのアライメントエラーが返される場合がある。この場合、サイズを調整してオーディオストリームを作成し直す。
                                        if( AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED == e.ErrorCode )
                                        {
-                                               int 更新間隔に一番近くてアライメントされているサイズsample = this.AudioClient.GetBufferSize();
-                                               this.更新間隔ms = ( 更新間隔に一番近くてアライメントされているサイズsample * 1000.0f / (float) this.WaveFormat.SampleRate );
+                                               #region " 排他&イベント駆動モードの場合、バッファサイズアライメントエラーが返される場合がある。この場合、サイズを調整してオーディオストリームを作成し直す。"
+                                               //----------------
+                                               this.更新間隔100ns = FDK.Utilities.変換_sec単位から100ns単位へ(
+                                                       (double) this.AudioClient.GetBufferSize() / (double) this.WaveFormat.SampleRate );   // GetBufferSize は、更新間隔に一番近い、アライメントされたバッファサイズ(sample単位)を返す。
 
                                                // AudioClient を一度解放し、もう一度アクティベートし直す。
                                                this.AudioClient.Dispose();
@@ -86,22 +101,21 @@ namespace FDK.メディア.サウンド.WASAPI
                                                        this.AudioClient = CSCore.CoreAudioAPI.AudioClient.FromMMDevice( 既定のデバイス );
                                                }
 
-                                               // アライメントされたサイズを使って、AudioClient を再初期化する。
+                                               // アライメントされたサイズを使って、AudioClient を再初期化する。それでもエラーなら例外発出。
                                                this.AudioClient.Initialize(
-                                                       CSCore.CoreAudioAPI.AudioClientShareMode.Exclusive, // 排他モード。
-                                                       CSCore.CoreAudioAPI.AudioClientStreamFlags.StreamFlagsEventCallback,    // イベント駆動モード。
-                                                       (long) ( this.更新間隔ms * 10000.0f + 0.5f ),   // バッファサイズ。イベント駆動モードでは、更新間隔と同じ値でなければならない。
-                                                       (long) ( this.更新間隔ms * 10000.0f + 0.5f ),   // 更新間隔。
-                                                       this.WaveFormat, // バッファのフォーマット。
-                                                       Guid.Empty );   // この AudioClient = AudioStrem が所属する AudioSession。NULLならデフォルトのAudioSessionに登録される。
-
-                                               // それでもエラーなら例外発生。
+                                                       this.共有モード,
+                                                       CSCore.CoreAudioAPI.AudioClientStreamFlags.StreamFlagsEventCallback,
+                                                       // | CSCore.CoreAudioAPI.AudioClientStreamFlags.StreamFlagsNoPersist,   // 音量とミュートを記憶しない → 無効。してください
+                                                       this.更新間隔100ns,
+                                                       this.更新間隔100ns,
+                                                       this.WaveFormat,
+                                                       Guid.Empty );
+                                               //----------------
+                                               #endregion
                                        }
                                }
 
-                               // 更新間隔を sample, byte 単位で保存する。
-                               this.更新間隔sample = this.AudioClient.GetBufferSize(); // バッファの長さはサンプル単位で返される。
-                               this.更新間隔byte = this.更新間隔sample * ( this.WaveFormat.Channels * this.WaveFormat.BytesPerSample );
+                               this.更新間隔sample = this.AudioClient.GetBufferSize();
                                //-----------------
                                #endregion
                                #region " AudioRenderClient を取得する。"
@@ -133,12 +147,15 @@ namespace FDK.メディア.サウンド.WASAPI
                                #region " 情報表示。"
                                //-----------------
                                FDK.Log.Info( $"WASAPIクライアントを初期化しました。" );
-                               FDK.Log.Info( $" モード: 排他&イベント駆動" );
+                               FDK.Log.Info( ( 共有モード == CSCore.CoreAudioAPI.AudioClientShareMode.Shared ) ?
+                                       " モード: 共有 & イベント駆動" :
+                                       " モード: 排他 & イベント駆動" );
                                FDK.Log.Info( $" フォーマット: {this.WaveFormat.BitsPerSample} bits, {this.WaveFormat.SampleRate} Hz" );
                                FDK.Log.Info( $" エンドポイントバッファ: {( (float) this.更新間隔sample / (double) this.WaveFormat.SampleRate ) * 1000.0f} ミリ秒 ({this.更新間隔sample} samples) × 2枚" );
                                FDK.Log.Info( $" 希望更新間隔: {希望更新間隔sec * 1000.0} ミリ秒" );
-                               FDK.Log.Info( $" 更新間隔: {this.更新間隔ms} ミリ秒 ({this.更新間隔sample} samples)" );
-                               FDK.Log.Info( $" 最小間隔: {最小間隔ms} ミリ秒" );
+                               FDK.Log.Info( $" 更新間隔: {this.更新間隔sec * 1000.0} ミリ秒 ({this.更新間隔sample} samples)" );
+                               if( 共有モード == CSCore.CoreAudioAPI.AudioClientShareMode.Exclusive )
+                                       FDK.Log.Info( $" 最小間隔: {FDK.Utilities.変換_100ns単位からsec単位へ( 排他モードでの最小間隔100ns )} ミリ秒" );
                                //-----------------
                                #endregion
 
@@ -147,7 +164,7 @@ namespace FDK.メディア.サウンド.WASAPI
                                // MediaFoundation が管理する、プロセス&MMCSSタスクごとに1つずつ作ることができる特別な共有ワークキューを取得、または生成して取得する。
                                int dwTaskId = 0;
                                SharpDX.MediaFoundation.MediaFactory.LockSharedWorkQueue(
-                                       ( 11.0 > this.更新間隔ms ) ? "Pro Audio" : "Games", 0, ref dwTaskId, out this.QueueID );
+                                       ( 0.011 > this.更新間隔sec ) ? "Pro Audio" : "Games", 0, ref dwTaskId, out this.QueueID );
 
                                // エンドポイントバッファからの出力要請イベントを作成し、AudioClient に登録する。
                                this.出力要請イベント = CreateEvent( IntPtr.Zero, false, false, "WASAPI出力要請イベント" );
@@ -239,15 +256,14 @@ namespace FDK.メディア.サウンド.WASAPI
                        this.Mixer.サウンドを削除する( sound );
                }
 
-               // WASAPI オブジェクト
+               protected CSCore.CoreAudioAPI.AudioClientShareMode 共有モード;
                protected CSCore.CoreAudioAPI.AudioClient AudioClient = null;
                protected CSCore.CoreAudioAPI.AudioRenderClient AudioRenderClient = null;
-
-               // エンドポイントバッファ情報
-               protected int 更新間隔sample = 0;   // デバイスから取得する。
-               protected float 更新間隔ms;
-               protected int 更新間隔byte;
                protected CSCore.WaveFormat WaveFormat = null;
+               protected long 更新間隔100ns = 0;
+               protected int 更新間隔sample = 0;
+               protected int 更新間隔byte => ( this.更新間隔sample * this.WaveFormat.Channels * this.WaveFormat.BytesPerSample );
+               protected double 更新間隔sec => ( FDK.Utilities.変換_100ns単位からsec単位へ( this.更新間隔100ns ) );
 
                // ミキサー。サウンドリストもここ。
                protected Mixer Mixer = null;
index 268cb71..31d1038 100644 (file)
@@ -146,6 +146,15 @@ namespace SST
                // ・このサービスインターフェースは、シングルスレッド(GUIスレッド)で同期実行される。(StrokeStyleT クラスの ServiceBehavior属性を参照。)
                // ・このサービスホストはシングルトンであり、すべてのクライアントセッションは同一(単一)のサービスインスタンスへ接続される。(Program.Main() を参照。)
 
+               /// <summary>
+               /// 曲を読み込み、演奏を開始する。
+               /// </summary>
+               /// <remarks>
+               /// ビュアーモードのときのみ有効。
+               /// </remarks>
+               /// <param name="path">曲ファイルパス</param>
+               /// <param name="startPart">演奏開始小節番号(0..)</param>
+               /// <param name="drumsSound">ドラムチップ音を発声させるなら true。</param>
                public void ViewerPlay( string path, int startPart = 0, bool drumsSound = true )
                {
                        if( StrokeStyleT.ビュアーモードではない )
@@ -158,6 +167,12 @@ namespace SST
                                ドラムチップ発声 = drumsSound,
                        } );
                }
+               /// <summary>
+               /// 現在の演奏を停止する。
+               /// </summary>
+               /// <remarks>
+               /// ビュアーモードのときのみ有効。
+               /// </remarks>
                public void ViewerStop()
                {
                        if( StrokeStyleT.ビュアーモードではない )
@@ -167,12 +182,16 @@ namespace SST
                                種別 = ViewerMessageType.演奏停止,
                        } );
                }
+               /// <summary>
+               /// サウンドデバイスの発声遅延[ms]を返す。
+               /// </summary>
+               /// <returns>遅延量[ms]</returns>
                public float GetSoundDelay()
                {
                        if( StrokeStyleT.ビュアーモードではない )
                                return 0f;
 
-                       return ( null != StrokeStyleT.Wasapiデバイス ) ? StrokeStyleT.Wasapiデバイス.遅延ms : 0f;
+                       return ( null != StrokeStyleT.Wasapiデバイス ) ? (float) ( StrokeStyleT.Wasapiデバイス.遅延sec * 1000.0 ) : 0f;
                }
                //----------------
                #endregion
@@ -289,7 +308,7 @@ namespace SST
                        #region " WASAPI デバイスを初期化する。"
                        //----------------
                        StrokeStyleT.bs_Wasapiデバイス = new FDK.メディア.サウンド.WASAPI.Device();
-                       StrokeStyleT.bs_Wasapiデバイス.初期化する( 15.0f );
+                       StrokeStyleT.bs_Wasapiデバイス.初期化する( CSCore.CoreAudioAPI.AudioClientShareMode.Exclusive, 0.015 );
                        //----------------
                        #endregion
                        #region " キーボード入力 を初期化する。"
index ccad00f..e9f2819 100644 (file)
@@ -60,7 +60,7 @@ namespace SST.ステージ.曲読込
                                                        float 作成時遅延ms = StrokeStyleT.演奏スコア.Header.サウンドデバイス遅延ms;
                                                        if( 0f < 作成時遅延ms )
                                                        {
-                                                               float 再生時遅延ms = StrokeStyleT.Wasapiデバイス.遅延ms;
+                                                               float 再生時遅延ms = (float) ( StrokeStyleT.Wasapiデバイス.遅延sec * 1000.0 );
                                                                long 加算分ms = (long) ( 作成時遅延ms - 再生時遅延ms );  // 例: 作成時遅延 7ms, 再生時遅延 10ms の場合、発声時刻に 7-10 = -3ms 加算する(3ms 早く発声させる)。
 
                                                                FDK.Log.Info( $"作成時遅延={作成時遅延ms}ms, 再生時遅延={再生時遅延ms}ms => 加算分 = {加算分ms}ms" );