2011-11-07 8 views
7

Próbuję odtworzyć dźwięk w tle w pętli w aplikacji JavaFX 2.0 przy użyciu JavaFX SDK 2.0.1. Postanowiłem użyć MediaPlayer utworzony przez następujący fragment kodu:Jak odtwarzać czyste pętle audio i jednokrotne dźwięki równolegle w JavaFX 2.0?

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

to w zasadzie działa, ale kiedy nowy cykl rozpoczyna tam jest mały (latency?) Przerwa pomiędzy końcem i początkiem dźwięku. Więc to nie działa dla mnie, ponieważ nie gra w czystą pętlę.

Postanowiłem zbudować nowy obiekt MediaPlayer i rozpocząć odtwarzanie za każdym razem, gdy Media się kończy. To działa dobrze do tej pory. Dodatkowo po kliknięciu używam przycisku odtwarzającego krótki klip AudioClip. Odkryłem, że częste i szybkie klikanie tego przycisku prowadzi do przerwań w dźwięku w tle. Stworzyłem przykład, aby odtworzyć to zachowanie, nieumyślnie odtwarzając AudioClip z głośnością 0, gdy przycisk zostanie kliknięty raz. Przykład nie jest niezależny, ponieważ brakuje wymaganych plików audio. To wymaga, aby umieścić 2 pliki audio w projekcie w katalogu źródłowym:

  • click.wav (bardzo krótki dźwięk kliknięcia ~ 300ms)
  • background.wav (~ 5 sekund Audio)

Jak uzyskać odtwarzanie czystej pętli audio w tle bez tych przerwań, gdy odtwarzane są inne jednorazowe dźwięki? Czy to tylko kwestia wydajności?

Przykład:

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(); 
    } 
} 
+1

Podczas korzystania z "javax.sound.sampled.SourceDataLine" dla dźwięku w tle nie ma problemu. Odtwarzanie dźwięku za pomocą "javafx.scene.media.Media" wydaje się działać inaczej. – pmoule

Odpowiedz

0

Korzystanie z innego wątku w

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); 
       } 
      }); 
     } 
    }); 

może rozwiązać ten problem przerywania

+1

Dzięki, ale kod jest już wykonywany w wątku aplikacji JavaFX. Tak więc nie ma innego zachowania podczas wywoływania 'Platform.runlater (...)'. I event próbował uruchomić go w nowo utworzonym wątku z 'new Thread (new Runnable (...)). Start();'. Problem jest nadal obecny. – pmoule

1

pan spojrzał ExecutorService? Będziesz mieć wtedy pewną liczbę wstępnie zdefiniowanych wątków:

ExecutorService service = Executors.newFixedThreadPool(4); 

gdzie 4 to liczba wątków, które tworzy. Poprawi to wydajność, ponieważ używa już utworzonych wątków zamiast tworzyć nowe za każdym razem, gdy chcesz coś uruchomić.

Można by utworzyć Runnable i wykonać go z obsługi tak:

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

Nie tylko to poprawić wydajność, ale to automatycznie przydziela zadania do nie-aktualnie zajęty wątku w jego puli wątków.

Zobacz także: Playing sound loops using javafx, które moim zdaniem rozwiązuje problem małego opóźnienia.

EDYCJA: cholera przepraszam, nie wiedziałem, że ten post był tak stary. Był to najlepszy wynik w Google.

Powiązane problemy