mirror of
				https://github.com/onyx-and-iris/voicemeeter-compact.git
				synced 2025-10-30 21:11:44 +00:00 
			
		
		
		
	ldirty added, true iff level value has changed. fetching level arrays moved to highest level of the app. pdelay and ldelay added to _base_vals dataclass.
		
			
				
	
	
		
			459 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			459 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| import tkinter as tk
 | |
| from tkinter import ttk
 | |
| from functools import partial
 | |
| 
 | |
| from .data import _base_vals
 | |
| 
 | |
| 
 | |
| class Config(ttk.Frame):
 | |
|     def __init__(self, parent, index, _id):
 | |
|         super().__init__(parent)
 | |
|         self._parent = parent
 | |
|         self.index = index
 | |
|         self.id = _id
 | |
|         self.s = parent.styletable
 | |
| 
 | |
|         self.phys_in, self.virt_in = parent.kind.ins
 | |
|         self.phys_out, self.virt_out = parent.kind.outs
 | |
| 
 | |
|         self.watch_pdirty()
 | |
| 
 | |
|     @property
 | |
|     def identifier(self):
 | |
|         return self.id
 | |
| 
 | |
|     @property
 | |
|     def target(self):
 | |
|         """returns the current interface"""
 | |
|         return self._parent.target
 | |
| 
 | |
|     def getter(self, param):
 | |
|         if param in dir(self.target):
 | |
|             return getattr(self.target, param)
 | |
| 
 | |
|     def setter(self, param, value):
 | |
|         if param in dir(self.target):
 | |
|             setattr(self.target, param, value)
 | |
| 
 | |
|     def scale_enter(self, *args):
 | |
|         _base_vals.in_scale_button_1 = True
 | |
| 
 | |
|     def scale_leave(self, *args):
 | |
|         _base_vals.in_scale_button_1 = False
 | |
|         self._parent.nav_frame.info_text.set("")
 | |
| 
 | |
|     def scale_callback(self, param, *args):
 | |
|         """callback function for scale widget"""
 | |
|         val = self.slider_vars[self.slider_params.index(param)].get()
 | |
|         self.setter(param, val)
 | |
|         self._parent.nav_frame.info_text.set(round(val, 1))
 | |
| 
 | |
|     def reset_scale(self, param, val, *args):
 | |
|         self.setter(param, val)
 | |
|         self.slider_vars[self.slider_params.index(param)].set(val)
 | |
| 
 | |
|     def col_row_configure(self):
 | |
|         [
 | |
|             child.grid_configure(padx=1, pady=1, sticky=(tk.W, tk.E))
 | |
|             for child in self.winfo_children()
 | |
|             if isinstance(child, ttk.Checkbutton)
 | |
|         ]
 | |
|         self.grid(sticky=(tk.W))
 | |
| 
 | |
|     def watch_pdirty(self):
 | |
|         self.after(1, self.watch_pdirty_step)
 | |
| 
 | |
|     def watch_pdirty_step(self):
 | |
|         """keeps params synced but ensures sliders are responsive"""
 | |
|         if self._parent.pdirty and not _base_vals.in_scale_button_1:
 | |
|             self.sync()
 | |
|         self.after(_base_vals.pdelay, self.watch_pdirty_step)
 | |
| 
 | |
| 
 | |
| class StripConfig(Config):
 | |
|     def __init__(self, parent, index, _id):
 | |
|         super().__init__(parent, index, _id)
 | |
| 
 | |
|         # create parameter variables
 | |
|         if self._parent.kind.name == "Basic":
 | |
|             self.slider_params = ("audibility",)
 | |
|             self.slider_vars = (tk.DoubleVar(),)
 | |
|         else:
 | |
|             self.slider_params = ("comp", "gate", "limit")
 | |
|             self.slider_vars = [
 | |
|                 tk.DoubleVar() for i, _ in enumerate(self.slider_params)
 | |
|             ]
 | |
| 
 | |
|         self.phys_out_params = [f"A{i+1}" for i in range(self.phys_out)]
 | |
|         self.phys_out_params_vars = [
 | |
|             tk.BooleanVar() for i, _ in enumerate(self.phys_out_params)
 | |
|         ]
 | |
| 
 | |
|         self.virt_out_params = [f"B{i+1}" for i in range(self.virt_out)]
 | |
|         self.virt_out_params_vars = [
 | |
|             tk.BooleanVar() for i, _ in enumerate(self.virt_out_params)
 | |
|         ]
 | |
| 
 | |
|         self.params = ("mono", "solo")
 | |
|         self.param_vars = list(tk.BooleanVar() for i, _ in enumerate(self.params))
 | |
| 
 | |
|         self.make_row0()
 | |
|         self.make_row1()
 | |
|         self.make_row2()
 | |
| 
 | |
|         # sync all parameters
 | |
|         self.sync()
 | |
|         self.sync_sliders()
 | |
| 
 | |
|         self.col_row_configure()
 | |
| 
 | |
|     @property
 | |
|     def target(self):
 | |
|         """use the correct interface"""
 | |
|         _target = super(StripConfig, self).target
 | |
|         return getattr(_target, self.identifier)[self.index]
 | |
| 
 | |
|     def make_row0(self):
 | |
|         # Create sliders
 | |
|         if self.index < self.phys_in:
 | |
|             if self._parent.kind.name == "Basic":
 | |
|                 # audibility
 | |
|                 aud_label = ttk.Label(self, text="Audibility")
 | |
|                 aud_scale = ttk.Scale(
 | |
|                     self,
 | |
|                     from_=0.0,
 | |
|                     to=10.0,
 | |
|                     orient="horizontal",
 | |
|                     length=_base_vals.level_width,
 | |
|                     variable=self.slider_vars[self.slider_params.index("audibility")],
 | |
|                     command=partial(self.scale_callback, "audibility"),
 | |
|                 )
 | |
|                 aud_scale.bind(
 | |
|                     "<Double-Button-1>", partial(self.reset_scale, "audibility", 0)
 | |
|                 )
 | |
|                 aud_scale.bind("<Button-1>", self.scale_enter)
 | |
|                 aud_scale.bind("<ButtonRelease-1>", self.scale_leave)
 | |
| 
 | |
|                 aud_label.grid(column=0, row=0)
 | |
|                 aud_scale.grid(column=1, row=0)
 | |
|             else:
 | |
|                 # comp
 | |
|                 comp_label = ttk.Label(self, text="Comp")
 | |
|                 comp_scale = ttk.Scale(
 | |
|                     self,
 | |
|                     from_=0.0,
 | |
|                     to=10.0,
 | |
|                     orient="horizontal",
 | |
|                     length=_base_vals.level_width,
 | |
|                     variable=self.slider_vars[self.slider_params.index("comp")],
 | |
|                     command=partial(self.scale_callback, "comp"),
 | |
|                 )
 | |
|                 comp_scale.bind(
 | |
|                     "<Double-Button-1>", partial(self.reset_scale, "comp", 0)
 | |
|                 )
 | |
|                 comp_scale.bind("<Button-1>", self.scale_enter)
 | |
|                 comp_scale.bind("<ButtonRelease-1>", self.scale_leave)
 | |
| 
 | |
|                 # gate
 | |
|                 gate_label = ttk.Label(self, text="Gate")
 | |
|                 gate_scale = ttk.Scale(
 | |
|                     self,
 | |
|                     from_=0.0,
 | |
|                     to=10.0,
 | |
|                     orient="horizontal",
 | |
|                     length=_base_vals.level_width,
 | |
|                     variable=self.slider_vars[self.slider_params.index("gate")],
 | |
|                     command=partial(self.scale_callback, "gate"),
 | |
|                 )
 | |
|                 gate_scale.bind(
 | |
|                     "<Double-Button-1>", partial(self.reset_scale, "gate", 0)
 | |
|                 )
 | |
|                 gate_scale.bind("<Button-1>", self.scale_enter)
 | |
|                 gate_scale.bind("<ButtonRelease-1>", self.scale_leave)
 | |
| 
 | |
|                 # limit
 | |
|                 limit_label = ttk.Label(self, text="Limit")
 | |
|                 limit_scale = ttk.Scale(
 | |
|                     self,
 | |
|                     from_=-40,
 | |
|                     to=12,
 | |
|                     orient="horizontal",
 | |
|                     length=_base_vals.level_width,
 | |
|                     variable=self.slider_vars[self.slider_params.index("limit")],
 | |
|                     command=partial(self.scale_callback, "limit"),
 | |
|                 )
 | |
|                 limit_scale.bind(
 | |
|                     "<Double-Button-1>", partial(self.reset_scale, "limit", 12)
 | |
|                 )
 | |
|                 limit_scale.bind("<Button-1>", self.scale_enter)
 | |
|                 limit_scale.bind("<ButtonRelease-1>", self.scale_leave)
 | |
| 
 | |
|                 # Position sliders
 | |
|                 comp_label.grid(column=0, row=0)
 | |
|                 comp_scale.grid(column=1, row=0)
 | |
|                 gate_label.grid(column=2, row=0)
 | |
|                 gate_scale.grid(column=3, row=0)
 | |
|                 limit_label.grid(column=4, row=0)
 | |
|                 limit_scale.grid(column=5, row=0)
 | |
| 
 | |
|     def make_row1(self):
 | |
|         # create buttons
 | |
|         self.a_buttons = [
 | |
|             ttk.Checkbutton(
 | |
|                 self,
 | |
|                 text=param,
 | |
|                 command=partial(self.toggle_a, param),
 | |
|                 style=f"{'Toggle.TButton' if _base_vals.using_theme else f'{param}.TButton'}",
 | |
|                 variable=self.phys_out_params_vars[self.phys_out_params.index(param)],
 | |
|             )
 | |
|             for param in self.phys_out_params
 | |
|         ]
 | |
|         self.b_buttons = [
 | |
|             ttk.Checkbutton(
 | |
|                 self,
 | |
|                 text=param,
 | |
|                 command=partial(self.toggle_b, param),
 | |
|                 style=f"{'Toggle.TButton' if _base_vals.using_theme else f'{param}.TButton'}",
 | |
|                 variable=self.virt_out_params_vars[self.virt_out_params.index(param)],
 | |
|             )
 | |
|             for param in self.virt_out_params
 | |
|         ]
 | |
| 
 | |
|         # set button positions
 | |
|         [
 | |
|             button.grid(
 | |
|                 column=self.a_buttons.index(button),
 | |
|                 row=1,
 | |
|             )
 | |
|             for button in self.a_buttons
 | |
|         ]
 | |
|         [
 | |
|             button.grid(
 | |
|                 column=len(self.a_buttons) + self.b_buttons.index(button),
 | |
|                 row=1,
 | |
|             )
 | |
|             for button in self.b_buttons
 | |
|         ]
 | |
| 
 | |
|     def toggle_a(self, param):
 | |
|         val = self.phys_out_params_vars[self.phys_out_params.index(param)].get()
 | |
|         self.setter(param, val)
 | |
|         if not _base_vals.using_theme:
 | |
|             self.s.configure(
 | |
|                 f"{param}.TButton", background=f'{"green" if val else "white"}'
 | |
|             )
 | |
| 
 | |
|     def toggle_b(self, param):
 | |
|         val = self.virt_out_params_vars[self.virt_out_params.index(param)].get()
 | |
|         self.setter(param, val)
 | |
|         if not _base_vals.using_theme:
 | |
|             self.s.configure(
 | |
|                 f"{param}.TButton", background=f'{"green" if val else "white"}'
 | |
|             )
 | |
| 
 | |
|     def make_row2(self):
 | |
|         if self._parent.kind.name in ("Banana", "Potato"):
 | |
|             if self.index == self.phys_in:
 | |
|                 self.params = list(map(lambda x: x.replace("mono", "mc"), self.params))
 | |
|             if self._parent.kind.name == "Banana":
 | |
|                 pass
 | |
|                 # karaoke modes not in RT Packet yet. May implement in future
 | |
|                 """
 | |
|                 if self.index == self.phys_in + 1:
 | |
|                     self.params = list(
 | |
|                         map(lambda x: x.replace("mono", "k"), self.params)
 | |
|                     )
 | |
|                     self.param_vars[self.params.index("k")] = tk.IntVar
 | |
|                 """
 | |
|             else:
 | |
|                 if self.index == self.phys_in + self.virt_in - 1:
 | |
|                     self.params = list(
 | |
|                         map(lambda x: x.replace("mono", "mc"), self.params)
 | |
|                     )
 | |
| 
 | |
|         param_buttons = [
 | |
|             ttk.Checkbutton(
 | |
|                 self,
 | |
|                 text=param,
 | |
|                 command=partial(self.toggle_p, param),
 | |
|                 style=f"{'Toggle.TButton' if _base_vals.using_theme else f'{param}.TButton'}",
 | |
|                 variable=self.param_vars[self.params.index(param)],
 | |
|             )
 | |
|             for param in self.params
 | |
|         ]
 | |
|         [
 | |
|             button.grid(
 | |
|                 column=param_buttons.index(button),
 | |
|                 row=2,
 | |
|             )
 | |
|             for button in param_buttons
 | |
|         ]
 | |
| 
 | |
|     def toggle_p(self, param):
 | |
|         val = self.param_vars[self.params.index(param)].get()
 | |
|         self.setter(param, val)
 | |
|         if not _base_vals.using_theme:
 | |
|             self.s.configure(
 | |
|                 f"{param}.TButton", background=f'{"green" if val else "white"}'
 | |
|             )
 | |
| 
 | |
|     def sync(self):
 | |
|         [
 | |
|             self.phys_out_params_vars[self.phys_out_params.index(param)].set(
 | |
|                 self.getter(param)
 | |
|             )
 | |
|             for param in self.phys_out_params
 | |
|         ]
 | |
|         [
 | |
|             self.virt_out_params_vars[self.virt_out_params.index(param)].set(
 | |
|                 self.getter(param)
 | |
|             )
 | |
|             for param in self.virt_out_params
 | |
|         ]
 | |
|         [
 | |
|             self.param_vars[self.params.index(param)].set(self.getter(param))
 | |
|             for param in self.params
 | |
|         ]
 | |
|         if not _base_vals.using_theme:
 | |
|             [
 | |
|                 self.s.configure(
 | |
|                     f"{param}.TButton",
 | |
|                     background=f'{"green" if self.phys_out_params_vars[self.phys_out_params.index(param)].get() else "white"}',
 | |
|                 )
 | |
|                 for param in self.phys_out_params
 | |
|             ]
 | |
|             [
 | |
|                 self.s.configure(
 | |
|                     f"{param}.TButton",
 | |
|                     background=f'{"green" if self.virt_out_params_vars[self.virt_out_params.index(param)].get() else "white"}',
 | |
|                 )
 | |
|                 for param in self.virt_out_params
 | |
|             ]
 | |
|             [
 | |
|                 self.s.configure(
 | |
|                     f"{param}.TButton",
 | |
|                     background=f'{"green" if self.param_vars[self.params.index(param)].get() else "white"}',
 | |
|                 )
 | |
|                 for param in self.params
 | |
|             ]
 | |
| 
 | |
|     def sync_sliders(self):
 | |
|         [
 | |
|             self.slider_vars[self.slider_params.index(param)].set(self.getter(param))
 | |
|             for param in self.slider_params
 | |
|         ]
 | |
| 
 | |
|     def col_row_configure(self):
 | |
|         super(StripConfig, self).col_row_configure()
 | |
|         [
 | |
|             self.columnconfigure(i, minsize=80)
 | |
|             for i in range(self.phys_out + self.virt_out)
 | |
|         ]
 | |
| 
 | |
| 
 | |
| class BusConfig(Config):
 | |
|     def __init__(self, parent, index, _id):
 | |
|         super().__init__(parent, index, _id)
 | |
|         # fmt: off
 | |
|         # create parameter variables
 | |
|         self.bus_modes = (
 | |
|             "normal", "Amix", "Bmix", "Repeat", "Composite", "TVMix", "UpMix21",
 | |
|             "UpMix41", "UpMix61", "CenterOnly", "LFEOnly", "RearOnly",
 | |
|         )
 | |
|         # fmt: on
 | |
|         self.params = ("mono", "eq", "eq_ab")
 | |
|         self.param_vars = [tk.BooleanVar() for i, _ in enumerate(self.params)]
 | |
| 
 | |
|         self.make_row0()
 | |
|         self.make_row1()
 | |
| 
 | |
|         # sync all parameters
 | |
|         self.sync()
 | |
| 
 | |
|         self.col_row_configure()
 | |
| 
 | |
|     @property
 | |
|     def target(self):
 | |
|         """returns the current interface"""
 | |
|         _target = super(BusConfig, self).target
 | |
|         return getattr(_target, self.identifier)[self.index]
 | |
| 
 | |
|     def make_row0(self):
 | |
|         self._cur_bus_mode = tk.StringVar()
 | |
|         self._cur_bus_mode.set(f"Bus Mode: {self.bus_modes[self.get_current_index()]}")
 | |
|         self.busmode_button = ttk.Button(self, textvariable=self._cur_bus_mode)
 | |
|         self.busmode_button.grid(column=0, row=0, columnspan=2, sticky=(tk.W))
 | |
|         self.busmode_button.bind("<Button-1>", self.rotate_bus_modes_right)
 | |
|         self.busmode_button.bind("<Button-3>", self.rotate_bus_modes_left)
 | |
| 
 | |
|     def get_current_index(self):
 | |
|         for mode in self.bus_modes:
 | |
|             if getattr(self.target.mode, mode.lower()):
 | |
|                 return self.bus_modes.index(mode)
 | |
| 
 | |
|     def rotate_bus_modes_right(self, *args):
 | |
|         current_index = self.get_current_index()
 | |
|         if current_index + 1 < len(self.bus_modes):
 | |
|             next = self.bus_modes[current_index + 1]
 | |
|         else:
 | |
|             next = self.bus_modes[0]
 | |
|         setattr(self.target.mode, next.lower(), True)
 | |
|         self._cur_bus_mode.set(f"Bus Mode: {next}")
 | |
| 
 | |
|     def rotate_bus_modes_left(self, *args):
 | |
|         current_index = self.get_current_index()
 | |
|         if current_index == 0:
 | |
|             next = self.bus_modes[-1]
 | |
|         else:
 | |
|             next = self.bus_modes[current_index - 1]
 | |
|         setattr(self.target.mode, next.lower(), True)
 | |
|         self._cur_bus_mode.set(f"Bus Mode: {next}")
 | |
| 
 | |
|     def make_row1(self):
 | |
|         param_buttons = [
 | |
|             ttk.Checkbutton(
 | |
|                 self,
 | |
|                 text=param,
 | |
|                 command=partial(self.toggle_p, param),
 | |
|                 style=f"{'Toggle.TButton' if _base_vals.using_theme else f'{param}.TButton'}",
 | |
|                 variable=self.param_vars[self.params.index(param)],
 | |
|             )
 | |
|             for param in self.params
 | |
|         ]
 | |
|         [
 | |
|             button.grid(
 | |
|                 column=param_buttons.index(button),
 | |
|                 row=1,
 | |
|             )
 | |
|             for button in param_buttons
 | |
|         ]
 | |
| 
 | |
|     def toggle_p(self, param):
 | |
|         val = self.param_vars[self.params.index(param)].get()
 | |
|         self.setter(param, val)
 | |
|         if not _base_vals.using_theme:
 | |
|             self.s.configure(
 | |
|                 f"{param}.TButton", background=f'{"green" if val else "white"}'
 | |
|             )
 | |
| 
 | |
|     def col_row_configure(self):
 | |
|         super(BusConfig, self).col_row_configure()
 | |
|         [
 | |
|             self.columnconfigure(i, minsize=80)
 | |
|             for i in range(self.phys_out + self.virt_out)
 | |
|         ]
 | |
| 
 | |
|     def sync(self):
 | |
|         [
 | |
|             self.param_vars[self.params.index(param)].set(self.getter(param))
 | |
|             for param in self.params
 | |
|         ]
 | |
|         if not _base_vals.using_theme:
 | |
|             [
 | |
|                 self.s.configure(
 | |
|                     f"{param}.TButton",
 | |
|                     background=f'{"green" if self.param_vars[self.params.index(param)].get() else "white"}',
 | |
|                 )
 | |
|                 for param in self.params
 | |
|             ]
 |