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
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
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
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.
|
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.
|
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 |
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.
|
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.
|
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.
|