// 初期化。 public static void 状態をリセットする() { スコア = null; データ種別 = データ種別.DTX; Random = new Random((int)(Stopwatch.GetTimestamp() % int.MaxValue)); 行番号 = 0; コマンド = ""; コマンドzzなし = ""; zz16進数 = -1; zz36進数 = -1; パラメータ = ""; コメント = ""; 小節番号 = 0; チャンネル番号 = 0; チップ種別 = チップ種別.Unknown; 小節解像度 = 384; // DTX の小節解像度は 384 固定 オブジェクト総数 = 0; オブジェクト番号 = 0; PAN定義マップ = new Dictionary <int, int>(); VOLUME定義マップ = new Dictionary <int, int>(); BGMWAVリスト = new List <int>(); BASEBPM = 0.0; BPM定義マップ = new Dictionary <int, double>(); BPM参照マップ = new Dictionary <チップ, int>(); 小節長倍率マップ = new SortedDictionary <int, double>(); }
private static (double 最小BPM, double 最大BPM) _最小最大BPMを調べて返す(SSTF.スコア score) { var result = (最小BPM : double.MaxValue, 最大BPM : double.MinValue); foreach (var chip in score.チップリスト.Where((c) => (c.チップ種別 == SSTF.チップ種別.BPM))) { result.最小BPM = Math.Min(result.最小BPM, chip.BPM); result.最大BPM = Math.Max(result.最大BPM, chip.BPM); } if (result.最小BPM == double.MaxValue || result.最大BPM == double.MinValue) { // BPMチップがひとつもなかった double 初期BPM = SSTF.スコア.初期BPM; result = (初期BPM, 初期BPM); } return(result); }
// ローカル private Dictionary <演奏.表示レーン種別, int> _ノーツ数を算出して返す(SSTF.スコア score, ユーザ設定 userConfig) { // ノーツ数マップを初期化。 var ノーツ数マップ = new Dictionary <演奏.表示レーン種別, int>(); foreach (演奏.表示レーン種別?lane in Enum.GetValues(typeof(演奏.表示レーン種別))) { if (lane.HasValue) { ノーツ数マップ.Add(lane.Value, 0); } } // 譜面内のすべてのチップについて…… foreach (var chip in score.チップリスト) { var prop = userConfig.ドラムチッププロパティリスト[chip.チップ種別]; // 1. AutoPlay ON のチップは、すべてが ON である場合を除いて、カウントしない。 if (userConfig.AutoPlay[prop.AutoPlay種別]) { if (!(userConfig.AutoPlayがすべてONである)) { continue; } } // 2. AutoPlay OFF 時でも、ユーザヒットの対象にならないチップはカウントしない。 if (!(prop.AutoPlayOFF_ユーザヒット)) { continue; } // カウント。 ノーツ数マップ[prop.表示レーン種別]++; } return(ノーツ数マップ); }
// ローカル internal static void _スコア読み込み時の後処理を行う(スコア score) { #region " 小節の先頭チップを追加する。" //---------------- { int 最大小節番号 = score.最大小節番号を返す(); // 「小節の先頭」チップは、小節線と同じく、全小節の先頭位置に置かれる。 // 小節線には今後譜面作者によって位置をアレンジできる可能性を残したいが、 // ビュアーが小節の先頭位置を検索するためには、小節の先頭に置かれるチップが必要になる。 // よって、譜面作者の影響を受けない(ビュアー用の)チップを機械的に配置する。 for (int i = 0; i <= 最大小節番号; i++) { score.チップリスト.Add( new チップ() { 小節番号 = i, チップ種別 = チップ種別.小節の先頭, 小節内位置 = 0, 小節解像度 = 1, }); } } //---------------- #endregion #region " チップリストを並び替える。" //---------------- score.チップリスト.Sort(); //---------------- #endregion #region " 全チップの発声/描画時刻と譜面内位置を計算する。" //----------------- { // 1. BPMチップを無視し(初期BPMで固定)、小節長倍率, 小節解像度, 小節内位置 から 発声/描画時刻を計算する。 // 以下、チップリストが小節番号順にソートされているという前提で。 double チップが存在する小節の先頭時刻ms = 0.0; int 現在の小節の番号 = 0; foreach (チップ chip in score.チップリスト) { // チップの小節番号が現在の小節の番号よりも大きい場合、チップが存在する小節に至るまで、チップが存在する小節の先頭時刻ms を更新する。 while (現在の小節の番号 < chip.小節番号) // 現在の小節番号 が chip.小節番号 に追いつくまでループする。 { double 現在の小節の小節長倍率 = score.小節長倍率を取得する(現在の小節の番号); チップが存在する小節の先頭時刻ms += _BPM初期値固定での1小節4拍の時間ms * 現在の小節の小節長倍率; 現在の小節の番号++; } // チップの発声/描画時刻を求める。 double チップが存在する小節の小節長倍率 = score.小節長倍率を取得する(現在の小節の番号); double 時刻sec = (チップが存在する小節の先頭時刻ms + (_BPM初期値固定での1小節4拍の時間ms * チップが存在する小節の小節長倍率 * chip.小節内位置) / (double)chip.小節解像度) / 1000.0; chip.発声時刻sec = 時刻sec; chip.描画時刻sec = 時刻sec; } // 2. 次に、BPMチップを考慮しながら調整する。 double 現在のBPM = スコア.初期BPM; int チップ数 = score.チップリスト.Count; for (int i = 0; i < チップ数; i++) { var BPMチップ = score.チップリスト[i]; if (BPMチップ.チップ種別 != チップ種別.BPM) { continue; // BPM チップ以外は無視。 } // BPMチップより後続の全チップの 発声/描画時刻ms を、新旧BPMの比率(加速率)で修正する。 double 加速率 = BPMチップ.BPM / 現在のBPM; // BPMチップ.dbBPM > 0.0 であることは読み込み時に保証済み。 for (int j = i + 1; j < チップ数; j++) { double 時刻sec = BPMチップ.発声時刻sec + (score.チップリスト[j].発声時刻sec - BPMチップ.発声時刻sec) / 加速率; score.チップリスト[j].発声時刻sec = 時刻sec; score.チップリスト[j].描画時刻sec = 時刻sec; } 現在のBPM = BPMチップ.BPM; } } //----------------- #endregion }