Reputation: 101
I'm developing a program that will be able to draw the audio waveform using the streamed amplitude data from a microphone or Line-in. The way I thought to do this would be to draw each point from the sample data at a rate equal to the sample rate, going 1 step over in the x direction with each point drawn. Therefore I would need to update the JavaFx Application thread around 44100 times a second to draw each point. Before I start doing this I wanted to test my idea out by just drawing a straight line and only updating each point every half a second. I'm using the Timeline class to do this. My code looks like this:
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();
}
}
However every time I do this my program becomes unresponsive and I have to force close it. I noticed that if I do the same thing but instead make Text blink on and off, it works perfectly fine. Is there a reason Lines aren't able to be drawn using the Timeline class? Does it put too much of a load on the thread? If so, what ways can I go around solving my idea. I just want to be able to draw a waveform in real time, updating at around 44,100 times a second.
Upvotes: 2
Views: 129
Reputation: 7910
I recommend AnimationTimer
for any ongoing animation. It attempts to update as close to 60 fps as it can. (I just read some comments following the first one, recommending AnimationTimer
. These folks are right. IDK why they didn't post that as an answer themselves.)
The question then becomes what to display. If I were attacking this problem, here is what I would try:
ConcurrentLinkedQueue
)ConcurrentLinkedQueue
with reads from your AudioInputLine
ConcurrentLinkedQueue
from the AnimationTimer
To get the timings to work out, you may need to use decimation (e.g., throwing out every 2nd or 2 out of 3 or more PCM data points), or linear interpolation if the needed decimation doesn't come out to an easy-to-use rational fraction. In other words, you are not tied to a 1:1 correspondence between the array (tied to pixels) and the PCM data points. The more decimation you use, the more high frequencies will be lost.
Upvotes: 0