Hello, I am working on a music visualizer type effect for my game. I am using something like this to measure the pitch and volume: (audio.volume > .5) what ever the function is, etc... But Ive run into a problem. Since the audio pitch and volume is set in the audio source inspector/code, it remains constant (so if I set the audio volume to .5. even if in the song there is a sudden increase in sound in the actual song, nothing will happen). How can I remedy this? Also, is there anyway to measure a sudden increase in volume/pitch regardless of the numbers? Thank you, I know this is an odd question.
There's not a simple way to do it. What you'll need to do is use the RMS of the data you get from AudioSource.GetOutputData, but I've never had to use an RMS calculation myself, so I don't know how to go about it. (I only know that this is the way to go about it from working with hardware and software audio effects devices over the yeas.) Anyone who knows, chiming in, would be appreciated!
Right, the 'volume' and 'pitch' fields don't reflect what's going on in the sound file; rather, they're simply values through which the *overall* volume and pitch can be specified. So, they're not what you're looking for. I haven't used them at all, but in Unity 3 there's a function or two (I believe) that allow you to retrieve a portion of the output for a given audio source; this is probably what you're looking for. Analyzing said output for the purpose of visualization isn't necessarily trivial, but if you search this forum and perhaps other general game development or programming forums for 'sound visualization' or 'music visualization', you should be able to find some info. [Too slow.]
I recently found a script that displays a bunch of values based on the selected audio source...but what do they mean(volume spikes, etc.)? There is a long list of values, are they taken from the song every few seconds? Code (csharp): var theClip : AudioClip; function Start () { audio.clip = theClip; audio.Play(); var spectrum : float[] = audio.GetOutputData (128, 2); for (var i = 0; i < spectrum.Length; i++) print(spectrum[i].ToString()); }
Et voila:- Code (csharp): function RMS(data: float[]) { var result = 0.0; for (i = 0; i < data.Length; i++) { result += data[i] * data[i]; } result /= data.Length; return Mathf.Sqrt(result); } The name is a bit ambiguous but it means the square root of the mean of the squares of all the data values.
Sorry, I should have made it clear I was referring to the suggestion made by Jessy earlier. You can use AudioSource.GetOutputData to get an array of PCM sample data and then use the RMS function on that array to get the overall volume of that section of the audio data. Decide on the time window you want for the volume data and then multiply that time by the sample rate to get the number of samples that should be in the array passed to GetOutputData. The docs for GetOutputData are a bit misleading here. The documented version of the function works but it produces a deprecation warning if you use it. The preferred version of the function is actually one that takes a float array as its first parameter. The length of the array determines the number of samples and the function updates this array with the fresh sample data on each call. Call the RMS function on this array to get the volume and arrange the whole process to be repeated after a delay equal to the time window:- Code (csharp): var vol: float; var sampleRate: float; var timeWindow: float; private var numSamples: float; private var window: float[]; function Start() { numSamples = sampleRate * timeWindow; window = new float[numSamples]; InvokeRepeating("UpdateVolume", 0, timeWindow); } function UpdateVolume() { audio.GetOutputData(window, 0); vol = RMS(window); } function RMS(data: float[]) { var result = 0.0; for (i = 0; i < data.Length; i++) { result += data[i] * data[i]; } result /= data.Length; return Mathf.Sqrt(result); }
So If I set this up correctly, I could make it so that every time the volume increases by more than a set value (or every time the volume for the current time frame is more than the previous)?
When I use your script I get the error "Assets/NewBehaviourScript.js(16,28): BCE0017: The best overload for the method 'UnityEngine.AudioSource.GetOutputData(int, int)' is not compatible with the argument list '(float[], int)'."
I got an error telling me about expected ) and ; I did that and I still get this error "Assets/NewBehaviourScript.js(16,28): BCE0017: The best overload for the method 'UnityEngine.AudioSource.GetOutputData(int, int)' is not compatible with the argument list '(float[])'."
Thanks, now I am getting no errors. So, if I wanted this script every time there was a sudden increase in volume (amplitude), like a drum beat or something, I would set up low sample time rates and then have something like "if (vol > previous sample by at least 1.5*previous sample, do this....)", or am I completely of track here?
Is there anyway to do this before the scene starts? Have an "analyzing" scene where the unity runs through the song (sped up, perhaps?), grabs the data needed and then, when the actual scene where that info is needed, the song is just playing and not being analyzed? Games that use audio to generate their levels (audiosurf, rhythm zone, etc.) use this technique(to increase performance I presume). Also, Is there anyway to use an outside audio track as the material for an audio source? As in, letting the player use their own music? I know there is a file browser on the unity wiki, could that work?
Is there a way to use external audio (from a microphone for example) as a source for analysis ? I'd like to use the amplitude of an incoming audio source to create earthquakes. After a threshold, the ground would start moving randomly according to the input sound.