diff --git a/app/src/main/resources/audio/mainmenu.wav b/app/src/main/resources/audio/mainmenu.wav new file mode 100644 index 0000000..c0c3e25 Binary files /dev/null and b/app/src/main/resources/audio/mainmenu.wav differ diff --git a/app/src/main/resources/audio/hdchirp_88k_log.wav b/app/src/main/resources/audio/testsound.wav similarity index 100% rename from app/src/main/resources/audio/hdchirp_88k_log.wav rename to app/src/main/resources/audio/testsound.wav diff --git a/framework/src/main/java/org/toop/framework/audio/AudioFilesManager.java b/framework/src/main/java/org/toop/framework/audio/AudioFiles.java similarity index 59% rename from framework/src/main/java/org/toop/framework/audio/AudioFilesManager.java rename to framework/src/main/java/org/toop/framework/audio/AudioFiles.java index 3bf23a4..6a1af3a 100644 --- a/framework/src/main/java/org/toop/framework/audio/AudioFilesManager.java +++ b/framework/src/main/java/org/toop/framework/audio/AudioFiles.java @@ -1,21 +1,20 @@ package org.toop.framework.audio; import java.io.IOException; -import java.io.InvalidObjectException; import java.nio.file.*; import java.util.HashSet; import java.util.Set; -public class AudioFilesManager { +public class AudioFiles { private Set audioFiles; private String audioDirectory; - public AudioFilesManager(String audioDirectory) throws NotDirectoryException { + public AudioFiles(String audioDirectory) throws NotDirectoryException { if (!audioDirectory.endsWith("/") && !audioDirectory.endsWith("\\")) { throw new NotDirectoryException(audioDirectory); } - this.audioFiles = AudioFilesManager.getAllAudioFiles(audioDirectory); + this.audioFiles = AudioFiles.getAudioFiles(audioDirectory); this.audioDirectory = audioDirectory; } @@ -23,6 +22,10 @@ public class AudioFilesManager { return this.audioFiles; } + public String getAudioDirectory() { + return this.audioDirectory; + } + public String getAudioFile(String file) { if (!audioFiles.contains(file)) { return null; @@ -30,7 +33,24 @@ public class AudioFilesManager { return audioDirectory + file; } - private static Set getAllAudioFiles(String audioDirectory) { + public static String removeAllKeepOnlyName(String fileDirectoryNameExtension) { + String withoutExtensionAndDirectory = ""; + + int i = fileDirectoryNameExtension.lastIndexOf('.'); + if (i > 0) { + withoutExtensionAndDirectory = fileDirectoryNameExtension.substring(0, i); + } + int y = withoutExtensionAndDirectory.lastIndexOf("/"); + int k = withoutExtensionAndDirectory.lastIndexOf("\\"); + if (y > 0) { + withoutExtensionAndDirectory = withoutExtensionAndDirectory.substring(y+1); + } else if (k > 0) { + withoutExtensionAndDirectory = withoutExtensionAndDirectory.substring(k+1); + } + return withoutExtensionAndDirectory; + } + + private static Set getAudioFiles(String audioDirectory) { Set fileSet = new HashSet<>(); try (DirectoryStream stream = Files.newDirectoryStream(Paths.get(audioDirectory))) { for (Path path : stream) { diff --git a/framework/src/main/java/org/toop/framework/audio/AudioPlayer.java b/framework/src/main/java/org/toop/framework/audio/AudioPlayer.java deleted file mode 100644 index a022297..0000000 --- a/framework/src/main/java/org/toop/framework/audio/AudioPlayer.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.toop.framework.audio; - -public class AudioPlayer { - - - -} diff --git a/framework/src/main/java/org/toop/framework/audio/SoundManager.java b/framework/src/main/java/org/toop/framework/audio/SoundManager.java new file mode 100644 index 0000000..3ef9be4 --- /dev/null +++ b/framework/src/main/java/org/toop/framework/audio/SoundManager.java @@ -0,0 +1,132 @@ +package org.toop.framework.audio; + +import org.toop.framework.audio.events.AudioEvents; +import org.toop.framework.eventbus.EventFlow; + +import java.io.*; +import java.util.*; +import javax.sound.sampled.*; + +public class SoundManager { + private javax.sound.sampled.Line.Info lineInfo; + + private final Map activeClips = new HashMap<>(); + private HashMap clips = new HashMap<>(); + private AudioFiles audioFiles; + private Vector afs; + private Vector sizes; + private Vector infos; + private Vector audios; + private int num=0; + + public SoundManager(AudioFiles audioFiles) { + afs=new Vector(); + sizes=new Vector(); + infos=new Vector(); + audios=new Vector(); + this.audioFiles = audioFiles; + for (var file : audioFiles.getAudioFiles()) { + try { + addClip(audioFiles.getAudioDirectory() + file); + } catch (IOException e) { + throw new RuntimeException(e); + } catch (UnsupportedAudioFileException e) { + throw new RuntimeException(e); + } catch (LineUnavailableException e) { + throw new RuntimeException(e); + } + } + new EventFlow() + .listen(this::handlePlaySound) + .listen(this::handleStopSound); + } + + private void handlePlaySound(AudioEvents.PlayAudio event) { + try { + this.playSound(event.fileNameNoExtensionAndNoDirectory(), event.loop()); + } catch (UnsupportedAudioFileException e) { + throw new RuntimeException(e); + } catch (LineUnavailableException e) { + throw new RuntimeException(e); + } + } + + private void handleStopSound(AudioEvents.StopAudio event) { + this.stopSound(event.fileNameNoExtensionAndNoDirectory()); + } + + private void addClip(String s) + throws IOException, UnsupportedAudioFileException, LineUnavailableException { + AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(new File(s)); + AudioFormat af = audioInputStream.getFormat(); + int size = (int) (af.getFrameSize() * audioInputStream.getFrameLength()); + byte[] audio = new byte[size]; + DataLine.Info info = new DataLine.Info(Clip.class, af, size); + audioInputStream.read(audio, 0, size); + + afs.add(af); + sizes.add(new Integer(size)); + infos.add(info); + audios.add(audio); + this.clips.put(AudioFiles.removeAllKeepOnlyName(s), this.audios.size()-1); + + num++; + } + + private ByteArrayInputStream loadStream(InputStream inputstream) + throws IOException + { + ByteArrayOutputStream bytearrayoutputstream = new ByteArrayOutputStream(); + byte data[] = new byte[1024]; + for(int i = inputstream.read(data); i != -1; i = inputstream.read(data)) + bytearrayoutputstream.write(data, 0, i); + + inputstream.close(); + bytearrayoutputstream.close(); + data = bytearrayoutputstream.toByteArray(); + return new ByteArrayInputStream(data); + } + + private void playSound(String audioFileName, boolean loop) + throws UnsupportedAudioFileException, LineUnavailableException { + int x = clips.get(audioFileName); + if (x > num) { + System.out.println("playSound: sample nr[" + x + "] is not available"); + } else { + Clip clip = (Clip) AudioSystem.getLine((DataLine.Info) infos.elementAt(x)); + clip.open((AudioFormat) afs.elementAt(x), (byte[]) audios.elementAt(x), + 0, ((Integer) sizes.elementAt(x)).intValue()); + + clip.start(); + if (loop) clip.loop(Clip.LOOP_CONTINUOUSLY); + + // store it so we can stop it later + activeClips.put(audioFileName, clip); // TODO: Do on snowflake for specific sound to stop + + // remove when finished (only for non-looping sounds) + clip.addLineListener(event -> { + if (event.getType() == LineEvent.Type.STOP && !clip.isRunning()) { + activeClips.remove(audioFileName); + clip.close(); + } + }); + } + } + + public void stopSound(String audioFileName) { + Clip clip = activeClips.get(audioFileName); + if (clip != null) { + clip.stop(); + clip.close(); + activeClips.remove(audioFileName); + } + } + + public void stopAllSounds() { + for (Clip clip : activeClips.values()) { + clip.stop(); + clip.close(); + } + activeClips.clear(); + } +} diff --git a/framework/src/main/java/org/toop/framework/audio/events/AudioEvents.java b/framework/src/main/java/org/toop/framework/audio/events/AudioEvents.java new file mode 100644 index 0000000..56aaf64 --- /dev/null +++ b/framework/src/main/java/org/toop/framework/audio/events/AudioEvents.java @@ -0,0 +1,12 @@ +package org.toop.framework.audio.events; + +import org.toop.framework.eventbus.events.EventWithoutSnowflake; +import org.toop.framework.eventbus.events.EventsBase; + +public class AudioEvents extends EventsBase { + /** Starts playing a sound. */ + public record PlayAudio(String fileNameNoExtensionAndNoDirectory, boolean loop) + implements EventWithoutSnowflake {} + + public record StopAudio(String fileNameNoExtensionAndNoDirectory) implements EventWithoutSnowflake {} +}