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

Question Byte[] to AudioClip

Discussion in 'Scripting' started by Hurd-Of-Daniels, Jun 14, 2020.

  1. Hurd-Of-Daniels

    Hurd-Of-Daniels

    Joined:
    Nov 19, 2017
    Posts:
    8
    Hello all,

    I've been messing around with sockets on unity and had the idea to make an online voice chat system, It sends the audio clip to the server as bytes, how do I convert the bytes back to an audio clip?

    Thanks,
    Daniel
     
  2. Cyber-Dog

    Cyber-Dog

    Joined:
    Sep 12, 2018
    Posts:
    352
    I suggest the use of NLayer.
    https://github.com/naudio/NLayer

    I have done similar work in the passed. But from file.

    Code (CSharp):
    1. MpegFile mpegFile = new MpegFile(path);
    2. float[] samples = new float[mpegFile.Length / sizeof(float)];
    3. mpegFile.ReadSamples(samples, 0, (int)(mpegFile.Length / sizeof(float)));
    4. AudioClip audioClip = AudioClip.Create(string name, (int)(mpegFile.Duration.TotalSeconds * mpegFile.SampleRate), mpegFile.Channels, mpegFile.SampleRate, false);
    5. audioClip.SetData(samples, 0);
    6. mpegFile.Dispose();
    Which based on this info I reckon it can be easily adapted for your use.
    Code (CSharp):
    1. var fileName = "myMp3File.mp3";
    2. var mpegFile = new MpegFile(filename);
    3. float[] samples = new float[44100];
    4. mpegFile.ReadSamples(samples, 0, 44100);
    Assuming "samples" would be your data array sent to server.
     
  3. Hurd-Of-Daniels

    Hurd-Of-Daniels

    Joined:
    Nov 19, 2017
    Posts:
    8
    Thanks your reply, Cyber-Dog,

    I will try it out when I got home.

    Thanks,
    Daniel
     
    Cyber-Dog likes this.
  4. Cyber-Dog

    Cyber-Dog

    Joined:
    Sep 12, 2018
    Posts:
    352
    If you have trouble getting the NLayer DLL to properly reference, hit me up :)
     
  5. Hurd-Of-Daniels

    Hurd-Of-Daniels

    Joined:
    Nov 19, 2017
    Posts:
    8
    Thanks for your help,

    Unfortunately, it didn't work

    Thanks,
    HurdOfDaniels
     
  6. Cyber-Dog

    Cyber-Dog

    Joined:
    Sep 12, 2018
    Posts:
    352
    No worries :)

    What didn't work?
    -Referencing NLayer
    -Converting byte[] data
     
  7. Hurd-Of-Daniels

    Hurd-Of-Daniels

    Joined:
    Nov 19, 2017
    Posts:
    8
    Converting byte[] data
     
  8. Cyber-Dog

    Cyber-Dog

    Joined:
    Sep 12, 2018
    Posts:
    352
    Ok no worries, I may be able to help. Can you show me the function that converts the audio to a byte[] in the first place?
     
  9. Cyber-Dog

    Cyber-Dog

    Joined:
    Sep 12, 2018
    Posts:
    352
    Also, much faster to just share this post here...
    https://stackoverflow.com/questions/10390356/serializing-deserializing-with-memory-stream

    If you take say ClassAdioFile, then convert to a Memory stream. The Memory stream can convert to a byte[] that in this case, you would send to the server.

    Then just do the reverse, deserialize byte[] to say ClassAdioFile.

    Just mark the class of your object as [system.serialzable]
    ----

    You would not require NLayer then most likely and keep everything standard to Unity.
     
  10. Hurd-Of-Daniels

    Hurd-Of-Daniels

    Joined:
    Nov 19, 2017
    Posts:
    8
    _message is the AudioClip and _messageStr is just ":AudioData:" but it gets cut out

    Code (CSharp):
    1. byte[] messageSent = Encoding.ASCII.GetBytes($"{_message}{_messageStr}<EOF>");
     
  11. Cyber-Dog

    Cyber-Dog

    Joined:
    Sep 12, 2018
    Posts:
    352
    Have a play with this. It's somewhat SUDO, didn't actually put in a project so the syntax may be off.
    Also, you may need to wrap the memory streams in a use case.

    Remember, however you are sending it to the "server" the data cannot be modified/formated between sending and receiving. It will all look fine but totally F***ed up.


    Code (CSharp):
    1.  
    2. [system.serializable]
    3. public class AudiClipModel
    4. {
    5.    public string stamp; //Time, who from, whatev's
    6.     public btye[] audioClipData;
    7. }
    8.  
    9. void SendVoive(AudioClip audioClip)
    10. {
    11.    AudiClipModel model = new AudiClipModel(){
    12.        stamp = DateTime.Now.ToString(),
    13.        audioClipData = new byte[]{audioClip.samples},
    14.    };
    15.    audioClip.GetData(model.audioClipData, 0);
    16.    
    17.    MemoryStream stream = new MemoryStream();
    18.    IFormatter formatter = new BinaryFormatter();
    19.    formatter.Serialize(stream, model);
    20.    
    21.    //this may be needed.
    22.     stream.position = 0;
    23.    
    24.    byte[] serverData = stream.ToSrray();
    25.    // send serverData to the server
    26. }
    27.  
    28. AudiClipModel ReceiveVoice()
    29. {
    30.    // Whatever logic to pull from whever your pulling from
    31.     byte[] serverData;
    32.    
    33.    MemoryStream stream = new MemoryStream(serverData);
    34.    IFormatter formatter = new BinaryFormatter();
    35.    AudiClipModel model = formatter.Deserialize(stream);
    36.    
    37.    return model;
    38. }
    39.  
    40.  

    Btw, I caught "<EOF>" in your previous code. I'm assuming you're using some kind of network listener?
    For testing purposes, I suggest you do some direct in/out tests locally with your code before sending out to a server.

    By that, I mean to write your AudioClip to a byte[] and immediately try and write it back. If it's all good, then you know whatever is going to the server is A-OK, and if it fails. It has something to do with how it's being transmitted.