diff --git a/src/nvda_voicemeeter/compound.py b/src/nvda_voicemeeter/compound.py index 4110c48..2f371df 100644 --- a/src/nvda_voicemeeter/compound.py +++ b/src/nvda_voicemeeter/compound.py @@ -2,7 +2,7 @@ import PySimpleGUI as psg class LabelSlider(psg.Frame): - """Compound Label Slider element""" + """Compound Label Slider Strip element""" def __init__(self, parent, i, param, range_=(0, 10), *args, **kwargs): self.parent = parent @@ -33,3 +33,105 @@ class LabelSlider(psg.Frame): if param in ("COMP", "GATE", "DENOISER"): return target.knob return target + + +class CompSlider(psg.Slider): + """Compressor Slider element""" + + def __init__(self, vm, index, param): + self.vm = vm + self.index = index + super().__init__(**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, + "disable_number_display": True, + "expand_x": True, + "enable_events": True, + "orientation": "horizontal", + "key": f"COMPRESSOR||SLIDER {param}", + } + case "RATIO": + return { + "range": (1, 8), + "default_value": self.vm.strip[self.index].comp.ratio, + "resolution": 0.1, + "disable_number_display": True, + "expand_x": True, + "enable_events": True, + "orientation": "horizontal", + "key": f"COMPRESSOR||SLIDER {param}", + } + case "THRESHOLD": + return { + "range": (-40, -3), + "default_value": self.vm.strip[self.index].comp.threshold, + "resolution": 0.1, + "disable_number_display": True, + "expand_x": True, + "enable_events": True, + "orientation": "horizontal", + "key": f"COMPRESSOR||SLIDER {param}", + } + case "ATTACK": + return { + "range": (0, 200), + "default_value": self.vm.strip[self.index].comp.attack, + "resolution": 0.1, + "disable_number_display": True, + "expand_x": True, + "enable_events": True, + "orientation": "horizontal", + "key": f"COMPRESSOR||SLIDER {param}", + } + case "RELEASE": + return { + "range": (0, 5000), + "default_value": self.vm.strip[self.index].comp.release, + "resolution": 0.1, + "disable_number_display": True, + "expand_x": True, + "enable_events": True, + "orientation": "horizontal", + "key": f"COMPRESSOR||SLIDER {param}", + } + case "KNEE": + return { + "range": (0, 1), + "default_value": self.vm.strip[self.index].comp.knee, + "resolution": 0.01, + "disable_number_display": True, + "expand_x": True, + "enable_events": True, + "orientation": "horizontal", + "key": f"COMPRESSOR||SLIDER {param}", + } + case "OUTPUT GAIN": + return { + "range": (-24, 24), + "default_value": self.vm.strip[self.index].comp.gainout, + "resolution": 0.01, + "disable_number_display": True, + "expand_x": True, + "enable_events": True, + "orientation": "horizontal", + "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) diff --git a/src/nvda_voicemeeter/popup.py b/src/nvda_voicemeeter/popup.py index 97b3f82..6bf3a31 100644 --- a/src/nvda_voicemeeter/popup.py +++ b/src/nvda_voicemeeter/popup.py @@ -4,6 +4,7 @@ from pathlib import Path import PySimpleGUI as psg from . import util +from .compound import LabelSliderCompressor logger = logging.getLogger(__name__) @@ -155,3 +156,33 @@ class Popup: 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("Auto Makeup", size=(12, 1)), psg.Button("Exit", size=(8, 1))]) + + popup = psg.Window(title, layout, 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["Exit"].bind("", "||FOCUS IN") + popup["Exit"].bind("", "||KEY ENTER") + while True: + event, values = popup.read() + if event in (psg.WIN_CLOSED, "Exit"): + break + match parsed_cmd := self.window.parser.match.parseString(event): + case [[button], ["KEY", "ENTER"]]: + popup.find_element_with_focus().click() + self.logger.debug(f"parsed::{parsed_cmd}") + popup.close() diff --git a/src/nvda_voicemeeter/window.py b/src/nvda_voicemeeter/window.py index 42a0215..975b19e 100644 --- a/src/nvda_voicemeeter/window.py +++ b/src/nvda_voicemeeter/window.py @@ -620,7 +620,19 @@ class NVDAVMWindow(psg.Window): self.write_event_value(f"INSERT CHECKBOX||{in_num} {channel}", val) # Advanced Settings - case ["ADVANCED SETTINGS"] | ["CTRL-A"]: + 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") + + case ["ADVANCED SETTINGS"]: if values["tabgroup"] == "tab||Settings": self.popup.advanced_settings(title="Advanced Settings") case [["ADVANCED", "SETTINGS"], ["FOCUS", "IN"]]: