Pregunta

I have a storm in my game, and so I've made an ambient audio file which slowly grows into a storm and rain fades in, which then becomes a loopable storm audio file. Here is how I've done it:

// Play intro clip and merge into main loop
var introTime = stormIntro.length;
AudioSource.PlayClipAtPoint( stormIntro, Vector3.zero, 0.7 );
Invoke( "StormMusic", introTime );

The way I'm currently trying to do it is get the length of the storm_intro audio clip, play the clip, and then invoke storm_loop to begin after the length of the intro has completed. This kinda works, but not really because there's occasionally a gap between the two. So how can I do it so the transition is seamless?

¿Fue útil?

Solución

I'm working on music middleware for Unity right now, and I experience this problems a lot. These "gaps" appear only because Unity needs to load audio data from disc before playing it, so it can't really play it right away. If you want to schedule some audioclip to play at specific point, you need to know about it ahead of time, you need to use AudioSource.PlayScheduled, as @Kay adviced.

You need to note that PlayScheduled operates not on standard Time.time, but on AudioSettings.dspTime. It never pauses, and can even stay the same in between of different launches of the game in the editor. So, you need to write something like audio.PlayScheduled( AudioSettings.dspTime + expectedDelay ); to play certain audio clip in expectedDelay seconds. You need to keep expectedDelay at some reasonable level so that Unity can load up the clip; the amount depends on your audio file size, it's import settings, device you're optimizing for and other things; I think you can come up with the right value after a few experiments.

But if you'll try to manually loop the clip, launching it over and over at the same spot, you'll experience gaps once again. They'll be much shorter, and you might not be able to notice them, but they'll be there — you can check by recording the audio output and looking at it in some audio editor. To get rid of this, I use to audio sources with the same clip and launch one after the other.

Otros consejos

I guess the gap is because loading the StormMusic clip takes some time. So if you can trigger the intro manually for instance by a collider, AudioSource.PlayScheduled should do what you want.

Unfortunately there is no PlayQueued or CrossFade method available for audio sources like in animation.

What Lake says is truth.

I dont know how, i dont know why, but Unity support Wav loop points from Wavosaur only. I never get it to work from other software, like fl studio or audacity.

Open your sound in Wavosaur, select the area you want to loop and click the "L" red icon. Thats'it, the sound will loop in Unity following your looppoints.

It's a shame that Unity doesn't document/enhance this usefull feature.

UNITY SUPPORTS WAV LOOP POINTS METADATA.

Let me say this again, because I have been destroying my neurons for 2 years for absolutely no reason:

UNITY SUPPORTS WAV LOOP POINTS METADATA.

So get rid of those mp3s, set wav loop points with Wavosaur (free), and let Unity compress the wav into vorbis for you at import time.

I know this is old, but I wanted to share my IntroLoop class for free! By default, this class plays the file from the beginning, looping from introBoundary to loopBoundary just like 5argon's. I have added some new features, coding time: 30 minutes. One, you can play just a loop, no intro. Two, same as default but you can start anywhere not just at the beginning and still have and intro and a loop. and Three, you can play a the file from point a to b without looping by setting IntroLoop.playOnce to false after constructing the intro loop object. So now you can put all your audio into a single file.

example of use: After attaching your audio to the script's object, drag the audio component to a public field, and send into the constructor, You can make more than one IntroLoop object from the same audio file. This example will play an intro starting at the 5 second mark and loop from the 10 second mark to the 20 second mark:

//Example of use
//Construct
IntroLoop clip = new IntroLoop(audioSource,5f,10f,20f);
//no intro just loop
IntroLoop clip2 = new IntroLoop(audioSource,10f,20f,false);

//you can set it to play once
clip2.playOnce = true;    

//call to start
clip.start();

//call once a frame, this resets the loop if the time hits the loop boundary
//or stops playing if playOnce = true
clip.checkTime(); 

//call to stop
clip.stop();


/* **************************************************** */
//The Music IntroLoop Class handles looping music, and playing an intro to the loop
public class IntroLoop {
    private AudioSource source;
    private float startBoundary;
    private float introBoundary;
    private float loopBoundary;
    //set to play a clip once
    public bool playOnce = false;

    //play from start for intro
    public IntroLoop(AudioSource source, float introBoundary, float loopBoundary) {
        this.source = source;
        this.startBoundary = 0;
        this.introBoundary = introBoundary;
        this.loopBoundary = loopBoundary;
    }
    //play from start for intro or just loop
    public IntroLoop(AudioSource source, float introBoundary, float loopBoundary, bool playIntro) {
        this.source = source;
        this.startBoundary = playIntro?0:introBoundary;
        this.introBoundary = introBoundary;
        this.loopBoundary = loopBoundary;
    }
    //play from startBoundary for intro, then loop
    public IntroLoop(AudioSource source, float startBoundary, float introBoundary, float loopBoundary) {
        this.source = source;
        this.startBoundary = startBoundary;
        this.introBoundary = introBoundary;
        this.loopBoundary = loopBoundary;
    }
    //call to start
    public void start() { this.source.time = this.startBoundary; this.source.Play(); }
    //call every frame
    public void checkTime() {
        Debug.Log(this.source.time);
        if (this.source.time >= this.loopBoundary) {
            if (!this.playOnce) { this.source.time = introBoundary; }
        } 
    }
    //call to stop
    public void stop() { this.source.Stop(); }  
}
//The Music IntroLoop Class
/* **************************************************** */

I made a solution called Introloop, which is a Unity plugin that you can play BGM with intro section that goes into endless loop without cutting the file into 2 clips.

I used AudioSettings.dspTime related method like scheduling to ensure precise looping. And it supports cross fading between 2 intro-included audio also. You only have to provide it 2 time point per audio, and the script will handle the rest of audio juggling.

http://forum.unity3d.com/threads/378370/

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top