Search Unity

Creating a custom AudioClip from another AudioClip with GetOutputData

Discussion in 'Editor & General Support' started by Skeletim, Jul 21, 2013.

  1. Skeletim

    Skeletim

    Joined:
    Jun 19, 2013
    Posts:
    29
    Thanks to the person helping with this in the Answers here, but I think I might need to bring this to forums. I too hope I can get some helpful feedback here. :) Thanks in advance.

    I've been trying to pull data from an AudioClip and filter it into another AudioClip. The first AudioClip will NOT be audible and will be muted (by design), but the second will. Yes, I know that may sound strange, but I do have a reason for that. I've gotten a bunch of help from previous answer and forums topics.

    I don't think I can use SetData with a blank AudioClip, so I had to use AudioClip.Create. For the sake of not slowing the process down, I created an array of only 10 elements. I would GetOutputData from the AudioSource when I hit a key, SetData to the array, and just to make sure, GetData to see it's elements. I used loops to output the 10 elements as I pressed a button, and each time it I pressed a key, it would GetOutputData, and SetData to the array. I put a loop after GetOutputData, and after GetData, just to make sure I was actually storing the correct data, which I was. So that all seemed to work. I even wrote the data in the array to a text file to see what I was getting.

    I was just going to store that data in an AudioClip and leave it in memory, (overwriting when necessary) and just PlayClipAtPoint instead of saving it to a Wav file, but I used the code found here to save to a file just so I could test the output as playable audio.

    I wanted to use an array that was 441000 long so it would hold a 1 channel (mono?) at a 44100 frequency, 10 second long clip. (I assume I calculated the length correctly)

    AudioSource.PlayClipAtPoint(myClip, Camera.main.transform.position)

    did nothing. It was silent, so when I replaced that line with the line to call the Save class, I find out I the output file is just 10 seconds worth of silence, and thats why I wasn't hearing anything. Thats when I wanted to output the array itself to a text file. And thats when I found that all the elements were 0. So it was silent after all. I found out that GetOutputData was only able to capture 64k of data. 4 bytes per float, so thats 16384 elements max. Apparently, it just poops out on me if I create a bigger array. Hmmm

    Yes, getting the audio from GetOutputData does start pulling data from the AudioClip at the exact time I press the button. Thats wonderful. I'm happy I figured out how to get it to work finally. I don't understand the arguments AudioClip.Create and how they effect the audio.

    static function Create (name : String, lengthSamples : int, channels : int, frequency : int, _3D : boolean, stream : boolean) : AudioClip

    I can't claim to know anything about audio files, but I if I change channels to 2 for example it speeds the clip up twice as fast. If I would have to be sure the audio clip I'm reading matches the frequency I use or vice versa, or the audio is going to be too fast or too slow. If there is anyone who has more experience with this that could explain it's parameters a bit better, I'd appreciate it. For example, what is _3D?

    Anyway, here is my code that I have been testing with to see how things work.

    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System;
    4. using System.IO;
    5.  
    6. public class example : MonoBehaviour {
    7.  
    8.     AudioClip myClip;
    9.     float[] samples;
    10.        
    11.     void Start() {
    12.         // Have to create a blank AudioClip or it makes it null and
    13.         // throws a NullReferenceException on the clip. It won't SetData
    14.         myClip = AudioClip.Create("sample",16384,1,44100,false,false);
    15.         samples = new float[myClip.samples];
    16.         // For some reason, the first time this is called, samples[] is
    17.         // blank (filled with all 0s), so I call it first so I can 'fix'
    18.         // it for the next time I need to call it.
    19.         GameObject.Find("audiosource").audio.GetOutputData(samples,1);
    20.     }
    21.    
    22.     void Update() {
    23.        
    24.         // Get Audio
    25.         if(Input.GetKeyDown("1")) {
    26.             GameObject.Find("audiosource").audio.GetOutputData(samples,1);
    27.             myClip.SetData(samples,0);
    28.         }
    29.        
    30.         // Play Audio
    31.         if(Input.GetKeyDown("2")) {
    32.             AudioSource.PlayClipAtPoint(myClip, Camera.main.transform.position);
    33.         }
    34.     }
    35. }
    My questions are, other than the ones I stated above, why is GetOutputData filling the array with 0s (or not filling it for that matter) the first time it's called? And would it be better to create a streaming AudioClip, because right now, I'm passing it a false.

    Guessing by the way that GetOutputData is only using 64k chunks, I'm probably going to have to repeatedly call that function and append the data to an existing array until the person stops it? Right?

    Edit: Something is um...way off. While I can get data, I guess there is some overlap in the data that I'm getting, and when I piece it all together it is making a horrible sound. I don't know if I created my clip wrong, if I'm piecing the data together wrong, plus I've had to increase the size of the sample to 8388608 because it was complaining it was too small. But that is roughly the length of the original clip I'm recording. I don't need the new clip that big. Please help if you can.
     
    Last edited: Jul 21, 2013
  2. Skeletim

    Skeletim

    Joined:
    Jun 19, 2013
    Posts:
    29
    The issue is the data obviously must be synced to framerate. I'm assuming its because Update gets called every frame, but it may be many times a second, so I'm getting overlap on the audio. I don't think I can use OnAudioFilter because I believe that only works on audio that is heard.

    To reiterate what I've been doing, I'm essentially streaming data from one clip to another.

    Do you know how I'm able to sync the audio that I'm getting from GetOutputData up correctly with the framerate so its not just a distorted mess?
     
    Last edited: Jul 21, 2013
  3. BruceKristelijn

    BruceKristelijn

    Joined:
    Apr 28, 2017
    Posts:
    107
    Did you ever figure this out? Kinda struggling with the same!
     
    zacharyaghaizu and unnanego like this.