How to convert 16-bit PCM audio byte-array to double or float array?

15,159

There is no alternative. You have to run a loop and cast each element of the array separately.

I do the same thing for shorts that I fft as floats:

public static float[] floatMe(short[] pcms) {
    float[] floaters = new float[pcms.length];
    for (int i = 0; i < pcms.length; i++) {
        floaters[i] = pcms[i];
    }
    return floaters;
}

EDIT 4/26/2012 based on comments

If you really do have 16 bit PCM but have it as a byte[], then you can do this:

public static short[] shortMe(byte[] bytes) {
    short[] out = new short[bytes.length / 2]; // will drop last byte if odd number
    ByteBuffer bb = ByteBuffer.wrap(bytes);
    for (int i = 0; i < out.length; i++) {
        out[i] = bb.getShort();
    }
    return out;
}

then

float[] pcmAsFloats = floatMe(shortMe(bytes));

Unless you are working with a weird and badly designed class that gave you the byte array in the first place, the designers of that class should have packed the bytes to be consistent with the way Java converts bytes (2 at a time) to shorts.

Share:
15,159
soren.qvist
Author by

soren.qvist

Updated on July 20, 2022

Comments

  • soren.qvist
    soren.qvist almost 2 years

    I'm trying to perform Fast Fourier Transform on a .3gpp audio file. The file contains a small 5 second recording in 44100kHz from the phones microphone.

    Every Java FFT algorithm I can find only takes double[], float[] or Complex[] inputs, for obvious reasons, but I'm reading in the audio file in a byte-array, so I'm kind of confused as to where I go from here. The only thing I could find is the answer to a previous question:

    Android audio FFT to retrieve specific frequency magnitude using audiorecord

    But I'm unsure as to wether or not this is the correct procedure. Anyone with any insight?

  • soren.qvist
    soren.qvist about 12 years
    This looks elegant, but I guess what confuses me is that this looks too arbitrary (I'm green when it comes to audio in Java). If 16-bit PCM is stored in bytes in such a way that it represents the power of an analog signal over time, then shouldn't the converting process be aware of this structure? I mean, how does getDouble() even know that this is an audio file?
  • soren.qvist
    soren.qvist about 12 years
    Thanks, I'm just confused that Java knows how to interpret this data. Maybe I've got the whole idea of how it's stored wrong (Look at my comment to Kyle's answer). Anyway, any code is appreciated, I'll be using this if I dont figure it out otherwise.
  • soren.qvist
    soren.qvist about 12 years
    Looking through the documentation I see that getDouble() actually returns a double, not double[]. So this would not work.
  • mwengler
    mwengler about 12 years
    @Kyle This answer is wrong. Wrong enough that it won't even compile. - getDouble() returns type double not double[]. This stops it compiling. - getDouble() grabs 4 bytes at once, strings them together in a 32-bits and interprets the whole thing as a double. Since the byte array was not stored as doubles, this will produce gibberish results, and only 1/2 as many doubles can be pulled from array as there were shorts put in to the array. - See my answer above for a way to use ByteBuffer to convert byte[] to short[] that works.
  • soren.qvist
    soren.qvist about 12 years
    Thanks for the edit mwengler. However, shouldn't pcmAsFloats be half length of the short array? 1 float = 4 bytes, 1 short = 2 bytes?
  • soren.qvist
    soren.qvist about 12 years
    Nevermind, it should of course be the same length as the short array as it is the same amount of samples.