Skip to content

Commit dd9a25b

Browse files
authored
Merge 6afcc0c into 25d408b
2 parents 25d408b + 6afcc0c commit dd9a25b

7 files changed

Lines changed: 137 additions & 10 deletions

File tree

source/audio/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@
66
from .soundSplit import (
77
SoundSplitState,
88
setSoundSplitState,
9+
updateSoundSplitState,
910
toggleSoundSplitState,
1011
)
1112

1213
__all__ = [
1314
"SoundSplitState",
1415
"setSoundSplitState",
16+
"updateSoundSplitState",
1517
"toggleSoundSplitState",
1618
]

source/audio/soundSplit.py

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,12 @@ def on_session_created(self, new_session: AudioSession):
155155

156156
def setSoundSplitState(state: SoundSplitState) -> dict:
157157
leftVolume, rightVolume = state.getAppVolume()
158+
appsVolume = (
159+
config.conf["audio"]["applicationsSoundVolume"] / 100
160+
* (1 - int(config.conf["audio"]["applicationsMuted"]))
161+
)
162+
leftVolume *= appsVolume
163+
rightVolume *= appsVolume
158164
leftNVDAVolume, rightNVDAVolume = state.getNVDAVolume()
159165
volumeSetter = VolumeSetter(leftVolume, rightVolume, leftNVDAVolume, rightNVDAVolume)
160166
applyToAllAudioSessions(volumeSetter)
@@ -163,7 +169,7 @@ def setSoundSplitState(state: SoundSplitState) -> dict:
163169
}
164170

165171

166-
def toggleSoundSplitState() -> None:
172+
def updateSoundSplitState(increment: int | None = None) -> None:
167173
if not nvwave.usingWasapiWavePlayer():
168174
message = _(
169175
# Translators: error message when wasapi is turned off.
@@ -173,17 +179,21 @@ def toggleSoundSplitState() -> None:
173179
ui.message(message)
174180
return
175181
state = SoundSplitState(config.conf["audio"]["soundSplitState"])
176-
allowedStates: list[int] = config.conf["audio"]["includedSoundSplitModes"]
177-
try:
178-
i = allowedStates.index(state)
179-
except ValueError:
180-
# State not found, resetting to default (OFF)
181-
i = -1
182-
i = (i + 1) % len(allowedStates)
183-
newState = SoundSplitState(allowedStates[i])
182+
if increment is None:
183+
newState = state
184+
else:
185+
allowedStates: list[int] = config.conf["audio"]["includedSoundSplitModes"]
186+
try:
187+
i = allowedStates.index(state)
188+
except ValueError:
189+
# State not found, resetting to default (OFF)
190+
i = -1
191+
i = (i + increment) % len(allowedStates)
192+
newState = SoundSplitState(allowedStates[i])
184193
result = setSoundSplitState(newState)
185194
config.conf["audio"]["soundSplitState"] = newState.value
186-
ui.message(newState.displayString)
195+
if increment is not None:
196+
ui.message(newState.displayString)
187197
if result["foundSessionWithNot2Channels"]:
188198
msg = _(
189199
# Translators: warning message when sound split trigger wasn't successful due to one of audio sessions
@@ -192,3 +202,7 @@ def toggleSoundSplitState() -> None:
192202
"one of audio sessions is either mono, or has more than 2 audio channels."
193203
)
194204
ui.message(msg)
205+
206+
207+
def toggleSoundSplitState() -> None:
208+
updateSoundSplitState(increment=1)

source/config/configSpec.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@
5959
whiteNoiseVolume = integer(default=0, min=0, max=100)
6060
soundSplitState = integer(default=0)
6161
includedSoundSplitModes = int_list(default=list(0, 1, 2))
62+
applicationsSoundVolume = integer(default=100, min=0, max=100)
63+
applicationsMuted = boolean(default=False)
6264
6365
# Braille settings
6466
[braille]

source/globalCommands.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4477,6 +4477,62 @@ def script_cycleParagraphStyle(self, gesture: "inputCore.InputGesture") -> None:
44774477
def script_cycleSoundSplit(self, gesture: "inputCore.InputGesture") -> None:
44784478
audio.toggleSoundSplitState()
44794479

4480+
@script(
4481+
description=_(
4482+
# Translators: Describes a command.
4483+
"Increases volume of applications by 5%",
4484+
),
4485+
category=SCRCAT_AUDIO,
4486+
gesture="kb:NVDA+alt+pageUp",
4487+
)
4488+
def script_increaseApplicationsVolume(self, gesture: "inputCore.InputGesture") -> None:
4489+
volume = config.conf["audio"]["applicationsSoundVolume"]
4490+
volume = min(100, volume + 5)
4491+
config.conf["audio"]["applicationsSoundVolume"] = volume
4492+
config.conf["audio"]["applicationsMuted"] = False
4493+
audio.updateSoundSplitState()
4494+
# Translators: a message reporting applications volume
4495+
msg = _("Applications volume %d") % volume
4496+
ui.message(msg)
4497+
4498+
@script(
4499+
description=_(
4500+
# Translators: Describes a command.
4501+
"Decreases volume of applications by 5%",
4502+
),
4503+
category=SCRCAT_AUDIO,
4504+
gesture="kb:NVDA+alt+pageDown",
4505+
)
4506+
def script_decreaseApplicationsVolume(self, gesture: "inputCore.InputGesture") -> None:
4507+
volume = config.conf["audio"]["applicationsSoundVolume"]
4508+
volume = max(0, volume - 5)
4509+
config.conf["audio"]["applicationsSoundVolume"] = volume
4510+
config.conf["audio"]["applicationsMuted"] = False
4511+
audio.updateSoundSplitState()
4512+
# Translators: a message reporting applications volume
4513+
msg = _("Applications volume %d") % volume
4514+
ui.message(msg)
4515+
4516+
@script(
4517+
description=_(
4518+
# Translators: Describes a command.
4519+
"Toggles applications mute",
4520+
),
4521+
category=SCRCAT_AUDIO,
4522+
gesture="kb:NVDA+alt+delete",
4523+
)
4524+
def script_toggleApplicationsMute(self, gesture: "inputCore.InputGesture") -> None:
4525+
muted = config.conf["audio"]["applicationsMuted"]
4526+
muted = not muted
4527+
config.conf["audio"]["applicationsMuted"] = muted
4528+
audio.updateSoundSplitState()
4529+
if muted:
4530+
# Translators: a message reporting applications volume
4531+
msg = _("Applications muted")
4532+
else:
4533+
msg = _("Applications unmuted")
4534+
ui.message(msg)
4535+
44804536

44814537
#: The single global commands instance.
44824538
#: @type: L{GlobalCommands}

source/gui/settingsDialogs.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2718,6 +2718,25 @@ def makeSettings(self, settingsSizer: wx.BoxSizer) -> None:
27182718
self.bindHelpEvent("SoundVolume", self.soundVolSlider)
27192719
self.soundVolSlider.SetValue(config.conf["audio"]["soundVolume"])
27202720

2721+
# Translators: This is the label for a slider control in the
2722+
# Audio settings panel.
2723+
label = _("Volume of application sounds")
2724+
self.appSoundVolSlider: nvdaControls.EnhancedInputSlider = sHelper.addLabeledControl(
2725+
label,
2726+
nvdaControls.EnhancedInputSlider,
2727+
minValue=0,
2728+
maxValue=100
2729+
)
2730+
self.bindHelpEvent("AppSoundVolume", self.appSoundVolSlider)
2731+
self.appSoundVolSlider.SetValue(config.conf["audio"]["applicationsSoundVolume"])
2732+
2733+
# Translators: This is the label for a checkbox control in the
2734+
# Audio settings panel.
2735+
label = _("Mute application sound")
2736+
self.muteApplicationsCheckBox: wx.CheckBox = sHelper.addItem(wx.CheckBox(self, label=label))
2737+
self.bindHelpEvent("MuteApplications", self.muteApplicationsCheckBox)
2738+
self.muteApplicationsCheckBox.SetValue(config.conf["audio"]["applicationsMuted"])
2739+
27212740
# Translators: This is a label for the sound split combo box in the Audio Settings dialog.
27222741
soundSplitLabelText = _("&Sound split mode:")
27232742
self.soundSplitComboBox = sHelper.addLabeledControl(
@@ -2807,6 +2826,8 @@ def onSave(self):
28072826

28082827
config.conf["audio"]["soundVolumeFollowsVoice"] = self.soundVolFollowCheckBox.IsChecked()
28092828
config.conf["audio"]["soundVolume"] = self.soundVolSlider.GetValue()
2829+
config.conf["audio"]["applicationsSoundVolume"] = self.appSoundVolSlider.GetValue()
2830+
config.conf["audio"]["applicationsMuted"] = self.muteApplicationsCheckBox.IsChecked()
28102831

28112832
index = self.soundSplitComboBox.GetSelection()
28122833
config.conf["audio"]["soundSplitState"] = index
@@ -2835,6 +2856,8 @@ def _onSoundVolChange(self, event: wx.Event) -> None:
28352856
wasapi
28362857
and not self.soundVolFollowCheckBox.IsChecked()
28372858
)
2859+
self.appSoundVolSlider.Enable(wasapi)
2860+
self.muteApplicationsCheckBox.Enable(wasapi)
28382861
self.soundSplitComboBox.Enable(wasapi)
28392862
self.soundSplitModesList.Enable(wasapi)
28402863

user_docs/en/changes.t2t

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ What's New in NVDA
2929
- Sound split: (#12985, @mltony)
3030
- Allows splitting NVDA sounds in one channel (e.g. left) while sounds from all other applications in the other channel (e.g. right).
3131
- Toggled by ``NVDA+alt+s``.
32+
- Volume of other applications can be adjusted by NVDA+Alt+PageUp/PageDown (#16052, @mltony)
3233
-
3334
-
3435

user_docs/en/userGuide.t2t

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1997,6 +1997,35 @@ By default only three modes are included.
19971997
Note that it is necessary to check at least one mode.
19981998
This option is not available if you have started NVDA with [WASAPI disabled for audio output #WASAPI] in Advanced Settings.
19991999

2000+
==== Applications volume ====[AppSoundVolume]
2001+
2002+
This slider allows to set volume of all currently running applications except for NVDA.
2003+
If any new applications start to output sound, their volume will also be affected.
2004+
This slider can also be controlled via the following keyboard commands:
2005+
2006+
%kc:beginInclude
2007+
|| Name | Key | Description |
2008+
| Increase applications volume | ``NVDA+alt+pageUp`` | Increases volume of all applications except NVDA by 5%. |
2009+
| Decrease applications volume | ``NVDA+alt+pageDown`` | Decreases volume of all applications except NVDA by 5%. |
2010+
2011+
%kc:endInclude
2012+
2013+
This option is not available if you have started NVDA with [WASAPI disabled for audio output #WASAPI] in Advanced Settings.
2014+
2015+
==== Mute other applications ====[MuteApplications]
2016+
2017+
This checkbox allows to mute all applications other than NVDA.
2018+
If any new applications start to output sound, their sound output will also be muted.
2019+
This checkbox can also be controlled via the following keyboard command:
2020+
2021+
%kc:beginInclude
2022+
|| Name | Key | Description |
2023+
| Toggle mute other applications | ``NVDA+alt+Delete`` | Mutes or unmutes all applications other than NVDA. |
2024+
2025+
%kc:endInclude
2026+
2027+
This option is not available if you have started NVDA with [WASAPI disabled for audio output #WASAPI] in Advanced Settings.
2028+
20002029
+++ Vision +++[VisionSettings]
20012030
The Vision category in the NVDA Settings dialog allows you to enable, disable and configure [visual aids #Vision].
20022031

0 commit comments

Comments
 (0)