Timekeeping Improvements and Small Optimizations (#544)

* make BeatActions coroutines instead of componentrs

* pooled scheduled sounds

implement S' entity seek

* remove debug prints from last two changes

* implement absolute time tracking

implement DSP time resyncing

* optimize GameManager

* update TMPro

* update IDE packages

* fix dsp sync making the drift worse

* fix issue with the JSL dll

* relocate debug print

* make scheduled pitch setter functional

* any cpu
This commit is contained in:
minenice55
2023-09-11 18:28:04 -04:00
committed by GitHub
parent 0acaafbebd
commit 60d29f19c6
157 changed files with 49650 additions and 2194 deletions

View File

@ -22,6 +22,7 @@ namespace HeavenStudio.Util
int loopIndex = 0;
private AudioSource audioSource;
private Conductor cond;
private int pauseTimes = 0;
@ -34,30 +35,48 @@ namespace HeavenStudio.Util
bool playInstant = false;
bool played = false;
bool queued = false;
public bool available = true;
const double PREBAKE_TIME = 0.5;
private void Start()
{
}
public void Play()
{
if (!available)
{
GameManager.instance.SoundObjects.Release(this);
return;
}
audioSource = GetComponent<AudioSource>();
cond = Conductor.instance;
available = false;
audioSource.clip = clip;
audioSource.pitch = pitch;
audioSource.volume = volume;
audioSource.loop = looping;
Conductor cnd = Conductor.instance;
loopEndBeat = -1;
loopIndex = 0;
audioSource.Stop();
if (beat == -1 && !scheduled)
{
audioSource.Play();
playInstant = true;
played = true;
startTime = AudioSettings.dspTime;
audioSource.PlayScheduled(startTime);
StartCoroutine(NotRelyOnBeatSound());
}
else
{
playInstant = false;
scheduledPitch = cnd.SongPitch;
startTime = (AudioSettings.dspTime + (cnd.GetSongPosFromBeat(beat) - cnd.songPositionAsDouble)/(double)scheduledPitch) - offset;
scheduledPitch = cond.SongPitch;
startTime = (AudioSettings.dspTime + (cond.GetSongPosFromBeat(beat) - cond.songPositionAsDouble) / (double)scheduledPitch) - offset;
if (scheduledPitch != 0 && AudioSettings.dspTime >= startTime)
{
@ -69,10 +88,15 @@ namespace HeavenStudio.Util
private void Update()
{
Conductor cnd = Conductor.instance;
cond = Conductor.instance;
double dspTime = AudioSettings.dspTime;
if (!played)
if (!available)
{
if (!Conductor.instance.isPlaying)
{
GameManager.instance.SoundObjects.Release(this);
return;
}
if (scheduled)
{
if (!queued && dspTime > scheduledTime - PREBAKE_TIME)
@ -90,7 +114,7 @@ namespace HeavenStudio.Util
{
if (!queued && dspTime > startTime - PREBAKE_TIME)
{
startTime = (dspTime + (cnd.GetSongPosFromBeat(beat) - cnd.songPositionAsDouble)/(double)scheduledPitch) - offset;
startTime = (dspTime + (cond.GetSongPosFromBeat(beat) - cond.songPositionAsDouble) / (double)scheduledPitch) - offset;
audioSource.PlayScheduled(startTime);
queued = true;
}
@ -101,11 +125,11 @@ namespace HeavenStudio.Util
}
else
{
if (!played && scheduledPitch != cnd.SongPitch)
if (!played && scheduledPitch != cond.SongPitch)
{
if (cnd.SongPitch == 0)
if (cond.SongPitch == 0)
{
scheduledPitch = cnd.SongPitch;
scheduledPitch = cond.SongPitch;
if (queued)
audioSource.Pause();
}
@ -115,8 +139,8 @@ namespace HeavenStudio.Util
{
audioSource.UnPause();
}
scheduledPitch = cnd.SongPitch;
startTime = (dspTime + (cnd.GetSongPosFromBeat(beat) - cnd.songPositionAsDouble)/(double)scheduledPitch);
scheduledPitch = cond.SongPitch;
startTime = (dspTime + (cond.GetSongPosFromBeat(beat) - cond.songPositionAsDouble) / (double)scheduledPitch);
if (queued)
audioSource.SetScheduledStartTime(startTime);
}
@ -129,7 +153,7 @@ namespace HeavenStudio.Util
{
if (looping && loopEndBeat != -1) // Looping sounds play forever unless params are set.
{
if (cnd.songPositionInBeats > loopEndBeat)
if (cond.songPositionInBeatsAsDouble > loopEndBeat)
{
KillLoop(fadeTime);
loopIndex++;
@ -140,10 +164,16 @@ namespace HeavenStudio.Util
IEnumerator NotRelyOnBeatSound()
{
if (!looping) // Looping sounds are destroyed manually.
if (!Conductor.instance.isPlaying)
{
yield return new WaitUntil(() => !audioSource.isPlaying);
Delete();
GameManager.instance.SoundObjects.Release(this);
yield break;
}
WaitUntil yieldIsAudioPlaying = new WaitUntil(() => !audioSource.isPlaying || !Conductor.instance.isPlaying);
if (played && !looping) // Looping sounds are destroyed manually.
{
yield return yieldIsAudioPlaying;
GameManager.instance.SoundObjects.Release(this);
}
}
@ -153,12 +183,6 @@ namespace HeavenStudio.Util
this.fadeTime = fadeTime;
}
public void Stop()
{
if (audioSource != null)
audioSource.Stop();
}
public void Pause()
{
if (audioSource != null)
@ -171,10 +195,23 @@ namespace HeavenStudio.Util
audioSource.UnPause();
}
public void Delete()
public void Stop()
{
GameManager.instance.SoundObjects.Remove(gameObject);
Destroy(gameObject);
available = true;
played = false;
queued = false;
playInstant = false;
looping = false;
scheduled = false;
beat = 0;
loopEndBeat = -1;
loopIndex = 0;
startTime = 0;
audioSource.loop = false;
audioSource.Stop();
gameObject.SetActive(false);
}
#region Bend
@ -182,12 +219,14 @@ namespace HeavenStudio.Util
// minenice: consider doing these in the audio thread so they can work per-sample?
public void BendUp(float bendTime, float bendedPitch)
{
if (!gameObject.activeSelf) return;
this.bendedPitch = bendedPitch;
StartCoroutine(BendUpLoop(bendTime));
}
public void BendDown(float bendTime)
{
if (!gameObject.activeSelf) return;
StartCoroutine(BendDownLoop(bendTime));
}
@ -225,10 +264,11 @@ namespace HeavenStudio.Util
public void KillLoop(double fadeTime)
{
if (!gameObject.activeSelf) return;
StartCoroutine(FadeLoop(fadeTime));
}
float loopFadeTimer = 0f;
double loopFadeTimer = 0f;
IEnumerator FadeLoop(double fadeTime)
{
float startingVol = audioSource.volume;
@ -236,11 +276,11 @@ namespace HeavenStudio.Util
while (loopFadeTimer < fadeTime)
{
loopFadeTimer += Time.deltaTime;
audioSource.volume = (float) Math.Max((1f - (loopFadeTimer / fadeTime)) * startingVol, 0.0);
audioSource.volume = (float)Math.Max((1f - (loopFadeTimer / fadeTime)) * startingVol, 0.0);
yield return null;
}
Delete();
yield return null;
GameManager.instance.SoundObjects.Release(this);
}
}
}