mirror of
https://github.com/onyx-and-iris/nvda-voicemeeter.git
synced 2026-04-07 18:03:35 +00:00
Compare commits
13 Commits
add-compre
...
implement-
| Author | SHA1 | Date | |
|---|---|---|---|
| 9cd65737e5 | |||
| 4a6ca2a353 | |||
| cc99b14e89 | |||
| 23458debaa | |||
| 496cc35321 | |||
| d758db9dee | |||
| 876de55ad2 | |||
| eab4b1c6a9 | |||
| 0aeb33608f | |||
| 5befe72ca1 | |||
| abab560281 | |||
| 6882adb47b | |||
| af602e087d |
18
README.md
18
README.md
@@ -107,12 +107,30 @@ 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 reset a slider back to its default value you may use `Control + Shift + R`.
|
||||||
|
|
||||||
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.
|
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`.
|
||||||
|
|
||||||
Pressing `Cancel` will close the popup window with no affect on the label.
|
Pressing `Cancel` will close the popup window with no affect on the label.
|
||||||
|
|
||||||
|
#### `Advanced Compressor|Gate`
|
||||||
|
|
||||||
|
For potato version only, you may access advanced Compressor and Gate sliders. Simply focus any Gate or Compressor slider and press `Control + A`. This will open a popup window where you can navigate between the different sliders with `TAB`. Move the sliders with the same binds you would for normal sliders. However, there are a couple of extra binds for certain controls.
|
||||||
|
|
||||||
|
For Compressor Release you may use:
|
||||||
|
|
||||||
|
- `Alt + Left|Right arrow` to move the slider by 10 steps.
|
||||||
|
- `Alt + Control + Left|Right arrow` to move the slider by 50 steps.
|
||||||
|
|
||||||
|
For Gate BP Sidechain, Attack, Hold, Release you may use:
|
||||||
|
|
||||||
|
- `Alt + Left|Right arrow` to move the slider by 10 steps.
|
||||||
|
- `Alt + Control + Left|Right arrow` to move the slider by 50 steps.
|
||||||
|
|
||||||
|
To reset a slider back to its default value you may use `Control + Shift + R`.
|
||||||
|
|
||||||
#### `Menu`
|
#### `Menu`
|
||||||
|
|
||||||
A single menu item `Voicemeeter` can be opened using `Alt` and then `v`. The menu allows you to:
|
A single menu item `Voicemeeter` can be opened using `Alt` and then `v`. The menu allows you to:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "nvda_voicemeeter"
|
name = "nvda_voicemeeter"
|
||||||
version = "0.4.2a1"
|
version = "0.5.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" },
|
||||||
@@ -35,16 +35,60 @@ shell = "build.ps1"
|
|||||||
line-length = 119
|
line-length = 119
|
||||||
|
|
||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
# Enable pycodestyle (`E`) and Pyflakes (`F`) codes by default.
|
select = [
|
||||||
select = ["E", "F"]
|
"E",
|
||||||
# Avoid enforcing line-length violations (`E501`). Let Black deal with this.
|
"F",
|
||||||
ignore = ["E501"]
|
]
|
||||||
|
ignore = [
|
||||||
# Allow autofix for all enabled rules (when `--fix`) is provided.
|
"E501",
|
||||||
fixable = ["A", "B", "C", "D", "E", "F", "G", "I", "N", "Q", "S", "T", "W", "ANN", "ARG", "BLE", "COM", "DJ", "DTZ", "EM", "ERA", "EXE", "FBT", "ICN", "INP", "ISC", "NPY", "PD", "PGH", "PIE", "PL", "PT", "PTH", "PYI", "RET", "RSE", "RUF", "SIM", "SLF", "TCH", "TID", "TRY", "UP", "YTT"]
|
]
|
||||||
|
fixable = [
|
||||||
|
"A",
|
||||||
|
"B",
|
||||||
|
"C",
|
||||||
|
"D",
|
||||||
|
"E",
|
||||||
|
"F",
|
||||||
|
"G",
|
||||||
|
"I",
|
||||||
|
"N",
|
||||||
|
"Q",
|
||||||
|
"S",
|
||||||
|
"T",
|
||||||
|
"W",
|
||||||
|
"ANN",
|
||||||
|
"ARG",
|
||||||
|
"BLE",
|
||||||
|
"COM",
|
||||||
|
"DJ",
|
||||||
|
"DTZ",
|
||||||
|
"EM",
|
||||||
|
"ERA",
|
||||||
|
"EXE",
|
||||||
|
"FBT",
|
||||||
|
"ICN",
|
||||||
|
"INP",
|
||||||
|
"ISC",
|
||||||
|
"NPY",
|
||||||
|
"PD",
|
||||||
|
"PGH",
|
||||||
|
"PIE",
|
||||||
|
"PL",
|
||||||
|
"PT",
|
||||||
|
"PTH",
|
||||||
|
"PYI",
|
||||||
|
"RET",
|
||||||
|
"RSE",
|
||||||
|
"RUF",
|
||||||
|
"SIM",
|
||||||
|
"SLF",
|
||||||
|
"TCH",
|
||||||
|
"TID",
|
||||||
|
"TRY",
|
||||||
|
"UP",
|
||||||
|
"YTT",
|
||||||
|
]
|
||||||
unfixable = []
|
unfixable = []
|
||||||
|
|
||||||
# Exclude a variety of commonly ignored directories.
|
|
||||||
exclude = [
|
exclude = [
|
||||||
".bzr",
|
".bzr",
|
||||||
".direnv",
|
".direnv",
|
||||||
@@ -68,19 +112,15 @@ exclude = [
|
|||||||
"node_modules",
|
"node_modules",
|
||||||
"venv",
|
"venv",
|
||||||
]
|
]
|
||||||
|
|
||||||
# Same as Black.
|
|
||||||
line-length = 119
|
line-length = 119
|
||||||
|
|
||||||
# Allow unused variables when underscore-prefixed.
|
|
||||||
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
|
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
|
||||||
|
|
||||||
# Assume Python 3.10
|
|
||||||
target-version = "py310"
|
target-version = "py310"
|
||||||
|
|
||||||
[tool.ruff.mccabe]
|
[tool.ruff.mccabe]
|
||||||
# Unlike Flake8, default to a complexity level of 10.
|
|
||||||
max-complexity = 10
|
max-complexity = 10
|
||||||
|
|
||||||
[tool.ruff.per-file-ignores]
|
[tool.ruff.per-file-ignores]
|
||||||
"__init__.py" = ["E402", "F401"] # Ignore unused import and variable not accessed violations
|
"__init__.py" = [
|
||||||
|
"E402",
|
||||||
|
"F401",
|
||||||
|
]
|
||||||
|
|||||||
@@ -478,18 +478,26 @@ class Builder:
|
|||||||
"""tab3 row represents bus composite toggle"""
|
"""tab3 row represents bus composite toggle"""
|
||||||
|
|
||||||
def add_strip_outputs(layout):
|
def add_strip_outputs(layout):
|
||||||
params = ["MONO", "EQ", "MUTE", "MODE"]
|
params = ["MONO", "EQ", "MUTE"]
|
||||||
if self.vm.kind.name == "basic":
|
if self.vm.kind.name == "basic":
|
||||||
params.remove("EQ")
|
params.remove("EQ")
|
||||||
label = {"MODE": "BUSMODE"}
|
busmodes = [util._bus_mode_map[mode] for mode in util.get_bus_modes(self.vm)]
|
||||||
layout.append(
|
layout.append(
|
||||||
[
|
[
|
||||||
psg.Button(
|
*[
|
||||||
label.get(param, param.capitalize()),
|
psg.Button(
|
||||||
size=(12 if param == "MODE" else 6, 2),
|
param.capitalize(),
|
||||||
key=f"BUS {i}||{param}",
|
size=(6, 2),
|
||||||
)
|
key=f"BUS {i}||{param}",
|
||||||
for param in params
|
)
|
||||||
|
for param in params
|
||||||
|
],
|
||||||
|
psg.ButtonMenu(
|
||||||
|
"BUSMODE",
|
||||||
|
size=(12, 2),
|
||||||
|
menu_def=["", busmodes],
|
||||||
|
key=f"BUS {i}||MODE",
|
||||||
|
),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ def get_nvdapath():
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
NVDA_PATH = Path(get_nvdapath()) / "nvda.exe"
|
NVDA_PATH = Path(get_nvdapath()) / "nvda.exe"
|
||||||
except FileNotFoundError as e:
|
except FileNotFoundError:
|
||||||
NVDA_PATH = ""
|
NVDA_PATH = ""
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
|
from typing import Union
|
||||||
|
|
||||||
import PySimpleGUI as psg
|
import PySimpleGUI as psg
|
||||||
|
|
||||||
|
from . import util
|
||||||
|
|
||||||
|
|
||||||
class LabelSlider(psg.Frame):
|
class LabelSlider(psg.Frame):
|
||||||
"""Compound Label Slider Strip element"""
|
"""Compound Label Slider Strip element"""
|
||||||
@@ -46,6 +50,7 @@ class CompSlider(psg.Slider):
|
|||||||
expand_x=True,
|
expand_x=True,
|
||||||
enable_events=True,
|
enable_events=True,
|
||||||
orientation="horizontal",
|
orientation="horizontal",
|
||||||
|
key=f"COMPRESSOR||SLIDER {param}",
|
||||||
**self.default_params(param),
|
**self.default_params(param),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -57,61 +62,144 @@ class CompSlider(psg.Slider):
|
|||||||
"default_value": self.vm.strip[self.index].comp.gainin,
|
"default_value": self.vm.strip[self.index].comp.gainin,
|
||||||
"resolution": 0.1,
|
"resolution": 0.1,
|
||||||
"disabled": True,
|
"disabled": True,
|
||||||
"key": f"COMPRESSOR||SLIDER {param}",
|
|
||||||
}
|
}
|
||||||
case "RATIO":
|
case "RATIO":
|
||||||
return {
|
return {
|
||||||
"range": (1, 8),
|
"range": (1, 8),
|
||||||
"default_value": self.vm.strip[self.index].comp.ratio,
|
"default_value": self.vm.strip[self.index].comp.ratio,
|
||||||
"resolution": 0.1,
|
"resolution": 0.1,
|
||||||
"key": f"COMPRESSOR||SLIDER {param}",
|
|
||||||
}
|
}
|
||||||
case "THRESHOLD":
|
case "THRESHOLD":
|
||||||
return {
|
return {
|
||||||
"range": (-40, -3),
|
"range": (-40, -3),
|
||||||
"default_value": self.vm.strip[self.index].comp.threshold,
|
"default_value": self.vm.strip[self.index].comp.threshold,
|
||||||
"resolution": 0.1,
|
"resolution": 0.1,
|
||||||
"key": f"COMPRESSOR||SLIDER {param}",
|
|
||||||
}
|
}
|
||||||
case "ATTACK":
|
case "ATTACK":
|
||||||
return {
|
return {
|
||||||
"range": (0, 200),
|
"range": (0, 200),
|
||||||
"default_value": self.vm.strip[self.index].comp.attack,
|
"default_value": self.vm.strip[self.index].comp.attack,
|
||||||
"resolution": 0.1,
|
"resolution": 0.1,
|
||||||
"key": f"COMPRESSOR||SLIDER {param}",
|
|
||||||
}
|
}
|
||||||
case "RELEASE":
|
case "RELEASE":
|
||||||
return {
|
return {
|
||||||
"range": (0, 5000),
|
"range": (0, 5000),
|
||||||
"default_value": self.vm.strip[self.index].comp.release,
|
"default_value": self.vm.strip[self.index].comp.release,
|
||||||
"resolution": 0.1,
|
"resolution": 0.1,
|
||||||
"key": f"COMPRESSOR||SLIDER {param}",
|
|
||||||
}
|
}
|
||||||
case "KNEE":
|
case "KNEE":
|
||||||
return {
|
return {
|
||||||
"range": (0, 1),
|
"range": (0, 1),
|
||||||
"default_value": self.vm.strip[self.index].comp.knee,
|
"default_value": self.vm.strip[self.index].comp.knee,
|
||||||
"resolution": 0.01,
|
"resolution": 0.01,
|
||||||
"key": f"COMPRESSOR||SLIDER {param}",
|
|
||||||
}
|
}
|
||||||
case "OUTPUT GAIN":
|
case "OUTPUT GAIN":
|
||||||
return {
|
return {
|
||||||
"range": (-24, 24),
|
"range": (-24, 24),
|
||||||
"default_value": self.vm.strip[self.index].comp.gainout,
|
"default_value": self.vm.strip[self.index].comp.gainout,
|
||||||
"resolution": 0.01,
|
"resolution": 0.1,
|
||||||
"disabled": True,
|
"disabled": True,
|
||||||
"key": f"COMPRESSOR||SLIDER {param}",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def check_bounds(param, val):
|
||||||
|
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))
|
||||||
|
return val
|
||||||
|
|
||||||
class LabelSliderCompressor(psg.Frame):
|
|
||||||
"""Compound Label Slider Compressor element"""
|
|
||||||
|
|
||||||
def __init__(self, parent, index, param, *args, **kwargs):
|
class GateSlider(psg.Slider):
|
||||||
|
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",
|
||||||
|
key=f"GATE||SLIDER {param}",
|
||||||
|
**self.default_params(param),
|
||||||
|
)
|
||||||
|
|
||||||
|
def default_params(self, param):
|
||||||
|
match param:
|
||||||
|
case "THRESHOLD":
|
||||||
|
return {
|
||||||
|
"range": (-60, -10),
|
||||||
|
"default_value": self.vm.strip[self.index].gate.threshold,
|
||||||
|
"resolution": 0.1,
|
||||||
|
}
|
||||||
|
case "DAMPING":
|
||||||
|
return {
|
||||||
|
"range": (-60, -10),
|
||||||
|
"default_value": self.vm.strip[self.index].gate.damping,
|
||||||
|
"resolution": 0.1,
|
||||||
|
}
|
||||||
|
case "BPSIDECHAIN":
|
||||||
|
return {
|
||||||
|
"range": (100, 4000),
|
||||||
|
"default_value": self.vm.strip[self.index].gate.bpsidechain,
|
||||||
|
"resolution": 1,
|
||||||
|
}
|
||||||
|
case "ATTACK":
|
||||||
|
return {
|
||||||
|
"range": (0, 1000),
|
||||||
|
"default_value": self.vm.strip[self.index].gate.attack,
|
||||||
|
"resolution": 0.1,
|
||||||
|
}
|
||||||
|
case "HOLD":
|
||||||
|
return {
|
||||||
|
"range": (0, 5000),
|
||||||
|
"default_value": self.vm.strip[self.index].gate.hold,
|
||||||
|
"resolution": 0.1,
|
||||||
|
}
|
||||||
|
case "RELEASE":
|
||||||
|
return {
|
||||||
|
"range": (0, 5000),
|
||||||
|
"default_value": self.vm.strip[self.index].gate.release,
|
||||||
|
"resolution": 0.1,
|
||||||
|
}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def check_bounds(param, val):
|
||||||
|
match param:
|
||||||
|
case "THRESHOLD":
|
||||||
|
val = util.check_bounds(val, (-60, -10))
|
||||||
|
case "DAMPING MAX":
|
||||||
|
val = util.check_bounds(val, (-60, -10))
|
||||||
|
case "BPSIDECHAIN":
|
||||||
|
val = util.check_bounds(val, (100, 4000))
|
||||||
|
case "ATTACK":
|
||||||
|
val = util.check_bounds(val, (0, 1000))
|
||||||
|
case "HOLD":
|
||||||
|
val = util.check_bounds(val, (0, 5000))
|
||||||
|
case "RELEASE":
|
||||||
|
val = util.check_bounds(val, (0, 5000))
|
||||||
|
return val
|
||||||
|
|
||||||
|
|
||||||
|
class LabelSliderAdvanced(psg.Frame):
|
||||||
|
"""Compound Label Slider element for Advanced Comp|Gate"""
|
||||||
|
|
||||||
|
def __init__(self, parent, index, param, slider_cls: Union[CompSlider, GateSlider], *args, **kwargs):
|
||||||
|
label_map = {
|
||||||
|
"DAMPING": "Damping Max",
|
||||||
|
"BPSIDECHAIN": "BP Sidechain",
|
||||||
|
}
|
||||||
|
|
||||||
layout = [
|
layout = [
|
||||||
[
|
[
|
||||||
psg.Text(param.capitalize(), size=8),
|
psg.Text(label_map.get(param, param.title()), size=10),
|
||||||
CompSlider(parent.vm, index, param),
|
slider_cls(parent.vm, index, param),
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
super().__init__(None, layout=layout, border_width=0, pad=0, *args, **kwargs)
|
super().__init__(None, layout=layout, border_width=0, pad=0, *args, **kwargs)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ def _make_hardware_ins_cache(vm) -> dict:
|
|||||||
def _make_hardware_outs_cache(vm) -> dict:
|
def _make_hardware_outs_cache(vm) -> dict:
|
||||||
hw_outs = {**{f"HARDWARE OUT||A{i + 1}": vm.bus[i].device.name for i in range(vm.kind.phys_out)}}
|
hw_outs = {**{f"HARDWARE OUT||A{i + 1}": vm.bus[i].device.name for i in range(vm.kind.phys_out)}}
|
||||||
if vm.kind.name == "basic":
|
if vm.kind.name == "basic":
|
||||||
hw_outs |= {f"HARDWARE OUT||A2": vm.bus[1].device.name}
|
hw_outs |= {"HARDWARE OUT||A2": vm.bus[1].device.name}
|
||||||
return hw_outs
|
return hw_outs
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from pathlib import Path
|
|||||||
import PySimpleGUI as psg
|
import PySimpleGUI as psg
|
||||||
|
|
||||||
from . import util
|
from . import util
|
||||||
from .compound import LabelSliderCompressor
|
from .compound import CompSlider, GateSlider, LabelSliderAdvanced
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -157,10 +157,26 @@ class Popup:
|
|||||||
self.logger.debug(f"parsed::{parsed_cmd}")
|
self.logger.debug(f"parsed::{parsed_cmd}")
|
||||||
popup.close()
|
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):
|
def compressor(self, index, title=None):
|
||||||
|
self.index = index
|
||||||
|
|
||||||
def _make_comp_frame() -> psg.Frame:
|
def _make_comp_frame() -> psg.Frame:
|
||||||
comp_layout = [
|
comp_layout = [
|
||||||
[LabelSliderCompressor(self.window, index, param)]
|
[LabelSliderAdvanced(self.window, index, param, CompSlider)]
|
||||||
for param in ("INPUT GAIN", "RATIO", "THRESHOLD", "ATTACK", "RELEASE", "KNEE", "OUTPUT GAIN")
|
for param in ("INPUT GAIN", "RATIO", "THRESHOLD", "ATTACK", "RELEASE", "KNEE", "OUTPUT GAIN")
|
||||||
]
|
]
|
||||||
return psg.Frame("ADVANCED COMPRESSOR", comp_layout)
|
return psg.Frame("ADVANCED COMPRESSOR", comp_layout)
|
||||||
@@ -171,37 +187,39 @@ class Popup:
|
|||||||
layout.append([step()])
|
layout.append([step()])
|
||||||
layout.append([psg.Button("MAKEUP", size=(12, 1)), psg.Button("Exit", size=(8, 1))])
|
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)
|
self.popup = psg.Window(title, layout, return_keyboard_events=False, finalize=True)
|
||||||
buttonmenu_opts = {"takefocus": 1, "highlightthickness": 1}
|
buttonmenu_opts = {"takefocus": 1, "highlightthickness": 1}
|
||||||
for param in ("INPUT GAIN", "RATIO", "THRESHOLD", "ATTACK", "RELEASE", "KNEE", "OUTPUT GAIN"):
|
for param in ("INPUT GAIN", "RATIO", "THRESHOLD", "ATTACK", "RELEASE", "KNEE", "OUTPUT GAIN"):
|
||||||
popup[f"COMPRESSOR||SLIDER {param}"].Widget.config(**buttonmenu_opts)
|
self.popup[f"COMPRESSOR||SLIDER {param}"].Widget.config(**buttonmenu_opts)
|
||||||
popup[f"COMPRESSOR||SLIDER {param}"].bind("<FocusIn>", "||FOCUS IN")
|
self.popup[f"COMPRESSOR||SLIDER {param}"].bind("<FocusIn>", "||FOCUS IN")
|
||||||
popup[f"COMPRESSOR||SLIDER {param}"].bind("<FocusOut>", "||FOCUS OUT")
|
self.popup[f"COMPRESSOR||SLIDER {param}"].bind("<FocusOut>", "||FOCUS OUT")
|
||||||
for event in ("KeyPress", "KeyRelease"):
|
for event in ("KeyPress", "KeyRelease"):
|
||||||
event_id = event.removeprefix("Key").upper()
|
event_id = event.removeprefix("Key").upper()
|
||||||
for direction in ("Left", "Right", "Up", "Down"):
|
for direction in ("Left", "Right", "Up", "Down"):
|
||||||
popup[f"COMPRESSOR||SLIDER {param}"].bind(
|
self.popup[f"COMPRESSOR||SLIDER {param}"].bind(
|
||||||
f"<{event}-{direction}>", f"||KEY {direction.upper()} {event_id}"
|
f"<{event}-{direction}>", f"||KEY {direction.upper()} {event_id}"
|
||||||
)
|
)
|
||||||
popup[f"COMPRESSOR||SLIDER {param}"].bind(
|
self.popup[f"COMPRESSOR||SLIDER {param}"].bind(
|
||||||
f"<Shift-{event}-{direction}>", f"||KEY SHIFT {direction.upper()} {event_id}"
|
f"<Shift-{event}-{direction}>", f"||KEY SHIFT {direction.upper()} {event_id}"
|
||||||
)
|
)
|
||||||
popup[f"COMPRESSOR||SLIDER {param}"].bind(
|
self.popup[f"COMPRESSOR||SLIDER {param}"].bind(
|
||||||
f"<Control-{event}-{direction}>", f"||KEY CTRL {direction.upper()} {event_id}"
|
f"<Control-{event}-{direction}>", f"||KEY CTRL {direction.upper()} {event_id}"
|
||||||
)
|
)
|
||||||
if param == "RELEASE":
|
if param == "RELEASE":
|
||||||
popup[f"COMPRESSOR||SLIDER {param}"].bind(
|
self.popup[f"COMPRESSOR||SLIDER {param}"].bind(
|
||||||
f"<Alt-{event}-{direction}>", f"||KEY ALT {direction.upper()} {event_id}"
|
f"<Alt-{event}-{direction}>", f"||KEY ALT {direction.upper()} {event_id}"
|
||||||
)
|
)
|
||||||
popup[f"COMPRESSOR||SLIDER {param}"].bind(
|
self.popup[f"COMPRESSOR||SLIDER {param}"].bind(
|
||||||
f"<Control-Alt-{event}-{direction}>", f"||KEY CTRL ALT {direction.upper()} {event_id}"
|
f"<Control-Alt-{event}-{direction}>", f"||KEY CTRL ALT {direction.upper()} {event_id}"
|
||||||
)
|
)
|
||||||
popup["MAKEUP"].bind("<FocusIn>", "||FOCUS IN")
|
self.popup[f"COMPRESSOR||SLIDER {param}"].bind("<Control-Shift-KeyPress-R>", "||KEY CTRL SHIFT R")
|
||||||
popup["MAKEUP"].bind("<Return>", "||KEY ENTER")
|
self.popup["MAKEUP"].bind("<FocusIn>", "||FOCUS IN")
|
||||||
popup["Exit"].bind("<FocusIn>", "||FOCUS IN")
|
self.popup["MAKEUP"].bind("<Return>", "||KEY ENTER")
|
||||||
popup["Exit"].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:
|
while True:
|
||||||
event, values = popup.read()
|
event, values = self.popup.read()
|
||||||
self.logger.debug(f"event::{event}")
|
self.logger.debug(f"event::{event}")
|
||||||
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"):
|
||||||
@@ -232,20 +250,10 @@ class Popup:
|
|||||||
else:
|
else:
|
||||||
val -= 1
|
val -= 1
|
||||||
|
|
||||||
match param:
|
val = CompSlider.check_bounds(param, val)
|
||||||
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)
|
setattr(self.window.vm.strip[index].comp, param.lower(), val)
|
||||||
popup[f"COMPRESSOR||SLIDER {param}"].update(value=val)
|
self.popup[f"COMPRESSOR||SLIDER {param}"].update(value=val)
|
||||||
if param == "KNEE":
|
if param == "KNEE":
|
||||||
self.window.nvda.speak(str(round(val, 2)))
|
self.window.nvda.speak(str(round(val, 2)))
|
||||||
else:
|
else:
|
||||||
@@ -277,20 +285,10 @@ class Popup:
|
|||||||
else:
|
else:
|
||||||
val -= 3
|
val -= 3
|
||||||
|
|
||||||
match param:
|
val = CompSlider.check_bounds(param, val)
|
||||||
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)
|
setattr(self.window.vm.strip[index].comp, param.lower(), val)
|
||||||
popup[f"COMPRESSOR||SLIDER {param}"].update(value=val)
|
self.popup[f"COMPRESSOR||SLIDER {param}"].update(value=val)
|
||||||
if param == "KNEE":
|
if param == "KNEE":
|
||||||
self.window.nvda.speak(str(round(val, 2)))
|
self.window.nvda.speak(str(round(val, 2)))
|
||||||
else:
|
else:
|
||||||
@@ -318,20 +316,10 @@ class Popup:
|
|||||||
else:
|
else:
|
||||||
val -= 0.1
|
val -= 0.1
|
||||||
|
|
||||||
match param:
|
val = CompSlider.check_bounds(param, val)
|
||||||
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)
|
setattr(self.window.vm.strip[index].comp, param.lower(), val)
|
||||||
popup[f"COMPRESSOR||SLIDER {param}"].update(value=val)
|
self.popup[f"COMPRESSOR||SLIDER {param}"].update(value=val)
|
||||||
if param == "KNEE":
|
if param == "KNEE":
|
||||||
self.window.nvda.speak(str(round(val, 2)))
|
self.window.nvda.speak(str(round(val, 2)))
|
||||||
else:
|
else:
|
||||||
@@ -355,7 +343,7 @@ class Popup:
|
|||||||
|
|
||||||
val = util.check_bounds(val, (0, 5000))
|
val = util.check_bounds(val, (0, 5000))
|
||||||
self.window.vm.strip[index].comp.release = val
|
self.window.vm.strip[index].comp.release = val
|
||||||
popup[f"COMPRESSOR||SLIDER {param}"].update(value=val)
|
self.popup[f"COMPRESSOR||SLIDER {param}"].update(value=val)
|
||||||
self.window.nvda.speak(str(round(val, 1)))
|
self.window.nvda.speak(str(round(val, 1)))
|
||||||
else:
|
else:
|
||||||
self.window.vm.event.pdirty = True
|
self.window.vm.event.pdirty = True
|
||||||
@@ -376,7 +364,7 @@ class Popup:
|
|||||||
|
|
||||||
val = util.check_bounds(val, (0, 5000))
|
val = util.check_bounds(val, (0, 5000))
|
||||||
self.window.vm.strip[index].comp.release = val
|
self.window.vm.strip[index].comp.release = val
|
||||||
popup[f"COMPRESSOR||SLIDER {param}"].update(value=val)
|
self.popup[f"COMPRESSOR||SLIDER {param}"].update(value=val)
|
||||||
self.window.nvda.speak(str(round(val, 1)))
|
self.window.nvda.speak(str(round(val, 1)))
|
||||||
else:
|
else:
|
||||||
self.window.vm.event.pdirty = True
|
self.window.vm.event.pdirty = True
|
||||||
@@ -412,7 +400,7 @@ class Popup:
|
|||||||
self.window.vm.strip[index].comp.gainin = val
|
self.window.vm.strip[index].comp.gainin = val
|
||||||
else:
|
else:
|
||||||
self.window.vm.strip[index].comp.gainout = val
|
self.window.vm.strip[index].comp.gainout = val
|
||||||
popup[f"COMPRESSOR||SLIDER {direction} GAIN"].update(value=val)
|
self.popup[f"COMPRESSOR||SLIDER {direction} GAIN"].update(value=val)
|
||||||
self.window.nvda.speak(str(round(val, 1)))
|
self.window.nvda.speak(str(round(val, 1)))
|
||||||
else:
|
else:
|
||||||
self.window.vm.event.pdirty = True
|
self.window.vm.event.pdirty = True
|
||||||
@@ -439,7 +427,7 @@ class Popup:
|
|||||||
self.window.vm.strip[index].comp.gainin = val
|
self.window.vm.strip[index].comp.gainin = val
|
||||||
else:
|
else:
|
||||||
self.window.vm.strip[index].comp.gainout = val
|
self.window.vm.strip[index].comp.gainout = val
|
||||||
popup[f"COMPRESSOR||SLIDER {direction} GAIN"].update(value=val)
|
self.popup[f"COMPRESSOR||SLIDER {direction} GAIN"].update(value=val)
|
||||||
self.window.nvda.speak(str(round(val, 1)))
|
self.window.nvda.speak(str(round(val, 1)))
|
||||||
else:
|
else:
|
||||||
self.window.vm.event.pdirty = True
|
self.window.vm.event.pdirty = True
|
||||||
@@ -466,21 +454,262 @@ class Popup:
|
|||||||
self.window.vm.strip[index].comp.gainin = val
|
self.window.vm.strip[index].comp.gainin = val
|
||||||
else:
|
else:
|
||||||
self.window.vm.strip[index].comp.gainout = val
|
self.window.vm.strip[index].comp.gainout = val
|
||||||
popup[f"COMPRESSOR||SLIDER {direction} GAIN"].update(value=val)
|
self.popup[f"COMPRESSOR||SLIDER {direction} GAIN"].update(value=val)
|
||||||
self.window.nvda.speak(str(round(val, 1)))
|
self.window.nvda.speak(str(round(val, 1)))
|
||||||
else:
|
else:
|
||||||
self.window.vm.event.pdirty = True
|
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"]:
|
case ["MAKEUP"]:
|
||||||
val = not self.window.vm.strip[index].comp.makeup
|
val = not self.window.vm.strip[index].comp.makeup
|
||||||
self.window.vm.strip[index].comp.makeup = val
|
self.window.vm.strip[index].comp.makeup = val
|
||||||
self.window.nvda.speak("on" if val else "off")
|
self.window.nvda.speak("on" if val else "off")
|
||||||
case [[button], ["FOCUS", "IN"]]:
|
case [[button], ["FOCUS", "IN"]]:
|
||||||
if button == "MAKEUP":
|
if button == "MAKEUP":
|
||||||
self.window.nvda.speak(f"{button} {'on' if self.window.vm.strip[index].comp.makeup else 'off'}")
|
self.window.nvda.speak(
|
||||||
|
f"{button} {'on' if self.window.vm.strip[index].comp.makeup else 'off'}"
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
self.window.nvda.speak(button)
|
self.window.nvda.speak(button)
|
||||||
case [_, ["KEY", "ENTER"]]:
|
case [_, ["KEY", "ENTER"]]:
|
||||||
popup.find_element_with_focus().click()
|
self.popup.find_element_with_focus().click()
|
||||||
self.logger.debug(f"parsed::{parsed_cmd}")
|
self.logger.debug(f"parsed::{parsed_cmd}")
|
||||||
popup.close()
|
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()
|
||||||
|
|||||||
@@ -48,8 +48,11 @@ def get_patch_composite_list(kind) -> list:
|
|||||||
for i in range(kind.phys_out):
|
for i in range(kind.phys_out):
|
||||||
[temp.append(f"IN#{i + 1} {channel}") for channel in ("Left", "Right")]
|
[temp.append(f"IN#{i + 1} {channel}") for channel in ("Left", "Right")]
|
||||||
for i in range(kind.phys_out, kind.phys_out + kind.virt_out):
|
for i in range(kind.phys_out, kind.phys_out + kind.virt_out):
|
||||||
[temp.append(f"IN#{i + 1} {channel}") for channel in ("Left", "Right", "Center", "LFE", "SL", "SR", "BL", "BR")]
|
[
|
||||||
temp.append(f"BUS Channel")
|
temp.append(f"IN#{i + 1} {channel}")
|
||||||
|
for channel in ("Left", "Right", "Center", "LFE", "SL", "SR", "BL", "BR")
|
||||||
|
]
|
||||||
|
temp.append("BUS Channel")
|
||||||
return temp
|
return temp
|
||||||
|
|
||||||
|
|
||||||
@@ -108,6 +111,24 @@ def get_channel_identifier_list(vm) -> list:
|
|||||||
return identifiers
|
return identifiers
|
||||||
|
|
||||||
|
|
||||||
|
_bus_mode_map = {
|
||||||
|
"normal": "Normal",
|
||||||
|
"amix": "Mix Down A",
|
||||||
|
"bmix": "Mix Down B",
|
||||||
|
"repeat": "Stereo Repeat",
|
||||||
|
"composite": "Composite",
|
||||||
|
"tvmix": "Up Mix TV",
|
||||||
|
"upmix21": "Up Mix 2.1",
|
||||||
|
"upmix41": "Up Mix 4.1",
|
||||||
|
"upmix61": "Up Mix 6.1",
|
||||||
|
"centeronly": "Center Only",
|
||||||
|
"lfeonly": "Low Frequency Effect Only",
|
||||||
|
"rearonly": "Rear Only",
|
||||||
|
}
|
||||||
|
|
||||||
|
_bus_mode_map_reversed = dict((reversed(item) for item in _bus_mode_map.items()))
|
||||||
|
|
||||||
|
|
||||||
def get_bus_modes(vm) -> list:
|
def get_bus_modes(vm) -> list:
|
||||||
if vm.kind.name == "basic":
|
if vm.kind.name == "basic":
|
||||||
return [
|
return [
|
||||||
@@ -157,3 +178,17 @@ def get_full_slider_params(i, kind) -> Iterable:
|
|||||||
if kind.name == "basic":
|
if kind.name == "basic":
|
||||||
params.remove("LIMIT")
|
params.remove("LIMIT")
|
||||||
return params
|
return params
|
||||||
|
|
||||||
|
|
||||||
|
def get_slider_modes() -> Iterable:
|
||||||
|
return (
|
||||||
|
"GAIN MODE",
|
||||||
|
"BASS MODE",
|
||||||
|
"MID MODE",
|
||||||
|
"TREBLE MODE",
|
||||||
|
"AUDIBILITY MODE",
|
||||||
|
"COMP MODE",
|
||||||
|
"GATE MODE",
|
||||||
|
"DENOISER MODE",
|
||||||
|
"LIMIT MODE",
|
||||||
|
)
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ class NVDAVMWindow(psg.Window):
|
|||||||
for i in range(self.kind.phys_out):
|
for i in range(self.kind.phys_out):
|
||||||
self[f"HARDWARE OUT||A{i + 1}"].Widget.config(**buttonmenu_opts)
|
self[f"HARDWARE OUT||A{i + 1}"].Widget.config(**buttonmenu_opts)
|
||||||
if self.kind.name == "basic":
|
if self.kind.name == "basic":
|
||||||
self[f"HARDWARE OUT||A2"].Widget.config(**buttonmenu_opts)
|
self["HARDWARE OUT||A2"].Widget.config(**buttonmenu_opts)
|
||||||
if self.kind.name != "basic":
|
if self.kind.name != "basic":
|
||||||
[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}
|
||||||
@@ -57,6 +57,7 @@ class NVDAVMWindow(psg.Window):
|
|||||||
self[f"STRIP {i}||SLIDER LIMIT"].Widget.config(**slider_opts)
|
self[f"STRIP {i}||SLIDER LIMIT"].Widget.config(**slider_opts)
|
||||||
for i in range(self.kind.num_bus):
|
for i in range(self.kind.num_bus):
|
||||||
self[f"BUS {i}||SLIDER GAIN"].Widget.config(**slider_opts)
|
self[f"BUS {i}||SLIDER GAIN"].Widget.config(**slider_opts)
|
||||||
|
self[f"BUS {i}||MODE"].Widget.config(**buttonmenu_opts)
|
||||||
if self.kind.name != "basic":
|
if self.kind.name != "basic":
|
||||||
for i in range(self.kind.phys_out):
|
for i in range(self.kind.phys_out):
|
||||||
self[f"ASIO CHECKBOX||IN{i + 1} 0"].Widget.config(state="readonly")
|
self[f"ASIO CHECKBOX||IN{i + 1} 0"].Widget.config(state="readonly")
|
||||||
@@ -190,9 +191,9 @@ class NVDAVMWindow(psg.Window):
|
|||||||
self[f"HARDWARE OUT||A{i + 1}"].bind("<space>", "||KEY SPACE", propagate=False)
|
self[f"HARDWARE OUT||A{i + 1}"].bind("<space>", "||KEY SPACE", propagate=False)
|
||||||
self[f"HARDWARE OUT||A{i + 1}"].bind("<Return>", "||KEY ENTER", propagate=False)
|
self[f"HARDWARE OUT||A{i + 1}"].bind("<Return>", "||KEY ENTER", propagate=False)
|
||||||
if self.vm.kind.name == "basic":
|
if self.vm.kind.name == "basic":
|
||||||
self[f"HARDWARE OUT||A2"].bind("<FocusIn>", "||FOCUS IN")
|
self["HARDWARE OUT||A2"].bind("<FocusIn>", "||FOCUS IN")
|
||||||
self[f"HARDWARE OUT||A2"].bind("<space>", "||KEY SPACE", propagate=False)
|
self["HARDWARE OUT||A2"].bind("<space>", "||KEY SPACE", propagate=False)
|
||||||
self[f"HARDWARE OUT||A2"].bind("<Return>", "||KEY ENTER", propagate=False)
|
self["HARDWARE OUT||A2"].bind("<Return>", "||KEY ENTER", propagate=False)
|
||||||
|
|
||||||
# Patch ASIO
|
# Patch ASIO
|
||||||
if self.kind.name != "basic":
|
if self.kind.name != "basic":
|
||||||
@@ -260,13 +261,16 @@ class NVDAVMWindow(psg.Window):
|
|||||||
self[f"STRIP {i}||SLIDER {param}"].bind("<Control-Shift-KeyPress-R>", "||KEY CTRL SHIFT R")
|
self[f"STRIP {i}||SLIDER {param}"].bind("<Control-Shift-KeyPress-R>", "||KEY CTRL SHIFT R")
|
||||||
|
|
||||||
# Bus Params
|
# Bus Params
|
||||||
params = ["MONO", "EQ", "MUTE", "MODE"]
|
params = ["MONO", "EQ", "MUTE"]
|
||||||
if self.vm.kind.name == "basic":
|
if self.vm.kind.name == "basic":
|
||||||
params.remove("EQ")
|
params.remove("EQ")
|
||||||
for i in range(self.kind.num_bus):
|
for i in range(self.kind.num_bus):
|
||||||
for param in params:
|
for param in params:
|
||||||
self[f"BUS {i}||{param}"].bind("<FocusIn>", "||FOCUS IN")
|
self[f"BUS {i}||{param}"].bind("<FocusIn>", "||FOCUS IN")
|
||||||
self[f"BUS {i}||{param}"].bind("<Return>", "||KEY ENTER")
|
self[f"BUS {i}||{param}"].bind("<Return>", "||KEY ENTER")
|
||||||
|
self[f"BUS {i}||MODE"].bind("<FocusIn>", "||FOCUS IN")
|
||||||
|
self[f"BUS {i}||MODE"].bind("<space>", "||KEY SPACE", propagate=False)
|
||||||
|
self[f"BUS {i}||MODE"].bind("<Return>", "||KEY ENTER", propagate=False)
|
||||||
|
|
||||||
# Bus Sliders
|
# Bus Sliders
|
||||||
for i in range(self.kind.num_bus):
|
for i in range(self.kind.num_bus):
|
||||||
@@ -300,13 +304,15 @@ 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.endswith("MODE"):
|
elif event in util.get_slider_modes():
|
||||||
mode = event
|
mode = event
|
||||||
self.nvda.speak(f"{mode} enabled")
|
self.nvda.speak(f"{mode} enabled")
|
||||||
|
self.logger.debug(f"entered slider mode {mode}")
|
||||||
continue
|
continue
|
||||||
elif event == "ESCAPE":
|
elif event == "ESCAPE":
|
||||||
if mode:
|
if mode:
|
||||||
self.nvda.speak(f"{mode} disabled")
|
self.nvda.speak(f"{mode} disabled")
|
||||||
|
self.logger.debug(f"exited from slider mode {mode}")
|
||||||
mode = None
|
mode = None
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@@ -423,7 +429,7 @@ class NVDAVMWindow(psg.Window):
|
|||||||
identifier, partial = focus.Key.split("||")
|
identifier, partial = focus.Key.split("||")
|
||||||
_, index = identifier.split()
|
_, index = identifier.split()
|
||||||
index = int(index)
|
index = int(index)
|
||||||
data = self.popup.rename("Label", index, title=f"Rename", tab=tab)
|
data = self.popup.rename("Label", index, title="Rename", tab=tab)
|
||||||
if not data: # cancel was pressed
|
if not data: # cancel was pressed
|
||||||
continue
|
continue
|
||||||
match tab:
|
match tab:
|
||||||
@@ -456,8 +462,12 @@ class NVDAVMWindow(psg.Window):
|
|||||||
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()
|
_, index = identifier.split()
|
||||||
if "SLIDER COMP" in partial:
|
match self.kind.name:
|
||||||
self.popup.compressor(int(index), title="Advanced Compressor")
|
case "potato":
|
||||||
|
if "SLIDER COMP" in partial:
|
||||||
|
self.popup.compressor(int(index), title="Advanced Compressor")
|
||||||
|
elif "SLIDER GATE" in partial:
|
||||||
|
self.popup.gate(int(index), title="Advanced Gate")
|
||||||
|
|
||||||
# Menus
|
# Menus
|
||||||
case [["Restart", "Audio", "Engine"], ["MENU"]]:
|
case [["Restart", "Audio", "Engine"], ["MENU"]]:
|
||||||
@@ -960,6 +970,7 @@ class NVDAVMWindow(psg.Window):
|
|||||||
self.vm.strip[int(index)].gain = 0
|
self.vm.strip[int(index)].gain = 0
|
||||||
self[f"STRIP {index}||SLIDER {param}"].update(value=0)
|
self[f"STRIP {index}||SLIDER {param}"].update(value=0)
|
||||||
case "COMP" | "GATE" | "DENOISER":
|
case "COMP" | "GATE" | "DENOISER":
|
||||||
|
target = getattr(self.vm.strip[int(index)], param.lower())
|
||||||
setattr(target, "knob", 0)
|
setattr(target, "knob", 0)
|
||||||
self[f"STRIP {index}||SLIDER {param}"].update(value=0)
|
self[f"STRIP {index}||SLIDER {param}"].update(value=0)
|
||||||
case "AUDIBILITY":
|
case "AUDIBILITY":
|
||||||
@@ -971,7 +982,7 @@ class NVDAVMWindow(psg.Window):
|
|||||||
case "LIMIT":
|
case "LIMIT":
|
||||||
self.vm.strip[int(index)].limit = 12
|
self.vm.strip[int(index)].limit = 12
|
||||||
self[f"STRIP {index}||SLIDER {param}"].update(value=12)
|
self[f"STRIP {index}||SLIDER {param}"].update(value=12)
|
||||||
self.nvda.speak(f"{param} {12 if param == 'LABEL' else 0}")
|
self.nvda.speak(f"{12 if param == 'LIMIT' else 0}")
|
||||||
|
|
||||||
# Bus Params
|
# Bus Params
|
||||||
case [["BUS", index], [param]]:
|
case [["BUS", index], [param]]:
|
||||||
@@ -997,40 +1008,27 @@ class NVDAVMWindow(psg.Window):
|
|||||||
"on" if val else "off",
|
"on" if val else "off",
|
||||||
)
|
)
|
||||||
case "MODE":
|
case "MODE":
|
||||||
bus_modes = util.get_bus_modes(self.vm)
|
chosen = util._bus_mode_map_reversed[values[event]]
|
||||||
next_index = bus_modes.index(val) + 1
|
setattr(self.vm.bus[int(index)].mode, chosen, True)
|
||||||
if next_index == len(bus_modes):
|
self.cache["bus"][event] = chosen
|
||||||
next_index = 0
|
|
||||||
next_bus = bus_modes[next_index]
|
|
||||||
phonetic = {
|
|
||||||
"amix": "Mix Down A",
|
|
||||||
"bmix": "Mix Down B",
|
|
||||||
"repeat": "Stereo Repeat",
|
|
||||||
"tvmix": "Up Mix TV",
|
|
||||||
"upmix21": "Up Mix 2.1",
|
|
||||||
"upmix41": "Up Mix 4.1",
|
|
||||||
"upmix61": "Up Mix 6.1",
|
|
||||||
"centeronly": "Center Only",
|
|
||||||
"lfeonly": "Low Frequency Effect Only",
|
|
||||||
"rearonly": "Rear Only",
|
|
||||||
}
|
|
||||||
setattr(self.vm.bus[int(index)].mode, next_bus, True)
|
|
||||||
self.cache["bus"][event] = next_bus
|
|
||||||
self.TKroot.after(
|
self.TKroot.after(
|
||||||
200,
|
200,
|
||||||
self.nvda.speak,
|
self.nvda.speak,
|
||||||
phonetic.get(next_bus, next_bus),
|
util._bus_mode_map[chosen],
|
||||||
)
|
)
|
||||||
case [["BUS", index], [param], ["FOCUS", "IN"]]:
|
case [["BUS", index], [param], ["FOCUS", "IN"]]:
|
||||||
if self.find_element_with_focus() is not None:
|
if self.find_element_with_focus() is not None:
|
||||||
label = self.cache["labels"][f"BUS {index}||LABEL"]
|
label = self.cache["labels"][f"BUS {index}||LABEL"]
|
||||||
val = self.cache["bus"][f"BUS {index}||{param}"]
|
val = self.cache["bus"][f"BUS {index}||{param}"]
|
||||||
if param == "MODE":
|
if param == "MODE":
|
||||||
self.nvda.speak(f"{label} bus {param} {val}")
|
self.nvda.speak(f"{label} bus {param} {util._bus_mode_map[val]}")
|
||||||
else:
|
else:
|
||||||
self.nvda.speak(f"{label} bus {param} {'on' if val else 'off'}")
|
self.nvda.speak(f"{label} {param} {'on' if val else 'off'}")
|
||||||
case [["BUS", index], [param], ["KEY", "ENTER"]]:
|
case [["BUS", index], [param], ["KEY", "SPACE" | "ENTER"]]:
|
||||||
self.find_element_with_focus().click()
|
if param == "MODE":
|
||||||
|
util.open_context_menu_for_buttonmenu(self, f"BUS {index}||MODE")
|
||||||
|
else:
|
||||||
|
self.find_element_with_focus().click()
|
||||||
|
|
||||||
# Bus Sliders
|
# Bus Sliders
|
||||||
case [["BUS", index], ["SLIDER", "GAIN"]]:
|
case [["BUS", index], ["SLIDER", "GAIN"]]:
|
||||||
@@ -1104,7 +1102,7 @@ class NVDAVMWindow(psg.Window):
|
|||||||
case [["BUS", index], ["SLIDER", "GAIN"], ["KEY", "CTRL", "SHIFT", "R"]]:
|
case [["BUS", index], ["SLIDER", "GAIN"], ["KEY", "CTRL", "SHIFT", "R"]]:
|
||||||
self.vm.bus[int(index)].gain = 0
|
self.vm.bus[int(index)].gain = 0
|
||||||
self[f"BUS {index}||SLIDER GAIN"].update(value=0)
|
self[f"BUS {index}||SLIDER GAIN"].update(value=0)
|
||||||
self.nvda.speak(str(val))
|
self.nvda.speak(str(0))
|
||||||
|
|
||||||
# Unknown
|
# Unknown
|
||||||
case _:
|
case _:
|
||||||
|
|||||||
Reference in New Issue
Block a user