更新JavaFx中的应用程序线程以绘制节点

问题描述 投票:2回答:1

我正在开发一个程序,该程序将能够使用来自麦克风或Line-in的流式幅度数据绘制音频波形。我认为这样做的方法是以等于采样率的速率从采样数据中绘制每个点,并在每个方向上沿x方向绘制1步。因此,我需要大约每秒44100次更新JavaFx Application线程以绘制每个点。在开始执行此操作之前,我想通过画一条直线并每半秒更新一次每个点来检验我的想法。我正在使用时间轴类来做到这一点。我的代码如下:

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闪烁,则效果很好。是否存在无法使用“时间轴”类绘制线的原因?它会给线程带来过多的负担吗?如果是这样,我该如何解决我的想法。我只希望能够实时绘制波形,并以每秒约44,100次的速度更新。

animation javafx audio audio-streaming javax.sound.sampled
1个回答
0
投票

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

然后问题变成要显示的内容。如果我正在攻击此问题,请尝试以下操作:

  1. 创建一个数组以保持位置,每个像素一个存储桶,用于显示的大小。
  2. [创建一个从这样的数组中提取数据的函数,可以由动画计时器调用它
  3. 创建并发安全队列以保存这些数组(例如ConcurrentLinkedQueue
  4. ConcurrentLinkedQueue的读取内容加载到AudioInputLine中>
  5. ConcurrentLinkedQueue的轮询AnimationTimer
  6. 要获得计时的时间,您可能需要使用抽取(例如,每3个或更多PCM数据点中的第2个或第2个扔掉),或者如果无法轻松进行所需的抽取,则使用线性插值使用有理分数。换句话说,您不受阵列(附加像素)和PCM数据点之间1:1对应的束缚。您使用的抽取越多,丢失的高频就会越多。

© www.soinside.com 2019 - 2024. All rights reserved.