This week, I'm going to write a brief technical devlog on how I have set up volume control options in Monumental Failure. Let's first show our final result.
Pretty typical sound options eh? In my implementation, the SFX and music channels can be affected individually, and the master will affect them both. I've also made the decision that 70% volume will be "normal", allowing the user to both decrease and increase volume.
Our first step is to create an Audio Mixer.
The audio mixer will have 1 group to start, I have named mine "Master". I then create two subgroups called Music and SoundEffects. You of course can create more groups as you need. For each group, you must expose the volume variable to script by right clicking and selecting Expose.
I'm not going to give details on how to do this next step, but there are two things you need in your scripts. The first is a reference to each of the AudioMixerGroups in your AudioMixer. This lets you set the volume variable you just exposed. The second is to ensure when your game plays audio, it is routed to the appropriate AudioMixerGroup. I solve these problems by having an audio controller class that stores references to the AudioMixerGroups. When I want to play a sound my scripts call a method in the audio controller which assigns the appropriate AudioMixerGroup.
The final step is translating the percentage in the Options menu into a value for volume. You will have noticed that the AudioMixerGroups have volume which can be set from -80 to +20 decibels. Decibels create a problem. Decibels work on a logarithmic scale, which means +10 is loud, and +20 is really really loud. Similarily anything below about -40 is nearly inaudible. How do we choose what decibel values our volume percentage translates to?
My solution starts by declaring a minimum DB, maximum DB and normal DB percentage (70% as mentioned above).
const float MAX_DB = 10f;
Here's where it gets a little ugly. I have a method that passes in a volume percentage as a float between 0 and 1. If that value is greater than my default percentage, I'll linearly interpolate between 0 and my max volume, otherwise, I'll use a circular out interpolation to find a value between 0 and my minimum volume.
public void SetMasterVolume(float iVolume)
Perhaps if my memory of how logarithmic scales work I could find a method better than this ugly code, but sometimes you just have to go with what works. Let me know if you have a better solution, or if my solution helped you!