Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Audio Cannot Find Matching Groups For Audio Mixer

Discussion in 'Audio & Video' started by Vennnot, Oct 16, 2019.

  1. Vennnot

    Vennnot

    Joined:
    Jun 21, 2017
    Posts:
    8
    Code (CSharp):
    1. z.source.outputAudioMixerGroup = audioMixer.FindMatchingGroups("SFX")[0];
    This line of code works but I don't know why these two don't:

    Code (CSharp):
    1. z.source.outputAudioMixerGroup = audioMixer.FindMatchingGroups("animation")[0];
    2.  
    3. z.source.outputAudioMixerGroup = audioMixer.FindMatchingGroups("music")[0];
    They are all siblings and have the same parent mixer/master volume.

    Could someone help me understand what is happening? Unity says the array is out of range but I do not understand what that means.
     
  2. Hikiko66

    Hikiko66

    Joined:
    May 5, 2013
    Posts:
    1,304
    You're fetching the first element of the array that unity returns from the FindMatchingGroups function.
    Code (csharp):
    1. [0]
    That is the first element. Unity is saying that there is no such element, so, it's saying it can't find anything. It's returning an empty array. No elements.

    Is your case the same? Is it "animation" or is it really "Animation"? That matters.

    If it is the same, can you check whether you can see the new mixergroups in the list when you click on any audiosource output field in the inspector, as if you were going to manually assign it at design time?
     
    Last edited: Oct 17, 2019
  3. Vennnot

    Vennnot

    Joined:
    Jun 21, 2017
    Posts:
    8
    Yes it is exactly the same, the exact code looks like this:

    Code (CSharp):
    1.  
    2.     void Update()
    3.     {
    4.         if(optionsMenu.musicAltered || optionsMenu.SFXAltered || optionsMenu.animationsAltered)
    5.         {
    6.             print("got here!");
    7.         foreach(Sound s in sounds)
    8.         {
    9.             s.source = gameObject.AddComponent<AudioSource>();
    10.             s.source.clip = s.clip;
    11.      
    12.         if(optionsMenu.musicAltered)
    13.         {
    14.         if (s.getTagged() == "music")
    15.         {          
    16.             print("adjusting music!");
    17.             s.source.outputAudioMixerGroup = audioMixer.FindMatchingGroups("music")[0];
    18.             s.volume = ((GetVolume("music")/80)+1);
    19.             s.source.volume = s.volume;
    20.         }
    21.         }
    22.         if(optionsMenu.SFXAltered)
    23.         {
    24.         if (s.getTagged() == "SFX")
    25.         {          
    26.             print("adjusting SFX!");
    27.             s.source.outputAudioMixerGroup = audioMixer.FindMatchingGroups("SFX")[0];
    28.             s.volume = ((GetVolume("SFX")/80)+1);
    29.             s.source.volume = s.volume;
    30.         }
    31.         }
    32.         if(optionsMenu.animationsAltered)
    33.         {
    34.         if (s.getTagged() == "animation")
    35.         {          
    36.             s.source.outputAudioMixerGroup = audioMixer.FindMatchingGroups("animation")[0];
    37.             s.volume = ((GetVolume("animation")/80)+1);
    38.             s.source.volume = s.volume;
    39.         }
    40.         }
    41.         }
    42.     }
    43.     }
    For some reason only the SFX one works but all three of them are the children of the masterMixer and music was the first one that was created so I don't understand why 0 works for SFX. The strings are correct. It has nothing to do with them.



    Could you elaborate on that last part again?

    The exact error it is throwing me is IndexOutOfRangeException: Index was outside the bounds of the array. That is for music and the animation thing not for SFX
     
  4. cropotowa

    cropotowa

    Joined:
    Oct 17, 2019
    Posts:
    1
    I have an intelligent man who understands this, I will give him your contact)
     
  5. Hikiko66

    Hikiko66

    Joined:
    May 5, 2013
    Posts:
    1,304
    Well, you can add an audiosource to a gameobject.
    Select any gameobject, in the inspector on the right click AddComponent and choose audiosource. Now you have an empty audiosource on that gameobject.

    In that audiosource you can select which mixer it will be sent to by modifying its output parameter. You can do this at design time in the inspector, or you can assign a mixer at runtime via script (what you are doing). We really just want to see if these mixer channels show up in the inspector as options.
    It's the second parameter in this picture. Clicking that little circle next to the output field should show all available mixers to send the audiosource to.
    https://docs.unity3d.com/uploads/Main/AudioSourceInspector.png

    You will want to know how to assign these things in the inspector before you start trying to hook them up in code.
    Please see this tutorial in which he shows you how to set up the relationship between audiosources and audiomixers in the inspector:



    That said, take a look at the screenshot you posted.
    You have the mixers on the left, "Master", "Music", "SFX" and the other one is hidden by the exposed parameters dropdown, I assume it's "Animation".
    So when you are finding the mixers, you should type those exactly as they are.

    Instead, what you are looking at is the exposed parameters which are lowercase. These are not mixers, these are just parameters pointing to very specific things that you can access via script at runtime. You don't need to expose the mixers themselves, because you can access them via FindMatchingGroups, or hook them up at design time.

    You have exposed the attentuation/volume parameters of 3 of the mixers. To make things less confusing, I would rename the exposed parameters to "AnimationMixerVolume", "MusicMixerVolume", "SFXMixerVolume"..
    Something that differentiates it from the mixers themselves, and tells us exactly what the parameter is pointing at.
    You can click the exposed parameter dropdown and right click an exposed param and select rename.

    An exposed parameter could also be pointing at a parameter on an effect on a mixer, like the cutoff of a low pass filter, for example.
    So you'd always call them something descriptive, MasterMixerLPFilterCutoff etc.
    Then you'd be able to fetch or change that filter cutoff in code at runtime, because it's an exposed parameter.

    For more on Exposed Parameters, and effectively a tutorial on what you're trying to do, please see:


    Anyway, I'd change the code like so.. I'd have a single place where I define my mixer names and exposed parameters so that if I change the names later, I only need to change them in one place, not throughout my code. These would be constants, because they should not be allowed to change while the code is running.

    Code (csharp):
    1.  
    2. //Mixer Names
    3. private const string MasterMixerName = "Master";
    4. private const string MusicMixerName = "Music";
    5. private const string SFXMixerName = "SFX";
    6. private const string AnimationMixerName = "Animation";
    7.  
    8. //Exposed Parameter Names
    9. private const string MasterMixerVolumeParam = "MasterMixerVolume";
    10. private const string AnimationMixerVolumeParam = "AnimationMixerVolume";
    11. private const string MusicMixerVolumeParam = "MusicMixerVolume";
    12. private const string SFXMixerVolumeParam = "SFXMixerVolume";
    13.  
    14. //Cache the AudioMixers so you only need to fetch them once at the start
    15. private AudioMixer MasterMixer;
    16. private AudioMixer MusicMixer;
    17. private AudioMixer SFXMixer;
    18. private AudioMixer AnimationMixer;
    19.  
    20. ...
    21.  
    22. //In Awake or Start, find and assign the mixers
    23. MasterMixer = audioMixer.FindMatchingGroups(MasterMixerName)[0];
    24. MusicMixer = audioMixer.FindMatchingGroups(MusicMixerName)[0];
    25. SFXMixer = audioMixer.FindMatchingGroups(SFXMixerName)[0];
    26. AnimationMixer = audioMixer.FindMatchingGroups(AnimationMixerName)[0];
    27.  
    ALTERNATIVELY--------------------
    You can assign the mixers directly in the inspector at design time, without dealing with mixer names in your code, and you wouldn't need to find and assign them at runtime, you wouldn't need to worry about changing your code when you rename them etc. It depends on whether you need to assign them at runtime for a particular reason or not. I assume you actually did this with the Master mixer.

    Code (csharp):
    1.  
    2. public AudioMixer MasterMixer;
    3. public AudioMixer MusicMixer;
    4. public AudioMixer SFXMixer;
    5. public AudioMixer AnimationMixer;
    6.  
    Then just select the corresponding mixers in the inspector for those fields and everything will be hooked up.
    --------------------------------------------

    Now let's talk about what you're doing here:
    Code (CSharp):
    1. s.source.outputAudioMixerGroup = audioMixer.FindMatchingGroups("animation")[0];
    2.             s.volume = ((GetVolume("animation")/80)+1);
    3.             s.source.volume = s.volume;
    I assume that GetVolume fetches the exposed parameter volume from the mixer?

    This doesn't make sense to me.
    If your audiosource is assigned to a mixer, the mixer volume will affect the volume of the audiosource automatically.
    You can still modify the volume of an audiosource independently, but what you seem to be trying to do (manually assign a mixer volume to an audiosource) isn't necessary and doesn't make sense either. What about if your audio sources need to be different volumes, but they need to be affected by the mixer volume?

    Basically this is what the audiomixer should be doing behind the scenes to the volumes of audio from audiosources assigned to it.

    Let's say we have an audiosource at volume 1 (100%).
    Let's say that it's assigned to an audiomixer that is at volume 1 (100%)
    it's multiplying those volumes to get the target volume for the audio. 1 * 1 = 1 (100% volume)

    Let's say we have an audiosource at volume 0.5 (50%).
    Let's say that it's assigned to an audiomixer that is at volume 1 (100%)
    it's multiplying those volumes to get the target volume for the audio. 0.5 * 1 = 0.5 (50% volume)

    Let's say we have an audiosource at volume 0.5 (50%).
    Let's say that it's assigned to an audiomixer that is at volume 0.5 (50%)
    it's multiplying those volumes to get the target volume for the audio. 0.5 * 0.5 = 0.25 (25% volume)

    If you had an audiosource at full volume 1 (100%)
    And it was going into a mixer at full volume 1 (100%)
    And that mixer was going into the master mixer, and the master mixer was at 0.0 (0%)
    that's 1 * 1 * 0 = 0 (0%) target volume.

    This is ignoring that the audiosource volume is linear 0 -1 and the mixer volume is in DB. That's why you have that weird calculation I suppose "/80)+1"


    So, if you want to change an audiomixer volume at runtime and have the audiosources assigned to that mixer react to that volume change, you can just modify the mixer volume by setting its exposed parameter for volume. You don't need to do anything with the audiosource volume, it's automatic.


    Code (CSharp):
    1.  
    2.  
    3. //Sliders fields to control the volume of mixers at runtime via the inspector. Range -80DB to 20DB
    4. [Range(-80, 20)]
    5. public float MasterMixerVolumeController = 0 f;
    6. [Range(-80, 20)]
    7. public float MusicMixerVolumeController = 0 f;
    8.  
    9. //Float volume fetched from the mixers exposed parameters to display the current volume in DB
    10. public float MasterMixerVolumeFromMixer;
    11. public float MusicMixerVolumeFromMixer;
    12.  
    13. //Mixer Names
    14. private const string MasterMixerName = "Master";
    15. private const string MusicMixerName = "Music";
    16.  
    17. //Exposed Parameter Names
    18. private const string MasterMixerVolumeParam = "MasterMixerVolume";
    19. private const string MusicMixerVolumeParam = "MusicMixerVolume";
    20.  
    21. //Cache the AudioMixers so you only need to fetch them once at the start
    22. private AudioMixer MasterMixer;
    23. private AudioMixer MusicMixer;
    24.  
    25. void Start() {
    26.  //Find and assign Mixers
    27.  MasterMixer = audioMixer.FindMatchingGroups(MasterMixerName)[0];
    28.  MusicMixer = audioMixer.FindMatchingGroups(MusicMixerName)[0];
    29.  
    30.  //Run through audiosources and assign appropriate mixers
    31.  foreach(Sound s in sounds) {
    32.   s.source = gameObject.AddComponent < AudioSource > ();
    33.   s.source.clip = s.clip;
    34.   if (s.getTagged() == "music") {
    35.    s.source.outputAudioMixerGroup = MusicMixer;
    36.   } else {
    37.    s.source.outputAudioMixerGroup = MasterMixer;
    38.   }
    39.  }
    40.  
    41. }
    42.  
    43. void Update() {
    44.  //Master
    45.  //Set the volume of the master mixer via exposed parameter based on the value of the slider
    46.  MasterMixer.SetFloat(MasterMixerVolumeParam, MasterMixerVolumeController);
    47.  //Get the volume of the master mixer via exposed parameter and output it into the variable passed.
    48.  MasterMixer.GetFloat(MasterMixerVolumeParam, out MasterMixerVolumeFromMixer);
    49.  
    50.  //Music
    51.  //Set the volume of the master mixer via exposed parameter based on the value of the slider
    52.  MusicMixer.SetFloat(MusicMixerVolumeParam, MusicMixerVolumeController);
    53.  //Get the volume of the master mixer via exposed parameter and output it into the variable passed.
    54.  MusicMixer.GetFloat(MusicMixerVolumeParam, out MusicMixerVolumeFromMixer);
    55. }
    56.  
    Then when you click on the gameobject with a script that looks something like this attached, it would have sliders and float fields for the master and music mixers
    The sliders can in play mode in the editor control (set) the Mixer volumes. The floats just fetch and display the current volume of the respective Mixer. Just so we have setting and getting values from the mixer covered.

    The mastermixer volume slider should affect all audiosources that are being routed through it, or any submixers that route to master, including the music mixer.

    The musicmixer volume slider should only affect audiosources that are being routed through the music mixer
     
    Last edited: Oct 18, 2019
    dyupa likes this.