Question

I've got a problem. In Java I need to read samples from a wav file. The file format is: wav, PCM_SIGNED, signed int of 2bytes = 16bits, little endian... The object reads the audio samples in BYTES and I need to convert this two bytes in one double value. I tried to use this formula but it's not completely correct:

mono = (double)((audioBytes[k] & 0xFF) | (audioBytes[k + 1] << 8));

Comparing the results with Matlab I always notice differences between the real value in Matlab and the converted one in Java. Can anybody help me please? Thank you, Dave

Was it helpful?

Solution

You haven't given us enough information to know why you're getting different results in Matlab and Java. Usually you scale the short channel data [-32768..32767] to a double in the range [-1..1] which it looks like you are attempting to do. Your java result: -3.0517578125E-5 is correct for the short value -1: -1/32768. I don't know why your Matlab result is different. You haven't shown us how you are arriving at your Matlab results.

If you have a large sequence of bytes (which I'm guessing you do), and you don't want to worry about BIG-ENDIAN vs LITTLE-ENDIAN or shifting bits and bytes, let java take care of it for you:

import java.nio.*;
...
ByteBuffer buf = ByteBuffer.wrap(audioBytes);
buf.order(ByteOrder.LITTLE_ENDIAN);

while (buf.remaining() >= 2) {
    short s = buf.getShort();
    double mono = (double) s;
    double mono_norm = mono / 32768.0;
    ...
}

ByteBuffer.getShort() reads the next two bytes of the buffer, takes care of the Little-Endian ordering, converts the bytes to a short, and positions itself for the next getXXX() call.

OTHER TIPS

This is the correct way:

double sampleValue = (double)(( bytes[0]<<8 ) | ( bytes[1]&0x00FF ));

(Change indices to swap little/big)

Cant you just do most_significant byte * 256 + least_significant_byte and then cast to double?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top