Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to play clean audio loops and one-shot sounds in parallel in JavaFX 2.0?

Tags:

javafx-2

I'm trying to play background audio in a loop in a JavaFX 2.0 application using JavaFX SDK 2.0.1. I decided to use a MediaPlayer created by the following piece of code:

MediaPlayerBuilder
.create().media(BACKGROUND_MEDIA)
.cycleCount(MediaPlayer.INDEFINITE);

This basically works, but when a new cycle starts there is a tiny (latency?) gap between the end and the start of the audio. So it's not a working option for me since it's not playing a clean loop.

I decided to build a new MediaPlayer object and start playback everytime Media ends. This works fine so far. Additionally, I use a button playing a short AudioClip when clicked. I discoverd that frequent and fast clicking this button leads to interrupts in the background audio. I created an example to reproduce this behaviour by inifinitely playing an AudioClip with volume 0 when the button is clicked once. The example is not self contained, since the required audio files are missing. It requires to place 2 audio files in the project's source directory:

  • click.wav (a really short click sound ~300ms)
  • background.wav (~5 seconds of audio)

How do I achieve playing a clean audio loop in background without these interrupts when other one-shot audio sounds are played? Is it just a performance issue?

Example:

package mediatest;

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.media.AudioClip;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaPlayerBuilder;
import javafx.stage.Stage;

public class MediaTest extends Application {

    private static final AudioClip CLICK_AUDIOCLIP = new AudioClip(MediaTest.class.getResource("/click.wav").toString());
    private static final Media BACKGROUND_MEDIA = new Media(MediaTest.class.getResource("/background.wav").toString());

    private MediaPlayerBuilder builder;

    public static void main(String[] args) {
        Application.launch(args);
    }

    @Override
    public void start(Stage primaryStage) {
        Group root = new Group();
        Scene scene = new Scene(root, 300, 250);

        this.builder = MediaPlayerBuilder
                       .create()
                       .media(BACKGROUND_MEDIA)
                       .onEndOfMedia(new Runnable() {

                           public void run() {
                               MediaPlayer player = MediaTest.this.builder.build();
                               player.play();
                           }
                       });

        MediaPlayer player = this.builder.build();
        player.play();

        Button btn = new Button();
        btn.setText("Repeat playing short audio clip");
        btn.setOnAction(new EventHandler<ActionEvent>() {

            public void handle(ActionEvent event) {
                //Simulation of many button clicks
                MediaTest.CLICK_AUDIOCLIP.setCycleCount(AudioClip.INDEFINITE);
                MediaTest.CLICK_AUDIOCLIP.play(0);
            }
        });

        root.getChildren().add(btn);

        primaryStage.setScene(scene);
        primaryStage.show();
    }
}
like image 913
pmoule Avatar asked Nov 07 '11 21:11

pmoule


1 Answers

have you looked into ExecutorService? You would then have a number of predefined threads like so:

ExecutorService service = Executors.newFixedThreadPool(4);

where 4 is the number of threads it makes. It will improve performance because it uses already made threads rather than making a new one each time you want to run something.

You would create a Runnable and execute it with the service like so:

Runnable r = new Runnable() {
    @Override
    public void run() {
       playSound();
    }
};
service.execute(r);

Not only would this improve performance but it automatically assigns the job to a not-currently-busy thread in its thread pool.

Also look at this: Playing sound loops using javafx which I believe solves your small latency problem.

EDIT: damn sorry, I didn't know this post was that old. It was a top result in google.

like image 50
Limnic Avatar answered Sep 19 '22 10:09

Limnic