Compare commits

...

3 Commits

Author SHA1 Message Date
3ca9e14e96 adds bass, mid and treble slider modes
patch bump
2023-09-21 09:33:22 +01:00
4ca64f94bc re 2023-09-21 08:35:55 +01:00
22bf109499 removes the spinbox from the rename popup
updates README

fixes #12

b1 bump
2023-09-20 18:24:24 +01:00
6 changed files with 74 additions and 67 deletions

View File

@ -106,7 +106,7 @@ All sliders may be controlled in three different ways:
- `Shift + Left|Right arrow` to move a slider by 0.1 steps. - `Shift + Left|Right arrow` to move a slider by 0.1 steps.
- `Control + Left|Right arrow` to move a slider by 3 steps. - `Control + Left|Right arrow` to move a slider by 3 steps.
To rename a strip/bus channel navigate to the relevant tab, then press `F2`. This will open a popup window where you can set the channel index (with a spinbox) and set the new label using a text input box. To rename a strip/bus channel focus on the channel in question and press `F2`. Then enter the new channel name into the text input widget and press the `Ok` button.
Pressing the `OK` button with an empty text input will clear the label. In this case the label will be read as a default value for that channel. For example, if the leftmost Strip label were cleared, the screen reader will now read `Hardware Input 1`. Pressing the `OK` button with an empty text input will clear the label. In this case the label will be read as a default value for that channel. For example, if the leftmost Strip label were cleared, the screen reader will now read `Hardware Input 1`.
@ -143,6 +143,9 @@ You may also enter slider modes which allow for control of the channels sliders
- `Control + G` will enter Gain mode - `Control + G` will enter Gain mode
- `Control + T` will enter Gate mode - `Control + T` will enter Gate mode
- `Control + L` will enter Limit mode - `Control + L` will enter Limit mode
- `Control + B` will enter Bass mode
- `Control + I` will enter Mid mode
- `Control + R` will enter Treble mode
To exit any of the slider modes press `Escape`. To exit any of the slider modes press `Escape`.

View File

@ -1,6 +1,6 @@
[project] [project]
name = "nvda_voicemeeter" name = "nvda_voicemeeter"
version = "0.3.0" version = "0.3.1"
description = "A Voicemeeter app compatible with NVDA" description = "A Voicemeeter app compatible with NVDA"
authors = [ authors = [
{ name = "onyx-and-iris", email = "code@onyxandiris.online" }, { name = "onyx-and-iris", email = "code@onyxandiris.online" },

View File

@ -323,7 +323,7 @@ class Builder:
) )
def add_param_sliders(layout): def add_param_sliders(layout):
layout.append([LabelSlider(self.window, i, param) for param in util.get_slider_params(i, self.vm)]) layout.append([LabelSlider(self.window, i, param) for param in util.get_slider_params(i, self.kind)])
def add_limit_slider(layout): def add_limit_slider(layout):
layout.append( layout.append(
@ -416,13 +416,13 @@ class Builder:
def add_param_sliders(layout): def add_param_sliders(layout):
if self.kind.name in ("basic", "banana"): if self.kind.name in ("basic", "banana"):
for param in util.get_slider_params(i, self.vm): for param in util.get_slider_params(i, self.kind):
layout.append([LabelSlider(self.window, i, param, range_=(-12, 12))]) layout.append([LabelSlider(self.window, i, param, range_=(-12, 12))])
else: else:
layout.append( layout.append(
[ [
LabelSlider(self.window, i, param, range_=(-12, 12)) LabelSlider(self.window, i, param, range_=(-12, 12))
for param in util.get_slider_params(i, self.vm) for param in util.get_slider_params(i, self.kind)
] ]
) )

View File

@ -11,6 +11,7 @@ logger = logging.getLogger(__name__)
class Popup: class Popup:
def __init__(self, window): def __init__(self, window):
self.window = window self.window = window
self.kind = self.window.kind
self.logger = logger.getChild(type(self).__name__) self.logger = logger.getChild(type(self).__name__)
def save_as(self, message, title=None, initial_folder=None): def save_as(self, message, title=None, initial_folder=None):
@ -46,28 +47,27 @@ class Popup:
if filepath: if filepath:
return Path(filepath) return Path(filepath)
def rename(self, message, title=None, tab=None): def rename(self, message, index, title=None, tab=None):
if tab == "Physical Strip": if "Strip" in tab:
upper = self.window.kind.phys_in + 1 if index < self.kind.phys_in:
elif tab == "Virtual Strip": title += f" Physical Strip {index + 1}"
upper = self.window.kind.virt_in + 1 else:
elif tab == "Buses": title += f" Virtual Strip {index - self.kind.phys_in + 1}"
upper = self.window.kind.num_bus + 1 else:
if index < self.kind.phys_out:
title += f" Physical Bus {index + 1}"
else:
title += f" Virtual Bus {index - self.kind.phys_out + 1}"
layout = [ layout = [
[psg.Text(message)], [psg.Text(message)],
[ [
[ [
psg.Spin(
list(range(1, upper)), initial_value=1, size=2, enable_events=True, key=f"Index", readonly=True
),
psg.Input(key="Edit"), psg.Input(key="Edit"),
], ],
[psg.Button("Ok"), psg.Button("Cancel")], [psg.Button("Ok"), psg.Button("Cancel")],
], ],
] ]
popup = psg.Window(title, layout, finalize=True) popup = psg.Window(title, layout, finalize=True)
popup["Index"].bind("<FocusIn>", "||FOCUS IN")
popup["Edit"].bind("<FocusIn>", "||FOCUS IN") popup["Edit"].bind("<FocusIn>", "||FOCUS IN")
popup["Ok"].bind("<FocusIn>", "||FOCUS IN") popup["Ok"].bind("<FocusIn>", "||FOCUS IN")
popup["Ok"].bind("<Return>", "||KEY ENTER") popup["Ok"].bind("<Return>", "||KEY ENTER")
@ -81,14 +81,7 @@ class Popup:
if event in (psg.WIN_CLOSED, "Cancel"): if event in (psg.WIN_CLOSED, "Cancel"):
break break
match parsed_cmd := self.window.parser.match.parseString(event): match parsed_cmd := self.window.parser.match.parseString(event):
case ["Index"]:
val = values["Index"]
self.window.nvda.speak(f"Index {val}")
case [[button], ["FOCUS", "IN"]]: case [[button], ["FOCUS", "IN"]]:
if button == "Index":
val = values["Index"]
self.window.nvda.speak(f"Index {val}")
else:
self.window.nvda.speak(button) self.window.nvda.speak(button)
case [[button], ["KEY", "ENTER"]]: case [[button], ["KEY", "ENTER"]]:
popup.find_element_with_focus().click() popup.find_element_with_focus().click()

View File

@ -141,12 +141,19 @@ def check_bounds(val, bounds: tuple) -> int | float:
return val return val
def get_slider_params(i, vm) -> Iterable: def get_slider_params(i, kind) -> Iterable:
if i < vm.kind.phys_in: if i < kind.phys_in:
if vm.kind.name == "basic": if kind.name == "basic":
return ("AUDIBILITY",) return ("AUDIBILITY",)
if vm.kind.name == "banana": if kind.name == "banana":
return ("COMP", "GATE") return ("COMP", "GATE")
if vm.kind.name == "potato": if kind.name == "potato":
return ("COMP", "GATE", "DENOISER") return ("COMP", "GATE", "DENOISER")
return ("BASS", "MID", "TREBLE") return ("BASS", "MID", "TREBLE")
def get_full_slider_params(i, kind) -> Iterable:
params = list(get_slider_params(i, kind) + ("GAIN", "LIMIT"))
if kind.name == "basic":
params.remove("LIMIT")
return params

View File

@ -50,7 +50,7 @@ class NVDAVMWindow(psg.Window):
[self[f"PATCH COMPOSITE||PC{i + 1}"].Widget.config(**buttonmenu_opts) for i in range(self.kind.phys_out)] [self[f"PATCH COMPOSITE||PC{i + 1}"].Widget.config(**buttonmenu_opts) for i in range(self.kind.phys_out)]
slider_opts = {"takefocus": 1, "highlightthickness": 1} slider_opts = {"takefocus": 1, "highlightthickness": 1}
for i in range(self.kind.num_strip): for i in range(self.kind.num_strip):
for param in util.get_slider_params(i, self.vm): for param in util.get_slider_params(i, self.kind):
self[f"STRIP {i}||SLIDER {param}"].Widget.config(**slider_opts) self[f"STRIP {i}||SLIDER {param}"].Widget.config(**slider_opts)
self[f"STRIP {i}||SLIDER GAIN"].Widget.config(**slider_opts) self[f"STRIP {i}||SLIDER GAIN"].Widget.config(**slider_opts)
if self.kind.name != "basic": if self.kind.name != "basic":
@ -109,7 +109,7 @@ class NVDAVMWindow(psg.Window):
self[f"STRIP {i}||SLIDER GAIN"].update(value=self.vm.strip[i].gain) self[f"STRIP {i}||SLIDER GAIN"].update(value=self.vm.strip[i].gain)
if self.kind.name != "basic": if self.kind.name != "basic":
self[f"STRIP {i}||SLIDER LIMIT"].update(value=self.vm.strip[i].limit) self[f"STRIP {i}||SLIDER LIMIT"].update(value=self.vm.strip[i].limit)
for param in util.get_slider_params(i, self.vm): for param in util.get_slider_params(i, self.kind):
if param in ("AUDIBILITY", "BASS", "MID", "TREBLE"): if param in ("AUDIBILITY", "BASS", "MID", "TREBLE"):
val = getattr(self.vm.strip[i], param.lower()) val = getattr(self.vm.strip[i], param.lower())
else: else:
@ -148,16 +148,18 @@ class NVDAVMWindow(psg.Window):
self.bind("<Control-o>", "CTRL-O") self.bind("<Control-o>", "CTRL-O")
self.bind("<Control-s>", "CTRL-S") self.bind("<Control-s>", "CTRL-S")
self.bind("<Control-m>", "CTRL-M") self.bind("<Control-m>", "CTRL-M")
self.bind("<Control-g>", "GAIN MODE")
self.bind("<Control-b>", "BASS MODE")
self.bind("<Control-i>", "MID MODE")
self.bind("<Control-r>", "TREBLE MODE")
if self.kind.name == "basic": if self.kind.name == "basic":
self.bind("<Control-u>", "AUDIBILITY MODE") self.bind("<Control-u>", "AUDIBILITY MODE")
self.bind("<Control-g>", "GAIN MODE")
elif self.kind.name == "banana": elif self.kind.name == "banana":
self.bind("<Control-g>", "GAIN MODE")
self.bind("<Control-c>", "COMP MODE") self.bind("<Control-c>", "COMP MODE")
self.bind("<Control-t>", "GATE MODE") self.bind("<Control-t>", "GATE MODE")
self.bind("<Control-l>", "LIMIT MODE") self.bind("<Control-l>", "LIMIT MODE")
else: else:
self.bind("<Control-g>", "GAIN MODE")
self.bind("<Control-c>", "COMP MODE") self.bind("<Control-c>", "COMP MODE")
self.bind("<Control-t>", "GATE MODE") self.bind("<Control-t>", "GATE MODE")
self.bind("<Control-d>", "DENOISER MODE") self.bind("<Control-d>", "DENOISER MODE")
@ -231,9 +233,7 @@ class NVDAVMWindow(psg.Window):
# Strip Sliders # Strip Sliders
for i in range(self.kind.num_strip): for i in range(self.kind.num_strip):
for param in util.get_slider_params(i, self.vm) + ("GAIN", "LIMIT"): for param in util.get_full_slider_params(i, self.kind):
if self.kind.name == "basic" and param == "LIMIT":
continue
self[f"STRIP {i}||SLIDER {param}"].bind("<FocusIn>", "||FOCUS IN") self[f"STRIP {i}||SLIDER {param}"].bind("<FocusIn>", "||FOCUS IN")
self[f"STRIP {i}||SLIDER {param}"].bind("<FocusOut>", "||FOCUS OUT") self[f"STRIP {i}||SLIDER {param}"].bind("<FocusOut>", "||FOCUS OUT")
self[f"STRIP {i}||SLIDER {param}"].bind("<Left>", "||KEY LEFT") self[f"STRIP {i}||SLIDER {param}"].bind("<Left>", "||KEY LEFT")
@ -291,12 +291,12 @@ class NVDAVMWindow(psg.Window):
self.logger.debug(f"values::{values}") self.logger.debug(f"values::{values}")
if event in (psg.WIN_CLOSED, "Exit"): if event in (psg.WIN_CLOSED, "Exit"):
break break
elif event in ("GAIN MODE", "COMP MODE", "GATE MODE", "DENOISER MODE", "LIMIT MODE"): elif event.endswith("MODE"):
mode = event mode = event
self.nvda.speak(f"{mode} enabled") self.nvda.speak(f"{mode} enabled")
elif event == "Escape:27": elif event == "Escape:27":
if mode: if mode:
self.nvda.speak(f"{mode.split()[0]} mode disabled") self.nvda.speak(f"{mode} disabled")
mode = None mode = None
if mode: if mode:
@ -380,41 +380,45 @@ class NVDAVMWindow(psg.Window):
| "SLIDER-MODE-CTRL-LEFT" | "SLIDER-MODE-CTRL-LEFT"
| "SLIDER-MODE-CTRL-RIGHT" as op | "SLIDER-MODE-CTRL-RIGHT" as op
]: ]:
op = op.removeprefix("SLIDER-MODE-").split("-")
if values["tabgroup"] not in ("tab||Physical Strip", "tab||Virtual Strip", "tab||Buses"): if values["tabgroup"] not in ("tab||Physical Strip", "tab||Virtual Strip", "tab||Buses"):
continue continue
param = values[event] param = values[event]
if focus := self.find_element_with_focus(): if focus := self.find_element_with_focus():
identifier, partial = focus.Key.split("||") identifier, partial = focus.Key.split("||")
_, index = identifier.split()
if param in util.get_full_slider_params(int(index), self.kind):
if "SLIDER" not in partial: if "SLIDER" not in partial:
op = op.removeprefix("SLIDER-MODE-").split("-")
self.write_event_value(f"{identifier}||SLIDER {param}||KEY {' '.join(op)}", None) self.write_event_value(f"{identifier}||SLIDER {param}||KEY {' '.join(op)}", None)
# Rename popups # Rename popups
case ["F2:113"]: case ["F2:113"]:
tab = values["tabgroup"].split("||")[1] tab = values["tabgroup"].split("||")[1]
if tab in ("Physical Strip", "Virtual Strip", "Buses"): if tab in ("Physical Strip", "Virtual Strip", "Buses"):
data = self.popup.rename("Label", title=f"Rename {tab}", tab=tab) if focus := self.find_element_with_focus():
identifier, partial = focus.Key.split("||")
_, index = identifier.split()
index = int(index)
data = self.popup.rename("Label", index, title=f"Rename", tab=tab)
if not data: # cancel was pressed if not data: # cancel was pressed
continue continue
index = int(data["Index"]) - 1
match tab: match tab:
case "Physical Strip": case "Physical Strip":
label = data.get("Edit", f"Hardware Input {index + 1}") label = data.get("Edit", f"Hardware Input {int(index) + 1}")
self.vm.strip[index].label = label self.vm.strip[int(index)].label = label
self[f"STRIP {index}||LABEL"].update(value=label) self[f"STRIP {index}||LABEL"].update(value=label)
self.cache["labels"][f"STRIP {index}||LABEL"] = label self.cache["labels"][f"STRIP {index}||LABEL"] = label
case "Virtual Strip": case "Virtual Strip":
index += self.kind.phys_in label = data.get("Edit", f"Virtual Input {int(index) + 1}")
label = data.get("Edit", f"Virtual Input {index - self.kind.phys_in + 1}") self.vm.strip[int(index)].label = label
self.vm.strip[index].label = label
self[f"STRIP {index}||LABEL"].update(value=label) self[f"STRIP {index}||LABEL"].update(value=label)
self.cache["labels"][f"STRIP {index}||LABEL"] = label self.cache["labels"][f"STRIP {index}||LABEL"] = label
case "Buses": case "Buses":
if index < self.kind.phys_out: if index < self.kind.phys_out:
label = data.get("Edit", f"Physical Bus {index + 1}") label = data.get("Edit", f"Physical Bus {int(index) + 1}")
else: else:
label = data.get("Edit", f"Virtual Bus {index - self.kind.phys_out + 1}") label = data.get("Edit", f"Virtual Bus {int(index) - self.kind.phys_out + 1}")
self.vm.bus[index].label = label self.vm.bus[int(index)].label = label
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