Correct way to Convert 16bit PCM Wave data to float
Asked Answered
B

3

6

I have a wave file in 16bit PCM form. I've got the raw data in a byte[] and a method for extracting samples, and I need them in float format, i.e. a float[] to do a Fourier Transform. Here's my code, does this look right? I'm working on Android so javax.sound.sampled etc. is not available.

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;
  }
Bolus answered 7/1, 2011 at 20:58 Comment(1)
See also: #15088168Anthracosilicosis
M
7

I had a similar solution, but IMHO a little cleaner. Unfortunately, there's no good library method as far as I'm aware: *This assumes the even bytes are the lower bytes

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;
}
Meson answered 7/1, 2011 at 21:52 Comment(2)
This only works for unsigned PCM, right? Otherwise you'd need to mask the sign bit from the second in each pair of bytes.Douche
@Douche : Can you please explain what to do in case of signed PCM ?Mele
N
3

You may try using the ByteBuffer API. http://developer.android.com/reference/java/nio/ByteBuffer.html#asFloatBuffer()

Nebuchadnezzar answered 31/5, 2011 at 15:45 Comment(0)
H
2

As indicated by hertzsprung the answer by jk. only works for unsigned PCM. On Android PCM16 is big-endian signed, so you need to account for the potentially negative value, encoded in two's complement. This means we need to check whether the high byte is greater than 127 and if so subtract 256 from it first before multiplying it by 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;
}
Hospice answered 17/3, 2015 at 4:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.