From 074da9069cbe7efbbfb1c4113c425e36ede2516a Mon Sep 17 00:00:00 2001 From: Ly-sec Date: Wed, 19 Nov 2025 23:27:42 +0100 Subject: [PATCH] OSD: add overdrive display Volume/Microphone: allow overdrive, clamp to 100/150% max AudioService: properly clamp to 100/150% (not only visually) --- Modules/Bar/Widgets/Microphone.qml | 12 +++++++-- Modules/Bar/Widgets/Volume.qml | 12 +++++++-- Modules/OSD/OSD.qml | 16 +++++++++++- Services/Media/AudioService.qml | 40 ++++++++++++++++++++++++++++++ 4 files changed, 75 insertions(+), 5 deletions(-) diff --git a/Modules/Bar/Widgets/Microphone.qml b/Modules/Bar/Widgets/Microphone.qml index bdde4392..232c170b 100644 --- a/Modules/Bar/Widgets/Microphone.qml +++ b/Modules/Bar/Widgets/Microphone.qml @@ -134,12 +134,20 @@ Item { icon: AudioService.getInputIcon() density: Settings.data.bar.density autoHide: false // Important to be false so we can hover as long as we want - text: Math.round(AudioService.inputVolume * 100) + text: { + const maxVolume = Settings.data.audio.volumeOverdrive ? 1.5 : 1.0; + const displayVolume = Math.min(maxVolume, AudioService.inputVolume); + return Math.round(displayVolume * 100); + } suffix: "%" forceOpen: displayMode === "alwaysShow" forceClose: displayMode === "alwaysHide" tooltipText: I18n.tr("tooltips.microphone-volume-at", { - "volume": Math.round(AudioService.inputVolume * 100) + "volume": (() => { + const maxVolume = Settings.data.audio.volumeOverdrive ? 1.5 : 1.0; + const displayVolume = Math.min(maxVolume, AudioService.inputVolume); + return Math.round(displayVolume * 100); + })() }) onWheel: function (delta) { diff --git a/Modules/Bar/Widgets/Volume.qml b/Modules/Bar/Widgets/Volume.qml index 796545eb..37faf7dd 100644 --- a/Modules/Bar/Widgets/Volume.qml +++ b/Modules/Bar/Widgets/Volume.qml @@ -117,12 +117,20 @@ Item { oppositeDirection: BarService.getPillDirection(root) icon: AudioService.getOutputIcon() autoHide: false // Important to be false so we can hover as long as we want - text: Math.round(AudioService.volume * 100) + text: { + const maxVolume = Settings.data.audio.volumeOverdrive ? 1.5 : 1.0; + const displayVolume = Math.min(maxVolume, AudioService.volume); + return Math.round(displayVolume * 100); + } suffix: "%" forceOpen: displayMode === "alwaysShow" forceClose: displayMode === "alwaysHide" tooltipText: I18n.tr("tooltips.volume-at", { - "volume": Math.round(AudioService.volume * 100) + "volume": (() => { + const maxVolume = Settings.data.audio.volumeOverdrive ? 1.5 : 1.0; + const displayVolume = Math.min(maxVolume, AudioService.volume); + return Math.round(displayVolume * 100); + })() }) onWheel: function (delta) { diff --git a/Modules/OSD/OSD.qml b/Modules/OSD/OSD.qml index aee09c94..9edf188a 100644 --- a/Modules/OSD/OSD.qml +++ b/Modules/OSD/OSD.qml @@ -73,13 +73,27 @@ Variants { function getDisplayPercentage() { const value = getCurrentValue(); const max = getMaxValue(); + if ((currentOSDType === "volume" || currentOSDType === "inputVolume") && Settings.data.audio.volumeOverdrive) { + const pct = Math.round(value * 100); + return pct + "%"; + } const pct = Math.round(Math.min(max, value) * 100); return pct + "%"; } function getProgressColor() { const isMutedState = (currentOSDType === "volume" && isMuted) || (currentOSDType === "inputVolume" && isInputMuted); - return isMutedState ? Color.mError : Color.mPrimary; + if (isMutedState) { + return Color.mError; + } + // When volumeOverdrive is enabled, show error color if volume is above 100% + if ((currentOSDType === "volume" || currentOSDType === "inputVolume") && Settings.data.audio.volumeOverdrive) { + const value = getCurrentValue(); + if (value > 1.0) { + return Color.mError; + } + } + return Color.mPrimary; } function getIconColor() { diff --git a/Services/Media/AudioService.qml b/Services/Media/AudioService.qml index 0193a9f2..46607639 100644 --- a/Services/Media/AudioService.qml +++ b/Services/Media/AudioService.qml @@ -59,6 +59,8 @@ Singleton { property bool mutedValue: true property real inputVolumeValue: 0 property bool inputMutedValue: true + property bool isClampingOutput: false + property bool isClampingInput: false // Initialization @@ -86,6 +88,21 @@ Singleton { if (isNaN(vol)) return; + // Clamp volume if it exceeds max when volumeOverdrive is disabled + if (!root.isClampingOutput) { + const maxVolume = Settings.data.audio.volumeOverdrive ? 1.5 : 1.0; + if (vol > maxVolume) { + root.isClampingOutput = true; + Qt.callLater(() => { + if (root.sink?.audio) { + root.sink.audio.volume = maxVolume; + } + root.isClampingOutput = false; + }); + return; + } + } + if (Math.abs(root.volumeValue - vol) > 0.001) { root.volumeValue = vol; } @@ -108,6 +125,21 @@ Singleton { if (vol === undefined || isNaN(vol)) return; + // Clamp volume if it exceeds max when volumeOverdrive is disabled + if (!root.isClampingInput) { + const maxVolume = Settings.data.audio.volumeOverdrive ? 1.5 : 1.0; + if (vol > maxVolume) { + root.isClampingInput = true; + Qt.callLater(() => { + if (root.source?.audio) { + root.source.audio.volume = maxVolume; + } + root.isClampingInput = false; + }); + return; + } + } + if (Math.abs(root.inputVolumeValue - vol) > 0.001) { root.inputVolumeValue = vol; } @@ -133,6 +165,10 @@ Singleton { // Output Control function increaseVolume() { + const maxVolume = Settings.data.audio.volumeOverdrive ? 1.5 : 1.0; + if (volume >= maxVolume) { + return; + } setVolume(volume + stepVolume); } @@ -173,6 +209,10 @@ Singleton { // Input Control function increaseInputVolume() { + const maxVolume = Settings.data.audio.volumeOverdrive ? 1.5 : 1.0; + if (inputVolume >= maxVolume) { + return; + } setInputVolume(inputVolume + stepVolume); }