diff --git a/app/src/main/java/org/toop/Main.java b/app/src/main/java/org/toop/Main.java index 636565c..ce1b23d 100644 --- a/app/src/main/java/org/toop/Main.java +++ b/app/src/main/java/org/toop/Main.java @@ -2,7 +2,6 @@ package org.toop; import org.toop.app.App; import org.toop.framework.audio.*; -import org.toop.framework.audio.interfaces.VolumeManager; import org.toop.framework.networking.NetworkingClientManager; import org.toop.framework.networking.NetworkingInitializationException; import org.toop.framework.resource.ResourceLoader; @@ -25,10 +24,10 @@ public final class Main { musicManager, soundEffectManager, new AudioVolumeManager() - .registerManager(VolumeTypes.MASTERVOLUME, musicManager) - .registerManager(VolumeTypes.MASTERVOLUME, soundEffectManager) - .registerManager(VolumeTypes.FX, soundEffectManager) - .registerManager(VolumeTypes.MUSIC, musicManager) + .registerManager(VolumeControl.MASTERVOLUME, musicManager) + .registerManager(VolumeControl.MASTERVOLUME, soundEffectManager) + .registerManager(VolumeControl.FX, soundEffectManager) + .registerManager(VolumeControl.MUSIC, musicManager) ).initListeners(); }).start(); } diff --git a/framework/src/main/java/org/toop/framework/audio/AudioEventListener.java b/framework/src/main/java/org/toop/framework/audio/AudioEventListener.java index 86cda08..2f56052 100644 --- a/framework/src/main/java/org/toop/framework/audio/AudioEventListener.java +++ b/framework/src/main/java/org/toop/framework/audio/AudioEventListener.java @@ -57,25 +57,22 @@ public class AudioEventListener + * This class acts as a central point for updating volume levels for different + * audio categories (MASTER, FX, MUSIC) and for registering audio managers + * to the appropriate volume types. + *

+ * + *

Key responsibilities:

+ * + * + *

Example usage:

+ *
{@code
+ * AudioVolumeManager volumeManager = new AudioVolumeManager();
+ *
+ * // Register music manager to MUSIC volume type
+ * volumeManager.registerManager(VolumeControl.MUSIC, musicManager);
+ *
+ * // Set master volume to 80%
+ * volumeManager.setVolume(0.8, VolumeControl.MASTERVOLUME);
+ *
+ * // Set FX volume to 50% of master
+ * volumeManager.setVolume(0.5, VolumeControl.FX);
+ *
+ * // Retrieve current MUSIC volume
+ * double musicVol = volumeManager.getVolume(VolumeControl.MUSIC);
+ * }
+ */ public class AudioVolumeManager implements VolumeManager { - public void setVolume(double newVolume, VolumeTypes type) { - type.setVolume(newVolume, VolumeTypes.MASTERVOLUME.getVolume()); + /** + * Sets the volume for a specific volume type. + *

+ * This method automatically takes into account the master volume + * for non-master types. + * + * @param newVolume the desired volume level (0.0 to 1.0) + * @param type the {@link VolumeControl} category to update + */ + @Override + public void setVolume(double newVolume, VolumeControl type) { + type.setVolume(newVolume, VolumeControl.MASTERVOLUME.getVolume()); } - public double getVolume(VolumeTypes type) { + /** + * Returns the current volume for the specified {@link VolumeControl} category. + * + * @param type the volume category + * @return the current volume (0.0 to 1.0) + */ + @Override + public double getVolume(VolumeControl type) { return type.getVolume(); } - public AudioVolumeManager registerManager(VolumeTypes type, AudioManager manager) { + /** + * Registers an {@link AudioManager} with the specified {@link VolumeControl} category. + *

+ * All active audio resources managed by the given {@link AudioManager} will + * automatically receive volume updates when the volume type changes. + * + * @param type the volume type to register the manager under + * @param manager the audio manager to register + * @return the current {@link AudioVolumeManager} instance (for method chaining) + */ + public AudioVolumeManager registerManager(VolumeControl type, AudioManager manager) { if (manager != null) { type.addManager(manager); } - return AudioVolumeManager.this; + return this; } - - @Override - public void updateAllVolumes() { - double masterVolume = VolumeTypes.MASTERVOLUME.getVolume(); - - for (VolumeTypes type : VolumeTypes.values()) { - if (type != VolumeTypes.MASTERVOLUME) { // skip master itself - type.setVolume(type.getVolume(), masterVolume); - } - } - } - -} \ No newline at end of file +} diff --git a/framework/src/main/java/org/toop/framework/audio/VolumeControl.java b/framework/src/main/java/org/toop/framework/audio/VolumeControl.java new file mode 100644 index 0000000..697ef76 --- /dev/null +++ b/framework/src/main/java/org/toop/framework/audio/VolumeControl.java @@ -0,0 +1,159 @@ +package org.toop.framework.audio; + +import org.toop.framework.audio.interfaces.AudioManager; +import org.toop.framework.resource.types.AudioResource; + +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * Enum representing different categories of audio volume in the application. + *

+ * Each volume type maintains its own volume level and a list of {@link AudioManager}s + * that manage audio resources of that type. The enum provides methods to set, get, + * and propagate volume changes, including master volume adjustments that automatically + * update dependent volume types (FX and MUSIC). + *

+ * + *

Volume types:

+ * + * + *

Key features:

+ * + * + *

Example usage:

+ *
{@code
+ * // Add a music manager to the MUSIC volume type
+ * VolumeControl.MUSIC.addManager(musicManager);
+ *
+ * // Set master volume to 80%
+ * VolumeControl.MASTERVOLUME.setVolume(0.8, 0);
+ *
+ * // Set FX volume to 50% of master
+ * VolumeControl.FX.setVolume(0.5, VolumeControl.MASTERVOLUME.getVolume());
+ *
+ * // Retrieve current music volume
+ * double musicVol = VolumeControl.MUSIC.getVolume();
+ * }
+ */ +public enum VolumeControl { + MASTERVOLUME(), + FX(), + MUSIC(); + + private final List> managers = new CopyOnWriteArrayList<>(); + private double volume = 1.0; + private double masterVolume = 1.0; + + /** + * Sets the volume for this volume type. + *

+ * If this type is {@link #MASTERVOLUME}, all dependent volume types + * (FX, MUSIC, etc.) are automatically updated to reflect the new master volume. + * Otherwise, the volume is scaled by the provided master volume. + * + * @param newVolume the new volume level (0.0 to 1.0) + * @param currentMasterVolume the current master volume for scaling non-master types + */ + public void setVolume(double newVolume, double currentMasterVolume) { + this.volume = clamp(newVolume); + + if (this == MASTERVOLUME) { + for (VolumeControl type : VolumeControl.values()) { + if (type != MASTERVOLUME) { + type.masterVolume = this.volume; + type.broadcastVolume(type.computeEffectiveVolume()); + } + } + } else { + this.masterVolume = clamp(currentMasterVolume); + broadcastVolume(computeEffectiveVolume()); + } + } + + /** + * Computes the effective volume for this type, taking into account + * the master volume if this is not {@link #MASTERVOLUME}. + * + * @return the effective volume (0.0 to 1.0) + */ + private double computeEffectiveVolume() { + return (this == MASTERVOLUME) ? volume : volume * masterVolume; + } + + /** + * Updates all registered audio managers with the given effective volume. + * + * @param effectiveVolume the volume to apply to all active audio resources + */ + private void broadcastVolume(double effectiveVolume) { + managers.stream() + .filter(Objects::nonNull) + .forEach(manager -> manager.getActiveAudio() + .forEach(aud -> aud.updateVolume(effectiveVolume))); + } + + /** + * Clamps a volume value to the valid range [0.0, 1.0]. + * + * @param vol the volume to clamp + * @return the clamped volume + */ + private double clamp(double vol) { + return Math.max(0, Math.min(vol, 1.0)); + } + + /** + * Gets the current volume for this type. + * + * @return the current volume (0.0 to 1.0) + */ + public double getVolume() { + return volume; + } + + /** + * Registers an {@link AudioManager} to this volume type. + *

+ * Duplicate managers are ignored. Managers will receive volume updates + * when this type's volume changes. + * + * @param manager the audio manager to register + */ + public void addManager(AudioManager manager) { + if (manager != null && !managers.contains(manager)) { + managers.add(manager); + } + } + + /** + * Removes a previously registered {@link AudioManager} from this type. + * + * @param manager the audio manager to remove + */ + public void removeManager(AudioManager manager) { + if (manager != null) { + managers.remove(manager); + } + } + + /** + * Returns an unmodifiable view of all registered audio managers for this type. + * + * @return a list of registered audio managers + */ + public List> getManagers() { + return Collections.unmodifiableList(managers); + } +} \ No newline at end of file diff --git a/framework/src/main/java/org/toop/framework/audio/VolumeTypes.java b/framework/src/main/java/org/toop/framework/audio/VolumeTypes.java deleted file mode 100644 index 1e02c61..0000000 --- a/framework/src/main/java/org/toop/framework/audio/VolumeTypes.java +++ /dev/null @@ -1,65 +0,0 @@ -package org.toop.framework.audio; - -import org.toop.framework.audio.interfaces.AudioManager; -import org.toop.framework.resource.types.AudioResource; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Objects; - -public enum VolumeTypes { - MASTERVOLUME(), - FX(), - MUSIC(); - - private final List> managers = new ArrayList<>(); - private double volume = 1.0; - private double masterVolume = 1.0; - - public void setVolume(double newVolume, double currentMasterVolume) { - this.volume = clamp(newVolume); - - if (this != MASTERVOLUME) { - this.masterVolume = clamp(currentMasterVolume); - } - - double effectiveVolume = computeEffectiveVolume(); - broadcastVolume(effectiveVolume); - } - - private double computeEffectiveVolume() { - return (this == MASTERVOLUME) ? volume : volume * masterVolume; - } - - private void broadcastVolume(double effectiveVolume) { - managers.stream() - .filter(Objects::nonNull) - .forEach(manager -> manager.getActiveAudio() - .forEach(aud -> aud.updateVolume(effectiveVolume))); - } - - private double clamp(double vol) { - return Math.max(0, Math.min(vol, 1.0)); - } - - public double getVolume() { - return volume; - } - - public void addManager(AudioManager manager) { - if (manager != null && !managers.contains(manager)) { - managers.add(manager); - } - } - - public void removeManager(AudioManager manager) { - if (manager != null) { - managers.remove(manager); - } - } - - public List> getManagers() { - return Collections.unmodifiableList(managers); - } -} \ No newline at end of file diff --git a/framework/src/main/java/org/toop/framework/audio/interfaces/AudioManager.java b/framework/src/main/java/org/toop/framework/audio/interfaces/AudioManager.java index 9849074..9ba7777 100644 --- a/framework/src/main/java/org/toop/framework/audio/interfaces/AudioManager.java +++ b/framework/src/main/java/org/toop/framework/audio/interfaces/AudioManager.java @@ -1,7 +1,5 @@ package org.toop.framework.audio.interfaces; -import org.toop.framework.audio.VolumeTypes; - import java.util.Collection; public interface AudioManager { diff --git a/framework/src/main/java/org/toop/framework/audio/interfaces/VolumeManager.java b/framework/src/main/java/org/toop/framework/audio/interfaces/VolumeManager.java index fdc4bdd..d5e03ab 100644 --- a/framework/src/main/java/org/toop/framework/audio/interfaces/VolumeManager.java +++ b/framework/src/main/java/org/toop/framework/audio/interfaces/VolumeManager.java @@ -1,10 +1,53 @@ package org.toop.framework.audio.interfaces; -import org.toop.framework.audio.VolumeTypes; -import org.toop.framework.resource.types.AudioResource; +import org.toop.framework.audio.VolumeControl; + +/** + * Interface for managing audio volumes in the application. + *

+ * Implementations of this interface are responsible for controlling the volume levels + * of different categories of audio (e.g., master volume, music, sound effects) and + * updating the associated audio managers or resources accordingly. + *

+ * + *

Typical responsibilities include:

+ * + * + *

Example usage:

+ *
{@code
+ * VolumeManager volumeManager = ...;
+ * // Set master volume to 80%
+ * volumeManager.setVolume(0.8, VolumeControl.MASTERVOLUME);
+ *
+ * // Set music volume to 50% of master
+ * volumeManager.setVolume(0.5, VolumeControl.MUSIC);
+ *
+ * // Retrieve current FX volume
+ * double fxVolume = volumeManager.getVolume(VolumeControl.FX);
+ * }
+ */ public interface VolumeManager { - void setVolume(double newVolume, VolumeTypes type); - double getVolume(VolumeTypes type); - void updateAllVolumes(); + + /** + * + * Sets the volume to for the specified {@link VolumeControl}. + * + * @param newVolume The volume to be set to. + * @param type The type of volume to change. + */ + void setVolume(double newVolume, VolumeControl type); + + /** + * Gets the current volume for the specified {@link VolumeControl}. + * + * @param type the type of volume to get. + * @return The volume as a {@link Double} + */ + double getVolume(VolumeControl type); }