2017-09-13 26 views
0

나는 사운드 디지털화에 대해 많이 모른다. 마이크 입력의 즉각적인 프로파일을 나타 내기 위해 노력하고 있습니다. 마이크에서 비트를 얻는 방법을 알고 있지만 프로파일로 해석하는 방법을 모르겠습니다. 누구든지 공백을 채울 수 있습니까? 마이크 입력의 프로파일을 그리시오

package test; 

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Container; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.RenderingHints; 
import java.awt.event.ActionEvent; 
import java.io.IOException; 
import java.io.OutputStream; 
import javax.sound.sampled.AudioFileFormat; 
import javax.sound.sampled.AudioFormat; 
import javax.sound.sampled.AudioInputStream; 
import javax.sound.sampled.AudioSystem; 
import javax.sound.sampled.DataLine; 
import javax.sound.sampled.LineUnavailableException; 
import javax.sound.sampled.TargetDataLine; 
import javax.swing.AbstractAction; 
import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.SwingUtilities; 

/** 
* 
* @author François Billioud 
*/ 
public class SoundRecorder extends JFrame { 

    /** JFrame for the GUI **/ 
    public SoundRecorder() { 
     super("Sound Recorder"); 
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     Container pane = getContentPane(); 
     pane.setLayout(new BorderLayout()); 
     pane.add(wavePane = new WavePane(), BorderLayout.CENTER); 
     pane.add(new JButton(new AbstractAction("ok") { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       dispose(); 
      } 
     }), BorderLayout.SOUTH); 
     setSize(300,300); 
     setLocationRelativeTo(null); 
    } 

    /** Just displays the frame and starts listening **/ 
    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       SoundRecorder rec = new SoundRecorder(); 
       rec.setVisible(true); 
       rec.listenToMic(); 
      } 
     }); 
    } 

    /** Draws the sound read from the mic **/ 
    private static class WavePane extends JPanel { 
     private final int[] x = new int[0]; 
     private int[] y = new int[0]; 
     private WavePane() { 
      setOpaque(true); 
      setBackground(Color.WHITE); 
     } 
     /** updates the data to be displayed **/ 
     public void setData(int[] y) { 
      this.y = y; 
      int n = y.length; 
      this.x = new int[n]; 
      float pas = getWidth()/(float)(n-1); 
      float xCurrent = 0; 
      for(int i=0; i<n; i++) { 
       this.x[i] = Math.round(xCurrent); 
       xCurrent+=pas; 
      } 
      repaint(); 
     } 
     /** Draws a line that represent the mic profile **/ 
     @Override 
     public void paint(Graphics g) { 
      super.paint(g); 
      Graphics2D g2D = (Graphics2D) g; 
      g2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON); 
      g2D.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); 
      g2D.drawPolyline(x, y, x.length); 
     } 
    } 

    /** Defines the audio format to be used. 
    * I know nothing about that and am open to suggestions if needed 
    */ 
    private static final AudioFormat format = new AudioFormat(
      16000, //Sample rate 
      16, //SampleSizeInBits 
      2, //Channels 
      true,//Signed 
      true //BigEndian 
    ); 

    /** Creates a thread that will read data from 
    * the mic and send it to the WavePane 
    * in order to be painted. 
    * We should be using a SwingWorker, but it will do 
    * for the sake of this demo. 
    **/ 
    private void listenToMic() { 
     new Thread(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        //Open the line and read 
        DataLine.Info info = new DataLine.Info(TargetDataLine.class, format); 

        //checks if system supports the data line 
        if (!AudioSystem.isLineSupported(info)) { 
         System.err.print("Line not supported"); 
        } 

        //starts listening 
        TargetDataLine line = (TargetDataLine) AudioSystem.getLine(info); 
        line.open(format); 
        line.start(); 

        //sends the stream to the interpreter 
        AudioInputStream ais = new AudioInputStream(line); 
        AudioSystem.write(ais, AudioFileFormat.Type.AU, new Interpreter()); 
       } catch (LineUnavailableException | IOException ex) { 
        System.err.println(ex.getLocalizedMessage()); 
       } 
      } 
     }).start(); 
    } 

    private final WavePane wavePane; 
    private class Interpreter extends OutputStream { 
     private int[] y; 

     @Override 
     public void write(int b) throws IOException { 
      //TBD 

      //Fill y array 
     } 

     @Override 
     public void flush() throws IOException { 
      //Sends the values found to the panel for drawing 
      wavePane.setData(y); 
     } 

    } 

} 

내가 this link을 발견하지만

편집 ... 나에게 도움이되지 않았다 : 좋아, 각각 16 비트, 내가 이해에서 하나 개의 주파수에 대한 진폭이다. 저는 2 채널을 가지고 있으므로 첫 채널을 얻기 위해 매 32 비트마다 32 비트를 읽어야합니다. 이제 각 프레임에 대해 얼마나 많은 주파수를 읽어야하는지 알 필요가 있습니다. 그런 다음 프로파일을 그릴 수 있다고 생각합니다. 어떤 힌트?

답변

0

마이크에서 오는 신호의 스펙트럼 (시간에 따른 주파수 당 에너지)을 그리려면 this을 읽고 싶을 수 있습니다. 아마 당신이 알고 싶었지만 필요한 수학이 있습니다.

진폭 (시간 경과에 따른 압력)을 그리려면 예를 들어 this을 확인하십시오.

오디오 형식의 지정에 따라 오디오 스트림의 내용은 PCM 스트림이됩니다. PCM 스트림은 모든 프레임이 그 순간의 사운드 압력 값이라는 것을 의미합니다. 각 프레임은 4 바이트, 채널 당 2 바이트로 구성됩니다. 처음 두 바이트는 채널 0, 다른 두 채널은 1입니다. 두 바이트는 빅 엔디안 형식입니다 (중요도가 더 낮은 바이트보다 먼저 올 것임). True로 서명 한 사실은 값이 -32768에서 32767 사이 인 것으로 해석해야 함을 의미합니다.

+0

매우 완벽한 링크를 제공해 주셔서 감사합니다. 실시간으로 마이크에서 주파수 당 에너지를 끌어오고 싶습니다. 링크는 좋지만 마이크 입력을 비트로 변환 할 때 STFT가 완료됩니다. 질문은 스트림을 읽었을 때 스트림에서 데이터가 정렬되는 방식과 내 표현을 얻기 위해 데이터를 다시 정렬해야하는 방식에 관한 것입니다. 무슨 뜻인지 알 겠어? – Sharcoux

+0

응답 내용에 스트림 내용에 대한 설명을 추가했습니다. – astraujums

+0

확인. 나는 단지 몇 가지 더 많은 정보를 가지고 있다고 생각합니다. 음수를 어떻게 해석해야합니까? 에너지는 음수가 될 수 없으므로 -3000은 PI의 단계에서 3000을 의미한다고 생각하십니까? 그렇다면 절대 값을 고려해야합니까? 빅 엔디안 부호없는 형식의 바이트 배열'byte [16]'을 가지고 있다면 그것을 숫자로 변환하는 올바른 방법은 무엇입니까? 당신의 도움을 주셔서 대단히 감사합니다! – Sharcoux