Performance Improvements (#173)

* improve performance with new render settings

- fix letterboxing losing camera references

* fin in missing params?

needs testing

* finish default param check

* scale jump animation of fan club spectators

* fix missing references in a karate man method

* more liberal use of Double in conductor

beatkeeping is now absolute instead of being additive

* optimize Conductor more

reduce caching from constantly sorting tempo changes despite game manager doing it for us
moved metronome logic to LateUpdate
This commit is contained in:
minenice55
2022-09-22 22:05:04 -04:00
committed by GitHub
parent af8dd6142e
commit 695f6671fb
26 changed files with 398 additions and 248 deletions

View File

@ -1,7 +1,6 @@
using System.Collections;
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Audio;
using Starpelly;
@ -21,15 +20,15 @@ namespace HeavenStudio
public float pitchedSecPerBeat => (secPerBeat / musicSource.pitch);
// Current song position, in seconds
private float songPos; // for Conductor use only
public float songPosition;
private double songPos; // for Conductor use only
public float songPosition => (float) songPos;
// Current song position, in beats
private float songPosBeat; // for Conductor use only
public float songPositionInBeats;
private double songPosBeat; // for Conductor use only
public float songPositionInBeats => (float) songPosBeat;
// Current time of the song
private float time;
private double time;
double lastAbsTime;
@ -54,7 +53,7 @@ namespace HeavenStudio
// Metronome tick sound enabled
public bool metronome = false;
public float timeSinceLastTempoChange = 0;
public float timeSinceLastTempoChange = Single.MinValue;
private bool beat;
@ -67,7 +66,7 @@ namespace HeavenStudio
public void SetBeat(float beat)
{
float secFromBeat = GetSongPosFromBeat(beat);
float secFromBeat = (float) GetSongPosFromBeat(beat);
if (musicSource.clip != null)
{
@ -79,11 +78,11 @@ namespace HeavenStudio
GameManager.instance.SetCurrentEventToClosest(beat);
songPosBeat = beat;
songPositionInBeats = songPosBeat;
}
public void Play(float beat)
{
GameManager.instance.SortEventsList();
bool negativeOffset = firstBeatOffset < 0f;
bool negativeStartTime = false;
@ -119,12 +118,12 @@ namespace HeavenStudio
if (musicStartTime < 0f)
{
musicSource.time = startPos;
musicSource.time = (float) startPos;
musicSource.PlayScheduled(AudioSettings.dspTime - firstBeatOffset / musicSource.pitch);
}
else
{
musicSource.time = musicStartTime;
musicSource.time = (float) musicStartTime;
musicSource.PlayScheduled(AudioSettings.dspTime);
}
}
@ -132,11 +131,11 @@ namespace HeavenStudio
{
if (negativeStartTime)
{
musicSource.time = startPos;
musicSource.time = (float) startPos;
}
else
{
musicSource.time = startPos + firstBeatOffset;
musicSource.time = (float) startPos + firstBeatOffset;
}
musicSource.PlayScheduled(AudioSettings.dspTime);
@ -160,7 +159,6 @@ namespace HeavenStudio
this.time = time;
songPosBeat = 0;
songPositionInBeats = 0;
isPlaying = false;
isPaused = false;
@ -171,33 +169,31 @@ namespace HeavenStudio
public void Update()
{
secPerBeat = 60f / songBpm;
if (isPlaying)
{
double absTime = Time.realtimeSinceStartupAsDouble;
float dt = (float) (absTime - lastAbsTime) * musicSource.pitch;
double dt = (absTime - lastAbsTime) * musicSource.pitch;
lastAbsTime = absTime;
time += dt;
songPos = time;
songPosition = songPos;
songPosBeat += (dt / secPerBeat);
songPositionInBeats = songPosBeat;
// songPositionInBeats = Time.deltaTime / secPerBeat;
songPosBeat = GetBeatFromSongPos(songPos - firstBeatOffset);
}
}
if (metronome)
public void LateUpdate()
{
if (metronome)
{
if (ReportBeat(ref lastReportedBeat))
{
if (ReportBeat(ref lastReportedBeat))
{
Util.Jukebox.PlayOneShot("metronome");
}
else if (songPositionInBeats < lastReportedBeat)
{
lastReportedBeat = Mathf.Round(songPositionInBeats);
}
Util.Jukebox.PlayOneShot("metronome");
}
else if (songPositionInBeats < lastReportedBeat)
{
lastReportedBeat = Mathf.Round(songPositionInBeats);
}
}
}
@ -242,87 +238,60 @@ namespace HeavenStudio
return GetBeatFromPosition(position, targetBeat - margin, margin);
}
private List<Beatmap.TempoChange> GetSortedTempoChanges(Beatmap chart)
{
//iterate over all tempo changes, adding to counter
List<Beatmap.TempoChange> tempoChanges = chart.tempoChanges;
tempoChanges.Sort((x, y) => x.beat.CompareTo(y.beat)); //sorts all tempo changes by ascending time (GameManager already does this but juste en cas...)
return tempoChanges;
}
private List<DynamicBeatmap.TempoChange> GetSortedTempoChanges(DynamicBeatmap chart)
{
//iterate over all tempo changes, adding to counter
List<DynamicBeatmap.TempoChange> tempoChanges = chart.tempoChanges;
tempoChanges.Sort((x, y) => x.beat.CompareTo(y.beat)); //sorts all tempo changes by ascending time (GameManager already does this but juste en cas...)
return tempoChanges;
GameManager.instance.SortEventsList();
return GameManager.instance.Beatmap.tempoChanges;
}
public float GetSongPosFromBeat(float beat)
public double GetSongPosFromBeat(float beat)
{
var chart = GameManager.instance.Beatmap;
SetBpm(chart.bpm);
//initial counter
float counter = 0f;
double counter = 0f;
//time of last tempo change, to know how much to add to counter
float lastTempoChangeBeat = 0f;
//iterate over all tempo changes, adding to counter
var tempoChanges = GetSortedTempoChanges(chart);
foreach (var t in tempoChanges)
foreach (var t in GameManager.instance.Beatmap.tempoChanges)
{
if (t.beat > beat)
{
// this tempo change is past our requested time, abort
break;
}
// Debug.Log("tempo change at " + t.beat);
counter += (t.beat - lastTempoChangeBeat) * secPerBeat;
// Debug.Log("counter is now " + counter);
// now update to new bpm
SetBpm(t.tempo);
lastTempoChangeBeat = t.beat;
}
//passed all past tempo changes, now extrapolate from last tempo change until requested position
counter += (beat - lastTempoChangeBeat) * secPerBeat;
// Debug.Log("GetSongPosFromBeat returning " + counter);
return counter;
}
//thank you @wooningcharithri#7419 for the psuedo-code
private float BeatsToSecs(float beats, float bpm)
private double BeatsToSecs(double beats, float bpm)
{
// Debug.Log("BeatsToSecs returning " + beats / bpm * 60);
return beats / bpm * 60f;
}
private float SecsToBeats(float s, float bpm)
private double SecsToBeats(double s, float bpm)
{
// Debug.Log("SecsToBeats returning " + s / 60f / bpm);
return s / 60f * bpm;
}
public float GetBeatFromSongPos(float seconds)
public double GetBeatFromSongPos(double seconds)
{
// Debug.Log("Getting beat of seconds " + seconds);
var chart = GameManager.instance.Beatmap;
float lastTempoChangeBeat = 0f;
float lastBpm = chart.bpm;
float counterSeconds = -firstBeatOffset;
double lastTempoChangeBeat = 0f;
double counterSeconds = -firstBeatOffset;
float lastBpm = GameManager.instance.Beatmap.bpm;
var tempoChanges = GetSortedTempoChanges(chart);
foreach (var t in tempoChanges)
foreach (var t in GameManager.instance.Beatmap.tempoChanges)
{
float beatToNext = t.beat - lastTempoChangeBeat;
float secToNext = BeatsToSecs(beatToNext, lastBpm);
float nextSecs = counterSeconds + secToNext;
double beatToNext = t.beat - lastTempoChangeBeat;
double secToNext = BeatsToSecs(beatToNext, lastBpm);
double nextSecs = counterSeconds + secToNext;
// Debug.Log("nextSecs is " + nextSecs + ", seconds " + seconds);
if (nextSecs >= seconds)
break;
@ -330,9 +299,6 @@ namespace HeavenStudio
lastBpm = t.tempo;
counterSeconds = nextSecs;
}
// Debug.Log("lastTempoChangeBeat is " + lastTempoChangeBeat + ", counterSeconds is " + counterSeconds);
return lastTempoChangeBeat + SecsToBeats(seconds - counterSeconds, lastBpm);
}
//
@ -357,7 +323,7 @@ namespace HeavenStudio
public float SongLengthInBeats()
{
if (!musicSource.clip) return 0;
return GetBeatFromSongPos(musicSource.clip.length);
return (float) GetBeatFromSongPos(musicSource.clip.length);
}
public bool SongPosLessThanClipLength(float t)
@ -368,6 +334,14 @@ namespace HeavenStudio
return false;
}
public bool SongPosLessThanClipLength(double t)
{
if (musicSource.clip != null)
return t < musicSource.clip.length;
else
return false;
}
public bool NotStopped()
{
return Conductor.instance.isPlaying == true || Conductor.instance.isPaused == true;