Правилен начин за конвертиране на 16-битови PCM Wave данни в плаващи

Имам вълнов файл в 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)


Имах подобно решение, но IMHO малко по-чисто. За съжаление няма добър библиотечен метод, доколкото ми е известно: * Това предполага, че четните байтове са по-ниските байтове

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 е със знак big-endian, така че трябва да отчетете потенциално отрицателната стойност, кодирана в две допълнение. Това означава, че трябва да проверим дали старшият байт е по-голям от 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