Working audio system with events.

This commit is contained in:
Bas de Jong
2025-09-29 13:45:28 +02:00
committed by Bas Antonius de Jong
parent a957195514
commit 9131803044
6 changed files with 169 additions and 12 deletions

Binary file not shown.

View File

@@ -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<String> 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<String> 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<String> getAudioFiles(String audioDirectory) {
Set<String> fileSet = new HashSet<>();
try (DirectoryStream<Path> stream = Files.newDirectoryStream(Paths.get(audioDirectory))) {
for (Path path : stream) {

View File

@@ -1,7 +0,0 @@
package org.toop.framework.audio;
public class AudioPlayer {
}

View File

@@ -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<String, Clip> activeClips = new HashMap<>();
private HashMap<String, Integer> 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();
}
}

View File

@@ -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 {}
}