Search Unity

Dynamic audio?

Discussion in 'Scripting' started by Deleted User, Nov 15, 2010.

  1. Deleted User

    Deleted User

    Guest

    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.
     
  2. Jessy

    Jessy

    Joined:
    Jun 7, 2007
    Posts:
    7,325
    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! :)
     
    Last edited: Nov 16, 2010
  3. Jesse Anders

    Jesse Anders

    Joined:
    Apr 5, 2008
    Posts:
    2,857
    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.]
     
  4. Aron

    Aron

    Joined:
    Oct 6, 2010
    Posts:
    54
    Bump, anyone made an audio visualizer?
     
  5. Deleted User

    Deleted User

    Guest

    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):
    1. var theClip : AudioClip;
    2. function Start () {
    3. audio.clip = theClip;
    4. audio.Play();
    5. var spectrum : float[] = audio.GetOutputData (128, 2);
    6. for (var i = 0; i < spectrum.Length; i++)
    7.     print(spectrum[i].ToString());
    8. }
     
  6. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    Et voila:-
    Code (csharp):
    1. function RMS(data: float[]) {
    2.     var result = 0.0;
    3.    
    4.     for (i = 0; i < data.Length; i++) {
    5.         result += data[i] * data[i];
    6.     }
    7.    
    8.     result /= data.Length;
    9.    
    10.     return Mathf.Sqrt(result);
    11. }
    The name is a bit ambiguous but it means the square root of the mean of the squares of all the data values.
     
  7. Deleted User

    Deleted User

    Guest

    What does that script do?
     
  8. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    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):
    1. var vol: float;
    2. var sampleRate: float;
    3. var timeWindow: float;
    4.  
    5. private var numSamples: float;
    6. private var window: float[];
    7.  
    8.  
    9. function Start() {
    10.     numSamples = sampleRate * timeWindow;
    11.     window = new float[numSamples];
    12.     InvokeRepeating("UpdateVolume", 0, timeWindow);
    13. }
    14.  
    15. function UpdateVolume() {
    16.     audio.GetOutputData(window, 0);
    17.     vol = RMS(window);
    18. }
    19.  
    20.  
    21. function RMS(data: float[]) {
    22.     var result = 0.0;
    23.    
    24.     for (i = 0; i < data.Length; i++) {
    25.         result += data[i] * data[i];
    26.     }
    27.    
    28.     result /= data.Length;
    29.    
    30.     return Mathf.Sqrt(result);
    31. }
     
  9. Deleted User

    Deleted User

    Guest

    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)?
     
  10. Deleted User

    Deleted User

    Guest

    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)'."
     
  11. Deleted User

    Deleted User

    Guest

    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[])'."
     
  12. Deleted User

    Deleted User

    Guest

    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?
     
  13. Deleted User

    Deleted User

    Guest

    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?
     
  14. jlgactionpinball

    jlgactionpinball

    Joined:
    May 19, 2017
    Posts:
    1
    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.