Converting raw byte data to float[]

18,440

Solution 1

If endianness is the problem, you should check the value of BitConverter.IsLittleEndian to determine if the bytes have to be reversed:

public static float[] ConvertByteToFloat(byte[] array) {
  float[] floatArr = new float[array.Length / 4];
  for (int i = 0; i < floatArr.Length; i++) {
    if (BitConverter.IsLittleEndian) {
      Array.Reverse(array, i * 4, 4);
    }
    floatArr[i] = BitConverter.ToSingle(array, i * 4);
  }
  return floatArr;
}

Solution 2

Isn't the problem that the 255 in the exponent represents NaN (see Wikipedia in the exponent section), so you should get a NaN. Try changing the last 255 to something else...

Solution 3

I assume that your byte[] doesn't contain the binary representation of floats, but either a sequence of Int8s or Int16s. The examples you posted don't look like audio samples based on float (neither NaN nor -2.41E+24 are in the range -1 to 1. While some new audio formats might support floats outside that range, traditionally audio data consists of signed 8 or 16 bit integer samples.

Another thing you need to be aware of is that often the different channels are interleaved. For example it could contain the first sample for the left, then for the right channel, and then the second sample for both... So you need to separate the channels while parsing.

It's also possible, but uncommon that the samples are unsigned. In which case you need to remove the offset from the conversion functions.

So you first need to parse current position in the byte array into an Int8/16. And then convert that integer to a float in the range -1 to 1.

If the format is little endian you can use BitConverter. Another possibility that works with both endiannesses is getting two bytes manually and combining them with a bit-shift. I don't remember if little or big endian is common. So you need to try that yourself.

This can be done with functions like the following(I didn't test them):

float Int8ToFloat(Int8 i)
{
  return ((i-Int8.MinValue)*(1f/0xFF))-0.5f;
}

float Int16ToFloat(Int16 i)
{
  return ((i-Int16.MinValue)*(1f/0xFFFF))-0.5f;
}

Solution 4

If it's the endianness that is wrong (you are reading big endian numbers) try these (be aware that they are "unsafe" so you have to check the unsafe flag in your project properties)

public static unsafe int ToInt32(byte[] value, int startIndex)
{
    fixed (byte* numRef = &value[startIndex])
    {
        var num = (uint)((numRef[0] << 0x18) | (numRef[1] << 0x10) | (numRef[2] << 0x8) | numRef[3]);
        return (int)num;
    }
}

public static unsafe float ToSingle(byte[] value, int startIndex)
{
    int val = ToInt32(value, startIndex);
    return *(float*)&val;
}
Share:
18,440
user488792
Author by

user488792

Updated on June 04, 2022

Comments

  • user488792
    user488792 almost 2 years

    I have this code for converting a byte[] to float[].

    public float[] ConvertByteToFloat(byte[] array)
    {
        float[] floatArr = new float[array.Length / sizeof(float)];
        int index = 0;
        for (int i = 0; i < floatArr.Length; i++)
        {
            floatArr[i] = BitConverter.ToSingle(array, index);
            index += sizeof(float);
        }
        return floatArr;
    }
    

    Problem is, I usually get a NaN result! Why should this be? I checked if there is data in the byte[] and the data seems to be fine. If it helps, an example of the values are:

    new byte[] {
        231,
        255,
        235,
        255,
    }
    

    But this returns NaN (Not a Number) after conversion to float. What could be the problem? Are there other better ways of converting byte[] to float[]? I am sure that the values read into the buffer are correct since I compared it with my other program (which performs amplification for a .wav file).

  • Guffa
    Guffa about 13 years
    That will convert each single byte into a float, not each group of four bytes into a float.
  • xanatos
    xanatos about 13 years
    If you need the funcs for doubles and Int64, just ask. I had to make them some months ago for a project of mine.
  • Jeff Mercado
    Jeff Mercado about 13 years
    I suspect this ultimately is the problem. Though it should be noted that this modifies the array so might not be the best approach.
  • Jeff Mercado
    Jeff Mercado about 13 years
    How is this relevant? Those numbers most likely came from a real float in that order. If converted as big-endian, it is a valid number (-2.417114E+24). You just can't change the data to get a real number.
  • user488792
    user488792 about 13 years
    Hi and thanks! I tried with the IsLittleEndian approach and it does work! However, there are still values in the resulting float[] that have NaN values. What other problem could it be?
  • CodesInChaos
    CodesInChaos about 13 years
    -2.41E+24 is a valid float, but typically not used in audio data, since audio data is typically restricted to -1 to 1. So I still think the byte array doesn't contain floats, but integer samples.
  • user488792
    user488792 about 13 years
    Hi and thanks for this! It works although there are still some NaN values so I think that endianness is only 1 part of the problem
  • xanatos
    xanatos about 13 years
    @user488792 How can you know it works then? Do you have some "reference" numbers?
  • vidstige
    vidstige about 13 years
    @Guffa ye, exactly. Clearified my answer a bit.
  • user488792
    user488792 about 13 years
    I tried the other suggestion of one of the answers here, and I compared them to each other and they were (seemed to) be the same.
  • user488792
    user488792 about 13 years
    Hi! Thanks. Ill try to see if this works. Im only working with mono audio currently so I think thats one less problem. Im currently using BitConverter for my previous code so Ill try that first.
  • Jeff Mercado
    Jeff Mercado about 13 years
    C# uses the older IEEE 754-1985 standard, not IEEE 754-2008 as you have linked.