Правильный способ преобразования 16-битных данных PCM Wave в float

У меня есть волновой файл в 16-битной форме PCM. У меня есть необработанные данные в byte[] и метод извлечения образцов, и мне они нужны в формате с плавающей запятой, то есть float[] для выполнения преобразования Фурье. Вот мой код, это выглядит правильно? Я работаю на Android, поэтому javax.sound.sampled и т. д. недоступны.

private static short getSample(byte[] buffer, int position) {
  return (short) (((buffer[position + 1] & 0xff) << 8) | (buffer[position] & 0xff));
}

...

float[] samples = new float[samplesLength];
  for (int i = 0;i<input.length/2;i+=2){
    samples[i/2] = (float)getSample(input,i) / (float)Short.MAX_VALUE;
  }

person fredley    schedule 07.01.2011    source источник
comment
См. также: stackoverflow.com/questions/15087668/   -  person Brad    schedule 27.12.2013


Ответы (3)


У меня было похожее решение, но ИМХО немного чище. К сожалению, насколько мне известно, нет хорошего библиотечного метода: * Предполагается, что четные байты являются младшими байтами.

private static float[] bytesToFloats(byte[] bytes) {
    float[] floats = new float[bytes.length / 2];
    for(int i=0; i < bytes.length; i+=2) {
        floats[i/2] = bytes[i] | (bytes[i+1] << 8);
    }
    return floats;
}
person jk.    schedule 07.01.2011
comment
Это работает только для неподписанного PCM, верно? В противном случае вам нужно будет замаскировать бит знака от второго в каждой паре байтов. - person hertzsprung; 30.10.2011
comment
@hertzsprung: Не могли бы вы объяснить, что делать в случае подписанного PCM? - person user1599964; 09.10.2014

Вы можете попробовать использовать ByteBuffer API. http://developer.android.com/reference/java/nio/ByteBuffer.html#asFloatBuffer()

person Dennis C    schedule 31.05.2011

Как указывает hertzsprung, ответ jk. работает только для неподписанного PCM. В Android PCM16 подписан с обратным порядком байтов, поэтому вам необходимо учитывать потенциально отрицательное значение, закодированное в двойках. дополнить. Это означает, что нам нужно проверить, больше ли старший байт 127, и если да, то сначала вычесть из него 256, прежде чем умножать его на 256.

private static float[] bytesToFloats(byte[] bytes) {
    float[] floats = new float[bytes.length / 2];
    for(int i=0; i < bytes.length; i+=2) {
        floats[i/2] = bytes[i] | (bytes[i+1] < 128 ? (bytes[i+1] << 8) : ((bytes[i+1] - 256) << 8));
    }
    return floats;
}
person Christian Fritz    schedule 17.03.2015