Compare commits

...

3 Commits

Author SHA1 Message Date
ef10b224d7 remove redundant if statement 2023-09-25 18:24:43 +01:00
89d0253591 add advanced comproessor slider events
voicemeeter-api version bumped

some of the spoken feedback for sliders corrected.
2023-09-25 18:22:17 +01:00
85527e0749 defines layout for compressor popup 2023-09-25 12:14:29 +01:00
5 changed files with 444 additions and 16 deletions

6
pdm.lock generated
View File

@@ -271,13 +271,13 @@ files = [
[[package]] [[package]]
name = "voicemeeter-api" name = "voicemeeter-api"
version = "2.4.9" version = "2.4.10"
requires_python = ">=3.10,<4.0" requires_python = ">=3.10,<4.0"
summary = "A Python wrapper for the Voiceemeter API" summary = "A Python wrapper for the Voiceemeter API"
dependencies = [ dependencies = [
"tomli<3.0.0,>=2.0.1; python_version < \"3.11\"", "tomli<3.0.0,>=2.0.1; python_version < \"3.11\"",
] ]
files = [ files = [
{file = "voicemeeter_api-2.4.9-py3-none-any.whl", hash = "sha256:a09fd07fe3799cd5c880d491048da81d94e49aa97ec753aa1f9289acd27be965"}, {file = "voicemeeter_api-2.4.10-py3-none-any.whl", hash = "sha256:2f75acb7b472e56b6bd8d4f1141f32d948c55ef9b30d5a08e085a1c8e76e2464"},
{file = "voicemeeter_api-2.4.9.tar.gz", hash = "sha256:47ad614a8b9ccb0b4e47acf65666ce0f0537a0890fffda9949e995bea70e679c"}, {file = "voicemeeter_api-2.4.10.tar.gz", hash = "sha256:1d8dfc1e8922179f8b97c90b90b9ed051082018c6af5feb1d48250140a02d40c"},
] ]

View File

@@ -8,7 +8,7 @@ authors = [
dependencies = [ dependencies = [
"pysimplegui>=4.60.5", "pysimplegui>=4.60.5",
"pyparsing>=3.1.1", "pyparsing>=3.1.1",
"voicemeeter-api>=2.4.9", "voicemeeter-api>=2.4.10",
] ]
requires-python = ">=3.10,<3.12" requires-python = ">=3.10,<3.12"
readme = "README.md" readme = "README.md"

View File

@@ -2,7 +2,7 @@ import PySimpleGUI as psg
class LabelSlider(psg.Frame): class LabelSlider(psg.Frame):
"""Compound Label Slider element""" """Compound Label Slider Strip element"""
def __init__(self, parent, i, param, range_=(0, 10), *args, **kwargs): def __init__(self, parent, i, param, range_=(0, 10), *args, **kwargs):
self.parent = parent self.parent = parent
@@ -33,3 +33,83 @@ class LabelSlider(psg.Frame):
if param in ("COMP", "GATE", "DENOISER"): if param in ("COMP", "GATE", "DENOISER"):
return target.knob return target.knob
return target return target
class CompSlider(psg.Slider):
"""Compressor Slider element"""
def __init__(self, vm, index, param):
self.vm = vm
self.index = index
super().__init__(
disable_number_display=True,
expand_x=True,
enable_events=True,
orientation="horizontal",
**self.default_params(param),
)
def default_params(self, param):
match param:
case "INPUT GAIN":
return {
"range": (-24, 24),
"default_value": self.vm.strip[self.index].comp.gainin,
"resolution": 0.1,
"key": f"COMPRESSOR||SLIDER {param}",
}
case "RATIO":
return {
"range": (1, 8),
"default_value": self.vm.strip[self.index].comp.ratio,
"resolution": 0.1,
"key": f"COMPRESSOR||SLIDER {param}",
}
case "THRESHOLD":
return {
"range": (-40, -3),
"default_value": self.vm.strip[self.index].comp.threshold,
"resolution": 0.1,
"key": f"COMPRESSOR||SLIDER {param}",
}
case "ATTACK":
return {
"range": (0, 200),
"default_value": self.vm.strip[self.index].comp.attack,
"resolution": 0.1,
"key": f"COMPRESSOR||SLIDER {param}",
}
case "RELEASE":
return {
"range": (0, 5000),
"default_value": self.vm.strip[self.index].comp.release,
"resolution": 0.1,
"key": f"COMPRESSOR||SLIDER {param}",
}
case "KNEE":
return {
"range": (0, 1),
"default_value": self.vm.strip[self.index].comp.knee,
"resolution": 0.01,
"key": f"COMPRESSOR||SLIDER {param}",
}
case "OUTPUT GAIN":
return {
"range": (-24, 24),
"default_value": self.vm.strip[self.index].comp.gainout,
"resolution": 0.01,
"key": f"COMPRESSOR||SLIDER {param}",
}
class LabelSliderCompressor(psg.Frame):
"""Compound Label Slider Compressor element"""
def __init__(self, parent, index, param, *args, **kwargs):
layout = [
[
psg.Text(param.capitalize(), size=8),
CompSlider(parent.vm, index, param),
]
]
super().__init__(None, layout=layout, border_width=0, pad=0, *args, **kwargs)

View File

@@ -4,6 +4,7 @@ from pathlib import Path
import PySimpleGUI as psg import PySimpleGUI as psg
from . import util from . import util
from .compound import LabelSliderCompressor
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -40,7 +41,7 @@ class Popup:
filepath = values["Browse"] filepath = values["Browse"]
break break
self.window.nvda.speak(button) self.window.nvda.speak(button)
case [[button], ["KEY", "ENTER"]]: case [_, ["KEY", "ENTER"]]:
popup.find_element_with_focus().click() popup.find_element_with_focus().click()
self.logger.debug(f"parsed::{parsed_cmd}") self.logger.debug(f"parsed::{parsed_cmd}")
popup.close() popup.close()
@@ -83,7 +84,7 @@ class Popup:
match parsed_cmd := self.window.parser.match.parseString(event): match parsed_cmd := self.window.parser.match.parseString(event):
case [[button], ["FOCUS", "IN"]]: case [[button], ["FOCUS", "IN"]]:
self.window.nvda.speak(button) self.window.nvda.speak(button)
case [[button], ["KEY", "ENTER"]]: case [_, ["KEY", "ENTER"]]:
popup.find_element_with_focus().click() popup.find_element_with_focus().click()
case ["Ok"]: case ["Ok"]:
data = values data = values
@@ -151,7 +152,335 @@ class Popup:
util.open_context_menu_for_buttonmenu(popup, f"BUFFER {driver}") util.open_context_menu_for_buttonmenu(popup, f"BUFFER {driver}")
case [[button], ["FOCUS", "IN"]]: case [[button], ["FOCUS", "IN"]]:
self.window.nvda.speak(button) self.window.nvda.speak(button)
case [[button], ["KEY", "ENTER"]]: case [_, ["KEY", "ENTER"]]:
popup.find_element_with_focus().click()
self.logger.debug(f"parsed::{parsed_cmd}")
popup.close()
def compressor(self, index, title=None):
def _make_comp_frame() -> psg.Frame:
comp_layout = [
[LabelSliderCompressor(self.window, index, param)]
for param in ("INPUT GAIN", "RATIO", "THRESHOLD", "ATTACK", "RELEASE", "KNEE", "OUTPUT GAIN")
]
return psg.Frame("ADVANCED COMPRESSOR", comp_layout)
layout = []
steps = (_make_comp_frame,)
for step in steps:
layout.append([step()])
layout.append([psg.Button("MAKEUP", size=(12, 1)), psg.Button("Exit", size=(8, 1))])
popup = psg.Window(title, layout, return_keyboard_events=False, finalize=True)
buttonmenu_opts = {"takefocus": 1, "highlightthickness": 1}
for param in ("INPUT GAIN", "RATIO", "THRESHOLD", "ATTACK", "RELEASE", "KNEE", "OUTPUT GAIN"):
popup[f"COMPRESSOR||SLIDER {param}"].Widget.config(**buttonmenu_opts)
popup[f"COMPRESSOR||SLIDER {param}"].bind("<FocusIn>", "||FOCUS IN")
popup[f"COMPRESSOR||SLIDER {param}"].bind("<FocusOut>", "||FOCUS OUT")
for event in ("KeyPress", "KeyRelease"):
event_id = event.removeprefix("Key").upper()
for direction in ("Left", "Right", "Up", "Down"):
popup[f"COMPRESSOR||SLIDER {param}"].bind(
f"<{event}-{direction}>", f"||KEY {direction.upper()} {event_id}"
)
popup[f"COMPRESSOR||SLIDER {param}"].bind(
f"<Shift-{event}-{direction}>", f"||KEY SHIFT {direction.upper()} {event_id}"
)
popup[f"COMPRESSOR||SLIDER {param}"].bind(
f"<Control-{event}-{direction}>", f"||KEY CTRL {direction.upper()} {event_id}"
)
if param == "RELEASE":
popup[f"COMPRESSOR||SLIDER {param}"].bind(
f"<Alt-{event}-{direction}>", f"||KEY ALT {direction.upper()} {event_id}"
)
popup[f"COMPRESSOR||SLIDER {param}"].bind(
f"<Control-Alt-{event}-{direction}>", f"||KEY CTRL ALT {direction.upper()} {event_id}"
)
popup["MAKEUP"].bind("<FocusIn>", "||FOCUS IN")
popup["MAKEUP"].bind("<Return>", "||KEY ENTER")
popup["Exit"].bind("<FocusIn>", "||FOCUS IN")
popup["Exit"].bind("<Return>", "||KEY ENTER")
while True:
event, values = popup.read()
self.logger.debug(f"event::{event}")
self.logger.debug(f"values::{values}")
if event in (psg.WIN_CLOSED, "Exit"):
break
match parsed_cmd := self.window.parser.match.parseString(event):
case [["COMPRESSOR"], ["SLIDER", param]]:
setattr(self.window.vm.strip[index].comp, param.lower(), values[event])
case [["COMPRESSOR"], ["SLIDER", param], ["FOCUS", "IN"]]:
self.window.nvda.speak(f"{param} {values[f'COMPRESSOR||SLIDER {param}']}")
case [
["COMPRESSOR"],
["SLIDER", param],
["KEY", "LEFT" | "RIGHT" | "UP" | "DOWN" as input_direction, "PRESS" | "RELEASE" as e],
]:
if e == "PRESS":
self.window.vm.event.pdirty = False
val = getattr(self.window.vm.strip[index].comp, param.lower())
match input_direction:
case "RIGHT" | "UP":
if param == "KNEE":
val += 0.1
else:
val += 1
case "LEFT" | "DOWN":
if param == "KNEE":
val -= 0.1
else:
val -= 1
match param:
case "RATIO":
val = util.check_bounds(val, (1, 8))
case "THRESHOLD":
val = util.check_bounds(val, (-40, -3))
case "ATTACK":
val = util.check_bounds(val, (0, 200))
case "RELEASE":
val = util.check_bounds(val, (0, 5000))
case "KNEE":
val = util.check_bounds(val, (0, 1))
setattr(self.window.vm.strip[index].comp, param.lower(), val)
popup[f"COMPRESSOR||SLIDER {param}"].update(value=val)
if param == "KNEE":
self.window.nvda.speak(str(round(val, 2)))
else:
self.window.nvda.speak(str(round(val, 1)))
else:
self.window.vm.event.pdirty = True
case [
["COMPRESSOR"],
["SLIDER", param],
["KEY", "CTRL", "LEFT" | "RIGHT" | "UP" | "DOWN" as input_direction, "PRESS" | "RELEASE" as e],
]:
if e == "PRESS":
self.window.vm.event.pdirty = False
val = getattr(self.window.vm.strip[index].comp, param.lower())
match input_direction:
case "RIGHT" | "UP":
if param == "KNEE":
val += 0.3
elif param == "RELEASE":
val += 5
else:
val += 3
case "LEFT" | "DOWN":
if param == "KNEE":
val -= 0.3
elif param == "RELEASE":
val -= 5
else:
val -= 3
match param:
case "RATIO":
val = util.check_bounds(val, (1, 8))
case "THRESHOLD":
val = util.check_bounds(val, (-40, -3))
case "ATTACK":
val = util.check_bounds(val, (0, 200))
case "RELEASE":
val = util.check_bounds(val, (0, 5000))
case "KNEE":
val = util.check_bounds(val, (0, 1))
setattr(self.window.vm.strip[index].comp, param.lower(), val)
popup[f"COMPRESSOR||SLIDER {param}"].update(value=val)
if param == "KNEE":
self.window.nvda.speak(str(round(val, 2)))
else:
self.window.nvda.speak(str(round(val, 1)))
else:
self.window.vm.event.pdirty = True
case [
["COMPRESSOR"],
["SLIDER", param],
["KEY", "SHIFT", "LEFT" | "RIGHT" | "UP" | "DOWN" as input_direction, "PRESS" | "RELEASE" as e],
]:
if e == "PRESS":
self.window.vm.event.pdirty = False
val = getattr(self.window.vm.strip[index].comp, param.lower())
match input_direction:
case "RIGHT" | "UP":
if param == "KNEE":
val += 0.01
else:
val += 0.1
case "LEFT" | "DOWN":
if param == "KNEE":
val -= 0.01
else:
val -= 0.1
match param:
case "RATIO":
val = util.check_bounds(val, (1, 8))
case "THRESHOLD":
val = util.check_bounds(val, (-40, -3))
case "ATTACK":
val = util.check_bounds(val, (0, 200))
case "RELEASE":
val = util.check_bounds(val, (0, 5000))
case "KNEE":
val = util.check_bounds(val, (0, 1))
setattr(self.window.vm.strip[index].comp, param.lower(), val)
popup[f"COMPRESSOR||SLIDER {param}"].update(value=val)
if param == "KNEE":
self.window.nvda.speak(str(round(val, 2)))
else:
self.window.nvda.speak(str(round(val, 1)))
else:
self.window.vm.event.pdirty = True
case [
["COMPRESSOR"],
["SLIDER", "RELEASE"],
["KEY", "ALT", "LEFT" | "RIGHT" as input_direction, "PRESS" | "RELEASE" as e],
]:
if e == "PRESS":
self.window.vm.event.pdirty = False
val = self.window.vm.strip[index].comp.release
match input_direction:
case "RIGHT" | "UP":
val += 10
case "LEFT" | "DOWN":
val -= 10
val = util.check_bounds(val, (0, 5000))
self.window.vm.strip[index].comp.release = val
popup[f"COMPRESSOR||SLIDER {param}"].update(value=val)
self.window.nvda.speak(str(round(val, 1)))
else:
self.window.vm.event.pdirty = True
case [
["COMPRESSOR"],
["SLIDER", "RELEASE"],
["KEY", "CTRL", "ALT", "LEFT" | "RIGHT" as input_direction, "PRESS" | "RELEASE" as e],
]:
if e == "PRESS":
self.window.vm.event.pdirty = False
val = self.window.vm.strip[index].comp.release
match input_direction:
case "RIGHT" | "UP":
val += 50
case "LEFT" | "DOWN":
val -= 50
val = util.check_bounds(val, (0, 5000))
self.window.vm.strip[index].comp.release = val
popup[f"COMPRESSOR||SLIDER {param}"].update(value=val)
self.window.nvda.speak(str(round(val, 1)))
else:
self.window.vm.event.pdirty = True
case [["COMPRESSOR"], ["SLIDER", "INPUT" | "OUTPUT" as direction, "GAIN"]]:
if direction == "INPUT":
self.window.vm.strip[index].comp.gainin = values[event]
else:
self.window.vm.strip[index].comp.gainout = values[event]
case [["COMPRESSOR"], ["SLIDER", "INPUT" | "OUTPUT" as direction, "GAIN"], ["FOCUS", "IN"]]:
label = f"{direction} GAIN"
self.window.nvda.speak(f"{label} {values[f'COMPRESSOR||SLIDER {label}']}")
case [
["COMPRESSOR"],
["SLIDER", "INPUT" | "OUTPUT" as direction, "GAIN"],
["KEY", "LEFT" | "RIGHT" | "UP" | "DOWN" as input_direction, "PRESS" | "RELEASE" as e],
]:
if e == "PRESS":
self.window.vm.event.pdirty = False
if direction == "INPUT":
val = self.window.vm.strip[index].comp.gainin
else:
val = self.window.vm.strip[index].comp.gainout
match input_direction:
case "RIGHT" | "UP":
val += 1
case "LEFT" | "DOWN":
val -= 1
val = util.check_bounds(val, (-24, 24))
if direction == "INPUT":
self.window.vm.strip[index].comp.gainin = val
else:
self.window.vm.strip[index].comp.gainout = val
popup[f"COMPRESSOR||SLIDER {direction} GAIN"].update(value=val)
self.window.nvda.speak(str(round(val, 1)))
else:
self.window.vm.event.pdirty = True
case [
["COMPRESSOR"],
["SLIDER", "INPUT" | "OUTPUT" as direction, "GAIN"],
["KEY", "CTRL", "LEFT" | "RIGHT" | "UP" | "DOWN" as input_direction, "PRESS" | "RELEASE" as e],
]:
if e == "PRESS":
self.window.vm.event.pdirty = False
if direction == "INPUT":
val = self.window.vm.strip[index].comp.gainin
else:
val = self.window.vm.strip[index].comp.gainout
match input_direction:
case "RIGHT" | "UP":
val += 3
case "LEFT" | "DOWN":
val -= 3
val = util.check_bounds(val, (-24, 24))
if direction == "INPUT":
self.window.vm.strip[index].comp.gainin = val
else:
self.window.vm.strip[index].comp.gainout = val
popup[f"COMPRESSOR||SLIDER {direction} GAIN"].update(value=val)
self.window.nvda.speak(str(round(val, 1)))
else:
self.window.vm.event.pdirty = True
case [
["COMPRESSOR"],
["SLIDER", "INPUT" | "OUTPUT" as direction, "GAIN"],
["KEY", "SHIFT", "LEFT" | "RIGHT" | "UP" | "DOWN" as input_direction, "PRESS" | "RELEASE" as e],
]:
if e == "PRESS":
self.window.vm.event.pdirty = False
if direction == "INPUT":
val = self.window.vm.strip[index].comp.gainin
else:
val = self.window.vm.strip[index].comp.gainout
match input_direction:
case "RIGHT" | "UP":
val += 0.1
case "LEFT" | "DOWN":
val -= 0.1
val = util.check_bounds(val, (-24, 24))
if direction == "INPUT":
self.window.vm.strip[index].comp.gainin = val
else:
self.window.vm.strip[index].comp.gainout = val
popup[f"COMPRESSOR||SLIDER {direction} GAIN"].update(value=val)
self.window.nvda.speak(str(round(val, 1)))
else:
self.window.vm.event.pdirty = True
case ["MAKEUP"]:
val = not self.window.vm.strip[index].comp.makeup
self.window.vm.strip[index].comp.makeup = val
self.window.nvda.speak("on" if val else "off")
case [[button], ["FOCUS", "IN"]]:
if button == "MAKEUP":
self.window.nvda.speak(f"{button} {'on' if self.window.vm.strip[index].comp.makeup else 'off'}")
else:
self.window.nvda.speak(button)
case [_, ["KEY", "ENTER"]]:
popup.find_element_with_focus().click() popup.find_element_with_focus().click()
self.logger.debug(f"parsed::{parsed_cmd}") self.logger.debug(f"parsed::{parsed_cmd}")
popup.close() popup.close()

View File

@@ -311,7 +311,7 @@ class NVDAVMWindow(psg.Window):
continue continue
match parsed_cmd := self.parser.match.parseString(event): match parsed_cmd := self.parser.match.parseString(event):
# Slide mode # Slider mode
case [["ALT", "LEFT" | "RIGHT" | "UP" | "DOWN" as direction], ["PRESS" | "RELEASE" as e]]: case [["ALT", "LEFT" | "RIGHT" | "UP" | "DOWN" as direction], ["PRESS" | "RELEASE" as e]]:
if mode: if mode:
self.write_event_value(f"SLIDER MODE {direction}||{e}", mode.split()[0]) self.write_event_value(f"SLIDER MODE {direction}||{e}", mode.split()[0])
@@ -446,6 +446,19 @@ class NVDAVMWindow(psg.Window):
self[f"BUS {index}||LABEL"].update(value=label) self[f"BUS {index}||LABEL"].update(value=label)
self.cache["labels"][f"BUS {index}||LABEL"] = label self.cache["labels"][f"BUS {index}||LABEL"] = label
# Advanced popups (settings, comp, gate)
case ["CTRL-A"]:
match values["tabgroup"]:
case "tab||Settings":
self.write_event_value("ADVANCED SETTINGS", None)
case "tab||Physical Strip":
if values["tabgroup||Physical Strip"] == "tab||Physical Strip||sliders":
if focus := self.find_element_with_focus():
identifier, partial = focus.key.split("||")
_, index = identifier.split()
if "SLIDER COMP" in partial:
self.popup.compressor(int(index), title="Advanced Compressor")
# Menus # Menus
case [["Restart", "Audio", "Engine"], ["MENU"]]: case [["Restart", "Audio", "Engine"], ["MENU"]]:
self.perform_long_operation(self.vm.command.restart, "ENGINE RESTART||END") self.perform_long_operation(self.vm.command.restart, "ENGINE RESTART||END")
@@ -620,7 +633,7 @@ class NVDAVMWindow(psg.Window):
self.write_event_value(f"INSERT CHECKBOX||{in_num} {channel}", val) self.write_event_value(f"INSERT CHECKBOX||{in_num} {channel}", val)
# Advanced Settings # Advanced Settings
case ["ADVANCED SETTINGS"] | ["CTRL-A"]: case ["ADVANCED SETTINGS"]:
if values["tabgroup"] == "tab||Settings": if values["tabgroup"] == "tab||Settings":
self.popup.advanced_settings(title="Advanced Settings") self.popup.advanced_settings(title="Advanced Settings")
case [["ADVANCED", "SETTINGS"], ["FOCUS", "IN"]]: case [["ADVANCED", "SETTINGS"], ["FOCUS", "IN"]]:
@@ -798,7 +811,7 @@ class NVDAVMWindow(psg.Window):
val = util.check_bounds(val, (-40, 12)) val = util.check_bounds(val, (-40, 12))
self.vm.strip[int(index)].limit = val self.vm.strip[int(index)].limit = val
self[f"STRIP {index}||SLIDER {param}"].update(value=val) self[f"STRIP {index}||SLIDER {param}"].update(value=val)
self.nvda.speak(str(val)) self.nvda.speak(str(round(val, 1)))
else: else:
self.vm.event.pdirty = True self.vm.event.pdirty = True
case [ case [
@@ -865,7 +878,10 @@ class NVDAVMWindow(psg.Window):
val = util.check_bounds(val, (-40, 12)) val = util.check_bounds(val, (-40, 12))
self.vm.strip[int(index)].limit = val self.vm.strip[int(index)].limit = val
self[f"STRIP {index}||SLIDER {param}"].update(value=val) self[f"STRIP {index}||SLIDER {param}"].update(value=val)
self.nvda.speak(f"{param} {val}") if param == "LIMIT":
self.nvda.speak(str(int(val)))
else:
self.nvda.speak(str(round(val, 1)))
else: else:
self.vm.event.pdirty = True self.vm.event.pdirty = True
case [ case [
@@ -932,7 +948,10 @@ class NVDAVMWindow(psg.Window):
val = util.check_bounds(val, (-40, 12)) val = util.check_bounds(val, (-40, 12))
self.vm.strip[int(index)].limit = val self.vm.strip[int(index)].limit = val
self[f"STRIP {index}||SLIDER {param}"].update(value=val) self[f"STRIP {index}||SLIDER {param}"].update(value=val)
self.nvda.speak(f"{param} {val}") if param == "LIMIT":
self.nvda.speak(str(int(val)))
else:
self.nvda.speak(str(round(val, 1)))
else: else:
self.vm.event.pdirty = True self.vm.event.pdirty = True
case [["STRIP", index], ["SLIDER", param], ["KEY", "CTRL", "SHIFT", "R"]]: case [["STRIP", index], ["SLIDER", param], ["KEY", "CTRL", "SHIFT", "R"]]:
@@ -1041,7 +1060,7 @@ class NVDAVMWindow(psg.Window):
val = util.check_bounds(val, (-60, 12)) val = util.check_bounds(val, (-60, 12))
self.vm.bus[int(index)].gain = val self.vm.bus[int(index)].gain = val
self[f"BUS {index}||SLIDER GAIN"].update(value=val) self[f"BUS {index}||SLIDER GAIN"].update(value=val)
self.nvda.speak(str(val)) self.nvda.speak(str(round(val, 1)))
else: else:
self.vm.event.pdirty = True self.vm.event.pdirty = True
case [ case [
@@ -1060,7 +1079,7 @@ class NVDAVMWindow(psg.Window):
val = util.check_bounds(val, (-60, 12)) val = util.check_bounds(val, (-60, 12))
self.vm.bus[int(index)].gain = val self.vm.bus[int(index)].gain = val
self[f"BUS {index}||SLIDER GAIN"].update(value=val) self[f"BUS {index}||SLIDER GAIN"].update(value=val)
self.nvda.speak(str(val)) self.nvda.speak(str(round(val, 1)))
else: else:
self.vm.event.pdirty = True self.vm.event.pdirty = True
case [ case [
@@ -1079,7 +1098,7 @@ class NVDAVMWindow(psg.Window):
val = util.check_bounds(val, (-60, 12)) val = util.check_bounds(val, (-60, 12))
self.vm.bus[int(index)].gain = val self.vm.bus[int(index)].gain = val
self[f"BUS {index}||SLIDER GAIN"].update(value=val) self[f"BUS {index}||SLIDER GAIN"].update(value=val)
self.nvda.speak(str(val)) self.nvda.speak(str(round(val, 1)))
else: else:
self.vm.event.pdirty = True self.vm.event.pdirty = True
case [["BUS", index], ["SLIDER", "GAIN"], ["KEY", "CTRL", "SHIFT", "R"]]: case [["BUS", index], ["SLIDER", "GAIN"], ["KEY", "CTRL", "SHIFT", "R"]]: