private string Adjust_Timing(TimingHelperVm arg, BackgroundWorker worker, DoWorkEventArgs _) { // Count int redlinesAdded = 0; var reader = EditorReaderStuff.GetFullEditorReaderOrNot(); foreach (string path in arg.Paths) { // Open beatmap var editor = EditorReaderStuff.GetNewestVersionOrNot(path, reader); Beatmap beatmap = editor.Beatmap; Timing timing = beatmap.BeatmapTiming; // Get all the times to snap List <Marker> markers = new List <Marker>(); if (arg.Objects) { markers.AddRange(beatmap.HitObjects.Select(ho => new Marker(ho.Time))); } if (arg.Bookmarks) { markers.AddRange(beatmap.GetBookmarks().Select(time => new Marker(time))); } if (arg.Greenlines) { // Get the offsets of greenlines markers.AddRange(from tp in timing.TimingPoints where !tp.Uninherited select new Marker(tp.Offset)); } if (arg.Redlines) { // Get the offsets of redlines markers.AddRange(from tp in timing.TimingPoints where tp.Uninherited select new Marker(tp.Offset)); } // Update progressbar if (worker != null && worker.WorkerReportsProgress) { worker.ReportProgress(20); } // Sort the markers markers = markers.OrderBy(o => o.Time).ToList(); // If there are no redlines add one with a default BPM if (!timing.TimingPoints.Any(tp => tp.Uninherited)) { timing.Add(new TimingPoint(0, 1000, 4, SampleSet.Soft, 0, 100, true, false, false)); } // Remove multiple markers on the same tick var newMarkers = new List <Marker>(markers.Count); newMarkers.AddRange(markers.Where((t, i) => i == 0 || Math.Abs(t.Time - markers[i - 1].Time) >= arg.Leniency + Precision.DOUBLE_EPSILON)); markers = newMarkers; // Calculate the beats between time and the last time or redline for each time // Time the same is 0 // Time a little after is smallest snap foreach (var marker in markers) { double time = marker.Time; TimingPoint redline = timing.GetRedlineAtTime(time - 1); // Resnap to that redline only double resnappedTime = timing.Resnap(time, arg.BeatDivisors, false, tp: redline); // Calculate beats from the redline double beatsFromRedline = (resnappedTime - redline.Offset) / redline.MpB; // Avoid problems if (MathHelper.ApproximatelyEquivalent(beatsFromRedline, 0, 0.0001)) { beatsFromRedline = arg.BeatDivisors.Min(o => o.GetValue()); } if (time == redline.Offset) { beatsFromRedline = 0; } // Initialize the beats from last marker double beatsFromLastMarker = beatsFromRedline; // Get the times between redline and this time List <Marker> timesBefore = markers.Where(o => o.Time <time && o.Time> redline.Offset).ToList(); if (timesBefore.Count > 0) { // Get the last time info double lastTime = timesBefore.Last().Time; double resnappedTimeL = timing.Resnap(lastTime, arg.BeatDivisors, false); // Change the beats from last marker beatsFromLastMarker = (resnappedTime - resnappedTimeL) / redline.MpB; // Avoid problems if (MathHelper.ApproximatelyEquivalent(beatsFromLastMarker, 0, 0.0001)) { beatsFromLastMarker = arg.BeatDivisors.Min(o => o.GetValue()); } if (lastTime == time) { beatsFromLastMarker = 0; } } // Set the variable marker.BeatsFromLastMarker = beatsFromLastMarker; if (arg.BeatsBetween != -1) { marker.BeatsFromLastMarker = arg.BeatsBetween; } } // Remove redlines except the first redline if (!arg.Redlines) { var first = timing.TimingPoints.FirstOrDefault(o => o.Uninherited); timing.RemoveAll(o => o.Uninherited && o != first); } // Update progressbar if (worker != null && worker.WorkerReportsProgress) { worker.ReportProgress(40); } // Loop through all the markers for (int i = 0; i < markers.Count; i++) { Marker marker = markers[i]; double time = marker.Time; TimingPoint redline = timing.GetRedlineAtTime(time - 1); double beatsFromLastMarker = marker.BeatsFromLastMarker; // Skip if 0 beats from last marker if (beatsFromLastMarker == 0) { continue; } // Get the times between redline and this time including this time List <Marker> markersBefore = markers.Where(o => o.Time <time && o.Time> redline.Offset).ToList(); markersBefore.Add(marker); // Calculate MpB // Average MpB from timesBefore and use time from redline double mpb = 0; double beatsFromRedline = 0; foreach (Marker markerB in markersBefore) { beatsFromRedline += markerB.BeatsFromLastMarker; mpb += GetMpB(markerB.Time - redline.Offset, beatsFromRedline, 0); } mpb /= markersBefore.Count; // Check if this MpB doesn't make the markers go offsnap too far bool canChangeRedline = CheckMpB(mpb, markersBefore, redline, arg); // Make changes if (canChangeRedline) { // Round the MpB to human values first mpb = HumanRoundMpB(mpb, markersBefore, redline, arg); // Change the MpB of the redline redline.MpB = mpb; } else { // Get the last time info and not the current markersBefore.Remove(marker); double lastTime = markersBefore.Last().Time; // Make new redline TimingPoint newRedline = redline.Copy(); TimingPoint lastHitsounds = timing.GetTimingPointAtTime(lastTime + 5); newRedline.Offset = lastTime; newRedline.OmitFirstBarLine = arg.OmitBarline; // Set omit to the argument newRedline.Kiai = lastHitsounds.Kiai; newRedline.SampleIndex = lastHitsounds.SampleIndex; newRedline.SampleSet = lastHitsounds.SampleSet; newRedline.Volume = lastHitsounds.Volume; timing.Add(newRedline); // Set the MpB newRedline.MpB = GetMpB(time - lastTime, beatsFromLastMarker, arg.Leniency); // Update the counter redlinesAdded++; } // Update progressbar if (worker != null && worker.WorkerReportsProgress) { worker.ReportProgress(i * 60 / markers.Count + 40); } } // Save the file editor.SaveFile(); } // Complete progressbar if (worker != null && worker.WorkerReportsProgress) { worker.ReportProgress(100); } // Do QuickRun stuff RunFinished?.Invoke(this, new RunToolCompletedEventArgs(true, reader != null, arg.Quick)); // Make an accurate message string message = "Successfully added "; message += redlinesAdded; if (Math.Abs(redlinesAdded) == 1) { message += " redlines!"; } else { message += " redlines!"; } return(arg.Quick ? string.Empty : message); }
bool FindSyncPoint(Music.SyncType syncType, int syncFactor, int currentSample, int entryPointSample, out int syncPointSample) { syncPointSample = currentSample; MusicMeterBySample currentMeter = GetMeterFromSample(currentSample); Timing currentTiming = currentMeter != null?currentMeter.GetTimingFromSample(currentSample) : new Timing(); Timing syncPointCandidateTiming = new Timing(currentTiming); switch (syncType) { case Music.SyncType.Immediate: syncPointSample = currentSample + entryPointSample; break; case Music.SyncType.ExitPoint: syncPointSample = CurrentSection.ExitPointSample; if (syncPointSample <= currentSample + entryPointSample) { return(false); } break; case Music.SyncType.Bar: syncPointCandidateTiming.Set(currentTiming.Bar - (currentTiming.Bar - currentMeter.StartBar) % syncFactor + syncFactor, 0, 0); syncPointSample = CurrentSection.GetSampleFromTiming(syncPointCandidateTiming); while (syncPointSample <= currentSample + entryPointSample) { syncPointCandidateTiming.Add(syncFactor); if (syncPointCandidateTiming > CurrentSection.ExitPointTiming) { return(false); } syncPointSample = CurrentSection.GetSampleFromTiming(syncPointCandidateTiming); } break; case Music.SyncType.Beat: syncPointCandidateTiming.Set(currentTiming.Bar, currentTiming.Beat - (currentTiming.Beat % syncFactor) + syncFactor, 0); syncPointCandidateTiming.Fix(currentMeter); syncPointSample = CurrentSection.GetSampleFromTiming(syncPointCandidateTiming); while (syncPointSample <= currentSample + entryPointSample) { syncPointCandidateTiming.Add(0, syncFactor, 0, currentMeter); syncPointCandidateTiming.Fix(currentMeter); if (syncPointCandidateTiming > CurrentSection.ExitPointTiming) { return(false); } currentMeter = GetMeterFromTiming(syncPointCandidateTiming); syncPointSample = CurrentSection.GetSampleFromTiming(syncPointCandidateTiming); } break; case Music.SyncType.Unit: syncPointCandidateTiming.Set(currentTiming.Bar, currentTiming.Beat, currentTiming.Unit - (currentTiming.Unit % syncFactor) + syncFactor); syncPointCandidateTiming.Fix(currentMeter); syncPointSample = CurrentSection.GetSampleFromTiming(syncPointCandidateTiming); while (syncPointSample <= currentSample + entryPointSample) { syncPointCandidateTiming.Add(0, 0, syncFactor, currentMeter); syncPointCandidateTiming.Fix(currentMeter); if (syncPointCandidateTiming > CurrentSection.ExitPointTiming) { return(false); } currentMeter = GetMeterFromTiming(syncPointCandidateTiming); syncPointSample = CurrentSection.GetSampleFromTiming(syncPointCandidateTiming); } break; case Music.SyncType.Marker: if (0 <= syncFactor && syncFactor < CurrentSection.Markers.Length && CurrentSection.Markers[syncFactor].Timings.Length > 0) { MusicSection.MusicMarker marker = CurrentSection.Markers[syncFactor]; int markerIndex = 0; syncPointCandidateTiming.Set(marker.Timings[markerIndex]); syncPointSample = CurrentSection.GetSampleFromTiming(syncPointCandidateTiming); while (syncPointSample <= currentSample + entryPointSample) { ++markerIndex; if (marker.Timings.Length <= markerIndex) { return(false); } syncPointCandidateTiming.Set(marker.Timings[markerIndex]); syncPointSample = CurrentSection.GetSampleFromTiming(syncPointCandidateTiming); } } else { print(String.Format("Failed to SetNextSection. {0} section doesn't have Marker[{1}].", CurrentSection.Name, syncFactor)); return(false); } break; } return(true); }
private string Copy_Timing(TimingCopierVm arg, BackgroundWorker worker, DoWorkEventArgs _) { string[] paths = arg.ExportPath.Split('|'); int mapsDone = 0; var reader = EditorReaderStuff.GetFullEditorReaderOrNot(); foreach (string exportPath in paths) { var editorTo = EditorReaderStuff.GetNewestVersionOrNot(exportPath, reader); var editorFrom = EditorReaderStuff.GetNewestVersionOrNot(arg.ImportPath, reader); Beatmap beatmapTo = editorTo.Beatmap; Beatmap beatmapFrom = editorFrom.Beatmap; Timing timingTo = beatmapTo.BeatmapTiming; Timing timingFrom = beatmapFrom.BeatmapTiming; // Get markers for hitobjects if mode 1 is used List <Marker> markers = new List <Marker>(); if (arg.ResnapMode == "Number of beats between objects stays the same") { markers = GetMarkers(beatmapTo, timingTo); } // Rid the beatmap of redlines // If a greenline exists at the same time as a redline then the redline ceizes to exist // Else convert the redline to a greenline: Inherited = false & MpB = -100 List <TimingPoint> removeList = new List <TimingPoint>(); foreach (TimingPoint redline in timingTo.Redlines) { TimingPoint greenlineHere = timingTo.GetGreenlineAtTime(redline.Offset); if (greenlineHere.Offset != redline.Offset) { var newGreenline = redline.Copy(); newGreenline.Uninherited = false; newGreenline.MpB = -100; timingTo.Add(newGreenline); } removeList.Add(redline); } foreach (TimingPoint tp in removeList) { timingTo.Remove(tp); } // Make new timing points changes List <TimingPointsChange> timingPointsChanges = new List <TimingPointsChange>(); // Add redlines var redlines = timingFrom.Redlines; foreach (TimingPoint tp in redlines) { timingPointsChanges.Add(new TimingPointsChange(tp, mpb: true, meter: true, unInherited: true, omitFirstBarLine: true, fuzzyness: Precision.DOUBLE_EPSILON)); } // Apply timing changes TimingPointsChange.ApplyChanges(timingTo, timingPointsChanges); if (arg.ResnapMode == "Number of beats between objects stays the same") { redlines = timingTo.Redlines; List <double> newBookmarks = new List <double>(); double lastTime = redlines.FirstOrDefault().Offset; foreach (Marker marker in markers) { // Get redlines between this and last marker TimingPoint redline = timingTo.GetRedlineAtTime(lastTime, redlines.FirstOrDefault()); double beatsFromLastTime = marker.BeatsFromLastMarker; while (true) { List <TimingPoint> redlinesBetween = redlines.Where(o => o.Offset <= lastTime + redline.MpB * beatsFromLastTime && o.Offset > lastTime).ToList(); if (redlinesBetween.Count == 0) { break; } TimingPoint first = redlinesBetween.First(); double diff = first.Offset - lastTime; beatsFromLastTime -= diff / redline.MpB; redline = first; lastTime = first.Offset; } // Last time is the time of the last redline in between double newTime = lastTime + redline.MpB * beatsFromLastTime; newTime = timingTo.Resnap(newTime, arg.BeatDivisors, firstTp: redlines.FirstOrDefault()); marker.Time = newTime; lastTime = marker.Time; } // Add the bookmarks foreach (Marker marker in markers) { // Check whether the marker is a bookmark if (marker.Object is double) { // Don't resnap bookmarks newBookmarks.Add((double)marker.Object); } } beatmapTo.SetBookmarks(newBookmarks); } else if (arg.ResnapMode == "Just resnap") { // Resnap hitobjects foreach (HitObject ho in beatmapTo.HitObjects) { ho.ResnapSelf(timingTo, arg.BeatDivisors, firstTp: redlines.FirstOrDefault()); ho.ResnapEnd(timingTo, arg.BeatDivisors, firstTp: redlines.FirstOrDefault()); } // Resnap greenlines foreach (TimingPoint tp in timingTo.Greenlines) { tp.ResnapSelf(timingTo, arg.BeatDivisors, firstTP: redlines.FirstOrDefault()); } timingTo.Sort(); } else { // Don't move objects } // Save the file editorTo.SaveFile(); // Update progressbar if (worker != null && worker.WorkerReportsProgress) { worker.ReportProgress(++mapsDone * 100 / paths.Length); } } // Make an accurate message string message = $"Successfully copied timing to {mapsDone} {(mapsDone == 1 ? "beatmap" : "beatmaps")}!"; return(message); }
public void AddChange(Timing timing, bool allAfter = false) { TimingPoint addingTimingPoint = null; TimingPoint prevTimingPoint = null; List <TimingPoint> onTimingPoints = new List <TimingPoint>(); bool onHasRed = false; bool onHasGreen = false; foreach (TimingPoint tp in timing) { if (tp == null) { continue; } // Continue nulls to avoid exceptions if (tp.Offset < MyTP.Offset && (prevTimingPoint == null || tp.Offset >= prevTimingPoint.Offset)) { prevTimingPoint = tp; } if (Math.Abs(tp.Offset - MyTP.Offset) <= Fuzzyness) { onTimingPoints.Add(tp); onHasRed = tp.Uninherited || onHasRed; onHasGreen = !tp.Uninherited || onHasGreen; } } if (onTimingPoints.Count > 0) { prevTimingPoint = onTimingPoints.Last(); } if (UnInherited && !onHasRed) { // Make new redline if (prevTimingPoint == null) { addingTimingPoint = MyTP.Copy(); addingTimingPoint.Uninherited = true; } else { addingTimingPoint = prevTimingPoint.Copy(); addingTimingPoint.Offset = MyTP.Offset; addingTimingPoint.Uninherited = true; } onTimingPoints.Add(addingTimingPoint); } if (!UnInherited && (onTimingPoints.Count == 0 || (MpB && !onHasGreen))) { // Make new greenline (based on prev) if (prevTimingPoint == null) { addingTimingPoint = MyTP.Copy(); addingTimingPoint.Uninherited = false; } else { addingTimingPoint = prevTimingPoint.Copy(); addingTimingPoint.Offset = MyTP.Offset; addingTimingPoint.Uninherited = false; if (prevTimingPoint.Uninherited) { addingTimingPoint.MpB = -100; } } onTimingPoints.Add(addingTimingPoint); } foreach (TimingPoint on in onTimingPoints) { if (MpB && (UnInherited ? on.Uninherited : !on.Uninherited)) { on.MpB = MyTP.MpB; } if (Meter && UnInherited && on.Uninherited) { on.Meter = MyTP.Meter; } if (Sampleset) { on.SampleSet = MyTP.SampleSet; } if (Index) { on.SampleIndex = MyTP.SampleIndex; } if (Volume) { on.Volume = MyTP.Volume; } if (Kiai) { on.Kiai = MyTP.Kiai; } if (OmitFirstBarLine && UnInherited && on.Uninherited) { on.OmitFirstBarLine = MyTP.OmitFirstBarLine; } } if (addingTimingPoint != null && (prevTimingPoint == null || !addingTimingPoint.SameEffect(prevTimingPoint) || UnInherited)) { timing.Add(addingTimingPoint); } if (allAfter) // Change every timingpoint after { foreach (TimingPoint tp in timing) { if (tp.Offset > MyTP.Offset) { if (Sampleset) { tp.SampleSet = MyTP.SampleSet; } if (Index) { tp.SampleIndex = MyTP.SampleIndex; } if (Volume) { tp.Volume = MyTP.Volume; } if (Kiai) { tp.Kiai = MyTP.Kiai; } } } } }