Reputation: 75
I'm trying to mix 2 audio clips (same format, same length). For each of my clips, I transform them into byte ararys, convert these byte arrays into 2D int arrays, add them, and convert my new 2D int array into a byte array, then write it to the disk. This works pretty well ... on only one channel. My created file, in this case test.wav, only has sound in the left ear. In my program, I have a method that allows me to store 2D int tabs into a txt file. I tried analyzing test.wav, converting it into a byte array and then into a 2D int array, the same way I use to convert my original clips. I get two vectors, one for each audio channel. In my first vector, I get what I'm supposed to have, an addition of the left channels of my two clips, but in my second vector (the right channel), I get a succession of -1 and 0. I am guessing there is something wrong with my TabToByte method but I can't put my finger on it.
Any help would be greatly appreciated ! Thanks' in advance.
The code :
public class Main {
public static void main (String[] args) {
//My audio clips
String wavFile1 = "C:\\Users\\Alban.Alban-PC\\Documents\\Java\\Generateur-de-musiques-commerciales\\Samples\\Fa.wav";
String wavFile2 = "C:\\Users\\Alban.Alban-PC\\Documents\\Java\\Generateur-de-musiques-commerciales\\Samples\\Drum beat.wav";
try {
AudioInputStream clip1 = AudioSystem.getAudioInputStream(new File(wavFile1));
AudioInputStream clip2 = AudioSystem.getAudioInputStream(new File(wavFile2));
//frameLength of each clip
int frameLength1 = (int) clip1.getFrameLength();
int frameLength2 = (int) clip2.getFrameLength();
//Frame size = 4 because I'm using 2-channels with 16-bits encoded sound
int frameSize1 = (int) clip1.getFormat().getFrameSize();
int frameSize2 = (int) clip2.getFormat().getFrameSize();
//Number of channels = 2
int numChannels = clip1.getFormat().getChannels();
//byte array to store my entier clips
byte[] eightBitByteArray1 = new byte[frameLength1 * frameSize1];
byte[] eightBitByteArray2 = new byte[frameLength2 * frameSize2];
//Converts my clips into chosen byte arrays
clip1.read(eightBitByteArray1);
clip2.read(eightBitByteArray2);
//I want to store my clip samples in 2D int arrays
int[][] toReturn1 = new int[numChannels][frameLength1];
int[][] toReturn2 = new int[numChannels][frameLength2];
int[][] toReturn = new int[numChannels][frameLength2];
//I convert each byte array into 2D int arrays
toReturn1 = ByteToTab(eightBitByteArray1);
toReturn2 = ByteToTab(eightBitByteArray2);
//I add my 2 int arrays
//This is equivalent to mixing my clips
toReturn = addTab(toReturn1, toReturn2);
//I convert my new int array into a new byte array
byte[] mix = TabToByte(toReturn);
//I store my 2D int arrays in txt files to see if I get proper results
fichierTxt(toReturn1, "do.txt");
fichierTxt(toReturn2, "drum.txt");
fichierTxt(toReturn, "mix.txt");
//I create an inputStream with my new byte array
InputStream byteArray = new ByteArrayInputStream(mix);
//I create a new clip
AudioInputStream ais = new AudioInputStream(byteArray,
clip1.getFormat(), clip1.getFrameLength());
//I write it on the disk
AudioSystem.write(ais,
AudioFileFormat.Type.WAVE,
new File("C:\\Users\\Alban.Alban-PC\\Documents\\Java\\test.wav"));
} catch (UnsupportedAudioFileException e) {
} catch (IOException e) {e.printStackTrace(); }
}
//Transforms 2 bytes into a single int
public static int getSixteenBitSample(int high, int low) {
return (high << 8) + (low & 0x00ff);
}
//Creates a byte array from a 2D int array
public static byte[] TabToByte (int[][] tab) {
byte[] b = new byte[tab[0].length*4];
int count = 0;
for (int i = 0; i < tab[0].length; i ++){
for (int j = 0; j <tab.length; j++){
for (int k = 0; k < 2; k++){
b[count] = (byte)(tab[j][i] >>> (count * 8));
count++;
}
}
}
return b;
}
//Creates a 2D int array from a byte array
public static int[][] ByteToTab (byte[] array) {
int sampleIndex = 0;
int[][] toReturn = new int [2][array.length/4];
for (int t = 0; t < array.length;) {
for (int channel = 0; channel < 2; channel++) {
int low = (int) array[t];
t++;
int high = (int) array[t];
t++;
int sample = getSixteenBitSample(high, low);
toReturn[channel][sampleIndex] = sample;
}
sampleIndex++;
}
return toReturn;
}
//Ajouter 2 tableaux de même dimension entre eux
public static int[][] addTab(int[][] tab1, int[][] tab2) {
int[][] tab = new int[tab1.length][tab1[0].length];
for (int i = 0; i < tab1.length; i ++) {
for (int j = 0; j < tab1[0].length; j++) {
tab [i][j] = tab1[i][j]+tab2[i][j];
}
}
return tab;
}
//To write a 2D tab into a txt file
public static void fichierTxt(int[][] tab, String s) {
try {
String s1 = "C:\\Users\\Alban.Alban-PC\\Documents\\Java\\";
String st = s1 +s;
File fichier = new File(st);
fichier.createNewFile();
FileWriter fichierWrite = new FileWriter(fichier);
for (int i = 0; i < tab.length; i++){
fichierWrite.write("[ ");
for (int j = 0; j < tab[i].length; j ++){
fichierWrite.write(tab[i][j]+" ");
}
fichierWrite.write("]");
fichierWrite.write(System.lineSeparator());
}
fichierWrite.close();
} catch (Exception e) {}
}
}
Upvotes: 0
Views: 1645
Reputation: 37835
You've got
b[count] = (byte)(tab[j][i] >>> (count * 8));
count++;
and you should have
b[count] = (byte)(tab[j][i] >>> (k * 8));
count++;
You probably meant to shift down by either 0
or 8
.
Shifting by count * 8
will get you weird results:(jls)
[…] only the five lowest-order bits of the right-hand operand are used as the shift distance. It is as if the right-hand operand were subjected to a bitwise logical
AND
operator&
with the mask value0x1f
(0b11111
). The shift distance actually used is therefore always in the range0
to31
, inclusive.
Upvotes: 2