void UpdateBeatLines4() { int measurePoolPos = 0, beatPoolPos = 0, quarterPoolPos = 0; Song song = editor.currentSong; uint startRange = song.WorldPositionToSnappedTick(editor.camYMin.position.y, 8); uint endRange = editor.maxPos; var timeSignatures = editor.currentSong.timeSignatures; int startIndex = SongObjectHelper.FindClosestPositionRoundedDown(startRange, timeSignatures); for (int tsIndex = startIndex; tsIndex < timeSignatures.Count && timeSignatures[tsIndex].tick <= endRange; ++tsIndex) { TimeSignature ts = timeSignatures[tsIndex]; uint nextTSTick = tsIndex + 1 < timeSignatures.Count ? timeSignatures[tsIndex + 1].tick : endRange; TimeSignature.MeasureInfo measureInfo = ts.GetMeasureInfo(); measurePoolPos += RenderBeatLines(ts, measureInfo.measureLine, measureLinePool, measurePoolPos, startRange, endRange, nextTSTick); beatPoolPos += RenderBeatLines(ts, measureInfo.beatLine, beatLinePool, beatPoolPos, startRange, endRange, nextTSTick); quarterPoolPos += RenderBeatLines(ts, measureInfo.quarterBeatLine, quarterBeatLinePool, quarterPoolPos, startRange, endRange, nextTSTick); } DisableBeatLines(measurePoolPos, measureLinePool); DisableBeatLines(beatPoolPos, beatLinePool); DisableBeatLines(quarterPoolPos, quarterBeatLinePool); }
public static uint TickToSnappedTick(uint tick, int step, Song song) { float resolution = song.resolution; var timeSignatures = song.timeSignatures; int tsIndex = SongObjectHelper.FindClosestPositionRoundedDown(tick, timeSignatures); TimeSignature ts = timeSignatures[tsIndex]; uint? endRange = tsIndex < (timeSignatures.Count - 1) ? (uint?)timeSignatures[tsIndex + 1].tick : null; TimeSignature.MeasureInfo measureInfo = ts.GetMeasureInfo(); TimeSignature.BeatInfo measureLineInfo = measureInfo.measureLine; TimeSignature.BeatInfo beatLineInfo = measureInfo.beatLine; uint tickOffsetFromTs = tick - ts.tick; int measuresFromTsToSnap = (int)((float)tickOffsetFromTs / measureLineInfo.tickGap); uint lastMeasureTick = ts.tick + (uint)(measuresFromTsToSnap * measureLineInfo.tickGap); float realBeatStep = step / 4.0f; float tickGap = beatLineInfo.tickGap / realBeatStep * ts.denominator / 4.0f; uint tickOffsetFromLastMeasure = tick - lastMeasureTick; int beatsFromLastMeasureToSnap = Mathf.RoundToInt((float)tickOffsetFromLastMeasure / tickGap); uint snappedTick = lastMeasureTick + (uint)(beatsFromLastMeasureToSnap * tickGap); if (endRange.HasValue) { return(snappedTick < endRange.Value ? snappedTick : endRange.Value); } else { return(snappedTick); } // Old algorithm // Snap position based on step //float factor = Song.FULL_STEP / (float)step * resolution / Song.STANDARD_BEAT_RESOLUTION; //float divisor = tick / factor; //float lowerBound = (int)divisor * factor; //float remainder = divisor - (int)divisor; // //if (remainder > 0.5f) // tick = (uint)Mathf.Round(lowerBound + factor); //else // tick = (uint)Mathf.Round(lowerBound); // //return tick; }
static string CheckForErrorsCloneHero(Song song, ref bool hasErrors) { StringBuilder sb = new StringBuilder(); sb.AppendLine("Clone Hero validation report: "); bool hasErrorsLocal = false; // Check that time signature positions line up on the measure from the previous time signature { var timeSignatures = song.timeSignatures; for (int tsIndex = 1; tsIndex < timeSignatures.Count; ++tsIndex) { TimeSignature previousTs = timeSignatures[tsIndex - 1]; TimeSignature.MeasureInfo measureInfo = previousTs.GetMeasureInfo(); TimeSignature tsToTest = timeSignatures[tsIndex]; uint deltaTick = tsToTest.tick - previousTs.tick; var measureLine = measureInfo.measureLine; if (((float)deltaTick % measureLine.tickGap) != 0) // Doesn't line up on a measure { hasErrorsLocal |= true; sb.AppendFormat("\tFound misaligned Time Signature at position {0}. Time signatures must be aligned to the measure set by the previous time signature.\n", tsToTest.tick); } } } if (!hasErrorsLocal) { sb.AppendLine("\tNo errors detected"); } hasErrors |= hasErrorsLocal; return(sb.ToString()); }
static string CheckForErrorsCloneHero(Song song, ValidationParameters validationParams, ref bool hasErrors) { StringBuilder sb = new StringBuilder(); sb.AppendLine("Clone Hero validation report: "); bool hasErrorsLocal = false; // Check that time signature positions line up on the measure from the previous time signature { var timeSignatures = song.timeSignatures; for (int tsIndex = 1; tsIndex < timeSignatures.Count; ++tsIndex) { TimeSignature previousTs = timeSignatures[tsIndex - 1]; TimeSignature.MeasureInfo measureInfo = previousTs.GetMeasureInfo(); TimeSignature tsToTest = timeSignatures[tsIndex]; uint deltaTick = tsToTest.tick - previousTs.tick; var measureLine = measureInfo.measureLine; if (((float)deltaTick % measureLine.tickGap) != 0) // Doesn't line up on a measure { hasErrorsLocal |= true; sb.AppendFormat("\tFound misaligned Time Signature at position {0}. Time signatures must be aligned to the measure set by the previous time signature.\n", tsToTest.tick); } } } // If we have no starpower but more than 1 solo section then CH will interpret this as an RB1 style midi, and misinterpret the solo markers as starpower if (validationParams.checkMidiIssues) { foreach (Song.Instrument instrument in EnumX <Song.Instrument> .Values) { if (instrument == Song.Instrument.Unrecognised) { continue; } foreach (Song.Difficulty difficulty in EnumX <Song.Difficulty> .Values) { Chart chart = song.GetChart(instrument, difficulty); if (chart.starPower.Count <= 0) { // Check for solo markers int soloMarkerCount = 0; foreach (ChartEvent ce in chart.events) { if (ce.eventName == MoonscraperChartEditor.Song.IO.MidIOHelper.SoloEventText) { ++soloMarkerCount; if (soloMarkerCount > 1) { hasErrorsLocal |= true; sb.AppendFormat("\tTrack {0} has no starpower and more than 1 solo section. If exported to the midi format, Clone Hero will interpret this chart as an older style midi, and will misinterpret solo markers as starpower.\n", instrument); goto NewInstrument; } } } } } NewInstrument :; } } if (!hasErrorsLocal) { sb.AppendLine("\tNo errors detected"); } hasErrors |= hasErrorsLocal; return(sb.ToString()); }