Java - Mixing audio files generates unwanted white noise - java

Recently, I've been experimenting with mixing AudioInputStreams together. After reading this post, or more importantly Jason Olson's answer, I came up with this code:
private static AudioInputStream mixAudio(ArrayList audio) throws IOException{
ArrayList<byte[]> byteArrays = new ArrayList();
long size = 0;
int pos = 0;
for(int i = 0; i < audio.size(); i++){
AudioInputStream temp = (AudioInputStream) audio.get(i);
byteArrays.add(convertStream(temp));
if(size < temp.getFrameLength()){
size = temp.getFrameLength();
pos = i;
}
}
byte[] compiledStream = new byte[byteArrays.get(pos).length];
for(int i = 0; i < compiledStream.length; i++){
int byteSum = 0;
for(int j = 0; j < byteArrays.size(); j++){
try{
byteSum += byteArrays.get(j)[i];
}catch(Exception e){
byteArrays.remove(j);
}
}
compiledStream[i] = (byte) (byteSum / byteArrays.size());
}
return new AudioInputStream(new ByteArrayInputStream(compiledStream), ((AudioInputStream)audio.get(pos)).getFormat(), ((AudioInputStream)audio.get(pos)).getFrameLength());
}
private static byte[] convertStream(AudioInputStream stream) throws IOException{
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int numRead;
while((numRead = stream.read(buffer)) != -1){
byteStream.write(buffer, 0, numRead);
}
return byteStream.toByteArray();
}
This code works very well for mixing audio files. However, it seems the more audio files being mixed, the more white noise that appears in the returned AudioInputStream. All of the files being combined are identical when it comes to formatting. If anyone has any suggestions\advice, thanks in advance.

I could be wrong, but I think your problem has to do with the fact that you are messing with the bytes instead of what the bytes mean. For instance, if you are working with a 16 bit sampling rate, 2 bytes form the number that corresponds to the amplitude rather than just 1 byte. So, you end up getting something close but not quite right.

Related

Is there any pointer feature in java to pass the byte array?

I need to divide a byte array into 3 parts and process them one by one
The first 120 data array is filled in callback function of a Bluetooth device read request, so it's impossible for me to change
byte[] data = new byte[120];
------
byte[] buf = new byte[40];
for (int i = 0; i < 3; ++i) {
System.arraycopy(data, i * 40, packetBuffer, 0, 40);
processDataStream(buf);
}
If in c/c++, I can use pointer so no need to call copy.
In Java, is arraycopy the best way? is there any more efficient way?
Thanks in advance
In most cases you'd just specify an offset and provide it to your method:
byte[] buf = new byte[40];
for (int i = 0; i < 3; ++i) {
processDataStream(buf, i * 40);
}
Then you only need to apply it:
processDataStream(byte[] buf, int offset) {
for (int i = offset; i < offset + 40; i++) {
...
}
}

Extract data from .wav file in Java

I am trying to extract data from .wav file to draw a wave graph, but I am stuck as I get the only a stream of 0s with my code:
AudioInputStream ais = AudioSystem.getAudioInputStream(new File("audio/sine_-06_05_02000.wav"));
AudioFormat format = ais.getFormat();
format = new AudioFormat(format.getFrameRate(), format.getSampleSizeInBits(), format.getChannels(), true, true);
ais = AudioSystem.getAudioInputStream(format, ais);
int sample_size = format.getSampleSizeInBits() / 8;
ArrayList<Long> data = new ArrayList<Long>();
int size = 400;
while (data.size() < size)
{
byte[] buffer = new byte[8];
ais.read(buffer, 8-sample_size, sample_size);
if (buffer[8-sample_size] < 0)
{
for (int i = 0; i < 8 - sample_size; i++)
{
buffer[i] = -1;
}
}
data.add(ByteBuffer.wrap(buffer).getLong());
}
for(long value:data)
{
System.out.println(value);
}
Please tell me why I cannot get the data and where my code is wrong if you could find out. Thank you!
Edit: I figured it out that my audio resource was digital, but the code was for analog audio.

Converting Bytes To BitSets

I am trying to figure out a way of taking data from a file and I want to store every 4 bytes as a bitset(32). I really have no idea of how to do this. I have played about with storing each byte from the file in an array and then tried to covert every 4 bytes to a bitset but I really cannot wrap my head around using bitsets. Any ideas on how to go about this?
FileInputStream data = null;
try
{
data = new FileInputStream(myFile);
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] b = new byte[1024];
int bytesRead;
while ((bytesRead = data.read(b)) != -1)
{
bos.write(b, 0, bytesRead);
}
byte[] bytes = bos.toByteArray();
Ok, you got your byte array. Now what you have to convert each byte to a bitset.
//Is number of bytes divisable by 4
bool divisableByFour = bytes.length % 4 == 0;
//Initialize BitSet array
BitSet[] bitSetArray = new BitSet[bytes.length / 4 + divisableByFour ? 0 : 1];
//Here you convert each 4 bytes to a BitSet
//You will handle the last BitSet later.
int i;
for(i = 0; i < bitSetArray.length-1; i++) {
int bi = i*4;
bitSetArray[i] = BitSet.valueOf(new byte[] { bytes[bi], bytes[bi+1], bytes[bi+2], bytes[bi+3]});
}
//Now handle the last BitSet.
//You do it here there may remain less than 4 bytes for the last BitSet.
byte[] lastBitSet = new byte[bytes.length - i*4];
for(int j = 0; j < lastBitSet.length; j++) {
lastBitSet[i] = bytes[i*4 + j]
}
//Put the last BitSet in your bitSetArray
bitSetArray[i] = BitSet.valueOf(lastBitSet);
I hope this works for you as I have written quickly and did not check if it works. But this gives you the basic idea, which was my intention at the beginning.

Trouble with saving a 4D array to file

I have some code that does not seem to operate the way it should. The whole point is to take a 256x128x256x2 array of integers, split it into 256 16x128x16x2 chunks, process the chunks into a byte array, then add that byte array to a main array of bytes to be saved. chunkdata[] is fine before saving, but after saving the whole file is blank except the first 4096 bytes. the location table (location of each chunk in the file) is there and the first four byte "chunk header" is there, everything else is 0's, which isn't supposed to happen.
public void createFile(int[][][][] map){
byte[] file = new byte[fileLength]; //22,024,192 bytes long
System.arraycopy(Sector.locationTable, 0, file, 0, Sector.locationTable.length); //This works as it should
for(int cx = 0; cx < 16; cx++)
{
for(int cz = 0; cz < 16; cz++)
{
int start = sectorLength+cx*(sectorLength*chunkSectorLength)+cz*(chunkRows*sectorLength*chunkSectorLength); //this algorithm works, just rather hideous
int[][][][] chunk = getChunk(map, cx * 16, cz * 16); //This works as it should
byte[] chunkdata = putChunk(chunk); //The data from this is correct
int counter = 0;
for(int i=start;i<chunkdata.length;i++){
file[i]=chunkdata[counter]; //Data loss here?
counter++;
}
}
}
System.out.println("Saving file...");
writeFile(file, fileLocation);
}
public static void writeFile(byte[] file,String filename){
try{
FileOutputStream fos = new FileOutputStream(filename);
fos.write(file);
fos.close();
Messages.showSuccessfulSave();
}catch(Exception ex){
Messages.showFileSavingError(ex);
}
}
So, assuming putChunk and getChunk work as intended, and my hideous algorithms, what could cause everything past the first 4096 bytes to be blank?
Thanks in advance.
Why are you comparing i against chunkdata.length when i is initialized with start? I think counter should be used instead.
Current:
int counter = 0;
for(int i=start;i<chunkdata.length;i++){
file[i]=chunkdata[counter]; //Data loss here?
counter++;
}
Instead, you want to write something like this:
int counter = 0;
for(int i=start;counter<chunkdata.length;i++){
file[i]=chunkdata[counter]; //Data loss here?
counter++;
}
or more compact way:
for(int i=start,counter = 0;counter<chunkdata.length;i++,counter++){
file[i]=chunkdata[counter]; //Data loss here?
}

Decoded mp3 stream can not be read

I am developing an application that uses mp3 encoding/decoding. While in principle it behaves correctly for most of the files, there are some exceptions. I detected that these files have a missing header. I get an array out of bound exception when attempting to decode. I used two approaches but both failed.
The first:
DecodedMpegAudioInputStream dais = (DecodedMpegAudioInputStream) AudioSystem.getAudioInputStream(daisf, ais);
byte[] audioData = IOUtils.toByteArray(dais);//exception here
And the second:
ByteOutputStream bos = new ByteOutputStream();
// Get the decoded stream.
byte[] byteData = new byte[1];
int nBytesRead = 0;
int offset = 0;
int cnt=1;
while (nBytesRead != -1) {
System.out.println("cnt="+cnt);
nBytesRead = dais.read(byteData, offset, byteData.length);//exception here at first loop
if (nBytesRead != -1) {
int numShorts = nBytesRead >> 1;
for (int j = 0; j < numShorts; j++) {
bos.write(byteData[j]);
}
}
cnt+=1;
}
byte[] audioData = bos.getBytes();
It seems that there is an issue with the headers or the structure of it, because the dais stream has content/bytes. However it can be opened with audacity and ffplay so I believe there should be a workaround. Any ideas how to counter it?
You could use code redundancy to improve reliability. Look into alternative libraries, such as Xuggler or JLayer.

Categories

Resources