Changes to in-editor waveform generation in 5.4?

My Unity plugin, LipSync Pro, uses the AudioUtil class through reflection to get a waveform preview texture of AudioClips to display in the editor, but I've noticed this is broken in the 5.4 beta. The GetWaveForm method seems to have gone entirely, and all I could find in the release notes is this:
Audio: Fixed audio clip waveform preview rendering sync issues after import and improved the way the waveforms are being rendered to be more dynamic and reveal more detail.

I get that quiet changes to internal, hidden classes like AudioUtil are to be expected so I'm not complaining, but the ability to get this waveform texture is pretty vital for me - is there any way I could get some info on how the new waveform previews are generated?


You could try this which displays the selected audioclip in a separate window, but it still relies on reflection, so no guarantees this won't change at some point:

using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Reflection;

public class RenderWave : EditorWindow
    public static void ShowWindow()

    void OnGUI()
        var clip = Selection.activeObject as AudioClip; if (clip == null) return;
        var path = AssetDatabase.GetAssetPath (clip); if (path == null) return;
        var importer = AssetImporter.GetAtPath (path); if (importer == null) return;
        var assembly = Assembly.GetAssembly (typeof (AssetImporter)); if (assembly == null) return;
        var type = assembly.GetType ("UnityEditor.AudioUtil"); if (type == null) return;
        var AudioUtil_GetMinMaxData = type.GetMethod ("GetMinMaxData"); if (AudioUtil_GetMinMaxData == null) return;
        var minMaxData = AudioUtil_GetMinMaxData.Invoke (null, new object[] { importer }) as float[]; if (minMaxData == null) return;

        var r = EditorGUILayout.GetControlRect (GUILayout.ExpandWidth (true), GUILayout.ExpandHeight (true));
        var curveColor = new Color (255 / 255f, 168 / 255f, 7 / 255f);
        int numChannels = clip.channels;
        int numSamples = minMaxData.Length / (2 * numChannels);
        float h = (float)r.height / numChannels;
        for (int channel = 0; channel < numChannels; channel++)
            var channelRect = new Rect (r.x, r.y + channel * h, r.width, h);
                delegate(float x, out Color col, out float minValue, out float maxValue)
                    col = curveColor;
                    float p = Mathf.Clamp(x * (numSamples - 2), 0.0f, numSamples - 2);
                    int i = (int)Mathf.Floor(p);
                    int offset1 = (i * numChannels + channel) * 2;
                    int offset2 = offset1 + numChannels * 2;
                    minValue = Mathf.Min(minMaxData[offset1 + 1], minMaxData[offset2 + 1]);
                    maxValue = Mathf.Max(minMaxData[offset1 + 0], minMaxData[offset2 + 0]);
                    if (minValue > maxValue) { float tmp = minValue; minValue = maxValue; maxValue = tmp; }

Brilliant, thanks for that! Looks like a move towards making this more easily accessible too, so that's good.