2

I am getting audio using the NAudio library which returns a 32 bit float[] of audio data. I'm trying to find a way to convert this to a 16 bit byte[] for playback.

private void sendData(float[] samples)
{
    Buffer.BlockCopy(samples, 0, byteArray, 0, samples.Length);
    byte[] encoded = codec.Encode(byteArray, 0, byteArray.Length);
    waveProvider.AddSamples(byteArray, 0, byteArray.Length);
    s.Send(encoded, SocketFlags.None);
}

The audio being sent to waveProvider is coming out static-y — I don't think I'm converting correctly. How can I convert to a byte array of 16 bit samples?

jacob
  • 4,656
  • 1
  • 23
  • 32
user547794
  • 14,263
  • 36
  • 103
  • 152

1 Answers1

5

Buffer.BlockCopy copies a number of bytes, but you're passing it a number of elements. Since a float is 4 bytes and a byte is obviously 1, you're using a fourth of samples to fill up half of byteArray, leaving the rest untouched. That probably won't give you very good audio, to say the least.

What you'll need to do is convert from a floating-point value between −1 and 1 to a 16-bit integer value between −215 and 215−1. If we convert to shorts rather than bytes, it's rather simple:

shortSample = (short)Math.Floor(floatSample * 32767);

(If you know that floatSample will always be less than 1, you should multiply by 32,768 rather than 32,767.)
Of course, you want a byte array rather than a short array. Unfortunately, you've not given enough information for that last step. There's two things that you'll need to know: endianness and signedness. If it's unsigned, you'll need to convert that short to a ushort by adding 32,768. Then you need to split each short or ushort up into two bytes. Endianness determines the order, but you'll probably need to do some bit-shifting.

icktoofay
  • 126,289
  • 21
  • 250
  • 231
  • Thanks for your response, it's starting to make some more sense. I'm not really familiar with Endianness but I will look through the library to see if I can figure that out. Just for my own learning - why do they need to be slit into 2 bytes? It looks like this is happening when I use the GetBytes method (byte[] samplesByteArray = BitConverter.GetBytes(shortSample);) – user547794 Sep 09 '13 at 00:21
  • @user547794: If it takes a 16-bit byte array and each byte is 8 bits, you need two bytes per 16-bit short. – icktoofay Sep 09 '13 at 00:24
  • 1
    Isn't the `Math.Floor` call redundant? – Rafael Sep 15 '16 at 17:04