mirror of
https://github.com/2OOP/pism.git
synced 2026-02-04 19:04:49 +00:00
Renamed VolumeTypes to VolumeControl. Made it thread safe. Added docs to VolumeControl and co.
removed .updateAllVolumes() in favor of auto updating inside enum instead
This commit is contained in:
@@ -57,25 +57,22 @@ public class AudioEventListener<T extends AudioResource, K extends AudioResource
|
||||
}
|
||||
|
||||
private void handleVolumeChange(AudioEvents.ChangeVolume event) {
|
||||
this.audioVolumeManager.setVolume(event.newVolume() / 100, VolumeTypes.MASTERVOLUME);
|
||||
this.audioVolumeManager.updateAllVolumes();
|
||||
this.audioVolumeManager.setVolume(event.newVolume() / 100, VolumeControl.MASTERVOLUME);
|
||||
}
|
||||
|
||||
private void handleFxVolumeChange(AudioEvents.ChangeFxVolume event) {
|
||||
this.audioVolumeManager.setVolume(event.newVolume() / 100, VolumeTypes.FX);
|
||||
this.audioVolumeManager.updateAllVolumes();
|
||||
this.audioVolumeManager.setVolume(event.newVolume() / 100, VolumeControl.FX);
|
||||
}
|
||||
|
||||
private void handleMusicVolumeChange(AudioEvents.ChangeMusicVolume event) {
|
||||
this.audioVolumeManager.setVolume(event.newVolume() / 100, VolumeTypes.MUSIC);
|
||||
this.audioVolumeManager.updateAllVolumes();
|
||||
this.audioVolumeManager.setVolume(event.newVolume() / 100, VolumeControl.MUSIC);
|
||||
}
|
||||
|
||||
private void handleGetVolume(AudioEvents.GetCurrentVolume event) {
|
||||
new EventFlow()
|
||||
.addPostEvent(
|
||||
new AudioEvents.GetCurrentVolumeResponse(
|
||||
audioVolumeManager.getVolume(VolumeTypes.MASTERVOLUME),
|
||||
audioVolumeManager.getVolume(VolumeControl.MASTERVOLUME),
|
||||
event.snowflakeId()))
|
||||
.asyncPostEvent();
|
||||
}
|
||||
@@ -84,7 +81,7 @@ public class AudioEventListener<T extends AudioResource, K extends AudioResource
|
||||
new EventFlow()
|
||||
.addPostEvent(
|
||||
new AudioEvents.GetCurrentFxVolumeResponse(
|
||||
audioVolumeManager.getVolume(VolumeTypes.FX),
|
||||
audioVolumeManager.getVolume(VolumeControl.FX),
|
||||
event.snowflakeId()))
|
||||
.asyncPostEvent();
|
||||
}
|
||||
@@ -93,7 +90,7 @@ public class AudioEventListener<T extends AudioResource, K extends AudioResource
|
||||
new EventFlow()
|
||||
.addPostEvent(
|
||||
new AudioEvents.GetCurrentMusicVolumeResponse(
|
||||
audioVolumeManager.getVolume(VolumeTypes.MUSIC),
|
||||
audioVolumeManager.getVolume(VolumeControl.MUSIC),
|
||||
event.snowflakeId()))
|
||||
.asyncPostEvent();
|
||||
}
|
||||
|
||||
@@ -4,32 +4,81 @@ import org.toop.framework.audio.interfaces.AudioManager;
|
||||
import org.toop.framework.audio.interfaces.VolumeManager;
|
||||
import org.toop.framework.resource.types.AudioResource;
|
||||
|
||||
/**
|
||||
* Concrete implementation of {@link VolumeManager} that delegates volume control
|
||||
* to the {@link VolumeControl} enum.
|
||||
* <p>
|
||||
* 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.
|
||||
* </p>
|
||||
*
|
||||
* <p>Key responsibilities:</p>
|
||||
* <ul>
|
||||
* <li>Set and get volume levels for each {@link VolumeControl} category.</li>
|
||||
* <li>Register {@link AudioManager} instances to specific volume types so
|
||||
* that their active audio resources receive volume updates automatically.</li>
|
||||
* <li>Automatically scales non-master volumes according to the current master volume.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>Example usage:</p>
|
||||
* <pre>{@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);
|
||||
* }</pre>
|
||||
*/
|
||||
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.
|
||||
* <p>
|
||||
* 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<? extends AudioResource> manager) {
|
||||
/**
|
||||
* Registers an {@link AudioManager} with the specified {@link VolumeControl} category.
|
||||
* <p>
|
||||
* 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<? extends AudioResource> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
* <p>
|
||||
* 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).
|
||||
* </p>
|
||||
*
|
||||
* <p>Volume types:</p>
|
||||
* <ul>
|
||||
* <li>{@link #MASTERVOLUME}: The global/master volume that scales all other volume types.</li>
|
||||
* <li>{@link #FX}: Volume for sound effects, scaled by the master volume.</li>
|
||||
* <li>{@link #MUSIC}: Volume for music tracks, scaled by the master volume.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>Key features:</p>
|
||||
* <ul>
|
||||
* <li>Thread-safe management of audio managers using {@link CopyOnWriteArrayList}.</li>
|
||||
* <li>Automatic propagation of master volume changes to dependent volume types.</li>
|
||||
* <li>Clamping volume values between 0.0 and 1.0 to ensure valid audio levels.</li>
|
||||
* <li>Dynamic registration and removal of audio managers for each volume type.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>Example usage:</p>
|
||||
* <pre>{@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();
|
||||
* }</pre>
|
||||
*/
|
||||
public enum VolumeControl {
|
||||
MASTERVOLUME(),
|
||||
FX(),
|
||||
MUSIC();
|
||||
|
||||
private final List<AudioManager<? extends AudioResource>> managers = new CopyOnWriteArrayList<>();
|
||||
private double volume = 1.0;
|
||||
private double masterVolume = 1.0;
|
||||
|
||||
/**
|
||||
* Sets the volume for this volume type.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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<? extends AudioResource> 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<? extends AudioResource> 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<AudioManager<? extends AudioResource>> getManagers() {
|
||||
return Collections.unmodifiableList(managers);
|
||||
}
|
||||
}
|
||||
@@ -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<AudioManager<? extends AudioResource>> 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<? extends AudioResource> manager) {
|
||||
if (manager != null && !managers.contains(manager)) {
|
||||
managers.add(manager);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeManager(AudioManager<? extends AudioResource> manager) {
|
||||
if (manager != null) {
|
||||
managers.remove(manager);
|
||||
}
|
||||
}
|
||||
|
||||
public List<AudioManager<? extends AudioResource>> getManagers() {
|
||||
return Collections.unmodifiableList(managers);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
package org.toop.framework.audio.interfaces;
|
||||
|
||||
import org.toop.framework.audio.VolumeTypes;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public interface AudioManager<T> {
|
||||
|
||||
@@ -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.
|
||||
* <p>
|
||||
* 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.
|
||||
* </p>
|
||||
*
|
||||
* <p>Typical responsibilities include:</p>
|
||||
* <ul>
|
||||
* <li>Setting the volume for a specific category (master, music, FX).</li>
|
||||
* <li>Retrieving the current volume of a category.</li>
|
||||
* <li>Ensuring that changes in master volume propagate to dependent audio categories.</li>
|
||||
* <li>Interfacing with {@link org.toop.framework.audio.interfaces.AudioManager} to update active audio resources.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>Example usage:</p>
|
||||
* <pre>{@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);
|
||||
* }</pre>
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user