Преобразование необработанных байтов в float[]
У меня есть этот код для преобразования byte[]
в 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;
}
Проблема в том, что я обычно получаю NaN
результат! Почему это должно быть? Я проверил, есть ли данные в byte[]
и данные вроде бы в порядке. Если это помогает, пример значений:
new byte[] {
231,
255,
235,
255,
}
Но это возвращается NaN
(Не число) после преобразования в число с плавающей точкой. В чем может быть проблема? Есть ли другие лучшие способы конвертации? byte[]
в float[]
? Я уверен, что значения, считанные в буфер, являются правильными, поскольку я сравнил их с другой моей программой (которая выполняет усиление для файла.wav).
5 ответов
Если проблема заключается в порядке байтов, вы должны проверить значение BitConverter.IsLittleEndian
чтобы определить, нужно ли поменять местами байты:
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;
}
Не проблема ли в том, что 255 в экспоненте представляет NaN (см. Википедию в разделе экспоненты), поэтому вы должны получить NaN. Попробуйте заменить последние 255 на что-то другое...
Я предполагаю, что ваш байт [] не содержит двоичное представление чисел с плавающей точкой, но либо последовательность Int8
с или Int16
s. Приведенные вами примеры не похожи на аудиосэмплы, основанные на числах с плавающей запятой (ни NaN, ни -2.41E+24 не находятся в диапазоне от -1 до 1. Хотя некоторые новые форматы аудио могут поддерживать операции с плавающей запятой вне этого диапазона, традиционно аудиоданные состоят из подписанных 8 или 16-битные целочисленные выборки.
Еще одна вещь, о которой вам нужно знать, это то, что часто различные каналы чередуются. Например, он может содержать первый сэмпл для левого, затем для правого канала, а затем второй сэмпл для обоих... Так что вам нужно разделить каналы при разборе.
Также возможно, но необычно, что образцы не подписаны. В этом случае вам нужно удалить смещение из функций преобразования.
Поэтому сначала вам нужно проанализировать текущую позицию в байтовом массиве в Int8/16. А затем преобразовать это целое число в число с плавающей точкой в диапазоне от -1 до 1.
Если формат имеет прямой порядок байтов, вы можете использовать BitConverter. Другая возможность, которая работает с обоими порядками байтов, - это получить два байта вручную и объединить их с битовым сдвигом. Я не помню, встречается ли маленький или большой порядок байтов. Так что вам нужно попробовать это самостоятельно.
Это можно сделать с помощью следующих функций (я их не тестировал):
float Int8ToFloat(Int8 i)
{
return ((i-Int8.MinValue)*(1f/0xFF))-0.5f;
}
float Int16ToFloat(Int16 i)
{
return ((i-Int16.MinValue)*(1f/0xFFFF))-0.5f;
}
Если это неправильный порядок байтов (вы читаете большие порядковые числа), попробуйте это (имейте в виду, что они "небезопасны", поэтому вы должны проверить флаг unsafe в свойствах вашего проекта)
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;
}
Зависит от того, как вы хотите преобразовать байты в число с плавающей точкой. Начните с попытки точно определить, что на самом деле хранится в байтовом массиве. Возможно, есть спецификация формата файла? Другие преобразования в вашем коде?
В случае, если каждый байт должен быть преобразован в число с плавающей запятой между 0 и 255:
public float[] ConvertByteToFloat(byte[] array)
{
return array.Select(b => (float)b).ToArray();
}
Если массив байтов содержит двоичное представление чисел с плавающей запятой, существует несколько представлений, и если хранимое в вашем файле представление не соответствует стандартному представлению с плавающей запятой языка C# ( IEEE 754), произойдут странные вещи, подобные этому.