Convert audio file to raw data (bytes) not working

Hello everyone!

1 . For my project I want to use voice recognition with input from the microphone, for this I need raw sound data (pcm). Using the Unity Audio system, I used the AudioClip.GetData() method I received float numbers and converted them to pcm and everything worked as expected.

The problem arose when I needed to change the audio system to fmod. After searching through a bunch of forum articles and trying thousands of lines of code, I got nothing. So just for testing I decided to try to just get the data from a pre-recorded audio file (I used a microphone before) and test everything on it.

To check the reliability of the received data, I decided to create a unity audio clip with the data (bytes) that I received from the fmod, but instead of my recorded sound I got a crackling sound.

Sound that i used: record.wav - Google Drive

For this experiment I used the code written from this topic (AudioClip.GetData Equivalent in FMOD?) and and at the end got this code:

public class Test: MonoBehaviour
{
    public string FilePath;
    public byte[] Bytes;
    public float[] Floats;

    public AudioSource Source;
    public AudioClip Clip;

    [ContextMenu("Play")]
    public void CreateAudioClipFromBytesAndPlay()
    {
        Bytes = GetSampleData(FilePath);
        Floats = ConvertByteToFloat(Bytes);
        Clip = AudioClip.Create("testSound", Floats.Length, 1, 44100, false);
        Clip.SetData(Floats, 0);
        Source.clip = Clip;
        Source.Play();
    }

    private float[] ConvertByteToFloat(byte[] bytes)
    {
        float[] samples = new float[bytes.Length / 4];
        Buffer.BlockCopy(bytes, 0, samples, 0, bytes.Length);
        return samples;
    }

 /// <summary>
    /// Return sample data in a byte array from an audio source using its file path 
    /// </summary>
    /// <param name="filePath"></param>
    /// <returns></returns>
	private byte[] GetSampleData(string filePath)
    {
        // Very useful tool for debugging FMOD function calls
        FMOD.RESULT result;

        // Sound variable to retrieve the sample data from
        FMOD.Sound sound; 

        // Creating the sound using the file path of the audio source 
        // Make sure to create the sound using the MODE.CREATESAMEPLE | MDOE.OPENONLY so the sample data can be retrieved
		result = FMODUnity.RuntimeManager.CoreSystem.createSound(filePath, FMOD.MODE.CREATESAMPLE | FMOD.MODE.OPENONLY, out sound);

        // Debug the results of the FMOD function call to make sure it got called properly
        if (result != FMOD.RESULT.OK)
        {
            Debug.Log("Failed to create sound with the result of: " + result);
            return null; 
        }

        // Retrieving the length of the sound in milliseconds to size the arrays correctly
		result = sound.getLength(out uint length, FMOD.TIMEUNIT.MS);

        if (result != FMOD.RESULT.OK)
        {
            Debug.Log("Failed to retrieve the length of the sound with result: " + result);
            return null; 
        }

        // Buffer which the sample data will be copied too 
        System.IntPtr buffer; 

        // Creating a pointer to newly allocated memory
        // This pointer must be released at the end of the function! 
        buffer = Marshal.AllocHGlobal((int)length * sizeof(byte));
		
        // Creating the return array which will have the sample data is a readable variable type 
        // Using the length of the sound to create it to the right size 
		byte[] byteArray = new byte[(int)length];

        // Retrieving the sample data to the pointer using the full length of the sound 
		result = sound.readData(buffer, length, out uint read);

        if (result != FMOD.RESULT.OK)
        {
            Debug.Log("Failed to retrieve data from sound: " + result);
            return null; 
        }

        // Make sure the pointer has been populated 
		if (_buffer != System.IntPtr.Zero)
		{			
            // Coping the data from our pointer to our usable array 
			Marshal.Copy(buffer, byteArray, 0, (int)length);
		}

        //Releasing the pointer 
        Marshal.FreeHGlobal(buffer); 

        //Returning the array populated with the sample data to be used
		return byteArray;
	}
}

2 . If I uncheck the “Use Unity Audio System” checkbox in project settings to use exclusively the Microphone class in Unity to record data to audioclip, will I not break anything in the fmod system?
2 . 1 . If this is possible, then can I then process the raw data from audio clip using fmod?

Thanks

There’s a few issues with the code snippet:

  • The first is that you’re getting the length in milliseconds with FMOD.TIMEUNIT.MS, when you likely want the number of PCM samples in bytes with FMOD.TIMEUNIT.PCMBYTES
  • The second is that Buffer.BlockCopy() just copies the bytes as is, causing the code to simply reinterpret the same bytes in a different format, which isn’t what you need. You’ll need to know the source format (this will vary) and destination format (should be 32 bit float), and then convert samples to the appropriate ranges - e.g. from signed 16 bit with a range of -32768 to 32767 to a 32 bit float with a range of -1.0 to 1.0. The BitConverter class may be of some use here.

You can use Unity’s Audio system alongside FMOD’s; we primarily recommend against it to save on system resources.

Yes, though since you’re working in real time between two completely separate audio system, you will need to handle an intermediate buffer and compensate for drift between the systems, if needed.

As an aside, you may find it simpler to only use FMOD to handle recording from your microphone and retrieving the sample data - we have a Unity example that demonstrates recording from your microphone into an FMOD sound, at which point you can Sound.readData as you already have in your existing snippet to retrieve the recorded sample data.