According to a comment from OP: cannot be reproduced any more
I use NetBeans to develop my Java programs, and they work perfectly.
But when I make a JAR file of my program, it gives me different output for the same input.
I had a hard time debugging, and I found that in NetBeans when I cast int to byte the result ranges in [-128; 128), while the same code in JCreator is in [0; 256)
How can I make the range always [-128; 128)?
private static byte[] convertHexString(String ss) {
try{
byte digest[] = new byte[ss.length() / 2];
for (int i = 0; i < digest.length; i++) {
String byteString = ss.substring(2 * i, 2 * i + 2);
int byteValue = Integer.parseInt(byteString, 16);
digest[i] = (byte) byteValue;
}
// Test
for(int i = 0; i < digest.length; ++i){
System.out.println(digest[i]);
}
return digest;
}
catch(Exception e){
return null;
}
}
It definitely looks like a bug. A byte ranges from -128 to 127, not 0 to 255.
Here is what I think is happening with a byte value of -1 (ie 0Xff), where it prints 255 instead:
public static void main(final String... args)
{
final ByteBuffer buf = ByteBuffer.allocate(4);
// What Java would do on casting...
buf.put((byte) 0xff);
buf.put((byte) 0xff);
buf.put((byte) 0xff);
buf.put((byte) 0xff);
buf.rewind();
System.out.println(buf.getInt()); // -1 -- good
buf.rewind();
// What JCreator seems to do on casting...
buf.put((byte) 0);
buf.put((byte) 0);
buf.put((byte) 0);
buf.put((byte) 0xff);
buf.rewind();
System.out.println(buf.getInt()); // 255 -- WRONG
}
That is, when "upcasting" from byte to int, whatever Java compiler you use doesn't do what the JLS requires it to do, that is, to carry the sign bit.
I seriously doubt that the compiler/runner you use is Oracle's JDK at the command line too for that reason.
(note that a PrintStream has a method to print an int, but not a byte; therefore the byte is promoted to an int)
It would appear that the value from the byte[] isn't converted properly in the println (anyhow, not as you expect and the JLS has it).
You can use
System.out.println(Byte.toString(digest[i]));
which should display -128 .. 127
Related
I have an array of bytes, byte bytes[], representing a greyscale image.
I want to invert the colours of this image - so figured I would just flip the bits (bitwise not).
I have attempted this as seen below (have included an extra loop to populate a dummy byte array to allow quick and easy re-creation of my problem)
Random rand = new Random();
byte bytes[] = new byte[500];
// populate a dummy byte array
for (int i = 0; i < bytes.length; ++i)
{
new Random().nextBytes(bytes);
System.out.println(bytes[i]);
}
for (int i = 0; i < bytes.length; ++i)
{
System.out.print(bytes[i] + " ");
//bytes[i] = ~bytes[i]; This throws an error as apparantly java treats a byte array as an integer array?!
bytes[i] = (byte)~bytes[i]; // This compiles but output not a bitwise not, results displayed below
System.out.println(bytes[i]);
}
The results I am getting are:
116 -117
48 -49
70 -71
What I'm looking for is: (I have added the binary manually to fuly illustrate what my understanding of bitwise not (please correct if wrong)
116 (01110100) = (10001011) 139
48 (00110000) = (11001111) 207
70 (01000110) = (10111001) 185
Thanks in advance for any advice
You can XOR the value with 255, so the particular line should be
bytes[i] = (byte) (bytes[i] ^ 0xff);
10001011 actually represents -117 (in two's complement format: https://en.wikipedia.org/wiki/Two%27s_complement ); Java byte type is signed. You probably want unsigned byte values as output (which range from 0 to 255).
As Java byte type is signed, it can only have values from -128 to 127. If you want to have values between 0 and 255 (like 139), you have to use some other type, for example short:
byte b = 116;
short sh = (short) (((short) b) ^ 0xff);
System.out.println(sh);
This produces 139.
You can leave it as it is. It's already correct, just printed in a confusing way.
For example note that (byte)207 will (by default) be printed as -49. But it's still the same value, it's just printed with a different interpretation of the most significant bit.
In short, change nothing.
java
public static byte[] bitwiseNot(byte[] array) {
byte[] bytes = new byte[array.length];
for (int i = 0; i < array.length; i++) {
bytes[i] = (byte) (array[i] ^ 0xff);
}
return bytes;
}
kotlin xor syntax
import kotlin.experimental.xor
fun bitwiseNot(array: ByteArray) : ByteArray {
return array.map{ b -> b xor 0xFF.toByte() }.toByteArray()
}
kotlin with Byte.inv() syntax
import kotlin.experimental.inv
fun bitwiseNot(array: ByteArray) : ByteArray {
return array.map{ b -> b.inv() }.toByteArray()
}
If you want to convert to BufferedImage
I want to convert integer to byte[] in java. And I did some research and found the code
public byte[] integerToBytes (int i) {
byte[] result = new byte[4];
result[0] = (byte) (i >>> 24);
result[1] = (byte) (i >>> 16);
result[2] = (byte) (i >>> 8);
result[3] = (byte) (i /*>> 0*/);
return result;
}
I'm pretty sure the code is right cause it passes the tests. However, I'm a little bit confused.
Suppose the integer is 36666666. And binary representation is 10001011110111110100101010.I can understand why it is true for result[0] since after the shift, it becomes 10001011(0x22).However,for result[1],after the shift,it becomes 1000101111011111(0x22F7).
But what I really want is just 0xF7.
Can someone explain this to me or I understand this code in a wrong way?
Cheers
The reason result[1] and others are just the lowest eight bits is due to the the cast to a byte performed on each assignment. Casting an int like 0x22F7 to a byte cuts off the top 3 bytes and leaves the least significant byte to be assigned to the new variable. Thus 0x22f7 becomes just 0xf7. Hope this helps.
I'm using jLayer to decode MP3 data, with this call:
SampleBuffer output = (SampleBuffer) decoder.decodeFrame(frameHeader, bitstream);
This call which returns the decoded data, returns an array of short[].
output.getBuffer();
When I call AudioTrack write() with that method, it plays fine as I loop through the file:
at.write(output.getBuffer(), 0, output.getBuffer().length);
However, when I convert the short[] array to byte[] array using any of the methods in this answer: https://stackoverflow.com/a/12347176/1176436 the sound gets distorted and jittery:
at.write(output.getBuffer(), 0, output.getBuffer().length);
becomes:
byte[] array = ShortToByte_Twiddle_Method(output.getBuffer());
at.write(array, 0, array.length);
Am I doing anything wrong and what can I do to fix it? Unfortunately I need the pcm data to be in a byte array for another 3rd party library I'm using. The file is 22kHz if that matters and this is how at is being instantiated:
at = new AudioTrack(AudioManager.STREAM_MUSIC, 22050, AudioFormat.CHANNEL_OUT_STEREO,
AudioFormat.ENCODING_PCM_16BIT, 10000 /* 10 second buffer */,
AudioTrack.MODE_STREAM);
Thank you so much in advance.
Edit: This is how I'm instantiating the AudioTrack variable now. So for 44kHz files, the value that is getting sent is 44100, while for 22kHz files, the value is 22050.
at = new AudioTrack(AudioManager.STREAM_MUSIC, decoder.getOutputFrequency(),
decoder.getOutputChannels() > 1 ? AudioFormat.CHANNEL_OUT_STEREO : AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT, 10000 /* 10 second buffer */,
AudioTrack.MODE_STREAM);
This is decode method:
public byte[] decode(InputStream inputStream, int startMs, int maxMs) throws IOException {
ByteArrayOutputStream outStream = new ByteArrayOutputStream(1024);
float totalMs = 0;
boolean seeking = true;
try {
Bitstream bitstream = new Bitstream(inputStream);
Decoder decoder = new Decoder();
boolean done = false;
while (!done) {
Header frameHeader = bitstream.readFrame();
if (frameHeader == null) {
done = true;
} else {
totalMs += frameHeader.ms_per_frame();
if (totalMs >= startMs) {
seeking = false;
}
if (!seeking) {
// logger.debug("Handling header: " + frameHeader.layer_string());
SampleBuffer output = (SampleBuffer) decoder.decodeFrame(frameHeader, bitstream);
short[] pcm = output.getBuffer();
for (short s : pcm) {
outStream.write(s & 0xff);
outStream.write((s >> 8) & 0xff);
}
}
if (totalMs >= (startMs + maxMs)) {
done = true;
}
}
bitstream.closeFrame();
}
return outStream.toByteArray();
} catch (BitstreamException e) {
throw new IOException("Bitstream error: " + e);
} catch (DecoderException e) {
throw new IOException("Decoder error: " + e);
}
}
This is how it sounds (wait a few seconds): https://vimeo.com/60951237 (and this is the actual file: http://www.tonycuffe.com/mp3/tail%20toddle.mp3)
Edit: I would have loved to have split the bounty, but instead I have given the bounty to Bill and the accepted answer to Neil. Both were a tremendous help. For those wondering, I ended up rewriting the Sonic native code which helped me move along the process.
As #Bill Pringlemeir says, the problem is that your conversion method doesn't actually convert. A short is a 16 bit number; a byte is an 8 bit number. The method you have chosen doesn't convert the contents of the shorts (ie go from 16 bits to 8 bits for the contents), it changes the way in which the same collection of bits is stored. As you say, you need something like this:
SampleBuffer output = (SampleBuffer) decoder.decodeFrame(frameHeader, bitstream);
byte[] array = MyShortToByte(output.getBuffer());
at.write(array, 0, array.length);
#Bill Pringlemeir's approach is equivalent to dividing all the shorts by 256 to ensure they fit in the byte range:
byte[] MyShortToByte(short[] buffer) {
int N = buffer.length;
ByteBuffer byteBuf = ByteBuffer.allocate(N);
while (N >= i) {
byte b = (byte)(buffer[i]/256); /*convert to byte. */
byteBuf.put(b);
i++;
}
return byteBuf.array();
}
This will work, but will probably give you very quiet, edgy tones. If you can afford the processing time, a two pass approach will probably give better results:
byte[] MyShortToByte(short[] buffer) {
int N = buffer.length;
short min = 0;
short max = 0;
for (int i=0; i<N; i++) {
if (buffer[i] > max) max = buffer[i];
if (buffer[i] < min) min = buffer[i];
}
short scaling = 1+(max-min)/256; // 1+ ensures we stay within range and guarantee no divide by zero if sequence is pure silence ...
ByteBuffer byteBuf = ByteBuffer.allocate(N);
for (int i=0; i<N; i++) {
byte b = (byte)(buffer[i]/scaling); /*convert to byte. */
byteBuf.put(b);
}
return byteBuf.array();
}
Again, beware signed / unsigned issue. The above works signed-> signed and unsigned->unsigned; but not between the two. It may be that you are reading signed shorts (-32768-32767), but need to output unsigned bytes (0-255), ...
If you can afford the processing time, a more precise (smoother) approach would be to go via floats (this also gets round the signed/unsigned issue):
byte[] MyShortToByte(short[] buffer) {
int N = buffer.length;
float f[] = new float[N];
float min = 0.0f;
float max = 0.0f;
for (int i=0; i<N; i++) {
f[i] = (float)(buffer[i]);
if (f[i] > max) max = f[i];
if (f[i] < min) min = f[i];
}
float scaling = 1.0f+(max-min)/256.0f; // +1 ensures we stay within range and guarantee no divide by zero if sequence is pure silence ...
ByteBuffer byteBuf = ByteBuffer.allocate(N);
for (int i=0; i<N; i++) {
byte b = (byte)(f[i]/scaling); /*convert to byte. */
byteBuf.put(b);
}
return byteBuf.array();
}
The issue is with your short to byte conversion. The byte conversion link preserves all information including the high and low byte portions. When you are converting from 16bit to 8bit PCM samples, you must discard the lower byte. My Java skills are weak, so the following may not work verbatim. See also: short to byte conversion.
ByteBuffer byteBuf = ByteBuffer.allocate(N);
while (N >= i) {
/* byte b = (byte)((buffer[i]>>8)&0xff); convert to byte. native endian */
byte b = (byte)(buffer[i]&0xff); /*convert to byte; swapped endian. */
byteBuf.put(b);
i++;
}
That is the following conversion,
AAAA AAAA SBBB BBBB -> AAAA AAAA, +1 if S==1 and positive else -1 if S==1
A is a bit that is kept. B is a discarded bit and S is a bit that you may wish to use for rounding. The rounding is not needed, but it may sound a little better. Basically, 16 bit PCM is higher resolution than 8 bit PCM. You lose those bits when the conversion is done. The short to byte routine tries to preserve all information.
Of course, you must tell the sound library that you are using 8-bit PCM. My guess,
at = new AudioTrack(AudioManager.STREAM_MUSIC, 22050, AudioFormat.CHANNEL_OUT_STEREO,
AudioFormat.ENCODING_PCM_8BIT, 10000 /* 10 second buffer */,
AudioTrack.MODE_STREAM);
If you can only use 16bit PCM to play audio, then you have to do the inverse and convert the 8bit PCM from the library to 16bit PCM for playback. Also note, that typically, 8bit samples are often NOT straight PCM but u-law or a-law encoded. If the 3rd party library uses these formats, the conversion is different but you should be able to code it from the wikipedia links.
NOTE: I have not included the rounding code as overflow and sign handling will complicate the answer. You must check for overflow (Ie, 0x8f + 1 gives 0xff or 255 + 1 giving -1). However, I suspect the library is not straight 8bit PCM.
See Also: Alsa PCM overview, Multi-media wiki entry on PCM - Ultimately Android uses ALSA for sound.
Other factors that must be correct for a PCM raw buffer are sample rate, number of channels (stereo/mono), PCM format including bits, companding, little/big endian and sample interleaving.
EDIT: After some investigation, the JLayer decoder typically returns big endian 16bit values. The Sonic filter, takes a byte but threats them as 16bit little endian underneath. Finally, the AudioTrack class expects 16 bit little endian underneath. I believe that for some reason the JLayer mp3 decoder will return 16bit little endian values. The decode() method in the question does a byte swap of the 16 bit values. Also, the posted audio sounds as if the bytes are swapped.
public byte[] decode(InputStream inputStream, int startMs, int maxMs, bool swap) throws IOException {
...
short[] pcm = output.getBuffer();
for (short s : pcm) {
if(swap) {
outStream.write(s & 0xff);
outStream.write((s >> 8) & 0xff);
} else {
outStream.write((s >> 8) & 0xff);
outStream.write(s & 0xff);
}
}
...
For 44k mp3s, you call the routine with swap = true;. For the 22k mp3 swap = false. This explains all the reported phenomena. I don't know why the JLayer mp3 decoder would sometimes output big endian and other times little endian. I imagine it depends on the source mp3 and not the sample rate.
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.
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));
Use the following code:
ret[0] = (byte)(x & 0xff);
ret[1] = (byte)((x >> 8) & 0xff);
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
}
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.
I want to change a values in byte array to put a long timestamp value in in the MSBs. Can someone tell me whats the best way to do it. I do not want to insert values bit-by-bit which I believe is very inefficient.
long time = System.currentTimeMillis();
Long timeStamp = new Long(time);
byte[] bArray = new byte[128];
What I want is something like:
byte[0-63] = timeStamp.byteValue();
Is something like this possible . What is the best way to edit/insert values in this byte array. since byte is a primitive I dont think there are some direct implementations I can make use of?
Edit:
It seems that System.currentTimeMillis() is faster than Calendar.getTimeInMillis(), so replacing the above code by it.Please correct me if wrong.
There are multiple ways to do it:
Use a ByteBuffer (best option - concise and easy to read):
byte[] bytes = ByteBuffer.allocate(Long.SIZE / Byte.SIZE).putLong(someLong).array();
You can also use DataOutputStream (more verbose):
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
dos.writeLong(someLong);
dos.close();
byte[] longBytes = baos.toByteArray();
Finally, you can do this manually (taken from the LongSerializer in Hector's code) (harder to read):
byte[] b = new byte[8];
for (int i = 0; i < size; ++i) {
b[i] = (byte) (l >> (size - i - 1 << 3));
}
Then you can append these bytes to your existing array by a simple loop:
// change this, if you want your long to start from
// a different position in the array
int start = 0;
for (int i = 0; i < longBytes.length; i ++) {
bytes[start + i] = longBytes[i];
}
If you want to really get under the hood...
public byte[] longToByteArray(long value) {
return new byte[] {
(byte) (value >> 56),
(byte) (value >> 48),
(byte) (value >> 40),
(byte) (value >> 32),
(byte) (value >> 24),
(byte) (value >> 16),
(byte) (value >> 8),
(byte) value
};
}
For me ByteBuffer and other utils are expensive from time perspective. Here are 2 methods that you can use:
// first method (that is using the second method), it return the array allocated and fulfilled
public byte[] longToByteArray(long value)
{
byte[] array = new byte[8];
longToByteArray(value,array,0);
return array;
}
// this method is useful if you have already allocated the buffer and you want to write the long a specific location in the array.
public void longToByteArray(long value, byte[] array, int startFrom)
{
for (int i=7; i>=0; i--)
{
array[startFrom+7-i] = (byte) (value >> i*8);
}
}
It doesn't look like you can slice a byte array to insert something into a subset without doing it byte by byte. Look at Grab a segment of an array in Java without creating a new array on heap . Basically what I would do is set create a 64 byte array and set the time to it then append a blank 64 byte array to it. Or just do it byte by byte.
I am updating this post because I have just announced a pre-release version of a library that will convert longs to byte arrays (and back again). The library is very small and will convert any java primitive to a byte array.
http://rschilling.wordpress.com/2013/09/26/pre-release-announcement-pend-oreille/
http://code.google.com/p/pend-oreille/
If you use it you can do things like convert long arrays to byte arrays:
Double[] doubles = new Double[1000];
for (int i = 2; i < 1002; i++) {
doubles[i - 2] = (double) i;
}
byte[] resultBytes1 = (byte[]) new PrimitiveHelper(PrimitiveUtil.unbox(doubles))
.asType(byte[].class);
You can also convert a single long value as well.
byte[] resultBytes1 = (byte[]) new PrimitiveHelper(1000l)
.asType(byte[].class);
Feel free to provide some feedback.
Update on October 4, 2013:
I've now released the production of the library http://rschilling.wordpress.com/2013/10/04/pend-oreille-official-1-0-release/