Обновление потока приложения в JavaFx для отрисовки узлов - PullRequest
2 голосов
/ 09 апреля 2020

Я разрабатываю программу, которая сможет рисовать звуковую форму с использованием потоковых данных амплитуды с микрофона или линейного входа. Я подумал, что для этого нужно будет нарисовать каждую точку из данных выборки со скоростью, равной частоте выборки, и сделать шаг 1 в направлении x с каждой нарисованной точкой. Поэтому мне нужно обновлять поток приложения JavaFx примерно 44100 раз в секунду, чтобы нарисовать каждую точку. Прежде чем начать, я хотел проверить свою идею, просто нарисовав прямую линию и обновляя каждую точку каждые полсекунды. Я использую класс 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();  
  } 
}

Однако каждый раз, когда я делаю это, моя программа перестает отвечать на запросы, и мне приходится принудительно закрывать ее. Я заметил, что если я делаю то же самое, но вместо этого заставляю текст мигать и выключаться, это прекрасно работает. Есть ли причина, по которой линии не могут быть нарисованы с использованием класса Timeline? Не слишком ли сильно загружен поток? Если так, то каким образом я могу решить мою идею? Я просто хочу иметь возможность рисовать осциллограммы в режиме реального времени, обновляя их со скоростью 44 100 раз в секунду.

1 Ответ

0 голосов
/ 09 апреля 2020

Я рекомендую AnimationTimer для любой продолжающейся анимации. Он пытается обновить как можно ближе к 60 кадрам в секунду. (Я только что прочитал некоторые комментарии после первого, порекомендовав AnimationTimer. Эти люди правы. ИДК, почему они сами не опубликовали это как ответ.)

Затем возникает вопрос, что отображать. Если бы я атаковал эту проблему, вот что я бы попробовал:

  1. создать массив для хранения позиций, по одному ведру на пиксель, для размера дисплея.
  2. сделать функция, которая выводит aws данных из такого массива, который может быть вызван таймером анимации
  3. , создает параллельную безопасную очередь для хранения этих массивов (например, ConcurrentLinkedQueue)
  4. загрузите ConcurrentLinkedQueue с чтениями из вашего AudioInputLine
  5. опроса из ConcurrentLinkedQueue из AnimationTimer

Чтобы время работало, вам может потребоваться используйте децимацию (например, выбрасывание каждых 2-х или 2-х из 3-х и более точек данных PCM) или линейную интерполяцию, если нужное прореживание не дает простой в использовании рациональной дроби. Другими словами, вы не привязаны к соответствию 1: 1 между массивом (привязанным к пикселям) и точками данных PCM. Чем больше вы используете децимацию, тем более высокие частоты будут потеряны.

...