Alexandru Circus
Alexandru Circus

Reputation: 5538

Java - from short to byte[2] using LITTLE_ENDIAN

I have some problems trying yo convert short value to byte[2]. I'm using this to make some transformations on some audio data buffer(applying gain to buffer). First I load the audio buffer like this:

mRecorder.read(buffer, 0, buffer.length);

where buffer is

private byte[] buffer;

Than, I get the sample (the recording is in 16bit sample size), like this:

short sample = getShort(buffer[i*2], buffer[i*2+1]);

The getShort is define like this:

/* 
 * 
 * Converts a byte[2] to a short, in LITTLE_ENDIAN format
 * 
 */
private short getShort(byte argB1, byte argB2)
{
    return (short)(argB1 | (argB2 << 8));
}

Then I apply gain to the sample:

sample *= rGain;

After this, I try to get back the byte array from the multiplied sample:

byte[] a = getByteFromShort(sample);

But this fails, because the sound has a lot of noise even if the gain is 1.

Below is the getByteFromShort method definion:

    private byte[] getByteFromShort(short x){
//variant 1 - noise
    byte[] a = new byte[2];
    a[0] = (byte)(x & 0xff);
    a[1] = (byte)((x >> 8) & 0xff);

//variant 2 - noise and almost broke my ears - very loud
//      ByteBuffer buffer = ByteBuffer.allocate(2);
//      buffer.putShort(x);
//      buffer.flip();

    return a;
}

So the problem is when converting the short value to byte[2]. When the gain was 1.0, the sound was fill with noise.

Below is the full gain applying method:

for (int i=0; i<buffer.length/2; i++)
{ // 16bit sample size                      
    short curSample = getShort(buffer[i*2], buffer[i*2+1]);
if(rGain != 1){
    //apply gain
    curSample *= rGain;
    //convert back from short sample that was "gained" to byte data
    byte[] a = getByteFromShort(curSample);
    //modify buffer to contain the gained sample
    buffer[i*2] = a[0];
    buffer[i*2 + 1] = a[1];
}

   }

Could you guys please take a look over getByteFromShort method and tell me where I'm wrong?

Thanks.

Upvotes: 1

Views: 1417

Answers (4)

x22
x22

Reputation: 541

getByteFromShort() seems OK.

getShort(byte argB1, byte argB2) is wrong. It produces incorrect result when argB1 is negative.

It should be

return (short)((argB1 & 0xff) | (argB2 << 8));

Upvotes: 5

BillRobertson42
BillRobertson42

Reputation: 12883

ByteBuffer and its cohorts in java.nio can help with this. Basically, you will create a ByteBuffer backed by an array with your data ByteBuffer.wrap(array). You can then set the endianness of the buffer with ByteBuffer.order() and use functions like get/put Int/Short/byte... to manipulate data in the underlying array.

Upvotes: 0

Peter Lawrey
Peter Lawrey

Reputation: 533710

I would use ByteBuffer

ByteBuffer buffer = ByteBuffer.allocate(8*1024);
mRecorder.read(buffer.array(), 0, buffer.capacity());
// using NIO
mRecorder.read(buffer);

while(buffer.remaining() > 1) {
    short s = bb.getShort(x);
    // do something with s
}

Upvotes: 0

GingerHead
GingerHead

Reputation: 8230

Use the following code:

ret[0] = (byte)(x & 0xff);
ret[1] = (byte)((x >> 8) & 0xff);

Upvotes: 0

Related Questions