Displaying an audio waveform in the editor

Unity’s UI includes a display of audio waveforms in it’s preview. Is there a simple way to display this, without parsing out the audio file myself?

I made a simpler script to create a waveform texture for GUI elements:

public Texture2D PaintWaveformSpectrum(AudioClip audio, float saturation, int width, int height, Color col) {
    Texture2D tex = new Texture2D(width, height, TextureFormat.RGBA32, false);
    float[] samples = new float[audio.samples];
    float[] waveform = new float[width];
    audio.GetData(samples, 0);
    int packSize = ( audio.samples / width ) + 1;
    int s = 0;
    for (int i = 0; i < audio.samples; i += packSize) {
        waveform ~~= Mathf.Abs(samples*);*~~

s++;
}

for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
tex.SetPixel(x, y, Color.black);
}
}

for (int x = 0; x < waveform.Length; x++) {
for (int y = 0; y <= waveform[x] * ((float)height * .75f); y++) {
tex.SetPixel(x, ( height / 2 ) + y, col);
tex.SetPixel(x, ( height / 2 ) - y, col);
}
}
tex.Apply();

return tex;
}
It’s a modified version of @Breakypower’s code in this thread: https://answers.unity.com/questions/699595/how-to-generate-waveform-from-audioclip.html*~~
It produces very lovely results for my purposes:
~~
[132224-capture.png*
|132224]~~
~~

Since the question got bumped here are the two ways the default inspector draws the wave preview:

  • AssetPreview.GetAssetPreview(audioClip);
  • AudioUtil.GetWaveFormFast(audioClip, 1, 0, audioClip.samples, r.width, r.height);

Both methods will return a Texture2D. The first one is used when the inspector width is smaller than 100 pixels, the second is used when it’s greater or equal to 100.

However the AudioUtil class is an internal class of the editor so you can’t use it directly without reflection.

What I did was use AudioListener.GetOutputData, and used the output array in a GL drawing function to draw the waveform to the screen. Here’s the script:

using UnityEngine;
using System.Collections;

public class ScopeViewer : MonoBehaviour {
	float[][] audioData = new float[2][];
	Material glMat;
	
	void Start () {
		if (!glMat) {
			audioData[0] = new float[2048];
			audioData[1] = new float[2048];
			Shader glSh = Shader.Find("Hidden/Internal-Colored");
			glMat = new Material(glSh);
			glMat.hideFlags = HideFlags.HideAndDontSave;
			glMat.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
			glMat.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
			glMat.SetInt("_Cull", (int)UnityEngine.Rendering.CullMode.Off);
			glMat.SetInt("_ZWrite", 0);
		}
	}

	void OnRenderObject () {
		AudioListener.GetOutputData(audioData[0], 0);
		AudioListener.GetOutputData(audioData[1], 1);
		float[] highestOutput = new float[2];
		highestOutput[0] = 0;
		highestOutput[1] = 0;
		for (int i=0; i<audioData[0].Length; i++) {
			if (Mathf.Abs(audioData[0]_) > highestOutput[0]) highestOutput[0] = Mathf.Abs(audioData[0]*);*_

if (Mathf.Abs(audioData[1]) > highestOutput[1]) highestOutput[1] = Mathf.Abs(audioData[1]);
* }*
* if (highestOutput[0] == 0) highestOutput[0] = 1;*
* if (highestOutput[1] == 0) highestOutput[1] = 1;*
* glMat.SetPass(0);*
* GL.PushMatrix();*
* GL.MultMatrix(transform.localToWorldMatrix);*
* GL.Begin(GL.QUADS);*
* GL.Color(Color.white);*
* GL.Vertex(new Vector3(-0.525f, 0.55f, 0));*
* GL.Vertex(new Vector3(0.525f, 0.55f, 0));*
* GL.Vertex(new Vector3(0.525f, -0.55f, 0));*
* GL.Vertex(new Vector3(-0.525f, -0.55f, 0));*
* GL.Color(Color.black);*
* GL.Vertex(new Vector3(-0.5f, 0.5f, 0));*
* GL.Vertex(new Vector3(0.5f, 0.5f, 0));*
* GL.Vertex(new Vector3(0.5f, -0.5f, 0));*
* GL.Vertex(new Vector3(-0.5f, -0.5f, 0));*
* GL.End();*
* GL.Begin(GL.LINES);*
* GL.Color(Color.white);*
* for (int i=0; i<audioData[0].Length/5-1; i++) {*
_ GL.Vertex(new Vector3((float)i/(audioData[0].Length/5)-0.5f, 0.5faudioData[0]/highestOutput[0], 0));
GL.Vertex(new Vector3((float)(i+1)/(audioData[0].Length/5)-0.5f, 0.5faudioData[0][i+1]/highestOutput[0], 0));

* }
for (int i=0; i<audioData[1].Length/5-1; i++) {
GL.Vertex(new Vector3((float)i/(audioData[1].Length/5)-0.5f, 0.5faudioData[1]/highestOutput[1], 0));

GL.Vertex(new Vector3((float)(i+1)/(audioData[1].Length/5)-0.5f, 0.5faudioData[1][i+1]/highestOutput[1], 0));
}
GL.End();
GL.PopMatrix();
}
}*_

My solution (Japanese page):

AudioUtil’s wrapper:

How to render the waveform: