// 進行と描画 public void 描画する(DeviceContext dc) { var 領域 = new RectangleF(78f, 455f, 357f, 55f); if (App進行描画.曲ツリー.フォーカス曲ノード != this._現在表示しているノード) { #region " フォーカスノードが変更されたので情報を更新する。" //---------------- this._現在表示しているノード = App進行描画.曲ツリー.フォーカス曲ノード; this._最小BPM = 120.0; this._最大BPM = 120.0; if (null != this._現在表示しているノード) { using (var songdb = new SongDB()) { var song = songdb.Songs.Where((r) => (r.Path == this._現在表示しているノード.曲ファイルの絶対パス.数なしパス)).SingleOrDefault(); if (null != song) { this._最小BPM = song.MinBPM ?? 120.0; this._最大BPM = song.MaxBPM ?? 120.0; } } } //---------------- #endregion } this._BPMパネル.描画する(領域.X - 5f, 領域.Y - 4f); bool 表示可能ノードである = (this._現在表示しているノード is MusicNode); // 現状、BPMを表示できるノードは MusicNode のみ。 if (表示可能ノードである) { // BPM を表示する。 if (10.0 >= Math.Abs(this._最大BPM - this._最小BPM)) // 差が10以下なら同一値とみなす。 { // (A) 「最小値」だけ描画。 this._パラメータ文字.描画する(dc, 領域.X + 120f, 領域.Y, this._最小BPM.ToString("0").PadLeft(3)); } else { // (B) 「最小~最大」を描画。 this._パラメータ文字.描画する(dc, 領域.X + 80f, 領域.Y, this._最小BPM.ToString("0") + "~" + this._最大BPM.ToString("0")); } } }
public SetNode(SetDef.Block block, VariablePath 基点フォルダパス, Node 親ノード) : this() { this.タイトル = block.Title; this.親ノード = 親ノード; using (var songdb = new SongDB()) { for (int i = 0; i < 5; i++) { this.MusicNodes[i] = null; if (block.File[i].Nullでも空でもない()) { VariablePath 曲のパス = Path.Combine(基点フォルダパス.数なしパス, block.File[i]); if (File.Exists(曲のパス.数なしパス)) { try { this.MusicNodes[i] = new MusicNode(Path.Combine(基点フォルダパス.数なしパス, block.File[i]), this); this.難易度[i].label = block.Label[i]; this.子ノードリスト.Add(this.MusicNodes[i]); var song = songdb.Songs.Where((r) => (r.Path == this.MusicNodes[i].曲ファイルの絶対パス.数なしパス)).SingleOrDefault(); this.難易度[i].level = (null != song) ? (float)song.Level : 0.00f; } catch { Log.ERROR("SetNode 内での MusicNode の生成に失敗しました。"); } } else { Log.ERROR($"set.def 内に指定されたファイルが存在しません。無視します。[{曲のパス.変数付きパス}] "); } } } } // 基点フォルダパス(set.def ファイルと同じ場所)に画像ファイルがあるなら、それをノード画像として採用する。 var サムネイル画像ファイルパス = (from ファイル名 in Directory.GetFiles(基点フォルダパス.数なしパス) where _対応するサムネイル画像名.Any(thumbファイル名 => (Path.GetFileName(ファイル名).ToLower() == thumbファイル名)) select ファイル名).FirstOrDefault(); if (null != サムネイル画像ファイルパス) { this.子Activityを追加する(this._ノード画像 = new テクスチャ(サムネイル画像ファイルパス)); } }
public MusicNode(VariablePath 曲ファイルパス, Node 親ノード) { this.親ノード = 親ノード; this.曲ファイルパス = 曲ファイルパス; // (まだ存在してなければ)曲DBに追加する。 曲DB.曲を追加または更新する(this.曲ファイルパス, App.ユーザ管理.ログオン中のユーザ); // 追加後、改めて曲DBから情報を取得する。 using (var songdb = new SongDB()) { var song = songdb.Songs.Where((r) => (r.Path == this.曲ファイルパス.数なしパス)).SingleOrDefault(); if (null != song) { this.タイトル = song.Title; this.サブタイトル = ""; this.サブタイトル = song.Artist; this.曲ファイルハッシュ = song.HashId; this.難易度[3] = ("FREE", (float)song.Level); // [3]:MASTER相当。set.def 内にある MusicNode でも同じ。 } // サムネイル画像を決定する。 string サムネイル画像ファイルパス = null; if (song.PreImage.Nullでも空でもない() && File.Exists(song.PreImage)) { // (A) DB に保存されている値があり、そのファイルが存在するなら、それを使う。 サムネイル画像ファイルパス = song.PreImage; } else { // (B) DB に保存されてない場合、曲ファイルと同じ場所に画像ファイルがあるなら、それをノード画像として採用する。 サムネイル画像ファイルパス = (from ファイル名 in Directory.GetFiles(Path.GetDirectoryName(this.曲ファイルパス.数なしパス)) where _対応するサムネイル画像名.Any(thumbファイル名 => (Path.GetFileName(ファイル名).ToLower() == thumbファイル名)) select ファイル名).FirstOrDefault(); } if (null != サムネイル画像ファイルパス) { this.子リスト.Add(this.ノード画像 = new テクスチャ(サムネイル画像ファイルパス)); } } // 曲ファイルと同じ場所に(対応する拡張子を持った)動画ファイルがあるなら、それを背景動画として採用する。 this.動画ファイルパス = (from ファイル名 in Directory.GetFiles(Path.GetDirectoryName(this.曲ファイルパス.数なしパス)) where _対応する動画の拡張子.Any(拡張子名 => (Path.GetExtension(ファイル名).ToLower() == 拡張子名)) select ファイル名).FirstOrDefault()?.ToVariablePath(); }
public void 描画する(グラフィックデバイス gd) { var 領域 = new RectangleF(78f, 455f, 357f, 55f); #region " ノードが変更されていたら情報を更新する。" //---------------- if (App.曲ツリー.フォーカスノード != this._現在表示しているノード) { this._現在表示しているノード = App.曲ツリー.フォーカス曲ノード; // MusicNode 以外は null が返される this._最小BPM = 120.0; this._最大BPM = 120.0; if (null != this._現在表示しているノード) { using (var songdb = new SongDB()) { var song = songdb.Songs.Where((r) => (r.Path == this._現在表示しているノード.曲ファイルパス.数なしパス)).SingleOrDefault(); if (null != song) { this._最小BPM = song.MinBPM ?? 120.0; this._最大BPM = song.MaxBPM ?? 120.0; } } } } //---------------- #endregion bool 表示可能ノードである = (this._現在表示しているノード is MusicNode); this._BPMパネル.描画する(gd, 領域.X - 5f, 領域.Y - 4f); if (表示可能ノードである) { if (10.0 >= Math.Abs(this._最大BPM - this._最小BPM)) { // (A) 「最小値」だけ描画。差が10以下なら同一値とみなす。 this._パラメータ文字.描画する(gd, 領域.X + 120f, 領域.Y, this._最小BPM.ToString("0").PadLeft(3)); } else { // (B) 「最小~最大」を描画。 this._パラメータ文字.描画する(gd, 領域.X + 80f, 領域.Y, this._最小BPM.ToString("0") + "~" + this._最大BPM.ToString("0")); } } }
public static void Main() { var songDB = new SongDB(); var numberOfSongs = int.Parse(Console.ReadLine()); for (int i = 0; i < numberOfSongs; i++) { var input = Console.ReadLine(); var songParams = input.Split(';'); try { var currentSong = new Song(songParams[0], songParams[1], songParams[2]); songDB.AddSong(currentSong); Console.WriteLine("Song added."); } catch (Exception e) { Console.WriteLine(e.Message); } } Console.WriteLine(songDB); }
public MusicNode(VariablePath 曲ファイルの絶対パス, Node 親ノード) { this.親ノード = 親ノード; this.曲ファイルの絶対パス = 曲ファイルの絶対パス; // (まだ存在してなければ)曲DBに追加する。 曲DB.曲を追加または更新する(this.曲ファイルの絶対パス, App.ユーザ管理.ログオン中のユーザ); // 追加後、改めて曲DBから情報を取得する。 using (var songdb = new SongDB()) { var song = songdb.Songs.Where((r) => (r.Path == this.曲ファイルの絶対パス.数なしパス)).SingleOrDefault(); if (null == song) { return; } this.タイトル = song.Title; this.サブタイトル = ""; this.サブタイトル = song.Artist; this.曲ファイルハッシュ = song.HashId; this.難易度[3] = ("FREE", (float)song.Level); // [3]:MASTER相当。set.def 内にある MusicNode でも同じ。 if (song.PreImage.Nullでも空でもない()) { var プレビュー画像ファイルの絶対パス = Path.Combine(Path.GetDirectoryName(song.Path), song.PreImage); this.子Activityを追加する(this.ノード画像 = new テクスチャ(プレビュー画像ファイルの絶対パス)); } if (song.PreSound.Nullでも空でもない()) { this.プレビュー音声ファイルの絶対パス = Path.Combine(Path.GetDirectoryName(song.Path), song.PreSound); } } }
public void 描画する(グラフィックデバイス gd) { var 領域dpx = new RectangleF(320f, 532f, 239f, 505f); #region " ノードが変更されていたら情報を更新する。" //---------------- if (App.曲ツリー.フォーカス曲ノード != this._現在表示しているノード) { this._現在表示しているノード = App.曲ツリー.フォーカス曲ノード; // MusicNode 以外は null が返される this._ノーツ数 = null; if (null != this._現在表示しているノード) { using (var songdb = new SongDB()) { var note = songdb.Songs.Where((r) => (r.HashId == this._現在表示しているノード.曲ファイルハッシュ)).SingleOrDefault(); if (null != note) { this._ノーツ数 = new Dictionary <表示レーン種別, int>() { { 表示レーン種別.Unknown, 0 }, { 表示レーン種別.LeftCrash, note.TotalNotes_LeftCymbal }, { 表示レーン種別.HiHat, note.TotalNotes_HiHat }, { 表示レーン種別.Foot, note.TotalNotes_LeftPedal }, { 表示レーン種別.Snare, note.TotalNotes_Snare }, { 表示レーン種別.Bass, note.TotalNotes_Bass }, { 表示レーン種別.Tom1, note.TotalNotes_HighTom }, { 表示レーン種別.Tom2, note.TotalNotes_LowTom }, { 表示レーン種別.Tom3, note.TotalNotes_FloorTom }, { 表示レーン種別.RightCrash, note.TotalNotes_RightCymbal }, }; } } } } //---------------- #endregion bool 表示可能ノードである = (this._現在表示しているノード is MusicNode); // 背景を表示。 this._背景画像.描画する(gd, 左位置: 領域dpx.X, 位置: 領域dpx.Y); // Total Notes を表示。 if (表示可能ノードである) { if (null != this._ノーツ数) { gd.D2DBatchDraw((dc) => { var Xオフセット = new Dictionary <表示レーン種別, float>() { { 表示レーン種別.LeftCrash, +70f }, { 表示レーン種別.HiHat, +88f }, { 表示レーン種別.Foot, +106f }, { 表示レーン種別.Snare, +124f }, { 表示レーン種別.Tom1, +142f }, { 表示レーン種別.Bass, +160f }, { 表示レーン種別.Tom2, +178f }, { 表示レーン種別.Tom3, +196f }, { 表示レーン種別.RightCrash, +214f }, }; const float Yオフセット = +2f; foreach (表示レーン種別 lane in Enum.GetValues(typeof(表示レーン種別))) { if (lane == 表示レーン種別.Unknown) { continue; } var 矩形 = new RectangleF(領域dpx.X + Xオフセット[lane], 領域dpx.Y + Yオフセット, 6f, 405f); 矩形.Top = 矩形.Bottom - (矩形.Height * Math.Min(this._ノーツ数[lane], 250) / 250f); dc.FillRectangle(矩形, this._色[lane]); } }); } } }
/// <summary> /// 指定した曲ファイルに対応するレコードがデータベースになければレコードを追加し、 /// あればそのレコードを更新する。 /// </summary> public static void 曲を追加または更新する(VariablePath 曲ファイルパス, ユーザ設定 ユーザ設定) { try { using (var songdb = new SongDB()) { var 一パス検索クエリ = songdb.Songs.Where((song) => (song.Path == 曲ファイルパス.数なしパス)); if (0 == 一パス検索クエリ.Count()) { // (A) 同一パスを持つレコードがDBになかった var 調べる曲のハッシュ = _ファイルのハッシュを算出して返す(曲ファイルパス); var 一ハッシュレコード = songdb.Songs.Where((song) => (song.HashId == 調べる曲のハッシュ)).SingleOrDefault(); if (null == 一ハッシュレコード) { #region " (A-a) 同一ハッシュを持つレコードがDBになかった → 新規追加 " //---------------- var 拡張子名 = Path.GetExtension(曲ファイルパス.数なしパス); var score = (SSTFormatCurrent.スコア)null; #region " スコアを読み込む " //---------------- if (".sstf" == 拡張子名) { score = new SSTFormatCurrent.スコア(曲ファイルパス.数なしパス); } else if (".dtx" == 拡張子名) { score = SSTFormatCurrent.DTXReader.ReadFromFile(曲ファイルパス.数なしパス); } else { throw new Exception($"未対応のフォーマットファイルです。[{曲ファイルパス.変数付きパス}]"); } //---------------- #endregion using ( score ) { // Songs レコード新規追加。 var ノーツ数 = _ノーツ数を算出して返す(score, ユーザ設定); var BPMs = _最小最大BPMを調べて返す(score); songdb.Songs.InsertOnSubmit( new Song() { HashId = _ファイルのハッシュを算出して返す(曲ファイルパス), Title = score.曲名, Path = 曲ファイルパス.数なしパス, LastWriteTime = File.GetLastWriteTime(曲ファイルパス.数なしパス).ToString("G"), Level = score.難易度, MinBPM = BPMs.最小BPM, MaxBPM = BPMs.最大BPM, TotalNotes_LeftCymbal = ノーツ数[表示レーン種別.LeftCrash], TotalNotes_HiHat = ノーツ数[表示レーン種別.HiHat], TotalNotes_LeftPedal = ノーツ数[表示レーン種別.Foot], TotalNotes_Snare = ノーツ数[表示レーン種別.Snare], TotalNotes_Bass = ノーツ数[表示レーン種別.Bass], TotalNotes_HighTom = ノーツ数[表示レーン種別.Tom1], TotalNotes_LowTom = ノーツ数[表示レーン種別.Tom2], TotalNotes_FloorTom = ノーツ数[表示レーン種別.Tom3], TotalNotes_RightCymbal = ノーツ数[表示レーン種別.RightCrash], // プレビュー画像は、曲ファイルからの相対パス。 PreImage = (score.プレビュー画像.Nullでも空でもない()) ? Path.Combine(Path.GetDirectoryName(曲ファイルパス.数なしパス), score.プレビュー画像) : "", Artist = score.アーティスト名, }); } songdb.DataContext.SubmitChanges(); Log.Info($"DBに曲を追加しました。{曲ファイルパス.変数付きパス}"); //---------------- #endregion } else { #region " (A-b) 同一ハッシュを持つレコードがDBにあった → 更新 " //---------------- var 拡張子名 = Path.GetExtension(曲ファイルパス.数なしパス); var score = (SSTFormatCurrent.スコア)null; #region " スコアを読み込む " //---------------- if (".sstf" == 拡張子名) { score = new SSTFormatCurrent.スコア(曲ファイルパス.数なしパス); } else if (".dtx" == 拡張子名) { score = SSTFormatCurrent.DTXReader.ReadFromFile(曲ファイルパス.数なしパス); } else { throw new Exception($"未対応のフォーマットファイルです。[{曲ファイルパス.変数付きパス}]"); } //---------------- #endregion using ( score ) { // Songs レコード更新。 var ノーツ数 = _ノーツ数を算出して返す(score, ユーザ設定); var BPMs = _最小最大BPMを調べて返す(score); var song = 一ハッシュレコード; song.Title = score.曲名; song.Path = 曲ファイルパス.数なしパス; song.LastWriteTime = File.GetLastWriteTime(曲ファイルパス.数なしパス).ToString("G"); song.Level = score.難易度; song.MinBPM = BPMs.最小BPM; song.MaxBPM = BPMs.最大BPM; song.TotalNotes_LeftCymbal = ノーツ数[表示レーン種別.LeftCrash]; song.TotalNotes_HiHat = ノーツ数[表示レーン種別.HiHat]; song.TotalNotes_LeftPedal = ノーツ数[表示レーン種別.Foot]; song.TotalNotes_Snare = ノーツ数[表示レーン種別.Snare]; song.TotalNotes_Bass = ノーツ数[表示レーン種別.Bass]; song.TotalNotes_HighTom = ノーツ数[表示レーン種別.Tom1]; song.TotalNotes_LowTom = ノーツ数[表示レーン種別.Tom2]; song.TotalNotes_FloorTom = ノーツ数[表示レーン種別.Tom3]; song.TotalNotes_RightCymbal = ノーツ数[表示レーン種別.RightCrash]; // プレビュー画像は、曲ファイルからの相対パス。 song.PreImage = (score.プレビュー画像.Nullでも空でもない()) ? Path.Combine(Path.GetDirectoryName(曲ファイルパス.数なしパス), score.プレビュー画像) : ""; song.Artist = score.アーティスト名; } songdb.DataContext.SubmitChanges(); Log.Info($"パスが異なりハッシュが同一であるレコードが検出されたため、曲の情報を更新しました。{曲ファイルパス.変数付きパス}"); //---------------- #endregion } } else { // (B) 同一パスを持つレコードがDBにあった var record = 一パス検索クエリ.Single(); string レコードの最終更新日時 = record.LastWriteTime; string 調べる曲の最終更新日時 = File.GetLastWriteTime(曲ファイルパス.数なしパス).ToString("G"); if (レコードの最終更新日時 != 調べる曲の最終更新日時) { #region " (B-a) 最終更新日時が変更されている → 更新 " //---------------- var 拡張子名 = Path.GetExtension(曲ファイルパス.数なしパス); var score = (SSTFormatCurrent.スコア)null; #region " スコアを読み込む " //---------------- if (".sstf" == 拡張子名) { score = new SSTFormatCurrent.スコア(曲ファイルパス.数なしパス); } else if (".dtx" == 拡張子名) { score = SSTFormatCurrent.DTXReader.ReadFromFile(曲ファイルパス.数なしパス); } else { throw new Exception($"未対応のフォーマットファイルです。[{曲ファイルパス.変数付きパス}]"); } //---------------- #endregion using ( score ) { var hash = _ファイルのハッシュを算出して返す(曲ファイルパス); var ノーツ数 = _ノーツ数を算出して返す(score, ユーザ設定); var BPMs = _最小最大BPMを調べて返す(score); // HashId 以外のカラムを更新する。 record.Title = score.曲名; record.LastWriteTime = 調べる曲の最終更新日時; record.Level = score.難易度; record.MinBPM = BPMs.最小BPM; record.MaxBPM = BPMs.最大BPM; record.TotalNotes_LeftCymbal = ノーツ数[表示レーン種別.LeftCrash]; record.TotalNotes_HiHat = ノーツ数[表示レーン種別.HiHat]; record.TotalNotes_LeftPedal = ノーツ数[表示レーン種別.Foot]; record.TotalNotes_Snare = ノーツ数[表示レーン種別.Snare]; record.TotalNotes_Bass = ノーツ数[表示レーン種別.Bass]; record.TotalNotes_HighTom = ノーツ数[表示レーン種別.Tom1]; record.TotalNotes_LowTom = ノーツ数[表示レーン種別.Tom2]; record.TotalNotes_FloorTom = ノーツ数[表示レーン種別.Tom3]; record.TotalNotes_RightCymbal = ノーツ数[表示レーン種別.RightCrash]; // プレビュー画像は、曲ファイルからの相対パス。 record.PreImage = (score.プレビュー画像.Nullでも空でもない()) ? Path.Combine(Path.GetDirectoryName(曲ファイルパス.数なしパス), score.プレビュー画像) : ""; record.Artist = score.アーティスト名; if (hash != record.HashId) { // ハッシュはキーなので、これが変わったら、古いレコードを削除して、新しいレコードを追加する。 var newRecord = record.Clone(); songdb.Songs.DeleteOnSubmit(record); songdb.DataContext.SubmitChanges(); // 一度Submitして先にレコード削除を確定しないと、次のInsertがエラーになる。(PathカラムはUnique属性なので) newRecord.HashId = hash; songdb.Songs.InsertOnSubmit(newRecord); } songdb.DataContext.SubmitChanges(); } Log.Info($"最終更新日時が変更されているため、曲の情報を更新しました。{曲ファイルパス.変数付きパス}"); //---------------- #endregion } else { #region " (B-b) それ以外 " //---------------- //---------------- #endregion } } } } catch (Exception e) { Log.ERROR($"曲DBへの曲の追加に失敗しました。({e.Message})[{曲ファイルパス.変数付きパス}]"); throw; } }
// 進行と描画 public void 描画する(DeviceContext dc) { var 領域dpx = new RectangleF(320f, 532f, 239f, 505f); if (App進行描画.曲ツリー.フォーカス曲ノード != this._現在表示しているノード) { #region " フォーカスノードが変更されたので情報を更新する。" //---------------- this._現在表示しているノード = App進行描画.曲ツリー.フォーカス曲ノード; // MusicNode 以外は null が返される this._ノーツ数 = null; if (null != this._現在表示しているノード) { using (var songdb = new SongDB()) { var note = songdb.Songs.Where((r) => (r.HashId == this._現在表示しているノード.曲ファイルハッシュ)).SingleOrDefault(); if (null != note) { this._ノーツ数 = new Dictionary <表示レーン種別, int>() { { 表示レーン種別.Unknown, 0 }, { 表示レーン種別.LeftCymbal, note.TotalNotes_LeftCymbal }, { 表示レーン種別.HiHat, note.TotalNotes_HiHat }, { 表示レーン種別.Foot, note.TotalNotes_LeftPedal }, { 表示レーン種別.Snare, note.TotalNotes_Snare }, { 表示レーン種別.Bass, note.TotalNotes_Bass }, { 表示レーン種別.Tom1, note.TotalNotes_HighTom }, { 表示レーン種別.Tom2, note.TotalNotes_LowTom }, { 表示レーン種別.Tom3, note.TotalNotes_FloorTom }, { 表示レーン種別.RightCymbal, note.TotalNotes_RightCymbal }, }; } } } //---------------- #endregion } this._背景画像.描画する(領域dpx.X, 領域dpx.Y); bool 表示可能ノードである = (this._現在表示しているノード is MusicNode); // 現状、曲ステータスを表示できるノードは MusicNode のみ。 if (表示可能ノードである) { // Total Notes を表示する。 if (null != this._ノーツ数) { グラフィックデバイス.Instance.D2DBatchDraw(dc, () => { dc.PrimitiveBlend = PrimitiveBlend.SourceOver; const float Yオフセット = +2f; var Xオフセット = new Dictionary <表示レーン種別, float>() { { 表示レーン種別.LeftCymbal, +70f }, { 表示レーン種別.HiHat, +88f }, { 表示レーン種別.Foot, +106f }, { 表示レーン種別.Snare, +124f }, { 表示レーン種別.Tom1, +142f }, { 表示レーン種別.Bass, +160f }, { 表示レーン種別.Tom2, +178f }, { 表示レーン種別.Tom3, +196f }, { 表示レーン種別.RightCymbal, +214f }, }; foreach (表示レーン種別 lane in Enum.GetValues(typeof(表示レーン種別))) { if (lane == 表示レーン種別.Unknown) { continue; } var 矩形 = new RectangleF(領域dpx.X + Xオフセット[lane], 領域dpx.Y + Yオフセット, 6f, 405f); 矩形.Top = 矩形.Bottom - (矩形.Height * Math.Min(this._ノーツ数[lane], 250) / 250f); dc.FillRectangle(矩形, this._色[lane]); } }); } } }