Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Smooth volume transition #187

Merged
merged 2 commits into from
Jun 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions platforms/common/src/main/java/dynamic_fps/impl/DynamicFPSMod.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import dynamic_fps.impl.util.Logging;
import dynamic_fps.impl.util.OptionsHolder;
import dynamic_fps.impl.util.Version;
import dynamic_fps.impl.util.SmoothVolumeHandler;
import dynamic_fps.impl.util.duck.DuckLoadingOverlay;
import dynamic_fps.impl.util.duck.DuckSoundEngine;
import dynamic_fps.impl.util.event.WindowObserver;
Expand Down Expand Up @@ -52,6 +53,7 @@ public class DynamicFPSMod {

public static void init() {
IdleHandler.init();
SmoothVolumeHandler.init();

Platform platform = Platform.getInstance();
Version version = platform.getModVersion(Constants.MOD_ID).orElseThrow();
Expand Down Expand Up @@ -97,6 +99,7 @@ public static void toggleDisabled() {
public static void onConfigChanged() {
modConfig.save();
IdleHandler.init();
SmoothVolumeHandler.init();
}

public static Screen getConfigScreen(Screen parent) {
Expand Down Expand Up @@ -159,6 +162,10 @@ public static float volumeMultiplier(SoundSource source) {
return config.volumeMultiplier(source);
}

public static DynamicFPSConfig.VolumeTransitionSpeed volumeTransitionSpeed() {
return modConfig.volumeTransitionSpeed();
}

public static boolean shouldShowToasts() {
return config.showToasts();
}
Expand Down Expand Up @@ -189,8 +196,11 @@ public static void handleStateChange(PowerState previous, PowerState current) {
System.gc();
}

for (SoundSource source : SoundSource.values()) {
((DuckSoundEngine) minecraft.getSoundManager().soundEngine).dynamic_fps$updateVolume(source);
// Update volume of current sounds for users not using smooth volume transition
if (!volumeTransitionSpeed().isActive()) {
for (SoundSource source : SoundSource.values()) {
((DuckSoundEngine) minecraft.getSoundManager().soundEngine).dynamic_fps$updateVolume(source);
}
}

if (before.graphicsState() != config.graphicsState()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,34 @@ public static Screen genConfigScreen(Screen parent) {
.build()
);

VariableStepTransformer volumeTransformer = getVolumeStepTransformer();

general.addEntry(
entryBuilder.startIntSlider(
localized("config", "volume_transition_speed_up"),
volumeTransformer.toStep((int) (DynamicFPSMod.volumeTransitionSpeed().getUp() * 10)),
1, 31
)
.setDefaultValue(volumeTransformer.toStep((int) (1.0f * 10)))
.setSaveConsumer(step -> DynamicFPSMod.volumeTransitionSpeed().setUp((float) volumeTransformer.toValue(step) / 10))
.setTextGetter(ClothConfig::volumeTransitionMessage)
.setTooltip(localized("config", "volume_transition_speed_tooltip"))
.build()
);

general.addEntry(
entryBuilder.startIntSlider(
localized("config", "volume_transition_speed_down"),
volumeTransformer.toStep((int) (DynamicFPSMod.volumeTransitionSpeed().getDown() * 10)),
1, 31
)
.setDefaultValue(volumeTransformer.toStep((int) (0.5f * 10)))
.setSaveConsumer(step -> DynamicFPSMod.volumeTransitionSpeed().setDown((float) volumeTransformer.toValue(step) / 10))
.setTextGetter(ClothConfig::volumeTransitionMessage)
.setTooltip(localized("config", "volume_transition_speed_tooltip"))
.build()
);

// Used for each state's frame rate target slider below
VariableStepTransformer fpsTransformer = getFpsTransformer();

Expand Down Expand Up @@ -169,6 +197,25 @@ private static Component idleTimeMessage(int value) {
}
}

private static VariableStepTransformer getVolumeStepTransformer() {
VariableStepTransformer transformer = new VariableStepTransformer();

transformer.addStep(1, 30);
transformer.addStep(970, 1000);

return transformer;
}

private static Component volumeTransitionMessage(int step) {
float value = (float) getVolumeStepTransformer().toValue(step) / 10;

if (value < 100.0f) {
return Component.literal(value + "%");
} else {
return localized("config", "volume_transition_speed_instant");
}
}

private static VariableStepTransformer getFpsTransformer() {
VariableStepTransformer transformer = new VariableStepTransformer();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,17 @@ public final class DynamicFPSConfig {
private int idleTime; // Seconds
private boolean detectIdleMovement;
private boolean uncapMenuFrameRate;
private VolumeTransitionSpeed volumeTransitionSpeed;

@SerializedName("states")
private final Map<PowerState, Config> configs;

private DynamicFPSConfig(boolean enabled, int abandonTime, boolean detectIdleMovement, boolean uncapMenuFrameRate, Map<PowerState, Config> configs) {
private DynamicFPSConfig(boolean enabled, int abandonTime, boolean detectIdleMovement, boolean uncapMenuFrameRate, VolumeTransitionSpeed volumeTransitionSpeed, Map<PowerState, Config> configs) {
this.enabled = enabled;
this.idleTime = abandonTime;
this.detectIdleMovement = detectIdleMovement;
this.uncapMenuFrameRate = uncapMenuFrameRate;
this.volumeTransitionSpeed = volumeTransitionSpeed;

this.configs = new EnumMap<>(configs);

Expand All @@ -36,6 +38,7 @@ public static DynamicFPSConfig createDefault() {
0,
true,
false,
new VolumeTransitionSpeed(1.0f, 0.5f),
new EnumMap<>(PowerState.class)
);

Expand Down Expand Up @@ -67,6 +70,10 @@ public void setIdleTime(int value) {
this.idleTime = value;
}

public VolumeTransitionSpeed volumeTransitionSpeed() {
return this.volumeTransitionSpeed;
}

public boolean detectIdleMovement() {
return this.detectIdleMovement;
}
Expand Down Expand Up @@ -96,4 +103,34 @@ public static DynamicFPSConfig load() {
public void save() {
Serialization.save(this);
}

public static class VolumeTransitionSpeed {
private float up;
private float down;

protected VolumeTransitionSpeed(float up, float down) {
this.up = up;
this.down = down;
}

public float getUp() {
return this.up;
}

public void setUp(float value) {
this.up = value;
}

public float getDown() {
return this.down;
}

public void setDown(float value) {
this.down = value;
}

public boolean isActive() {
return this.up != 100.0f || this.down != 100.0f;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ private static void upgradeConfig(JsonObject root) {
addUncapMenuFrameRate(root);
addEnabled(root);
addDetectIdleMovement(root);
addVolumeTransitionSpeed(root);
}

private static void addIdleTime(JsonObject root) {
Expand Down Expand Up @@ -181,6 +182,18 @@ private static void addDetectIdleMovement(JsonObject root) {
}
}

private static void addVolumeTransitionSpeed(JsonObject root) {
// Add volume_transition_speed object if it's missing
if (!root.has("volume_transition_speed")) {
JsonObject object = new JsonObject();

object.addProperty("up", 1.0f);
object.addProperty("down", 0.5f);

root.add("volume_transition_speed", object);
}
}

private static @Nullable JsonObject getStatesAsObject(JsonObject root) {
if (!root.has("states")) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.Map;

import dynamic_fps.impl.util.SmoothVolumeHandler;
import net.minecraft.client.Minecraft;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Final;
Expand All @@ -16,7 +17,6 @@
import com.llamalad7.mixinextras.sugar.Local;
import com.mojang.blaze3d.audio.Listener;

import dynamic_fps.impl.DynamicFPSMod;
import dynamic_fps.impl.util.duck.DuckSoundEngine;
import net.minecraft.client.Options;
import net.minecraft.client.resources.sounds.SoundInstance;
Expand Down Expand Up @@ -104,7 +104,7 @@ private float calculateVolume(SoundInstance instance) {
*/
@Inject(method = { "play", "playDelayed" }, at = @At("HEAD"), cancellable = true)
private void play(SoundInstance instance, CallbackInfo callbackInfo) {
if (DynamicFPSMod.volumeMultiplier(instance.getSource()) == 0.0f) {
if (SmoothVolumeHandler.volumeMultiplier(instance.getSource()) == 0.0f) {
callbackInfo.cancel();
}
}
Expand All @@ -125,6 +125,6 @@ private float adjustVolume(float value, @Nullable SoundSource source) {
source = SoundSource.MASTER;
}

return value * DynamicFPSMod.volumeMultiplier(source);
return value * SmoothVolumeHandler.volumeMultiplier(source);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package dynamic_fps.impl.util;

import dynamic_fps.impl.DynamicFPSMod;
import dynamic_fps.impl.service.Platform;
import dynamic_fps.impl.util.duck.DuckSoundEngine;
import net.minecraft.client.Minecraft;
import net.minecraft.sounds.SoundSource;

import java.util.HashMap;
import java.util.Map;

public class SmoothVolumeHandler {
private static boolean active = false;
private static final Minecraft minecraft = Minecraft.getInstance();
private static final Map<SoundSource, Float> currentOverrides = new HashMap<>();

public static void init() {
if (active || !DynamicFPSMod.volumeTransitionSpeed().isActive()) {
return;
}

active = true;
Platform.getInstance().registerStartTickEvent(SmoothVolumeHandler::tickVolumes);
}

public static float volumeMultiplier(SoundSource source) {
if (!active) {
return DynamicFPSMod.volumeMultiplier(source);
} else {
return currentOverrides.getOrDefault(source, 1.0f);
}
}

private static void tickVolumes() {
for (SoundSource source : SoundSource.values()) {
float desired = DynamicFPSMod.volumeMultiplier(source);
float current = currentOverrides.getOrDefault(source, 1.0f);

if (current != desired) {
if (current < desired) {
float up = DynamicFPSMod.volumeTransitionSpeed().getUp();
currentOverrides.put(source, Math.min(desired, current + up / 20.0f));
} else {
float down = DynamicFPSMod.volumeTransitionSpeed().getDown();
currentOverrides.put(source, Math.max(desired, current - down / 20.0f));
}

// Update volume of currently playing sounds
((DuckSoundEngine) minecraft.getSoundManager().soundEngine).dynamic_fps$updateVolume(source);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@
"config.dynamic_fps.uncap_menu_frame_rate": "Uncap Menu FPS",
"config.dynamic_fps.uncap_menu_frame_rate_tooltip": "Remove the 60 FPS limit in the main menu.",

"config.dynamic_fps.volume_transition_speed_up": "Upward Volume Transition Speed",
"config.dynamic_fps.volume_transition_speed_down": "Downward Volume Transition Speed",
"config.dynamic_fps.volume_transition_speed_instant": "Immediate",
"config.dynamic_fps.volume_transition_speed_tooltip": "Set the speed at which the game volume will be adjusted per second.",

"config.dynamic_fps.frame_rate_target": "Frame Rate Target",
"config.dynamic_fps.volume_multiplier": "Volume Multiplier",

Expand Down
1 change: 1 addition & 0 deletions platforms/fabric/src/main/resources/fabric.mod.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"LotuxPunk",
"Madis0",
"mpustovoi",
"N4TH4NOT",
"notlin4",
"parly",
"Pixaurora",
Expand Down
1 change: 1 addition & 0 deletions platforms/forge/src/main/resources/META-INF/mods.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Thanks to:
DenaryDev
dima-dencep
EuropaYou
N4TH4NOT
parly
Pixaurora
Setadokalo
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Thanks to:
DenaryDev
dima-dencep
EuropaYou
N4TH4NOT
parly
Pixaurora
Setadokalo
Expand Down
1 change: 1 addition & 0 deletions platforms/quilt/src/main/resources/quilt.mod.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"DenaryDev": "Contributor",
"dima-dencep": "Contributor",
"EuropaYou": ["Contributor", "Translator"],
"N4TH4NOT": "Contributor",
"parly": "Contributor",
"Pixaurora": ["Contributor" ,"Translator"],
"Setadokalo": "Contributor",
Expand Down