diff --git a/app/src/main/java/org/toop/app/App.java b/app/src/main/java/org/toop/app/App.java
index 931bd2c..051cdfc 100644
--- a/app/src/main/java/org/toop/app/App.java
+++ b/app/src/main/java/org/toop/app/App.java
@@ -10,10 +10,12 @@ import javafx.scene.Scene;
import javafx.stage.Stage;
import org.toop.framework.asset.AssetManager;
import org.toop.framework.asset.resources.LocalizationAsset;
+import org.toop.framework.audio.SoundManager;
+import org.toop.framework.audio.events.AudioEvents;
+import org.toop.framework.eventbus.EventFlow;
import org.toop.local.AppContext;
import java.util.Locale;
-import java.util.ResourceBundle;
public class App extends Application {
private static Stage stage;
@@ -49,6 +51,9 @@ public class App extends Application {
App.stage = stage;
App.scene = scene;
App.root = root;
+
+ new EventFlow().addPostEvent(new AudioEvents.StartBackgroundMusic()).postEvent();
+ new EventFlow().addPostEvent(new AudioEvents.ChangeVolume(0.3)).postEvent();
}
public static void activate(Menu menu) {
diff --git a/app/src/main/resources/assets/audio/dramatic.wav b/app/src/main/resources/assets/audio/fx/dramatic.wav
similarity index 100%
rename from app/src/main/resources/assets/audio/dramatic.wav
rename to app/src/main/resources/assets/audio/fx/dramatic.wav
diff --git a/app/src/main/resources/assets/audio/hitsound0.wav b/app/src/main/resources/assets/audio/fx/hitsound0.wav
similarity index 100%
rename from app/src/main/resources/assets/audio/hitsound0.wav
rename to app/src/main/resources/assets/audio/fx/hitsound0.wav
diff --git a/app/src/main/resources/assets/audio/hitsound1.wav b/app/src/main/resources/assets/audio/fx/hitsound1.wav
similarity index 100%
rename from app/src/main/resources/assets/audio/hitsound1.wav
rename to app/src/main/resources/assets/audio/fx/hitsound1.wav
diff --git a/app/src/main/resources/assets/audio/mainmenu.wav b/app/src/main/resources/assets/audio/fx/mainmenu.wav
similarity index 100%
rename from app/src/main/resources/assets/audio/mainmenu.wav
rename to app/src/main/resources/assets/audio/fx/mainmenu.wav
diff --git a/app/src/main/resources/assets/audio/sadtrombone.wav b/app/src/main/resources/assets/audio/fx/sadtrombone.wav
similarity index 100%
rename from app/src/main/resources/assets/audio/sadtrombone.wav
rename to app/src/main/resources/assets/audio/fx/sadtrombone.wav
diff --git a/app/src/main/resources/assets/audio/scawymusic.wav b/app/src/main/resources/assets/audio/fx/scawymusic.wav
similarity index 100%
rename from app/src/main/resources/assets/audio/scawymusic.wav
rename to app/src/main/resources/assets/audio/fx/scawymusic.wav
diff --git a/app/src/main/resources/assets/audio/suspensful.wav b/app/src/main/resources/assets/audio/fx/suspensful.wav
similarity index 100%
rename from app/src/main/resources/assets/audio/suspensful.wav
rename to app/src/main/resources/assets/audio/fx/suspensful.wav
diff --git a/app/src/main/resources/assets/audio/testsound.wav b/app/src/main/resources/assets/audio/fx/testsound.wav
similarity index 100%
rename from app/src/main/resources/assets/audio/testsound.wav
rename to app/src/main/resources/assets/audio/fx/testsound.wav
diff --git a/app/src/main/resources/assets/audio/winsound.wav b/app/src/main/resources/assets/audio/fx/winsound.wav
similarity index 100%
rename from app/src/main/resources/assets/audio/winsound.wav
rename to app/src/main/resources/assets/audio/fx/winsound.wav
diff --git a/app/src/main/resources/assets/audio/music/damned.mp3 b/app/src/main/resources/assets/audio/music/damned.mp3
new file mode 100644
index 0000000..4b0bfbc
Binary files /dev/null and b/app/src/main/resources/assets/audio/music/damned.mp3 differ
diff --git a/app/src/main/resources/assets/audio/music/extraction-point.mp3 b/app/src/main/resources/assets/audio/music/extraction-point.mp3
new file mode 100644
index 0000000..1fc6430
Binary files /dev/null and b/app/src/main/resources/assets/audio/music/extraction-point.mp3 differ
diff --git a/framework/pom.xml b/framework/pom.xml
index 5e84787..b32b25c 100644
--- a/framework/pom.xml
+++ b/framework/pom.xml
@@ -102,6 +102,14 @@
25
+
+
+ org.openjfx
+ javafx-media
+ 25
+
+
+
org.reflections
@@ -122,24 +130,6 @@
25
25
UTF-8
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/framework/src/main/java/org/toop/framework/asset/AssetLoader.java b/framework/src/main/java/org/toop/framework/asset/AssetLoader.java
index dfcd1ac..bec2c97 100644
--- a/framework/src/main/java/org/toop/framework/asset/AssetLoader.java
+++ b/framework/src/main/java/org/toop/framework/asset/AssetLoader.java
@@ -242,4 +242,4 @@ public class AssetLoader {
int i = name.lastIndexOf('.');
return (i > 0) ? name.substring(i + 1) : "";
}
-}
+}
\ No newline at end of file
diff --git a/framework/src/main/java/org/toop/framework/asset/AssetManager.java b/framework/src/main/java/org/toop/framework/asset/AssetManager.java
index 1630ae0..f10d507 100644
--- a/framework/src/main/java/org/toop/framework/asset/AssetManager.java
+++ b/framework/src/main/java/org/toop/framework/asset/AssetManager.java
@@ -147,4 +147,4 @@ public class AssetManager {
public static void addAsset(Asset extends BaseResource> asset) {
assets.put(asset.getName(), asset);
}
-}
+}
\ No newline at end of file
diff --git a/framework/src/main/java/org/toop/framework/asset/resources/MusicAsset.java b/framework/src/main/java/org/toop/framework/asset/resources/MusicAsset.java
new file mode 100644
index 0000000..87c27f6
--- /dev/null
+++ b/framework/src/main/java/org/toop/framework/asset/resources/MusicAsset.java
@@ -0,0 +1,38 @@
+package org.toop.framework.asset.resources;
+
+import javafx.scene.media.Media;
+
+import java.io.*;
+
+@FileExtension({"mp3"})
+public class MusicAsset extends BaseResource implements LoadableResource {
+ private Media media;
+
+ public MusicAsset(final File audioFile) {
+ super(audioFile);
+ }
+
+ public Media getMedia() {
+ if (media == null) {
+ media = new Media(file.toURI().toString());
+ }
+ return media;
+ }
+
+ @Override
+ public void load() {
+ if (media == null) media = new Media(file.toURI().toString());
+ this.isLoaded = true;
+ }
+
+ @Override
+ public void unload() {
+ media = null;
+ isLoaded = false;
+ }
+
+ @Override
+ public boolean isLoaded() {
+ return isLoaded;
+ }
+}
\ No newline at end of file
diff --git a/framework/src/main/java/org/toop/framework/asset/resources/AudioAsset.java b/framework/src/main/java/org/toop/framework/asset/resources/SoundEffectAsset.java
similarity index 86%
rename from framework/src/main/java/org/toop/framework/asset/resources/AudioAsset.java
rename to framework/src/main/java/org/toop/framework/asset/resources/SoundEffectAsset.java
index 4b00212..c9c81a8 100644
--- a/framework/src/main/java/org/toop/framework/asset/resources/AudioAsset.java
+++ b/framework/src/main/java/org/toop/framework/asset/resources/SoundEffectAsset.java
@@ -1,12 +1,15 @@
package org.toop.framework.asset.resources;
+import javafx.scene.media.Media;
+
import javax.sound.sampled.*;
import java.io.*;
+import java.net.URI;
@FileExtension({"wav"})
-public class AudioAsset extends BaseResource implements LoadableResource {
+public class SoundEffectAsset extends BaseResource implements LoadableResource {
- public AudioAsset(final File audioFile) {
+ public SoundEffectAsset(final File audioFile) {
super(audioFile);
}
diff --git a/framework/src/main/java/org/toop/framework/audio/SoundManager.java b/framework/src/main/java/org/toop/framework/audio/SoundManager.java
index d870662..0dc1f72 100644
--- a/framework/src/main/java/org/toop/framework/audio/SoundManager.java
+++ b/framework/src/main/java/org/toop/framework/audio/SoundManager.java
@@ -1,9 +1,12 @@
package org.toop.framework.audio;
+import javafx.application.Platform;
+import javafx.scene.media.MediaPlayer;
import org.toop.framework.SnowflakeGenerator;
import org.toop.framework.asset.Asset;
import org.toop.framework.asset.AssetManager;
-import org.toop.framework.asset.resources.AudioAsset;
+import org.toop.framework.asset.resources.MusicAsset;
+import org.toop.framework.asset.resources.SoundEffectAsset;
import org.toop.framework.audio.events.AudioEvents;
import org.toop.framework.eventbus.EventFlow;
@@ -12,13 +15,17 @@ import java.util.*;
import javax.sound.sampled.*;
public class SoundManager {
- private final Map activeClips = new HashMap<>();
- private final HashMap audioResources = new HashMap<>();
+ private final List activeMusic = new ArrayList<>();
+ private final Queue backgroundMusicQueue = new LinkedList<>();
+ private final Map activeSoundEffects = new HashMap<>();
+ private final HashMap audioResources = new HashMap<>();
private final SnowflakeGenerator idGenerator = new SnowflakeGenerator(); // TODO: Don't create a new generator
+ private double volume = 1.0;
+
public SoundManager() {
// Get all Audio Resources and add them to a list.
- for (Asset asset : AssetManager.getAllOfType(AudioAsset.class)) {
+ for (Asset asset : AssetManager.getAllOfType(SoundEffectAsset.class)) {
try {
this.addAudioResource(asset);
} catch (IOException | LineUnavailableException | UnsupportedAudioFileException e) {
@@ -27,7 +34,9 @@ public class SoundManager {
}
new EventFlow()
.listen(this::handlePlaySound)
- .listen(this::handleStopSound);
+ .listen(this::handleStopSound)
+ .listen(this::handleMusicStart)
+ .listen(this::handleVolumeChange);
}
private void handlePlaySound(AudioEvents.PlayAudio event) {
@@ -42,14 +51,70 @@ public class SoundManager {
this.stopSound(event.clipId());
}
- private void addAudioResource(Asset audioAsset)
+ private void addAudioResource(Asset audioAsset)
throws IOException, UnsupportedAudioFileException, LineUnavailableException {
this.audioResources.put(audioAsset.getName(), audioAsset.getResource());
}
+ private void handleVolumeChange(AudioEvents.ChangeVolume event) {
+ if (event.newVolume() > 1.0) this.volume = 1.0;
+ else this.volume = Math.max(event.newVolume(), 0.0);
+ for (MediaPlayer mediaPlayer : this.activeMusic) {
+ mediaPlayer.setVolume(this.volume);
+ }
+ }
+
+ private void handleMusicStart(AudioEvents.StartBackgroundMusic e) {
+ backgroundMusicQueue.clear();
+ Platform.runLater(() -> {
+ backgroundMusicQueue.addAll(
+ AssetManager.getAllOfType(MusicAsset.class).stream()
+ .map(Asset::getResource)
+ .toList()
+ );
+ backgroundMusicPlayer();
+ });
+
+ }
+
+ private void addBackgroundMusic(MusicAsset musicAsset) {
+ backgroundMusicQueue.add(musicAsset);
+ }
+
+ private void backgroundMusicPlayer() {
+ MusicAsset ma = backgroundMusicQueue.poll();
+ if (ma == null) return;
+
+ MediaPlayer mediaPlayer = new MediaPlayer(ma.getMedia());
+
+ mediaPlayer.setOnEndOfMedia(() -> {
+ addBackgroundMusic(ma);
+ activeMusic.remove(mediaPlayer);
+ mediaPlayer.dispose();
+ ma.unload();
+ backgroundMusicPlayer(); // play next
+ });
+
+ mediaPlayer.setOnStopped(() -> {
+ addBackgroundMusic(ma);
+ activeMusic.remove(mediaPlayer);
+ ma.unload();
+ });
+
+ mediaPlayer.setOnError(() -> {
+ addBackgroundMusic(ma);
+ activeMusic.remove(mediaPlayer);
+ ma.unload();
+ });
+
+ mediaPlayer.setVolume(this.volume);
+ mediaPlayer.play();
+ activeMusic.add(mediaPlayer);
+ }
+
private long playSound(String audioFileName, boolean loop) throws UnsupportedAudioFileException, LineUnavailableException, IOException {
- AudioAsset asset = audioResources.get(audioFileName);
+ SoundEffectAsset asset = audioResources.get(audioFileName);
// Return -1 which indicates resource wasn't available
if (asset == null){
@@ -71,12 +136,12 @@ public class SoundManager {
long clipId = idGenerator.nextId();
// store it so we can stop it later
- activeClips.put(clipId, clip); // TODO: Do on snowflake for specific sound to stop
+ activeSoundEffects.put(clipId, 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(clipId);
+ activeSoundEffects.remove(clipId);
clip.close();
}
});
@@ -86,7 +151,7 @@ public class SoundManager {
}
public void stopSound(long clipId) {
- Clip clip = activeClips.get(clipId);
+ Clip clip = activeSoundEffects.get(clipId);
if (clip == null) {
return;
@@ -94,14 +159,14 @@ public class SoundManager {
clip.stop();
clip.close();
- activeClips.remove(clipId);
+ activeSoundEffects.remove(clipId);
}
public void stopAllSounds() {
- for (Clip clip : activeClips.values()) {
+ for (Clip clip : activeSoundEffects.values()) {
clip.stop();
clip.close();
}
- activeClips.clear();
+ activeSoundEffects.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
index 0f0e158..d7eecbb 100644
--- a/framework/src/main/java/org/toop/framework/audio/events/AudioEvents.java
+++ b/framework/src/main/java/org/toop/framework/audio/events/AudioEvents.java
@@ -1,5 +1,6 @@
package org.toop.framework.audio.events;
+import org.toop.framework.asset.resources.MusicAsset;
import org.toop.framework.eventbus.events.EventWithoutSnowflake;
import org.toop.framework.eventbus.events.EventsBase;
@@ -9,4 +10,8 @@ public class AudioEvents extends EventsBase {
implements EventWithoutSnowflake {}
public record StopAudio(long clipId) implements EventWithoutSnowflake {}
+
+ public record StartBackgroundMusic() implements EventWithoutSnowflake {}
+ public record ChangeVolume(double newVolume) implements EventWithoutSnowflake {}
+
}