54

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.

Aaron
  • 541
  • 1
  • 4
  • 3
  • 2
    is it big-endian or little-endian? I think you need `java.nio.ByteBuffer` to handle this conversion. – LiuYan 刘研 Apr 11 '11 at 18:29
  • Possible duplicate of [how to convert short array to byte array](http://stackoverflow.com/questions/10804852/how-to-convert-short-array-to-byte-array) – patryk.beza May 11 '16 at 23:05

6 Answers6

106

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);
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • 3
    short[] audioData = ByteBuffer.wrap(audioBytes2).order(ByteOrder.BIG_ENDIAN).asShortBuffer().array(); Throws an UnsupportedOperationException. – Aaron Apr 11 '11 at 19:21
  • 1
    @Aaron - 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). – kdgregory Apr 11 '11 at 19:52
  • 1
    @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. – Peter Lawrey Apr 11 '11 at 20:31
  • Is this only converting the bytes directly to shorts or is it combining two bytes into a short like I need it to? – Aaron Apr 11 '11 at 23:42
  • 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. – Peter Lawrey Apr 12 '11 at 06:30
  • Is `byte[] bytes = {};` pseudocode for set bytes to something? Is this standard in Java stackoverflow? – Collin Bell Jan 17 '17 at 06:51
  • @CollinBell it's short hand for `byte[] bytes = new byte[0];` – Peter Lawrey Jan 17 '17 at 08:05
  • @PeterLawrey Is that standard/common notion?...just to know if I should use it when communicating with others. – Collin Bell Jan 18 '17 at 03:07
  • @CollinBell I use it all the time, I expect that's what is generally used in the JDK code. – Peter Lawrey Jan 18 '17 at 09:22
  • I suggest to use in android ByteOrder.nativeOrder() – Uriel Frankel Nov 24 '21 at 15:27
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();
}
Scott Izu
  • 2,229
  • 25
  • 12
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());
}
Edwin Dalorzo
  • 76,803
  • 25
  • 144
  • 205
5
byte[2] bytes;

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

short s = (short)r;
Radiodef
  • 37,180
  • 14
  • 90
  • 125
Jagadeesh
  • 239
  • 5
  • 9
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.

Matt DiMeo
  • 1,095
  • 8
  • 11
  • I'm actually using something similar to that after the reconversion with an audioInputStream. – Aaron Apr 11 '11 at 18:56
-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).

jtahlborn
  • 52,909
  • 5
  • 76
  • 118