Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Join us on Dec 8, 2022, between 7 am & 7 pm EST, in the DOTS Dev Blitz Day 2022 - Q&A forum, Discord, and Unity3D Subreddit to learn more about DOTS directly from the Unity Developers.
    Dismiss Notice
  3. Have a look at our Games Focus blog post series which will show what Unity is doing for all game developers – now, next year, and in the future.
    Dismiss Notice

how do I immediately play a new audioclip without delay(code included)?

Discussion in 'Audio & Video' started by simpson45711, Dec 2, 2014.

  1. simpson45711

    simpson45711

    Joined:
    Mar 16, 2013
    Posts:
    18
    I currently have 2 Background music audio clips which I want to play immediately one after another (intro followed by a loop when the intro is done playing).

    However, no matter what I try, there seems to me a noticeable gap(especially on mobiles) when transitioning from one track to an other... Is there any way around this (other than crossfading)

    Both my audio clips are set to 'stream from source' in import settings
    Below is what I have come up with so far:::

    Code (CSharp):
    1.     ///////////////////////////////////////////////////////////
    2.     private static bool loopStarted = false;
    3.     public AudioClip backGroundMusic_Intro;
    4.     public AudioClip backGroundMusic_Loop;
    5.  
    6.         //--Separate audio sources to try and avoid loading delays
    7.     private AudioSource bgA;
    8.     private AudioSource bgB;
    9.  
    10.  
    11.     void Awake(){
    12.    
    13.         bgA = gameObject.AddComponent<AudioSource>();
    14.         bgB = gameObject.AddComponent<AudioSource>();
    15.    
    16.         bgA.clip = backGroundMusic_Intro;
    17.         bgB.clip = backGroundMusic_Loop;
    18.  
    19.         bgA.loop = false;
    20.         bgB.loop = true;
    21.    
    22.         bgA.Play ();
    23.     }
    24.  
    25.     // Fixed Update called multiple times per frame
    26.     void FixedUpdate () {
    27.         if(loopStarted == false && !(bgA.isPlaying)){
    28.             bgB.Play();
    29.             Destroy (bgA);
    30.             loopStarted = true;
    31.         }
    32.     }
    33.     ///////////////////////////////////////////////////////////
     
  2. gregzo

    gregzo

    Joined:
    Dec 17, 2011
    Posts:
    795
    Hi!

    1) FixedUpdate nope. It's meant for physics, not audio.

    2) You're checking if clip A has done playing before playing the next one: too late.

    Solution: use PlayDelayed and account for latency.

    code:

    Code (CSharp):
    1.  
    2.  
    3. double initLatency = .1d;
    4.  
    5. void Start() //Awake is for initialization...
    6. {
    7.      double playTime = AudioSettings.dspTime + initLatency;
    8.      bgA.PlayDelayed( ( float )playTime );
    9.      playTime += ( double )bgA.clip.duration;
    10.      bgB.PlayDelayed( ( float )playTime );    
    11. }
    -Notice that I add some latency to the first playTime to make sure that the engine has time to preload and schedule the clip. This is especially important for streaming clips.
     
  3. simpson45711

    simpson45711

    Joined:
    Mar 16, 2013
    Posts:
    18
    Thanks, this worked pretty good : D
     
  4. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,553
    Alternatively the plugin I made called Introloop will solve the problem, and the background music does not have to be cut up to 2 clips.

    I used AudioSettings.dspTime and audio scheduling instead of PlayDelayed/coroutine for accuracy internally, since normal game time method is subject to lag in the game. If interested you could see it here : http://forum.unity3d.com/threads/378370/
     
  5. SonicBloomEric

    SonicBloomEric

    Joined:
    Sep 11, 2014
    Posts:
    1,047
    You may want to use PlayScheduled to lock playback to the DSP timeline.
    1. Schedule Intro at a start time a little bit in the future (handles warmup):
      introAudioSource.PlayScheduled(AudioSettings.dspTime + 0.25f);
    2. Schedule Loop to start when Intro ends:
      loopAudioSource.PlayScheduled(AudioSettings.dspTime + 0.25f + introClip.length);
    If there's a gap, you might subtract a tiny bit off of the loop's scheduled time (like 0.01 or something - would need testing).
     
  6. SonicBloomEric

    SonicBloomEric

    Joined:
    Sep 11, 2014
    Posts:
    1,047
    I don't think this guarantees a more smooth fade, actually. At least not universally...

    As I understand it, volume adjustments are applied when the Audio Mix thread requests more samples to render. This is a separate thread from the Main thread where scripts generally do their work. And given how Unity's main thread works, you might actually be calling "volume = x" multiple times without the samples ever being actually updated (this partially depends on the size of your dspBufferSize).

    Of course, the framerate (and any hitches you're receiving) will play a huge factor in how all of this works...
     
  7. Nifflas

    Nifflas

    Joined:
    Jun 13, 2013
    Posts:
    117
    I know about the audio thread thing, but my reasoning was that continuous changes should still ideally be set frequently and in small steps to not sound jumpy. After testing a bunch of things, I guess you're totally right tho. I had misunderstood the nature of FixedUpdate and thought it was spread out over time equally, rather than how it actually works (skipping frames / running multiple times in one frame, if needed).

    Well, I guess I know that now! :)

    Sorry about the off-topicness.
     
    Last edited: Jan 8, 2016
    SonicBloomEric likes this.