I really appreciate you taking the time to not just show the solution to the problem and add a code snippet to copy. You show how it can be done, explain the code and even address problems / negative examples. This is perfect for learning. Thank you very much!
I'm just getting started learning Unity and am about to add audio to my first solo project. I definitely would have fallen for the beginner's traps shown here. It really seems worthwhile to go the extra mile to avoid a buggy mess. Thanks for the solid info and great job on the tutorial!
I really appreciate how you write comments outlining what you’re going to do before writing the actual code. It clearly explains your thought process, and as a viewer, it couldn’t be more helpful. Thank you so much for this tutorial!
Really cool tutorial, something i would change to avoid code repetition is to pick the random clip in the PlayRandomSound function but then call the original PlaySound function and pass the random audioclip
Sometimes it can be useful to keep your sliders going between 0 and 100 for displaying the volume as text or perhaps saving the volume level to player prefs. So rather than changing the numbers on the slider I wrote a couple of functions for converting between whole numbers (0 to 100) and the Log10 values and visa versa. private static float ValueToVolume(float value) { var normalized = value / 100f; var scaled = Mathf.Lerp(0.0001f, 1f, normalized); var volume = Mathf.Log10(scaled) * 20f; return volume; } private static float VolumeToValue(float volume) { var scaled = Mathf.Pow(10, volume / 20f); var normalized = Mathf.InverseLerp(0.0001f, 1f, scaled); var value = normalized * 100f; return value; }
This video made my job much easier. I decided to leave the sound part until last, along with a lot of prefabs. The only thing I will do now is to give all the sounds as variables to the soundFxManager and call those sounds from the prefabs. Otherwise I would have to add sounds to all of them one by one. thanks a lot.
I've never seen anyone instantiate and destroy AudioSource objects like that. Each of my sound managers has a single audio source mapped to an audio mixer group and I use PlayOneShot() to play sound effects. Of course that doesn't use spatial audio though so if you really want the surround sound effect I guess you need an approach similar to yours. I would probably implement object pooling though so as not create a bunch of garbage and get lag spikes.
yea I was never able to find a solution that I was 100% happy with, so I made this one. PlayClipAtPoint has the spatial audio, but it uses Instantiate/Destroy with no way to change that as far as I can tell. PlayOneShot is great except for the spatial audio being a bit lacking. This way, you get the spatial audio, as well as the abillity to easily swap it into an object pooling system (and by extension, control your voice count fairly easily so you don't go above the threshold.)
@@sasquatchbgames Hey I wanted to share with you an implementation where you actually can add a mixergroup to an audiosource that is instantiated at runtime. I had this same problem so I managed to get this solution up and working. You need to put your mixer in the "Resources" folder. Then you can get a reference to it in script with _myMixer = Resources.Load("stringPath") as Audiomixer; (Example "Resources/Mixers/Mainmixer") THEN You can get a reference to the mixergroup by AudioMixerGroup _sfxGroup = _myMixer.FindMatchingGroups("stringName") THEN You can assign it to an audiosource at runtime by. _exampleAudioSource.outputAudioMixerGroup = _sfxGroup; AND now you can instantiate Audiosources at runtime while still having control of their mix!
Object pooling was my first thought as well. Im debating implementing object pooling for this system, but I'm not sure if it's worth it in the project I'm working on because there would only ever be like 3 sound effects playing at once, but you never know if that'll change
@@iiropeltonen I'm just finding this now, a year or so later. Could you explain how I integrate this into the tutorial? Also, I'm so far up to 7:24 and the Destroy() doesn't work for me, the cloned SoundFXObject stays.
The log10(level) * 20 is the aproximative real world formula to calculate the power of sound. So what is the value of X for x.pow(10) == level. Also that was a great tutorial, I will be using yous system in my current project.
Instead of instantiating and destroying the audio source, As we would still assign the audio clip we want, could object pooling be used and maybe as a precaution remove the clip from the audio source before returning source to pool?
Great video. Just wondering if we should follow the same setup within the music manager such as using a prefab game object (i.e. "MusicObject) and make a singleton as well?
Nicely done. All the most important points covered. Something I would add is that in addition to playing random clips, it’s nice also randomly setting the pitch and volume, which can give a sense that you have more asset variation. The issue then is that destroying by clip length will not adapt to the length change from pitch adjustment. To account for this, you can set the destroy time for the spawned AudioSource to: audioSource.clip.length/audioSource.pitch. Hope that helps!
I want to add: it’s cool seeing your journey. Glad you’re sharing it through TH-cam :) I do technical game audio professionally (full time - I’m not looking for money here), so I just thought I’d extend that if you run into audio issues with your game you can hit me up for some advice. Cheers and best of luck!
This is absolutetly fucking amazing. Thank you yo! You've saved our deadlined project by telling us how NOT to do it aswell, thats what I was thinking to do first xD
I need help because I used your method I have a problem because I have Main Menu scene and I need data and slider refrences to carry through every scene I have Settings sliders in mein menu scene and in th ehub of my game and I dont know how to carry data from one to another
it doesnt work, for some reason it only plays sounds when the audio that is linked to the object that i want to play sound is the same a the soundfxobject, if i try something different it will spawn a sfxobject in the scene but the audio wont play
I noticed that there was a delay though on the audio clip. I am having this issue too with my own project. I want the audio to immediately come in as it gives better feedback to the player. Do you know how to do this?
If there is a single sfx audio manager what would happen in the case of multiple sfx playing at the same time? Or is this a case were we wouldnt want to make a singleton
How can I make it so these settings persist using PlayerPrefs? I have added a save button and the values are stored correctly, in my GameManager's on Awake function I load these values, set them in the SoundMixerManager and also in my OptionsMenuUI to the sliders. The sliders continue to be full.
No errors and I did everything as said but the sound just doesnt play. The soundObject even spawns in and deletes itself but theres just no sound. Edit: Don't mind this comment, I'm just stupid and forgot to call the audioSource.Play() function in the method
How does it sound like: Create a script with all functions and clips inside like die() respawn() etc add it to a empty gameobject than access to it through that gameobject with find methor or manualy adding your enemy object player object etc that was first thing in my mind
This is a great solution for an audio manager however how might this implement a Stop() function? If say you had an audio sound that you wanted to stop mid sfx then how would you reference the audioSource? Say i have a light sound that plays when a light is active. When I turn off that light how do I make the sound stop with it?
Nice tutorial. I get this error: Some objects were not cleaned up when closing the scene. (Did you spawn new GameObjects from OnDestroy?) The following scene GameObjects were found: SoundFXObject(Clone) SoundFXObject(Clone) My code is the same a the tutorial, this error happens if i restart the scene every time. Any ideas on how to fix it?
Every button has a onClick event in the inspector, add the SoundManager into it, and active the playSoundFX method. All of this can be done in the inspector, on the button component. Or you can add a reference for the button into a script and add a onClickListenter on it, then call the PlaySoundFX method this way.
Hello!!! Thank you for very cool tutor! But how can I save these values in PlayerPrefs and then load them afterwards, to save the settings? public AudioMixerGroup Mixer; private void Start() { GetComponentInChildren().value = PlayerPrefs.GetFloat("MusVolume", 1); GetComponentInChildren().value = PlayerPrefs.GetFloat("FxVolume", 1); } public void MusicVolume(float volume) { Mixer.audioMixer.SetFloat("MusicVolume", Mathf.Log10(volume) * 20f); PlayerPrefs.SetFloat("MusVolume", volume); } public void SFXVolume(float volume) { Mixer.audioMixer.SetFloat("SfxVolume", Mathf.Log10(volume) * 20f); PlayerPrefs.SetFloat("FxVolume", volume); }
Won't this cause performance issues? like you can't use object pooling her, looks like it will generate a lot of garbage collection since we keep destroy and respawn audio objects especially when you have multiple sounds for the same character.
Probably a good optimisation to add on top if you end up producing too much garbage. Remember, only optimize when it becomes an issue, focus on getting the game out
Probably the best Unity audio tutorial I have seen so far.
Agreed - so incredibly helpful!
I really appreciate you taking the time to not just show the solution to the problem and add a code snippet to copy.
You show how it can be done, explain the code and even address problems / negative examples.
This is perfect for learning. Thank you very much!
I'm just getting started learning Unity and am about to add audio to my first solo project. I definitely would have fallen for the beginner's traps shown here. It really seems worthwhile to go the extra mile to avoid a buggy mess. Thanks for the solid info and great job on the tutorial!
I really appreciate how you write comments outlining what you’re going to do before writing the actual code. It clearly explains your thought process, and as a viewer, it couldn’t be more helpful. Thank you so much for this tutorial!
rare W
I am very stunned ! The title "...the RIGHT WAY" is really not an exaggeration. Thank you for that ! FYI for other dev's: Works under 2023.3
I love these kind of managers! I have a 2D project template and each time I find a gem like this I work it in there. Thanks a lot!
this shit so goated. Love having short instructions for different methods cause i can choose whichever one is more convenient depending on the project
This is the most efficient sound manager I've ever tried, you have my respect man!
You should combine this with codemonkeys soundmanager, it's the ultimate sound system
This was immensely helpful. Also, the way you made dividers in the hierarchy was one of those "why didn't I think of that??" things. Thanks a bunch!
Really cool tutorial, something i would change to avoid code repetition is to pick the random clip in the PlayRandomSound function but then call the original PlaySound function and pass the random audioclip
Sometimes it can be useful to keep your sliders going between 0 and 100 for displaying the volume as text or perhaps saving the volume level to player prefs.
So rather than changing the numbers on the slider I wrote a couple of functions for converting between whole numbers (0 to 100) and the Log10 values and visa versa.
private static float ValueToVolume(float value)
{
var normalized = value / 100f;
var scaled = Mathf.Lerp(0.0001f, 1f, normalized);
var volume = Mathf.Log10(scaled) * 20f;
return volume;
}
private static float VolumeToValue(float volume)
{
var scaled = Mathf.Pow(10, volume / 20f);
var normalized = Mathf.InverseLerp(0.0001f, 1f, scaled);
var value = normalized * 100f;
return value;
}
This video made my job much easier. I decided to leave the sound part until last, along with a lot of prefabs. The only thing I will do now is to give all the sounds as variables to the soundFxManager and call those sounds from the prefabs. Otherwise I would have to add sounds to all of them one by one.
thanks a lot.
You should make a guide on how to create that kind of pause menu!
Thanks!
Thank you!
OMG THANK YOU SOOOO MUCH I WAS SITTING ON THIS FOR 2 DAYS AND NOW I HAVE PUT SOUNDS AND SFX ON EVERYTHING THANKS TO THX SO MUCH!!!!!
you increased my confidence ngl
This is by far the best tutorial I have followed! Thanks 😃
There might be a lot of sounds and creating/destroying gameobjects is taxing, isn't it?
You really make the best tutorials!
I've never seen anyone instantiate and destroy AudioSource objects like that. Each of my sound managers has a single audio source mapped to an audio mixer group and I use PlayOneShot() to play sound effects. Of course that doesn't use spatial audio though so if you really want the surround sound effect I guess you need an approach similar to yours. I would probably implement object pooling though so as not create a bunch of garbage and get lag spikes.
yea I was never able to find a solution that I was 100% happy with, so I made this one.
PlayClipAtPoint has the spatial audio, but it uses Instantiate/Destroy with no way to change that as far as I can tell. PlayOneShot is great except for the spatial audio being a bit lacking.
This way, you get the spatial audio, as well as the abillity to easily swap it into an object pooling system (and by extension, control your voice count fairly easily so you don't go above the threshold.)
@@sasquatchbgames Hey I wanted to share with you an implementation where you actually can add a mixergroup to an audiosource that is instantiated at runtime. I had this same problem so I managed to get this solution up and working.
You need to put your mixer in the "Resources" folder. Then you can get a reference to it in script with
_myMixer = Resources.Load("stringPath") as Audiomixer; (Example "Resources/Mixers/Mainmixer")
THEN
You can get a reference to the mixergroup by
AudioMixerGroup _sfxGroup = _myMixer.FindMatchingGroups("stringName")
THEN
You can assign it to an audiosource at runtime by.
_exampleAudioSource.outputAudioMixerGroup = _sfxGroup;
AND now you can instantiate Audiosources at runtime while still having control of their mix!
@@iiropeltonen awesome man, thanks!
Object pooling was my first thought as well. Im debating implementing object pooling for this system, but I'm not sure if it's worth it in the project I'm working on because there would only ever be like 3 sound effects playing at once, but you never know if that'll change
@@iiropeltonen I'm just finding this now, a year or so later. Could you explain how I integrate this into the tutorial?
Also, I'm so far up to 7:24 and the Destroy() doesn't work for me, the cloned SoundFXObject stays.
The log10(level) * 20 is the aproximative real world formula to calculate the power of sound. So what is the value of X for x.pow(10) == level. Also that was a great tutorial, I will be using yous system in my current project.
Thanks buddy! almost 2025 and still relevant!
This tutorial is a godsend! Ty Sir!
Banger tutorial man
Thanks for the wonderful tutorial
Instead of instantiating and destroying the audio source, As we would still assign the audio clip we want, could object pooling be used and maybe as a precaution remove the clip from the audio source before returning source to pool?
yea. i hope this isn't considered treason, but @git-amend has a good tutorial on this if you still need it.
Great video. Just wondering if we should follow the same setup within the music manager such as using a prefab game object (i.e. "MusicObject) and make a singleton as well?
Thanks! This will be my video reference to create audio systems.
You saved so much time of mine. Thanks a lot.
Hey, you didn't show how to call the menu, nor how to make the sliders :(
Great Tutorial, as always.
Thanks again! 🙂
thank you! great video
Thank you. Very helpful video!!
Clicked. Coded. Works.
Nicely done. All the most important points covered.
Something I would add is that in addition to playing random clips, it’s nice also randomly setting the pitch and volume, which can give a sense that you have more asset variation.
The issue then is that destroying by clip length will not adapt to the length change from pitch adjustment. To account for this, you can set the destroy time for the spawned AudioSource to:
audioSource.clip.length/audioSource.pitch.
Hope that helps!
I want to add: it’s cool seeing your journey. Glad you’re sharing it through TH-cam :)
I do technical game audio professionally (full time - I’m not looking for money here), so I just thought I’d extend that if you run into audio issues with your game you can hit me up for some advice. Cheers and best of luck!
This is absolutetly fucking amazing. Thank you yo! You've saved our deadlined project by telling us how NOT to do it aswell, thats what I was thinking to do first xD
my dear good sir, Mathf.Log10(value) * 20f ..... where value ranges from 0 to -80
log(-ve numbers) is giving NaN output ..how's it working for you
Thanks for the help!
I need help because I used your method I have a problem because I have Main Menu scene and I need data and slider refrences to carry through every scene I have Settings sliders in mein menu scene and in th ehub of my game and I dont know how to carry data from one to another
Amazing tutorial :)
it doesnt work, for some reason it only plays sounds when the audio that is linked to the object that i want to play sound is the same a the soundfxobject, if i try something different it will spawn a sfxobject in the scene but the audio wont play
fantastic explanations
I noticed that there was a delay though on the audio clip. I am having this issue too with my own project. I want the audio to immediately come in as it gives better feedback to the player. Do you know how to do this?
If there is a single sfx audio manager what would happen in the case of multiple sfx playing at the same time? Or is this a case were we wouldnt want to make a singleton
What about using the UI Toolkit instead of the legacy UI elements?
Can I do this same thing but instead of creating my own sound clips array, use the built in Random Audio Container in unity? v helpful tutorial
How can I make it so these settings persist using PlayerPrefs? I have added a save button and the values are stored correctly, in my GameManager's on Awake function I load these values, set them in the SoundMixerManager and also in my OptionsMenuUI to the sliders.
The sliders continue to be full.
Fixed it by loading the values from PlayerPrefs in Start() instead of Awake(). :D
Do you know how to set it up to play an audio clip before playing a looping, continuous piece of music?
No errors and I did everything as said but the sound just doesnt play. The soundObject even spawns in and deletes itself but theres just no sound.
Edit: Don't mind this comment, I'm just stupid and forgot to call the audioSource.Play() function in the method
How does it sound like: Create a script with all functions and clips inside like die() respawn() etc add it to a empty gameobject than access to it through that gameobject with find methor or manualy adding your enemy object player object etc that was first thing in my mind
This is a great solution for an audio manager however how might this implement a Stop() function? If say you had an audio sound that you wanted to stop mid sfx then how would you reference the audioSource?
Say i have a light sound that plays when a light is active. When I turn off that light how do I make the sound stop with it?
what if you want to control the volume of individual sound effects in the mixer?
Nice tutorial.
I get this error:
Some objects were not cleaned up when closing the scene. (Did you spawn new GameObjects from OnDestroy?)
The following scene GameObjects were found:
SoundFXObject(Clone)
SoundFXObject(Clone)
My code is the same a the tutorial, this error happens if i restart the scene every time.
Any ideas on how to fix it?
sure, but what if sound is continuous and needs to follow the source?
great video thank you thank you
what does it mean if I get and error in Unity that says "The name 'volume' does not exist in the current context?"
audioSource.pitch = (float)Random.Range(8, 12) / 10; Good way to randomize your sound if you only have one
Nice tuto, BUT, how to play a sound FX from a Button?
Every button has a onClick event in the inspector, add the SoundManager into it, and active the playSoundFX method.
All of this can be done in the inspector, on the button component.
Or you can add a reference for the button into a script and add a onClickListenter on it, then call the PlaySoundFX method this way.
Can this be used in 3D games too? Haven't tested it yet but I just wanna be sure
Of course, no difference.
I use it in my 3D game.
Hello!!! Thank you for very cool tutor! But how can I save these values in PlayerPrefs and then load them afterwards, to save the settings?
public AudioMixerGroup Mixer;
private void Start()
{
GetComponentInChildren().value = PlayerPrefs.GetFloat("MusVolume", 1);
GetComponentInChildren().value = PlayerPrefs.GetFloat("FxVolume", 1);
}
public void MusicVolume(float volume)
{
Mixer.audioMixer.SetFloat("MusicVolume", Mathf.Log10(volume) * 20f);
PlayerPrefs.SetFloat("MusVolume", volume);
}
public void SFXVolume(float volume)
{
Mixer.audioMixer.SetFloat("SfxVolume", Mathf.Log10(volume) * 20f);
PlayerPrefs.SetFloat("FxVolume", volume);
}
nice tutorials
wait so if I have 20 coins at a place in my game and i collect them ..i will have to spawn 20 audiosources ?
yes
What about saving the value of voiumes ?? These will be lost each time the scene reloads? or
not?
did you find a solution? wondering the same thing
@@ThePoePoee playerprefs can be used I think
@@mustafa_unitydevyes use player prefs and save it as float or int
Do the sliders stop working after reloading scene?
yes
For me it doesn't create a soundFXObject in the inspector
under the script for the manager that is
Won't this cause performance issues? like you can't use object pooling her, looks like it will generate a lot of garbage collection since we keep destroy and respawn audio objects especially when you have multiple sounds for the same character.
Probably a good optimisation to add on top if you end up producing too much garbage. Remember, only optimize when it becomes an issue, focus on getting the game out
First
wull
what's the point of this comment exactly