1
\$\begingroup\$

In Unity, I want to trigger an event when an audio clip finishes playing. Would it be more CPU efficient to keep checking if the audio clip is playing with

WaitUntil(() => audioSource.isPlaying == false);

or would it be more efficient to use:
WaitForSeconds(audioClip.length);
to simply wait a certain amount of time?

How can I run a test in Unity to see which one is more CPU efficient?

\$\endgroup\$
3
  • \$\begingroup\$ Did you try starting a few hundred of one of these, to see if one version or the other makes a more noticeable spike in the profiler? \$\endgroup\$
    – DMGregory
    Commented Mar 24, 2019 at 20:43
  • \$\begingroup\$ No, how do I start a few hundred coroutine events at the same time that also run simultaneously? \$\endgroup\$ Commented Mar 24, 2019 at 20:44
  • \$\begingroup\$ The same ways we use to do a few hundred passes of most other things should work, like a standard for loop. What did you try? \$\endgroup\$
    – DMGregory
    Commented Mar 24, 2019 at 20:46

1 Answer 1

3
\$\begingroup\$

isPlaying will also return false if the song gets paused via. Pause.

Therefore I'd recommend waiting for the clip.length instead. Be aware tough this will only work in case your song plays with a pitch of 1.

Anything else will cause the AudioSource to play faster or backwards and therefore the WaitForSeconds call doesn't actually wait until the song ends.


Instead of thinking about which Wait call to use, it would probably make much more sense to ensure you cache the WaitForSeconds or WaitUntil call.

This is helpful because the new keyword heap allocates the given class meaning it has to be garbage collected once it is not used anymore. If you instead create it at the start of the coroutine and reuse it. You can save precious garbage allocations, which especially for low end devices (Phones etc.) can make a huge performance difference.


Method to actually wait until the clip ends:

There is still one drawback if you increase/decrease the pitch while the Coroutine has already started the WaitForSeconds call will still be off by the given pitch difference.

private IEnumerator ExampleCoroutine(AudioSource source) {
    // Cache the WaitForSeconds call, this is done because
    // like any other class WaitForSeconds causes garbage because it is heap allocated.
    // Therefore we cache it to simply reuse the same class instance.
    var waitForClipRemainingTime = new WaitForSeconds(source.GetClipRemainingTime());
    yield return waitForClipRemainingTime;
    // Trigger event here!
}

Needed ExtensionHelpers:

using UnityEngine;
using UnityEngine.Audio;

public static class AudioSourceExtension {
    public static bool IsReversePitch(this AudioSource source) {
        return source.pitch < 0f;
    }

    public static float GetClipRemainingTime(this AudioSource source) {
        // Calculate the remainingTime of the given AudioSource,
        // if we keep playing with the same pitch.
        float remainingTime = (source.clip.length - source.time) / source.pitch;
        return source.IsReversePitch() ?
            (source.clip.length + remainingTime) :
            remainingTime;
    }
}
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .