How to normalize mixed WAV files

2020-06-29 21:53发布

I am trying to mix two WAV files.

The WAV files are available as byte arrays and I am using below code to mix the two.

byte[] byte1 , byte[] byte2

// 44 is header of wav file
for( int i = 44 ; i < byte1.length ; i++){
   byte1[i] = byte1[i] + byte2[i];
}

The above code mostly works. But when the result is more than maximum wave (16 bit audio file), it has noise. How can I normalize mixed sound?

3条回答
劫难
2楼-- · 2020-06-29 22:14
    short[] audioData1 = null;
    short[] audioData2 = null;

    int n = 0;

    try {
        DataInputStream in1;
        in1 = new DataInputStream(new FileInputStream("v1.wav"));
        ByteArrayOutputStream bos = new ByteArrayOutputStream();

        try {

            while ((n = in1.read()) != -1) {
                bos.write(n);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        ByteBuffer bb = ByteBuffer.wrap(bos.toByteArray());
        bb.order(ByteOrder.LITTLE_ENDIAN);
        ShortBuffer sb = bb.asShortBuffer();
        audioData1 = new short[sb.capacity()];

        for (int i = 0; i < sb.capacity(); i++) {
            audioData1[i] = sb.get(i);
        }

    } catch (IOException e) {
        e.printStackTrace();
    }

    try {
        DataInputStream in1;
        in1 = new DataInputStream(new FileInputStream("v2.wav"));
        ByteArrayOutputStream bos = new ByteArrayOutputStream();

        try {

            while ((n = in1.read()) != -1) {
                bos.write(n);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        ByteBuffer bb = ByteBuffer.wrap(bos.toByteArray());
        bb.order(ByteOrder.LITTLE_ENDIAN);
        ShortBuffer sb = bb.asShortBuffer();
        audioData2=  new short[sb.capacity()];

        sb.get(audioData2);


        System.out.println();
    } catch (IOException e) {
        e.printStackTrace();
    }

    // find the max:
    float max = 0;
    for (int i = 22; i < audioData1.length; i++) {
        if (Math.abs(audioData1[i] + audioData2[i]) > max)
            max = Math.abs(audioData1[i] + audioData2[i]);
    }

    System.out.println("" + (Short.MAX_VALUE - max));

    int a, b, c;

    // now find the result, with scaling:
    for (int i = 22; i < audioData1.length; i++) {
        a = audioData1[i];
        b = audioData2[i];

        c = Math.round(Short.MAX_VALUE * (audioData1[i] + audioData2[i])
                / max);

        if (c > Short.MAX_VALUE)
            c = Short.MAX_VALUE;
        if (c < Short.MIN_VALUE)
            c = Short.MIN_VALUE;


        audioData1[i] = (short) c; 

    }

    // to turn shorts back to bytes.
    byte[] end = new byte[audioData1.length * 2];
    ByteBuffer.wrap(end).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().put(audioData1);

    try {
        OutputStream out  = new FileOutputStream("mixer.wav");

        for (int i = 0; i < end.length; i++) {
            out.write(end[i]);
            out.flush();
        }

        out.close();

    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

this works, thanks all for answers

查看更多
孤傲高冷的网名
3楼-- · 2020-06-29 22:16
    short[] audioData1 = null;
    short[] audioData2 = null;

    int n = 0;

    DataInputStream in1;
    try {
        in1 = new DataInputStream(new FileInputStream("audio1.wav"));

        audioData1 = new short[in1.available() / 2];
        ShortBuffer b1 = ShortBuffer.wrap(audioData1);
        try {

            while (true) {
                n = in1.readShort();
                b1.put((short) n);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }

    DataInputStream in2;
    try {
        in2 = new DataInputStream(new FileInputStream("audio2.wav"));

        audioData2 = new short[in2.available() / 2];
        ShortBuffer b2 = ShortBuffer.wrap(audioData2);
        try {

            while (true) {
                n = in2.readShort();
                b2.put((short) n);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    } catch (IOException e) {
        e.printStackTrace();
    }

        // find the max:
    float max = 0;
    for (int i = 44; i < audioData1.length; i++) {
        if (Math.abs(audioData1[i] + audioData2[i]) > max)
            max = Math.abs(audioData1[i] + audioData2[i]);
    }

    // now find the result, with scaling:
    for (int i = 44; i < audioData1.length; i++) {
        audioData1[i] = (short) Math.round(Short.MAX_VALUE
                * (audioData1[i] + audioData2[i]) / max);
    }


    DataOutputStream out;

    try {
        out = new DataOutputStream(new FileOutputStream("mix.wav"));

        for (int i = 0; i < audioData1.length; i++) {
            out.writeShort(audioData1[i]);
            out.flush();
        }

        out.close();

    } catch (IOException e) {
        e.printStackTrace();
    }

now it is in short, it won't work because value max is 32768 (max short) and nothing changed

查看更多
Juvenile、少年°
4楼-- · 2020-06-29 22:35

First of all, if, indeed, your audio is 16 bits, adding it byte-by-byte won't work. Other people commented on this. You can see my answer here for how to handle this problem.

using Android's AudioTrack to combine bytes of sound samples produces noise

Secondly, to "normalize" it, you'll have to find the peak first, and then scale all results to that value. That means two loops: one to find the "peak" and one to add the values, scaling to the new peak. Something like this:

//this is the raw audio data -- no header
short[] audioData1 , short[] audioData2

//find the max:
float max = 0;
for( int i = 0 ; i < audioData1.length ; i++) {
   if( Math.abs( audioData1[i] + audioData2[i] ) > max )
      max = Math.abs( audioData1[i] + audioData2[i] );
}

//now find the result, with scaling:
for( int i = 0 ; i < audioData1.length ; i++) {
   audioData1[i] = Math.Round(Short.MAX_VALUE * ( audioData1[i] + audioData2[i] ) / max) ;
}
//normalized result in audioData1
查看更多
登录 后发表回答