【问题标题】:Determine Amplitude of Sound From Microphone确定来自麦克风的声音幅度
【发布时间】:2014-04-09 19:52:40
【问题描述】:

我正在尝试确定使用 Java Sound API 录制的乐器(小号、吉他等)的振幅,并显示振幅与时间的关系图。我对这个 API 没有太多经验,也不太清楚如何计算声波输入的 RMS 或 FFT。我该如何实现这一目标?

import javax.swing.*; 
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.sound.sampled.*;

public class FrequencyAmplitude extends JFrame {
/**
     * 
     */
    private static final long serialVersionUID = 1173050310536562125L;
//CAPTURE AUDIO TEST #1
  protected boolean running;
  ByteArrayOutputStream out;

  public FrequencyAmplitude() {
    super("Recording Demo");
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    Container content = getContentPane();

    final JButton capture = new JButton("Record");
    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);
              }
            }
            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);
  }
  public static void main(String args[]) {
    JFrame frame = new FrequencyAmplitude();
    frame.pack();
    frame.setVisible(true);
  }
}

    enter code here

【问题讨论】:

  • 您发布的代码与您要解决的问题有什么关系?您当前的实施有什么问题?
  • 没有错,我没有说有什么错,我的问题是从这个设置中我将如何计算音频的音量?
  • 哦,代码是用来录制音频的
  • 一开始我打算建议DataLine.getLevel(),但似乎没有实现。有一个关于它的讨论 here 和解决方法。

标签: java audio fft rms amplitude


【解决方案1】:

将字节数组转换为浮点数组。基本上就是这样。float数组的长度将是byte数组长度的1/8。

如果将代码的输出粘贴到 excel 或 libre office calc(ubuntu) 中,您将看到波形

    ByteBuffer buf = ByteBuffer.wrap(bytes);
    long[] longs = new long[bytes.length / 8];
    for (int i = 0; i < longs.length; i++)
     {
        longs[i] = buf.getLong(i*8);
        System.out.println(longs[]i);

     }

这不是理想的做法,但为了简单起见,将代码放在 CaptureAudio 的 while 块中。不要重新计算超过大约两秒,然后将输出复制到 excel 中绘制折线图。你会看到波形。

【讨论】:

  • System.out.println(longs[]i); 中的错误
猜你喜欢
  • 2012-01-22
  • 2011-08-09
  • 1970-01-01
  • 1970-01-01
  • 2021-09-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-21
相关资源
最近更新 更多