package eu.midnightdust.yaytris.util.sound; import eu.midnightdust.yaytris.Settings; import javax.sound.sampled.*; import java.io.IOException; /** * Handle music in separate threads to not interrupt the main game */ public class MusicThread extends Thread { private static final int BUFFER_SIZE = 8192; private final boolean looped; private final String fileLocation; private boolean playing; public MusicThread(String fileLocation, boolean looped) { this.fileLocation = fileLocation; this.looped = looped; this.playing = true; } public void stopMusic() { this.playing = false; } @Override public void run() { do { playMusic(fileLocation); } while (looped && playing); } /** * INTERNAL! * Play the long audio file found at the specified location. * Fades out after calling {@link #stopMusic()}. * Adapted from: Baeldung * * @see SoundUtil#playMusic(String, boolean) */ private void playMusic(String fileLocation) { try (AudioInputStream stream = AudioSystem.getAudioInputStream(SoundUtil.getResource(fileLocation))) { AudioFormat format = stream.getFormat(); DataLine.Info info = new DataLine.Info(SourceDataLine.class, format); SourceDataLine sourceDataLine = (SourceDataLine) AudioSystem.getLine(info); sourceDataLine.open(format); sourceDataLine.start(); SoundUtil.setVolume(sourceDataLine, Settings.musicVolume); float fadeOut = 1.0f; byte[] bufferBytes = new byte[BUFFER_SIZE]; int readBytes; while ((readBytes = stream.read(bufferBytes)) != -1) { if (!playing) { fadeOut = (float) Math.sin(fadeOut - 0.01f); // Sinus fade-out SoundUtil.setVolume(sourceDataLine, (int) (fadeOut * Settings.musicVolume)); if (fadeOut <= 0) break; } sourceDataLine.write(bufferBytes, 0, readBytes); } sourceDataLine.drain(); sourceDataLine.close(); } catch (LineUnavailableException | IOException | UnsupportedAudioFileException e) { throw new RuntimeException(e); } catch (IllegalArgumentException ignored) { // Happens when no audio device is connected } } }