Playing an Integer/Double Array in Java - java

I'm trying to play an array in a Java program.
So far I was able to play byte arrays with the following code:
AudioFormat audioFormat = new AudioFormat(samplingFreq, bps, 1, true, true);
SourceDataLine sdline = AudioSystem.getSourceDataLine(audioFormat);
line.open(audioFormat);
sdline.start();
sdline.write(playArray, 0, playArray.length);
sdline.drain();
sdline.close();
However, with this I'm only able to play byte arrays since the write method only accepts byte arrays as argument. I want to be able to play 16/32 bits per sample arrays as well.
Are there any ways to play integer arrays or even doubles using AudioSystem(or any other class).

With the help of the comment from #greg-449, I was able to solve the problem. To play higher bits per second, you just need to increase the bps argument and send bytes one after another.
As an example, if we want to send 1867 as a sample, we need 16 bits which are as follows :
0000 0111 0100 1011
The first 8 bits are 7 in decimal and the second eight bits are 75 in decimal, so since we're using big endian(last argument of the AudioFormat argument), the first element of our byte array should be 7 and the second element should be 75. So for 16 bits, we just need two bytes for each sample.

Related

Merging two bytes?

I am learning how MIDI works and am wondering how to merge two bytes. There is a paragraph that states the following
“The status and channel Bytes are merged into one byte (00-FF) Because these messages have an MSB (Most Significant Byte) of 1 the command statuses actually begin at 80 hexadecimal (128 and up to 255) The LSB (Least Significant Byte takes a value of 0-F Hexadecimal (0 to 15) to specify which MIDI channel the command will be sent to. A command message tells the MIDI gear to perform certain types of things like play a note, change the volume, add effects, and other types of things. This table shows the different command status and what they do.”
I am not 100% sure what it means by merging Bytes into a byte. Any help would be appreciated. If you could provide an example of how to do this in java with an explanation I’d be even more grateful.
So I found the answer to the problem.
Byte b1 = 0xF;
Byte b2 = 0xF;
Byte merged = (b1 >> 4 | b2);
Byte 1 is shifted four bits to the left to guarantee it is the most significant bit while byte 2 is bitwise or as the least significant bits. The important thing is that the paragraph i posted above says you may merge two bytes together. Both bytes must be at a maximum of 4 bits. If they exceed 8 bits total the result is a short or int based on how large the result is.

Unknown input byte length convert to int

My android program need to receive int values from arduino analog sensor via usb and print them on real time graph, i receive byte[] from call back function.
i tried many ways to convert from byte[] to string or int include new String new Integer BigInteger parseInt and some code method that i find in other topics, but nothing work i receive only half of the correct values, other values to much bugger or smaller.
The byte[] length changed from 1 to 4 , their is some empty bytes, it look like this(log):
How i can to convert it to correct values? where the problem?
In ideal i need receive int values between 230 to 300 from sensor.
It seems that your sensor is using text protocol. If I convert your bytes to ASCII chars, it will be:
..
10-LF
50-2
53-5
56-8
..
13-CR
10-LF
50-2
53-5
..
54-6
13-CR
10-LF
etc.
Interpreted as
258
256
so, I thing the best solution is to accumulate received bytes as chars and when CRLF is reveived, read whole string (with stripped CRLF) as int - probably via parseInt.
Arduino code segment?
Guessing badly : int is a 16 bit value byte is 8 bits.
Int_8 is -128 to 127 . uint8_t 0-255 not supported by java as far as i know but you can use the char type unsigned 16 bit(need to cast it).

Combining elements of a byte[] array into 16-bit numbers

This is an excerpt of code from a music tuner application. A byte[] array is created, audio data is read into the buffer arrays, and then the for loop iterates through buffer and combines the values at indices n,n+1, to create an array of 16-bit numbers that is half the length.
byte[] buffer = new byte[2*1200];
targetDataLine.read(buffer, 0, buffer.length)
for ( int i = 0; i < n; i+=2 ) {
int value = (short)((buffer[i]&0xFF) | ((buffer[i+1]&0xFF) << 8)); //**Don't understand**
a[i >> 1] = value;
}
So far, what I have is this:
From a different SO post, I learned that every byte being stored in a larger type must be & with 0xFF, due to its conversion to a 32-bit number. I guess the leading 24 bits are filled with 1s (though I don't know why it isn't filled with zeros... wouldn't leading with 1s change the value of the number? 000000000010 (2) is different from 111111110010 (-14), after all.), so the purpose of 0xff is to only grab the last 8 bits (which is the whole byte).
When buffer[i+1] is shifted left by 8 bits, this makes it so that, when ORing, the eight bits from buffer[i+1] are in the most significant positions, and the eight bits from buffer[i] are in the least significant eight bits. We wind up with a 16-bit number that is of the form buffer[i+1] + buffer[i]. (I'm using + but I understand it's closer to concatenation.)
First, why are we ORing buffer[i] | buffer[i+1] << 8? This seems to destroy the original sound information unless we pull it back out in the same way; while I understand that OR will combine them into one value, I don't see how that value can be useful or used in calculations later. And the only way this data is accessed later is as its literal values:
diff += Math.abs(a[j]-a[i+j];
If I have 101 and 111, added together I should get 12, or 1100. Yet 101 | 111 << 3 gives 111101, which is equal to 61. The closest I got to understanding was that 101 (5) | 111000 (56) is the same as adding 5+56=61. But the order matters -- doing the reverse 101 <<3 | 111 is completely different. I really don't understand how the data can remain useful, when it is OR'd in this way.
The other problem I'm having is that, because Java uses signed bytes, the eighth position doesn't indicate the value, but the sign. If I'm ORing two binary signed numbers, then in the resulting 16-bit number, the bit at 2⁷ is now acting as a value instead of a placeholder. If I had a negative byte before running the OR, then in my final value post-operation, it would now erroneously be acting as though the original number had a positive 2⁷ in it. 0xff doesn't get rid of this, because it preserves the eighth, signed byte, so shouldn't this be a problem?
For example, 1111 (-1) and 0101, when OR'd, might give 01011111. But 1111 wasn't representing POSITIVE 1111, it was representing the signed version; yet in the final answer, it now is acting as a positive 2³.
UPDATE: I marked the accepted answer, but it took that + a little extra work to figure out where I went wrong. For anyone who may read this in the future:
As far as the signing goes, the code I have uses signed bytes. My only guess as to why this doesn't mess anything up is because all of the values received might be of positive sign. Except that this doesn't make sense, given a waveform varies amplitude from [-1,1]. I'm going to play around with this to try and figure it out. If there are negative signs, the implementation of code here doesn't seem to remove the 1 when ORing, so I suspect that it doesn't affect the computation too much (given that we're dealing with really large values (diff += means diff will be really large -- a few extra 1s shouldn't hurt the outcome given the code and the comparisons it relies on. So this was all wrong. I gave it some more thought and it's really simple, actually -- the only reason this was such a problem is because I didn't know about big-endian, and then once I read about it, I misunderstood exactly how it is implemented. Endian-ness explained in the next bulletpoint.
Regarding the order in which the bits are placed, destroying the sound, etc. The code I'm using sets bigEndian=false, meaning that the byte order goes from least significant byte to most significant byte. For this reason, combining the two indices of buffer requires taking the second index, placing its bits first, and placing the first index as second (so we are now in big-endian byte order). One of the problems I had was the impression that "endian-ness" determines the bit order. I thought 10010101 big-endian would become 10101001 small-endian. Turns out this is not the case -- the bits in each byte remain in their original order; the difference is that the bytes are ordered "backward". So 10110101 111000001 big-endian becomes 11100001 10110101 -- same bit order within each byte; however, different byte order.
Finally, I'm not sure why, but the accepted answer is correct: targetDataLine.read() may place the bits into a byte array only (not just in my code, but in all Java code using targetDataLine -- read() only accepts arguments where the destination var is a byte array), but the data is in fact one short split into two bytes. It is for this reason that every two indices must be combined together.
Coming back to the signing goes, it should be obvious by now why this isn't an issue. This is the commenting that I now have in the code, which more coherently explains what it took all of this^ to explain before:
/* The Javadoc explains that the targetDataLine will only read to a byte-typed array.
However, because the sample size is 16-bit, it is actually storing 16-bit numbers
there (shorts), auto-parsing them every eight bits. Additionally, because it is storing
them in little-endian, bits [2^0,2^7] are stored in index[i] in normal order (powers 76543210)
while bits [2^8,2^15] are stored in index[i+1]. So, together they currently read as [7-6-5-4-3-2-1-0 15-14-13-12-11-10-9-8],
which is a problem. In the next for loop, we take care of this and re-organize the bytes by swapping every pair (remember the bits are ok, but the bytes are out of order).
Also, although the array is signed, this will not matter when we combine bytes, because the sign-bit (2^15) will be placed
back at the beginning like it normally is; although 2^7 currently exists as the most significant bit in its byte,
it is not a sign-indicating bit,
because it is really the middle of the short which was split. */
This is combining the byte stream from input in low bytes first byte order to a stream of shorts in internal byte order.
With sign extesion it is more a question of the sign encoding of the original byte stream. If the original byte stream is unsigned (coding values from 0 to 255), then the overcomes the then unwanted effects of java treating values as signed. So educated guess is taht the external byte strem encodes unsigned bytes.
Judging whether the code is plausible needs information on what externel encoding is being treated and what internal encoding is used. E.g. (wild guess could be totally wrong!): the two byte junks read coud belong to 2 channels of a stereo sound encoding and are put into a single short for ease of internal processing. You should look at the encoding being read and the use of the converted data within the application.

Isolating arbitrary bits from a Byte array

In my android app I receive from a sensor data with the size of 8 Byte
via Bluetooth Smart using Android BluetoothGatt. The data contains values for temperature, pressure and humidity. The values are splitted up in the following way.
PRESSURE:
Byte 1 + Byte 2 + first 4 Bits of Byte 3, other 4 bits are 0
TEMPERATURE:
Byte 4 + Byte 5 + first 4 bits of Byte 6, other 4 bits are 0
HUMIDITY:
Byte 7 + Byte 8
Now at the moment I have a Byte Array that contains the 8 Byte.
My Problem is that I don't know how to extract or isolate the bits for temperature, pressure and humidity as described above.
Does anyone have an idea how to solve this?
You need to use bit manipulation operations to extract the values.
For example
int pressure = (byte[0]&0xff)<<16+(byte[1]&0xff)<<8+(byte[2]&0xff)
(the 16s and 8s may need to be 12 and 4 or 0 4 and 12 depending on exactly what it means).
The operations you need are << which shifts the bits inside the byte around and the &0xff which changes the signed byte into a signed integer before you shift it. Otherwise the sign bit will mess things up.

How to determine if 8bit WAV File is signed or unsigned, using Java and without javax.sound

I need to know whether a ".wav" of 8bits, is signed or unsigned PCM, by only reading file. I cannot use "javax.sound.sampled.*" or AudioSystem libraries.
8 bit (or lower) WAV files are always unsigned. 9 bit or higher are always signed:
Each sample is contained in an integer i. The size of i is the smallest number of bytes required to contain the specified sample size. The least significant byte is stored first. The bits that represent the sample amplitude are stored in the most significant bits of i, and the remaining bits are set to zero.
For example, if the sample size (recorded in nBitsPerSample) is 12 bits, then each sample is stored in a two-byte integer. The least significant four bits of the first (least significant) byte is set
to zero.
The data format and maximum and minimums values for PCM waveform samples of various sizes are as follows:
Multimedia Programming Interface
and Data Specifications 1.0 - IBM/Microsoft, August 1991
In the wav File, 8-bit samples are stored as unsigned bytes, ranging from 0 to 255.
The 16-bit samples are stored as signed integers in 2's-complement.

Categories