Comment lire des boucles audio propres et des sons one-shot en parallèle dans JavaFX 2.0?


J'essaie de lire l'audio d'arrière-plan en boucle dans une application JavaFX 2.0 en utilisant JavaFX SDK 2.0.1. J'ai décidé d'utiliser un MediaPlayer créé par le morceau de code suivant:

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

Cela fonctionne essentiellement, mais quand un nouveau cycle commence, il y a une minuscule (latence?) écart entre la fin et le début de l'audio. Donc, ce n'est pas une option de travail pour moi car il ne joue pas une boucle propre.

J'ai décidé de construire un nouvel objet MediaPlayer et de lancer la lecture à chaque fin de média. Ce fonctionne très bien jusqu'à présent. De plus, j'utilise un bouton pour lire un court clip audio lorsque vous cliquez dessus. J'ai découvert que le fait de cliquer fréquemment et rapidement sur ce bouton entraîne des interruptions dans l'audio d'arrière-plan. J'ai créé un exemple pour reproduire ce comportement en jouant inifinitely un clip audio avec le volume 0 lorsque le bouton est cliqué une fois. L'exemple n'est pas autonome, car les fichiers audio requis sont manquants. Il nécessite de placer 2 fichiers audio dans le répertoire source du projet:

  • cliquez sur.WAV (un son de clic très court ~300 ms)
  • contexte.wav (~5 secondes d'audio)

Comment puis-je obtenir la lecture d'une boucle audio propre en arrière-plan sans ces interruptions lorsque d'autres sons audio one-shot sont lus? Est-ce juste un problème de performance?

Exemple:

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();
    }
}
Author: pmoule, 2011-11-08

2 answers

Avez-vous examiné ExecutorService? Vous auriez alors un certain nombre de threads prédéfinis comme ceci:

ExecutorService service = Executors.newFixedThreadPool(4);

Où 4 est le nombre de threads qu'il fait. Cela améliorera les performances car il utilise des threads déjà créés plutôt que d'en créer un nouveau chaque fois que vous souhaitez exécuter quelque chose.

Vous créeriez un Runnable et l'exécuteriez avec le service comme ceci:

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

Non seulement cela améliorerait les performances, mais il attribue automatiquement le travail à un pas-actuellement occupé fil dans son pool de threads.

Regardez aussi ceci: Jouer des boucles sonores en utilisant javafx qui, je crois, résout votre petit problème de latence.

EDIT: putain désolé, je ne savais pas que ce post était si vieux. C'était un meilleur résultat dans Google.

 1
Author: Limnic, 2014-02-15 19:51:48

En utilisant un autre thread à

public void handle(ActionEvent event) {
            Platform.runLater(new Runnable()
            {
               @Override
               public void run()
               {  
                  //Simulation of many button clicks
                  MediaTest.CLICK_AUDIOCLIP.setCycleCount(AudioClip.INDEFINITE);
                  MediaTest.CLICK_AUDIOCLIP.play(0);
               }
            });
        }
    });

Peut résoudre le problème de l'interruption

 0
Author: Bruno Vieira, 2012-09-19 12:33:12