简体   繁体   中英

Java (Sound) - Converting a 2D int array into a byte array

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) {}
    }
}

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 value 0x1f ( 0b11111 ). The shift distance actually used is therefore always in the range 0 to 31 , inclusive.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM