diff --git a/src/nvda_voicemeeter/builder.py b/src/nvda_voicemeeter/builder.py index 88576a5..0727db1 100644 --- a/src/nvda_voicemeeter/builder.py +++ b/src/nvda_voicemeeter/builder.py @@ -5,6 +5,7 @@ from .util import ( get_asio_samples_list, get_input_device_list, get_insert_checkbox_index, + get_output_device_list, get_patch_composite_list, get_tabs_labels, ) @@ -23,7 +24,10 @@ class Builder: layout0 = [] if self.kind.name == "basic": - steps = (self.make_tab0_row0,) + steps = ( + self.make_tab0_row0, + self.make_tab0_row1, + ) else: steps = ( self.make_tab0_row0, @@ -31,6 +35,7 @@ class Builder: self.make_tab0_row2, self.make_tab0_row3, self.make_tab0_row4, + self.make_tab0_row5, ) for step in steps: layout0.append([step()]) @@ -72,11 +77,33 @@ class Builder: return psg.Menu(menu_def, key="menus") def make_tab0_row0(self) -> psg.Frame: - """tab0 row0 represents hardware outs""" + """tab0 row0 represents hardware ins""" def add_physical_device_opts(layout): devices = get_input_device_list(self.vm) devices.append("- remove device selection -") + layout.append( + [ + psg.ButtonMenu( + f"IN {i + 1}", + size=(6, 3), + menu_def=["", devices], + key=f"HARDWARE IN||{i + 1}", + ) + for i in range(self.kind.phys_in) + ] + ) + + hardware_in = list() + [step(hardware_in) for step in (add_physical_device_opts,)] + return psg.Frame("Hardware In", hardware_in) + + def make_tab0_row1(self) -> psg.Frame: + """tab0 row1 represents hardware outs""" + + def add_physical_device_opts(layout): + devices = get_output_device_list(self.vm) + devices.append("- remove device selection -") if self.kind.name == "basic": num_outs = self.kind.phys_out + self.kind.virt_out else: @@ -97,8 +124,8 @@ class Builder: [step(hardware_out) for step in (add_physical_device_opts,)] return psg.Frame("Hardware Out", hardware_out) - def make_tab0_row1(self) -> psg.Frame: - """tab0 row1 represents patch asio inputs to strips""" + def make_tab0_row2(self) -> psg.Frame: + """tab0 row2 represents patch asio inputs to strips""" def add_asio_checkboxes(layout, i): nums = list(range(99)) @@ -134,8 +161,8 @@ class Builder: asio_checkboxes = [inner] return psg.Frame("PATCH ASIO Inputs to Strips", asio_checkboxes) - def make_tab0_row2(self) -> psg.Frame: - """tab0 row2 represents patch composite""" + def make_tab0_row3(self) -> psg.Frame: + """tab0 row3 represents patch composite""" def add_physical_device_opts(layout): outputs = get_patch_composite_list(self.vm.kind) @@ -155,8 +182,8 @@ class Builder: [step(hardware_out) for step in (add_physical_device_opts,)] return psg.Frame("PATCH COMPOSITE", hardware_out) - def make_tab0_row3(self) -> psg.Frame: - """tab0 row3 represents patch insert""" + def make_tab0_row4(self) -> psg.Frame: + """tab0 row4 represents patch insert""" def add_insert_checkboxes(layout, i): if i <= self.kind.phys_in: @@ -200,8 +227,8 @@ class Builder: return psg.Frame("PATCH INSERT", asio_checkboxes) - def make_tab0_row4(self) -> psg.Frame: - """tab0 row4 represents asio buffer""" + def make_tab0_row5(self) -> psg.Frame: + """tab0 row5 represents asio buffer""" samples = get_asio_samples_list() samples.append("Default") @@ -218,6 +245,7 @@ class Builder: ) ] ], + key="ASIO BUFFER FRAME", ) def make_tab1_row(self, i) -> psg.Frame: @@ -234,7 +262,14 @@ class Builder: else f"STRIP {i}||B{j - self.kind.phys_out + 1}", ) for j in range(self.kind.phys_out + self.kind.virt_out) - ] + ], + ) + layout.append( + [ + psg.Button("Mono", size=(6, 2), key=f"STRIP {i}||MONO"), + psg.Button("Solo", size=(6, 2), key=f"STRIP {i}||SOLO"), + psg.Button("Mute", size=(6, 2), key=f"STRIP {i}||MUTE"), + ], ) outputs = list() @@ -261,6 +296,22 @@ class Builder: for j in range(self.kind.phys_out + self.kind.virt_out) ] ) + if i == self.kind.phys_in + self.kind.virt_in - 2: + layout.append( + [ + psg.Button("K", size=(6, 2), key=f"STRIP {i}||MONO"), + psg.Button("Solo", size=(6, 2), key=f"STRIP {i}||SOLO"), + psg.Button("Mute", size=(6, 2), key=f"STRIP {i}||MUTE"), + ], + ) + else: + layout.append( + [ + psg.Button("MC", size=(6, 2), key=f"STRIP {i}||MONO"), + psg.Button("Solo", size=(6, 2), key=f"STRIP {i}||SOLO"), + psg.Button("Mute", size=(6, 2), key=f"STRIP {i}||MUTE"), + ], + ) outputs = list() [step(outputs) for step in (add_strip_outputs,)] @@ -274,7 +325,14 @@ class Builder: """tab3 row represents bus composite toggle""" def add_strip_outputs(layout): - layout.append([psg.Button(f"BUSMODE", size=(12, 2), key=f"BUS {i}||MODE")]) + layout.append( + [ + psg.Button("Mono", size=(6, 2), key=f"BUS {i}||MONO"), + psg.Button("EQ", size=(6, 2), key=f"BUS {i}||EQ"), + psg.Button("Mute", size=(6, 2), key=f"BUS {i}||MUTE"), + psg.Button(f"BUSMODE", size=(12, 2), key=f"BUS {i}||MODE"), + ] + ) outputs = list() [step(outputs) for step in (add_strip_outputs,)] diff --git a/src/nvda_voicemeeter/models.py b/src/nvda_voicemeeter/models.py index da66ab3..d682da2 100644 --- a/src/nvda_voicemeeter/models.py +++ b/src/nvda_voicemeeter/models.py @@ -1,37 +1,52 @@ +def _make_hardware_ins_cache(vm) -> dict: + return {**{f"HARDWARE IN||{i + 1}": vm.strip[i].device.name for i in range(vm.kind.phys_in)}} + + def _make_hardware_outs_cache(vm) -> dict: return {**{f"HARDWARE OUT||A{i + 1}": vm.bus[i].device.name for i in range(vm.kind.phys_out)}} -def _make_output_cache(vm) -> dict: - match vm.kind.name: - case "basic": - return { - **{f"STRIP {i}||A1": vm.strip[i].A1 for i in range(vm.kind.num_strip)}, - **{f"STRIP {i}||B1": vm.strip[i].B1 for i in range(vm.kind.num_strip)}, - } - case "banana": - return { - **{f"STRIP {i}||A1": vm.strip[i].A1 for i in range(vm.kind.num_strip)}, - **{f"STRIP {i}||A2": vm.strip[i].A2 for i in range(vm.kind.num_strip)}, - **{f"STRIP {i}||A3": vm.strip[i].A3 for i in range(vm.kind.num_strip)}, - **{f"STRIP {i}||B1": vm.strip[i].B1 for i in range(vm.kind.num_strip)}, - **{f"STRIP {i}||B2": vm.strip[i].B2 for i in range(vm.kind.num_strip)}, - } - case "potato": - return { - **{f"STRIP {i}||A1": vm.strip[i].A1 for i in range(vm.kind.num_strip)}, - **{f"STRIP {i}||A2": vm.strip[i].A2 for i in range(vm.kind.num_strip)}, - **{f"STRIP {i}||A3": vm.strip[i].A3 for i in range(vm.kind.num_strip)}, - **{f"STRIP {i}||A4": vm.strip[i].A4 for i in range(vm.kind.num_strip)}, - **{f"STRIP {i}||A5": vm.strip[i].A5 for i in range(vm.kind.num_strip)}, - **{f"STRIP {i}||B1": vm.strip[i].B1 for i in range(vm.kind.num_strip)}, - **{f"STRIP {i}||B2": vm.strip[i].B2 for i in range(vm.kind.num_strip)}, - **{f"STRIP {i}||B3": vm.strip[i].B3 for i in range(vm.kind.num_strip)}, - } - - -def _make_bus_mode_cache(vm) -> dict: - return {**{f"BUS {i}||MODE": vm.bus[i].mode.get() for i in range(vm.kind.num_bus)}} +def _make_param_cache(vm, channel_type) -> dict: + params = {} + if channel_type == "strip": + match vm.kind.name: + case "basic": + params |= { + **{f"STRIP {i}||A1": vm.strip[i].A1 for i in range(vm.kind.num_strip)}, + **{f"STRIP {i}||B1": vm.strip[i].B1 for i in range(vm.kind.num_strip)}, + } + case "banana": + params |= { + **{f"STRIP {i}||A1": vm.strip[i].A1 for i in range(vm.kind.num_strip)}, + **{f"STRIP {i}||A2": vm.strip[i].A2 for i in range(vm.kind.num_strip)}, + **{f"STRIP {i}||A3": vm.strip[i].A3 for i in range(vm.kind.num_strip)}, + **{f"STRIP {i}||B1": vm.strip[i].B1 for i in range(vm.kind.num_strip)}, + **{f"STRIP {i}||B2": vm.strip[i].B2 for i in range(vm.kind.num_strip)}, + } + case "potato": + params |= { + **{f"STRIP {i}||A1": vm.strip[i].A1 for i in range(vm.kind.num_strip)}, + **{f"STRIP {i}||A2": vm.strip[i].A2 for i in range(vm.kind.num_strip)}, + **{f"STRIP {i}||A3": vm.strip[i].A3 for i in range(vm.kind.num_strip)}, + **{f"STRIP {i}||A4": vm.strip[i].A4 for i in range(vm.kind.num_strip)}, + **{f"STRIP {i}||A5": vm.strip[i].A5 for i in range(vm.kind.num_strip)}, + **{f"STRIP {i}||B1": vm.strip[i].B1 for i in range(vm.kind.num_strip)}, + **{f"STRIP {i}||B2": vm.strip[i].B2 for i in range(vm.kind.num_strip)}, + **{f"STRIP {i}||B3": vm.strip[i].B3 for i in range(vm.kind.num_strip)}, + } + params |= { + **{f"STRIP {i}||MONO": vm.strip[i].mono for i in range(vm.kind.num_strip)}, + **{f"STRIP {i}||SOLO": vm.strip[i].solo for i in range(vm.kind.num_strip)}, + **{f"STRIP {i}||MUTE": vm.strip[i].mute for i in range(vm.kind.num_strip)}, + } + return params + else: + return { + **{f"BUS {i}||MONO": vm.bus[i].mono for i in range(vm.kind.num_bus)}, + **{f"BUS {i}||EQ": vm.bus[i].eq.on for i in range(vm.kind.num_bus)}, + **{f"BUS {i}||MUTE": vm.bus[i].mute for i in range(vm.kind.num_bus)}, + **{f"BUS {i}||MODE": vm.bus[i].mode.get() for i in range(vm.kind.num_bus)}, + } def _make_label_cache(vm) -> dict: @@ -56,8 +71,10 @@ def _make_label_cache(vm) -> dict: def _make_patch_asio_cache(vm) -> dict: - return {**{f"ASIO CHECKBOX||{i}": vm.patch.asio[i].get() for i in range(vm.kind.phys_out * 2)}} + if vm.kind.name != "basic": + return {**{f"ASIO CHECKBOX||{i}": vm.patch.asio[i].get() for i in range(vm.kind.phys_out * 2)}} def _make_patch_insert_cache(vm) -> dict: - return {**{f"INSERT CHECKBOX||{i}": vm.patch.insert[i].on for i in range(vm.kind.num_strip_levels)}} + if vm.kind.name != "basic": + return {**{f"INSERT CHECKBOX||{i}": vm.patch.insert[i].on for i in range(vm.kind.num_strip_levels)}} diff --git a/src/nvda_voicemeeter/util.py b/src/nvda_voicemeeter/util.py index 44eada8..91ef1a4 100644 --- a/src/nvda_voicemeeter/util.py +++ b/src/nvda_voicemeeter/util.py @@ -14,6 +14,10 @@ def get_insert_checkbox_index(kind, channel, num) -> int: def get_input_device_list(vm) -> list: + return ["{type}: {name}".format(**vm.device.input(i)) for i in range(vm.device.ins)] + + +def get_output_device_list(vm) -> list: return ["{type}: {name}".format(**vm.device.output(i)) for i in range(vm.device.outs)] @@ -88,3 +92,20 @@ def get_channel_identifier_list(vm) -> list: for j in range(8): identifiers.append(f"IN{i + 1} {j}") return identifiers + + +def get_bus_modes() -> list: + return [ + "normal", + "amix", + "bmix", + "repeat", + "composite", + "tvmix", + "upmix21", + "upmix41", + "upmix61", + "centeronly", + "lfeonly", + "rearonly", + ] diff --git a/src/nvda_voicemeeter/window.py b/src/nvda_voicemeeter/window.py index b726d60..bdd29c4 100644 --- a/src/nvda_voicemeeter/window.py +++ b/src/nvda_voicemeeter/window.py @@ -6,10 +6,10 @@ import PySimpleGUI as psg from .builder import Builder from .models import ( - _make_bus_mode_cache, + _make_hardware_ins_cache, _make_hardware_outs_cache, _make_label_cache, - _make_output_cache, + _make_param_cache, _make_patch_asio_cache, _make_patch_insert_cache, ) @@ -18,6 +18,7 @@ from .parser import Parser from .util import ( _patch_insert_channels, get_asio_checkbox_index, + get_bus_modes, get_channel_identifier_list, get_insert_checkbox_index, get_patch_composite_list, @@ -39,9 +40,10 @@ class NVDAVMWindow(psg.Window): self.kind = self.vm.kind self.logger = logger.getChild(type(self).__name__) self.cache = { + "hw_ins": _make_hardware_ins_cache(self.vm), "hw_outs": _make_hardware_outs_cache(self.vm), - "outputs": _make_output_cache(self.vm), - "busmode": _make_bus_mode_cache(self.vm), + "strip": _make_param_cache(self.vm, "strip"), + "bus": _make_param_cache(self.vm, "bus"), "labels": _make_label_cache(self.vm), "asio": _make_patch_asio_cache(self.vm), "insert": _make_patch_insert_cache(self.vm), @@ -52,11 +54,16 @@ class NVDAVMWindow(psg.Window): layout = self.builder.run() super().__init__(title, layout, return_keyboard_events=True, finalize=True) buttonmenu_opts = {"takefocus": 1, "highlightthickness": 1} + for i in range(self.kind.phys_in): + self[f"HARDWARE IN||{i + 1}"].Widget.config(**buttonmenu_opts) for i in range(self.kind.phys_out): self[f"HARDWARE OUT||A{i + 1}"].Widget.config(**buttonmenu_opts) 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["ASIO BUFFER"].Widget.config(**buttonmenu_opts) + if self.kind.name != "basic": + self["ASIO BUFFER FRAME"].update(visible=False) + self["ASIO BUFFER FRAME"].hide_row() self.register_events() def __enter__(self): @@ -92,23 +99,25 @@ class NVDAVMWindow(psg.Window): def on_pdirty(self): self.cache = { + "hw_ins": _make_hardware_ins_cache(self.vm), "hw_outs": _make_hardware_outs_cache(self.vm), - "outputs": _make_output_cache(self.vm), - "busmode": _make_bus_mode_cache(self.vm), + "strip": _make_param_cache(self.vm, "strip"), + "bus": _make_param_cache(self.vm, "bus"), "labels": _make_label_cache(self.vm), "asio": _make_patch_asio_cache(self.vm), "insert": _make_patch_insert_cache(self.vm), } for key, value in self.cache["labels"].items(): self[key].update(value=value) - for key, value in self.cache["asio"].items(): - identifier, i = key.split("||") - partial = get_channel_identifier_list(self.vm)[int(i)] - self[f"{identifier}||{partial}"].update(value=value) - for key, value in self.cache["insert"].items(): - identifier, i = key.split("||") - partial = get_channel_identifier_list(self.vm)[int(i)] - self[f"{identifier}||{partial}"].update(value=value) + if self.kind.name != "basic": + for key, value in self.cache["asio"].items(): + identifier, i = key.split("||") + partial = get_channel_identifier_list(self.vm)[int(i)] + self[f"{identifier}||{partial}"].update(value=value) + for key, value in self.cache["insert"].items(): + identifier, i = key.split("||") + partial = get_channel_identifier_list(self.vm)[int(i)] + self[f"{identifier}||{partial}"].update(value=value) def register_events(self): """Registers events for widgets""" @@ -118,6 +127,12 @@ class NVDAVMWindow(psg.Window): self.bind("", "CTRL-TAB") self.bind("", "CTRL-SHIFT-TAB") + # Hardware In + for i in range(self.vm.kind.phys_in): + self[f"HARDWARE IN||{i + 1}"].bind("", "||FOCUS IN") + self[f"HARDWARE IN||{i + 1}"].bind("", "||KEY SPACE", propagate=False) + self[f"HARDWARE IN||{i + 1}"].bind("", "||KEY ENTER", propagate=False) + # Hardware Out for i in range(self.vm.kind.phys_out): self[f"HARDWARE OUT||A{i + 1}"].bind("", "||FOCUS IN") @@ -146,7 +161,7 @@ class NVDAVMWindow(psg.Window): else: [self[f"INSERT CHECKBOX||IN{i + 1} {j}"].bind("", "||FOCUS IN") for j in range(8)] - # Strip Outputs + # Strip Params for i in range(self.kind.num_strip): for j in range(self.kind.phys_out): self[f"STRIP {i}||A{j + 1}"].bind("", "||FOCUS IN") @@ -154,11 +169,20 @@ class NVDAVMWindow(psg.Window): for j in range(self.kind.virt_out): self[f"STRIP {i}||B{j + 1}"].bind("", "||FOCUS IN") self[f"STRIP {i}||B{j + 1}"].bind("", "||KEY ENTER") + if i < self.kind.phys_in: + for param in ("MONO", "SOLO", "MUTE"): + self[f"STRIP {i}||{param}"].bind("", "||FOCUS IN") + self[f"STRIP {i}||{param}"].bind("", "||KEY ENTER") + else: + for param in ("MONO", "SOLO", "MUTE"): + self[f"STRIP {i}||{param}"].bind("", "||FOCUS IN") + self[f"STRIP {i}||{param}"].bind("", "||KEY ENTER") - # Bus Modes + # Bus Params for i in range(self.kind.num_bus): - self[f"BUS {i}||MODE"].bind("", "||FOCUS IN") - self[f"BUS {i}||MODE"].bind("", "||KEY ENTER") + for param in ("MONO", "EQ", "MUTE", "MODE"): + self[f"BUS {i}||{param}"].bind("", "||FOCUS IN") + self[f"BUS {i}||{param}"].bind("", "||KEY ENTER") # ASIO Buffer if self.kind.name != "basic": @@ -367,6 +391,27 @@ class NVDAVMWindow(psg.Window): case [["tabs"], ["FOCUS", "IN"]]: self.nvda.speak(f"tab {values['tabs']}") + # Hardware In + case [["HARDWARE", "IN"], [key]]: + selection = values[f"HARDWARE IN||{key}"] + index = int(key) - 1 + match selection.split(":"): + case [device_name]: + setattr(self.vm.strip[index].device, "wdm", "") + self.TKroot.after(200, self.nvda.speak, f"HARDWARE IN {key} device selection removed") + case [driver, device_name]: + setattr(self.vm.strip[index].device, driver, device_name.strip()) + phonetic = {"mme": "em em e"} + self.TKroot.after( + 200, + self.nvda.speak, + f"HARDWARE IN {key} set {phonetic.get(driver, driver)} {device_name}", + ) + case [["HARDWARE", "IN"], [key], ["FOCUS", "IN"]]: + self.nvda.speak(f"HARDWARE INPUT {key} {self.cache['hw_ins'][f'HARDWARE IN||{key}']}") + case [["HARDWARE", "IN"], [key], ["KEY", "SPACE" | "ENTER"]]: + open_context_menu_for_buttonmenu(self, f"HARDWARE IN||{key}") + # Hardware out case [["HARDWARE", "OUT"], [key]]: selection = values[f"HARDWARE OUT||{key}"] @@ -454,38 +499,116 @@ class NVDAVMWindow(psg.Window): case [["ASIO", "BUFFER"], ["KEY", "SPACE" | "ENTER"]]: open_context_menu_for_buttonmenu(self, "ASIO BUFFER") - # Strip outputs - case [["STRIP", index], [output]]: - val = not self.cache["outputs"][f"STRIP {index}||{output}"] - setattr(self.vm.strip[int(index)], output, val) - self.cache["outputs"][f"STRIP {index}||{output}"] = val - self.nvda.speak(f"STRIP {index} {output} {label if label else ''} {'on' if val else 'off'}") - case [["STRIP", index], [output], ["FOCUS", "IN"]]: - val = self.cache["outputs"][f"STRIP {index}||{output}"] + # Strip Params + case [["STRIP", index], [param]]: label = self.cache["labels"][f"STRIP {index}||LABEL"] - self.nvda.speak(f"{label} {output} {'on' if val else 'off'}") - case [["STRIP", index], [output], ["KEY", "ENTER"]]: + match param: + case "MONO": + if int(index) < self.kind.phys_in: + actual = param.lower() + elif int(index) == self.kind.phys_in + self.kind.virt_in - 2: + actual = "k" + else: + actual = "mc" + phonetic = {"k": "karaoke"} + if actual == "k": + next_val = self.vm.strip[int(index)].k + 1 + if next_val == 4: + next_val = 0 + setattr(self.vm.strip[int(index)], actual, next_val) + self.cache["strip"][f"STRIP {index}||{param}"] = next_val + self.nvda.speak( + f"{label} {phonetic.get(actual, actual)} {['off', 'k m', 'k 1', 'k 2'][next_val]}" + ) + else: + val = not self.cache["strip"][f"STRIP {index}||{param}"] + setattr(self.vm.strip[int(index)], actual, val) + self.cache["strip"][f"STRIP {index}||{param}"] = val + self.nvda.speak(f"{label} {phonetic.get(actual, actual)} {'on' if val else 'off'}") + case _: + val = not self.cache["strip"][f"STRIP {index}||{param}"] + setattr(self.vm.strip[int(index)], param if param[0] in ("A", "B") else param.lower(), val) + self.cache["strip"][f"STRIP {index}||{param}"] = val + self.nvda.speak(f"{label} {param} {'on' if val else 'off'}") + case [["STRIP", index], [param], ["FOCUS", "IN"]]: + val = self.cache["strip"][f"STRIP {index}||{param}"] + match param: + case "MONO": + if int(index) < self.kind.phys_in: + actual = param.lower() + elif int(index) == self.kind.phys_in + self.kind.virt_in - 2: + actual = "k" + else: + actual = "mc" + case _: + actual = param + phonetic = {"k": "karaoke"} + label = self.cache["labels"][f"STRIP {index}||LABEL"] + if actual == "k": + self.nvda.speak( + f"{label} {phonetic.get(actual, actual)} {['off', 'k m', 'k 1', 'k 2'][self.cache['strip'][f'STRIP {int(index)}||{param}']]}" + ) + else: + self.nvda.speak(f"{label} {phonetic.get(actual, actual)} {'on' if val else 'off'}") + case [["STRIP", index], [param], ["KEY", "ENTER"]]: self.find_element_with_focus().click() - # Bus modes - case [["BUS", index], ["MODE"]]: - val = self.cache["busmode"][event] - if val != "normal": - self.vm.bus[int(index)].mode.normal = True - self.cache["busmode"][event] = "normal" + # Bus Params + case [["BUS", index], [param]]: + val = self.cache["bus"][event] + label = self.cache["labels"][f"BUS {index}||LABEL"] + match param: + case "EQ": + val = not val + self.vm.bus[int(index)].eq.on = val + self.cache["bus"][event] = val + self.TKroot.after( + 200, + self.nvda.speak, + f"{label} bus {param} {'on' if val else 'off'}", + ) + case "MONO" | "MUTE": + val = not val + setattr(self.vm.bus[int(index)], param.lower(), val) + self.cache["bus"][event] = val + self.TKroot.after( + 200, + self.nvda.speak, + f"{label} bus {param} {'on' if val else 'off'}", + ) + case "MODE": + bus_modes = get_bus_modes() + next_index = bus_modes.index(val) + 1 + if next_index == len(bus_modes): + 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( + 200, + self.nvda.speak, + f"{label} bus mode {phonetic.get(next_bus, next_bus)}", + ) + case [["BUS", index], [param], ["FOCUS", "IN"]]: + label = self.cache["labels"][f"BUS {index}||LABEL"] + val = self.cache["bus"][f"BUS {index}||{param}"] + if param == "MODE": + self.nvda.speak(f"{label} bus {param} {val}") else: - self.vm.bus[int(index)].mode.composite = True - self.cache["busmode"][event] = "composite" - label = self.cache["labels"][f"BUS {index}||LABEL"] - self.TKroot.after( - 200, - self.nvda.speak, - f"{label} bus mode {self.cache['busmode'][event]}", - ) - case [["BUS", index], ["MODE"], ["FOCUS", "IN"]]: - label = self.cache["labels"][f"BUS {index}||LABEL"] - self.nvda.speak(f"{label} bus mode {self.cache['busmode'][f'BUS {index}||MODE']}") - case [["BUS", index], ["MODE"], ["KEY", "ENTER"]]: + self.nvda.speak(f"{label} bus {param} {'on' if val else 'off'}") + case [["BUS", index], [param], ["KEY", "ENTER"]]: self.find_element_with_focus().click() # Unknown