I need a fairly simple crossfade system for my game whereby two pieces of music crossfade over each other so that one takes the others place. I’ve been reading around on how to do it, I think my general approach is alright, but I need some help with “fading over time” because that part happens instantly which it shouldn’t of course and then it goes silent.
In the game I’ll have 4 tracks of identical length, so I made this method called ChangeTrack(int) which is supposed to do what it says on the tin. In the method I first figure whether I even need to change track because if my new track index is going to be the same as the current one playing, there is no point in changing tracks.
Then I figure out what current playtime the music is at, so that I can put that in the temporary audiosource which will take over for playing the current track while the main audio source, will get the new track to continue playing from the exact time the other one is supposed to crossfade at (hope that makes sense!).
Then I start a coroutine where the temporary source will fade out volume over 1 second (thought might have to change that) and the current source will fade the volume from 0 back to 1.
But when I use my current script, the transition happens instantly and everything goes quiet. I assume it’s because I tried to use a forloop to do the lerping. But I am not sure how I’d need to do this otherwise. I am not using Update currently though I might have to?
CODE EDIT
The code has been slightly revised so that it holds on to both audio sources all the time, rather than getting rid of the crossfade source after it’s done playing. Though the music just instantly switches over rather than cross fading between the two tracks.
Help and improvements would be appreciated
The component itself is attached to a singleton.
I never considered returning a null. I thought I had to return one of the normal ones like WaitForSeconds() or WaitForEndOfFrame(). I’ll try this out when I can
It’s more or less the same. They return at slightly different times during the frame, returning null returns before rendering, EndOfFrame returns after rendering. In your case there’s no noticeable difference, I just find returning null to be cleaner than returning a yield instruction.
I pass it a CrossFadeDuration of 3 (as in 3 seconds). Do I have to do that differently? It doesn’t seem to matter what value I put as CrossFadeDuration. It still transitions instantly.
I think the following Lines are problematic:
5 (move to end)
8 (not required)
10 (remove, should start at beginning)
12 (not really required)
21/22 (ok, but I would move before coroutine call)
25 revert to code sample with crossfadetime and <=
27/28 or call it crossfadeduration, as long as same name as in 25
Well this isn’t the main issue, but this isn’t correct:
time += Time.deltaTime / CrossFadeDuration;
float progress = time / CrossFadeDuration;
Since you’re dividing time into the “progress” float, you don’t need to divide your Time.deltaTime.
I would suggest putting debug log statements in there to print out the input/output values. Print out the CrossFadeDuration, print out the volumes inside the while loop, print out something at the end of the coroutine.
Your code looks fine to me so this is just an exercise in debugging at this point.
The whole point of this system is that it crossfades from one piece of music to the other, starting at the previous piece of musics current position.
I figured out what the issue was. I had forgotten 2 code changes that you added, which I missed. So now the code works smoothly, and I simplified the logic somewhat. It’s not pretty but it works very well. I made a bool that determines whether I need to fade from main to secondary audio source or from secondary to main source.
No problem. Just FYI if you wanted to go a different route, DOTween is a free fully featured tweening package for Unity. It includes audio pitch and volume tweens.
With it, you could accomplish a crossfade with this syntax: