Does anyone know how to input or output bytes without skipping the zeros
I am trying to write a program that exports an array of ints to unsigned shorts.
I have written code to write and read wave files, but they aren't formatted right.
Read Example
// dwChunkSize
byteConvertedLong = extractBytes(4);
dwFormatChunkSize = convertBytesToLong(byteConvertedLong);
System.out.println("Format Chunk size: " + dwFormatChunkSize);
// wFormatTag
byteConvertedInt = extractBytes(2);
System.out.println("Format Tag: " + convertBytesToInt(byteConvertedInt));
functions for reading data:
// convert byte to long
public long convertBytesToLong(byte[] values) {
byte[] spliceToArray = {0, 0, 0, 0,
values[0], values[1], values[2], values[3]};
ByteBuffer debuffer = ByteBuffer.wrap(spliceToArray);
long returnValue = (long)debuffer.getLong();
return returnValue;
}
// convert byte to int
public int convertBytesToInt(byte[] values) {
byte[] spliceToArray = {0, 0, values[0], values[1]};
ByteBuffer debuffer = ByteBuffer.wrap(spliceToArray);
int returnValue = debuffer.getInt();
return returnValue;
}
// extract bytes to DataOutputStream
public byte[] extractBytes(int bytesToExtract)
throws IOException {
// define byte array
byte[] extractedBytes = new byte[bytesToExtract];
// extract bytes
dis.read(extractedBytes, byteTracker, bytesToExtract);
return extractedBytes;
}
Write example
// dwChunkSize
byteConvertedLong = convertLongToBytes(dwFormatChunkSize);
appendBytes(byteConvertedLong, 4, 8);
// wFormatTag
byteConvertedInt = convertIntToByte(W_FORMAT_TAG);
appendBytes(byteConvertedInt, 2, 4);
Functions for writing;
// convert long to byte
public byte[] convertLongToBytes(long value) {
ByteBuffer buffer = ByteBuffer.allocate(8);
buffer.putLong(value);
return buffer.array();
}
// convert int to byte
public byte[] convertIntToByte(int value) {
ByteBuffer buffer = ByteBuffer.allocate(4);
buffer.putInt(value);
return buffer.array();
}
// append bytes to DataOutputStream
public void appendBytes(byte[] bytesToAppend, int start, int end)
throws IOException {
for (int i = start; i < end; i++) {
dos.writeByte(bytesToAppend[i]);
}
}
I have to use Long and int variabls to read and write ints and shorts respectively so that they are written as unsigned numbers.
I have been following instructions on this site https://blogs.msdn.microsoft.com/dawate/2009/06/23/intro-to-audio-programming-part-2-demystifying-the-wav-format/ to make sure all the data is formatted right
The main problem with both reading and writing is that if I read 1 as a short (0000000000000001), it will skip the zeros and start reading from 1 (10000000000000000).
If that isn't the problem I don't know what is?
It turned out that Wave files are written in little endian and I was writing in big endian. I needed to implement a function that reversed the bytes of the byte array.
I came up with this.
// bigToLittleEndien method
public byte[] bigToLittleEndien(byte[] oldArray) {
// new array
byte[] newArray = new byte[oldArray.length];
// reverse the order of byes
for (int i = 0, j = oldArray.length - 1; i < oldArray.length; i++, j--) {
newArray[i] = oldArray[j];
}
// return the new bytes
return newArray;
}
I had some other problems that were small but I fixed them all.
Related
I can not mix two audio extension files wav. My work:
byte[] bufData1 = null;
byte[] bufData2 = null;
ArrayList<Byte> bufData3 = new ArrayList<Byte>();
Creating two arrays with raw audio data
public void bootloadInputData(String p1, String p2) throws IOException {
bufData1 = bootloadReadFileByte(p1);
bufData2 = bootloadReadFileByte(p2);
System.arraycopy(bufData1, 44, bufData1, 0, (bufData1.length - 44));
System.arraycopy(bufData2, 44, bufData2, 0, (bufData2.length - 44));
}
public byte[] bootloadReadFileByte(String path) throws IOException{
ByteArrayOutputStream out = null;
InputStream input = null;
try{
out = new ByteArrayOutputStream();
input = new BufferedInputStream(new FileInputStream(path));
int data = 0;
while((data = input.read()) != -1){
out.write(data);
}
}
finally{
if(null != input){
input.close();
}
if(null != out){
out.close();
}
}
return out.toByteArray();
}
Mixing the bytes of raw audio data
public void bootloadOutputData() throws IOException {
for(int i = 0; i < ((bufData1.length + bufData2.length) / 4); i += 4) {
if(i < bufData1.length){
bufData3.add(bufData1[i]);
bufData3.add(bufData1[i+1]);
bufData3.add(bufData1[i+2]);
bufData3.add(bufData1[i+3]);
}
if(i < bufData2.length){
bufData3.add(bufData2[i]);
bufData3.add(bufData2[i+1]);
bufData3.add(bufData2[i+2]);
bufData3.add(bufData2[i+3]);
}
}
}
Create a new file, fill in the header and raw audio data.
private void bootloadCreateWaveMix(String p1, String p2, String p3) throws IOException {
int size1 = 0;
int size2 = 0;
FileInputStream fis1 = null;
FileInputStream fis2 = null;
try {
fis1 = new FileInputStream(p1);
fis2 = new FileInputStream(p2);
size1 = fis1.available();
size2 = fis2.available();
} finally {
if(fis1 != null){
fis1.close();
}
if(fis2 != null){
fis2.close();
}
}
int mNumBytes = (size1 + size2);
DataOutputStream out = null;
try {
out = new DataOutputStream(new FileOutputStream(p3));
writeId(out, "RIFF");
writeInt(out, 36 + mNumBytes);
writeId(out, "WAVE");
writeId(out, "fmt ");
writeInt(out, 16);
writeShort(out, (short) 1);
writeShort(out, (short) 4);
writeInt(out, (int) 44100);
writeInt(out, 2 * 44100 * 16 / 8);
writeShort(out, (short)(2 * 16 / 8));
writeShort(out, (short) 16);
writeId(out, "data");
writeInt(out, mNumBytes);
out.write(toByteArray(bufData3));
} finally {
if(out != null){
out.close();
}
}
}
private static void writeId(OutputStream out, String id) throws IOException {
for (int i = 0; i < id.length(); i++) out.write(id.charAt(i));
}
private static void writeInt(OutputStream out, int val) throws IOException {
out.write(val >> 0);
out.write(val >> 8);
out.write(val >> 16);
out.write(val >> 24);
}
private static void writeShort(OutputStream out, short val) throws IOException {
out.write(val >> 0);
out.write(val >> 8);
}
public static byte[] toByteArray(ArrayList<Byte> in) {
byte[] data = new byte[in.size()];
for (int i = 0; i < data.length; i++) {
data[i] = (byte) in.get(i);
}
return data;
}
Question:
This code does not correctly create a file that the computer can not
play, but the device can. Reproduction is bad, there is some kind of
interference at the end of the merged files. Also, playback ends when
the first file ends, even if the second file is larger than the first
one. Another problem with the channels on the idea is two stereo
files, and in the title I indicate 4 life even though 2. The files
will always be 44100/16 bit / stereo
If I understand correctly, you want to do the following:
Given 2 input WAV files, mix them together to a single WAV file.
The contents of the output will be the input files played at the same time, not one after the other.
The length of the new file will be the length of the longest of the input files.
All files, input and output, are 16 bit, stereo 44100Hz.
If that's the case, here are (some of) your mistakes:
You need to parse the incoming files so that you don't read their headers as audio data (Do not skip this step just because you already know the format of the audio. You need to read the headers to confirm the data format and accurately determine the number of samples in your input. Also, note that 2/16/44100 WAV files can have different size headers because they can contain various chunks, so you can't just skip over X bytes and then read the file -- you must parse the header!).
If the WAV files are all 16-bit, you need to convert the incoming data from bytes to shorts (note, this is not a simple typecasting -- you must pack 2 bytes into each short. I believe you can use a DataInputStream for this, but be sure to take endianness into account -- WAV files are little-endian and Java is big-endian). Once you've got the shorts representing your samples, average the shorts from the separate files to do the mixing. Your averaged values must then be converted back to bytes (DataOutputStream) to save the resulting file. When you've run out of data from one file, substitute zero.
Your calculation of numBytes is incorrect -- it is not the sum of raw bytes in both files, but a somewhat more complex calculation. In your case, you want it to be equal to something like this:
n1 = number of samples in file 1
n2 = number of samples in file 2
n = MAX( n1 + n2 )
numBytes = n * (number of channels) * (number of bytes per channel) = n * 2 * 2
I strongly urge you to consider using a library like JMF to tackle 1 & 2.
I am trying to process audio using VST plugins load via JVST.
Roughly speaking, what I am doing is the following:
1 open an audio input stream that takes a wav file
2 until the file is not finished
2.1 read a block of frames and store them as byte[]
2.2 convert byte[] to float[]
2.3 process the float[] with a JVST call to the VST plugin
2.4 convert float[] to byte[]
2.5 push byte[] in the audio output stream
What happens, now, is that if I comment out 2.3, the audio is converted from bytes to floats and back, and sounds perfect. If I instead perform the VST processing, borderline white noise comes out. I don't really know how to proceed. My intuition is that something might be wrong with the byte[] to float[] conversion, but I don't know what. I tried changing the endian of the bytes, didn't work.
Anybody has suggestions?
Here is the actual code file:
public class ByteConv
{
public static void main(String[] args) throws Exception {
AEffect effect = VST.load("G:/AnalogDelay");
// Startup the plugin
// Ask the plugin to display its GUI using the SWT window handle
MiniHost miniHost = new MiniHost(effect);
// miniHost.setBlockOnOpen(true);
// miniHost.open();
effect.open();
effect.setSampleRate(44100.0f);
effect.setBlockSize(512);
File file = new File("C:\\Users\\Laimon\\Desktop\\wma-01.wav");
try {
AudioFormat format = AudioSystem.getAudioFileFormat(file).getFormat();
System.out.println(format.toString());
AudioInputStream inputStream = AudioSystem.getAudioInputStream(file);
SourceDataLine sourceLine = AudioSystem.getSourceDataLine(format);
sourceLine.open();
sourceLine.start();
int bytesPerFrame = inputStream.getFormat().getFrameSize();
if (bytesPerFrame == AudioSystem.NOT_SPECIFIED) {
// some audio formats may have unspecified frame size
// in that case we may read any amount of bytes
bytesPerFrame = 1;
}
// Set an arbitrary buffer size of 512 frames.
int numBytes = 512 * bytesPerFrame;
byte[] audioBytes = new byte[numBytes];
int numBytesRead = 0;
// Try to read numBytes bytes from the file.
while ((numBytesRead = inputStream.read(audioBytes)) != -1) {
// Convert byte[] into float[] for processing
float[] monoInput = byteArrayToFloatArray(audioBytes, numBytesRead);
// Prepare input array with same wave on all channels
float[][] vstInput = new float[effect.numInputs][];
for (int i = 0; i < vstInput.length; i++)
vstInput[i] = monoInput;
// Allocate output array of same size
float[][] vstOutput = new float[effect.numOutputs][monoInput.length];
effect.processReplacing(vstInput, vstOutput, vstInput[0].length);
audioBytes = floatArrayToByteArray(vstOutput[0]);
sourceLine.write(audioBytes, 0, numBytesRead);
}
} catch(IOException | LineUnavailableException | UnsupportedAudioFileException ex) {
}
VST.dispose(effect);
}
private static float[] byteArrayToFloatArray(byte[] barray, int n) {
// We assume n in between 0 and barray.length
System.arraycopy(barray, 0, barray, 0, n);
ByteBuffer bb = ByteBuffer.wrap(barray);
FloatBuffer fb = bb.asFloatBuffer();
float[] flush = new float[fb.capacity()];
fb.get(flush);
return flush;
}
private static byte[] floatArrayToByteArray(float[] farray) {
ByteBuffer bb = ByteBuffer.allocate(farray.length*4);
for (int i = 0; i < farray.length; i++)
bb.putFloat(i*4, farray[i]);
return bb.array();
}
}
Thanks in advance for any help!
I am trying to concatenate long and bytearray to another bytearray.
I tried like this :
byte[] value1= new byte[16];
byte[] value2= new byte[16];
byte[] finalvalue = new byte[value1.length + value2.length];
long ts = System.currentTimeMillis();
int val = 100;
ByteBuffer.wrap(value1).order(ByteOrder.LITTLE_ENDIAN).asLongBuffer().put(ts);
ByteBuffer.wrap(value2).order(ByteOrder.LITTLE_ENDIAN).asIntBuffer().put(val);
System.arraycopy(value1, 0, finalvalue, 0, value1.length);
System.arraycopy(value2, 0, finalvalue, value1.length,value2.length);
When I tried to print this, I am not getting the correct values. It printing like this
BYTEVALUE -95-15-4410659100000000002000000000000000
it should print like this
- BYTEVALUE- 1354707038625,100
Can anyone help me out where I am going wrong.
Help will be appreciated.
Update:
Use to print values using StringBuffer like this:
StringBuffer sb = new StringBuffer(finalvalue.length);
for (int i = 0; i < finalvalue.length; i++) {
sb.append(finalvalue[i]);
}
Your code is not doing what you think it is. Consider the following self-contained application:
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class ByteArrayTest {
public static void main(String[] args) {
byte[] value1 = new byte[16];
byte[] value2 = new byte[16];
byte[] finalvalue = new byte[value1.length + value2.length];
long ts = System.currentTimeMillis();
int val = 100;
ByteBuffer.wrap(value1).order(ByteOrder.LITTLE_ENDIAN).asLongBuffer()
.put(ts);
ByteBuffer.wrap(value2).order(ByteOrder.LITTLE_ENDIAN).asIntBuffer()
.put(val);
System.arraycopy(value1, 0, finalvalue, 0, value1.length);
System.arraycopy(value2, 0, finalvalue, value1.length, value2.length);
printByteArray(finalvalue);
}
private static void printByteArray(final byte[] array) {
StringBuilder sb = new StringBuilder(array.length);
for (byte b : array) {
sb.append(String.format("%02X", b));
}
System.out.println(sb.toString());
}
}
The output of this is:
BE26086B3B010000000000000000000064000000000000000000000000000000
Splitting this into component parts, we can see why:
The first sixteen bytes are BE26086B3B0100000000000000000000. This is your timestamp in little endian order. If you ignore the zero bytes, this converts to 1,354,710,394,558 in decimal, which is correct.
The second sixteen bytes are 64000000000000000000000000000000, which is your hard-coded value 100.
The zeroes represent the space in the byte arrays that you didn't use.
I have a java client and a C server. I server wants to send a data packet to the client containing some information in a specific order as shown below:
char *buf = NULL;
if(!(buf = malloc(sizeof(char) * pkt_len)))
{
printf("Could not malloc\n");
return -1;
}
memcpy(buf, &pkt_type, 2);
memcpy(buf + 2, &pkt_len, 4);
memcpy(buf + 6, &more_to_come, 1);
memcpy(buf + 7, &fb_id, 8);
memcpy(buf + 15, &match, 4);
memcpy(buf + 19, el->name, name_len);
memcpy(buf + 19 + name_len, "\n\r", 2);
if(send(clientSock, buf, pkt_len, 0) < 0)
{
printf("Can not write to socket %d\n", clientSock);
return -1;
}
Ofcourse I have convereted all the shorts, integers and long integers to network bytes order before writing them to the buffer. The data is received as a string by the Java client. My problem is how to parse this string. For example, I would to know a way to read off the 2 bytes that indicate the pkt length and cast it to a short in host-byte-order. I am aware that Java provides a method to convert a string to an array of bytes. But what do I do after I have obtained the bytes array. Some code to perform this task would be appreciated
You mean something like this?:
char[] charArray = new char[2];
charArray[0] = "a".charAt(0);
charArray[1] = "b".charAt(0);
String string = new String(charArray);
I assume a char is one byte in length here.
You could use a DataInputStream. Depending on your data types, something like the following might get you started. Note the example uses ASCII as the character encoding and doesn't try to be efficient in any way.
package grimbo.test.bytes;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.IOException;
public class BytesTest {
public static void main(String[] args) throws IOException {
// start setup test data
byte[] msgStart = {
/*pkt_type*/0, 1,
/*pkt_len*/0, 0, 0, 1,
/*more_to_come*/1,
/*fb_id*/1, 2, 3, 4, 5, 6, 7, 8,
/*match*/2, 2, 2, 2 };
String name = "John Smith\n\r";
byte[] nameBytes = name.getBytes("ASCII");
byte[] msg = new byte[msgStart.length + nameBytes.length];
System.arraycopy(msgStart, 0, msg, 0, msgStart.length);
System.arraycopy(nameBytes, 0, msg, msgStart.length, nameBytes.length);
// end setup test data
DataInputStream in = new DataInputStream(new ByteArrayInputStream(msg));
new BytesTest().read(in);
}
void read(DataInputStream in) throws IOException {
// assuming pkt_type is an unsigned 2-byte value
int pkt_type = in.readUnsignedShort();
print(pkt_type);
// assuming pkt_len is an unsigned 4-byte value
// Java doesn't have those, so read a signed int and mask to a long
long pkt_len = in.readInt() & 0xFFFFFFFFL;
print(pkt_len);
// assuming vanilla byte is ok for this, but Java bytes are signed, not unsigned
byte more_to_come = in.readByte();
print(more_to_come);
// don't know the format of this, so left as bytes
byte[] fb_id = new byte[8];
in.readFully(fb_id);
print(fb_id);
// don't know the format of this, so left as bytes
byte[] match = new byte[4];
in.readFully(match);
print(match);
char[] nr = { '\n', '\r' };
byte[] name = readUntil(in, nr);
print(name);
System.out.println(">" + new String(name, "ASCII") + "<");
}
private byte[] readUntil(DataInputStream in, /* stop reading when these chars are found */char[] terminate)
throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int terminateIdx = 0;
int input = -1;
while ((input = in.read()) > -1) {
if (input == terminate[terminateIdx]) {
if (terminateIdx == (terminate.length - 1)) {
// we've found the termination sequence
byte[] buf = baos.toByteArray();
// - terminateIdx because we don't include the termination sequence
byte[] result = new byte[buf.length - terminateIdx];
System.arraycopy(buf, 0, result, 0, result.length);
return result;
}
terminateIdx++;
} else {
// no match, reset count
terminateIdx = 0;
}
baos.write(input);
}
return baos.toByteArray();
}
private void print(long l) {
System.out.println(l);
}
void print(byte[] bytes) {
for (int i = 0; i < bytes.length; i++) {
if (i > 0) {
System.out.print(",");
}
System.out.print(bytes[i]);
}
System.out.println();
}
}
And the output is:
1
1
1
1,2,3,4,5,6,7,8
2,2,2,2
74,111,104,110,32,83,109,105,116,104
>John Smith<
This question already has answers here:
Easy way to concatenate two byte arrays
(13 answers)
Closed 4 years ago.
I have two byte arrays and I am wondering how I would go about adding one to the other or combining them to form a new byte array.
You're just trying to concatenate the two byte arrays?
byte[] one = getBytesForOne();
byte[] two = getBytesForTwo();
byte[] combined = new byte[one.length + two.length];
for (int i = 0; i < combined.length; ++i)
{
combined[i] = i < one.length ? one[i] : two[i - one.length];
}
Or you could use System.arraycopy:
byte[] one = getBytesForOne();
byte[] two = getBytesForTwo();
byte[] combined = new byte[one.length + two.length];
System.arraycopy(one,0,combined,0 ,one.length);
System.arraycopy(two,0,combined,one.length,two.length);
Or you could just use a List to do the work:
byte[] one = getBytesForOne();
byte[] two = getBytesForTwo();
List<Byte> list = new ArrayList<Byte>(Arrays.<Byte>asList(one));
list.addAll(Arrays.<Byte>asList(two));
byte[] combined = list.toArray(new byte[list.size()]);
Or you could simply use ByteBuffer with the advantage of adding many arrays.
byte[] allByteArray = new byte[one.length + two.length + three.length];
ByteBuffer buff = ByteBuffer.wrap(allByteArray);
buff.put(one);
buff.put(two);
buff.put(three);
byte[] combined = buff.array();
You can do this by using Apace common lang package (org.apache.commons.lang.ArrayUtils class ). You need to do the following
byte[] concatBytes = ArrayUtils.addAll(one,two);
I think it is best approach,
public static byte[] addAll(final byte[] array1, byte[] array2) {
byte[] joinedArray = Arrays.copyOf(array1, array1.length + array2.length);
System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
return joinedArray;
}
The simplest method (inline, assuming a and b are two given arrays):
byte[] c = (new String(a, cch) + new String(b, cch)).getBytes(cch);
This, of course, works with more than two summands and uses a concatenation charset, defined somewhere in your code:
static final java.nio.charset.Charset cch = java.nio.charset.StandardCharsets.ISO_8859_1;
Or, in more simple form, without this charset:
byte[] c = (new String(a, "l1") + new String(b, "l1")).getBytes("l1");
But you need to suppress UnsupportedEncodingException which is unlikely to be thrown.
The fastest method:
public static byte[] concat(byte[] a, byte[] b) {
int lenA = a.length;
int lenB = b.length;
byte[] c = Arrays.copyOf(a, lenA + lenB);
System.arraycopy(b, 0, c, lenA, lenB);
return c;
}
String temp = passwordSalt;
byte[] byteSalt = temp.getBytes();
int start = 32;
for (int i = 0; i < byteData.length; i ++)
{
byteData[start + i] = byteSalt[i];
}
The problem with your code here is that the variable i that is being used to index the arrays is going past both the byteSalt array and the byteData array. So, Make sure that byteData is dimensioned to be at least the maximum length of the passwordSalt string plus 32. What will correct it is replacing the following line:
for (int i = 0; i < byteData.length; i ++)
with:
for (int i = 0; i < byteSalt.length; i ++)
Assuming your byteData array is biger than 32 + byteSalt.length()...you're going to it's length, not byteSalt.length. You're trying to copy from beyond the array end.
I've used this code which works quite well just do appendData and either pass a single byte with an array, or two arrays to combine them :
protected byte[] appendData(byte firstObject,byte[] secondObject){
byte[] byteArray= {firstObject};
return appendData(byteArray,secondObject);
}
protected byte[] appendData(byte[] firstObject,byte secondByte){
byte[] byteArray= {secondByte};
return appendData(firstObject,byteArray);
}
protected byte[] appendData(byte[] firstObject,byte[] secondObject){
ByteArrayOutputStream outputStream = new ByteArrayOutputStream( );
try {
if (firstObject!=null && firstObject.length!=0)
outputStream.write(firstObject);
if (secondObject!=null && secondObject.length!=0)
outputStream.write(secondObject);
} catch (IOException e) {
e.printStackTrace();
}
return outputStream.toByteArray();
}