How do I get the current volume level (amplitude) of playing audio (not the set volume but how loud it is)

How do I get the current volume level (amplitude) of playing audio (not the set volume but how loud it is)?

There doesn’t seem to be an obvious function to get this value. I really just want a simple float value that I can set a mouth blend shape value to - so I can approximate talking, while a character speaks.

I know it might not look perfect but at least the loader the speech the more the mouth will open, and with most speech patterns the volume goes up and down and so will approximate the mouth opening and closing.

I second this question. There has to be a way, but the only things I found is the function AudioSource.GetOutputData, which no longer exists, and the function AudioClip.GetData, which delivers what I seek, but is too costly on the CPU to be called at regular intervals. Seriously, only one call brings the frame rate down seriously, and I would need it for a bunch of objects, which update at the same time. /Edit: Ok, scratch that, I had another issue. My code works now, and I will write an according answer.

5 Answers

5

You can use AudioClip.GetData to get what you need. Just write a script like this:

using UnityEngine;

public class AudioSourceLoudnessTester : MonoBehaviour {

	public AudioSource audioSource;
	public float updateStep = 0.1f;
	public int sampleDataLength = 1024;

	private float currentUpdateTime = 0f;

	private float clipLoudness;
	private float[] clipSampleData;

	// Use this for initialization
	void Awake () {
	
		if (!audioSource) {
			Debug.LogError(GetType() + ".Awake: there was no audioSource set.");
		}
		clipSampleData = new float[sampleDataLength];

	}
	
	// Update is called once per frame
	void Update () {
	
		currentUpdateTime += Time.deltaTime;
		if (currentUpdateTime >= updateStep) {
			currentUpdateTime = 0f;
			audioSource.clip.GetData(clipSampleData, audioSource.timeSamples); //I read 1024 samples, which is about 80 ms on a 44khz stereo clip, beginning at the current sample position of the clip.
			clipLoudness = 0f;
			foreach (var sample in clipSampleData) {
				clipLoudness += Mathf.Abs(sample);
			}
			clipLoudness /= sampleDataLength; //clipLoudness is what you are looking for
		}

	}

}

I update the loudness value only once every 100ms to keep its CPU usage down, and make sure to declare the float for the sample data globally, since it could annoy the garbage collector, if you declare a huge array and destroy it again every update step.

Thank You very much !

Hi, I know this is an ancient thread, but is there a way to isolate the amplitude of the volume of different “stems” or frequency ranges with something like a low-pass filter that the user will never hear?

I slightly modified the script to edit the emission color on a material based on the current amplitude. Still, I would like to change different materials based on different instruments and avoid increasing filesize with different audio files.

Thanks,
Mark.

And if you lose the SmoothDamp and move the camera in FixedUpdate?

I used this :slight_smile:

Thanks

Do you know what happens if you have a sample size of 4 or 8 rather than 1024? Do the values match on average?

As you can see in the foreach-loop of my code, I average all my samples. A larger sample size means of course that I get a more average value. With a sample size of 4 or 8, the averages might fluctuate too much to be of actual use. As I said above, a sample size of 1024 equals about 80ms on a 44kHtz clip. A sample size of 8 would hardly be one millisecond.

I am using Mathf.SmoothDamp to have a smooth camera movement.

Hi I am having trouble trying to implement your code with an audio source with no clip attached with the AudioSource.GetOutputData(). but I keep getting errors? I have the audio coming from a live source and need to monitor the volume. @Chris_Entropy Thanks!

You haven't specified what errors you're getting, but if you're trying to use an audio source with no clip, you might try adding the following to the top of your Update function: if (audioSource.clip == null) { return; } which should keep anything from happening until you've actually loaded a clip at runtime. I had the same issue using a file browser to select music, not any particular clip. Hope it helps!

i mean the camera is following the player (i am using Mathf.SmoothDamp for that)