Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add multiple clip playing support #544

Merged
merged 8 commits into from
Apr 2, 2024
90 changes: 59 additions & 31 deletions src/client/java/minicraft/core/io/Sound.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
import minicraft.util.Logging;
import org.jetbrains.annotations.Nullable;

import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.DataLine;
Expand All @@ -13,6 +15,9 @@
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;

import java.applet.AudioClip;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
Expand All @@ -21,10 +26,16 @@ public class Sound {
// Creates sounds from their respective files
private static final HashMap<String, Sound> sounds = new HashMap<>();

private Clip clip; // Creates a audio clip to be played
private final DataLine.Info info;
private final byte[] raw;
private final AudioFormat format;
private final long length;

private Sound(Clip clip) {
this.clip = clip;
private Sound(DataLine.Info info, byte[] raw, AudioFormat format, long length) {
this.info = info;
this.raw = raw;
this.format = format;
this.length = length;
}

public static void resetSounds() {
Expand All @@ -33,7 +44,9 @@ public static void resetSounds() {

public static void loadSound(String key, InputStream in, String pack) {
try {
DataLine.Info info = new DataLine.Info(Clip.class, AudioSystem.getAudioFileFormat(in).getFormat());
AudioFileFormat fileFormat = AudioSystem.getAudioFileFormat(in);
AudioFormat format = fileFormat.getFormat();
DataLine.Info info = new DataLine.Info(Clip.class, format);

if (!AudioSystem.isLineSupported(info)) {
Logging.RESOURCEHANDLER_SOUND.error("ERROR: Audio format of file \"{}\" in pack \"\" is not supported: {}", key, pack, AudioSystem.getAudioFileFormat(in));
Expand Down Expand Up @@ -65,25 +78,21 @@ public static void loadSound(String key, InputStream in, String pack) {
return;
}

Clip clip = (Clip)AudioSystem.getLine(info);
clip.open(AudioSystem.getAudioInputStream(in));

clip.addLineListener(e -> {
if (e.getType() == LineEvent.Type.STOP) {
clip.flush();
clip.setFramePosition(0);
}
});

sounds.put(key, new Sound(clip));
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buf = new byte[8192];
int length;
while ((length = in.read(buf)) != -1) {
out.write(buf, 0, length);
}
sounds.put(key, new Sound(info, out.toByteArray(), format, fileFormat.getFrameLength()));

} catch (LineUnavailableException | UnsupportedAudioFileException | IOException e) {
} catch (UnsupportedAudioFileException | IOException e) {
CrashHandler.errorHandle(e, new CrashHandler.ErrorInfo("Audio Could not Load", CrashHandler.ErrorInfo.ErrorType.REPORT,
String.format("Could not load audio: %s in pack: %s", key, pack)));
}
}

/** Recommend {@link #play(String)} and {@link #loop(String, boolean)}. */
/** Recommend {@link #play(String)} and {@link #loop(String, int)}. */
@Nullable
public static Sound getSound(String key) {
return sounds.get(key);
Expand All @@ -95,27 +104,46 @@ public static void play(String key) {
if (sound != null) sound.play();
}

/** This method does safe check for {@link #loop(boolean)}. */
public static void loop(String key, boolean start) {
/** This method does safe check for {@link #loop(int)}. */
public static void loop(String key, int count) {
Sound sound = sounds.get(key);
if (sound != null) sound.loop(start);
if (sound != null) sound.loop(count);
}

public void play() {
if (!(boolean)Settings.get("sound") || clip == null) return;
@Nullable
private Clip createClip() {
try {
Clip clip = (Clip) AudioSystem.getLine(info); // Creates an audio clip to be played
clip.open(new AudioInputStream(new ByteArrayInputStream(raw), format, length));
clip.addLineListener(e -> {
if (e.getType() == LineEvent.Type.STOP) {
clip.flush();
clip.close();
}
});

if (clip.isRunning() || clip.isActive())
clip.stop();
return clip;
} catch (LineUnavailableException | IOException e) {
Logging.RESOURCEHANDLER_SOUND.error(e, "Unable to create Clip");
return null;
}
}

public void play() {
if (!(boolean)Settings.get("sound")) return;

clip.start();
Clip clip = createClip();
if (clip != null) {
clip.start();
}
}

public void loop(boolean start) {
if (!(boolean)Settings.get("sound") || clip == null) return;
public void loop(int count) {
if (!(boolean)Settings.get("sound")) return;

if (start)
clip.loop(Clip.LOOP_CONTINUOUSLY);
else
clip.stop();
Clip clip = createClip();
if (clip != null) {
clip.loop(count);
}
}
}