2

我正在开发一个程序,该程序将能够使用来自麦克风或线路输入的流式幅度数据来绘制音频波形。我想这样做的方法是以等于采样率的速率从样本数据中绘制每个点,在绘制每个点时在 x 方向上移动 1 步。因此,我需要每秒更新大约 44100 次 JavaFx 应用程序线程来绘制每个点。在我开始这样做之前,我想通过画一条直线并且每半秒更新一次每个点来测试我的想法。我正在使用 Timeline 类来执行此操作。我的代码如下所示:

public class JavaFxPractice extends Application { 
  private int xValue = 50;

  @Override 
  public void start(Stage primaryStage) {      
    Pane pane = new Pane();

    EventHandler<ActionEvent> eventHandler = e -> {
      xValue++;
      Line point = new Line(xValue,50,xValue,50);
      pane.getChildren().add(point);
    };

    Timeline animation = new Timeline(new KeyFrame(Duration.millis((500)), eventHandler)); 
    animation.setCycleCount(500);
    animation.play();

    Scene scene = new Scene(pane, 600, 500);
    primaryStage.setTitle("Streaming Test");
    primaryStage.setScene(scene);
    primaryStage.show();  
  } 
}

但是,每次我这样做时,我的程序都会变得无响应,我必须强制关闭它。我注意到,如果我做同样的事情,而是让 Text 闪烁,它工作得非常好。是否有原因无法使用 Timeline 类绘制线条?它会给线程带来太多负担吗?如果是这样,我可以通过什么方式解决我的想法。我只想能够实时绘制波形,以每秒 44,100 次左右的速度更新。

4

1 回答 1

0

我推荐AnimationTimer任何正在进行的动画。它尝试尽可能接近 60 fps 进行更新。(我刚刚阅读了第一个评论之后的一些评论,推荐AnimationTimer。这些人是对的。IDK 为什么他们自己没有将其发布为答案。)

那么问题就变成了要显示什么。如果我要解决这个问题,我会尝试以下方法:

  1. 制作一个数组来保存位置,每个像素一个桶,用于显示的大小。
  2. 制作一个从这样的数组中提取数据的函数,可以由动画计时器调用
  3. 创建一个并发安全队列来保存这些数组(例如,ConcurrentLinkedQueue
  4. 加载ConcurrentLinkedQueue从您的读取AudioInputLine
  5. 民意ConcurrentLinkedQueue调查AnimationTimer

要确定时间,您可能需要使用抽取(例如,在 3 个或更多 PCM 数据点中每隔 2 个或 2 个丢弃一次),或者如果所需的抽取不能轻松实现,则使用线性插值- 使用有理分数。换句话说,您不会被绑定到数组(绑定到像素)和 PCM 数据点之间的 1:1 对应关系。您使用的抽取越多,丢失的高频就越多。

于 2020-04-09T15:36:25.137 回答