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

How to create waveform texture from AudioClip?

Discussion in 'Scripting' started by Rukas90, Feb 18, 2019.

  1. Rukas90

    Rukas90

    Joined:
    Sep 20, 2015
    Posts:
    169
    Hello,
    I've been trying to generate the waveform from the audioclip to a texture, but I ran into one issue.

    For some reason the waveform is not drawn entirely. I created this really simple sound to check and it appears that it didn't generated waveform from the entire track, but only from half or less of the track. Could someone give some help on this? Thank you

    I found the code below from here: https://answers.unity.com/questions/699595/how-to-generate-waveform-from-audioclip.html

    Code (CSharp):
    1. public Texture2D PaintWaveformSpectrum(AudioClip audio, float saturation, int width, int height, Color col) {
    2.       Texture2D tex = new Texture2D(width, height, TextureFormat.RGBA32, false);
    3.       float[] samples = new float[audio.samples];
    4.       float[] waveform = new float[width];
    5.       audio.GetData(samples, 0);
    6.       int packSize = ( audio.samples / width ) + 1;
    7.       int s = 0;
    8.       for (int i = 0; i < audio.samples; i += packSize) {
    9.           waveform[s] = Mathf.Abs(samples[i]);
    10.           s++;
    11.       }
    12.  
    13.       for (int x = 0; x < width; x++) {
    14.           for (int y = 0; y < height; y++) {
    15.               tex.SetPixel(x, y, Color.black);
    16.           }
    17.       }
    18.  
    19.       for (int x = 0; x < waveform.Length; x++) {
    20.           for (int y = 0; y <= waveform[x] * ((float)height * .75f); y++) {
    21.               tex.SetPixel(x, ( height / 2 ) + y, col);
    22.               tex.SetPixel(x, ( height / 2 ) - y, col);
    23.           }
    24.       }
    25.       tex.Apply();
    26.  
    27.       return tex;
    28.   }
    Code (CSharp):
    1. public class Draw : MonoBehaviour
    2. {
    3.     public int width = 500;
    4.     public int height = 100;
    5.     public Color waveformColor = Color.green;
    6.     public Color bgColor = Color.green;
    7.     public float sat = .5f;
    8.  
    9.     [SerializeField] Image img;
    10.     [SerializeField] AudioClip clip;
    11.  
    12.     void Start()
    13.     {
    14.         Texture2D texture = TestAudioWaveformDraw.PaintWaveformSpectrum(clip, sat, width, height, waveformColor, bgColor);
    15.         img.overrideSprite = Sprite.Create(texture, new Rect(0f, 0f, texture.width, texture.height), new Vector2(0.5f, 0.5f));
    16.     }
    17. }
    Result:
    Generated Waveform:

    Actual Waveform:
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,520
    Try it with a monaural track... I'm gonna guess it's something to do with how you're handling the stereo data.

    You can trivially reimport your stereo clip as mono by ticking the "Force to Mono" checkbox in the Unity inspector for that clip.

    You could instead also trivially try multiplying packSize by 2 before using it, see if you get the entire clip.
     
    Rukas90 likes this.
  3. Rukas90

    Rukas90

    Joined:
    Sep 20, 2015
    Posts:
    169
    Hey, thanks! Turning clips to 'Force to Mono' did the trick! ;)

    I wanted to ask you one more thing if it's okay, is there a possibility to turn clip to be in mono through script? I am creating this music player and I will be sending clips that are most likely won't be in mono. Is there a way to turn them to mono in script? Thanks again! :)
     
    Last edited: Feb 19, 2019
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,520
    Sure: the AudioClip object has a .channels property to tell if it is stereo or mono. if it is stereo, you can simply step over every other sample to take one or the other (left/right).

    Alternately you can average the sample from both channels I guess... I'd defer to an audio engineer as far as the best strategies for blending a stereo track down to mono. Each way is going to have advantages and drawbacks as to what it does to the quality of the underlying sound. I think Audacity just averages the left/right samples but I'm not 100% sure.
     
    Bunny83 likes this.
  5. Rukas90

    Rukas90

    Joined:
    Sep 20, 2015
    Posts:
    169
    Thanks for the tip!
    I only wanted the Mono version of a track for the waveform, the sound that will be playing will be the original file, so I won't be changing any of the user configured settings to change the overall sound quality.

    So what I did in the end is simply checked if the track is stereo and if so I cloned the clip and removed right channel so it only has left. I think it could be either one, just simply turned it to mono. And then used this mono clip to draw the waveform. And that fixed my issue now. :)
    At least I hope so, you never know what might pop up :D

    Again thanks for the help I appreciate it!

    Here's how I cloned the track, if someone needs it. I'm not sure if it's the best way, but it did the trick!
    Code (CSharp):
    1. public AudioClip CloneAudioClip(AudioClip audioClip, string name)
    2.     {
    3.         AudioClip newAudioClip = AudioClip.Create(name, audioClip.samples, audioClip.channels, audioClip.frequency, false);
    4.         float[] copyData = new float[audioClip.samples * audioClip.channels];
    5.         audioClip.GetData(copyData, 0);
    6.  
    7.         List<float> monoData = new List<float>();
    8.         for (int i = 0; i < copyData.Length; i+=2)
    9.         {
    10.             monoData.Add(copyData[i]);
    11.         }
    12.         newAudioClip.SetData(monoData.ToArray(), 0);
    13.  
    14.         return newAudioClip;
    15.     }
     
    Kurt-Dekker likes this.
  6. CDAfonso

    CDAfonso

    Joined:
    Sep 16, 2019
    Posts:
    26
    Hello

    Hello Rukas90,

    Do you create an empty image and then assign this script to it?

    Can you leave here the whole code?
    Thanks
     
  7. ksam2

    ksam2

    Joined:
    Apr 28, 2012
    Posts:
    1,079
    Can you please put all the script? I can't make it to work.
     
  8. Crossway

    Crossway

    Joined:
    May 24, 2016
    Posts:
    507
    Hi, did you find the whole code? I need this too
     
  9. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,520
    Please don't reply to old threads. It's against forum rules. If you have an issue, start your own post... it's FREE!

    The code posted at this link works fine:

    https://answers.unity.com/questions/699595/how-to-generate-waveform-from-audioclip.html

    I just tested it and it works precisely as posted, no changes at all.

    If you're having an issue with it, START YOUR OWN THREAD.

    How to report your problem productively in the Unity3D forums:

    http://plbm.com/?p=220

    How to understand compiler and other errors and even fix them yourself:

    https://forum.unity.com/threads/ass...3-syntax-error-expected.1039702/#post-6730855

    If you post a code snippet, ALWAYS USE CODE TAGS:

    How to use code tags: https://forum.unity.com/threads/using-code-tags-properly.143875/
     
    Crossway likes this.
  10. Crossway

    Crossway

    Joined:
    May 24, 2016
    Posts:
    507
    Thanks, sorry but how does it works? I mean where should I attach this script
     
  11. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,520
    This is SUPER-basic Unity stuff. It sounds like you might need to work through a few basic Unity tutorials. There's no sense whatsoever in someone retyping it all here for you long-hand.

    Here is a fantastic basic tutorial for Unity:

     
    Crossway likes this.