Is it necessary to have it fade? Or do you just want to loop a specific section?
Loop a specific section
using UnityEngine;
public class AudioLooper : MonoBehaviour
{
public AudioSource audioSource;
public float loopStart;
public float loopEnd;
private void Start()
{
// Set the initial playback position to the loop start position
audioSource.time = loopStart;
}
private void Update()
{
// Check if the audio clip has reached the end of the loop section
if (audioSource.time >= loopEnd)
{
// Set the time to the start of the loop section
audioSource.time = loopStart;
}
}
}
This is a lot easier if you just record the music to include the blending, but sometimes you can’t do that.
Once you can detect the current time (audioSource.time), you can calculate the desired volume at that time. Mathf.InverseLerp interpolates but clamps the result to 0~1, so it’s easy:
1f - Mathf.InverseLerp(fadeStartTime, clipEndTime, audioSource.time);```
The problem is the overlapping nature of your crossfade. I think you need two AudioSource to do that, one for the "current" loop which begins to fade, and one for the "next" loop which starts to play at the beginning of the other's fade. Then you can reuse the first AudioSource as the next-next one.
thanks, I have the music but when i try to create a good loop in premiere somehow the sound is getting screwed on the export
I guess Im not a sound guy
If I was just doing this for a movie I could easily do it since I just have to duplicate the effect for the duration, but for a game I need it to be able to run infinitely.
Anyway if I embed the loop into the music the beginning of the song is no longer a clean start
I don’t mind having many audio sources, thanks for the code for fading
I do need to fade the end otherwise it doesnt sound clean.
Using update to check for the time, I think gives me a clue of when to create the extra audio source thx
thats exactly what was happening to me then, the exported file was coming out with an empty frame on the tail end no matter what, thanks for the heads up
Oh, it occurred to me I already had this class lying around. It can use one or two AudioSources, and ping-pong them with a list of clips to be selected randomly. If using two AudioSources (such as with one on a child object of the other), it will do the crossfade just as I suggested above. If using only one AudioSource, it just plays them using PlayOneShot, so the clips need their own ramp-in.
public class AmbientSound: MonoBehaviour
{
public AudioClip[] clips;
public AudioSource one;
public AudioSource two;
public float overlap = 2f;
[Range(0f, 1f)] public float volume = 1f;
private float time = 0f;
private float transition = 0f;
// [ReadOnly]
public AudioClip playing = null;
void Start()
{
if (one == null)
one = GetComponentInChildren<AudioSource>();
if (two == one)
two = null;
}
void Update()
{
if (one == null)
return;
if (clips == null || clips.Length == 0)
return;
time += Time.deltaTime;
// are we ready to start a clip?
if (one != null && playing == null)
{
playing = clips[Random.Range(0, clips.Length)];
time = 0f;
if (two == null)
one.PlayOneShot(playing);
else
{ one.Stop(); one.clip = playing; one.time = 0f; one.Play(); }
transition = Mathf.Max(0.001f, playing.length - overlap);
//Debug.Log($"chose {playing} will transition in {transition}");
}
// ramp in first source's volume if we can, otherwise hold
//
if (two == null)
one.volume = volume;
else
one.volume = volume * Mathf.InverseLerp(0f, overlap, one.time);
// if we have two sources, ramp out second source's volume
if (two != null && two.clip != null)
{
two.volume = volume * (1f - Mathf.InverseLerp(
two.clip.length-overlap, two.clip.length, two.time));
if (two.volume <= 0f || two.time >= two.clip.length)
{
//Debug.Log($"stopped {two.clip}");
two.Stop();
two.clip = null;
}
}
// approaching end of clip in one, prepare for a choice
if (time >= transition)
{
playing = null;
//Debug.Log($"open to new choices");
if (two != null)
{
Assert.IsTrue(two.clip == null);
AudioSource swap = two;
two = one;
one = swap;
}
}
}
It is an industry-standard practice to actually bake all the fading needed, into the audio file itself. Even if it wasn’t recorded like that, it’s always possible to edit it to be seamlessly loopable. You must copy/paste the “fade out” and overlay it on top of the beginning of the audio file. Then, when it loops back, it will behave exactly the same as shown in your picture.
You will also need two separate files. 1 is the first file to play. 2 is the file to play on all subsequent loops. 1 is the normal song but stops exactly at the “fade out” tail. 2 is the same thing but the “fade out” tail is overlaid onto the beginning. (If you don’t care that the beginning of the first loop will include the fade out tail, because it’s very quiet and barely noticeable, then you really only need file #2).
Then, all the game logic has to do is make sure the audio file loops completely seamlessly. There is no crossfading or special logic needed.
Surprisingly a lot of people don’t know this. They even did it totally wrong in the video game “Outward” and there was an audible glitch every time it looped. I had to make a mod to fix it.
Above, I agreed that it’s preferable to do so. It’s always possible, but not always feasible. If you’re trying to emulate cross-fades between randomly selected variations, the number of pre-recorded cross-fade snippets you need to make and manage increases at an exponential rate. A-fades-into-B, A-fades-into-C, C-fades-into-B, etc.
While a team the size of Nintendo’s Super Mario Wonder may be able to stitch together all those assets and choose to do so because major parts of the gameplay is designed around adaptive music middleware, a much smaller team (or solo dev) would much rather say “here’s the five different bits of audio, please pick from them randomly and cross-fade on two audio channels.”