2012-07-04 2 views
0

Я пытаюсь смешивать два файла 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-битный аудиофайл), он имеет шум. Как я могу нормализовать смешанный звук?

+2

Вы должны обрабатывать его с помощью значения образца, а не байта. Вероятно, это пары байтов, чтобы сделать 16-битные значения выборки, но это может быть не так - вам нужно будет изучить заголовок .wav, чтобы узнать. Существуют ли не простые библиотеки, которые помогут вам в этом? – Rup

+0

может использовать другой аудиокодек? – ArtemStorozhuk

+0

Я не использую какой-либо кодек, я пишу в native, byte by byte, @Rup Я не нашел для него никакой хорошей библиотеки :( – user1028269

ответ

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

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

4

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

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

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

//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 
+0

см. код внизу – user1028269

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

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

+0

Это не сработает, потому что вы все еще читаете данные в виде байтов. Обратите внимание, что массивы в моем коде являются шортами, а не байтами. –

+0

@Bjorn Рош обновлен, пожалуйста, см. Его – user1028269

+1

Это не сработает. DataInputStream и DataOutputStream ожидают данные в сетевом порядке байтов (big endian). Однако очень вероятно, что ваша машина немного ориентирована, поэтому вы получите свои шорты в неправильной энциклопедии –

Смежные вопросы