Search code examples
javajavafxplayback

How do you make an AudioClip/MediaPlayer in JavaFX loop perfectly?


I'm trying to play a sound that loops perfectly where you can't tell when it starts over. I know that I can get an AudioClip or MediaPlayer to loop indefinitely with the setCycleCount method, and this works. However, the audio isn't perfectly continuous; there's a very split second where it's not playing, so it's extremely obvious when it starts over. I know it's not a problem with the audio file itself because when I play it on loop on an audio player, it loops perfectly. I've tried both AudioClip and MediaPlayer, and I tried using setOnEndOfMedia to make it loop instead, but they all had the same problem. Here's an example:

import java.io.File;
import java.net.*;
import java.util.Scanner;
import javafx.scene.media.*;

public class AudioTest {
    public static void main(String[] args) {
        URI audioURI = new File("filePath").toURI();
        
        AudioClip audio = new AudioClip(audioURI.toString());
        audio.setCycleCount(AudioClip.INDEFINITE);
        audio.play();
        
        /*
        setOnEndOfMedia version
        
        MediaPlayer audio = new MediaPlayer(new Media(audioURI.toString()));
        audio.setOnEndOfMedia(new Runnable() {
            @Override
            public void run() {
                audio.seek(Duration.ZERO);
                audio.play();
            }
        });
        */
        
        new Scanner(System.in).next(); // to prevent the program from closing immediately
    }
}

and a link to an example audio file: https://drive.google.com/file/d/1NzlqY-K7m__qXE6iKJw3H26KZ8Ql4U2n/view?usp=sharing

My operating system is Windows 11, and I'm using Java 17 and JavaFX 17. My CPU is an 11th Gen Intel(R) Core(TM) i5-1135G7. Is there any way I can fix this?


Solution

  • Here is an example with javax.sound that loops a wav file (the sine wave file named tone.wav that you link in your question).

    I loop the sound five times, but you can loop it as many times as you want.

    To use it from a JavaFX application, you could wrap the sound playback using javax.sound in a JavaFX task and supply an interface to it (being careful of the threading coding for concurrent applications).

    import javax.sound.sampled.*;
    import java.io.IOException;
    import java.util.Objects;
    import java.util.Scanner;
    
    public class SoundTest {
        public static void main(String[] args) throws LineUnavailableException, IOException, UnsupportedAudioFileException {
            AudioInputStream stream = AudioSystem.getAudioInputStream(
                    Objects.requireNonNull(
                            SoundTest.class.getResource(
                                    "tone.wav"
                            )
                    )
            );
            AudioFormat format = stream.getFormat();
            DataLine.Info info = new DataLine.Info(Clip.class, format);
            Clip clip = (Clip) AudioSystem.getLine(info);
            clip.open(stream);
            clip.loop(5);
    //        clip.start();
    
            new Scanner(System.in).next(); // to prevent the program from closing immediately
        }
    }
    

    For me, I get a continual, seamless loop of the audio with the javax.sound playback.

    But with the Java MediaPlayer or AudioClip, using your sample code, I get a break between loops as you mention in your question. I do not know why this is and if it is restricted to some attribute of the sound you are playing or some current limitation of JavaFX audio playback on certain or all platforms. You might want to ask the openjfx-dev mailing list for more information.

    The test system used was JavaFX 21.0.1 and OpenJDK 21 on an OS X 14.1.2 Mac.

    A note on javax.sound usage.

    javax.sound is an alternate sound playback interface to JavaFX media. The javax.sound packages are part of the java.desktop module which is (as of JavaFX 21) required as part of any JavaFX installation (even though the javax.sound system has nothing to do with JavaFX).

    The javax.sound system might not fit your requirements though as it may not natively play back the sound formats you want, but for certain sound formats it might be a workable alternative.

    Oracle provide a tutorial for the javax.sound API if needed.