public 譜面(メインフォーム form) { this.Form = form; // 初期化 this.SSTFormatScore = new スコア(); this.譜面表示下辺の譜面内絶対位置grid = 0; foreach (var kvp in this.dicレーン番号) { this.dicレーン番号逆引き.Add(kvp.Value, kvp.Key); } #region " 最初は10小節ほど用意しておく → 10小節目の先頭に Unknown チップを置くことで実現。" //----------------- this.SSTFormatScore.チップリスト.Add( new 描画用チップ() { チップ種別 = チップ種別.Unknown, 小節番号 = 9, // 0から数えて10番目の小節 = 009 小節解像度 = 1, 小節内位置 = 0, 譜面内絶対位置grid = 9 * this.Form.GRID_PER_PART, // 小節009の先頭位置 }); //----------------- #endregion }
internal static bool _行解析_オブジェクト記述(ref スコア スコア, ref C行解析時の状態変数 現在の, string コマンド, string パラメータ, string コメント) { if (!(_小節番号とチャンネル番号を取得する(コマンド, out 現在の.小節番号, out 現在の.チャンネル番号))) { return(false); } パラメータ = パラメータ.Replace("_", ""); // 見やすさのために '_' を区切り文字として使用できる(DTX仕様) パラメータ = パラメータ.ToLower(); // すべて小文字化(三十六進数変換表には大文字がないので) if (0x02 == 現在の.チャンネル番号) { #region " ch02 小節長倍率 " //---------------- if (!(_DTX仕様の実数を取得する(パラメータ, out float 小節長倍率))) { Debug.WriteLineIf(Verbose, $"{現在の.行番号}: ch02 のパラメータ(小節長倍率)に指定された実数の解析に失敗しました。"); return(false); } else if (0.0 >= 小節長倍率) { Debug.WriteLineIf(Verbose, $"{現在の.行番号}: ch02 のパラメータ(小数長倍率)に 0 または負数を指定することはできません。"); return(false); } 現在の.小節長倍率マップ.Remove(現在の.小節番号); // 上書き可 現在の.小節長倍率マップ[現在の.小節番号] = 小節長倍率; return(true); //---------------- #endregion }
internal static bool _行解析_BPMzz(ref スコア スコア, ref C行解析時の状態変数 現在の, string コマンド, string パラメータ, string コメント) { if (!(コマンド.ToLower().StartsWith("bpm", ignoreCase: true, culture: null)) || (5 != コマンド.Length)) { return(false); } int zz = _三十六進数変換表.IndexOf(コマンド[3]) * 36 + _三十六進数変換表.IndexOf(コマンド[4]); // 36進数2桁表記 if ((1 > zz) || (36 * 36 - 1 < zz)) { return(false); // 有効範囲は 1~3599 } if (float.TryParse(パラメータ, out float bpm値) && (0f < bpm値) && (1000f > bpm値)) // 値域制限はDTX仕様 { // ※ 無限管理には非対応。 現在の.BPM定義マップ.Remove(zz); // 上書き可 現在の.BPM定義マップ[zz] = bpm値; return(true); } else { return(false); } }
public void Dispose() { this.SSTFormatScore = null; this.小節番号文字フォント?.Dispose(); this.小節番号文字フォント = null; this.小節番号文字ブラシ?.Dispose(); this.小節番号文字ブラシ = null; this.小節番号文字フォーマット?.Dispose(); this.小節番号文字フォーマット = null; this.ガイド線ペン?.Dispose(); this.ガイド線ペン = null; this.小節線ペン?.Dispose(); this.小節線ペン = null; this.拍線ペン?.Dispose(); this.拍線ペン = null; this.レーン区分線ペン?.Dispose(); this.レーン区分線ペン = null; this.レーン区分線太ペン?.Dispose(); this.レーン区分線太ペン = null; this.カレントラインペン?.Dispose(); this.カレントラインペン = null; this.レーン名文字フォント?.Dispose(); this.レーン名文字フォント = null; this.レーン名文字ブラシ?.Dispose(); this.レーン名文字ブラシ = null; this.レーン名文字影ブラシ?.Dispose(); this.レーン名文字影ブラシ = null; this.レーン名文字フォーマット?.Dispose(); this.レーン名文字フォーマット = null; this.チップの太枠ペン?.Dispose(); this.チップの太枠ペン = null; this.チップ内文字列フォーマット?.Dispose(); this.チップ内文字列フォーマット = null; this.チップ内文字列フォント?.Dispose(); this.チップ内文字列フォント = null; this.白丸白バツペン?.Dispose(); this.白丸白バツペン = null; this.Form = null; }
internal static bool _行解析_COMMENT(ref スコア スコア, ref C行解析時の状態変数 現在の, string コマンド, string パラメータ, string コメント) { if ("comment" != コマンド.ToLower()) { return(false); } スコア.Header.説明文 = パラメータ; return(true); }
internal static bool _行解析_TITLE(ref スコア スコア, ref C行解析時の状態変数 現在の, string コマンド, string パラメータ, string コメント) { if ("title" != コマンド.ToLower()) { return(false); } スコア.Header.曲名 = パラメータ; return(true); }
/// <summary> /// 行からDTXデータを読み込み、スコアを生成する。 /// </summary> /// <returns>生成されたスコア。</returns> public static スコア ReadFromString(string 全入力文字列) { var スコア = new スコア(); // 解析 _行解析(ref スコア, ref 全入力文字列); // 後処理 スコア.曲データファイルを読み込む_後処理だけ(); return(スコア); }
public ゲームランナー(int 回数, bool サイレントモード = false) { var ゲーム = new ゲーム(サイレントモード); var スコア = new スコア(); for (var index = 0; index < 回数; index++) { スコア.勝者登録(ゲーム.実行()); } Console.WriteLine(スコア); }
internal static bool _行解析_BASEBPM(ref スコア スコア, ref C行解析時の状態変数 現在の, string コマンド, string パラメータ, string コメント) { if ("basebpm" != コマンド.ToLower()) { return(false); } if (float.TryParse(パラメータ, out float bpm値)) { 現在の.BASEBPM = bpm値; // 上書き可 return(true); } else { return(false); } }
internal static bool _行解析_BPM(ref スコア スコア, ref C行解析時の状態変数 現在の, string コマンド, string パラメータ, string コメント) { if ("bpm" != コマンド.ToLower()) { return(false); } if (float.TryParse(パラメータ, out float bpm値)) { // ※ 無限管理には非対応。 //bpm値 += 現在の.BASEBPM; --> #BPM: の値には #BASEBPM を加算しない。(DTX仕様) // "#BPM:" に対応するBPMチップは、常に、小節番号==0かつ小節内位置==0に置かれる。 var bpmChip = スコア.チップリスト.FirstOrDefault((c) => (c.チップ種別 == チップ種別.BPM && c.小節番号 == 0 && c.小節内位置 == 0)); if (null != bpmChip) { // (A) すでに存在するなら上書き bpmChip.BPM = bpm値; } else { // (B) まだ存在していないなら新規追加 bpmChip = new チップ() { チップ種別 = チップ種別.BPM, 小節番号 = 0, 小節解像度 = 現在の.小節解像度, 小節内位置 = 0, 音量 = チップ.最大音量, BPM = bpm値, }; スコア.チップリスト.Add(bpmChip); } return(true); } else { return(false); } }
// ローカル private Dictionary <演奏.表示レーン種別, int> _ノーツ数を算出して返す(スコア 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 ドラムチッププロパティ = userConfig.ドラムチッププロパティリスト[chip.チップ種別]; // 1. AutoPlay ON のチップは、すべてが ON である場合を除いて、カウントしない。 if (userConfig.AutoPlay[ドラムチッププロパティ.AutoPlay種別]) { if (!(userConfig.AutoPlayがすべてONである)) { continue; } } // 2. AutoPlay OFF 時でも、ユーザヒットの対象にならないチップはカウントしない。 if (!(ドラムチッププロパティ.AutoPlayOFF_ユーザヒット)) { continue; } // カウント。 ノーツ数マップ[ドラムチッププロパティ.表示レーン種別]++; } return(ノーツ数マップ); }
private static (double 最小BPM, double 最大BPM) _最小最大BPMを調べて返す(スコア score) { var result = (最小BPM : double.MaxValue, 最大BPM : double.MinValue); var BPMchips = score.チップリスト.Where((c) => (c.チップ種別 == チップ種別.BPM)); foreach (var chip in BPMchips) { 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 = スコア.初期BPM; result = (初期BPM, 初期BPM); } return(result); }
public void 曲データファイルを読み込む(string ファイル名) { // 解放 this.SSTFormatScore = null; // 読み込み this.SSTFormatScore = スコア.ファイルから生成する(ファイル名); // 後処理 #region " 小節線・拍線チップをすべて削除する。" //----------------- this.SSTFormatScore.チップリスト.RemoveAll((chip) => ( chip.チップ種別 == チップ種別.小節線 || chip.チップ種別 == チップ種別.拍線 || chip.チップ種別 == チップ種別.Unknown)); //----------------- #endregion #region " チップリストのすべてのチップを、描画用チップに変換する。" //---------------- { // バックアップを取って、 var 元のチップリスト = new チップ[this.SSTFormatScore.チップリスト.Count]; for (int i = 0; i < this.SSTFormatScore.チップリスト.Count; i++) { 元のチップリスト[i] = this.SSTFormatScore.チップリスト[i]; } // クリアして、 this.SSTFormatScore.チップリスト.Clear(); // 再構築。 for (int i = 0; i < 元のチップリスト.Length; i++) { this.SSTFormatScore.チップリスト.Add(new 描画用チップ(元のチップリスト[i])); } } //---------------- #endregion #region " 全チップに対して「譜面内絶対位置grid」を設定する。" //----------------- { int チップが存在する小節の先頭grid = 0; int 現在の小節番号 = 0; foreach (描画用チップ chip in this.SSTFormatScore.チップリスト) { // チップの小節番号が現在の小節番号よりも大きい場合、チップが存在する小節に至るまで、「nチップが存在する小節の先頭grid」を更新する。 while (現在の小節番号 < chip.小節番号) { double 現在の小節の小節長倍率 = this.SSTFormatScore.小節長倍率を取得する(現在の小節番号); チップが存在する小節の先頭grid += (int)(this.Form.GRID_PER_PART * 現在の小節の小節長倍率); 現在の小節番号++; // 現在の小節番号 が chip.小節番号 に追いつくまでループする。 } chip.譜面内絶対位置grid = チップが存在する小節の先頭grid + (chip.小節内位置 * this.小節長をグリッドで返す(chip.小節番号)) / chip.小節解像度; } } //----------------- #endregion }
internal static void _行解析(ref スコア スコア, ref string 全入力文字列) { // 現在の状態の初期化。 var 現在の = new C行解析時の状態変数() { 小節番号 = 0, 小節解像度 = 384, // DTX の小節解像度。 チップ種別 = チップ種別.Unknown, 小節長倍率マップ = new SortedDictionary <int, float>(), BPM定義マップ = new Dictionary <int, float>(), BPM参照マップ = new Dictionary <チップ, int>(), }; Debug.WriteLineIf(Verbose, "行解析を開始します。"); #region " 前処理(1) TAB は SPACE に置換しておく。" //---------------- 全入力文字列 = 全入力文字列.Replace('\t', ' '); //---------------- #endregion #region " すべての行について解析。" //---------------- using (var sr = new StringReader(全入力文字列)) { string 行; // 1行ずつ処理。 for (現在の.行番号 = 1; (行 = sr.ReadLine()) != null; 現在の.行番号++) { // 行分解。 if (!(_行分解(行, out string コマンド, out string パラメータ, out string コメント))) { Debug.WriteLineIf(Verbose, $"{現在の.行番号}: 行分解に失敗しました。"); continue; } if (string.IsNullOrEmpty(コマンド)) { continue; } // 行処理。 var done = _行解析_TITLE(ref スコア, ref 現在の, コマンド, パラメータ, コメント) || _行解析_COMMENT(ref スコア, ref 現在の, コマンド, パラメータ, コメント) || _行解析_BASEBPM(ref スコア, ref 現在の, コマンド, パラメータ, コメント) || _行解析_BPM(ref スコア, ref 現在の, コマンド, パラメータ, コメント) || _行解析_BPMzz(ref スコア, ref 現在の, コマンド, パラメータ, コメント) || _行解析_オブジェクト記述(ref スコア, ref 現在の, コマンド, パラメータ, コメント); // 行処理に失敗 //if( !( done ) ) // Debug.WriteLineIf( Verbose, $"{現在の.行番号}: 未知のコマンドが使用されました。スキップします。[{コマンド}]" ); } } //---------------- #endregion #region " 後処理(1) BPMチップの値を引き当てる。" //---------------- { foreach (var kvp in 現在の.BPM参照マップ) { kvp.Key.BPM = 現在の.BPM定義マップ[kvp.Value] + 現在の.BASEBPM; // 複数あるなら最後の値が入っている。 } 現在の.BPM参照マップ.Clear(); // 引き当てが終わったら、マップが持つチップへの参照を解放する。 } //---------------- #endregion #region " 後処理(2) 小節長倍率マップをもとに、スコアの小節長倍率リストを構築する。" //---------------- { double 現在の倍率 = 1.0f; for (int i = 0; i <= スコア.最大小節番号; i++) // すべての小節に対して設定。(SST仕様) { if (現在の.小節長倍率マップ.ContainsKey(i)) { 現在の倍率 = (double)現在の.小節長倍率マップ[i]; // 指定された倍率は、それが指定された小節以降の小節にも適用する。(DTX仕様) } スコア.小節長倍率を設定する(i, 現在の倍率); } } //---------------- #endregion // 解析終了。 Debug.WriteLineIf(Verbose, "行解析を終了しました。"); }