GameObject that appears when you call
IntroloopPlayer.Instance.xxxx contains 2
IntroloopTrack represent one
IntroloopAudio and we needed 2 because when cross-fading we must hear 2 audio at the same time at some point. Each call to
Play method, Introloop will alternate between these two
IntroloopTrack contains 2 Unity's
AudioSource so in total Introloop achieve it's playback function with 4
AudioSource. We need 2
AudioSource because of intro and looping functionality. When approaching loop point, the other
AudioSource will be scheduled and waiting to take the baton from previous one, while the previous one is also scheduled to stop at the same time. The scheduling is accurate because it uses
AudioSettings.dspTime function in Unity which is independent from game's timescale. Scheduling will happen when one
AudioSource is reaching halfway til the switching point.
AudioSource actually loads the same audio data (from the same
IntroloopAudio) so memory usage is not doubled.
AudioSettings.dspTime for scheduling audio pieces, which is independent of normal game's clock. This means if you implement
Time.timeScale for pausing the game or for some other reason, it will have no effect on Introloop and it will continue playing. (You can have music still playing while the game pause, for example.)
However there are some situations that can mess up the timing and can produce weird behaviours. For example when creating games in Unity and Introloop is playing, if you make the Unity window inactive everything will stop and resume nicely (The playing audio,
On the other hand if you do things like right-clicking on any
GameObject in your Hierarchy and keep the popup menu open, you will notice that your game stopped updating but the music still plays. This will cause Introloop to miss the schedule and I can't fix it because OS-level behaviour is not in my control. This kind of behaviour can only happen in the Editor though, so you should not have to worry about it in real game.
I am sorry to say that no, it won't work! Read on for detailed reasons that I have been fighting with since 4.x era.
I finished Introloop a long time ago and have been using it in my projects both personal and at work. However the reason I cannot put in on store is because there are much more problems in 4.x about memory that I will explain shortly.
In Unity 4.x if we connect
IntroloopAudio to the inspector like we did now in Unity 5, since it contains reference to
AudioClip, all the songs will be instantly loaded into memory even if you are not going to play it yet. The same happen when you connect
public AudioClip inspector variable. When scene start it checks all inspector slots and load everything. Even if you use
Resources.Unload(resource) to quickly free it, the unavoidable memory spike at scene load certainly can crash mobile project with low amount of RAM. (It did really happen to me)
In Unity 5.x if you click any
AudioClip you will notice some new checkboxes that is not present in Unity 4.x, Preload Audio Data and Load In Background (Corresponding to the new scripting counterpart
AudioClip.loadInBackground respectively.) The first one is godsend, since if you uncheck it the audio will not load unless you call the new
AudioClip.LoadAudioData() (In Unity 4.x it works like this is set to true all the times.) And so it enables us to use Unity's workflow of connecting the inspector.
How about ditching the connect thing and put the
IntroloopAudio in the Resoources folder and load it dynamically in Unity 4.x? Yes, the memory spike is no more but it requires that all your audio is in Resources folder and loaded through
Resources.Load(string). This Resources folder restriction feels unnatural and difficult to explain to others and also makes your project messy. (But I have been doing this personally before Unity 5.0) Moreover
Resources.Load(string) is designed for run-time execution, it is string based which is not flexible like normal asset-to-inspector preconnecting in Unity. Not to mention that
Resources.Unload(resource) is too low-level, sometimes it doesn't unload because something is using the resource and even produce errors. The only error-free way to unload is
Resources.UnloadUnusedAssets() but it traverse all
GameObject in your scene and it is very bad for performance. (A plugin should never reach out of its own thing also.)
In Unity 5.x to free audio we finally have a dedicated
AudioClip.UnloadAudioData() (Counterpart of also new
AudioClip.LoadAudioData()) and it is much more reliable than
Resource.Unload(resource). The new Load In Background option is not mandatory for Introloop but also useful. In Unity 4.x your code will block when loading audio (Combine that with the must-load-all-connected-audio problem and you get a lag everytime a scene loads!). Checking this to true and your code will continue running while it loads! As an extra, in Unity 5.x the Profiler reports audio data more truthfully. (I have gone through hell being tricked repeatedly in 4.x already...)
For these reasons, if you try Introloop in Unity 4.x it will not compile since it is missing aforementioned 5.x functions.
IntroloopAudio is just a link to original audio. Also, it is important to set your import settings correctly. Introloop will work with any combination of load types, (Compressed In Memory, Decompress On Load, Streaming) compression settings (Vorbis, PCM) and options : Load In Background, Preload Audio Data. I recommend unchecking Preload Audio Data for all audio since if not, all
IntroloopAudio connected to any
GameObject will all be loaded on scene start. Other settings you can set them as you like. As a bonus, if you check Log Information in
IntroloopSettings that is attached to the template object and your audio has Load In Background enabled, the log will include a time taken to load that audio too.
Actually even the time with 3 decimal places is not enough, since the actual unit for location in audio is sample. The time will be converted to sample by Unity, and this is where an audio might slip off a few samples producing an audible seams.
I use time in seconds since it is easier to get and in most case produce good result. But if your audio is not seamless (and you are sure that your time is exact), you can try adding very small number to both boundaries by the same amount. Since the audio bits after the boundaries should sound the same, doing this should not change the song at all but you will get a new transition point. This new seam might work out better than the previous point. Try this several times to find out the best spot. (Remember the original point too! You can't go back more than that.)
This limitation is actually on Unity's side. As WebGL is currently in preview status, this page lists current limitations. One of them is about audio, which directly affect this plugin. (All "Schedule" method does not work on WebGL)
I have reported the bug, and they responded that it would be resolved in Unity 5.4. So let's wait until then!
(Ps. Now it's Unity 5.6.0f3 already but after I tested the Schedule methods are still not implemented on WebGL.)
Introloop uses 4
AudioSource in tandem, and changes their volume for crossfading, etc. regulary so it is not easy to directly manipulate them. For global volume/sfx that you might adjust in option screen, the current best practice in Unity 5 is using the Audio Mixer. You can route Introloop's audio to your mixer by following this tutorial.
After this, the level of that track you routed to can be controlled from script. Mainly via SetFloat/GetFloat which you can then link to your slider UI. More info.
The memory overhead will be the same as Unity's normal audio loading and playing, as it is basically just 4 AudioSources that loads the same audio. This means the memory depends on your import settings of the said audio. (Thus "Streaming" would use the least memory as it loads just around the playhead.) You can determine the memory overhead by dragging your 3.5MB 32-bit song to the AudioSource (with your desired loading type) and look at the Profiler. (Beware that just clicking the file might cause a false memory overhead as the Profiler profiles memories used for previewing in the editor)
Other than that, the additional memory overhead is from storing the GameObjects and variables that manages the looping mechanism. I don't think that is significant compared to the audio data itself.
However Introloop does something more that are different from just issuing .Play() .Stop() directly to the AudioSource :
Introloop does not split the music clip or buffer data at any point. You are correct about Unity's Update API, but Unity has an another timing mechanism specifically for audio, dspTime.
There are 3 methods that utilize this,
SetScheduledEndTime. After you call them, when dspTime comes to that point you specify an audio will play regardless of if it is in-between Update frame or not. Therefore I can set it up to loop to itself without cutting the asset. (Actually it is not looping to itself but a duplicate of itself that is waiting at the seam. When dspTime arrives one will stop and the other one will begin.)
The difficulties of using this is it is like setting a trap. You have to plan things ahead of time to also allows it to loads up the audio. Introloop's strategy is to schedule when there is halfway to go approaching the loop point. The schedule cannot be cancelled, if user decides to stop, pause or change music in the period after it already scheduled we also have to reschedule to override the old ones. The schedule can even be met while an AudioSource is stopping or pausing but luckily will not take effect until it is playing again, so we can reschedule before resuming to prevent it jumping to a wrong place.