Skip to content

Instantly share code, notes, and snippets.

@fuzzblob
Created October 29, 2018 22:19
Show Gist options
  • Save fuzzblob/f87ab206852deff2edb2726fc89472f0 to your computer and use it in GitHub Desktop.
Save fuzzblob/f87ab206852deff2edb2726fc89472f0 to your computer and use it in GitHub Desktop.
Unity Waveform UI with customizable resolution
/*
// UI inspector example implementation
Rect waveformRect = GUILayoutUtility.GetRect(waveformSize.x, waveformSize.y, GUIStyle.none);
EditorUtil.Waveform(waveformRect, clip, waveformSize);
float playMarker = 0f; // replace with a 0-1 seek position
if (playMarker >= 0f) {
Rect progressRect = new Rect(waveformRect);
float width = progressRect.width * playMarker;
progressRect.width = Mathf.Clamp(width, 6, width);
GUI.Box(progressRect, "", "SelectionRect");
}
*/
// UI method implementation
public class EditorUtil
{
public static void Waveform(Rect waveformRect, AudioClip clip, Vector2 size, float playMarker = -1f, float[] beatMarkers = null, int downBeat = 0)
{
// can't load data when audio is set to streaming
if(clip.loadState != AudioDataLoadState.Loaded)
clip.LoadAudioData();
// only do expensive calcs on repaint
if (Event.current.type != EventType.Repaint)
return;
Texture2D waveformTexture = GetWaveformTexture(clip, size); // AssetPreview.GetAssetPreview(clip);
if (waveformTexture == null)
return;
GUIStyle tempStyle = new GUIStyle();
tempStyle.normal.background = waveformTexture;
tempStyle.Draw(waveformRect, GUIContent.none, false, false, false, false);
}
private static Color waveformBG = new Color(0.25f, 0.25f, 0.25f);
private static Color waveformColor = new Color(1f, 0.6f, 0.2f);
public static Texture2D GetWaveformTexture(AudioClip clip, Vector2 size) {
// get sample data
float[] samples = new float[clip.samples * clip.channels];
if (clip.GetData(samples, 0) == false)
return null;
// setup texture
int width = (int) size.x;
int height = (int) size.y;
Texture2D texture = new Texture2D(width, height);
// get sampleIntensity
int resolution = clip.samples / width;
// draw color arracy per pixel in width
Color[] colors = new Color[height];
float midHeight = height / 2f;
float sampleComp = 0f;
for (int i = 0; i < width; i++) {
// get wave intensity
float sampleChunk = 0;
for (int ii = 0; ii < resolution; ii++)
sampleChunk += Mathf.Abs(samples[(i * resolution) + ii]);
sampleChunk = sampleChunk / resolution * 1.5f;
for (int h = 0; h < height; h++) {
// get value of height relative to totalHeight
if (h < midHeight)
sampleComp = Mathf.InverseLerp(midHeight, 0, h);
else
sampleComp = Mathf.InverseLerp(midHeight, height, h);
// corralate to sample height
if (sampleComp > sampleChunk)
colors[h] = waveformBG;
else
colors[h] = waveformColor;
}
// set pixels
texture.SetPixels(i, 0, 1, height, colors);
}
// push to graphics card
texture.Apply();
// return finished texture
return texture;
}
}
@zatrgo
Copy link

zatrgo commented Oct 28, 2024

I'm kinda amazed that this still works after 6 years. This is exactly what I needed... or, it would be, if it didn't draw exactly half of the audioclip I put in. I can't tell myself why it's getting exactly half the length, so if you're still active, would you have any idea?

@fuzzblob
Copy link
Author

My first thought (not having seen this code in a long time) is that it might be multi channel audio not being handled correctly. Like in line 46 is clip.samples referring to all samples or just the count of one channel? I'm not sure what exactly is wrong but thats my first guess...

@zatrgo
Copy link

zatrgo commented Oct 28, 2024

Looks like that was the case after all, tysm! I changed it to int resolution = (clip.samples * clip.channels) / width; and it's working now! Having only two channels to work with definitely made it simpler lol

@fuzzblob
Copy link
Author

amazing! another alternative would be to render whichever channel is louder at that sample. So reading the amount of channels worth of samples to compare and select the largest abs(), or to render them in different colours at the same location. Thanks for reaching out and raising the issue :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment