2023-08-22 16:11:24 +01:00
|
|
|
import PySimpleGUI as psg
|
|
|
|
|
2023-08-23 02:04:18 +01:00
|
|
|
from .util import (
|
|
|
|
get_asio_checkbox_index,
|
2023-08-26 21:55:39 +01:00
|
|
|
get_asio_samples_list,
|
2023-08-23 02:04:18 +01:00
|
|
|
get_input_device_list,
|
|
|
|
get_insert_checkbox_index,
|
2023-09-06 00:03:12 +01:00
|
|
|
get_output_device_list,
|
2023-08-25 18:29:43 +01:00
|
|
|
get_patch_composite_list,
|
2023-08-28 12:11:34 +01:00
|
|
|
get_tabs_labels,
|
2023-08-23 02:04:18 +01:00
|
|
|
)
|
2023-08-23 00:27:37 +01:00
|
|
|
|
2023-08-22 16:11:24 +01:00
|
|
|
|
|
|
|
class Builder:
|
|
|
|
"""Responsible for building the Window layout"""
|
|
|
|
|
2023-08-26 00:11:05 +01:00
|
|
|
def __init__(self, window):
|
2023-08-22 16:11:24 +01:00
|
|
|
self.window = window
|
2023-08-26 00:11:05 +01:00
|
|
|
self.vm = self.window.vm
|
2023-08-22 16:11:24 +01:00
|
|
|
self.kind = self.vm.kind
|
|
|
|
|
|
|
|
def run(self) -> list:
|
2023-08-26 21:55:39 +01:00
|
|
|
menu = [[self.make_menu()]]
|
2023-08-26 19:46:39 +01:00
|
|
|
|
2023-08-25 22:25:30 +01:00
|
|
|
layout0 = []
|
2023-08-23 02:31:15 +01:00
|
|
|
if self.kind.name == "basic":
|
2023-09-06 00:03:12 +01:00
|
|
|
steps = (
|
|
|
|
self.make_tab0_row0,
|
|
|
|
self.make_tab0_row1,
|
|
|
|
)
|
2023-08-23 02:31:15 +01:00
|
|
|
else:
|
2023-08-26 21:55:39 +01:00
|
|
|
steps = (
|
|
|
|
self.make_tab0_row0,
|
|
|
|
self.make_tab0_row1,
|
|
|
|
self.make_tab0_row2,
|
|
|
|
self.make_tab0_row3,
|
|
|
|
self.make_tab0_row4,
|
2023-09-06 00:03:12 +01:00
|
|
|
self.make_tab0_row5,
|
2023-08-26 21:55:39 +01:00
|
|
|
)
|
2023-08-23 02:31:15 +01:00
|
|
|
for step in steps:
|
2023-08-25 22:25:30 +01:00
|
|
|
layout0.append([step()])
|
|
|
|
|
|
|
|
layout1 = []
|
|
|
|
steps = (self.make_tab1_rows,)
|
|
|
|
for step in steps:
|
|
|
|
layout1.append([step()])
|
|
|
|
|
|
|
|
layout2 = []
|
|
|
|
steps = (self.make_tab2_rows,)
|
|
|
|
for step in steps:
|
|
|
|
layout2.append([step()])
|
2023-08-25 18:29:43 +01:00
|
|
|
|
2023-08-26 20:22:46 +01:00
|
|
|
layout3 = []
|
|
|
|
steps = (self.make_tab3_rows,)
|
|
|
|
for step in steps:
|
|
|
|
layout3.append([step()])
|
|
|
|
|
2023-08-28 12:11:34 +01:00
|
|
|
layouts = [layout0, layout1, layout2, layout3]
|
|
|
|
|
|
|
|
tabs = [psg.Tab(identifier, layouts[i], key=identifier) for i, identifier in enumerate(get_tabs_labels())]
|
|
|
|
tab_group = psg.TabGroup([tabs], change_submits=True, key="tabs")
|
2023-08-25 18:29:43 +01:00
|
|
|
|
2023-08-26 19:46:39 +01:00
|
|
|
return [[menu], [tab_group]]
|
|
|
|
|
|
|
|
def make_menu(self) -> psg.Menu:
|
|
|
|
menu_def = [
|
|
|
|
[
|
|
|
|
"&Voicemeeter",
|
|
|
|
[
|
|
|
|
"Restart Audio Engine::MENU",
|
2023-09-01 03:04:39 +01:00
|
|
|
"Save Settings::MENU",
|
|
|
|
"Load Settings::MENU",
|
|
|
|
"Load Settings on Startup ::MENU",
|
2023-08-26 19:46:39 +01:00
|
|
|
],
|
|
|
|
],
|
|
|
|
]
|
2023-08-26 21:55:39 +01:00
|
|
|
return psg.Menu(menu_def, key="menus")
|
2023-08-22 16:11:24 +01:00
|
|
|
|
2023-08-25 18:50:29 +01:00
|
|
|
def make_tab0_row0(self) -> psg.Frame:
|
2023-09-06 00:03:12 +01:00
|
|
|
"""tab0 row0 represents hardware ins"""
|
2023-08-25 18:29:43 +01:00
|
|
|
|
2023-08-22 16:11:24 +01:00
|
|
|
def add_physical_device_opts(layout):
|
2023-08-23 02:04:18 +01:00
|
|
|
devices = get_input_device_list(self.vm)
|
2023-08-24 16:07:28 +01:00
|
|
|
devices.append("- remove device selection -")
|
2023-09-06 00:03:12 +01:00
|
|
|
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 -")
|
2023-08-26 10:42:18 +01:00
|
|
|
if self.kind.name == "basic":
|
|
|
|
num_outs = self.kind.phys_out + self.kind.virt_out
|
|
|
|
else:
|
|
|
|
num_outs = self.kind.phys_out
|
2023-08-22 16:11:24 +01:00
|
|
|
layout.append(
|
|
|
|
[
|
2023-08-24 16:07:28 +01:00
|
|
|
psg.ButtonMenu(
|
2023-08-25 20:41:48 +01:00
|
|
|
f"A{i + 1}",
|
2023-08-24 16:07:28 +01:00
|
|
|
size=(6, 3),
|
2023-08-25 20:23:21 +01:00
|
|
|
menu_def=["", devices],
|
2023-08-25 20:41:48 +01:00
|
|
|
key=f"HARDWARE OUT||A{i + 1}",
|
2023-08-22 16:11:24 +01:00
|
|
|
)
|
2023-08-26 10:42:18 +01:00
|
|
|
for i in range(num_outs)
|
2023-08-22 16:11:24 +01:00
|
|
|
]
|
|
|
|
)
|
|
|
|
|
|
|
|
hardware_out = list()
|
|
|
|
[step(hardware_out) for step in (add_physical_device_opts,)]
|
|
|
|
return psg.Frame("Hardware Out", hardware_out)
|
|
|
|
|
2023-09-06 00:03:12 +01:00
|
|
|
def make_tab0_row2(self) -> psg.Frame:
|
|
|
|
"""tab0 row2 represents patch asio inputs to strips"""
|
2023-08-25 18:29:43 +01:00
|
|
|
|
2023-08-22 16:11:24 +01:00
|
|
|
def add_asio_checkboxes(layout, i):
|
|
|
|
nums = list(range(99))
|
|
|
|
layout.append(
|
2023-08-23 00:27:37 +01:00
|
|
|
[
|
|
|
|
psg.Spin(
|
|
|
|
nums,
|
2023-09-05 05:30:46 +01:00
|
|
|
initial_value=self.window.cache["asio"][f"ASIO CHECKBOX||{get_asio_checkbox_index(0, i)}"],
|
2023-08-23 00:27:37 +01:00
|
|
|
size=2,
|
|
|
|
enable_events=True,
|
|
|
|
key=f"ASIO CHECKBOX||IN{i} 0",
|
|
|
|
)
|
|
|
|
],
|
2023-08-22 16:11:24 +01:00
|
|
|
)
|
|
|
|
layout.append(
|
2023-08-23 00:27:37 +01:00
|
|
|
[
|
|
|
|
psg.Spin(
|
|
|
|
nums,
|
2023-09-05 05:30:46 +01:00
|
|
|
initial_value=self.window.cache["asio"][f"ASIO CHECKBOX||{get_asio_checkbox_index(1, i)}"],
|
2023-08-23 00:27:37 +01:00
|
|
|
size=2,
|
|
|
|
enable_events=True,
|
|
|
|
key=f"ASIO CHECKBOX||IN{i} 1",
|
|
|
|
)
|
|
|
|
],
|
2023-08-22 16:11:24 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
inner = list()
|
2023-08-22 18:13:15 +01:00
|
|
|
asio_checkboxlists = ([] for _ in range(self.kind.phys_out))
|
|
|
|
for i, checkbox_list in enumerate(asio_checkboxlists):
|
2023-08-22 16:11:24 +01:00
|
|
|
[step(checkbox_list, i + 1) for step in (add_asio_checkboxes,)]
|
|
|
|
inner.append(psg.Frame(f"In#{i + 1}", checkbox_list))
|
|
|
|
|
|
|
|
asio_checkboxes = [inner]
|
|
|
|
return psg.Frame("PATCH ASIO Inputs to Strips", asio_checkboxes)
|
2023-08-22 18:13:15 +01:00
|
|
|
|
2023-09-06 00:03:12 +01:00
|
|
|
def make_tab0_row3(self) -> psg.Frame:
|
|
|
|
"""tab0 row3 represents patch composite"""
|
2023-08-25 18:29:43 +01:00
|
|
|
|
|
|
|
def add_physical_device_opts(layout):
|
|
|
|
outputs = get_patch_composite_list(self.vm.kind)
|
|
|
|
layout.append(
|
|
|
|
[
|
|
|
|
psg.ButtonMenu(
|
2023-08-25 20:23:21 +01:00
|
|
|
f"PC{i + 1}",
|
2023-08-25 18:29:43 +01:00
|
|
|
size=(6, 2),
|
2023-08-25 20:23:21 +01:00
|
|
|
menu_def=["", outputs],
|
|
|
|
key=f"PATCH COMPOSITE||PC{i + 1}",
|
2023-08-25 18:29:43 +01:00
|
|
|
)
|
2023-08-25 20:23:21 +01:00
|
|
|
for i in range(self.kind.phys_out)
|
2023-08-25 18:29:43 +01:00
|
|
|
]
|
|
|
|
)
|
|
|
|
|
|
|
|
hardware_out = list()
|
|
|
|
[step(hardware_out) for step in (add_physical_device_opts,)]
|
|
|
|
return psg.Frame("PATCH COMPOSITE", hardware_out)
|
|
|
|
|
2023-09-06 00:03:12 +01:00
|
|
|
def make_tab0_row4(self) -> psg.Frame:
|
|
|
|
"""tab0 row4 represents patch insert"""
|
2023-08-25 18:29:43 +01:00
|
|
|
|
2023-08-22 18:13:15 +01:00
|
|
|
def add_insert_checkboxes(layout, i):
|
|
|
|
if i <= self.kind.phys_in:
|
2023-08-24 17:22:37 +01:00
|
|
|
[
|
|
|
|
layout.append(
|
|
|
|
[
|
|
|
|
psg.Checkbox(
|
|
|
|
text=channel,
|
|
|
|
default=self.vm.patch.insert[get_insert_checkbox_index(self.kind, j, i)].on,
|
|
|
|
enable_events=True,
|
|
|
|
key=f"INSERT CHECKBOX||IN{i} {j}",
|
|
|
|
)
|
|
|
|
],
|
|
|
|
)
|
|
|
|
for j, channel in enumerate(("LEFT", "RIGHT"))
|
|
|
|
]
|
2023-08-22 18:13:15 +01:00
|
|
|
else:
|
|
|
|
layout.append(
|
|
|
|
[
|
2023-08-23 00:27:37 +01:00
|
|
|
psg.Checkbox(
|
2023-08-24 17:22:37 +01:00
|
|
|
text=channel,
|
|
|
|
default=self.vm.patch.insert[get_insert_checkbox_index(self.kind, j, i)].on,
|
2023-08-23 00:27:37 +01:00
|
|
|
enable_events=True,
|
2023-08-24 17:22:37 +01:00
|
|
|
key=f"INSERT CHECKBOX||IN{i} {j}",
|
|
|
|
)
|
|
|
|
for j, channel in enumerate(("LEFT", "RIGHT", "C", "LFE", "SL", "SR", "BL", "BR"))
|
2023-08-22 18:13:15 +01:00
|
|
|
],
|
|
|
|
)
|
|
|
|
|
|
|
|
asio_checkboxes = list()
|
|
|
|
inner = list()
|
|
|
|
checkbox_lists = ([] for _ in range(self.kind.num_strip))
|
|
|
|
for i, checkbox_list in enumerate(checkbox_lists):
|
|
|
|
if i < self.kind.phys_in:
|
|
|
|
[step(checkbox_list, i + 1) for step in (add_insert_checkboxes,)]
|
|
|
|
inner.append(psg.Frame(f"In#{i + 1}", checkbox_list))
|
|
|
|
else:
|
|
|
|
[step(checkbox_list, i + 1) for step in (add_insert_checkboxes,)]
|
|
|
|
asio_checkboxes.append([psg.Frame(f"In#{i + 1}", checkbox_list)])
|
|
|
|
asio_checkboxes.insert(0, inner)
|
|
|
|
|
|
|
|
return psg.Frame("PATCH INSERT", asio_checkboxes)
|
2023-08-25 22:25:30 +01:00
|
|
|
|
2023-09-06 00:03:12 +01:00
|
|
|
def make_tab0_row5(self) -> psg.Frame:
|
|
|
|
"""tab0 row5 represents asio buffer"""
|
2023-08-26 21:55:39 +01:00
|
|
|
|
|
|
|
samples = get_asio_samples_list()
|
|
|
|
samples.append("Default")
|
|
|
|
|
|
|
|
return psg.Frame(
|
|
|
|
"ASIO BUFFER",
|
|
|
|
[
|
|
|
|
[
|
|
|
|
psg.ButtonMenu(
|
|
|
|
"ASIO BUFFER",
|
2023-09-01 03:04:39 +01:00
|
|
|
size=(14, 2),
|
2023-08-26 21:55:39 +01:00
|
|
|
menu_def=["", samples],
|
|
|
|
key="ASIO BUFFER",
|
|
|
|
)
|
|
|
|
]
|
|
|
|
],
|
2023-09-06 00:03:12 +01:00
|
|
|
key="ASIO BUFFER FRAME",
|
2023-08-26 21:55:39 +01:00
|
|
|
)
|
|
|
|
|
2023-08-25 22:25:30 +01:00
|
|
|
def make_tab1_row(self, i) -> psg.Frame:
|
2023-08-27 21:03:28 +01:00
|
|
|
"""tab1 row represents a strip's outputs (A1-A5, B1-B3)"""
|
|
|
|
|
2023-08-25 22:25:30 +01:00
|
|
|
def add_strip_outputs(layout):
|
|
|
|
layout.append(
|
|
|
|
[
|
|
|
|
psg.Button(
|
|
|
|
f"A{j + 1}" if j < self.kind.phys_out else f"B{j - self.kind.phys_out + 1}",
|
|
|
|
size=(4, 2),
|
|
|
|
key=f"STRIP {i}||A{j + 1}"
|
|
|
|
if j < self.kind.phys_out
|
|
|
|
else f"STRIP {i}||B{j - self.kind.phys_out + 1}",
|
|
|
|
)
|
2023-08-26 10:42:18 +01:00
|
|
|
for j in range(self.kind.phys_out + self.kind.virt_out)
|
2023-09-06 00:03:12 +01:00
|
|
|
],
|
|
|
|
)
|
|
|
|
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"),
|
|
|
|
],
|
2023-08-25 22:25:30 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
outputs = list()
|
|
|
|
[step(outputs) for step in (add_strip_outputs,)]
|
2023-09-05 05:30:46 +01:00
|
|
|
return psg.Frame(self.window.cache["labels"][f"STRIP {i}||LABEL"], outputs, key=f"STRIP {i}||LABEL")
|
2023-08-25 22:25:30 +01:00
|
|
|
|
2023-08-26 00:11:05 +01:00
|
|
|
def make_tab1_rows(self) -> psg.Frame:
|
2023-08-26 10:42:18 +01:00
|
|
|
layout = [[self.make_tab1_row(i)] for i in range(self.kind.phys_in)]
|
2023-08-26 00:11:05 +01:00
|
|
|
return psg.Frame(None, layout, border_width=0)
|
2023-08-25 22:25:30 +01:00
|
|
|
|
|
|
|
def make_tab2_row(self, i) -> psg.Frame:
|
2023-08-27 21:03:28 +01:00
|
|
|
"""tab2 row represents a strip's outputs (A1-A5, B1-B3)"""
|
|
|
|
|
2023-08-25 22:25:30 +01:00
|
|
|
def add_strip_outputs(layout):
|
|
|
|
layout.append(
|
|
|
|
[
|
|
|
|
psg.Button(
|
|
|
|
f"A{j + 1}" if j < self.kind.phys_out else f"B{j - self.kind.phys_out + 1}",
|
|
|
|
size=(4, 2),
|
|
|
|
key=f"STRIP {i}||A{j + 1}"
|
|
|
|
if j < self.kind.phys_out
|
|
|
|
else f"STRIP {i}||B{j - self.kind.phys_out + 1}",
|
|
|
|
)
|
2023-08-26 10:42:18 +01:00
|
|
|
for j in range(self.kind.phys_out + self.kind.virt_out)
|
2023-08-25 22:25:30 +01:00
|
|
|
]
|
|
|
|
)
|
2023-09-06 00:03:12 +01:00
|
|
|
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"),
|
|
|
|
],
|
|
|
|
)
|
2023-08-25 22:25:30 +01:00
|
|
|
|
|
|
|
outputs = list()
|
|
|
|
[step(outputs) for step in (add_strip_outputs,)]
|
2023-09-05 05:30:46 +01:00
|
|
|
return psg.Frame(self.window.cache["labels"][f"STRIP {i}||LABEL"], outputs, key=f"STRIP {i}||LABEL")
|
2023-08-25 22:25:30 +01:00
|
|
|
|
2023-08-26 00:11:05 +01:00
|
|
|
def make_tab2_rows(self) -> psg.Frame:
|
2023-08-26 20:22:46 +01:00
|
|
|
layout = [[self.make_tab2_row(i)] for i in range(self.kind.phys_in, self.kind.phys_in + self.kind.virt_in)]
|
|
|
|
return psg.Frame(None, layout, border_width=0)
|
|
|
|
|
2023-09-05 05:30:46 +01:00
|
|
|
def make_tab3_row(self, i) -> psg.Frame:
|
2023-08-27 21:03:28 +01:00
|
|
|
"""tab3 row represents bus composite toggle"""
|
|
|
|
|
2023-08-26 20:22:46 +01:00
|
|
|
def add_strip_outputs(layout):
|
2023-09-06 00:03:12 +01:00
|
|
|
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"),
|
|
|
|
]
|
|
|
|
)
|
2023-08-26 20:22:46 +01:00
|
|
|
|
2023-09-05 05:30:46 +01:00
|
|
|
outputs = list()
|
|
|
|
[step(outputs) for step in (add_strip_outputs,)]
|
|
|
|
return psg.Frame(self.window.cache["labels"][f"BUS {i}||LABEL"], outputs, key=f"BUS {i}||LABEL")
|
2023-08-26 20:22:46 +01:00
|
|
|
|
2023-09-05 05:30:46 +01:00
|
|
|
def make_tab3_rows(self) -> psg.Frame:
|
2023-08-26 20:22:46 +01:00
|
|
|
layout = [[self.make_tab3_row(i)] for i in range(self.kind.num_bus)]
|
2023-08-26 00:11:05 +01:00
|
|
|
return psg.Frame(None, layout, border_width=0)
|