Nand
Nand

Reputation:

How to convert a (short) sample in a soundfile to array of bytes

In converting from short to a byte array I found the following solution on the web but could not quite understand the logic involved.

//buffer is an array of bytes, bytes[]
buffer[position] = (byte)(sample & 0xff);
buffer[position+1] = (byte)((sample >> 8) & 0xff);

Can someone tell me why 0xff (256) is being anded to the sample which is a short?

Upvotes: 3

Views: 1969

Answers (4)

user633535
user633535

Reputation: 11

buffer[position] = (byte)(sample & 0xff);
buffer[position+1] = (byte)((sample >> 8) & 0xff);

must be :

buffer[position] = (byte)((sample >> 8) & 0xff);
buffer[position+1] = (byte)(sample & 0xff);

Upvotes: 1

Vinko Vrsalovic
Vinko Vrsalovic

Reputation: 340486

This code probably comes from C code (or was written by a C programmer who don't parse Java as well as erickson does). This is because in Java a cast from a type with more information to a type with less information will discard the higher order bits and thus the & 0xff is unnecessary in both cases.

A short has 16 bits, two bytes. So it needs to take two slots in the byte array, because if we just casted a short into a byte one byte would be lost.

So, the code you have does

1110001100001111 sample
0000000011111111 0xff
0000000000001111 sample & 0xff => first byte`

Then, displaces the sample to get the second byte

0000000011100011 sample >> 8
0000000011111111 0xff
0000000011100011 (sample >> 8 ) & 0xff => second byte

Which can be a lot better written as erickson shows below (hopefully it'll be above soon).

Upvotes: 11

erickson
erickson

Reputation: 269877

The other answers have some good information, but unfortunately, they both promote an incorrect idea about the cast to byte.

The & 0xFF is unnecessary in both cases in your original code.

A narrowing cast discards the high-order bits that don't fit into the narrower type. In fact, the & 0xFF actually first causes the short to be promoted to an int with the most significant 24 bits cleared, which is then chopped down and stuffed in a byte by the cast. See the Java Language Specification Section §5.1.3 for details.

buffer[position] = (byte) sample;
buffer[position+1] = (byte) (sample >>> 8);

Also, note my use of the right shift with zero extension, rather than sign extension. In this case, since you're immediately casting the result of the shift to a byte, it doesn't matter. In general, however, the operators give different results, and you should be deliberate in what you choose.

Upvotes: 2

Paul Sonier
Paul Sonier

Reputation: 39520

It makes sure there's no overflow; specifically, the first line there is taking the LSByte of "sample" and masking OUT your upper 8 bits, giving you only values in the range of 0-255; the second line there is taking the MSByte of "sample" (by performing the right-shift) and doing the same thing. It shouldn't be necessary on the second line, since the right-shift by 8 should drop out the 8 least significant bits, but it does make the code a little bit more symmetric.

I would assume that this is because since sample is a short (2 bytes) any values in the range of 256-6553 would be interpreted as 255 by the byte conversion.

Upvotes: 1

Related Questions