音频电平表

问题描述:

我是新来编程,我试图做一个Java应用程序,将“听到”(不一定记录)的声音和显示有多大。我想转换录音到数字,所以我可以看到声音水平的差异。我得到了这段代码,并添加了“getLevel()”方法,该方法返回当前录音的振幅,但每次都返回-1。我想我不是正确使用它。任何想法,我必须调用这种方法?我必须在一周内完成我的项目,所以任何帮助将非常感谢!音频电平表

public class Capture extends JFrame { 

     protected boolean running; 
     ByteArrayOutputStream out; 

     public Capture() { 
     super("Capture Sound Demo"); 
     setDefaultCloseOperation(EXIT_ON_CLOSE); 
     Container content = getContentPane(); 

     final JButton capture = new JButton("Capture"); 
     final JButton stop = new JButton("Stop"); 
     final JButton play = new JButton("Play"); 

     capture.setEnabled(true); 
     stop.setEnabled(false); 
     play.setEnabled(false); 

     ActionListener captureListener = 
      new ActionListener() { 
      public void actionPerformed(ActionEvent e) { 
      capture.setEnabled(false); 
      stop.setEnabled(true); 
      play.setEnabled(false); 
      captureAudio(); 
      } 
     }; 
     capture.addActionListener(captureListener); 
     content.add(capture, BorderLayout.NORTH); 

     ActionListener stopListener = 
      new ActionListener() { 
      public void actionPerformed(ActionEvent e) { 
      capture.setEnabled(true); 
      stop.setEnabled(false); 
      play.setEnabled(true); 
      running = false; 
      } 
     }; 
     stop.addActionListener(stopListener); 
     content.add(stop, BorderLayout.CENTER); 

     ActionListener playListener = 
      new ActionListener() { 
      public void actionPerformed(ActionEvent e) { 
      playAudio(); 
      } 
     }; 
     play.addActionListener(playListener); 
     content.add(play, BorderLayout.SOUTH); 
     } 

     private void captureAudio() { 
     try { 
      final AudioFormat format = getFormat(); 
      DataLine.Info info = new DataLine.Info(
      TargetDataLine.class, format); 
      final TargetDataLine line = (TargetDataLine) 
      AudioSystem.getLine(info); 
      line.open(format); 
      line.start(); 

      Runnable runner = new Runnable() { 
      int bufferSize = (int)format.getSampleRate() 
       * format.getFrameSize(); 
      byte buffer[] = new byte[bufferSize]; 

      public void run() { 
       out = new ByteArrayOutputStream(); 
       running = true; 
       try { 
       while (running) { 
        int count = 
        line.read(buffer, 0, buffer.length); 
        if (count > 0) { 
        out.write(buffer, 0, count); 

        System.out.println(line.getLevel()); // |-this is what i added-| 
        } 
       } 
       out.close(); 
       } catch (IOException e) { 
       System.err.println("I/O problems: " + e); 
       System.exit(-1); 
       } 
      } 
      }; 
      Thread captureThread = new Thread(runner); 
      captureThread.start(); 
     } catch (LineUnavailableException e) { 
      System.err.println("Line unavailable: " + e); 
      System.exit(-2); 
     } 
     } 

     private void playAudio() { 
     try { 
      byte audio[] = out.toByteArray(); 
      InputStream input = 
      new ByteArrayInputStream(audio); 
      final AudioFormat format = getFormat(); 
      final AudioInputStream ais = 
      new AudioInputStream(input, format, 
      audio.length/format.getFrameSize()); 
      DataLine.Info info = new DataLine.Info(
      SourceDataLine.class, format); 
      final SourceDataLine line = (SourceDataLine) 
      AudioSystem.getLine(info); 
      line.open(format); 
      line.start(); 

      Runnable runner = new Runnable() { 
      int bufferSize = (int) format.getSampleRate() 
       * format.getFrameSize(); 
      byte buffer[] = new byte[bufferSize]; 

      public void run() { 
       try { 
       int count; 
       while ((count = ais.read(
        buffer, 0, buffer.length)) != -1) { 
        if (count > 0) { 
        line.write(buffer, 0, count); 
        } 
       } 

       line.drain(); 
       line.close(); 

       } catch (IOException e) { 
       System.err.println("I/O problems: " + e); 
       System.exit(-3); 
       } 
      } 
      }; 
      Thread playThread = new Thread(runner); 
      playThread.start(); 
     } catch (LineUnavailableException e) { 
      System.err.println("Line unavailable: " + e); 
      System.exit(-4); 
     } 
     } 

     private AudioFormat getFormat() { 
     float sampleRate = 8000; 
     int sampleSizeInBits = 8; 
     int channels = 1; 
     boolean signed = true; 
     boolean bigEndian = true; 
     return new AudioFormat(sampleRate, 
      sampleSizeInBits, channels, signed, bigEndian); 
     } 

     @SuppressWarnings("deprecation") 
    public static void main(String args[]) { 
     JFrame frame = new Capture(); 
     frame.pack(); 
     frame.show(); 
     } 
} 
+0

你却加上'的System.out.println(line.getLevel()) ;'?请参阅文档:http://docs.oracle.com/javase/7/docs/api/javax/sound/sampled/DataLine.html#getLevel%28%29“返回: 此行中信号的当前幅度,或AudioSystem.NOT_SPECIFIED“所以-1意味着别的东西出错了。 – turbo

+0

请注意,'running'在不同步的线程中被访问,没有同步分配:在UI线程和捕获线程中。通常情况下,你可以确保通过剔除“volatile”来获得'running'的当前值。 – Vertex

是的,就像@tubro说的那样,它是AudioSystem.NOT_SPECIFIED = -1

我在我的程序中使用以下函数通过计算均方根来获得分贝的响度。请注意,我假设归一化样本的值为-1到+1。为此,我写了一个PCM解码器至极支持不同格式的8位,16位,符号,无符号大端等

public final class Loudness { 
    public static final float evaluate(final float[] window) { 
     if (window == null) { 
      throw new NullPointerException(); 
     } else if (window.length == 0) { 
      throw new IllegalArgumentException("window is empty"); 
     } 

     float sum = 0.0f; 
     for (int i = 0; i < window.length; i++) { 
      assert window[i] >= -1.0f && window[i] <= 1.0f; 
      sum += (window[i] * window[i]); 
     } 
     // Root Mean Square 
     // 0 <= rms <= 1 
     final float rms = (float) Math.sqrt(sum/window.length); 
     // 0 <= decibel 
     final float decibel = (float) (20 * Math.log10(rms)); 
     return decibel; 
    } 
} 
+0

好吧,我设法使它捕获音频并在xls文件上打印当前样本的时间戳和值,但存在一个问题:即使我在时间和值之间放置了一些空格,似乎它们在不同的列中,它们实际上位于xls的同一列,它只是展开并覆盖下一列(如果您不明白,我可以放置一个打印屏幕)。如何使它打印时间和数据振幅在两个不同的列? – xchris

+0

@xchris:在时间和度量值之间放置一个制表符:'System.out.println(time +“\ t”+ value)''。将控制台输出复制并粘贴到excel中的左上角单元格 – Vertex

+0

是的,“\ t”在csv上无法正常工作,但它在xls上正常工作,谢谢! – xchris