Show / Hide Table of Contents

Class IntroloopPlayer

A component that coordinates 4 UnityEngine.AudioSource together with scheduling methods to achieve gap-less looping music with intro section.

Inheritance
System.Object
UnityEngine.Object
UnityEngine.Component
UnityEngine.Behaviour
UnityEngine.MonoBehaviour
IntroloopPlayer
IntroloopPlayer<T>
Namespace: E7.Introloop
Assembly: E7.Introloop.dll
Syntax
public class IntroloopPlayer : MonoBehaviour
Remarks

2 UnityEngine.AudioSource uses scheduling methods to stitch up audio precisely, while the other 2 sources are there to support cross fading to a new Introloop audio.

Potentially there is a moment when all 4 sources are playing at the same time. (e.g. One introlooping audio at the seam, while being tasked to cross fade into an another introloop audio that starts near the seam.)

Properties

DefaultIntroloopAudio

Works like UnityEngine.AudioSource.clip property. You can set this to any IntroloopAudio for it to be used when you call Play() or Play(Single, Single) next.

Declaration
public IntroloopAudio DefaultIntroloopAudio { get; set; }
Property Value
Type Description
IntroloopAudio

Instance

Get a convenient singleton instance of IntroloopPlayer from anywhere in your code. It has DontDestroyOnLoad applied.

Before calling this for the first time, call SetSingletonInstanceTemplateSource(AudioSource) first to setup its TemplateSource from script. (It does not exist until runtime, you cannot setup the template ahead of time unlike non-singleton instances.)

Declaration
public static IntroloopPlayer Instance { get; }
Property Value
Type Description
IntroloopPlayer

InternalAudioSources

If you wish to do something that affects all 4 UnityEngine.AudioSource that Introloop utilize at once, do a foreach on this property.

Declaration
public IEnumerable<AudioSource> InternalAudioSources { get; }
Property Value
Type Description
System.Collections.Generic.IEnumerable<UnityEngine.AudioSource>
Remarks

You should not use this in Awake, as Introloop might still not yet spawn the UnityEngine.AudioSource.

PlayOnAwake

Works like UnityEngine.AudioSource.playOnAwake, play the connected DefaultIntroloopAudio automatically on Awake.

Declaration
public bool PlayOnAwake { get; set; }
Property Value
Type Description
System.Boolean

TemplateSource

When it would spawn 4 UnityEngine.AudioSource for the first time on Start(), read out the fields from this UnityEngine.AudioSource reference and copy them to all 4. Assigning this after it had already spawned underlying 4 UnityEngine.AudioSource has no effect.

To apply this template again after Start(), use ApplyAudioSource(AudioSource). The argument could be this TemplateSource or any other UnityEngine.AudioSource.

Declaration
public AudioSource TemplateSource { get; set; }
Property Value
Type Description
UnityEngine.AudioSource
Remarks

The UnityEngine.AudioSource does not need to be since it just need to read the fields out for copy. Also it does not need to be anywhere on the scene, it can come from a prefab with UnityEngine.AudioSource in your project.

Methods

ApplyAudioSource(AudioSource)

Copy fields from applyFrom to all 4 underlying UnityEngine.AudioSource. Make it as if they had applyFrom as a TemplateSource from the beginning. (Or you can think this method as a way to late-assign a TemplateSource.)

Declaration
public void ApplyAudioSource(AudioSource applyFrom)
Parameters
Type Name Description
UnityEngine.AudioSource applyFrom
Remarks

The UnityEngine.AudioSource does not need to be since it just need to read the fields out for copy. Also it does not need to be anywhere on the scene, it can come from a prefab with UnityEngine.AudioSource in your project.

GetDebugStringsTrack1()

Each player contains 4 UnityEngine.AudioSource, this method returns the current information of the first pair for debugging purpose.

Declaration
public string[] GetDebugStringsTrack1()
Returns
Type Description
System.String[]

GetDebugStringsTrack2()

Each player contains 4 UnityEngine.AudioSource, this method returns the current information of the second pair for debugging purpose.

Declaration
public string[] GetDebugStringsTrack2()
Returns
Type Description
System.String[]

GetPlayheadTime()

This interpretation of a play time could decrease when it goes over looping boundary back to intro boundary. Conceptually Introloop audio has infinite length, so this time is a bit different from normal sense.

Declaration
public float GetPlayheadTime()
Returns
Type Description
System.Single
Remarks

Think as it as not "elapsed time" but rather the position of the actual playhead, expressed in time as if the pitch is 1.

For example with pitch enabled, the play head will move slowly, and so the time returned from this method respect that slower play head.

It is usable with Play(IntroloopAudio, Single, Single) as a start time to "restore" the play from remembered time. With only 1 IntroloopPlayer you can stop and unload previous song then continue later after reloading it.

Common use case includes battle music which resumes the field music afterwards. If the battle is memory consuming unloading the field music could help.

OnApplicationPause(Boolean)

This is a dirty workaround for the bug in 2019.1+ where on game minimize or UnityEngine.AudioListener pause, all UnityEngine.AudioSource.SetScheduledEndTime(System.Double) will be lost.

I confirmed it is not a problem in 2018.4 LTS. The ideal fix is to call Pause just before the game goes to minimize then Resume after we comeback to reschedule.

However at this callback Pause does not work, as all audio are already on its way to pausing. So an another approach is that we will remember the time just before the pause, and the play again after coming back using that time. The Seek method can be used instead of Play here so you don't have to specify the previous audio.

Please see : https://forum.unity.com/threads/introloop-easily-play-looping-music-with-intro-section-v4-0-0-2019.378370/#post-4793741 Track the case here : https://fogbugz.unity3d.com/default.asp?1151637_4i53coq9v07qctp1

Declaration
public void OnApplicationPause(bool paused)
Parameters
Type Name Description
System.Boolean paused

Pause()

Pause the currently playing IntroloopAudio immediately without unloading. Call Resume(Single) to continue playing.

Declaration
public void Pause()

Pause(Single)

Fading out to pause the currently playing IntroloopAudio without unloading. Call Resume(Single) to continue playing.

Declaration
public void Pause(float fadeLengthSeconds)
Parameters
Type Name Description
System.Single fadeLengthSeconds

Fade out length to use in seconds.

  • 0 is a special value that will still apply small pop removal fade time.
  • If negative, this method works like Pause() overload.

Play()

Similar to Play(IntroloopAudio, Single, Single) overload, but has no optional arguments so it is able to receive calls from UnityEngine.Events.UnityEvent.

Declaration
public void Play()

Play(IntroloopAudio)

Similar to Play(IntroloopAudio, Single, Single) overload, but has only a single argument so it is able to receive calls from UnityEngine.Events.UnityEvent.

Declaration
public void Play(IntroloopAudio introloopAudio)
Parameters
Type Name Description
IntroloopAudio introloopAudio

Play(IntroloopAudio, Single, Single)

Play any IntroloopAudio asset with the argument introloopAudio, regardless of IntroloopAudio asset assigned in DefaultIntroloopAudio.

Declaration
public void Play(IntroloopAudio introloopAudio, float fadeLengthSeconds = 0F, float startTime = 0F)
Parameters
Type Name Description
IntroloopAudio introloopAudio

A reference to IntroloopAudio asset file to play.

System.Single fadeLengthSeconds

Fade in/out length to use in seconds.

  • If 0, it uses a small pop removal fade time.
  • If negative, it is immediate.
The audio will be unloaded only after it had fade out completely.
System.Single startTime

Specify starting point in time instead of starting from the beginning.

The time you specify here will be converted to "play head time", Introloop will make the play head at the point in time as if you had played for this amount of time before starting.

Since IntroloopAudio conceptually has infinite length, any number that is over looping boundary will be wrapped over to the intro boundary in the calculation. (Except that if the audio is non-looping)

The time specified here is not taking Pitch into account. It's an elapsed time as if Pitch is 1.

Remarks

It applies Volume and Pitch to the underlying UnityEngine.AudioSource.

If an another IntroloopAudio is playing on this player, it could cross-fade between the two if fadeLengthSeconds is provided. The faded out audio will be unloaded automatically once the fade is finished.

Exceptions
Type Condition
System.ArgumentNullException

Thrown when introloopAudio is null.

Play(Single, Single)

Play IntroloopAudio asset currently assigned to DefaultIntroloopAudio.

Declaration
public void Play(float fadeLengthSeconds = 0F, float startTime = 0F)
Parameters
Type Name Description
System.Single fadeLengthSeconds

Fade in/out length to use in seconds.

  • If 0, it uses a small pop removal fade time.
  • If negative, it is immediate.
The audio will be unloaded only after it had fade out completely.
System.Single startTime

Specify starting point in time instead of starting from the beginning.

The time you specify here will be converted to "play head time", Introloop will make the play head at the point in time as if you had played for this amount of time before starting.

Since IntroloopAudio conceptually has infinite length, any number that is over looping boundary will be wrapped over to the intro boundary in the calculation. (Except that if the audio is non-looping)

The time specified here is not taking Pitch into account. It's an elapsed time as if Pitch is 1.

Remarks

It applies Volume and Pitch to the underlying UnityEngine.AudioSource.

If an another IntroloopAudio is playing on this player, it could cross-fade between the two if fadeLengthSeconds is provided. The faded out audio will be unloaded automatically once the fade is finished.

Exceptions
Type Condition
System.ArgumentNullException

Thrown when DefaultIntroloopAudio was not assigned.

Preload(IntroloopAudio)

An experimental feature in the case that you really want the audio to start in an instant you call Play(IntroloopAudio, Single, Single). You must use the same IntroloopAudio that you preload in the next play.

Declaration
public void Preload(IntroloopAudio introloopAudio)
Parameters
Type Name Description
IntroloopAudio introloopAudio
Remarks

By normally using Play(IntroloopAudio, Single, Single) and Stop(Single) it loads the audio the moment you called Play(IntroloopAudio, Single, Single). Introloop waits for an audio to load before playing with a coroutine.

(Only if you have UnityEngine.AudioClip.loadInBackground in the import settings. Otherwise, Play(IntroloopAudio, Single, Single) will be a blocking call.)

Introloop can't guarantee that the playback will be instant, but your game can continue while it is loading. By using this method before actually calling Play(IntroloopAudio, Single, Single) it will instead be instant.

This function is special even songs with UnityEngine.AudioClip.loadInBackground can be loaded in a blocking fashion. (You can put Play(IntroloopAudio, Single, Single) immediately in the next line expecting a fully loaded audio.)

However be aware that memory is managed less efficiently in the following case : Normally Introloop immediately unloads the previous track to minimize memory. But if you use Preload(IntroloopAudio) then did not call Play(IntroloopAudio, Single, Single) with the same IntroloopAudio afterwards, the loaded memory will be unmanaged.

(Just like if you tick UnityEngine.AudioClip.preloadAudioData on your clip and have them in a hierarchy somewhere, then did not use it.)

Does not work with UnityEngine.AudioClipLoadType.Streaming audio loading type.

Resume(Single)

Resume playing of previously paused (Pause(Single)) IntroloopAudio. If currently not pausing, it does nothing.

Declaration
public void Resume(float fadeLengthSeconds = 0F)
Parameters
Type Name Description
System.Single fadeLengthSeconds

Fade out length to use in seconds.

  • If 0, it uses a small pop removal fade time.
  • If negative, it resumes immediately.
Remarks

Note that if it is currently "fading to pause", the state is not considered paused yet so you can't resume in that time.

Seek(Single)

Move the play head of the currently playing audio to anywhere in terms of elapsed time.

  • If it is currently playing, you can instantly move the play head position to anywhere else.
  • If it is not playing, no effect. (This includes while in paused state, you cannot seek in paused state.)
Declaration
public void Seek(float elapsedTime)
Parameters
Type Name Description
System.Single elapsedTime

Introloop will make the play head at the point in time as if you had played for this amount of time before starting.

The time you specify here will be converted to "play head time", Introloop will make the play head at the point in time as if you had played for this amount of time before starting.

Since IntroloopAudio conceptually has infinite length, any number that is over looping boundary will be wrapped over to the intro boundary in the calculation. (Except that if the audio is non-looping) The time specified here is not taking Pitch into account. It's an elapsed time as if Pitch is 1.

Remarks

An internal implementation is not actually a seek, but a completely new Play(IntroloopAudio, Single, Single) with the previous IntroloopAudio.

This is why you cannot seek while in pause, as it actually does a new play for you. It is handy because it doesn't require you to remember and specify that audio again.

SetMixerGroup(AudioMixerGroup)

Assign a different audio mixer group to all underlying UnityEngine.AudioSource.

Declaration
public void SetMixerGroup(AudioMixerGroup audioMixerGroup)
Parameters
Type Name Description
UnityEngine.Audio.AudioMixerGroup audioMixerGroup

SetSingletonInstanceTemplateSource(AudioSource)

Call this before the first use of Instance to have the singleton instance copy UnityEngine.AudioSource fields from templateSource.

Declaration
public static void SetSingletonInstanceTemplateSource(AudioSource templateSource)
Parameters
Type Name Description
UnityEngine.AudioSource templateSource
Remarks

Singleton instance is convenient but you cannot pre-connect TemplateSource like a regular instance because it does not exist until runtime.

If you had already used the singleton instance before calling this, you can still call ApplyAudioSource(AudioSource) on the singleton instance to apply different settings of UnityEngine.AudioSource.

Stop()

Stop the currently playing IntroloopAudio immediately and unload it from memory.

Declaration
public void Stop()

Stop(Single)

Fading out to stop the currently playing IntroloopAudio, and unload it from memory once it is completely faded out.

Declaration
public void Stop(float fadeLengthSeconds)
Parameters
Type Name Description
System.Single fadeLengthSeconds

Fade out length to use in seconds.

  • 0 is a special value that will still apply small pop removal fade time.
  • If negative, this method works like Stop() overload.
In This Article
Back to top
A Unity plugin by 5argon from Exceed7 Experiments. Problems/suggestions/contact : 5argon@exceed7.com Discord Unity Forum