Hello!
I want to get an array of all the snapshots and groups in an audio mixer. Is that possible? I don’t think I see anything for that in the API.
Thanks!
Hello!
I want to get an array of all the snapshots and groups in an audio mixer. Is that possible? I don’t think I see anything for that in the API.
Thanks!
You could try FindObjectsOfType and then test for them being children of the AudioMixer with AudioMixer.FindMatchingGroups (group.name).
Same with snapshots. The api is pretty minimal.
I’m assuming you want this in editor mode?
I haven’t really worked much on editor scripting, so I’m not sure whether you can load mixers and use reflection to fetch that data in editor mode. I can fetch that data in playmode, though.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.Audio;
using System.Reflection;
using System;
public class FetchMixerData : MonoBehaviour {
public AudioMixer AudMix;
public AudioMixerGroup[] AudioMixerGroups;
public AudioMixerSnapshot[] AudioSnapshots;
public List<string> ExposedParams;
public List<string>[] GroupEffects;
// Use this for initialization
void Start () {
AudMix = Resources.Load ("MainMixer") as AudioMixer;
SyncToMixer ();
}
// Update is called once per frame
void Update () {
}
public void SyncToMixer()
{
Debug.Log("----Syncing to Mixer---------------------------------------------------------------------");
//Fetch all audio groups under MASTER
AudioMixerGroups = AudMix.FindMatchingGroups ("Master");
Debug.Log("----AudioGroups----------------------------------------------------");
for (int x = 0; x < AudioMixerGroups.Length; x++) {
//Debug.Log(AudioMixerGroups[x].name);
}
//PropertyInfo[] groupPropInf = AudioMixerGroups.GetType().GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.FlattenHierarchy);
//MemberInfo[] groupMemberInf = AudioMixerGroups.GetType().GetMembers(BindingFlags.Public|BindingFlags.Static|BindingFlags.Instance);
//FieldInfo[] groupFieldInf = AudioMixerGroups.GetType ().GetFields (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.FlattenHierarchy);
GroupEffects = new List<string>[AudioMixerGroups.Length];
for (int x = 0; x < AudioMixerGroups.Length; x++) {
Debug.Log("AudioGroup " + AudioMixerGroups[x].name + "---------------------------");
Debug.Log("----Effects----");
GroupEffects[x] = new List<string>();
Array effects = (Array)AudioMixerGroups[x].GetType().GetProperty("effects").GetValue(AudioMixerGroups[x], null);
for(int i = 0; i< effects.Length; i++)
{
var o = effects.GetValue(i);
string effect = (string)o.GetType().GetProperty("effectName").GetValue(o, null);
GroupEffects[x].Add(effect);
Debug.Log(effect);
}
}
//PropertyInfo[] PropInf = AudMix.GetType().GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.FlattenHierarchy);
//MemberInfo[] MemberInf = AudMix.GetType().GetMembers(BindingFlags.Public|BindingFlags.Static|BindingFlags.Instance);
//FieldInfo[] FieldInf = AudMix.GetType ().GetFields (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.FlattenHierarchy);
//Exposed Params
Array parameters = (Array)AudMix.GetType().GetProperty("exposedParameters").GetValue(AudMix, null);
Debug.Log("----ExposedParams----------------------------------------------------");
for(int i = 0; i< parameters.Length; i++)
{
var o = parameters.GetValue(i);
string Param = (string)o.GetType().GetField("name").GetValue(o);
ExposedParams.Add(Param);
Debug.Log(Param);
}
//Snapshots
AudioSnapshots = (AudioMixerSnapshot[])AudMix.GetType().GetProperty("snapshots").GetValue(AudMix, null);
Debug.Log("----Snapshots----------------------------------------------------");
for(int i = 0; i< AudioSnapshots.Length; i++)
{
Debug.Log(AudioSnapshots[i].name);
}
//PropertyInfo[] snapPropInf = Snapshots.GetType().GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.FlattenHierarchy);
//MemberInfo[] snapMemberInf = Snapshots.GetType().GetMembers(BindingFlags.Public|BindingFlags.Static|BindingFlags.Instance);
//FieldInfo[] snapFieldInf = Snapshots.GetType ().GetFields (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.FlattenHierarchy);
}
}
If anyone can get it working in editor scripting, can you post here?
This is quite a popular question, and 99% of people would want to get this information from editor mode.
I’m not sure what wouldn’t be working – everything in that script seemed to work in the Editor just fine.
Any idea how to get the value for the Attenuation on each snapshot?
It works in the editor in playmode, but most people will want that information in the editor in edit mode.
Not too sure about snapshot attenuation or any of those details. I was just trying to see if I could get the basic info at the time.
You need to set breakpoints and mouse over the objects being fetched at runtime.
Then you can see the structure and try to find what you are looking for
I’m new to C# and Reflection and such – what do you mean “mouse over the objects being fetched at runtime”?
I have expanded the code:
PropertyInfo[] snapPropInf = audioSnapshots.GetType().GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.FlattenHierarchy);
MemberInfo[] snapMemberInf = audioSnapshots.GetType().GetMembers(BindingFlags.Public|BindingFlags.Static|BindingFlags.Instance);
FieldInfo[] snapFieldInf = audioSnapshots.GetType ().GetFields (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.FlattenHierarchy);
Debug.Log ("snapPropInf: " + snapPropInf.Length);
for (int pi = 0; pi < snapPropInf.Length; pi++) {
Debug.Log ("snapPropInf[" + pi + "]: " + snapPropInf [pi]);
}
Debug.Log ("snapMemberInf: " + snapMemberInf.Length);
for (int mi = 0; mi < snapMemberInf.Length; mi++) {
Debug.Log ("snapMemberInf[" + mi + "]: " + snapMemberInf [mi]);
}
Debug.Log ("snapFieldInf: " + snapFieldInf.Length);
for (int fi = 0; fi < snapFieldInf.Length; fi++) {
Debug.Log ("snapFieldInf[" + fi + "]: " + snapFieldInf [fi]);
}
However, I’m not really sure how to read the information the console is providing.
For instance, I’m thinking that’s how you knew to look for “effects” and “effectName” in this code:
groupEffects = new List<string>[audioGroups.Length];
for (int x = 0; x < audioGroups.Length; x++) {
Debug.Log ("AudioGroup " + audioGroups[x].name);
groupEffects[x] = new List<string>();
Array effects = (Array)audioGroups[x].GetType().GetProperty("effects").GetValue(audioGroups[x], null);
for(int i = 0; i< effects.Length; i++)
{
var o = effects.GetValue(i);
string effect = (string)o.GetType().GetProperty("effectName").GetValue(o, null);
groupEffects[x].Add(effect);
Debug.Log(effect);
}
}
Is that right? Or maybe I’m looking at this all wrong?
It means set a breakpoint after you’ve retrieved all members, properties, and fields. Then you can inspect them one-by-one. If you’re using Visual Studio, you can just mouse over the variables snapPropInfo (etc) and check out the values reflection returned. In MonoDevelop, I think you’d have to check in the Locals tab.
Got it – I crashed unity, but did see a lot of stuff in the locals tab. Not sure yet how to actually read it…but this will have to wait until after some unhealthy food and watching the only football game I watch each year!
If you need to execute a method to inspect the value of a PropertyInfo object, you can just execute this code in the Immediate Window. Both IDEs have that feature.
//assuming some object called AudioSnapshots is in scope
int propertyIndex = 0;
int snapShotIndex = 0;
snapPropInfo = typeof(AudioMixerSnapshot).GetProperties();
snapPropInfo[propertyIndex].GetValue(AudioSnapshots[snapShotIndex], null);
And you can change the indexes to change the objects and properties you’re inspecting.
Ok, this may be above my pay grade right now, but I’ll look into it more either tonight or tomorrow.
For now, I have a some-what working script: http://infinitypbr.com/snapshotexporter.unitypackage
The Problem(s):
To Use:
If anyone is interested in trying it out and figuring out what’s going on with the problems, the help would be appreciated!
(The goal is to allow, with one click, the exporting of all snapshots from an Audio Mixer. This way you can mix a bunch of versions of a song, and then get all of them as single .wav files to use in the game, so you don’t need to have all the layers)
* Potential work around: I know the volume of each snapshot during play mode. The script can run during play mode. So if I link it to other info from the scene, it could control the scene – basically load the snapshot in the scene, then export (knowing the volume levels), then load the next snapshot etc.
This isn’t the best since that means you (1) have to be in play mode and (2) have to have the file structure set up…but I think it would work.
Update!
Ok, I fixed the volume problem – there was a line that divided the output by the number of clips. Turns out thats not needed.
Also, I’m able to export based on the current mix in edit mode.
Unfortunately, I’m not sure how to switch the mix via code in edit mode. Even in play mode, where I have code that switches the snapshot, it all happens the same frame so the values don’t seem to update, and all exports are the same.
Transitioning to a new snapshot doesn’t work in editor mode at all via code.
So my new thoughts are…
Another Update!
Now I can export a single snapshot (using a custom name) in edit mode. User must select the snapshot in the Audio Mixer first.
And then in play mode, a new option appears to batch export all the snapshots.
It works! That’s nice.
BUT! There’s a new problem. Popping. It doesn’t always happen, but there’s a lot of popping depending on what’s playing, especially timpani hits. I tried lowering the overall output volume, but it only got quieter without removing the popping.
I’ll have to figure this one out, since it’s pointless if the quality of the output pops.
If you’re in the editor, this will work -
This example assumes 2 things:
var assetsAtPath = AssetDatabase.LoadAllAssetRepresentationsAtPath("Assets/Audio/Ambience/Music.mixer");
Debug.Log($"assetsAtPath: {assetsAtPath.Length}");
foreach (var assetRepresentation in assetsAtPath)
{
AudioMixerSnapshot snapshot = assetRepresentation as AudioMixerSnapshot;
if (snapshot != null)
{
Debug.Log($"mixer snapshots: {snapshot.name}");
}
}
output:
mixer snapshots: NoVolume```