/// 入力:
/// StrokeStyleT.演奏スコア(ビュアーモードなら null でも可)
/// StrokeStyleT.ユーザ管理.現在選択されているユーザ(譜面スクロール速度の倍率)
- /// StrokeStyleT.ビュアーモードである
/// StrokeStyleT.Wasapiデバイス.AudioClock
+ /// StrokeStyleT.ビュアーモードである
+ /// StrokeStyleT.最後に取得したビュアーメッセージ
///
/// 出力:
/// (A) クリアまたは失敗した場合
this.スクロール譜面.ヒット判定数加算 = ( hitType ) => {
this.ヒットした回数[ hitType ]++;
};
- this.スクロール譜面.背景動画再生開始 = () => {
+ this.スクロール譜面.背景動画の長さsec = () => {
+ return ( null != this.BGM ) ? this.BGM.長さsec : 0.0;
+ };
+ this.スクロール譜面.背景動画再生開始 = ( 開始位置sec ) => {
+ this.背景動画.再生を開始する( 開始位置sec );
this.背景動画開始済み.Value = true;
+ this.BGM?.再生を開始する( 開始位置sec );
+ this.BGM再生開始済み = true;
};
this.スクロール譜面.チップヒット = ( chip ) => {
this.回転羽.発火する( chip.チップ種別 );
- this.ドラムサウンド.発声する( chip.チップ種別, chip.音量 * 0.25f );
+ if( this.Autoチップのドラム音を再生する )
+ this.ドラムサウンド.発声する( chip.チップ種別, chip.音量 * 0.25f );
};
this.スクロール譜面.ステージクリア = () => {
- this.現在のフェーズ.Value = ( StrokeStyleT.ビュアーモードである ) ? フェーズ.ビュアーメッセージ待機中 : フェーズ.クリアor失敗;
+ this.現在のフェーズ.Value = フェーズ.クリアor失敗;
};
this.スクロール譜面.リアルタイム演奏時刻sec = () => {
return this.現在の演奏時刻secを返す();
this.子リスト.Add( this.背景動画 = new 動画( StrokeStyleT.演奏スコア.背景動画ファイル名, StrokeStyleT.Config.動画デコーダのキューサイズ ) );
// 動画から BGM を作成してミキサーに追加。
- this.BGM = new FDK.メディア.サウンド.WASAPI排他.Sound();
+ this.BGM = new FDK.メディア.サウンド.WASAPIold.Sound();
this.BGM.ファイルから作成する( StrokeStyleT.演奏スコア.背景動画ファイル名 );
StrokeStyleT.Wasapiデバイス.サウンドをミキサーに追加する( this.BGM ); // 作成に失敗した Sound を追加しても鳴らないだけなので、ノーチェックで大丈夫。
}
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 )
{
this.活性化した直後である = false;
this.FPS = new FDK.カウンタ.FPS();
- this.演奏開始時刻sec = this.サウンドタイマ.現在のデバイス位置secを取得する( StrokeStyleT.Wasapiデバイス.AudioClock );
+
+ double 演奏開始位置の先頭からの時間sec = 0.0;
+ var msg = StrokeStyleT.最後に取得したビュアーメッセージ;
+ if( null != msg )
+ {
+ 演奏開始位置の先頭からの時間sec = this.スクロール譜面.演奏開始小節番号を設定しその時刻secを返す( msg.演奏開始小節番号 );
+ this.Autoチップのドラム音を再生する = msg.ドラムチップ発声;
+ }
+ this.演奏開始時刻sec =
+ this.サウンドタイマ.現在のデバイス位置secを取得する( StrokeStyleT.Wasapiデバイス.AudioClock ) - // '+' じゃないので注意!
+ 演奏開始位置の先頭からの時間sec;
}
//----------------
#endregion
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 );
// ESC 押下 → キャンセル
if( StrokeStyleT.キーボード入力.キーが押された( SharpDX.DirectInput.Key.Escape ) &&
- ( false == StrokeStyleT.ビュアーモードである ) )
+ StrokeStyleT.ビュアーモードではない ) // ビュアーモードでは無効。
{
this.BGMを解放する();
this.現在のフェーズ.Value = フェーズ.キャンセル;
Math.Max( StrokeStyleT.ユーザ管理.現在選択されているユーザ.譜面スクロール速度の倍率 - 0.5, 0.5 ); // 最小 0.5
}
}
-
+ public void 演奏を停止する()
+ {
+ this.スクロール譜面?.演奏を停止する();
+ this.背景動画開始済み.Value = false;
+ this.BGMを解放する();
+ }
public void BGMを解放する()
{
if( null != this.BGM ) // 背景動画がなければ BGM も null である
FDK.Utilities.解放する( ref this.BGM );
}
}
- public void 演奏開始小節から描画開始チップと演奏開始時刻を取得する( int 演奏開始小節番号, out int 描画開始チップ番号, out double 演奏開始時刻sec )
- {
- const double 小節の先頭時刻から実際に演奏開始する時刻までの差sec = -0.5; // ← 早めるので負数
- var score = StrokeStyleT.演奏スコア;
-
- 描画開始チップ番号 = -1;
- 演奏開始時刻sec = 0.0;
-
- #region " 条件チェック。"
- //----------------
- Trace.Assert( 0 <= 演奏開始小節番号, $"不正な演奏開始小節番号が指定されました。[{演奏開始小節番号}]" );
-
- if( this.活性化していない )
- {
- FDK.Log.ERROR( "活性化されていません。" );
- return;
- }
- if( StrokeStyleT.ビュアーモードではない )
- {
- if( null == score )
- {
- FDK.Log.ERROR( "演奏スコアが null です。" );
- return;
- }
- if( null == score.チップリスト )
- {
- FDK.Log.ERROR( "演奏スコアのチップリストが null です。" );
- return;
- }
- }
- //----------------
- #endregion
-
- #region " 描画開始チップ(仮決め)を検索する。"
- //----------------
- for( int i = 0; i < score.チップリスト.Count; i++ )
- {
- // チップ種別「小節の先頭」が必ずひっかかるはず。
- if( 演奏開始小節番号 <= score.チップリスト[ i ].小節番号 )
- {
- 描画開始チップ番号 = i;
- break; // 発見。
- }
- }
-
- if( 0 > 描画開始チップ番号 )
- {
- // 見つからなかった場合、演奏開始位置は曲の終了後を示しているものとみなす。
- 描画開始チップ番号 = Math.Max( 0, score.チップリスト.Count - 1 ); // 一番最後(空なら先頭)のチップを選択する。
- }
- //----------------
- #endregion
- #region " 描画開始チップの発声時刻よりちょっと早めの時刻を演奏開始時刻とし、描画開始チップを再検索する必要があれば行う(本決め)。"
- //----------------
- 演奏開始時刻sec =
- score.チップリスト[ 描画開始チップ番号 ].発声時刻sec +
- 小節の先頭時刻から実際に演奏開始する時刻までの差sec;
-
- // 現在の描画開始チップから、前に戻る方向へ検索する。
- for( int i = ( 描画開始チップ番号 - 1 ); i >= 0; i-- )
- {
- if( score.チップリスト[ i ].発声時刻sec < 演奏開始時刻sec )
- break; // 再検索終了。
-
- 描画開始チップ番号 = i;
- }
- //----------------
- #endregion
- }
protected bool 活性化した直後である = false;
protected FDK.同期.RWLock<bool> 背景動画開始済み = new FDK.同期.RWLock<bool>( false );
protected bool BGM再生開始済み = false;
protected FDK.同期.RWLock<double> 現在進行描画中の譜面スクロール速度の倍率 = new FDK.同期.RWLock<double>( 0.0 );
protected double 演奏開始時刻sec = 0.0;
- protected readonly FDK.メディア.サウンド.WASAPI排他.SoundTimer サウンドタイマ = new FDK.メディア.サウンド.WASAPI排他.SoundTimer();
+ protected bool Autoチップのドラム音を再生する = true;
+ protected readonly FDK.メディア.サウンド.WASAPIold.SoundTimer サウンドタイマ = new FDK.メディア.サウンド.WASAPIold.SoundTimer();
protected readonly SST.ステージ.演奏.コンボ コンボ;
protected readonly SST.ステージ.演奏.レーンフレーム レーンフレーム;
protected readonly SST.ステージ.演奏.スクロール譜面 スクロール譜面;
/// 解放は、演奏ステージクラスの非活性化後に、外部から行われる。
/// <see cref="SST.ステージ.演奏.演奏ステージ.BGMを解放する"/>
/// </remarks>
- protected FDK.メディア.サウンド.WASAPI排他.Sound BGM = null;
+ protected FDK.メディア.サウンド.WASAPIold.Sound BGM = null;
protected FDK.カウンタ.FPS FPS = null;
/// <summary>
/// 動的子Activity。背景動画を再生しない場合は null のまま。