Search Unity

Introloop - Easily play looping music with intro section

Discussion in 'Assets and Asset Store' started by 5argon, Jan 8, 2016.

  1. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    Screenshot 2019-11-20 16.30.59.png

    Demo, Installations, Scripting Ref., FAQ : http://www.exceed7.com/introloop/
    Change log : http://exceed7.com/introloop/CHANGELOG.html
    Asset Store Link : http://u3d.as/mxD
    Contact : Post on this thread or mail to 5argon@exceed7.com or Discord http://discord.gg/KgXRaKU

    Less than 1 minute explanation of what it is :

    Get that charm of a polished game. Adds huge value to music. Directs player's feel with an intro. Gives every song a memorable and immersive feeling which can't be put in an OST.

    Let's recall memorable moment from favorite games you have played. A destined fight with arch rival? Roaming overworld map for the first time? An opening stage that really hooks you that you can't put down the joystick?

    Wondered why they stuck so well in your memory? The answer is music intro and I am going to make you realize that it is important. I think I am not the only one who noticed this so I made Introloop for the person who cares about his own game soundtrack :D

    Many commercial game music has certain charm when you are listening to it in game because they're programmed to have a nice intro that sets the mood of that particular scene, before transitioning seamlessly to a music loop, never having to play the intro again. This is the source of immersive feeling you never get when you listen to the song again in an OST.

    In Unity if you select "Loop" in an AudioSource, the song will loop to beginning when it reaches the very end.


    With Introloop, you can specify 2 time point "Intro Boundary" and "Looping Boundary" in your audio. Playing with this plugin, it will now loop back to Intro Boundary when it reaches Looping Boundary, effectively make the section before Intro Boundary an intro section that plays only once and the rest will be looping.


    Introloop is also natural for the composer. Almost all DAW has a "loop bracket" function. You can start playing before the left edge of the bracket, but once the playhead is inside and finally arrives at the right edge then it loops back to the left edge.

    Introloop make the composer very comfortable as he see what the game would play like what he can preview on the DAW. Exporting the song is easy as he can export the whole song without any special care like having to export twice to cut them up for the developer.



    Advantages

    • No need to cut the actual file into 2 parts.
    • Because of that you can use any compression (like OGG) without fear of messing the precision at the head and tail of audio file. Feel free to utilize the Unity's compression quality slider - and any other audio settings built-in. It even works with
      Streaming
      load type.
    • It is easy to experiment and adjust the loop point right in Unity. In a splitting clips solution you will have to cut the music over and over again until it is seamless enough.
    • Updating music from your composer is easy, as long as the song structure is the same you can just replace the whole music and use the old boundaries.
    • Automatic audio memory releasing at appropriate time. Perfect for mobile project. This is not the case in Unity as even after the song has stopped it will be still in your RAM.
    • Supports pause, resume, fade in, fade out and even cross fading between introlooping audio.
    • Built in pop/clicks reduction when stopping the music suddenly.
    • An asset-based design allows you to have more metadata per audio, such as a default volume. This is not possible in an imported
      AudioClip
      .
    • Supports time operation such as seeking or starting at a different time. Note that in Introloop the time is theoretically infinite. These operations are more complex than same thing you usually see in other audio API.
    • You could specify a constant pitch for each asset file. The loop scheduling is still dead-accurate.
    • Route the entire plugin to your game's
      AudioMixerGroup
      for your own higher level control. Casting epic spell and wanted to duck the BGM down? Just route to your mixer and use Unity mixer's ducking feature on it.
    • Modern plugin design. It is in a proper UPM (Unity Package Manager) shape with
      package.json
      , with a proper Assembly Definition Files, namespaced properly,
      internal
      utilized effectively, asset-based design will not clutter your scene with anything, and it came with no other assortments of audio features.
    • The license purchase came with full source code.

    It is a common practice used in many commercial games. Intro adds huge value to music, turning into a powerful tool for directing player's feel and blends more into gameplay.

    It's not just about random battles, any feeling you would like your player to feel, use music intro to direct him/her to that direction right from the start then keep it going with your gameplay.

    See real examples from commercial games and try out the demo in the website below.
    http://www.exceed7.com/introloop/



    Feel free to ask me any question about Introloop. Criticisms, suggestions are all welcomed as I wanted to know what you guys want. Thank you!
     
    Last edited: Nov 22, 2019
  2. Cascho01

    Cascho01

    Joined:
    Mar 19, 2010
    Posts:
    1,347
    Cool.
    Can we expect a smooth loop without any noticable "cracks" when it jumps from end to startpoint?
    In my experience this is the hardest point to solve.
     
  3. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    Yes! You can expect it as long as your 2 time point is precise enough. The timing is achieved by not the normal game time nor coroutine but by
    Code (CSharp):
    1. AudioSettings.dspTime, AudioSource.PlayScheduled, AudioSource.SetScheduledStartTime and AudioSource.SetScheduledEndTime
    internally to ensure this.

    I have provided the demo in this page so you can test the seamless-ness. Or alternatively if you don't have the PC now, download this game to your mobile phone and hear if you notice any cracks or not. (The title screen already is using Introloop)
     
    Last edited: Jan 8, 2016
  4. hima

    hima

    Joined:
    Oct 1, 2010
    Posts:
    183
    Is there a way to change a track's volume in real time? In my game, the player can change global background music volume in the option screen. It'd be nice if they can hear the change in real time.
     
  5. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    Yes. For global volume/sfx that you will 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 : http://www.exceed7.com/introloop/getting-started.html

    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.
    https://unity3d.com/learn/tutorials/modules/beginner/5-pre-order-beta/exposed-audiomixer-parameters
     
    hima likes this.
  6. hima

    hima

    Joined:
    Oct 1, 2010
    Posts:
    183
    Thank you! I totally forgot about the new Audio features in Unity5. This mean I have to rewrite how I handle audio in the game again but it should be much easier to deal with.
     
    5argon likes this.
  7. Fallenleader

    Fallenleader

    Joined:
    Jan 26, 2015
    Posts:
    7
    The only flaw I have seen with this, is for systems like the N3DS.
    Ultimately, this solution is exactly what I need, but I cannot guarantee it will work for specific devices, which is why I am holding off on a purchase.
    How would using your solution work for all devices, and not just a specific set for normal everyday user devices?
     
  8. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    Hello, thank you for interested in Introloop. It's true that I could not confirm either that if it is working on 3DS or not because I don't have their dev kits. At first I assume it is Unity's job to make the code cross-compile successfully but then there is the case like WebGL where all audio "Schedule" functions are still not implemented. (they told me it is ready in 5.4, but haven't tested since then.)

    I am not sure that it also happen in 3DS or not but I could not verify it. (I will update the website with a list of untested systems along with the next update)
     
  9. Douvantzis

    Douvantzis

    Joined:
    Mar 21, 2016
    Posts:
    79
    Is the track decoded or is it streamed form the source?
     
  10. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    Hello, sorry for the late reply. You can choose whatever import settings you like and they will be in effect like it normally did. (Encoding quality, playback mode, etc.)

    Introloop uses original audio without cutting or altering anything. Internally basically it is 4 audio sources which cooperate with each others and each one have your music file loaded, so in turn, audio sources will respect all import settings.
     
  11. oliran

    oliran

    Joined:
    Sep 29, 2015
    Posts:
    49
    IntroloopPlayer randomly doesn't play the music at all (Unity 5.5). I don't know how to reproduce it as it seems random.

    In case you need it, the settings for the audioclip is:
    Load in background disabled
    Decompress On Load
    Preload Audio Data enabled
    Vorbis

    Any ideas? Has anyone else experienced this?
     
  12. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    Thank you for the report. I will look into this immediately.
    My active project that also uses Introloop is also on 5.5, so I will try to reproduce it. (If I have fixed the issue, I will come back to report again.)

    If the audio file is not sensitive, you can send the audio file, the audio's .meta file, and the corresponding Introloop asset file (that contains the 2 loop points) to me via DM. It will help me find the problem!
     
  13. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    I am pleased to inform you that version 2.0 of Introloop has finally been released. (It is also on sale 30% as a part of Unity open sale until the end of this April 2017.)

    https://www.assetstore.unity3d.com/en/#!/content/51095

    Release Note
    • (14/04/2017) Version 2.0 - New functions includes :
      • Pitch - You can now specify pitch in an IntroloopAudio asset file. If you would like to use multiple pitches of the same audio, you can just copy the asset file and have different pitches. It can reference to the same actual audio file. Works fine with pause, resume, automatic memory management.
      • Preload - A feature where critical precision of starting an Introloop Audio is needed. Load the audio by calling IntroloopAudio.Instance.Preload(yourIntroloopAudio) beforehand to pre-consume memory, and then call Play as usual afterwards.
      • Ogg Streaming as Introloop on iOS/Android - In Unity 5.5.2 they added support for choosing "Streaming" with OGG on iOS/Android. I am happy to inform that this option works with Introloop. Everthing will be the same except it will not cost you as much memory of an entire audio on Play as before in an exchange for some CPU workload.
    The website (http://exceed7.com/introloop/) also has already been updated with demo of version 2.0, which you can try the song with altered pitch. As always, if you found any problems I am ready to help you here or in the e-mail. Thank you!
     
  14. arkogelul

    arkogelul

    Joined:
    Nov 14, 2016
    Posts:
    105
    Hi,

    That looks great ! i'm trying to achieve that but couldn't get my head around how dspTime and playSchedule functions works.
    Is it possible to loop the intro and the outro instead of looping the middle part ?
     
  15. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    Hello. By definition of intro and outro I think it should not be seamlessly loopable? That's why we need Introloop, to loop the middle loopable part, and you would not have an outro since by definition of "loop" the music should never ends, thus no need for an outro.

    But if you do want to loop the intro over and over, you could set up the intro boundary as 0 and outro boundary as the "supposed to be" intro boundary.

    With the same idea you could set the intro boundary as the "supposed to be" looping boundary and outro boundary as the song's length, it should loop the outro over and over once it arrives there.

    Please do clarify if I misunderstand something. Thank you.
     
  16. arkogelul

    arkogelul

    Joined:
    Nov 14, 2016
    Posts:
    105
    I actually would like to loop the intro until a certain event, then play the middle part once and then play the "outro" over and over until another event ends the music (fade out).

    EDIT: Nevermind, I actually managed to do what I wanted :)
     
    Last edited: Sep 20, 2017
    5argon likes this.
  17. Fallenleader

    Fallenleader

    Joined:
    Jan 26, 2015
    Posts:
    7
    The ONLY reason I bought this already is because I am making my game for other systems than this specific embedded one. It seems one could achieve the same effect by fully grasping dspTime, SetScheduledStartTime, SetScheduledEndTime, and PlayScheduled, but be it lack of time, laziness, or both, I just decided to use your tool as it will save me time in the end.
    This all being said, I really need to know what kind of memory footprint I will have to expect compared to toher means of looping music. I actually have 2 other usable options available that approach this solution in a less than ideal manor without much memory overhead.
    Can you please share in both Megabytes and Megabits (MB and MiB receptively) the typical memory overhead for a 3.5MB song at 32 bit Wav (on import)?
    I am targeting the Nintendo 3DS, which already has limited memory, and I am trying to land it onto an Old 3DS variant which is even more crippled memory wise( try ~16MB memory to work with).
    If you cannot specify something this precise, can you at least explain how much additional memory overhead it would have in general compared to a solution like 5000 samples of silence for a buffer, as my other method uses?
     
  18. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    Hello. Yes this project is basically manipulating dspTime, SetScheduledStartTime, SetScheduledEndTime, and PlayScheduled to achieve the effect while multiple AudioSources coordinate with each other.

    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 :

    1. When you stop the audio (and the audio finished fading out completely, if you choose to stop with a fade out), it is automatically unloaded from memory. This is not the case when you just call "Stop" to the AudioSource. This is in effect if you choose "Decompress on load" or "Compressed in memory" type.

    2. If you cross fade the audio, there will be a moment when both audio are in memory. This means if both audio file has "Decompress On Load" you will have the whole size of 2 audios in the memory in that cross fading moment. However, when it finished cross fading the faded out ones will be automatically unloaded. If your memory allowance is very critical you might want to avoid the cross fading by fading out the first song then begin playing the second song later.

    Also please note that I haven't test on the 3DS as I don't have the dev kit. I once test on the WebGL build and there is a problem that web platform does not support any _Scheduled_ methods at all, I don't think that is the case with 3DS but there might be a similar problem of unsupported method that Unity team have not yet implement. In the case that it really does not work please inform me (and you can also issue a refund). Thank you.
     
    Last edited: Oct 27, 2017
    Fallenleader likes this.
  19. Fallenleader

    Fallenleader

    Joined:
    Jan 26, 2015
    Posts:
    7
    Please don't get me wrong. I bought this for more platforms than the 3DS ;)
    I eventually plan to learn how dspTime, SetScheduledStartTime, SetScheduledEndTime, and PlayScheduled works for the sake of being thorough, but this tool is still quite useful.
    This is why I said that the only reason I went ahead and bought it despite not being sure about 3DS support is I will definitely utilize it on other platforms. I am quite sure you have extensively tested it on PC and Android if nothing else, and as many users as you have, I am sure all Unity free platforms are tested, if not other systems that require devnet access (e.g. Playstation, Xbox, Nintendo, etc).
    I have seen enough to be impressed. I can easily make a quick test as soon as possible to find out for you.

    On another note, does this have pause and resume support? How does oneshot SFX sounds work?
     
  20. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    Introloop can pause and resume! You can try the free demo in the website http://exceed7.com/introloop/ the last 3 colored button can demonstrate the function.

    The limitation is that if you issued Stop, currently there is no way to start at any other point besides the beginning. I planned to make it so that you can specify a time to start the song, that also take account of the looping function. (For example a song with 1s intro and 4s looping part, if you call PlayFrom(5) you would begin at the intro boundary because 5s means it have already looped 1 time.)

    For oneshot SFX, Introloop is not designed to play SFX. You can instead use a normal PlayOneShot(). (I am not sure if I misunderstood something, as "SFX" is not supposed to be looping or has an intro?) Introloop is not a complete audio management as opposed solutions like Master Audio, SoundManagerPro etc. that aims to be all-in-one. Introloop is just a tool that you can use just for the BGM part of your game.
     
    Last edited: Nov 8, 2017
  21. castor76

    castor76

    Joined:
    Dec 5, 2011
    Posts:
    2,517
    Hello.

    I am enjoying IntroLoop. But I recently came to some question about how it is able to accurately loop the music.

    As I understand Unity Update API will respond only as quickly as the next frame update. So if the looping time falls in between each frame draw call (aka in between update call) how do you handle such looping case smoothly? Do you internally split the music clip asset into 2 different parts?
     
  22. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    Hello, thank you for using Introloop.

    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 (https://docs.unity3d.com/ScriptReference/AudioSettings-dspTime.html).

    There are 3 methods that utilize this, AudioSource.PlayScheduled, SetScheduledStartTime, and 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.
     
  23. MetaMythril

    MetaMythril

    Joined:
    May 5, 2010
    Posts:
    150
    @5argon Hi! I just wanted to share an issue I had that I was able to fix.

    In IntroloopPlayer.FadeUpdate() you use Time.deltaTime to fade volumes but this causes functions like Pause() to stop working for me when my game did something that caused Time.timeScale to be set to 0 (effectively pausing the game).

    Changing the use of Time.deltaTime to Time.unscaledDeltaTime fixed my issue and now I'm able to pause and resume music even if the timeScale is at 0.

    My justification for this is for things like when a player acquires a new weapon or item and a jingle melody plays (like in Super Metroid). I needed to pause the currently playing track so I could play the jingle on a separate AudioSource (not connected to IntroloopPlayer) since it's just a one-off sound. I needed to "pause" the game when the notification window and jingle is displayed, then promptly resume once window was dismissed.

    Would you consider making this fix permanent?
     
  24. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    Sorry for the long absent,

    Yes I have overlooked this case, this is definitely a problem. Audio should not be related to game's time scale by definition in most case. Thank you for reporting.

    I will include this fix in the next update along with a new feature, that is allowing you to subclass IntroloopPlayer and thus able to make a specialized Play method tailored for your game, (e.g. EventMusicPlayer.Get.PlayRelaxed()) or having multiple instances running at the same time. (e.g. BGMPlayer.Get.PlayField(); AmbientPlayer.Get.PlayWindy(); )
     
    MetaMythril likes this.
  25. Marrt

    Marrt

    Joined:
    Feb 7, 2012
    Posts:
    613
    Hi, i can't believe this is still not part of vanilla Unity.

    Is this plugin suitable for:
    - short sounds? like machine-gun-loops with a fadeout-echo after the last shot is fired
    - mobile? I plan to have at least two of such machine-gun-audiosources active at the same time plus a seamlessly looping background track. Would this compromise performance compared to the normal AudioSource?

    Thanks!
     
  26. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    Hello Marrt, (I can't believe it too)

    1. Introloop was not designed for sound effects but it should work with short sound. However the situation you described cannot be achieved by Introloop. Introloop adds intro but you wants to add a unique outro. What Introloop can do for you is have a machine gun with startup sound (as an intro) then enters a loop part. When you stop firing, you could tell Introloop to stop then play an additional fade out sound you have. (This part is not related to Introloop and you can use a regular AudioSource, or also Introloop)

    For that kind of behavioral sound I think things like WWISE or fmod is the correct tool for this job. You can set your entire project's sound effect to have various behavior. You can even have just one shot sound (not a loop) one rev up sound and one wind down sound and program fmod to play rev up -> one shot repeatedly (+with variations) -> wind down when asked to. Plus all the settings are separated from the project, so you could have someone else design the sound without touching Unity. Beware of a latency problem, in fmod I have tested and the latency seems to be about Unity's "Default" or "Good Latency". There might be a setting that enable fmod to match Unity's "Best Latency" but I stopped using fmod since long time ago.

    Ps. I am actually making a WWISE/fmod-like tool that works in Unity and manage your sound effects + program it's behavior like what I described and directly solve your problem. But it will be very long way to go until it finishes that you should not wait for it. (I won't release it until I see it working fine in my new game, which is also far from finish)

    2. Introloop was made originally for mobile use but it works in a standalone also. (It does not work on WebGL) Theoretically Introloop is 4 AudioSources working together. (There is a detailed explanation in http://exceed7.com/introloop/faq.html) So strictly speaking the compromise is +3 AudioSource. However from my experience from my own game (iOS/Android game) 3 more AudioSources does not cause any noticable performance loss. There is no additional cost of memory usage since all 4 AudioSources uses the same audio in the memory. The only point is that when you crossfade songs you will have 2 audio in memory for a short time before the old one automatically unload itself when completely faded out.
     
    Last edited: Mar 30, 2018
    Marrt likes this.
  27. Fallenleader

    Fallenleader

    Joined:
    Jan 26, 2015
    Posts:
    7
    I would like to report back on using Introloop on the 3DS.
    Sadly, I haven't had much luck. This isn't so much due to introloop itself failing, as DSP issues from what I can gather (though this side of development is honestly not my strength). The scheduled audio when played together for the looping part will heavily desync, making this tool not an option for that platform unfortunately.

    I would appreciate further correspondence, maybe even a more idiot friendly solution using a single script, as I can easily split my audio, but currently cannot avoid that glitch of silence when swapping an intro to a looping song. This also adds the additional headache of multiple files, and probably more overhead I am not thinking about right off hand.

    For other platforms, this tool has been invaluable, and despite my initial skepticism, I am extremely content. Cheap but effective. This tool could easily sell for way more than you list, but you chose not to price gouge consumers, and unlike many other assets I have seen, provide active feedback!
     
    5argon likes this.
  28. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    Thank you!

    If all the __Schedule method is not working precisely then we don't have much option because it is the most precise one. But if the problem is only with `dspTime` then it might be possible to schedule with a normal coroutine. (yield return new WaitForSeconds(___)) But still the time will not be precise because it is frame-dependent. It will resume at the first frame after that wait time and I think it won't be seamless enough. I guess it is the same with `MonoBehavior.Invoke`. If you can put up with frame-level seams (That would be around 1/30s ~ 1/60s depending on your frame rate) it might be enough.

    Or you could employ a cross-fade trick and try to blend between 2 clips. I have done it with ambient sounds before because it would blend easier (around Unity 4 era) but it caused many bugs when the game pause, entering cutscenes, time slowdown, etc. (It actually leads to me creating Introloop to based on Scheduled method more than a year later, when I saw Unity 5 can defer loading audio and manually unloads audio.)

    I would like a 3DS to test, but honestly I am heavily interested in Nintendo Switch for my next game!
     
  29. Fallenleader

    Fallenleader

    Joined:
    Jan 26, 2015
    Posts:
    7
    3DS is relatively easy to work with, assuming you have a spare one you can mod, and a bit of patience.
    Granted, you are confined to 2 rules of thumb:
    1: Developing outside of a dev/testkit means final products would involve purchasing an actual testkit before considering submission (that should be clearly evident), and it technically breaks ToS, so speak no evil, get no ban hammer. Development rules apply regardless if you convert the output or not. if you run into an issue, the tools to dump debug logs work all the same. A CFW unit for developing is basically a slightly limited testkit that can play retail games.
    2: Builds require you to manually convert them to work on the retail unit. This can present the possibility of bugs that normally wouldn't exist (I have had no issues so far). It is straightforward to do, but becomes a tedious chore if you say forget a single line of code, as you have to compile, convert, and reinstall each time, rather than do a signle compile and install for the testkit.

    Testkits are easily obtainable for only a margin more than an actual NEW retail unit, though you can also get a used retail Old 2DS (unadvised due to memory limitations) or even a used New 2DS for fairly cheap, and modding it is actually easy enough if you know how to read directions. Only thing you lack is 3D, and you sacrifice the ability to immediately submit your game, as well as gain the minor headaches I mentioned before. It boils down to cost vs usage.

    Also, Nintendo is doing Switch units/access on a case by case basis. While I have a game fairly well along in development, I was rejected on my request. YMMV. I am honestly eager to get my hands on my own switch testkit to start porting to, so I have been putting my retail 3DS to use in the meantime while I save up for when I am able to get my switch unit. If I complete my game if/before Switch becomes openly available, I will get myself a 3DS testkit to make sure everything is ready, and release a 3DS version for more leverage for a Switch.
     
    5argon likes this.
  30. KOemxe

    KOemxe

    Joined:
    May 1, 2018
    Posts:
    35
    Hi @5argon !

    Thanks very much for writing what you have with this. I have enjoyed your InterLoop audio library so far.

    One issue. I've been playing with this to figure out how to loop music consistently between levels until you reach the end menu in the build list of scenes. I've been trying to use a counter as a static instance outside of my Game Manager that plays the tracks, but it seems that the Awake method spawns a new instance of InterLoop each level? In this case, it seems more copies of my audio track try to play at the same time, causing some sound conflicts.

    Would you have some insight in how to handle this issue?

    Code (CSharp):
    1. public class GameManagement : MonoBehaviour {
    2.  
    3.     bool gameHasEnded = false;
    4.  
    5.     public float restartDelay = 1f;
    6.  
    7.     public GameObject completeLevelUI;
    8.  
    9.     public IntroloopAudio IntroloopAudio;
    10.  
    11.     void Awake()
    12.     {
    13.         Debug.Log("There are ");
    14.         Debug.Log("Count is " + LoadCounter.GameLoadedCounter);
    15.         //Debug.Log("StartCount is " + PlayerPrefs.GetInt("StartCount"));
    16.         if (LoadCounter.GameLoadedCounter == 0)
    17.         {
    18.             //IntroloopPlayer.FindObjectsOfType(this.IntroloopPlayer.Instance);
    19.             Debug.Log("Playing music, should be first time");
    20.             play(0);
    21.             //LoadCounter.GameLoadedCounter++;
    22.         }
    23.         LoadCounter.GameLoadedCounter++;
    24.         //PlayerPrefs.SetInt("StartCount", startCount);
    25.         Debug.Log("Counted up to " + LoadCounter.GameLoadedCounter);
    26.         //Destroy(this);
    27.     }
    28.  
    29.     public void play(int var)
    30.     {
    31.         IntroloopPlayer.Instance.Play(IntroloopAudio);
    32.     }
    33.  
    34.     public void CompleteLevel ()
    35.     {
    36.         Debug.Log(SceneManager.GetActiveScene().buildIndex);
    37.         Debug.Log("Out of: " + SceneManager.sceneCountInBuildSettings);
    38.         if ((SceneManager.GetActiveScene().buildIndex + 1) == SceneManager.sceneCountInBuildSettings -1)
    39.         {
    40.             //IntroloopPlayer.Instance.StopFade();
    41.             // play(1);
    42.             completeLevelUI.SetActive(true);
    43.         }
    44.         else
    45.         {
    46.             completeLevelUI.SetActive(true);
    47.         }
    48.     }
    49.  
    50.     public void EndGame()
    51.     {
    52.         if (gameHasEnded == false)
    53.         {
    54.             gameHasEnded = true;
    55.             Debug.Log("Game Over");
    56.             Invoke("Restart", restartDelay);
    57.         }
    58.  
    59.     }
    60.  
    61.     void Restart()
    62.     {
    63.         IntroloopPlayer.Instance.Pause();
    64.             SceneManager.LoadScene(SceneManager.GetActiveScene().name);
    65.         IntroloopPlayer.Instance.Resume();
    66.     }
    67.  
    68. }
    Let me know your thoughts! I think this has been a good exercise in trying to flex on instantiation and perhaps encapsulation, but I figured you might see something that was under my nose.
     
  31. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    Hello @KOemxe,

    This is strange, because `IntroloopPlayer` gets `DontDestroyOnLoad` on its `Awake` (See IntroloopPlayer.cs). When the sound plays for the first time in your Hierarchy view did IntroloopPlayer game object resides in "DontDestroyOnLoad" Unity generated scene like this?

    Screenshot 2018-05-01 11.19.48.png

    Because everything in this scene won't be destroyed even with LoadSceneMode.Single, and then the next time you play sound it should be able to find this instance. (See IntroloopPlayer.cs > public static IntroloopPlayer Instance {... )

    Can you try going to the provided IntroloopDemo scene, then modify the code at `Awake()` adding :

    Code (CSharp):
    1. playButtons[0].onClick.Invoke();
    And then at `Update()` adds :

    Code (CSharp):
    1.         if(Input.GetKeyDown(KeyCode.P))
    2.         {
    3.             UnityEngine.SceneManagement.SceneManager.LoadScene("IntroloopDemo");
    4.         }
    So that the song plays immediately on scene load, then you can press P repeatedly to reload the same scene. Did `IntroloopPlayer` game object multiplies itself? In my case it doesn't, so from here you might be able to track down the problem by comparing the difference of this demo scene from your game.

    I will try to think of other ways that cause this problem.
     
    Last edited: May 1, 2018
  32. KOemxe

    KOemxe

    Joined:
    May 1, 2018
    Posts:
    35
    Hi @5argon , maybe I didn't look hard enough but... link to the demo project so I can test this?

    It DOES seem that the "DontDestroyOnLoad" only occurs after the first restart...
     
    Last edited: May 2, 2018
  33. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    The demo project is a scene in a `Demo` folder. It is provided along with other plugin's script. It is at "Introloop/Demo/IntroloopDemo"

    If you double click that scene file and enter play mode, did the "DontDestroyOnLoad" occur immediately? (No restart)
     
  34. KOemxe

    KOemxe

    Joined:
    May 1, 2018
    Posts:
    35
    Hi 5argon,

    I can't find the Awake() method in any of your scripts in the demo scene. Is it Start() in this case?
     
  35. KOemxe

    KOemxe

    Joined:
    May 1, 2018
    Posts:
    35
    Is the problem that I'm calling the IntroLoop player from a destroyable object like my GameManagement class? I wouldn't mind zipping up the project so that you can look if you're interested.
     
  36. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    Sorry my bad, there is no Awake method. What I meant is you can try to define Awake and put some audio playing in there. When you enter the scene you should hear the song immediately, then try to press P to reload the scene. In my case `IntroloopPlayer` get DontDestroyOnLoad from the first time the scene was loaded.

    That would be the best way for me to help you! I can look at it as soon as you send me the project. (Please remove any sensitive information if you have)
     
  37. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    Great news, after a long time finally Introloop v3.0 is coming soon, now in the testing phase against my own game.

    Screenshot 2018-05-03 16.32.07.png

    Highlight includes :

    - Multiple Introloop singleton playing at the same time by subclassing : You could have MyBGMPlayer.Get.PlayBattleTheme() + MyAmbientPlayer.Get.PlayWindy() instead of IntroloopPlayer.Instance.Play(battleTheme) without the wind. Each subclass could use its own template prefab so you can pre-connect things or route mixers before runtime.

    There is a new demo scene demonstrating this function. You can play 2 IntroloopAudio, one using `IntroloopPlayer.Instance` and an another using your subclass. Each one use its own template prefab in the Resources folder. (Match by class name)

    Screenshot 2018-05-03 17.04.59.png

    - Local Introloop : GetComponent<IntroloopAudio>() that you have attached somewhere in the scene and everything works. You can also .AddComponent<IntroloopAudio>() and the next frame it will be ready to play. Local Introloop does not automatically get `DontDestroyOnLoad` unlike the static-singleton `IntroloopPlayer.Instance` or the new `Subclass.Get`

    - Positional Introloop : The point of having local Introloop is you could have it positioned meaningfully. Imagine you have 10 bushes with its own seamlessly looping leaf sound. You can have Introloop in each bush and as you approach it will get louder. There are many additional methods to help you setup audio source spatial curve to an IntroloopPlayer.

    (Positional Introloop was inspired by an e-mail from one of my user. If you have any other use case which is not covered yet by Introloop please do not hesitate to e-mail me or post here!)

    A new demo scene demonstrating the positional function is also available.

    Screenshot 2018-05-03 16.37.43.png

    On a related note, Introloop is on sale right now as a part of Unity's annual May Madness Sale. (I highly recommend getting I2Localization and Odin Inspector too while you have the chance. They are so good I want to advertise it for free. Haha)
     
    Last edited: May 3, 2018
  38. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    It's been a year since the last update. Thank you for all your supports so far!
    As per SemVer, big version change introduce breaking changes.

    The website http://exceed7.com/introloop/index.html and store images https://www.assetstore.unity3d.com/#!/content/51095 has been renewed throughout.

    [4.0.0]


    Known issues

    Do not use
    AudioListener.pause
    to pause, the documentation said that it would preserve scheduling status, but what I found is that sometimes it deletes
    PlaySchedule
    on coming back from pause. I have submitted as a bug report which you could track here if it was resolved or not. If possible, stop completely and resume by playing anew with the new
    startTime
    parameter.

    Added
    Unity Package Manager & Assembly Definition File
    The package has been conformed to the recent Unity practice of putting
    packages.json
    and properly using
    asmdef
    file. In the future when Asset Store became integrated with UPM, Introloop is now ready for that.

    This also allows you to put the Introloop package outside your Unity project, instead anywhere in your harddisk, then use the local UPM feature to share a single Introloop sources over multiple projects, thanks to
    packages.json
    file.

    This is a breaking change if you are also using
    asmdef
    file, because you now have to link up your
    asmdef
    with Introloop's
    E7.Introloop
    .

    The assembly definitions will also prevents scripts in the intro scene from getting into your game as well, since you could link to only
    E7.Introloop
    and not
    E7.Introloop.Demo
    . In the future when incremental compiler works better and we could enter play mode without assembly reload, this would help your game even more.

    Script icons added

    Icon_IntroloopAudio.png Icon_IntroloopPlayer.png

    Screenshot 2019-05-05 02.33.51.png

    IntroloopAudio
    icon is provided so you could discern them from other
    ScriptableObject
    files.

    IntroloopPlayer
    icon is also added, which could show up in the scene since it is a
    MonoBehaviour
    . If you don't like this, you can click on "Gizmos" in your Scene tab, and then left click on the icon image, not on the little arrow or the checkbox. It will be greyed out and disappear from the scene view.

    An Affinity Designer project files are even included, so you could modify some part of the icon if you don't like them!

    startTime
    optional parameter added to
    IntroloopPlayer.Play

    This is one of the most requested feature. You are now able to specify start time when starting introloop audio.

    The time you specify here is called "playhead time". Since
    IntroloopAudio
    conceptually has infinite length, any number that is over looping boundary will be wrapped over to the intro boundary in the calculation.

    In effect, you can never specify start time so that it starts after looping boundary.

    GetPlayheadTime()
    added to
    IntroloopPlayer

    You can also ask the currently playing
    IntroloopPlayer
    the "playhead time". This is not accumulated, the time could decrease when it goes over looping boundary back to intro boundary. So you better visualize it as an actual playhead that jumps back on loop.

    This number is usable with the new start time option. Together, you can implement something like remembering field music time and enter battle scene with an another Introloop music completely replaced the field music. When you come back, you can use the remembered "playhead time" to start the field music from the same place. It is a good idea to start from the beginning if the player had passed through some "check point" like a cutscene or entered town, otherwise continue with the playhead time.

    Changed
    IntroloopSettings
    is now the field of
    IntroloopPlayer
    rather than a separated component

    That was a stupid design, but I was afraid to let that go.

    It will cause missing script on your prefab template in your
    Resources/Introloop/
    folder, please go remove the missing component which was
    IntroloopSettings
    and assign those values in
    IntroloopPlayer
    instead. Luckily the values are just a mixer and fade time, but sorry for inconvenience.

    A bit of prepare time added to immediate Play() method
    Theoretically playing "instantly" is impossible, even though we want it to play "right now" on calling
    IntroloopPlayer.Play()
    . So this time is the near-instant future that we told the scheduling method to start. With this, it could get better chance that the first loop is accurate at the expense of some waiting time.

    (But Introloop was never meant to be a low latency solution, for that please search for Native Audio.)

    Previously, you could randomly get a bit off first loop depending on whether it could fulfill this "right now" or not. You notice that usually all loops except the first one are accurate, that's because it got time far into the future as a schedule, unlike the first play.

    The default number
    0.02f
    is choosen to be a bit more that 16ms, the time per 1 frame on 60 FPS. So that it could get through a busy frame.

    Removed
    Default fade length removed from
    IntroloopSettings

    I have decided that default fade length should be something coming from your game, rather than the task of Introloop. Along with this...

    All
    _Fade
    variants of
    Play
    ,
    Stop
    ,
    Pause
    ,
    Resume
    removed

    There is now just 1 version of each. Now the normal version handles fade by using the optional fade parameter. Enter 0 or not using the parameter to get the usual "pop removal fade length". If you use negative number, the action is immediate without pop removal fade length.

    If you was using default fade length with
    Fade
    variants, make your own default fade length variable coming from the game and input it into the fade parameter of each method.

    Dropped support for Unity 5.5.6 and 5.6.5
    I used to maintain support far back to those versions. It's time to move on! Even though nothing prevents Introloop from working on those versions, project downgrading is getting more and more difficult.

    The new support ranges is as follows : Oldest version in Unity Hub, latest LTS version, latest TECH version, and latest beta version will be tested. As of current, they are : 2017.1.5f1, 2017.4.26f1, 2018.3.14f1, 2019.1.1f1.

    Fixed
    Streaming load type is now much more accurate when used with Introloop
    The mentioned prepare time is the final key to use
    Streaming
    audio load type with Introloop! Because streaming audio size is technically so small that it tries to start instantly, it conflicts with the scheduled start time that is too immediate to fulfill. I observed that with this small delay,
    Streaming
    audio's first loop became much more reliable. Took me long enough to figure this one out. Now, enjoy your memory-conscious introlooped music.

    Suppressed unassigned variables warnings
    I put
    pragma warning disable 0649
    on several places. No idea how I didn't think of doing this before after all these years. (Sorry)

    Code documentation + website improved
    I have rewritten everything, and also some XML tag that links code references together are added.
     
  39. SakamotoRyu

    SakamotoRyu

    Joined:
    Apr 15, 2017
    Posts:
    5
    はじめまして。坂本龍と申します。日本語OKとのことなので、日本語で質問いたします。
    Introloopを2018年1月24日から使用しておりますが、Unityを2018.4.3f1から2019.1.9f1にアップデートし、それに合わせてIntroloopを3.xから4.0.0にアップデートしました。すると、下記の3つのエラーが発生しました。

    Assets\Introloop\Runtime\IntroloopPlayerAbstract.cs(11,48): error CS0305: Using the generic type 'IntroloopPlayer<T>' requires 1 type arguments
    Assets\Introloop\Runtime\IntroloopPlayerAbstract.cs(11,74): error CS0305: Using the generic type 'IntroloopPlayer<T>' requires 1 type arguments
    Assets\Introloop\Runtime\IntroloopPlayerAbstract.cs(14, 33): error CS0115: 'IntroloopPlayer<T>.IsIntroloopSubclass': no suitable method found to override

    環境は下記の通りです。
    Windows 7
    Unity 2019.1.9f1
    Microsoft Visual Studio Community 2017 Version 15.9.14
    Microsoft .NET Framework Version 4.7.03062z

    対応をよろしくお願いします。
     

    Attached Files:

  40. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    はじめまして! 日本語はほぼだけ出来るですが頑張ります

    さっきに 2019.1.9 に試したですが問題なしでした.. おそらくコンパイルしたスクリップの残ったキャッシュの問題と思います。(「IntroloopPlayer<T>」 Genericクラスが 「IntroloopPlayer」 Genericではないなのと同じクラス名でコンパイラを混乱させるかも.. )

    Screenshot 2019-07-12 16.09.48.png

    まずは Introloop の asmdef を reimport してみようか、

    Screenshot 2019-07-12 16.11.36.png

    解決していませんなら、Library/ScriptAssemblies を全て削除してみてください。

    Screenshot 2019-07-12 16.13.31.png

    それ以外、4.0.0 には「IntroloopSettings」というコンポーネントクラスが消しましたので、Resources/Introloop/IntroloopPlayer のprefabに一つのmissing componentがあると思います。今は「IntroloopPlayer」だけが必要なのであのmissing componentを削除してokです

    Screenshot 2019-07-12 16.24.04.png
     
    Last edited: Jul 12, 2019
    SakamotoRyu likes this.
  41. SakamotoRyu

    SakamotoRyu

    Joined:
    Apr 15, 2017
    Posts:
    5
    素早い対応ありがとうございます。Introloop/Scriptsフォルダや、IntroloopSettings.csが残っていたので、それを削除しました。また、Resources/Introloop/IntroloopPlayerのmissing componentを削除しました。すると、すべてのエラーが解決しました。ありがとうございました。
     
    5argon likes this.
  42. SakamotoRyu

    SakamotoRyu

    Joined:
    Apr 15, 2017
    Posts:
    5
    不具合を報告します。Time.timeScaleが0のとき、音楽が正常にループしないことがあるようです。IntroloopTrack.csの465行目と474行目でTime.timeが使われていますが、これが原因だと思います。これをTime.unscaledTimeに変更すべきだと思います。また、音楽が効果音よりも優先されるようにするために、AudioSourceのPriorityを0にすべきだと思います。
     
  43. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    ご意見ありがとうございます。自分のゲームは timeScale 0と1しかないので見落としてしまった。
    Priorityの方はIntroloopTrack.csのAwakeにそれを追加していいです:

    Code (CSharp):
    1.  
    2.             as1.priority = 0;
    3.             as2.priority = 0;
    4.  
    次のバーションにこの修正を含めます。
     
    SakamotoRyu likes this.
  44. SakamotoRyu

    SakamotoRyu

    Joined:
    Apr 15, 2017
    Posts:
    5
    すみません。私はIntroloop4.0.0を改造し、Time.timeをTime.unscaledTimeに変更しました。しかし、Time.timeScaleを0にした状態で、ゲームを非アクティブにしてしばらくしてからゲームを再開すると、音楽が途切れることがあります。
    私はこのバグの原因をこのように考えます。
    ・Time.timeは、Time.timeScaleが0のときもゲームが非アクティブのときも停止します。
    ・Time.unscaledTimeは、Time.timeScaleが0のときもゲームが非アクティブのときも進行します。
    ・音楽は、timeScaleが0のときは進行しますが、ゲームが非アクティブのときは停止します。(Project SettingsのRun In Backgroundがオンのときは、非アクティブでも再生されつづけます。)
    これらの齟齬によってバグが発生していると思います。音楽の再生と同期した時間の計測法はありませんか?
     
  45. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    あ、このバグ分かります。事実はUnity 2019.1+ 特定のバグでした (2018.4 なら問題なし)

    SetScheduledEndTime した AudioSource はこちらの条件でスケジュールが勝手に消えます :

    - AudioListener.pause = true そして false
    - ゲームを minimize または他のアプリに切り替え (例えゲームにレビューしてくださいボタンを押してApp Storeに行く) = ゲームが非アクティブ
    - Editor内ならポースボタン (プレイの隣なの) を使う

    そして timeScale と関係ないです (1でも発生します)

    サンプルシーンでもこのバグを再生できます。2回目のループがスケジュールした時 (Source1 debugのテキストが PLAYING/SCHEDULEDになる時) ポースボタンを2回押して、2019.1ならSTOPPEDになる しかし2018.4ならPLAYING/SCHEDULED状態が保存されます

    ケースのページはこちらです : https://fogbugz.unity3d.com/default.asp?1151637_4i53coq9v07qctp1
    しかし2ヶ月ほどが経ってまだ直りされなかった..

    今の回避策は OnApplicationPause でIntroloopをPause - Resumeしてください。

    _____

    For English speakers :

    2019.1 has a big bug about SetScheduledEndTime. When you make the game inactive via AudioListener.pause or minimizing/switching away the game, the schedule will disappear and it will cause Introloop to cut off on the next audio stitch. It is even reproducable with a pause button in-Editor. 2019.1 actually has an audio engine upgrade under the hood in preparation for DOTS Audio, I think that is the cause.

    If you use 2018.4 this bug does not exist.

    I have already reported this https://fogbugz.unity3d.com/default.asp?1151637_4i53coq9v07qctp1 but it's been 2 months without a fix. I could do nothing about this. (It affects all games that used SetScheduledEndTime)

    But there is a workaround, that is you should pause/resume the introloop source on going inactive and coming back to active, since resuming in Introloop means rescheduling and it does not matter if the schedule disappeared or not. If it is an app switch, you can use OnApplicationPause to create an opportunity to pause/resume.
     
    Last edited: Jul 28, 2019
    SakamotoRyu likes this.
  46. EdFear

    EdFear

    Joined:
    Jun 5, 2009
    Posts:
    4
    Hi there! I'm interested in licensing this, but have a question first:

    Is it possible to specify the loop points in sample #s rather than time?
    We need very precise playback and I'm a little concerned that converting the sample number into a (less accurate) time will cause issues, and we're on such an aggressive schedule that I don't think we're going to have the time to manually test and adjust the 'IntroLoop-specific' loop points when we already have accurate sample-based loop points from our composer.

    Thanks!
    Ed
     
  47. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    Hi, Introloop used seconds and not samples. These are the reasons :

    - The core method of Unity that make everything works cross-platform : PlayScheduled, SetScheduledStartTime and SetScheduledEndTime all uses time in seconds. So, I would like to make it so that what you entered is directly feeded to these methods.

    - Sample-as-position is not stable as it depends on your audio's sampling rate. And in Unity, one could freely override, preserve, or optimize sampling rate in the import settings. (I don't know if there are other criteria that Unity changes your sampling rate, but Android for example mysteriously uses 24000Hz audio source) If you use sample, then it will be off if for some reason you or Unity change/optimize the rate. Time unit is more resilience to change.

    Theoretically I could write a convertor that turns sample to seconds while checking the audio's sampling rate, but it is not here currently. If you don't mind converting sample unit to seconds manually, you can calculate :

    Point in time = Which sample / Sampling Rate

    For example if your boundary is at sample no. 88200, on a music that was sampled at 44100Hz (44100 samples per one second) the answer is you are currently at second : 88200/44100 = 2.

    I understand that time in sample is dead-accurate, but it is still up to the performance of Unity's schedule methods that used seconds. And we don't know what Unity do to that seconds under the hood, which may be different per platform. The reason why Unity used seconds is likely that it is flexible, so for platform that supports sample-accurate scheduling Unity may convert it to samples. (A guess, since I don't know Unity's C++ source)

    (I know Android native could do sample-based scheduling if you go as deep as OpenSL ES level because you are in control of each bytes pushed out, but Introloop is not a native-interfacing plugin so we are stuck with Unity's second accuracy.)
     
  48. EdFear

    EdFear

    Joined:
    Jun 5, 2009
    Posts:
    4
    Got you - thanks very much for the explanation, really appreciate it!
     
  49. SakamotoRyu

    SakamotoRyu

    Joined:
    Apr 15, 2017
    Posts:
    5
    ありがとうございます。timeScaleとは関係なく、Unity2019.1のバグだったんですね。回避策まで教えてくださり、本当に助かりました。
     
  50. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    New version 4.1.0 is now released. This is especially important for 2019.1+ users because that version has a bug and this has a built-in fix.

    [4.1.0] - 2019-08-15

    Added
    Seek(elapsedTime)
    This new method internally implemented as calling Play with custom startTime. Except that you do not need to specify which audio because it remembered your previous audio. Also it only works if the state is playing. From the outside, it looks like you are "seeking" the playhead.

    Introloop naturally has infinite timeline. The time specified here is instead an elapsed time, Introloop will make the current position like you have played by this amount of time, according to your loop boundaries.

    It is added as a part of 2019.1+ hack to fix Unity bug, which requires remembering the audio and play again. But I guess it may be handy, so I decided to make it public.

    Dirty hack to fix 2019.1+ bug added into all IntroloopPlayer
    There is a bug in 2019.1+ where on game minimize, on pressing pause button in editor, or pausing AudioListener, all ScheduledEndTime will be lost. I confirmed it is not a problem in 2018.4 LTS. And it obviously affects Introloop.

    There is an OnApplicationPause(bool) added to IntroloopPlayer to fix this while waiting for Unity team to address the bug for real. I have reported since 2019.1 release, as of now that 2019.2 has been released plus the old version is at 2019.1.14f1, it was not fixed yet. I think I couldn't wait for another half a year, so I decided to bake the workaround into the code.

    The ideal fix is to call Pause just before the game goes to minimize then Resume after we comeback to reschedule. However at OnApplicationPause, Pause does not work, as all audio are already on its way to pausing. (Introloop need to see which one is playing to resume correctly.)

    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. This hack does that, using the new Seek added in this same update, and it is wrapped in #if UNITY_2019_1_OR_NEWER. Also, OnApplicationPause do not get called in editor when pressing pause button (near the play mode button) so you will still experience this bug in the editor. In real device it should take care of the bug.

    Track that bug : https://fogbugz.unity3d.com/default.asp?1151637_4i53coq9v07qctp1

    Changed
    Pause and Stop overloads changed to be able to take action in the same frame
    • Previous behaviour : Pause() or Stop() without any fade time specified will results in a small pop removal fade time added to reduce harsh noise when pausing.
    • Previous behaviour : Pause(-1) or Stop(-1) with negative fade time results in 0 fade time, however it needs at least the next frame to actually pause or stop since it uses the same routine as the one with fade time.
    • Previous behaviour : Pause(0) or Stop(0) with zero fade time will results in a small pop removal fade time added to reduce harsh noise when pausing.
    • Previous behaviour : Pause(555) or Stop(555) with positive fade time will fade to pause or fade to stop as expected.
    There is a problem that no matter what you cannot stop an audio in the same frame that you tell it to. This may cause problem in some situation where you want to free up memory and cannot wait any frame.

    • New behaviour : Pause() or Stop() without any fade time specified enters a special routine that instantly pause or stop in the same frame.
    • New behaviour : Pause(-1) or Stop(-1) with negative fade time enters a special routine that instantly pause or stop in the same frame.
    • New behaviour : Pause(0) or Stop(0) with zero fade time will results in a small pop removal fade time added to reduce harsh noise when pausing. (unchanged)
    • New behaviour : Pause(555) or Stop(555) with positive fade time will fade to pause or fade to stop as expected. (unchanged)
    To use the old pop removal fade time pause or stop, now the only way is that you have to use the overload with fade time, but instead input 0. It means you wants "virtually no fade" but also you don't want a noise problem. It is now a little different from the overload without any argument which do it instantly.

    Fixed
    • Priority of audio sources generated are now 0 (the highest). Since it is very likely that you do not want any other sound effects to cut off the music when virtual audio sources run out.
    • Time method used inside IntroloopTrack.cs was Time.time. It is now Time.unscaledTime so it could accommodate games with dynamically scaled time.

    @SakamotoRyu 前の対策について OnApplicationPauseに事実は IntroloopPlayer.Pause が使用出来ませんでした (その瞬間は AudioSourceがすでにpauseになっていますので) だから戻る時に IntroloopAudio.Resumeが効果なしくて、バグが直されません。

    代わりに IntroloopPlayer.GetPlayheadTime -> IntroloopPlayer.Play( 前のIntroloopAudio, 覚えた playhead time) がバグを対策できます。

    そして4.1.0にこのバグの対策は IntroloopPlayer のコードに組み込んで(下のコード)、何もしてなくて普通にこのバグを回避するはずです。アップデートしてみてください。

    Code (CSharp):
    1. #if UNITY_2019_1_OR_NEWER
    2.         private float timeBeforePause;
    3.         /// <summary>
    4.         /// This is a dirty workaround for the bug in 2019.1+ where on game minimize or AudioListener pause,
    5.         /// All ScheduledEndTime will be lost. I confirmed it is not a problem in 2018.4 LTS.
    6.         ///
    7.         /// The ideal fix is to call Pause just before the game goes to minimize then Resume after we comeback to reschedule.
    8.         /// However at this callback Pause does not work, as all audio are already on its way to pausing.
    9.         ///
    10.         /// So an another approach is that we will remember the time just before the pause, and the play again
    11.         /// after coming back using that time. The Seek method can be used instead of Play here so you don't have to specify the
    12.         /// previous audio.
    13.         ///
    14.         /// Please see : https://forum.unity.com/threads/introloop-easily-play-looping-music-with-intro-section-v4-0-0-2019.378370/#post-4793741
    15.         /// Track the case here : https://fogbugz.unity3d.com/default.asp?1151637_4i53coq9v07qctp1
    16.         /// </summary>
    17.         public void OnApplicationPause(bool paused)
    18.         {
    19.             if (paused)
    20.             {
    21.                 timeBeforePause = this.GetPlayheadTime();
    22.             }
    23.             else
    24.             {
    25.                 this.Seek(timeBeforePause);
    26.             }
    27.         }
    28. #endif
     
    Last edited: Aug 13, 2019