Java down和upampling upampling

时间:2018-03-09 13:25:57

标签: java audio recording downsampling

我是java Sound API的初学者,在oracle和richard brawlin中阅读了许多内容,并尝试使用他的程序进行一些项目。我想要捕获的第一个是声音并对其进行下采样,然后给出正确的音频形式。然后我会尝试相同但没有录音。

首先,我将向您展示代码的重要部分,然后我将告诉您我的问题:

在这里,我用我的麦克风录制声音:

stopCapture = false;
try{
    int i = 0;
    System.out.println("Start");
    //Schleife um daten aufzunehmen
  while(!stopCapture){
    //daten vom targetDataLine lesen
    int cnt = targetDataLine.read(tempBuffer,0,tempBuffer.length);


    if(cnt > 0){//Jeder 5. Wert wird übernommen
      //Die daten in der bytearrayoutputstream speichern
      byteArrayOutputStream.write(tempBuffer, 0, cnt);

      }


    }

然后我在Bytearray audioData中转换byteArrayOutputStream并尝试使用samplerate 48000/5 = 9800“下采样”我录制的音频。换句话说,它是我的bytearray audioData的每5个值。然后我想将它插回到原始的samplerate 48000.参见代码:

public void run(){
try{
  int cnt;
  int n = 0;
  int k = 0;
  int m = 0;
  double summe = 0;


  ByteArrayOutputStream aufnahme_2 = new ByteArrayOutputStream();

  System.out.println("Replay");
  //Schleife soll solange laufen bis die letzte Datei abgespielt wurde.
  //Am ende gibt die Datei -1 raus
  Downsampling 5==> Jeder 5. Wert wird übernommen
 for(; m<= audioData.length;m++) {

      if ( m%5 < 0.000001 & m != 0) {
          k++;
          n=k;
      }

      for(;n<=5+k;n++) {
          if(n*5 < audioData.length) {
              if(Math.abs((double) m/5-n) <0.00001) {
              summe = summe+ audioData[n*5];
          }
              else {
              summe = summe + audioData[n*5]*Math.sin(Math.PI*((double) m/5-n))/( Math.PI*((double) m/5-n));    //Der double cast muss sein, damit die zahl als double und nicht als int gerechnet wird 
          }
         }
      }

      //byteBuffer.putShort((short) summe);
      aufnahme_2.write((short) summe);      //Short weil der Datentyp short 2Byte große ist
      summe = 0;
      n=k;
  }
  ergebnis = aufnahme_2.toByteArray();

  InputStream byteArrayInputStream_down = new ByteArrayInputStream(ergebnis);
  audioInputStream = new AudioInputStream(byteArrayInputStream_down, audioFormat,ergebnis.length); 

  while((cnt = audioInputStream.read(tempBuffer,0,tempBuffer.length))!=-1) {

    if(cnt > 0){
      sourceDataLine.write(tempBuffer, 0, cnt);

    }
  }

我的Audioformat:

 private AudioFormat getAudioFormat(){

float sampleRate = 48000;
int sampleSizeInBits = 16;
int channels = 2;
boolean signed = true;
boolean bigEndian = false;

return new AudioFormat(sampleRate, sampleSizeInBits, channels, signed, bigEndian);

}

有了这个音响制品,我收到了非常糟糕的声音质量。当我在8中更改sampleSizeInBits时声音更清晰为什么?我希望得到16位的分辨率。我试图以整数,字节....格式保护我的sinc值,没有任何帮助。所以我希望有人可以帮助并告诉我为什么不起作用的原因。

PS:我发送了一张我用Matlab制作的图片来表明我的目标: 蓝线是我的音频输入,黑色是重采样的重建音频输出

enter image description here

1 个答案:

答案 0 :(得分:0)

这是整个程序:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.ShortBuffer;

import javax.sound.sampled.*;

public class AudioCapture01 extends JFrame{


  boolean stopCapture = false;
  ByteArrayOutputStream byteArrayOutputStream;
  AudioFormat audioFormat;
  TargetDataLine targetDataLine;
  AudioInputStream audioInputStream;
  SourceDataLine sourceDataLine;
  byte [] audioData;


  public static void main(String args[]){

    new AudioCapture01();
  }//end main

  public AudioCapture01(){//constructor
    final JButton captureBtn =  new JButton("Capture");

    final JButton stopBtn = new JButton("Stop");

    final JButton playBtn = new JButton("Playback");


    captureBtn.setEnabled(true);
    stopBtn.setEnabled(false);
    playBtn.setEnabled(false);

    //Register anonymous listeners
    captureBtn.addActionListener(
      new ActionListener(){
        public void actionPerformed(
                        ActionEvent e){
          captureBtn.setEnabled(false);
          stopBtn.setEnabled(true);
          playBtn.setEnabled(false);
          //Capture input data from the
          // microphone until the Stop
          // button is clicked.
          captureAudio();
        }//end actionPerformed
      }//end ActionListener
    );//end addActionListener()
    getContentPane().add(captureBtn);

    stopBtn.addActionListener(
      new ActionListener(){
        public void actionPerformed(
                        ActionEvent e){
          captureBtn.setEnabled(true);
          stopBtn.setEnabled(false);
          playBtn.setEnabled(true);

          stopCapture = true;
        }//end actionPerformed
      }//end ActionListener
    );//end addActionListener()
    getContentPane().add(stopBtn);

    playBtn.addActionListener(
      new ActionListener(){
        public void actionPerformed(
                        ActionEvent e){
          //Play back all of the data
          // that was saved during
          // capture.
          playAudio();
        }//end actionPerformed
      }//end ActionListener
    );//end addActionListener()
    getContentPane().add(playBtn);

    getContentPane().setLayout(
                     new FlowLayout());
    setTitle("Capture/Playback Demo");
    setDefaultCloseOperation(
                        EXIT_ON_CLOSE);
    setSize(350,70);
    setVisible(true);
  }// end constructor

     private void captureAudio(){
    try{


        //Schema F implementierung... richtige aufnahme mit samplerate 48000Hz
      audioFormat = getAudioFormat();

DataLine.Info dataLineInfo=new DataLine.Info(TargetDataLine.class,audioFormat);


      //hier wird das Objekt TargetDataLine erstellt
      targetDataLine = (TargetDataLine) AudioSystem.getLine(dataLineInfo);     
      targetDataLine.open(audioFormat);
      targetDataLine.start();


      Thread captureThread =  new Thread(new CaptureThread());            

      captureThread.start();
    } 
    catch (Exception e) {
      System.out.println(e);
      System.exit(0);
    }
  }

  // Vorteil eines Bytearrayutputstream ist es, dass das Array sich automatisch erweitert
  // Die daten sind im ByteArrayOutputStream gespeichert
  //in der Methode werden die Daten widergegeben und abgespielt
  private void playAudio() {
    try{
      // das was gesampelt wurde wird in ein byte array umgewandelt um damit weitere methoden zu nutzen
    int i =0;
    audioData = byteArrayOutputStream.toByteArray();
      System.out.println("laenge von audioData" + audioData.length);    //Um zu sehen was passiert

      /**for(; i< audioData.length ;i++) {
          System.out.println(audioData[i]);
      }

      System.out.println("Index i = " + i);
      */           

      //das Array wandel ich in ein inpustream um
      InputStream byteArrayInputStream = new ByteArrayInputStream(audioData); 

         //Um am ende es in ein audioinputstream hinzuzufügen
        //wird benutzt um daraus die daten zu lesen und sie in die sourcedataline zu schreiben
      audioInputStream = new AudioInputStream(byteArrayInputStream, audioFormat,audioData.length/audioFormat.getFrameSize()); 

      //Damit kann ich es sofort abspielen lassen.
      //audioInputStream = AudioSystem.getAudioInputStream(audioFormat_down,new AudioInputStream(targetDataLine)); 
      //Das heißt ich speicher die Daten nicht zuerst in einem Array sondern lass sie sofort abspielen    
      DataLine.Info dataLineInfo = new DataLine.Info(SourceDataLine.class, audioFormat);

      //Sourcedataline ist dafür verantworlich das die Daten       
      sourceDataLine = (SourceDataLine) AudioSystem.getLine(dataLineInfo); 

      sourceDataLine.open(audioFormat);
      sourceDataLine.start();

   // Threat um die daten die aufgenommen wurden abzuspielen
      Thread playThread = new Thread(new PlayThread());

      playThread.start();
    } 
    catch (Exception e) {
      System.out.println(e);
      System.exit(0);
    }
  }


  private AudioFormat getAudioFormat(){

    float sampleRate = 48000;
    int sampleSizeInBits = 16;//change it to 8 to get a clear sound
    int channels = 2;
    boolean signed = true;
    boolean bigEndian = false;

    return new AudioFormat(sampleRate, sampleSizeInBits, channels, signed, bigEndian);

  }


//die Innere Thread Methode um den "run" ablauf der signalaufnahme zu regulieren
class CaptureThread extends Thread{
  //temporerer buffer
  byte tempBuffer[] = new byte[10000];
  public void run(){
    byteArrayOutputStream = new ByteArrayOutputStream(); //hier initialisiere ich die variabele bytearrayoutputstream

    stopCapture = false;
    try{
        int i = 0;
        System.out.println("Start");
        //Schleife um daten aufzunehmen
      while(!stopCapture){
        //daten vom targetDataLine lesen
        int cnt = targetDataLine.read(tempBuffer,0,tempBuffer.length);


        if(cnt > 0){//Jeder 5. Wert wird übernommen
          //Die daten in der bytearrayoutputstream speichern
          byteArrayOutputStream.write(tempBuffer, 0, cnt);

          }
        i++;

        }
      System.out.println("Aufnahme hat Werte = "+ i +"gespeichert");

      byteArrayOutputStream.close();
    }catch (Exception e) {
      System.out.println(e);
      System.exit(0);
    }
  }
}

//Die innere klasse von Thread um die gespeicherten daten im bytearrayoutputstream abzuspielen
class PlayThread extends Thread{
  byte tempBuffer[] = new byte[200000];
  byte ergebnis[] = new byte[audioData.length];

  ByteBuffer byteBuffer;
  ShortBuffer shortBuffer;


  public void run(){
    try{
      int cnt;
      int n = 0;
      int k = 0;
      int m = 0;
      double summe = 0;

      //byteBuffer = ByteBuffer.wrap(ergebnis);
      //shortBuffer = byteBuffer.asShortBuffer();
      ByteArrayOutputStream aufnahme_2 = new ByteArrayOutputStream();

      System.out.println("Replay");
      //Schleife soll solange laufen bis die letzte Datei abgespielt wurde.
      //Am ende gibt die Datei -1 raus
     /** while((cnt = audioInputStream.read(tempBuffer,0,tempBuffer.length))!=-1) {
          System.out.println(tempBuffer[i]);
          i++;
         if(cnt > 0){
            //schreibt daten in den Mixer
          //sourceDataLine.write(tempBuffer, 0, cnt);

        }

      }
      System.out.println("index i = "+i);
      */
      //Versuch :SI-interpolation tempBuffer hat die Werte gespeichert. Downsampling 5==> Jeder 5. Wert wird übernommen
     for(; m<= audioData.length;m++) {

          if ( m%5 < 0.000001 & m != 0) {
              k++;
              n=k;
          }

          for(;n<=5+k;n++) {
              if(n*5 < audioData.length) {
                  if(Math.abs((double) m/5-n) <0.00001) {
                  summe = summe+ audioData[n*5];
              }
                  else {
                  summe = summe + audioData[n*5]*Math.sin(Math.PI*((double) m/5-n))/( Math.PI*((double) m/5-n));    //Der double cast muss sein, damit die zahl als double und nicht als int gerechnet wird 
              }
             }
          }

          //byteBuffer.putShort((short) summe);
          aufnahme_2.write((int) summe);        //Short weil der Datentyp short 2Byte große ist
          summe = 0;
          n=k;
      }
      ergebnis = aufnahme_2.toByteArray();

      /** 
      System.out.println("Ergebnisse");
      for(n=0;n < audioData.length; n++) {                           Die Arrayliste auf die Werte von audioData und ergebnisse zu prüfen
          System.out.println(ergebnis[n]+" "+ audioData[n]+ " "+n);
      }
      */


      InputStream byteArrayInputStream_down = new ByteArrayInputStream(ergebnis);
      audioInputStream = new AudioInputStream(byteArrayInputStream_down, audioFormat,ergebnis.length); 

      while((cnt = audioInputStream.read(tempBuffer,0,tempBuffer.length))!=-1) {

        if(cnt > 0){
          sourceDataLine.write(tempBuffer, 0, cnt);

        }
      }

      sourceDataLine.stop();
      sourceDataLine.close();
    }
    catch (Exception e) {
      System.out.println(e);
      System.exit(0);
    }
  }
}
}