onyx-and-iris 0aeb33608f implements reset binds
Advanced Comp|Gate section added to README.

bump to version 0.5.0b1
2023-09-26 23:51:34 +01:00

716 lines
34 KiB
Python

import logging
from pathlib import Path
import PySimpleGUI as psg
from . import util
from .compound import CompSlider, GateSlider, LabelSliderAdvanced
logger = logging.getLogger(__name__)
class Popup:
def __init__(self, window):
self.window = window
self.kind = self.window.kind
self.logger = logger.getChild(type(self).__name__)
def save_as(self, message, title=None, initial_folder=None):
layout = [
[psg.Text(message)],
[
psg.FileSaveAs("Browse", initial_folder=str(initial_folder), file_types=(("XML", ".xml"),)),
psg.Button("Cancel"),
],
]
popup = psg.Window(title, layout, finalize=True)
popup["Browse"].bind("<FocusIn>", "||FOCUS IN")
popup["Browse"].bind("<Return>", "||KEY ENTER")
popup["Cancel"].bind("<FocusIn>", "||FOCUS IN")
popup["Cancel"].bind("<Return>", "||KEY ENTER")
filepath = None
while True:
event, values = popup.read()
self.logger.debug(f"event::{event}")
self.logger.debug(f"values::{values}")
if event in (psg.WIN_CLOSED, "Cancel"):
break
match parsed_cmd := self.window.parser.match.parseString(event):
case [[button], ["FOCUS", "IN"]]:
if values["Browse"]:
filepath = values["Browse"]
break
self.window.nvda.speak(button)
case [_, ["KEY", "ENTER"]]:
popup.find_element_with_focus().click()
self.logger.debug(f"parsed::{parsed_cmd}")
popup.close()
if filepath:
return Path(filepath)
def rename(self, message, index, title=None, tab=None):
if "Strip" in tab:
if index < self.kind.phys_in:
title += f" Physical Strip {index + 1}"
else:
title += f" Virtual Strip {index - self.kind.phys_in + 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 = [
[psg.Text(message)],
[
[
psg.Input(key="Edit"),
],
[psg.Button("Ok"), psg.Button("Cancel")],
],
]
popup = psg.Window(title, layout, finalize=True)
popup["Edit"].bind("<FocusIn>", "||FOCUS IN")
popup["Ok"].bind("<FocusIn>", "||FOCUS IN")
popup["Ok"].bind("<Return>", "||KEY ENTER")
popup["Cancel"].bind("<FocusIn>", "||FOCUS IN")
popup["Cancel"].bind("<Return>", "||KEY ENTER")
data = {}
while True:
event, values = popup.read()
self.logger.debug(f"event::{event}")
self.logger.debug(f"values::{values}")
if event in (psg.WIN_CLOSED, "Cancel"):
break
match parsed_cmd := self.window.parser.match.parseString(event):
case [[button], ["FOCUS", "IN"]]:
self.window.nvda.speak(button)
case [_, ["KEY", "ENTER"]]:
popup.find_element_with_focus().click()
case ["Ok"]:
data = values
break
self.logger.debug(f"parsed::{parsed_cmd}")
popup.close()
return data
def advanced_settings(self, title):
def _make_buffering_frame() -> psg.Frame:
buffer = [
[
psg.ButtonMenu(
driver,
size=(14, 2),
menu_def=["", util.get_asio_samples_list(driver)],
key=f"BUFFER {driver}",
)
for driver in ("MME", "WDM", "KS", "ASIO")
],
]
return psg.Frame("BUFFERING", buffer)
layout = []
steps = (_make_buffering_frame,)
for step in steps:
layout.append([step()])
layout.append([psg.Button("Exit", size=(8, 2))])
popup = psg.Window(title, layout, finalize=True)
buttonmenu_opts = {"takefocus": 1, "highlightthickness": 1}
for driver in ("MME", "WDM", "KS", "ASIO"):
popup[f"BUFFER {driver}"].Widget.config(**buttonmenu_opts)
popup[f"BUFFER {driver}"].bind("<FocusIn>", "||FOCUS IN")
popup[f"BUFFER {driver}"].bind("<space>", "||KEY SPACE", propagate=False)
popup[f"BUFFER {driver}"].bind("<Return>", "||KEY ENTER", propagate=False)
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 ["BUFFER MME" | "BUFFER WDM" | "BUFFER KS" | "BUFFER ASIO"]:
if values[event] == "Default":
if "MME" in event:
val = 1024
elif "WDM" in event or "KS" in event:
val = 512
else:
val = 0
else:
val = int(values[event])
driver = event.split()[1]
self.window.vm.set(f"option.buffer.{driver.lower()}", val)
self.window.TKroot.after(
200, self.window.nvda.speak, f"{driver} BUFFER {val if val else 'default'}"
)
case [["BUFFER", driver], ["FOCUS", "IN"]]:
val = int(self.window.vm.get(f"option.buffer.{driver.lower()}"))
self.window.nvda.speak(f"{driver} BUFFER {val if val else 'default'}")
case [["BUFFER", driver], ["KEY", "SPACE" | "ENTER"]]:
util.open_context_menu_for_buttonmenu(popup, f"BUFFER {driver}")
case [[button], ["FOCUS", "IN"]]:
self.window.nvda.speak(button)
case [_, ["KEY", "ENTER"]]:
popup.find_element_with_focus().click()
self.logger.debug(f"parsed::{parsed_cmd}")
popup.close()
def on_pdirty(self):
if self.popup.Title == "Advanced Compressor":
for param in ("RATIO", "THRESHOLD", "ATTACK", "RELEASE", "KNEE"):
self.popup[f"COMPRESSOR||SLIDER {param}"].update(
value=getattr(self.window.vm.strip[self.index].comp, param.lower())
)
self.popup["COMPRESSOR||SLIDER INPUT GAIN"].update(value=self.window.vm.strip[self.index].comp.gainin)
self.popup["COMPRESSOR||SLIDER OUTPUT GAIN"].update(value=self.window.vm.strip[self.index].comp.gainout)
elif self.popup.Title == "Advanced Gate":
for param in ("THRESHOLD", "DAMPING", "BPSIDECHAIN", "ATTACK", "HOLD", "RELEASE"):
self.popup[f"GATE||SLIDER {param}"].update(
value=getattr(self.window.vm.strip[self.index].gate, param.lower())
)
def compressor(self, index, title=None):
self.index = index
def _make_comp_frame() -> psg.Frame:
comp_layout = [
[LabelSliderAdvanced(self.window, index, param, CompSlider)]
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))])
self.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"):
self.popup[f"COMPRESSOR||SLIDER {param}"].Widget.config(**buttonmenu_opts)
self.popup[f"COMPRESSOR||SLIDER {param}"].bind("<FocusIn>", "||FOCUS IN")
self.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"):
self.popup[f"COMPRESSOR||SLIDER {param}"].bind(
f"<{event}-{direction}>", f"||KEY {direction.upper()} {event_id}"
)
self.popup[f"COMPRESSOR||SLIDER {param}"].bind(
f"<Shift-{event}-{direction}>", f"||KEY SHIFT {direction.upper()} {event_id}"
)
self.popup[f"COMPRESSOR||SLIDER {param}"].bind(
f"<Control-{event}-{direction}>", f"||KEY CTRL {direction.upper()} {event_id}"
)
if param == "RELEASE":
self.popup[f"COMPRESSOR||SLIDER {param}"].bind(
f"<Alt-{event}-{direction}>", f"||KEY ALT {direction.upper()} {event_id}"
)
self.popup[f"COMPRESSOR||SLIDER {param}"].bind(
f"<Control-Alt-{event}-{direction}>", f"||KEY CTRL ALT {direction.upper()} {event_id}"
)
self.popup[f"COMPRESSOR||SLIDER {param}"].bind("<Control-Shift-KeyPress-R>", "||KEY CTRL SHIFT R")
self.popup["MAKEUP"].bind("<FocusIn>", "||FOCUS IN")
self.popup["MAKEUP"].bind("<Return>", "||KEY ENTER")
self.popup["Exit"].bind("<FocusIn>", "||FOCUS IN")
self.popup["Exit"].bind("<Return>", "||KEY ENTER")
self.window.vm.observer.add(self.on_pdirty)
while True:
event, values = self.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
val = CompSlider.check_bounds(param, val)
setattr(self.window.vm.strip[index].comp, param.lower(), val)
self.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
val = CompSlider.check_bounds(param, val)
setattr(self.window.vm.strip[index].comp, param.lower(), val)
self.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
val = CompSlider.check_bounds(param, val)
setattr(self.window.vm.strip[index].comp, param.lower(), val)
self.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
self.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
self.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
self.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
self.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
self.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", "SHIFT", "R"],
]:
if direction == "INPUT":
self.window.vm.strip[index].comp.gainin = 0
else:
self.window.vm.strip[index].comp.gainout = 0
self.popup[f"COMPRESSOR||SLIDER {direction} GAIN"].update(value=0)
self.window.nvda.speak(str(0))
case [["COMPRESSOR"], ["SLIDER", param], ["KEY", "CTRL", "SHIFT", "R"]]:
match param:
case "RATIO":
val = 1
case "THRESHOLD":
val = -20
case "ATTACK":
val = 10
case "RELEASE":
val = 50
case "KNEE":
val = 0.5
setattr(self.window.vm.strip[index].comp, param.lower(), val)
self.popup[f"COMPRESSOR||SLIDER {param}"].update(value=val)
self.window.nvda.speak(str(round(val, 1)))
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"]]:
self.popup.find_element_with_focus().click()
self.logger.debug(f"parsed::{parsed_cmd}")
self.window.vm.observer.remove(self.on_pdirty)
self.popup.close()
def gate(self, index, title=None):
self.index = index
def _make_gate_frame() -> psg.Frame:
gate_layout = [
[LabelSliderAdvanced(self.window, index, param, GateSlider)]
for param in ("THRESHOLD", "DAMPING", "BPSIDECHAIN", "ATTACK", "HOLD", "RELEASE")
]
return psg.Frame("ADVANCED GATE", gate_layout)
layout = []
steps = (_make_gate_frame,)
for step in steps:
layout.append([step()])
layout.append([psg.Button("Exit", size=(8, 1))])
self.popup = psg.Window(title, layout, return_keyboard_events=False, finalize=True)
buttonmenu_opts = {"takefocus": 1, "highlightthickness": 1}
for param in ("THRESHOLD", "DAMPING", "BPSIDECHAIN", "ATTACK", "HOLD", "RELEASE"):
self.popup[f"GATE||SLIDER {param}"].Widget.config(**buttonmenu_opts)
self.popup[f"GATE||SLIDER {param}"].bind("<FocusIn>", "||FOCUS IN")
self.popup[f"GATE||SLIDER {param}"].bind("<FocusOut>", "||FOCUS OUT")
for event in ("KeyPress", "KeyRelease"):
event_id = event.removeprefix("Key").upper()
for direction in ("Left", "Right", "Up", "Down"):
self.popup[f"GATE||SLIDER {param}"].bind(
f"<{event}-{direction}>", f"||KEY {direction.upper()} {event_id}"
)
self.popup[f"GATE||SLIDER {param}"].bind(
f"<Shift-{event}-{direction}>", f"||KEY SHIFT {direction.upper()} {event_id}"
)
self.popup[f"GATE||SLIDER {param}"].bind(
f"<Control-{event}-{direction}>", f"||KEY CTRL {direction.upper()} {event_id}"
)
if param in ("BPSIDECHAIN", "ATTACK", "HOLD", "RELEASE"):
self.popup[f"GATE||SLIDER {param}"].bind(
f"<Alt-{event}-{direction}>", f"||KEY ALT {direction.upper()} {event_id}"
)
self.popup[f"GATE||SLIDER {param}"].bind(
f"<Control-Alt-{event}-{direction}>", f"||KEY CTRL ALT {direction.upper()} {event_id}"
)
self.popup[f"GATE||SLIDER {param}"].bind("<Control-Shift-KeyPress-R>", "||KEY CTRL SHIFT R")
self.popup["Exit"].bind("<FocusIn>", "||FOCUS IN")
self.popup["Exit"].bind("<Return>", "||KEY ENTER")
self.window.vm.observer.add(self.on_pdirty)
while True:
event, values = self.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 [["GATE"], ["SLIDER", param]]:
setattr(self.window.vm.strip[index].gate, param.lower(), values[event])
case [["GATE"], ["SLIDER", param], ["FOCUS", "IN"]]:
label_map = {
"DAMPING": "Damping Max",
"BPSIDECHAIN": "BP Sidechain",
}
self.window.nvda.speak(f"{label_map.get(param, param)} {values[f'GATE||SLIDER {param}']}")
case [
["GATE"],
["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].gate, param.lower())
match input_direction:
case "RIGHT" | "UP":
val += 1
case "LEFT" | "DOWN":
val -= 1
val = GateSlider.check_bounds(param, val)
setattr(self.window.vm.strip[index].gate, param.lower(), val)
self.popup[f"GATE||SLIDER {param}"].update(value=val)
if param == "BPSIDECHAIN":
self.window.nvda.speak(str(int(val)))
else:
self.window.nvda.speak(str(round(val, 1)))
else:
self.window.vm.event.pdirty = True
case [
["GATE"],
["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].gate, param.lower())
match input_direction:
case "RIGHT" | "UP":
val += 3
case "LEFT" | "DOWN":
val -= 3
val = GateSlider.check_bounds(param, val)
setattr(self.window.vm.strip[index].gate, param.lower(), val)
self.popup[f"GATE||SLIDER {param}"].update(value=val)
if param == "BPSIDECHAIN":
self.window.nvda.speak(str(int(val)))
else:
self.window.nvda.speak(str(round(val, 1)))
else:
self.window.vm.event.pdirty = True
case [
["GATE"],
["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].gate, param.lower())
match input_direction:
case "RIGHT" | "UP":
val += 0.1
case "LEFT" | "DOWN":
val -= 0.1
val = GateSlider.check_bounds(param, val)
setattr(self.window.vm.strip[index].gate, param.lower(), val)
self.popup[f"GATE||SLIDER {param}"].update(value=val)
if param == "BPSIDECHAIN":
self.window.nvda.speak(str(int(val)))
else:
self.window.nvda.speak(str(round(val, 1)))
else:
self.window.vm.event.pdirty = True
case [
["GATE"],
["SLIDER", "BPSIDECHAIN" | "ATTACK" | "HOLD" | "RELEASE" as param],
["KEY", "ALT", "LEFT" | "RIGHT" as input_direction, "PRESS" | "RELEASE" as e],
]:
if e == "PRESS":
self.window.vm.event.pdirty = False
val = getattr(self.window.vm.strip[index].gate, param.lower())
match input_direction:
case "RIGHT" | "UP":
val += 10
case "LEFT" | "DOWN":
val -= 10
val = GateSlider.check_bounds(param, val)
setattr(self.window.vm.strip[index].gate, param.lower(), val)
self.popup[f"GATE||SLIDER {param}"].update(value=val)
if param == "BPSIDECHAIN":
self.window.nvda.speak(str(int(val)))
else:
self.window.nvda.speak(str(round(val, 1)))
else:
self.window.vm.event.pdirty = True
case [
["GATE"],
["SLIDER", "BPSIDECHAIN" | "ATTACK" | "HOLD" | "RELEASE" as param],
["KEY", "CTRL", "ALT", "LEFT" | "RIGHT" as input_direction, "PRESS" | "RELEASE" as e],
]:
if e == "PRESS":
self.window.vm.event.pdirty = False
val = getattr(self.window.vm.strip[index].gate, param.lower())
match input_direction:
case "RIGHT" | "UP":
val += 50
case "LEFT" | "DOWN":
val -= 50
val = GateSlider.check_bounds(param, val)
setattr(self.window.vm.strip[index].gate, param.lower(), val)
self.popup[f"GATE||SLIDER {param}"].update(value=val)
if param == "BPSIDECHAIN":
self.window.nvda.speak(str(int(val)))
else:
self.window.nvda.speak(str(round(val, 1)))
else:
self.window.vm.event.pdirty = True
case [["GATE"], ["SLIDER", param], ["KEY", "CTRL", "SHIFT", "R"]]:
match param:
case "THRESHOLD":
val = -60
case "DAMPING":
val = -60
case "BPSIDECHAIN":
val = 100
case "ATTACK":
val = 0
case "HOLD":
val = 500
case "RELEASE":
val = 1000
setattr(self.window.vm.strip[index].gate, param.lower(), val)
self.popup[f"GATE||SLIDER {param}"].update(value=val)
self.window.nvda.speak(str(round(val, 1)))
case [[button], ["FOCUS", "IN"]]:
self.window.nvda.speak(button)
case [_, ["KEY", "ENTER"]]:
self.popup.find_element_with_focus().click()
self.logger.debug(f"parsed::{parsed_cmd}")
self.window.vm.observer.remove(self.on_pdirty)
self.popup.close()