Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Question create AudioClip from byte[] in Unity

Discussion in 'Audio & Video' started by Vishav3, Nov 30, 2021.

  1. Vishav3

    Vishav3

    Joined:
    May 14, 2021
    Posts:
    8
    Dear all,

    I have problem. I am sending wav file from one unity project to another. I get sound from it in byte[]. Then convert byte[] to float[]:

    Sender Code:

    Code (CSharp):
    1. AudioBytes = File.ReadAllBytes(@"C:\Users\vishav3\Desktop\recordedWav\Send.wav");
    2.             mySocket.GetStream().Write(AudioBytes, 0, AudioBytes.Length);
    Reciever Code:

    Code (CSharp):
    1. void Connection()
    2.     {
    3.         Debug.Log("connection");
    4.         List<byte> bigbuffer = new List<byte>();
    5.  
    6.         byte[] tempbuffer = new byte[1024];
    7.         NetworkStream stream = client.GetStream();
    8.  
    9.         while (stream.Read(tempbuffer, 0, tempbuffer.Length) > 0)
    10.         {
    11.             bigbuffer.AddRange(tempbuffer);
    12.             Debug.Log("Read");
    13.             if (!stream.DataAvailable)
    14.             {
    15.                 break;
    16.             }
    17.         }
    18.  
    19.         // now you can convert to a native byte array
    20.         byte[] completedbuffer = new byte[bigbuffer.Count];
    21.  
    22.         bigbuffer.CopyTo(completedbuffer);
    23.  
    24.         //Do something with the data
    25.         //string decodedmsg = Encoding.ASCII.GetString(completedbuffer);
    26.         Debug.Log("length" + completedbuffer.Length);
    27.         float_msg = ConvertByteToFloat(completedbuffer);
    28.         PlayOnce = true;
    29.  
    30.     }
    31.  
    Conversion from Byte to Float:

    Code (CSharp):
    1. private float[] ConvertByteToFloat(byte[] array)
    2.             {
    3.                 float[] floatArr = new float[array.Length / 4];
    4.                 for (int i = 0; i < floatArr.Length; i++)
    5.                 {
    6.                     if (BitConverter.IsLittleEndian)
    7.                         Array.Reverse(array, i * 4, 4);
    8.                     floatArr[i] = BitConverter.ToSingle(array, i*4) / 0x80000000;
    9.                 }
    10.                 return floatArr;
    11.             }
    12.  
    13.  
    14.             float[] f = ConvertByteToFloat(bytes);
    Then create AudioClip:

    Code (CSharp):
    1. clip = AudioClip.Create("ClipName", float_msg.Length, channels, sampleRate, false);
    2.             clip.SetData(float_msg, 0);
    3.             audioSource.clip = clip;
    4.             audioSource.Play();
    5.             PlayOnce = false;
    But playing sound is complete noise. Where i am doing it wrong? Any kind of suggestions would be helpful.
     
  2. The_Island

    The_Island

    Unity Technologies

    Joined:
    Jun 1, 2021
    Posts:
    502
    If you check the documentation, AudioClip.SetData expects the audio samples, but when you do File.ReadAllBytes, you take the header and the audio samples. It is potentially why you hear noises. You can use AudioClip.GetData to get the samples from an AudioClip. Be sure to have the correct sample rate and channels count, or else you will still hear noises.
     
  3. Vishav3

    Vishav3

    Joined:
    May 14, 2021
    Posts:
    8
  4. The_Island

    The_Island

    Unity Technologies

    Joined:
    Jun 1, 2021
    Posts:
    502
    I made a script creating an AudioClip from GetData. Can you make sure this works in your project? If this works then, the issue is probably in the code sending the data.
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class StreamAudioTest : MonoBehaviour
    6. {
    7.     public AudioSource receiverSource;
    8.  
    9.     public AudioClip clip;
    10.  
    11.     // Start is called before the first frame update
    12.     void Start()
    13.     {
    14.         int channels = clip.channels;
    15.         int frequency = clip.frequency;
    16.         float[] samples = new float[clip.samples * clip.channels];
    17.         clip.GetData(samples, 0);
    18.  
    19.         CreateAndPlay(samples, channels, frequency);
    20.     }
    21.  
    22.     void CreateAndPlay(float[] samples, int channels, int frequency)
    23.     {
    24.         var clip = AudioClip.Create("ClipName", samples.Length, channels, frequency, false);
    25.         clip.SetData(samples, 0);
    26.         receiverSource.clip = clip;
    27.         receiverSource.Play();
    28.     }
    29. }
    30.  
    If not, when you check the array from AudioClip.GetData, does the array has other value than zero? If yes, did you try setting Decompress on load in the importer like the note mentioned?
     
  5. Vishav3

    Vishav3

    Joined:
    May 14, 2021
    Posts:
    8
    @The_Island I am getting all zeros in the array. Why?
     
  6. The_Island

    The_Island

    Unity Technologies

    Joined:
    Jun 1, 2021
    Posts:
    502
    Did you try to set Decompress on load in the importer? Otherwise, can you share the file either here or message me directly?
     
  7. The_Island

    The_Island

    Unity Technologies

    Joined:
    Jun 1, 2021
    Posts:
    502
    I checked the audio file and it seems ok.
    I thought you had the audio file imported in the sender project, but it is not the case from what I understand. Do you need to play the file while streaming? Is it an issue to download it and play it after? We don't support importing or streaming an audio file at runtime, but if you are doing this in the Editor only and can wait for the complete file, you can use AssetDatabase.ImportAsset. Even though we don't support this out of the box, it doesn't mean you can't do this yourself. You need to get the PCM data from your file. You can search around for a WAV parser to get the audio samples and feed them to the AudioClip using SetData. If your audio was compressed, you would need to decompress it, but it is not your case. So you can focus on the parser, and you should be fine.
     
    Last edited: Dec 6, 2021
  8. iwillbenice

    iwillbenice

    Joined:
    Jun 7, 2013
    Posts:
    21
    Endian safe solution:


    Code (CSharp):
    1. private float[] ConvertByteToFloat(byte[] array)
    2. {
    3.    float[] floatArr = new float[array.Length / 4];
    4.    for (int i = 0; i < floatArr.Length; i++)
    5.    {
    6.        if (BitConverter.IsLittleEndian)
    7.            Array.Reverse(array, i * 4, 4);
    8.        floatArr[i] = BitConverter.ToSingle(array, i*4) / 0x80000000;
    9.    }
    10.    return floatArr;
    11. }
    12.  
    13.  
    14. private byte[] ConvertFloatToByte(float[] array)
    15. {
    16.    byte[] byteArr = new byte[array.Length * 4];
    17.    for (int i = 0; i < array.Length; i++)
    18.    {
    19.        var bytes = BitConverter.GetBytes(array[i] * 0x80000000);
    20.        Array.Copy(bytes, 0, byteArr, i * 4, bytes.Length);
    21.        if (BitConverter.IsLittleEndian)
    22.            Array.Reverse(byteArr, i * 4, 4);
    23.    }
    24.    return byteArr;
    25. }
    26.