byte array to short array and back again in java
Asked Answered
H

6

55

I'm having some issues taking audio data stored in a byte array, converting it to a big-endian short array, encoding it, then changing it back into a byte array. Here is what I have. The original audio data is stored in audioBytes2. I am using the same format for decode with a minus on the cos function instead. Unfortunately, changing the byte and short data types is non-negotiable.

    short[] audioData = null;
    int nlengthInSamples = audioBytes2.length / 2;
    audioData = new short[nlengthInSamples];

    for (int i = 0; i < nlengthInSamples; i++) {
       short MSB = (short) audioBytes2[2*i+1];
       short LSB = (short) audioBytes2[2*i];
       audioData[i] = (short) (MSB << 8 | (255 & LSB));
    }

    int i = 0;
    while (i < audioData.length) {
        audioData[i] = (short)(audioData[i] + (short)5*Math.cos(2*Math.PI*i/(((Number)EncodeBox.getValue()).intValue())));
        i++;
    }

    short x = 0;
    i = 0;
    while (i < audioData.length) {
        x = audioData[i];
        audioBytes2[2*i+1] = (byte)(x >>> 0);
        audioBytes2[2*i] = (byte)(x >>> 8);
        i++;
    }

I have done everything that I can think of to make this work, but the closest I've come is getting it to work every other encode/decode and I have no idea why. Thanks for any help.

Holytide answered 11/4, 2011 at 18:12 Comment(2)
is it big-endian or little-endian? I think you need java.nio.ByteBuffer to handle this conversion.Countrywoman
Possible duplicate of how to convert short array to byte arrayGlennaglennie
M
105

I also suggest you try ByteBuffer.

byte[] bytes = {};
short[] shorts = new short[bytes.length/2];
// to turn bytes to shorts as either big endian or little endian. 
ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(shorts);

// to turn shorts back to bytes.
byte[] bytes2 = new byte[shortsA.length * 2];
ByteBuffer.wrap(bytes2).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().put(shortsA);
Moton answered 11/4, 2011 at 18:49 Comment(10)
short[] audioData = ByteBuffer.wrap(audioBytes2).order(ByteOrder.BIG_ENDIAN).asShortBuffer().array(); Throws an UnsupportedOperationException.Holytide
@Holytide - yes, but what throws that exception? (hint: a ShortBuffer acts as a view on an underlying ByteBuffer, and its get() method should do exactly what you want).Cabasset
@kdgregory, It wasn't until you suggested the fix. I forgot array() only works if the underlying store is an short[] or similar primitive array to match the XxxxxBuffer.Moton
Is this only converting the bytes directly to shorts or is it combining two bytes into a short like I need it to?Holytide
As you can see it create half as many shorts as bytes and twice as many bytes are shorts. If it didn't do the conversion you needed the ByteOrder would be pointless. as just casting byte to short and back again doesn't require a ByteOrder. If you have doubts, I suggest you try it and see if it suits your needed.Moton
Is byte[] bytes = {}; pseudocode for set bytes to something? Is this standard in Java stackoverflow?Xerophagy
@CollinBell it's short hand for byte[] bytes = new byte[0];Moton
@PeterLawrey Is that standard/common notion?...just to know if I should use it when communicating with others.Xerophagy
@CollinBell I use it all the time, I expect that's what is generally used in the JDK code.Moton
I suggest to use in android ByteOrder.nativeOrder()Perfection
L
13
public short bytesToShort(byte[] bytes) {
     return ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).getShort();
}
public byte[] shortToBytes(short value) {
    return ByteBuffer.allocate(2).order(ByteOrder.LITTLE_ENDIAN).putShort(value).array();
}
Legra answered 8/8, 2013 at 6:30 Comment(1)
It does not convert short array to byte array.Joannjoanna
L
6

How about some ByteBuffers?

byte[] payload = new byte[]{0x7F,0x1B,0x10,0x11};
ByteBuffer bb = ByteBuffer.wrap(payload).order(ByteOrder.BIG_ENDIAN);
ShortBuffer sb = bb.asShortBuffer();
while(sb.hasRemaining()){
  System.out.println(sb.get());
}
Lacework answered 11/4, 2011 at 18:48 Comment(0)
R
5
byte[2] bytes;

int r = bytes[1] & 0xFF;
r = (r << 8) | (bytes[0] & 0xFF);

short s = (short)r;
Rabies answered 27/6, 2015 at 10:59 Comment(0)
N
2

Your code is doing little-endian shorts, not big. You've the indexing for MSB and LSB swapped.

Since you are using big-endian shorts, you could be using a DataInputStream wrapped around a ByteArrayInputStream (and DataOutputStream/ByteArrayOutputStream) on the other end, rather than doing your own decoding.

If you're getting every other decode working, I'd guess you've got an odd number of bytes, or an off-by-one error elsewhere which is causing your mistake to get fixed on every other pass.

Finally, I'd step through the array with i+=2 and use MSB= arr[i] and LSB=arr[i+1] rather than multiplying by 2, but that's just me.

Norvell answered 11/4, 2011 at 18:30 Comment(1)
I'm actually using something similar to that after the reconversion with an audioInputStream.Holytide
R
-1

It looks like you are swapping the byte order between reading the bytes in and writing them back out (unsure if this is intentional or not).

Reaction answered 11/4, 2011 at 18:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.