Voltar para o Blog
Quest Log

Audio Mixer na Unity: Volume de Música e Efeitos no Menu

Mesa de som estilizada com dois controles deslizantes, um para música e outro para efeitos, dentro da janela de um editor de jogos

Unity Audio Mixer na prática: grupos Música e Efeitos, parâmetro exposto, slider em decibéis com Log10, volume salvo e snapshot de pausa, com C# do Unity 6.

Ferramenta:UnityC#

Audio Mixer na Unity: Volume de Música e Efeitos no Menu

O Unity Audio Mixer é o asset que deixa o jogador controlar música e efeitos separados: você cria grupos, expõe o volume de cada um para o script e liga um slider do menu que converte 0 a 1 em decibéis. No fim deste guia você tem um menu com dois sliders que soam naturais, salvam a escolha do jogador, não zeram o mixer de forma errada e ainda abafam a música quando o jogo pausa.

Todo o código foi escrito para o Unity 6.3 LTS e usa só a API de UnityEngine.Audio, sem pacote extra.

O que é o Audio Mixer da Unity

Sem mixer, cada AudioSource toca direto no AudioListener da câmera, e a única forma de mexer no volume geral é mudar o volume de cada fonte ou o AudioListener.volume, que afeta tudo junto. Isso não serve para um menu de opções, onde o jogador quer música baixa e efeitos altos.

O Audio Mixer é um asset que fica entre as fontes e o listener. Ele sempre tem um grupo Master, e você cria grupos filhos abaixo dele. Cada AudioSource aponta a saída (campo Output) para um grupo. Cada grupo tem volume próprio em decibéis, pode receber efeitos (filtro, reverb, compressor) e o Master soma tudo no final.

A faixa de volume de um grupo vai de -80 dB, que é silêncio, até +20 dB de ganho, segundo a documentação do Unity 6.3. O valor 0 dB significa "o som como foi importado". Guarde esse número: é a origem do bug mais comum de slider de volume.

Criando grupos Master, Música e Efeitos

  1. No Project, clique com o botão direito e escolha Create > Audio Mixer. Chame de MainMixer.
  2. Dê dois cliques no asset para abrir a janela Audio Mixer. Na coluna da esquerda aparece a seção Groups com o Master.
  3. Selecione o Master e clique no + da seção Groups. Crie Musica. Selecione o Master de novo e crie Efeitos. Os dois precisam ser filhos do Master, não um filho do outro.
  4. Em cada AudioSource da cena, arraste o grupo certo para o campo Output. A fonte da trilha vai em Musica; tiros, pulos e passos vão em Efeitos.

Se o jogo tem diálogo ou ambiente, crie os grupos agora, mesmo que o menu só tenha dois sliders. Reorganizar saídas depois, com 200 prefabs prontos, é trabalho chato. Uma dica que economiza tempo: deixe os prefabs de efeito com o Output já preenchido, assim todo inimigo novo nasce no grupo certo.

Expondo o parâmetro de volume

O script não enxerga o volume do grupo até você expor o parâmetro:

  1. Selecione o grupo Musica na janela do mixer.
  2. No Inspector, clique com o botão direito no nome Volume e escolha Expose 'Volume (of Musica)' to script. Aparece uma setinha ao lado do campo.
  3. No canto superior direito da janela do Audio Mixer, abra Exposed Parameters. O parâmetro vem com um nome genérico, como MyExposedParam.
  4. Clique com o botão direito nele, Rename, e troque para MusicVolume.
  5. Repita para Efeitos com o nome SfxVolume.

O nome é sensível a maiúsculas. MusicVolume e musicVolume são parâmetros diferentes para o SetFloat, e ele não lança exceção quando erra: só retorna false. Por isso o código abaixo guarda os nomes em constantes e confere o retorno.

Slider para decibel com Mathf.Log10

Aqui mora o problema. O slider do Unity UI vai de 0 a 1, o mixer trabalha em decibéis. A conversão errada que aparece em muito tutorial é mapear linear: Mathf.Lerp(-80f, 0f, valor). O resultado é um slider em que 80% do curso soa quase igual e o som despenca no último pedaço. O ouvido percebe volume de forma logarítmica, então a conversão também precisa ser.

A fórmula certa é dB = 20 * log10(linear). Com o slider em 1, dá 0 dB (volume original). Em 0,5, dá cerca de -6 dB, que soa como "metade". Em 0,0001, dá exatamente -80 dB, o silêncio do mixer.

E aí está o bug do zero: Mathf.Log10(0f) retorna infinito negativo. Mandar isso para o mixer gera comportamento estranho, e em alguns casos o som some até reiniciar o jogo. A correção é nunca deixar o valor chegar a zero: configure o Min Value do slider em 0.0001 e, por garantia, faça um clamp no código.

Configuração dos sliders no Inspector: Min Value 0.0001, Max Value 1, Whole Numbers desmarcado.

Arquivo VolumeSettings.cs:

using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.UI;

public class VolumeSettings : MonoBehaviour
{
    public const string MusicParam = "MusicVolume";
    public const string SfxParam = "SfxVolume";
    private const float MinLinear = 0.0001f;
    private const float DefaultLinear = 0.75f;

    [SerializeField] private AudioMixer mixer;
    [SerializeField] private Slider musicSlider;
    [SerializeField] private Slider sfxSlider;

    private void Start()
    {
        float music = PlayerPrefs.GetFloat(MusicParam, DefaultLinear);
        float sfx = PlayerPrefs.GetFloat(SfxParam, DefaultLinear);

        musicSlider.SetValueWithoutNotify(music);
        sfxSlider.SetValueWithoutNotify(sfx);

        ApplyVolume(MusicParam, music);
        ApplyVolume(SfxParam, sfx);

        musicSlider.onValueChanged.AddListener(OnMusicChanged);
        sfxSlider.onValueChanged.AddListener(OnSfxChanged);
    }

    private void OnDestroy()
    {
        musicSlider.onValueChanged.RemoveListener(OnMusicChanged);
        sfxSlider.onValueChanged.RemoveListener(OnSfxChanged);
        PlayerPrefs.Save();
    }

    private void OnMusicChanged(float value)
    {
        ApplyVolume(MusicParam, value);
        PlayerPrefs.SetFloat(MusicParam, value);
    }

    private void OnSfxChanged(float value)
    {
        ApplyVolume(SfxParam, value);
        PlayerPrefs.SetFloat(SfxParam, value);
    }

    private void ApplyVolume(string parameter, float linear)
    {
        float clamped = Mathf.Clamp(linear, MinLinear, 1f);
        float decibels = Mathf.Log10(clamped) * 20f;

        if (!mixer.SetFloat(parameter, decibels))
        {
            Debug.LogWarning($"Parâmetro '{parameter}' não encontrado no mixer. Confira o nome em Exposed Parameters.");
        }
    }
}

Por que cada decisão:

  • Start, não Awake. A documentação do AudioMixer.SetFloat no Unity 6.3 diz para não chamar o método em Awake, OnEnable ou no RuntimeInitializeLoadType.AfterSceneLoad, porque o resultado pode ser imprevisível. Chame em Start ou depois.
  • SetValueWithoutNotify. Carregar o valor salvo sem disparar o evento evita gravar de novo o que você acabou de ler.
  • O máximo é 0 dB, não +20. Dá para deixar o slider ir acima de 1 e chegar ao ganho positivo, mas isso estoura áudio que já foi mixado no máximo. Deixe o reforço para quem mixa, não para o jogador.

Salvando e carregando o volume

O PlayerPrefs resolve bem para duas preferências de volume. O código grava a cada mudança do slider e força o PlayerPrefs.Save() quando o menu é destruído, que é o momento em que o jogador terminou de mexer.

Tem uma armadilha: se o volume só é aplicado no Start do menu de opções, o jogo começa com o mixer no padrão e só respeita a escolha do jogador quando ele abre o menu. A correção é aplicar os valores salvos também na primeira cena, num objeto que sempre existe.

Arquivo AudioBootstrap.cs:

using UnityEngine;
using UnityEngine.Audio;

public class AudioBootstrap : MonoBehaviour
{
    [SerializeField] private AudioMixer mixer;

    private void Start()
    {
        Apply(VolumeSettings.MusicParam);
        Apply(VolumeSettings.SfxParam);
    }

    private void Apply(string parameter)
    {
        float linear = Mathf.Clamp(PlayerPrefs.GetFloat(parameter, 0.75f), 0.0001f, 1f);
        mixer.SetFloat(parameter, Mathf.Log10(linear) * 20f);
    }
}

Coloque o AudioBootstrap na cena inicial (tela de título ou splash). Se o seu jogo tem um gerenciador de áudio persistente com DontDestroyOnLoad, esse código pode morar nele. A estrutura de um gerenciador desses é a mesma em qualquer engine; o post sobre barramentos de áudio e mixagem na Godot mostra a ideia no outro lado, e os conceitos de grupo, envio e efeito valem igual.

Juntar mixer, menu, pausa, cenas e salvamento é o ponto em que muita gente que aprende sozinha trava: cada peça funciona isolada, e o jogo inteiro não fecha. No curso de Unity você monta esse esqueleto (menu de opções, áudio, pausa e troca de cena) dentro de um jogo completo, com revisão de quem já entregou jogo.

Curso de Unity
Quer fazer seu primeiro jogo na Unity?

No curso de Unity 6 da CursoGame.Dev você vai do zero ao primeiro jogo, com um desafio prático em cada level e suporte individual no WhatsApp quando travar.

Conhecer o curso de Unity
Suporte no WhatsAppAcesso vitalícioGarantia de 7 dias

Snapshots: abafar som na pausa

Um snapshot é uma fotografia de todos os parâmetros do mixer. O padrão é ter um Snapshot inicial; você cria outros no + da seção Snapshots da janela. A troca entre eles é interpolada, então dá para fazer a música ficar abafada e mais baixa quando o jogo pausa, em vez de parar seco.

Aqui entra uma regra que derruba muita gente: depois que um parâmetro recebe SetFloat, os snapshots param de controlá-lo. A documentação do Unity 6.3 diz isso com todas as letras. Se o seu snapshot de pausa tenta baixar o mesmo Volume que o slider controla, nada acontece.

A saída é usar o snapshot para outra coisa:

  1. No grupo Musica, clique em Add Effect no Inspector e escolha Lowpass.
  2. Crie o snapshot Pausado. Com ele selecionado, baixe o Cutoff freq do Lowpass para algo perto de 800 Hz.
  3. Volte ao snapshot normal e deixe o Cutoff em 22000 Hz (som limpo).
  4. No asset do mixer, mude Update Mode para Unscaled Time. Sem isso, se a sua pausa usa Time.timeScale = 0, a transição do snapshot também congela.

Arquivo PauseAudio.cs:

using UnityEngine;
using UnityEngine.Audio;

public class PauseAudio : MonoBehaviour
{
    [SerializeField] private AudioMixerSnapshot normalSnapshot;
    [SerializeField] private AudioMixerSnapshot pausedSnapshot;
    [SerializeField] private float transitionSeconds = 0.25f;

    public void SetPaused(bool paused)
    {
        AudioMixerSnapshot target = paused ? pausedSnapshot : normalSnapshot;
        target.TransitionTo(transitionSeconds);
    }
}

Chame SetPaused(true) do mesmo lugar que abre o menu de pausa. O volume do jogador continua valendo, porque ele está em outro parâmetro, e a música ganha aquele som de "atrás de uma parede" que todo mundo reconhece. Esse tipo de detalhe é parte do que separa áudio funcional de áudio que ajuda o jogo.

Erros comuns: slider não linear e -80 dB no zero

O slider some com o som só no final. Você está convertendo de forma linear. Troque por Mathf.Log10(valor) * 20f.

Arrastar o slider até o zero trava o áudio. O slider está chegando a 0 e o Log10 devolve infinito negativo. Min Value em 0.0001 e clamp no código.

SetFloat não faz nada. Três causas, nessa ordem: o nome não bate com Exposed Parameters (maiúsculas contam), o parâmetro nunca foi exposto, ou o método roda no Awake. O Debug.LogWarning do código acima pega o primeiro caso.

Os efeitos continuam altos com o slider no mínimo. Alguma AudioSource está com Output vazio e toca direto no listener, fora do mixer. Procure fontes sem Output na Hierarchy, principalmente as criadas por script com AddComponent<AudioSource>(), e atribua outputAudioMixerGroup no código.

O snapshot de pausa não muda o volume. Ele está tentando mexer num parâmetro que já recebeu SetFloat. Use outro parâmetro (o Lowpass acima) ou chame mixer.ClearFloat("MusicVolume") antes, sabendo que aí o slider perde o controle até o próximo SetFloat.

O volume volta ao padrão quando o jogo abre. Falta aplicar os valores salvos na cena inicial, como no AudioBootstrap.

Próximo passo

Monte o mixer com três grupos (Música, Efeitos e Interface), ligue os sliders e teste no build, não só no editor: o PlayerPrefs grava em lugares diferentes em cada plataforma, e é no build que você confirma que a preferência sobrevive a fechar e abrir o jogo.

Depois, vá para o lado do design: leia o guia de áudio design para jogos para decidir o que cada grupo deve soar e quando o mixer deve mudar de snapshot durante o jogo (combate, menu, cutscene). O código deste post já aguenta essas trocas; o que falta é decidir o momento de cada uma.

Perguntas frequentes

Qual a faixa de volume do Audio Mixer da Unity?

O volume de um grupo vai de -80 dB (silêncio) até +20 dB de ganho. O valor 0 dB é o volume original do som, sem corte nem reforço. Por isso o slider do menu não pode mandar 0 a 1 direto para o mixer: precisa converter para decibéis.

Por que o slider de volume da Unity não parece linear?

Porque o ouvido percebe volume em escala logarítmica. Se você mapeia o slider de forma linear para -80 a 0 dB, quase todo o curso do slider soa igual e o som some de repente no fim. Converter com Mathf.Log10(valor) * 20 deixa a resposta natural.

Como expor um parâmetro no Audio Mixer da Unity?

Selecione o grupo no Audio Mixer, clique com o botão direito no nome Volume no Inspector e escolha Expose Volume (of Música) to script. Depois, na lista Exposed Parameters do topo da janela do mixer, renomeie o parâmetro para um nome curto, como MusicVolume. É esse nome que vai no SetFloat.

Por que o snapshot parou de mudar o volume depois que usei SetFloat?

A documentação da Unity avisa que, depois de um SetFloat, aquele parâmetro deixa de ser controlado pelos snapshots. Use o snapshot para outros parâmetros (um filtro passa-baixa, por exemplo) ou chame ClearFloat para devolver o controle ao snapshot.