Как нормализовать смешанные файлы WAV

Я пытаюсь смешать два файла WAV.

Файлы WAV доступны в виде байтовых массивов, и я использую приведенный ниже код для их смешивания.

byte[] byte1 , byte[] byte2

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

Приведенный выше код в основном работает. Но когда результат превышает максимальную волну (16-битный аудиофайл), он имеет шум. Как я могу нормализовать смешанный звук?

 Rup04 июл. 2012 г., 16:17
Вы должны обрабатывать его по образцу, а не по байту. Это, вероятно, пары байтов для получения 16-битных значений выборки, но это может быть не так - вам нужно будет изучить заголовок .wav, чтобы выяснить это. Есть ли не простые библиотеки, чтобы помочь вам со всем этим?
 Bera04 июл. 2012 г., 17:22
Я должен добавить байты?
 Oliver Charlesworth04 июл. 2012 г., 17:19
Согласен с Rup; добавление отдельных байтов не имеет смысла. Вам нужно добавить 16-битные величины.
 Bera04 июл. 2012 г., 16:27
Я не использую какой-либо кодек, пишу на нативном, от байта к байту, @Rup Я не нашел для него ни одной хорошей библиотеки :(
 ArtemStorozhuk04 июл. 2012 г., 16:17
может использовать другой аудиокодек?

Ответы на вопрос(3)

    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();
    }

короче говоря, он не будет работать, потому что значение max равно 32768 (max short) и ничего не изменилось

 Bera06 июл. 2012 г., 09:33
@ Бьорн Рош обновлен, пожалуйста, посмотрите
 06 июл. 2012 г., 10:06
Это не сработает. DataInputStream и DataOutputStream ожидают данные в сетевом порядке байтов (с прямым порядком байтов). Однако весьма вероятно, что ваша машина имеет младший порядок байтов, поэтому вы перепутаете свои шорты с неправильным порядком байтов.
 06 июл. 2012 г., 16:12
нет, вы должны поменяться байтами самостоятельно, но есть обертки, написанные людьми. Вы можете найти их, выполнив поиск прямо здесь по переполнению стека. Nils несколько ошибочен: порядковый номер вашей машины не имеет значения, java всегда имеет большой порядковый номер, но wav-файлы имеют меньший порядковый номер, следовательно, отсталость.
 05 июл. 2012 г., 17:22
Это не сработает, потому что вы все еще читаете данные в байтах. Обратите внимание, что массивы в моем коде являются короткими, а не байтами.
 Bera06 июл. 2012 г., 10:58
Есть ли другой вариант, чтобы прочитать короткие данные из файла?
Решение Вопроса
    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();
    }
}

это работает, спасибо всем за ответы

Прежде всего, если ваше аудио действительно 16-битное, добавление его побайтно не будет работать. Другие люди прокомментировали это. Вы можете увидеть мой ответ здесь, как решить эту проблему.

использование AudioTrack для Android для объединения байтов звуковых образцов создает шум

Во-вторых, чтобы «нормализовать» Поэтому вам сначала нужно найти пик, а затем масштабировать все результаты до этого значения. Это означает, что две петли: одна, чтобы найти «пик» и один, чтобы добавить значения, масштабируя до нового пика. Что-то вроде этого:

//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
 Bera05 июл. 2012 г., 10:13
пожалуйста, смотрите код внизу

Ваш ответ на вопрос