OSDN Git Service

SSTFEditor から Viewer モードの StrokeStyleT を使って再生する機能を実装。ただし、まだ曲の先頭からの再生のみ。
authorくまかみ工房 <kumakamikoubou@gmail.com>
Sun, 6 Nov 2016 14:27:12 +0000 (23:27 +0900)
committerくまかみ工房 <kumakamikoubou@gmail.com>
Sun, 6 Nov 2016 14:27:12 +0000 (23:27 +0900)
SSTFEditor/SSTFEditor.csproj
SSTFEditor/メインフォーム.cs
SSTFEditor/譜面/C譜面.cs
SSTFormat/スコア.cs
StrokeStyleT/StrokeStyleT.cs
StrokeStyleT/StrokeStyleT.csproj
StrokeStyleT/ViewerMessage.cs [new file with mode: 0644]
StrokeStyleT/ステージ/演奏/スクロール譜面.cs
StrokeStyleT/ステージ/演奏/演奏ステージ.cs

index 01ffe94..585a0de 100644 (file)
@@ -36,6 +36,8 @@
   <ItemGroup>
     <Reference Include="System" />
     <Reference Include="System.Core" />
+    <Reference Include="System.ServiceModel" />
+    <Reference Include="System.ServiceModel.Channels" />
     <Reference Include="System.Xml.Linq" />
     <Reference Include="System.Data.DataSetExtensions" />
     <Reference Include="Microsoft.CSharp" />
       <Project>{f6bd5fad-8cbd-4df4-89bf-bbdbe6c5c6fe}</Project>
       <Name>SSTFormat</Name>
     </ProjectReference>
+    <ProjectReference Include="..\StrokeStyleT\StrokeStyleT.csproj">
+      <Project>{ed72fd06-c276-42dc-9301-83de699bdf4c}</Project>
+      <Name>StrokeStyleT</Name>
+    </ProjectReference>
   </ItemGroup>
   <ItemGroup>
     <WCFMetadata Include="Service References\" />
index 44c2fb9..9b448d9 100644 (file)
@@ -6,6 +6,8 @@ using System.IO;
 using System.IO.Pipes;
 using System.Linq;
 using System.Reflection;
+using System.ServiceModel;
+using System.ServiceModel.Channels;
 using System.Text.RegularExpressions;
 using System.Windows.Forms;
 using FDK;     // for string拡張
@@ -225,6 +227,9 @@ namespace SSTFEditor
                protected int 現在のガイド間隔 = 0;
                protected Point 選択モードのコンテクストメニューを開いたときのマウスの位置;
 
+               protected ChannelFactory<SST.IStrokeStyleTService> SSTファクトリ = null;
+               protected SST.IStrokeStyleTService SSTサービス = null;
+
                private bool bs_未保存である = false;
                private SSTFormat.チップ種別 bs_e現在のチップ種別;
                private int bs_GRID_PER_PIXEL = 1;
@@ -282,7 +287,7 @@ namespace SSTFEditor
                        
                        // 最近使ったファイル一覧を更新する。
                        this.ConfigのRecentUsedFilesをファイルメニューへ追加する();
-                       
+
                        // その他の初期化。
                        this.Act新規作成する();
                        this.Actガイド間隔を変更する( 16 );   // 初期は 1/16 間隔。
@@ -293,13 +298,24 @@ namespace SSTFEditor
                }
                protected void Actアプリを終了する()
                {
+                       // SSTファクトリを閉じる。
+                       this.SSTサービス = null;    // サービスは解放処理なし
+                       try
+                       {
+                               this.SSTファクトリ.Close();
+                       }
+                       catch( CommunicationException )
+                       {
+                               // すでに通信が閉じられている(SSTサービスホストが終了している)。
+                       }
+
                        // 一時ファイルが残っていれば、削除する。
                        if( File.Exists( this.最後にプレイヤーに渡した一時ファイル名 ) )
                                File.Delete( this.最後にプレイヤーに渡した一時ファイル名 );
 
                        // Config.xml を保存する。
                        this.Config.保存する( Path.Combine( this.ユーザフォルダパス, Properties.Resources.CONFIG_FILE_NAME ) );
-                       
+
                        FDK.Utilities.解放する( ref this.譜面 );
                        FDK.Utilities.解放する( ref this.選択モード );
                }
@@ -766,43 +782,53 @@ namespace SSTFEditor
                                this.最後にプレイヤーに渡した一時ファイル名, 
                                一時ファイルである: true );    // 一時ファイルなので、「最近使ったファイル一覧」には残さない。
 
-                       using( var stream = new NamedPipeServerStream( "SSTFEditor Viewer Device Information" ) )
+                       // SSTサービスを取得する。
+                       this.SSTサービスが起動していれば取得する();
+
+                       // SSTサービスが起動していない場合は、Viewer プロセスを起動する。
+                       if( null == this.SSTサービス )
                        {
-                               // ビュアーを起動する。
-                               string 仮想ドラムオプション = ( 仮想ドラムを使う ) ? @" -d" : @"";
                                try
                                {
-                                       Process.Start(
-                                               this.Config.ViewerPath,
-                                               $"\"{this.最後にプレイヤーに渡した一時ファイル名}\" -p {小節番号.ToString()}{仮想ドラムオプション}" );
+                                       Process.Start( this.Config.ViewerPath );
                                }
                                catch
                                {
-                                       return; // 起動に失敗。
+                                       return; // 起動に失敗。
                                }
 
-                               // デバイス情報を得る。
-                               stream.WaitForConnection();
-
-                               using( var reader = new StreamReader( stream ) )
+                               // Viewer の提供するSSTサービスへ接続する。
+                               for( int retry = 0; retry < 10; retry++ )       // 最大10回リトライ。
                                {
-                                       var msg = reader.ReadLine();
+                                       this.SSTサービスが起動していれば取得する();
 
-                                       var match = Regex.Match( msg, @"^SoundDevice.Delay=(\d+(\.\d+)?)$" );  // 負数やべき乗には非対応。
-                                       if( match.Success )
-                                       {
-                                               var strValue = match.Groups[ 1 ].Value;
-                                               float value = 0f;
-                                               if( float.TryParse( strValue, out value ) )     // 正しく float に変換できる文字列なら、
-                                               {
-                                                       this.textBoxサウンド遅延ms.Text = strValue;   // GUI と、
-                                                       this.譜面.SSTFormatScore.Header.サウンドデバイス遅延ms = value; // 譜面にセットする。
+                                       if( null != this.SSTサービス )
+                                               break;  // サービスに接続できた。
 
-                                                       this.未保存である = true;
-                                               }
-                                       }
+                                       // 少し待ってリトライ。
+                                       System.Threading.Thread.Sleep( 500 );
+                               }
+                               if( null == this.SSTサービス )
+                               {
+                                       this.Viewer再生関連GUIのEnabledを設定する();
+                                       return; // サービスへの接続に失敗した。
                                }
                        }
+
+                       // サウンドデバイス遅延を取得する。
+                       float 遅延ms = this.SSTサービス.GetSoundDelay();
+                       if( this.譜面.SSTFormatScore.Header.サウンドデバイス遅延ms != 遅延ms )
+                       {
+                               this.textBoxサウンド遅延ms.Text = 遅延ms.ToString();                            // GUI と
+                               this.譜面.SSTFormatScore.Header.サウンドデバイス遅延ms = 遅延ms;  // 譜面にセットする。
+                               this.未保存である = true;
+                       }
+
+                       // 演奏開始を指示する。
+                       this.SSTサービス.ViewerPlay(
+                               path: this.最後にプレイヤーに渡した一時ファイル名,
+                               startPart: 小節番号,
+                               drumsSound: 仮想ドラムを使う );
                }
                protected void Act再生を停止する()
                {
@@ -1429,34 +1455,33 @@ namespace SSTFEditor
                }
                protected void Viewer再生関連GUIのEnabledを設定する()
                {
-                       if( File.Exists( this.Config.ViewerPath ) )
-                       {
-                               // (A) Viewer が存在するなら、各GUIは有効。
-
-                               this.toolStripButton先頭から再生.Enabled = true;
-                               this.toolStripButton現在位置から再生.Enabled = true;
-                               this.toolStripButton現在位置からBGMのみ再生.Enabled = true;
-                               this.toolStripButton再生停止.Enabled = true;
+                       bool 各GUIは有効 = false;
 
-                               this.toolStripMenuItem先頭から再生.Enabled = true;
-                               this.toolStripMenuItem現在位置から再生.Enabled = true;
-                               this.toolStripMenuItem現在位置からBGMのみ再生.Enabled = true;
-                               this.toolStripMenuItem再生停止.Enabled = true;
+                       if( null != this.SSTサービス )
+                       {
+                               // (A) SSTサービスが起動しているなら、各GUIは有効。
+                               各GUIは有効 = true;
+                       }
+                       else if( File.Exists( this.Config.ViewerPath ) )
+                       {
+                               // (B) SSTサービスが起動していなくても、Viewer が存在するなら、各GUIは有効。
+                               各GUIは有効 = true;
                        }
                        else
                        {
-                               // (B) Viewer が存在しないなら、各GUIは無効。
+                               // (C) SSTサービスが起動しておらず、Viewer も存在しないなら、各GUIは無効。
+                               各GUIは有効 = false;
+                       }
 
-                               this.toolStripButton先頭から再生.Enabled = false;
-                               this.toolStripButton現在位置から再生.Enabled = false;
-                               this.toolStripButton現在位置からBGMのみ再生.Enabled = false;
-                               this.toolStripButton再生停止.Enabled = false;
+                       this.toolStripButton先頭から再生.Enabled = 各GUIは有効;
+                       this.toolStripButton現在位置から再生.Enabled = 各GUIは有効;
+                       this.toolStripButton現在位置からBGMのみ再生.Enabled = 各GUIは有効;
+                       this.toolStripButton再生停止.Enabled = 各GUIは有効;
 
-                               this.toolStripMenuItem先頭から再生.Enabled = false;
-                               this.toolStripMenuItem現在位置から再生.Enabled = false;
-                               this.toolStripMenuItem現在位置からBGMのみ再生.Enabled = false;
-                               this.toolStripMenuItem再生停止.Enabled = false;
-                       }
+                       this.toolStripMenuItem先頭から再生.Enabled = 各GUIは有効;
+                       this.toolStripMenuItem現在位置から再生.Enabled = 各GUIは有効;
+                       this.toolStripMenuItem現在位置からBGMのみ再生.Enabled = 各GUIは有効;
+                       this.toolStripMenuItem再生停止.Enabled = 各GUIは有効;
                }
                protected void ConfigのRecentUsedFilesをファイルメニューへ追加する()
                {
@@ -1533,6 +1558,25 @@ namespace SSTFEditor
                {
                        this.toolStripLabel音量.Text = ( this.dic音量ラベル.ContainsKey( this.現在のチップ音量 ) ) ? this.dic音量ラベル[ this.現在のチップ音量 ] : @"???";
                }
+               protected void SSTサービスが起動していれば取得する()
+               {
+                       // ファクトリが未生成なら生成する。
+                       if( null == this.SSTファクトリ )
+                               this.SSTファクトリ = new ChannelFactory<SST.IStrokeStyleTService>( new NetNamedPipeBinding( NetNamedPipeSecurityMode.None ) );
+
+                       // サービスが未取得なら取得する。
+                       if( null == this.SSTサービス )
+                       {
+                               try
+                               {
+                                       this.SSTサービス = this.SSTファクトリ.CreateChannel( new EndpointAddress( "net.pipe://localhost/StrokeStyleT/Viewer" ) );
+                               }
+                               catch( EndpointNotFoundException )
+                               {
+                                       this.SSTサービス = null;    // 取得失敗。
+                               }
+                       }
+               }
 
                // GUIイベントメソッド
 
index 4bc0381..cf24868 100644 (file)
@@ -50,6 +50,7 @@ namespace SSTFEditor
                                { SSTFormat.チップ種別.小節線, 編集レーン種別.Unknown },
                                { SSTFormat.チップ種別.拍線, 編集レーン種別.Unknown },
                                { SSTFormat.チップ種別.小節メモ, 編集レーン種別.Unknown },
+                               { SSTFormat.チップ種別.小節の先頭, 編集レーン種別.Unknown },
                                { SSTFormat.チップ種別.Unknown, 編集レーン種別.Unknown },
                        };
                        //-----------------
index dbe77df..7d63d4c 100644 (file)
@@ -1313,6 +1313,7 @@ namespace SSTFormat
                                                if( cc.チップ種別 == チップ種別.小節線 ||
                                                        cc.チップ種別 == チップ種別.拍線 ||
                                                        cc.チップ種別 == チップ種別.小節メモ ||
+                                                       cc.チップ種別 == チップ種別.小節の先頭 ||
                                                        cc.チップ種別 == チップ種別.Unknown )
                                                {
                                                        continue;   // これらは出力しないので無視。
@@ -1353,7 +1354,7 @@ namespace SSTFormat
                                        {
                                                var lane = (レーン種別) laneObj;
 
-                                               if( 0 < dicレーン別チップリスト[ lane ].Count )
+                                               if( 0 < dicレーン別チップリスト[ lane ].Count ) 
                                                {
                                                        sw.Write( $"Lane={lane.ToString()}; " );
 
index dc99463..607fe88 100644 (file)
@@ -1,4 +1,5 @@
 using System;
+using System.Collections.Concurrent;
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.Linq;
@@ -136,22 +137,28 @@ namespace SST
                        if( StrokeStyleT.ビュアーモードではない )
                                return;
 
-                       // todo: 演奏を開始する。
+                       this.ビュアーメッセージキュー.Enqueue( new ViewerMessage() {
+                               種別 = ViewerMessageType.演奏開始,
+                               曲ファイルパス = path,
+                               演奏開始小節番号 = startPart,
+                               ドラムチップ発声 = drumsSound,
+                       } );
                }
                public void ViewerStop()
                {
                        if( StrokeStyleT.ビュアーモードではない )
                                return;
 
-                       // todo: 演奏を停止する。
+                       this.ビュアーメッセージキュー.Enqueue( new ViewerMessage() {
+                               種別 = ViewerMessageType.演奏停止,
+                       } );
                }
                public float GetSoundDelay()
                {
                        if( StrokeStyleT.ビュアーモードではない )
                                return 0f;
 
-                       // todo: 発声遅延[ms]を返す。
-                       return 0f;
+                       return ( null != StrokeStyleT.Wasapiデバイス ) ? StrokeStyleT.Wasapiデバイス.遅延ms : 0f;
                }
                //----------------
                #endregion
@@ -160,6 +167,7 @@ namespace SST
                protected ApplicationState State;
                protected SharpDX.Windows.RenderForm MainForm = null;
                protected SharpDX.Size2F 設計画面サイズdpx = SharpDX.Size2F.Empty;
+               protected ConcurrentQueue<ViewerMessage> ビュアーメッセージキュー = new ConcurrentQueue<ViewerMessage>();
                protected FDK.メディア.デバイスリソース デバイスリソース = null;
                protected SST.ステージ.ステージ 最初のダミーステージ = null;
                protected SST.ステージ.起動.起動ステージ 起動ステージ = null;
@@ -423,6 +431,7 @@ namespace SST
                                SharpDX.DXGI.PresentFlags.None );
                        //----------------
                        #endregion
+
                        #region " ステージの状態をチェックし、必要あれば遷移またはアプリを終了する。"
                        //----------------
                        if( null != this.現在のステージ )
@@ -434,12 +443,18 @@ namespace SST
                                                //----------------
                                                if( StrokeStyleT.ビュアーモードである )
                                                {
+                                                       // ビュアー用ユーザでログインする。
                                                        FDK.Log.Info( "ビュアーモード: AutoPlayer ユーザでログインします。" );
                                                        this.ログインする( Properties.Resources.AUTOPLAYER );
 
+                                                       // 曲読込ステージ向けの初期設定。
                                                        StrokeStyleT.曲ツリー管理.現在の管理対象ツリー = null;
                                                        StrokeStyleT.曲ツリー管理.現在選択されているノード = null;
+                                                       
+                                                       // 演奏ステージ向けの初期設定。
+                                                       StrokeStyleT.演奏スコア = null;
 
+                                                       // 演奏ステージへ。
                                                        this.演奏ステージ.活性化する( this.デバイスリソース );
                                                        this.現在のステージ = this.演奏ステージ;
                                                }
@@ -564,26 +579,113 @@ namespace SST
                                                break;
 
                                        case nameof( ステージ.演奏.演奏ステージ ):
-                                               #region " 演奏終了 → 結果ステージへ。"
-                                               //--------------------
-                                               if( this.演奏ステージ.現在のフェーズ.Value == ステージ.演奏.演奏ステージ.フェーズ.クリアor失敗 )
+                                               if( StrokeStyleT.ビュアーモードである )
                                                {
-                                                       this.現在のステージ.非活性化する( this.デバイスリソース );
-                                                       this.現在のステージ = this.結果ステージ;
-                                                       this.現在のステージ.活性化する( this.デバイスリソース );
+                                                       // (A) ビュアーモード
+
+                                                       #region " ビュアーメッセージがあれば処理する。"
+                                                       //----------------
+                                                       var msg = this.ビュアーメッセージを取得する();
+
+                                                       if( null != msg )
+                                                       {
+                                                               #region " (A) 演奏開始 "
+                                                               //----------------
+                                                               if( msg.種別 == ViewerMessageType.演奏開始 && (
+                                                                       this.演奏ステージ.現在のフェーズ.Value == ステージ.演奏.演奏ステージ.フェーズ.ビュアーメッセージ待機中 ||
+                                                                       this.演奏ステージ.現在のフェーズ.Value == ステージ.演奏.演奏ステージ.フェーズ.演奏中 )
+                                                                       )
+                                                               {
+                                                                       // MusicNode を作成する。
+                                                                       var node = (SST.曲.MusicNode) null;
+                                                                       try
+                                                                       {
+                                                                               node = new 曲.MusicNode( msg.曲ファイルパス );
+                                                                       }
+                                                                       catch
+                                                                       {
+                                                                               FDK.Log.ERROR( $"MusicNode の作成に失敗しました。" );
+                                                                               node = null;
+                                                                       }
+
+                                                                       // 作成に成功したときのみ次へ進む。
+                                                                       if( null != node )
+                                                                       {
+                                                                               // 演奏を停止する。
+                                                                               this.演奏ステージ.非活性化する( this.デバイスリソース );
+                                                                               this.演奏ステージ.BGMを解放する();
+
+                                                                               // 現在選択されているノードとして登録する。
+                                                                               StrokeStyleT.曲ツリー管理.現在選択されているノード = node;
+
+                                                                               // todo: 演奏開始小節番号を保存し、反映する。
+
+                                                                               // 曲読込ステージへ。
+                                                                               this.現在のステージ = this.曲読込ステージ;
+                                                                               this.曲読込ステージ.活性化する( this.デバイスリソース );
+                                                                       }
+                                                               }
+                                                               //----------------
+                                                               #endregion
+                                                               #region " (B) 演奏停止 "
+                                                               //----------------
+                                                               else if( msg.種別 == ViewerMessageType.演奏停止 && (
+                                                                       this.演奏ステージ.現在のフェーズ.Value == ステージ.演奏.演奏ステージ.フェーズ.ビュアーメッセージ待機中 ||
+                                                                       this.演奏ステージ.現在のフェーズ.Value == ステージ.演奏.演奏ステージ.フェーズ.演奏中 )
+                                                                       )
+                                                               {
+                                                                       this.演奏ステージ.演奏を停止する();
+                                                                       this.演奏ステージ.現在のフェーズ.Value = ステージ.演奏.演奏ステージ.フェーズ.ビュアーメッセージ待機中;
+                                                               }
+                                                               //----------------
+                                                               #endregion
+                                                               #region " その他 "
+                                                               //----------------
+                                                               else
+                                                               {
+                                                                       // その他のメッセージは無視。
+                                                               }
+                                                               //----------------
+                                                               #endregion
+                                                       }
+                                                       //----------------
+                                                       #endregion
+                                                       #region " クリア/キャンセル → メッセージ待機へ。"
+                                                       //----------------
+                                                       if( this.演奏ステージ.現在のフェーズ.Value == ステージ.演奏.演奏ステージ.フェーズ.クリアor失敗 ||
+                                                               this.演奏ステージ.現在のフェーズ.Value == ステージ.演奏.演奏ステージ.フェーズ.キャンセル )
+                                                       {
+                                                               // フェーズのみ変更。BGM は止めない。
+                                                               this.演奏ステージ.現在のフェーズ.Value = ステージ.演奏.演奏ステージ.フェーズ.ビュアーメッセージ待機中;
+                                                       }
+                                                       //----------------
+                                                       #endregion
                                                }
-                                               //--------------------
-                                               #endregion
-                                               #region " キャンセル → 選曲ステージへ。"
-                                               //--------------------
-                                               if( this.演奏ステージ.現在のフェーズ.Value == ステージ.演奏.演奏ステージ.フェーズ.キャンセル )
+                                               else
                                                {
-                                                       this.現在のステージ.非活性化する( this.デバイスリソース );
-                                                       this.現在のステージ = this.選曲ステージ;
-                                                       this.現在のステージ.活性化する( this.デバイスリソース );
+                                                       // (B) 通常モード
+
+                                                       #region " 演奏終了 → 結果ステージへ。"
+                                                       //--------------------
+                                                       if( this.演奏ステージ.現在のフェーズ.Value == ステージ.演奏.演奏ステージ.フェーズ.クリアor失敗 )
+                                                       {
+                                                               this.現在のステージ.非活性化する( this.デバイスリソース );
+                                                               this.現在のステージ = this.結果ステージ;
+                                                               this.現在のステージ.活性化する( this.デバイスリソース );
+                                                       }
+                                                       //--------------------
+                                                       #endregion
+                                                       #region " キャンセル → 選曲ステージへ。"
+                                                       //--------------------
+                                                       if( this.演奏ステージ.現在のフェーズ.Value == ステージ.演奏.演奏ステージ.フェーズ.キャンセル )
+                                                       {
+                                                               this.現在のステージ.非活性化する( this.デバイスリソース );
+                                                               this.現在のステージ = this.選曲ステージ;
+                                                               this.現在のステージ.活性化する( this.デバイスリソース );
+                                                       }
+                                                       //--------------------
+                                                       #endregion
                                                }
-                                               //--------------------
-                                               #endregion
                                                break;
 
                                        case nameof( ステージ.結果.結果ステージ ):
@@ -687,6 +789,20 @@ namespace SST
                        StrokeStyleT.ユーザ管理.ユーザを選択する( ユーザ名 );
                        FDK.Log.Info( $"ユーザが選択されました。[{StrokeStyleT.ユーザ管理.現在選択されているユーザ.名前}]" );
                }
+               /// <returns>メッセージがない場合は null を返す。</returns>
+               private ViewerMessage ビュアーメッセージを取得する()
+               {
+                       var msg = (ViewerMessage) null;
+
+                       if( StrokeStyleT.ビュアーモードである &&
+                               ( 0 < this.ビュアーメッセージキュー.Count ) &&
+                               this.ビュアーメッセージキュー.TryDequeue( out msg ) )
+                       {
+                               return msg;
+                       }
+
+                       return null;
+               }
 
                #region " バックストア。"
                //----------------
index 99acdf8..3b313f9 100644 (file)
@@ -94,6 +94,7 @@
   <ItemGroup>
     <Compile Include="IStrokeStyleTService.cs" />
     <Compile Include="Win32.cs" />
+    <Compile Include="ViewerMessage.cs" />
     <Compile Include="曲\タイトルテクスチャ.cs" />
     <Compile Include="ステージ\選曲\曲パネルビュー.cs" />
     <Compile Include="設定\Config.cs" />
diff --git a/StrokeStyleT/ViewerMessage.cs b/StrokeStyleT/ViewerMessage.cs
new file mode 100644 (file)
index 0000000..f0cc16e
--- /dev/null
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+
+namespace SST
+{
+       enum ViewerMessageType
+       {
+               指示なし,
+               演奏開始,
+               演奏停止,
+       }
+
+       class ViewerMessage
+       {
+               public ViewerMessageType 種別 { get; set; } = ViewerMessageType.指示なし;
+               public string 曲ファイルパス { get; set; } = null;
+               public int 演奏開始小節番号 { get; set; } = 0;
+               public bool ドラムチップ発声 { get; set; } = true;
+       }
+}
index 05aaa7b..df031bc 100644 (file)
@@ -64,6 +64,10 @@ namespace SST.ステージ.演奏
                {
                        this.画面の高さdpx = dr.設計画面サイズdpx.Height;
                }
+               public void 演奏を停止する()
+               {
+                       this.描画開始チップ番号 = -1;
+               }
                public void 小節線拍線を進行描画する( デバイスリソース dr, double 現在の演奏時刻sec )
                {
                        this.画面内に収まるチップをすべて進行描画する(
index 6335cb7..a4a1d71 100644 (file)
@@ -71,7 +71,7 @@ namespace SST.ステージ.演奏
                                this.ドラムサウンド.発声する( chip.チップ種別, chip.音量 * 0.25f );
                        };
                        this.スクロール譜面.ステージクリア = () => {
-                               this.現在のフェーズ.Value = ( StrokeStyleT.ビュアーモードである ) ? フェーズ.ビュアーメッセージ待機中 : フェーズ.クリアor失敗;
+                               this.現在のフェーズ.Value = フェーズ.クリアor失敗;
                        };
                        this.スクロール譜面.リアルタイム演奏時刻sec = () => {
                                return this.現在の演奏時刻secを返す();
@@ -117,7 +117,18 @@ namespace SST.ステージ.演奏
                        foreach( var 判定 in typeof( ヒット判定種別 ).GetEnumValues() )
                                this.ヒットした回数[ (ヒット判定種別) 判定 ] = 0;
 
-                       this.現在のフェーズ.Value = ( StrokeStyleT.ビュアーモードである ) ? フェーズ.ビュアーメッセージ待機中 : フェーズ.演奏中;
+                       // 最初のフェーズを設定する。
+                       if( StrokeStyleT.ビュアーモードである )
+                       {
+                               // 演奏スコアが設定済みなら演奏開始。それ以外ならメッセージ待機へ。
+                               this.現在のフェーズ.Value = ( null != StrokeStyleT.演奏スコア ) ? フェーズ.演奏中 : フェーズ.ビュアーメッセージ待機中;
+                       }
+                       else
+                       {
+                               // 演奏開始。
+                               this.現在のフェーズ.Value = フェーズ.演奏中;
+                       }
+
                        this.活性化した直後である = true;
                }
                protected override void On非活性化( デバイスリソース dr )
@@ -193,7 +204,6 @@ namespace SST.ステージ.演奏
                        this.スクロール譜面.チップを進行描画する( dr, 演奏時刻sec );
                        this.回転羽.進行描画する( dr );
                        this.FPS.VPSをカウントする();
-                       this.FPS.FPSをカウントする();
                        this.FPS画像.表示文字列 = $"VPS: {this.FPS.現在のVPS.ToString()} / FPS: {this.FPS.現在のFPS.ToString()}";
                        this.FPS画像.進行描画する( dr, 0f, 0f );
 
@@ -203,7 +213,7 @@ namespace SST.ステージ.演奏
 
                        // ESC 押下 → キャンセル
                        if( StrokeStyleT.キーボード入力.キーが押された( SharpDX.DirectInput.Key.Escape ) &&
-                               ( false == StrokeStyleT.ビュアーモードである ) )
+                               StrokeStyleT.ビュアーモードではない )  // ビュアーモードでは無効。
                        {
                                this.BGMを解放する();
                                this.現在のフェーズ.Value = フェーズ.キャンセル;
@@ -222,6 +232,11 @@ namespace SST.ステージ.演奏
                        }
                }
 
+               public void 演奏を停止する()
+               {
+                       this.スクロール譜面?.演奏を停止する();
+                       this.BGMを解放する();
+               }
                public void BGMを解放する()
                {
                        if( null != this.BGM )  // 背景動画がなければ BGM も null である