// TODO: refactor with ScoreExtensions.CalculateDuration(). public static void UpdateStartTime([NotNull] this Bar bar) { var score = bar.Basic.Score; var notes = score.GetAllNotes(); var allBpmNotes = notes.Where(n => n.Basic.Type == NoteType.VariantBpm).ToArray(); var currentTiming = score.Project.Settings.StartTimeOffset; var currentBpm = score.Project.Settings.BeatPerMinute; var currentInterval = BeatmapMathHelper.BpmToInterval(currentBpm); foreach (var b in score.Bars) { if (b == bar) { break; } var currentGridPerSignature = b.GetGridPerSignature(); var numGrids = b.GetNumberOfGrids(); if (allBpmNotes.Any(n => n.Basic.Bar == b)) { var bpmNotesInThisBar = allBpmNotes.Where(n => n.Basic.Bar == b).ToList(); bpmNotesInThisBar.Sort((n1, n2) => n1.Basic.IndexInGrid.CompareTo(n2.Basic.IndexInGrid)); var bpmNoteIndex = 0; for (var i = 0; i < numGrids; ++i) { if (bpmNoteIndex < bpmNotesInThisBar.Count) { var bpmNote = bpmNotesInThisBar[bpmNoteIndex]; Debug.Assert(bpmNote.Params != null, "bpmNote.Params != null"); if (i == bpmNote.Basic.IndexInGrid) { currentBpm = bpmNote.Params.NewBpm; currentInterval = BeatmapMathHelper.BpmToInterval(currentBpm); ++bpmNoteIndex; } } currentTiming += currentInterval / currentGridPerSignature; } } else { var currentSignature = b.GetSignature(); currentTiming += currentInterval * currentSignature; } } var startTime = TimeSpan.FromSeconds(currentTiming); bar.Temporary.StartTime = startTime; }
private void BtnOneMeasureMore_Click(object sender, EventArgs e) { if (!CheckFields()) { return; } var bpm = double.Parse(txtBPM.Text, NumberStyles.Number, CultureInfo.CurrentCulture); var startOffset = double.Parse(txtMusicOffset.Text, NumberStyles.Number, CultureInfo.CurrentCulture); var interval = BeatmapMathHelper.BpmToInterval(bpm); int beatCount; switch (_primaryBeatMode) { case PrimaryBeatMode.EveryFourBeats: beatCount = 4; break; case PrimaryBeatMode.EveryThreeBeats: beatCount = 3; break; default: throw new ArgumentOutOfRangeException(); } startOffset += beatCount * interval; _musicOffset = startOffset; txtMusicOffset.Text = _musicOffset.ToString("0.000"); txtMusicOffset.Focus(); txtMusicOffset.SelectAll(); }
public static TimeSpan CalculateDuration([NotNull] this Bar bar) { var notes = bar.Notes; var score = bar.Basic.Score; var currentBpm = score.Project.Settings.BeatPerMinute; foreach (var b in score.Bars) { if (b == bar) { break; } var thisBarHasBpm = b.Notes.Count != 0 && b.Notes.Any(n => n.Basic.Type == NoteType.VariantBpm); if (!thisBarHasBpm) { continue; } var bpmNotes = b.Notes.Where(n => n.Basic.Type == NoteType.VariantBpm).ToList(); bpmNotes.Sort(Note.TimingComparison); var currentBpmNote = bpmNotes[bpmNotes.Count - 1]; Debug.Assert(currentBpmNote.Params != null, "currentBpmNote.Params != null"); currentBpm = currentBpmNote.Params.NewBpm; } var hasAnyBpmNote = notes.Count != 0 && notes.Any(n => n.Basic.Type == NoteType.VariantBpm); var currentInterval = BeatmapMathHelper.BpmToInterval(currentBpm); double seconds; if (hasAnyBpmNote) { var bpmNotesInThisBar = bar.Notes.Where(n => n.Basic.Bar == bar).ToList(); var numGrids = bar.GetNumberOfGrids(); var currentGridPerSignature = bar.GetGridPerSignature(); bpmNotesInThisBar.Sort((n1, n2) => n1.Basic.IndexInGrid.CompareTo(n2.Basic.IndexInGrid)); var bpmNoteIndex = 0; seconds = 0; for (var i = 0; i < numGrids; ++i) { if (bpmNoteIndex < bpmNotesInThisBar.Count) { var bpmNote = bpmNotesInThisBar[bpmNoteIndex]; if (i == bpmNote.Basic.IndexInGrid) { currentInterval = BeatmapMathHelper.BpmToInterval(currentBpm); ++bpmNoteIndex; } } seconds += currentInterval * i / currentGridPerSignature; } } else { seconds = BeatmapMathHelper.BpmToInterval(currentBpm) * bar.GetSignature(); } return(TimeSpan.FromSeconds(seconds)); }
private static CompiledScore Compile([NotNull] Score score, [CanBeNull] TimeSpan?userDefinedEnding) { var notes = score.GetAllNotes(); // First, calculate all timing at the grid lines. var allBpmNotes = notes.Where(n => n.Basic.Type == NoteType.VariantBpm).ToArray(); var timings = new Dictionary <Bar, double[]>(); var currentTiming = score.Project.Settings.StartTimeOffset; var currentBpm = score.Project.Settings.BeatPerMinute; var currentInterval = BeatmapMathHelper.BpmToInterval(currentBpm); foreach (var bar in score.Bars) { var currentGridPerSignature = bar.GetGridPerSignature(); var numGrids = bar.GetNumberOfGrids(); var t = new double[numGrids]; if (allBpmNotes.Any(n => n.Basic.Bar == bar)) { // If there are variant BPM notes, we have to do some math... var bpmNotesInThisBar = allBpmNotes.Where(n => n.Basic.Bar == bar).ToList(); bpmNotesInThisBar.Sort((n1, n2) => n1.Basic.IndexInGrid.CompareTo(n2.Basic.IndexInGrid)); var bpmNoteIndex = 0; for (var i = 0; i < numGrids; ++i) { if (bpmNoteIndex < bpmNotesInThisBar.Count) { var bpmNote = bpmNotesInThisBar[bpmNoteIndex]; if (i == bpmNote.Basic.IndexInGrid) { Debug.Assert(bpmNote.Params != null, "bpmNote.Params != null"); // Yes! We have a visitor: a variant BPM note! currentBpm = bpmNote.Params.NewBpm; currentInterval = BeatmapMathHelper.BpmToInterval(currentBpm); ++bpmNoteIndex; } } t[i] = currentTiming; currentTiming += currentInterval / currentGridPerSignature; } } else { // If there are no variant BPM notes, things get a lot easier. for (var i = 0; i < numGrids; ++i) { t[i] = currentTiming + currentInterval * i / currentGridPerSignature; } var currentSignature = bar.GetSignature(); currentTiming += currentInterval * currentSignature; } timings[bar] = t; } // Then, create a list and fill in basic information. var compiledNotes = new List <CompiledNote>(); var noteMap1 = new Dictionary <CompiledNote, Note>(); var noteMap2 = new Dictionary <Note, CompiledNote>(); foreach (var note in notes) { if (!note.Helper.IsGaming) { continue; } var compiledNote = new CompiledNote(); compiledNote.Type = note.Basic.Type; compiledNote.HitTiming = timings[note.Basic.Bar][note.Basic.IndexInGrid]; compiledNote.StartPosition = note.Basic.StartPosition; compiledNote.FinishPosition = note.Basic.FinishPosition; compiledNote.FlickType = note.Basic.FlickType; compiledNote.IsSync = note.Helper.IsSync; compiledNotes.Add(compiledNote); noteMap1[compiledNote] = note; noteMap2[note] = compiledNote; } compiledNotes.Sort((n1, n2) => n1.HitTiming.CompareTo(n2.HitTiming)); // ReSharper disable once InconsistentNaming // Then, calculate group IDs. var currentGroupID = 1; foreach (var compiledNote in compiledNotes) { if (compiledNote.GroupID != 0) { continue; } var note = noteMap1[compiledNote]; if (!note.Helper.IsFlick && !note.Helper.IsSlide) { continue; } var cn = compiledNote; if (note.Helper.IsFlick) { var n = note; while (n != null) { cn.GroupID = currentGroupID; n = n.Editor.NextFlick; if (n != null) { cn = noteMap2[n]; } } ++currentGroupID; } else if (note.Helper.IsSlide) { var n = note; var n2 = n; while (n != null) { cn.GroupID = currentGroupID; n2 = n; n = n.Editor.NextSlide; if (n != null) { cn = noteMap2[n]; } } // A slide group, directly followed by a flick group. if (n2.Helper.HasNextFlick) { n = n2.Editor.NextFlick; while (n != null) { cn = noteMap2[n]; cn.GroupID = currentGroupID; n = n.Editor.NextFlick; } } ++currentGroupID; } } // Then, add three key notes. (Keynotes, hahaha.) var totalNoteCount = compiledNotes.Count; var scoreInfoNote = new CompiledNote(); scoreInfoNote.Type = NoteType.NoteCount; // Here I used a trick. This will run well while violating the meaning of enum. scoreInfoNote.FlickType = (NoteFlickType)totalNoteCount; var songStartNote = new CompiledNote { Type = NoteType.MusicStart }; var endTiming = userDefinedEnding?.TotalSeconds ?? currentTiming; var songEndNote = new CompiledNote { Type = NoteType.MusicEnd, HitTiming = endTiming }; compiledNotes.Insert(0, scoreInfoNote); compiledNotes.Insert(1, songStartNote); compiledNotes.Add(songEndNote); // ReSharper disable once InconsistentNaming // Finally, ID them. var currentNoteID = 1; foreach (var note in compiledNotes) { note.ID = currentNoteID; ++currentNoteID; } // We did it! Oh yeah! var compiledScore = new CompiledScore(compiledNotes); return(compiledScore); }
public static IReadOnlyList <IReadOnlyList <TimeSpan> > UpdateNoteHitTimings([NotNull] this Score score) { var notes = score.GetAllNotes(); // First, calculate all timing at the grid lines. var allBpmNotes = notes.Where(n => n.Basic.Type == NoteType.VariantBpm).ToArray(); var timings = new List <TimeSpan[]>(); var currentTiming = TimeSpan.FromSeconds(score.Project.Settings.StartTimeOffset); var currentBpm = score.Project.Settings.BeatPerMinute; var currentInterval = BeatmapMathHelper.BpmToInterval(currentBpm); foreach (var bar in score.Bars) { var currentGridPerSignature = bar.GetGridPerSignature(); var numGrids = bar.GetNumberOfGrids(); var t = new TimeSpan[numGrids]; if (allBpmNotes.Any(n => n.Basic.Bar == bar)) { // If there are variant BPM notes, we have to do some math... var bpmNotesInThisBar = allBpmNotes.Where(n => n.Basic.Bar == bar).ToList(); bpmNotesInThisBar.Sort((n1, n2) => n1.Basic.IndexInGrid.CompareTo(n2.Basic.IndexInGrid)); var bpmNoteIndex = 0; for (var i = 0; i < numGrids; ++i) { if (bpmNoteIndex < bpmNotesInThisBar.Count) { var bpmNote = bpmNotesInThisBar[bpmNoteIndex]; if (i == bpmNote.Basic.IndexInGrid) { Debug.Assert(bpmNote.Params != null, "bpmNote.Params != null"); // Yes! We have a visitor: a variant BPM note! currentBpm = bpmNote.Params.NewBpm; currentInterval = BeatmapMathHelper.BpmToInterval(currentBpm); ++bpmNoteIndex; } } t[i] = currentTiming; currentTiming += TimeSpan.FromSeconds(currentInterval / currentGridPerSignature); } } else { // If there are no variant BPM notes, things get a lot easier. for (var i = 0; i < numGrids; ++i) { t[i] = currentTiming + TimeSpan.FromSeconds(currentInterval * i / currentGridPerSignature); } var currentSignature = bar.GetSignature(); currentTiming += TimeSpan.FromSeconds(currentInterval * currentSignature); } // The timing index should equal corresponding bar index. timings.Add(t); } // Update the HitTiming property of each gaming note. foreach (var note in notes) { if (!note.Helper.IsGaming) { continue; } note.Temporary.HitTiming = timings[note.Basic.Bar.Basic.Index][note.Basic.IndexInGrid]; } return(timings); }