- Home /
Accurate Audio Time (Milliseconds)
Hello,
I am trying to write a script that will trigger a new audio file at certain loop points within an original file if a key has been pressed (or some such event). In this case, the time of the original file has been divided by 6, and is just set to play the next section of music when it hits that time point, but seconds are not nearly accurate enough for a tidy loop, unless music is at 120bpm.
Is there another way?
Does audioSource output a flag when it loops or finishes?
var otherClip: AudioClip;
var playNow = false;
var segments = 6;
yield WaitForSeconds ((audio.clip.samples / 441000) / segments);
playNow = true;
function Update ()
{
if(playNow)
{
audio.clip = otherClip;
audio.Play();
playNow = false;
}
}
Any help would be greatly appreciated.
thanks.
Answer by aldonaletto · Oct 30, 2011 at 09:03 AM
You can accurately set the starting point of a sound in audio.time or audio.timeSamples (this refers to the original sample rate), but Unity provided no means to set a stop or loop mark. You can stop it at certain time or sample count comparing the current audio.time or audio.timeSamples to the desired limit in FixedUpdate or Update, but there will always exist some uncertainty, since these functions are called at discrete time intervals (20mS for FixedUpdate, and fairly variable in Update). If you want to loop precisely, you must edit the sound to make it a seamless, continuous loop, and set Loop at the AudioSource. I use this to make ambient sounds, and call Play/Stop to use mute on/off to turn the sound on and off.
The AudioSource.isPlaying flag tells when the sound is playing. It can't help in this loop feature, but is useful - for instance - to avoid start playing the sound again while it's already playing. NOTE: it only works with Play; PlayOneShot or PlayClipAtPoint don't affect audio.isPlaying.
EDITED: I think the best alternative is to have 3 separated audio files, and change the audio.clip variable when you want to play a different sound. It's better for looped sounds, because they can play continuously without noticeable breaks. You could use the function below to fade out the current sound and start a new one (remember to clear or set audio.loop after calling this function, if necessary):
var sound1: AudioClip; // define the sounds in the Inspector var sound2: AudioClip; var sound3: AudioClip;
function FadeAndChange(newSound: AudioClip, fadeTime: float){ var iniVol = audio.volume; for (var t:float = 1; t > 0; ){ // fade out cur sound during fadeTime seconds t -= Time.deltaTime/fadeTime; audio.volume = iniVol * t; yield; // return here next frame } audio.clip = newSound; // change to the new sound audio.volume = iniVol; // restore volume audio.Play(); // make sure the new sound is playing } But if you want to have one single file and play different sections, you can use this:
var startSound1: int; // set these variables in the Inspector var endSound1: int; var startSound2: int; var endSound2: int; var startSound3: int; var endSound3: int;
var loop: boolean; // loops if true
private var startSound: int; private var endSound: int;
// you can loop or just stop at the endSound with this code function FixedUpdate(){ if (audio.timeSamples >= endSound){ if (loop){ audio.timeSamples = startSound; } else { audio.Stop(); } } }
// use this function to fade out a segment and start a new one
function FadeAndChange(newStart: int, newEnd: int, fadeTime: float){ var iniVol = audio.volume; for (var t:float = 1; t > 0; ){ // fade out current sound t -= Time.deltaTime/fadeTime; audio.volume = iniVol * t; yield; // return here next frame } startSound = newStart; // change to the new start/end endSound = newEnd; audio.volume = iniVol; // restore volume audio.Play(); }
Hey,
So i guess if i can set the starting point accurately, and then with FixedUpdate there is a possible 20ms crossover before the last one stops, that wouldn't be to bad, at least worth a shot. Does that make sense, and if so, any tips to help me along, the code i posted was pretty much the extent of my ability, and it's 90% cut and paste.
Thanks $$anonymous$$ate.
Just had a look in the reference, what about AudioSource.mute? Could that be called more accurately if i had all the tracks playing at once? or sharp volume ramps?
As long as you can guarantee that all the tracks will be synchronised, that should actually work!
You can set AudioSource.mute to true (mute) or false using the FixedUpdate function within this same 20mS uncertainty, but usually this doesn't help too much - there's no sound, but the audio continue playing.
What exactly are you trying to do? Playing a looped sound at certain parts of your game? For instance: you have a 20 seconds music that should sound continuously while you are in certain area?
I can guarantee all the tracks will be synchronised when they come out of my DAW, other than that...
it's for a little app, I have a sculpture that plays a continuous melodic loop with an animation, when the player presses it, i'd like it to transition to the next section of the melody/animation. There are only a few segments, probably 3. Could i get the exact sample position of the current track when it is touched, then calculate the distance to the end of the loop, start the next phrase accurately, then either mute, or quickly fade the original out to avoid click?