receive data as float in processing programming from serial port - java

below is a code from arduino:
typedef union{
float number;
uint8_t bytes[4];
} FLOATUNION_t;
FLOATUNION_t myValue;
float getFloat(){
int cont = 0;
FLOATUNION_t f;
while (cont < 4 ){
f.bytes[cont] = Serial.read() ;
cont = cont +1;
}
return f.number;
}
is there any alternative to this for processing programming(java)?
totally i need a code which recieve binary data from serial port and i want that data in float type in processing programming.
originally i am sending some data through serial send block in Simulink to processing programming, i am using processing.serial library , but i could not get thise bits and convert them to float or int.

You need to :
buffer each byte a time from Simulink into Processing: Serial's buffer() / serialEvent() / readBytes(bytesFromSimulink) could work nicely in tandem here
pack the bytes into a an int (shifting bytes as needed) and OR-ing them:
int intBits = bytesFromSimulink[3] << 24 | bytesFromSimulink[2] << 16 | bytesFromSimulink[1] << 8 | bytesFromSimulink[0];
convert the int to a float via Float.intBitsToFloat(): floatFromSimulink = Float.intBitsToFloat( intBits );
Here's a basic sketch to illustrate the ideas above:
import processing.serial.*;
// how many bytes are expecting sent in one go
final int SERIAL_BUFFER_SIZE = 4;
// pre-allocate serial read buffer
byte[] bytesFromSimulink = new byte[SERIAL_BUFFER_SIZE];
// float from bytes
float floatFromSimulink;
// serial port reference
final String PORT_NAME = "COM2";
final int BAUD_RATE = 115200;
Serial simulinkPort;
void setup(){
size(300, 300);
try{
simulinkPort = new Serial(this, PORT_NAME, BAUD_RATE);
// only fire serialEvent() when the right number of bytes has been buffered
simulinkPort.buffer(SERIAL_BUFFER_SIZE);
}catch(Exception e){
println("error opening serial port(" + PORT_NAME + "): double check the port name, wiring and make sure the port isn't already open in another application");
e.printStackTrace();
exit();
}
}
void draw(){
background(0);
// format bytes to hex and float to 2 decimal places
text(String.format("hex: %s\nfloat: %.2f", hex(byteFromSimulink), floatFromSimulink),
10, 15);
}
void serialEvent(Serial port) {
port.readBytes(bytesFromSimulink);
// pack bytes into a 32bit int (shifting each byte accordingly): double check the byte order (e.g. LSB / MSB)
int intBits = bytesFromSimulink[3] << 24 |
bytesFromSimulink[2] << 16 |
bytesFromSimulink[1] << 8 |
bytesFromSimulink[0];
// convert int to to float
floatFromSimulink = Float.intBitsToFloat( intBits );
}
// pretty-print byte array
String hex(byte[] data){
String output = "";
for(byte singleByte : data){
output += hex(singleByte) + ' ';
}
return output;
}
Hopefully the above just works, but bare in mind it's untested code.
There are two things I could think could go wrong:
The bytes not arriving in the correct order. (let's say Simulink is continuously streaming serial data, but Processing starts later and only catches data from the 2nd, 3rd or 4th byte instead of the first: data will be shifted). You can try to remove buffer()/serialEvent() with a blocking loop and getting one byte at a time (e.g. if(simulinkPort.available() >= 1) myNewByte = simulinkPort.read();) and counting / packing bytes into the byte array manually. You could also try a call/response approach: e.g. Simulink doesn't send any data until it receives a single character from Processing (let's say 'A'), then starts streaming, so Processing is ready to buffer 4 bytes at a time from the get go.
I'm not sure in which order the bytes are sent from simulink: above I'm assuming right to left, but it's the other way around simply swap indices: int intBits = byteFromSimulink[0] << 24 | byteFromSimulink[1] << 16 | byteFromSimulink[2] << 8 | byteFromSimulink[3];
The other gotcha in Java/Processing is that bytes are from -127 to 127 so you would want mask bytes when inspecting: println(myByte & 0xFF);
Based on g00se's suggestion in the comments bellow here's an attempt at a ByteBuffer option:
import java.nio.ByteBuffer;
import processing.serial.*;
// how many bytes are expecting sent in one go
final int SERIAL_BUFFER_SIZE = 4;
// pre-allocate serial read buffer
ByteBuffer bytesFromSimulink;
// float from bytes
float floatFromSimulink;
// serial port reference
final String PORT_NAME = "COM2";
final int BAUD_RATE = 115200;
Serial simulinkPort;
void setup(){
size(300, 300);
try{
simulinkPort = new Serial(this, PORT_NAME, BAUD_RATE);
// only fire serialEvent() when the right number of bytes has been buffered
simulinkPort.buffer(SERIAL_BUFFER_SIZE);
bytesFromSimulink = ByteBuffer.allocate(SERIAL_BUFFER_SIZE);
}catch(Exception e){
println("error opening serial port(" + PORT_NAME + "): double check the port name, wiring and make sure the port isn't already open in another application");
e.printStackTrace();
exit();
}
}
void draw(){
background(0);
// format bytes to hex and float to 2 decimal places
text(String.format("hex: %s\nfloat: %.2f", hex(bytesFromSimulink), floatFromSimulink),
10, 15);
}
void serialEvent(Serial port) {
// pass new data to the byte buffer
bytesFromSimulink.put(port.readBytes(SERIAL_BUFFER_SIZE));
// set the index back to 0
bytesFromSimulink.rewind();
// read the first (rewinded) 4 bytes as a float
floatFromSimulink = bytesFromSimulink.getFloat();
}
// pretty-print byte array
String hex(ByteBuffer data){
String output = "";
for(int i = 0 ; i < data.limit(); i++){
output += hex(data.get(i)) + ' ';
}
return output;
}

Related

Store Binary Data in QR Code (ZXING Java Library)

My Java program needs to send a binary payload via QR Code, but I can't get it to work. I have tried several QR Code libraries and many approaches, but all seem to have this problem. My current implementation uses ZXING.
The problem is that all the Java libraries I've tried seem to be focused on String payloads, and do not provide support for binary data. The common suggested solution to this is to encode the binary data as Base64. However, my data is already near the size limit of QR Codes. With the 33% inflation caused by Base64 encoding, my data is too big. I have already expended significant effort into reducing the size of the payload, and it currently consists of 4 character hashes delimited by new lines; all inside max level compression by the Java Deflator class. I can't make it any smaller.
I need a way to store binary data in a QR code with minimal data inflation overhead.
Update:
I recently went back and published the referenced code as a project on GitHub for anyone who wants to use it.
https://github.com/yurelle/Base45Encoder
I developed a solution which only introduces a storage efficiency loss of -8%. It exploits a built-in compression optimization of the ZXING QR Code Library.
Explanation
ZXING will automatically detect if your String payload is purely AlphaNumeric (by their own definition), and if so, it will automatically compress 2 AlphaNumeric characters into 11 bits. The definition ZXING uses for "alphanumeric" is all-caps only, 0-9, and a few special symbols ('/', ':', etc.). All told, their definition allows 45 possible values. Then, it packs 2 of these Base45 digits into 11 bits.
2 digits in base 45 is 2,025 possible values. 11 bits has a maximum storage capacity of 2,048 possible states. This is only a loss of 1.1% in storage efficiency behind raw binary.
45 ^ 2 = 2,025
2 ^ 11 = 2,048
2,048 - 2,025 = 23
23 / 2,048 = 0.01123046875 = 1.123%
However, this is the ideal / theoretical efficiency. My implementation processes data in chunks, using a Long as a computational buffer. However, since Java Long's are singed, we can only use the lower 7 bytes. The conversion code requires continuously positive values; using the highest 8th byte would contaminate the sign bit and randomly produce negative values.
Real-World Test:
Using a 7 byte Long to encode a 2KB buffer of random bytes, we get the following results.
Raw Binary Size: 2,048
Encoded String Size: 3,218
QR Code Alphanum Size: 2,213 (after the QR Code compresses 2 base45 digits to 11 bits)
This is a real-world storage efficiency loss of only 8%.
2,213 - 2,048 = 165
165 / 2,048 = 0.08056640625 = 8.0566%
Solution
I implemented it as a self-contained static utility class, so all you have to do is call:
//Encode
final byte[] myBinaryData = ...;
final String encodedStr = BinaryToBase45Encoder.encodeToBase45QrPayload(myBinaryData);
//Decode
final byte[] decodedBytes = BinaryToBase45Encoder.decodeBase45QrPayload(encodedStr);
Alternatively, you can also do it via InputStreams:
//Encode
final InputStream in_1 = ... ;
final String encodedStr = BinaryToBase45Encoder.encodeToBase45QrPayload(in_1);
//Decode
final InputStream in_2 = ... ;
final byte[] decodedBytes = BinaryToBase45Encoder.decodeBase45QrPayload(in_2);
Here's the implementation
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
/**
* For some reason none of the Java QR Code libraries support binary payloads. At least, none that
* I could find anyway. The commonly suggested workaround for this is to use Base64 encoding.
* However, this results in a 33% payload size inflation. If your payload is already near the size
* limit of QR codes, this is a lot.
*
* This class implements an encoder which takes advantage of a built-in compression optimization
* of the ZXING QR Code library, to enable the storage of Binary data into a QR Code, with a
* storage efficiency loss of only -8%.
*
* The built-in optimization is this: ZXING will automatically detect if your String payload is
* purely AlphaNumeric (by their own definition), and if so, it will automatically compress 2
* AlphaNumeric characters into 11 bits.
*
*
* ----------------------
*
*
* The included ALPHANUMERIC_TABLE is the conversion table used by the ZXING library as a reverse
* index for determining if a given input data should be classified as alphanumeric.
*
* See:
*
* com.google.zxing.qrcode.encoder.Encoder.chooseMode(String content, String encoding)
*
* which scans through the input string one character at a time and passes them to:
*
* getAlphanumericCode(int code)
*
* in the same class, which uses that character as a numeric index into the the
* ALPHANUMERIC_TABLE.
*
* If you examine the values, you'll notice that it ignores / disqualifies certain values, and
* effectively converts the input into base 45 (0 -> 44; -1 is interpreted by the calling code
* to mean a failure). This is confirmed in the function:
*
* appendAlphanumericBytes(CharSequence content, BitArray bits)
*
* where they pack 2 of these base 45 digits into 11 bits. This presents us with an opportunity.
* If we can take our data, and convert it into a compatible base 45 alphanumeric representation,
* then the QR Encoder will automatically pack that data into sub-byte chunks.
*
* 2 digits in base 45 is 2,025 possible values. 11 bits has a maximum storage capacity of 2,048
* possible states. This is only a loss of 1.1% in storage efficiency behind raw binary.
*
* 45 ^ 2 = 2,025
* 2 ^ 11 = 2,048
* 2,048 - 2,025 = 23
* 23 / 2,048 = 0.01123046875 = 1.123%
*
* However, this is the ideal / theoretical efficiency. This implementation processes data in
* chunks, using a Long as a computational buffer. However, since Java Long's are singed, we
* can only use the lower 7 bytes. The conversion code requires continuously positive values;
* using the highest 8th byte would contaminate the sign bit and randomly produce negative
* values.
*
*
* Real-World Test:
*
* Using a 7 byte Long to encode a 2KB buffer of random bytes, we get the following results.
*
* Raw Binary Size: 2,048
* Encoded String Size: 3,218
* QR Code Alphanum Size: 2,213 (after the QR Code compresses 2 base45 digits to 11 bits)
*
* This is a real-world storage efficiency loss of only 8%.
*
* 2,213 - 2,048 = 165
* 165 / 2,048 = 0.08056640625 = 8.0566%
*/
public class BinaryToBase45Encoder {
public final static int[] ALPHANUMERIC_TABLE;
/*
* You could probably just copy & paste the array literal from the ZXING source code; it's only
* an array definition. But I was unsure of the licensing issues with posting it on the internet,
* so I did it this way.
*/
static {
final Field SOURCE_ALPHANUMERIC_TABLE;
int[] tmp;
//Copy lookup table from ZXING Encoder class
try {
SOURCE_ALPHANUMERIC_TABLE = com.google.zxing.qrcode.encoder.Encoder.class.getDeclaredField("ALPHANUMERIC_TABLE");
SOURCE_ALPHANUMERIC_TABLE.setAccessible(true);
tmp = (int[]) SOURCE_ALPHANUMERIC_TABLE.get(null);
} catch (NoSuchFieldException e) {
e.printStackTrace();//Shouldn't happen
tmp = null;
} catch (IllegalAccessException e) {
e.printStackTrace();//Shouldn't happen
tmp = null;
}
//Store
ALPHANUMERIC_TABLE = tmp;
}
public static final int NUM_DISTINCT_ALPHANUM_VALUES = 45;
public static final char[] alphaNumReverseIndex = new char[NUM_DISTINCT_ALPHANUM_VALUES];
static {
//Build AlphaNum Index
final int len = ALPHANUMERIC_TABLE.length;
for (int x = 0; x < len; x++) {
// The base45 result which the alphanum lookup table produces.
// i.e. the base45 digit value which String characters are
// converted into.
//
// We use this value to build a reverse lookup table to find
// the String character we have to send to the encoder, to
// make it produce the given base45 digit value.
final int base45DigitValue = ALPHANUMERIC_TABLE[x];
//Ignore the -1 records
if (base45DigitValue > -1) {
//The index into the lookup table which produces the given base45 digit value.
//
//i.e. to produce a base45 digit with the numeric value in base45DigitValue, we need
//to send the Encoder a String character with the numeric value in x.
alphaNumReverseIndex[base45DigitValue] = (char) x;
}
}
}
/*
* The storage capacity of one digit in the number system; i.e. the maximum
* possible number of distinct values which can be stored in 1 logical digit
*/
public static final int QR_PAYLOAD_NUMERIC_BASE = NUM_DISTINCT_ALPHANUM_VALUES;
/*
* We can't use all 8 bytes, because the Long is signed, and the conversion math
* requires consistently positive values. If we populated all 8 bytes, then the
* last byte has the potential to contaminate the sign bit, and break the
* conversion math. So, we only use the lower 7 bytes, and avoid this problem.
*/
public static final int LONG_USABLE_BYTES = Long.BYTES - 1;
//The following mapping was determined by brute-forcing -1 Long (all bits 1), and compressing to base45 until it hit zero.
public static final int[] BINARY_TO_BASE45_DIGIT_COUNT_CONVERSION = new int[] {0,2,3,5,6,8,9,11,12};
public static final int NUM_BASE45_DIGITS_PER_LONG = BINARY_TO_BASE45_DIGIT_COUNT_CONVERSION[LONG_USABLE_BYTES];
public static final Map<Integer, Integer> BASE45_TO_BINARY_DIGIT_COUNT_CONVERSION = new HashMap<>();
static {
//Build Reverse Lookup
int len = BINARY_TO_BASE45_DIGIT_COUNT_CONVERSION.length;
for (int x=0; x<len; x++) {
int numB45Digits = BINARY_TO_BASE45_DIGIT_COUNT_CONVERSION[x];
BASE45_TO_BINARY_DIGIT_COUNT_CONVERSION.put(numB45Digits, x);
}
}
public static String encodeToBase45QrPayload(final byte[] inputData) throws IOException {
return encodeToBase45QrPayload(new ByteArrayInputStream(inputData));
}
public static String encodeToBase45QrPayload(final InputStream in) throws IOException {
//Init conversion state vars
final StringBuilder strOut = new StringBuilder();
int data;
long buf = 0;
// Process all input data in chunks of size LONG.BYTES, this allows for economies of scale
// so we can process more digits of arbitrary size before we hit the wall of the binary
// chunk size in a power of 2, and have to transmit a sub-optimal chunk of the "crumbs"
// left over; i.e. the slack space between where the multiples of QR_PAYLOAD_NUMERIC_BASE
// and the powers of 2 don't quite line up.
while(in.available() > 0) {
//Fill buffer
int numBytesStored = 0;
while (numBytesStored < LONG_USABLE_BYTES && in.available() > 0) {
//Read next byte
data = in.read();
//Push byte into buffer
buf = (buf << 8) | data; //8 bits per byte
//Increment
numBytesStored++;
}
//Write out in lower base
final StringBuilder outputChunkBuffer = new StringBuilder();
final int numBase45Digits = BINARY_TO_BASE45_DIGIT_COUNT_CONVERSION[numBytesStored];
int numB45DigitsProcessed = 0;
while(numB45DigitsProcessed < numBase45Digits) {
//Chunk out a digit
final byte digit = (byte) (buf % QR_PAYLOAD_NUMERIC_BASE);
//Drop digit data from buffer
buf = buf / QR_PAYLOAD_NUMERIC_BASE;
//Write Digit
outputChunkBuffer.append(alphaNumReverseIndex[(int) digit]);
//Track output digits
numB45DigitsProcessed++;
}
/*
* The way this code works, the processing output results in a First-In-Last-Out digit
* reversal. So, we need to buffer the chunk output, and feed it to the OutputStream
* backwards to correct this.
*
* We could probably get away with writing the bytes out in inverted order, and then
* flipping them back on the decode side, but just to be safe, I'm always keeping
* them in the proper order.
*/
strOut.append(outputChunkBuffer.reverse().toString());
}
//Return
return strOut.toString();
}
public static byte[] decodeBase45QrPayload(final String inputStr) throws IOException {
//Prep for InputStream
final byte[] buf = inputStr.getBytes();//Use the default encoding (the same encoding that the 'char' primitive uses)
return decodeBase45QrPayload(new ByteArrayInputStream(buf));
}
public static byte[] decodeBase45QrPayload(final InputStream in) throws IOException {
//Init conversion state vars
final ByteArrayOutputStream out = new ByteArrayOutputStream();
int data;
long buf = 0;
int x=0;
// Process all input data in chunks of size LONG.BYTES, this allows for economies of scale
// so we can process more digits of arbitrary size before we hit the wall of the binary
// chunk size in a power of 2, and have to transmit a sub-optimal chunk of the "crumbs"
// left over; i.e. the slack space between where the multiples of QR_PAYLOAD_NUMERIC_BASE
// and the powers of 2 don't quite line up.
while(in.available() > 0) {
//Convert & Fill Buffer
int numB45Digits = 0;
while (numB45Digits < NUM_BASE45_DIGITS_PER_LONG && in.available() > 0) {
//Read in next char
char c = (char) in.read();
//Translate back through lookup table
int digit = ALPHANUMERIC_TABLE[(int) c];
//Shift buffer up one digit to make room
buf *= QR_PAYLOAD_NUMERIC_BASE;
//Append next digit
buf += digit;
//Increment
numB45Digits++;
}
//Write out in higher base
final LinkedList<Byte> outputChunkBuffer = new LinkedList<>();
final int numBytes = BASE45_TO_BINARY_DIGIT_COUNT_CONVERSION.get(numB45Digits);
int numBytesProcessed = 0;
while(numBytesProcessed < numBytes) {
//Chunk out 1 byte
final byte chunk = (byte) buf;
//Shift buffer to next byte
buf = buf >> 8; //8 bits per byte
//Write byte to output
//
//Again, we need to invert the order of the bytes, so as we chunk them off, push
//them onto a FILO stack; inverting their order.
outputChunkBuffer.push(chunk);
//Increment
numBytesProcessed++;
}
//Write chunk buffer to output stream (in reverse order)
while (outputChunkBuffer.size() > 0) {
out.write(outputChunkBuffer.pop());
}
}
//Return
out.flush();
out.close();
return out.toByteArray();
}
}
Here are some tests I ran to verify the code:
#Test
public void stringEncodingTest() throws IOException {
//Init test data
final String testStr = "Some cool input data! !##$%^&*()_+";
//Encode
final String encodedStr = BinaryToBase45Encoder.encodeToBase45QrPayload(testStr.getBytes("UTF-8"));
//Decode
final byte[] decodedBytes = BinaryToBase45Encoder.decodeBase45QrPayload(encodedStr);
final String decodedStr = new String(decodedBytes, "UTF-8");
//Output
final boolean matches = testStr.equals(decodedStr);
assert(matches);
System.out.println("They match!");
}
#Test
public void binaryEncodingAccuracyTest() throws IOException {
//Init test data
final int maxBytes = 10_000;
for (int x=1; x<=maxBytes; x++) {
System.out.print("x: " + x + "\t");
//Encode
final byte[] inputArray = getTestBytes(x);
final String encodedStr = BinaryToBase45Encoder.encodeToBase45QrPayload(inputArray);
//Decode
final byte[] decodedBytes = BinaryToBase45Encoder.decodeBase45QrPayload(encodedStr);
//Output
for (int y=0; y<x; y++) {
assertEquals(inputArray[y], decodedBytes[y]);
}
System.out.println("Passed!");
}
}
#Test
public void binaryEncodingEfficiencyTest() throws IOException, WriterException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
//Init test data
final byte[] inputData = new byte[2048];
new Random().nextBytes(inputData);
//Encode
final String encodedStr = BinaryToBase45Encoder.encodeToBase45QrPayload(inputData);
//Write to QR Code Encoder // Have to use Reflection to force access, since the function is not public.
final BitArray qrCode = new BitArray();
final Method appendAlphanumericBytes = com.google.zxing.qrcode.encoder.Encoder.class.getDeclaredMethod("appendAlphanumericBytes", CharSequence.class, BitArray.class);
appendAlphanumericBytes.setAccessible(true);
appendAlphanumericBytes.invoke(null, encodedStr, qrCode);
//Output
final int origSize = inputData.length;
final int qrSize = qrCode.getSizeInBytes();
System.out.println("Raw Binary Size:\t\t" + origSize + "\nEncoded String Size:\t" + encodedStr.length() + "\nQR Code Alphanum Size:\t" + qrSize);
//Calculate Storage Efficiency Loss
final int delta = origSize - qrSize;
final double efficiency = ((double) delta) / origSize;
System.out.println("Storage Efficiency Loss: " + String.format("%.3f", efficiency * 100) + "%");
}
public static byte[] getTestBytes(int numBytes) {
final Random rand = new Random();
final ByteArrayOutputStream bos = new ByteArrayOutputStream();
for (int x=0; x<numBytes; x++) {
//bos.write(255);// -1 (byte) = 255 (int) = 1111 1111
byte b = (byte) rand.nextInt();
bos.write(b);
}
return bos.toByteArray();
}

Audio samples mixing or changing volume causes saturation and white noise

I have a multichannel input (i'm using Soundflower 64ch on mac), and I'm trying to mixdown 4 channels of the 64 channels to an stereo output.
What i am doing is, reading chunks of 1024 frames, with 64 channels every frame, then converting the bytebuffer to Short array (values between -32,768 <-> 32,767, because samples are 16 bits).
This way I add for example channel1[sample] + channel2[sample] and I get the mix of both channels.
But here is a problem, the sum can overflow the Short (16 bit) range, introducing saturation in the sound. So what I'm doing is (channel1[sample] + channel2[sample]) / 2 but when I divide by 2, I hear a lot of white sound.
Also if I try to reduce the volumen of a channel by doing channel1[sample] * 0.5 there is a lot of saturation.
Why does it happen?
Here is my full code, note that I'm converting bytes to short to handle better, and then I'm converting back to bytes for write the mix to the stereo output:
public static void main(String[] args) throws LineUnavailableException {
int inputChannels = 64;
AudioFormat inputFormat = new AudioFormat(48000, 16, inputChannels, true, false);
AudioFormat outputFormat = new AudioFormat(48000, 16, 2, true, false);
TargetDataLine mic = AudioSystem.getTargetDataLine(inputFormat);
SourceDataLine speaker = AudioSystem.getSourceDataLine(outputFormat);
mic.open(inputFormat);
speaker.open(outputFormat);
mic.start();
speaker.start();
AudioInputStream audioInputStream = new AudioInputStream(mic);
int bytesPerFrame = audioInputStream.getFormat().getFrameSize();
// Set an arbitrary buffer size of 1024 frames.
int CHUNK = 1024 ;
int numBytes = CHUNK * bytesPerFrame;
byte[] audioBytes = new byte[numBytes];
try {
byte[][] frames = new byte[CHUNK][bytesPerFrame];
int i = 0, j = 0
;
while (true) {
// read to audioBytes.
audioInputStream.read(audioBytes);
// split audioBytes in _CHUNK_ frames (1024 frames)
for(j=0; j<CHUNK; j++) {
frames[j] = Arrays.copyOfRange(audioBytes, j * bytesPerFrame, j * bytesPerFrame + bytesPerFrame);
}
// convert bytearray to shortarray
short[][] shortFrames = new short[CHUNK][inputChannels];
for(i=0; i < frames.length; i++) {
ByteBuffer.wrap(frames[i]).order(ByteOrder.BIG_ENDIAN).asShortBuffer().get(shortFrames[i]);
}
short[] leftOutput = new short[CHUNK*2];
short[] rightOutput = new short[CHUNK*2];
for (i=0; i<CHUNK; i++) {
short channel1 = shortFrames[i][0];
short channel2 = shortFrames[i][1];
short channel3 = shortFrames[i][2];
short channel4 = shortFrames[i][3];
leftOutput[i] = (short)(channel4);
rightOutput[i] = (short)(channel4);;
}
//convert shortarray in byte buffer
ByteBuffer byteBuf = ByteBuffer.allocate(CHUNK * 2 * 2); // 2 bytes * 2 output channels
for (i=0; i<CHUNK; i++) {
byteBuf.putShort(leftOutput[i]);
byteBuf.putShort(rightOutput[i]);
}
speaker.write(byteBuf.array(),0,byteBuf.array().length);
}
} catch (Exception ex) {
// Handle the error...
System.out.println("exception");
System.out.println(ex.toString());
}
}
IDK if the issue is how the bytes are being converted to shorts and back, but since you asked about this in the comment, I will post it. Assume buffer has contiguous little-endian bytes at 16-bit encoding. Just reverse the byte indexes for big-endian.
pcmShort = ( buffer[i] & 0xff ) | ( buffer[i+1] << 8 );
The conversion of pcm to byte that I use follows (for little-endian, reverse the indexes for big-endian):
outBuffer[i] = (byte)pcmShort[0];
outBuffer[i+1] = (byte)((int)pcmShort[0] >> 8);
Maybe you can use the two methods (your attempt with ByteBuffer and getShort, and the above) side-by-side on the same data and check if the resulting arrays hold the same values?
Another thing I'd try to do is to just get a single track working. If that sounds okay, then check on the mixing. It's kind of unlikely that the signals are so hot that they are overrunning. So something else is probably going on.
I should try this out myself, I'm not sure when I'll get to it. It could potentially be an improvement over what I've been doing.

How to implement chrome native messaging message handling protocol in java

I tried to implement native messaging protocol in java but it didn't work.
I tried it following way.
private String readMessage() {
int length = getInt(getLength());
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
byte[] b = new byte[4];
try {
int total;
for(int totalRead = 0 ; totalRead < length ; totalRead = totalRead + 4){
System.in.read(b); // make sure
bOut.write(b);
}
} catch (IOException e) {
e.printStackTrace();
}
String bRes = null;
try {
bRes = new String(bOut.toByteArray(), "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return bRes;
}
To read size i have used following methods:
This construct the int from first four bytes
private int getInt(byte[] bytes)
{
return (bytes[3] << 24) & 0xff000000 |
(bytes[2] << 16) & 0x00ff0000 |
(bytes[1] << 8) & 0x0000ff00 |
(bytes[0] << 0) & 0x000000ff;
}
This reads first four bytes and returns byte array
private byte[] getLength()
{
int length = 0 ;
byte[] bytes = new byte[4];
try
{
System.in.read(bytes);
} catch (IOException e)
{
e.printStackTrace();
}
return bytes;
}
This gives "Error when communicating with the native messaging host" error. How can i implement this protocol correctly in java.
Can someone provide simple working example for java
My approach below gives a Java implementation that receives a message from a Chrome App and sends a message back. On my little-endian machine it works.
I haven't properly studied your effort but hopefully this will help with your 'simple working example' request.
The main points:
Communication is with the standard stream. As you know, read in the first 4 bytes separately to learn the length (here, in to lengthByte):
byte[] lengthByte = new byte[4];
int bytesRead = System.in.read(lengthByte,0,4);
//Read the message into byte[] c:
byte[] c = new byte[text_length];
int lengthAppMessage = System.in.read(c,0,text_length);
When writing back to the app, we write the message length in the 1st 4 bytes. For the message {"m":"hi"}, which is the message I send below, the message length is 10. (For {"m":"hello"} it's 13, etc.)
int returnedMessageLength = 10;
System.out.write((byte) (returnedMessageLength));
System.out.write((byte)0);
System.out.write((byte)0);
System.out.write((byte)0);
Where the last three lines are padding to sum to 4 bytes. You may need to put these three lines in to the stream before the message length.
When appending the message, the {"...":"..."} format is needed. We can send the message through in sections e.g.
System.out.append('{');
System.out.append('"');
System.out.append('m');
System.out.append('"');
System.out.append(':');
System.out.append('"');
System.out.append('h');
System.out.append('i');
System.out.append('"');
System.out.append('}');
The point is that breaking the message in to sections and sending each section separately circumnavigates the Java formatting problem (caused by the single outer quotes.)
Put all of the above code inside a never-ending 'while' loop to avoid exiting too soon. (To see this code running, I integrated it with the example from Google's native messaging page.)
This is not good code that I've used, but either by accident or design, it worked this way for me.
The below codes works well on my side.
//Convert length from Bytes to int
public static int getInt(byte[] bytes) {
return (bytes[3] << 24) & 0xff000000|
(bytes[2] << 16)& 0x00ff0000|
(bytes[1] << 8) & 0x0000ff00|
(bytes[0] << 0) & 0x000000ff;
}
// Read an input from Chrome Extension
static public String receiveMessage(){
byte[] b = new byte[4];
try{
System.in.read(b);
int size = getInt(b);
byte[] msg = new byte[size];
System.in.read(msg);
// make sure to get message as UTF-8 format
String msgStr = new String(msg, "UTF-8");
return msgStr;
}catch (IOException e){
e.printStackTrace();
return null;
}
}
You could use https://github.com/Cosium/web-native-messaging-host .
It is a java library allowing to turn any JVM application into a Web Native Messaging Host .

Integer to byte and byte to integer convertion - java

I'm developing an app based on Samsung Chord SDK. I need to send the video's current position in the sendDataToAll(), which accepts data in byte[][]. My problem is that when I try to send the current position (which is an int) type-casted into byte, I'm getting negative value (in byte) as returned. And when I try to convert the negative value in to int in the OnDataRecived(), it's still the same negative value. How do I solve this issue?
Sending code:
//for sending the message
int currPos = mVideoView.getCurrentPosition();
logView.append("Duration sent= " + currPos);
//Integer resume = -3;
Byte msgByte = new Byte("-3");
byte [] [] pay = new byte [1] [2];
pay[0] [0] = msgByte;
Byte msgByte2 = new Byte((byte) currPos);
logView.append("Duration sent= " + msgByte2);
pay[0] [1] = msgByte2;
mChordchannel.sendDataToAll("Integer", pay);
// im sending -3 so that im checking that the user pressed the resume .
Receiving code:
//on receiving
else if(intRec == -3) {
Byte pos = rec[0] [1];
int posn;
posn = pos.intValue();
logView.append("Duration received= " + posn);
mVideoView.seekTo(posn);
mVideoView.start();
}
I don't know anything about the Samsung Chord SDK, but you can't fit (most) ints in a byte. An int is 4 bytes wide.
To create a payload compatible with your current code, that sends all 4 bytes:
byte[][] payload = { {
-3,
(byte)(currPos >> 24),
(byte)(currPos >> 16),
(byte)(currPos >> 8),
(byte)(currPos >> 0),
} };
mChordchannel.sendDataToAll("Integer", payload);
To receive:
int position = new java.math.BigInteger(
Arrays.copyOfRange(rec[0], 1, 5)).intValue();
P.S. This is not pretty code! It is tolerable for basic ints, but if you later find you need to transmit more complicated data structures you will need a better way. Some ideas, in increasing order of sophistication:
Use data streams (wrap a DataOutputStream around a ByteArrayOutputStream; write values; when done writing, close the DataOutputStream and call toByteArray() on the ByteArrayOutputStream to get the payload).
Use serialization (wrap an ObjectOutputStream around a ByteArrayOutputStream; write values and/or objects; finish as above).
Use a JSON-encoder or XML-encoder. (E.g., encode the data as a String, then call getBytes("UTF-8") on the String and send that.)

Java Convert 7bit Charset Octets to Readable String (From PDU SMS)

I'm receiving SMS from GSM modem in PDU format; the TP-User-Data is "C8329BFD06DDDF72363904"
and what I get is: "�2����r69", while the sent sms is "Hello World!".
Here is my java code:
private String fromPDUText(String PDUSMSText) {
String endoding = PDUSMSText.substring(0, 2);
PDUSMSText = PDUSMSText.substring(18);
byte bs[] = new byte[PDUSMSText.length() / 2];
for(int i = 0; i < PDUSMSText.length(); i += 2) {
bs[i / 2] = (byte) Integer.parseInt(PDUSMSText.substring(i, i + 2), 16);
}
try {
String out = new String(bs, "ASCII");
} catch(UnsupportedEncodingException e) {
e.printStackTrace();
return "";
} finally {
return out;
}
}
The input is packed in 7-bits per character, which means that every 8 bytes encode 9 characters. Constructing a parser for this format can be a fun exercise or a frustrating experience, depending on how you take it. You are probably better off using a library, and a quick Google search reveals several code examples.
This is how 7Bit characters are packed:
Encoding-Decoding-7-bit-User-Data-for-SMS-PDU-PDU
Personally I find it easiest to attack this kind of problem by viewing it as having a pipe where you feed 8 bits in one end and retrieve 7 bits in the other. As long as there is at least 7 bits in the pipe you read from it. When there are less than 7 bits you need to add some more so you write 8 new bits to it. So what you need is:
A pipe that can hold at least 14 bits (but why be cheap? Go with a 32-bit int!).
A counter keeping track of how many bits are in the pipe at any given moment.
The algorithm in pseudo code is as follows:
pipe = 0;
bitCount = 0;
while(hasMoreData())
{
pipe |= readByte() << bitCount;
bitCount += 8;
while(bitCount >= 7)
{
writeByte(pipe & 0x7F);
pipe >>= 7;
bitCount -= 7;
}
}

Categories

Resources