1
votes

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

1
Mixing implies that you want to end up with an audio file file that is the summation of the two signals. It should end up being the same amount of channels with the length of the longer of the two files. What you are doing in your bootloadOutputData actually appears to be "interleaving" samples of the two audio files. What I would expect is to 1) Convert each sample to int or float. 2) Add them together 3) Convert that result to bytes, and write it to your outputEhz
as stepping stone to mix together multiple tracks is to get code working which reads in one track burrowing down to the PCM raw audio level where you have access to the audio curve bytes ... print them to console as you read across the input file then save that low level raw audio to an output file ... once you have that working its far easier to do multiple tracks in parallelScott Stensland
also use mono audio not stereo as stereo adds complexity you can easily add later ... free audio work station Audacity is your friend visualize the audio there until you write your own audio code toolbox utils to do similar ;-)Scott Stensland
@Ehz. It turns out I also need to parse every file on the paragraphs and each new paragraph to be translated into (int) and sum each int countParagraphs[] = new int[count]; countParagraphs[0] = (c1 + c2); //... And in the end all values to int convert to byte and write raw data?A. Nick
@ScottStensland. Thanks for the reply. Could you elaborate on the tracks?A. Nick

1 Answers

1
votes

If I understand correctly, you want to do the following:

  1. Given 2 input WAV files, mix them together to a single WAV file.
  2. The contents of the output will be the input files played at the same time, not one after the other.
  3. The length of the new file will be the length of the longest of the input files.
  4. All files, input and output, are 16 bit, stereo 44100Hz.

If that's the case, here are (some of) your mistakes:

  1. 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!).
  2. 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.
  3. 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.