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); }
// Should be called once the physics system has settled down void Init() { ChartEditor editor = ChartEditor.Instance; Debug.Assert(!hitWindowFeeder.enabled); hitWindowFeeder.enabled = true; if (botEnabled) { // We want the bot to automatically hit any sustains that are currently active in the view, but for which the notes are already past the strikeline Song song = editor.currentSong; float currentTime = editor.currentVisibleTime; uint currentTick = song.TimeToTick(currentTime, song.resolution); int index = SongObjectHelper.FindClosestPositionRoundedDown(currentTick, editor.currentChart.notes); if (index != SongObjectHelper.NOTFOUND) { Note note = editor.currentChart.notes[index]; List <Note> sustainNotes = new List <Note>(); NoteFunctions.GetPreviousOfSustains(sustainNotes, note, GameSettings.extendedSustainsEnabled); foreach (Note chordNote in note.chord) { sustainNotes.Add(chordNote); } foreach (Note sustainNote in sustainNotes) { if (sustainNote.controller != null) { hitWindowFeeder.TryAddNote(sustainNote.controller); } } } } }
// Calculate the beat lines directly from the time signature positions themselves void UpdateBeatLines3() { 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; uint standardMeasureLengthTicks = (uint)(Song.RESOLUTIONS_PER_MEASURE * song.resolution); int startIndex = SongObjectHelper.FindClosestPositionRoundedDown(startRange, timeSignatures); for (int tsIndex = startIndex; tsIndex < timeSignatures.Count && timeSignatures[tsIndex].tick <= endRange; ++tsIndex) { TimeSignature ts = timeSignatures[tsIndex]; uint nextTick = ts.tick; uint nextTSTick = tsIndex + 1 < timeSignatures.Count ? timeSignatures[tsIndex + 1].tick : endRange; float beatDeltaTick = standardMeasureLengthTicks / ts.beatsPerMeasure; uint startDeltaFromTSTick = startRange > ts.tick ? (startRange - ts.tick) : 0; int quarterLineIndex = (int)Mathf.Round((float)(startDeltaFromTSTick) / beatDeltaTick); // Jump to the next reasonable line index rather than looping until we get there if (quarterLineIndex > 0) { --quarterLineIndex; } while (nextTick < nextTSTick && nextTick <= endRange) { uint currentTick = nextTick; bool tickIsMeasure = quarterLineIndex % ts.quarterNotesPerMeasure == 0; if (currentTick >= startRange && currentTick < nextTSTick && currentTick <= endRange) { if (tickIsMeasure) { SetBeatLinePosition(currentTick, measureLinePool, ref measurePoolPos); } else { SetBeatLinePosition(currentTick, beatLinePool, ref beatPoolPos); } } nextTick = ts.tick + (uint)Mathf.Round(beatDeltaTick * (++quarterLineIndex)); uint tickDelta = nextTick - currentTick; uint newPosition = currentTick + tickDelta / 2; if (newPosition >= startRange && newPosition < nextTSTick && newPosition <= endRange) { SetBeatLinePosition(newPosition, quarterBeatLinePool, ref quarterPoolPos); } } } DisableBeatLines(measurePoolPos, measureLinePool); DisableBeatLines(beatPoolPos, beatLinePool); DisableBeatLines(quarterPoolPos, quarterBeatLinePool); }
public SongObjectTracker(SongObjectCache <T> objects, uint startTick) { this.objects = objects; // Skip ahead to where we're actually going to start int startIndex = SongObjectHelper.FindClosestPositionRoundedDown(startTick, objects); if (startIndex != SongObjectHelper.NOTFOUND) { currentIndex = startIndex; } }
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; }
public static Note.SpecialType IsStarpower(Note note) { Note.SpecialType specialType = Note.SpecialType.None; int index = SongObjectHelper.FindClosestPositionRoundedDown(note.tick, note.chart.starPower); if (index != SongObjectHelper.NOTFOUND) { Starpower sp = note.chart.starPower[index]; if (sp.tick == note.tick || (sp.tick <= note.tick && sp.tick + sp.length > note.tick)) { specialType = Note.SpecialType.StarPower; } } return(specialType); }
public void Update() { ChartEditor editor = ChartEditor.Instance; float time = editor.currentVisibleTime; Song song = editor.currentSong; if (feederNoteIndex <= 0) { uint currentTick = song.TimeToTick(time, song.resolution); feederNoteIndex = SongObjectHelper.FindClosestPositionRoundedDown(currentTick, editor.currentChart.notes); } if (hitWindow != null && feederNoteIndex >= 0 && feederNoteIndex < editor.currentChart.notes.Count) { uint maxScanTick = editor.maxPos; int noteIndex = feederNoteIndex; while (noteIndex < editor.currentChart.notes.Count) { Note note = editor.currentChart.notes[noteIndex]; if (note.tick > maxScanTick) { break; } ++noteIndex; bool validControllerAttached = note.controller != null && note.controller.isActiveAndEnabled && !note.controller.hit; if (validControllerAttached && note.tick != lastAddedTick) { if (!hitWindow.DetectEnter(note, time)) { break; } else { lastAddedTick = note.tick; } feederNoteIndex = noteIndex; // Only increase the feeder note index if we pass notes that are completely valid. The notes ahead may have simply not been loaded into view yet. Need to reproccess them once they do come into view } } } }
uint CalculateNextBeatTickPosition(uint currentTickPosition) { Song song = editor.currentSong; var timeSignatures = editor.currentSong.timeSignatures; uint standardMeasureLengthTicks = (uint)(Song.RESOLUTIONS_PER_MEASURE * song.resolution); int lastTsIndex = SongObjectHelper.FindClosestPositionRoundedDown(currentTickPosition, timeSignatures); TimeSignature currentTimeSignature = timeSignatures[lastTsIndex]; TimeSignature nextTimeSignature = lastTsIndex + 1 < timeSignatures.Count ? timeSignatures[lastTsIndex + 1] : null; uint tickOrigin = currentTimeSignature.tick; float beatDeltaTick = standardMeasureLengthTicks / currentTimeSignature.beatsPerMeasure; if (nextTimeSignature != null && currentTickPosition + beatDeltaTick >= nextTimeSignature.tick) { return(nextTimeSignature.tick); } uint deltaTick = currentTickPosition - tickOrigin; uint remainder = (uint)Mathf.Round(deltaTick % beatDeltaTick); return(tickOrigin + deltaTick - remainder + (uint)Mathf.Round(beatDeltaTick)); }