Loop music on specific timings

Hello !

I’ve created a way to loop music in the following way:

Music always starts at time = 0, then when it reaches, for example, time = 240.45s, it must go back to time = 0.943s.

To basically loop seamlessly but not from start to end.

The bounds “loopTimes.start” and “loopTimes.end” are defined when the music is first played, to know where they are for each music.

I did this:

private void Update() {
  if (musicSource.isPlaying && loopTimes != null && musicSource.time >= loopTimes.end) {
    musicSource.time = loopTimes.start;
  }
}

That seems to work fine, but what I wonder is, what would happen if the game lags and the Update function is called less often ? Will the transition happen potentially later and be noticeable ?

Yeah, I just added a million object colliding with each other to simulate lag, and yeah the transition is not always exactly at the same time because of it.

I guess I need to do a fade in/out then…

Update runs at the current frame rate, which is too slow to play or loop audio without gaps. As you found out, the latency also depends on the current fps.

Instead, you need to use the scheduled methods on the audio source, like AudioSource.PlayScheduled or AudioSource.SetScheduledEndTime. These allow you to precisely set the dsp time the audio starts/stop playing.

To do more complex things, you might need to use multiple audio sources. For the looping you mentioned, you probably need one playing source that you schedule to stop and then another source that you schedule to play at the same time, as you cannot do a scheduled seek.

Thanks for answering !

Actually, I just used FixedUpdate over Update and it works well even with massive lag. I guess it’s because unlike Update, FixedUpdate is assured to be called 60 times per second ?

Your way looks way cleaner though ! I’ll look into it.

FixedUpdate only changes things related to physics. If the lag is caused by something else, FixedUpdate will be exactly as accurate as Update.

The reason is that FixedUpdate is called as part of the frame loop, just like Update. It only gets skipped or called in a loop to reach the target fixed time step. I.e., if Update is delayed by something, FixedUpdate will be delayed exactly the same, just then called multiple times to catch up.

It helps in your case with tons of collisions because the physics itself is causing the lag, executing many expensive physics time steps per frame. FixedUpdate will run between those expensive calculations, Update will run only once.

2 Likes

So I tried to use these functions and it really isn’t easy.

It fails if I change the pitch, or if I pause the game, because dspTime continues at the same rate while the song doesn’t (slowed down/sped up or stopped)

So how do you manage these cases ?

Yeah, Unity’s audio support is on the basic side and doing more advanced things requires a lot of juggling.

If you change the pitch to the same value for the whole duration, you can just calculate the adjusted length (length = duration / pitch) and schedule with that.

If you adjust the pitch dynamically, you need to re-calculate the length and update the schedule every time you change the pitch. Or at least estimate if you could reach the schedule in the next frame and schedule only then but taking care if the frame is shorter/longer than expected.

Hm, and since Update still runs when pausing the game, I guess I could delay this the same way or something ?

Tricky but possible I guess.
Thanks a lot for your guidance, I’ll look into that !