diff --git a/vmcompact/app.py b/vmcompact/app.py index 049b690..da6829f 100644 --- a/vmcompact/app.py +++ b/vmcompact/app.py @@ -61,6 +61,11 @@ class App(tk.Tk): # start pdirty watcher self.upd_pdirty() + self.strip_levels = None + self.bus_levels = None + self._strip_levels = None + self._bus_levels = None + self.watch_levels() self.resizable(False, False) if _base_vals.themes_enabled: @@ -85,6 +90,14 @@ class App(tk.Tk): def pdirty(self, val): self._pdirty = val + @property + def ldirty(self): + return self._ldirty + + @ldirty.setter + def ldirty(self, val): + self._ldirty = val + @property def configuration(self): return configuration["app"] @@ -155,7 +168,27 @@ class App(tk.Tk): def upd_pdirty_step(self): self.pdirty = self.target.pdirty - self.after(1, self.upd_pdirty_step) + self.after(_base_vals.pdelay, self.upd_pdirty_step) + + def watch_levels(self): + self.after(1, self.watch_levels_step) + + def watch_levels_step(self): + """ + Continuously fetch level arrays, only update + if ldirty + """ + self._strip_levels = self.target.strip_levels + self._bus_levels = self.target.bus_levels + + self.ldirty = not ( + self.strip_levels == self._strip_levels + and self.bus_levels == self._bus_levels + ) + if self.ldirty: + self.strip_levels = self._strip_levels + self.bus_levels = self._bus_levels + self.after(_base_vals.ldelay, self.watch_levels_step) def dragging(self, event, *args): if event.widget is self: diff --git a/vmcompact/channels.py b/vmcompact/channels.py index 21cbe44..9692671 100644 --- a/vmcompact/channels.py +++ b/vmcompact/channels.py @@ -1,6 +1,7 @@ import tkinter as tk from tkinter import ttk from functools import partial +from math import log from .data import _base_vals from .config import StripConfig, BusConfig @@ -76,6 +77,11 @@ class Channel(ttk.LabelFrame): self.setter("gain", self.gain.get()) self._parent._parent.nav_frame.info_text.set(round(self.gain.get(), 1)) + def convert_level(self, val): + if _base_vals.vban_connected: + return round(-val * 0.01, 1) + return round(20 * log(val, 10), 1) if val > 0 else -200.0 + def _make_widgets(self): """Creates a progressbar, scale, mute button and config button for a single channel""" # Progress bar @@ -131,7 +137,7 @@ class Channel(ttk.LabelFrame): """keeps params synced but ensures sliders are responsive""" if self._parent._parent.pdirty and not _base_vals.in_scale_button_1: self.sync() - self.after(1, self.watch_pdirty_step) + self.after(_base_vals.pdelay, self.watch_pdirty_step) def sync(self): """sync params with voicemeeter""" @@ -201,14 +207,39 @@ class Strip(Channel): def watch_levels_step(self): if not _base_vals.dragging: - vals = self.target.levels.prefader - val = vals[0] if vals[0] > vals[1] else vals[0] - self.level.set(val) - self.level.set( - (0 if self.mute.get() else 100 + (val - 18) + self.gain.get()) - ) + if self._parent._parent.ldirty: + if self.index <= self._parent.phys_in: + vals = ( + self.convert_level( + self._parent._parent.strip_levels[self.index * 2] + ), + self.convert_level( + self._parent._parent.strip_levels[self.index * 2 + 1] + ), + ) + else: + vals = ( + self.convert_level( + self._parent._parent.strip_levels[ + self._parent.phys_in * 2 + + (self.index - self._parent.phys_in) * 8 + ] + ), + self.convert_level( + self._parent._parent.strip_levels[ + self._parent.phys_in * 2 + + (self.index - self._parent.phys_in) * 8 + + 1 + ] + ), + ) + peak = vals[0] if vals[0] > vals[1] else vals[0] + self.level.set( + (0 if self.mute.get() else 100 + (peak - 18) + self.gain.get()) + ) self.after( - 25 if not _base_vals.in_scale_button_1 else 100, self.watch_levels_step + _base_vals.ldelay if not _base_vals.in_scale_button_1 else 100, + self.watch_levels_step, ) @@ -251,14 +282,18 @@ class Bus(Channel): def watch_levels_step(self): if not _base_vals.dragging: - vals = self.target.levels.all - val = vals[0] if vals[0] > vals[1] else vals[0] - self.level.set(val) - self.level.set( - (0 if self.mute.get() else 100 + (val - 18) + self.gain.get()) - ) + if self._parent._parent.ldirty: + vals = ( + self.convert_level(self._parent._parent.bus_levels[self.index * 8]), + self.convert_level( + self._parent._parent.bus_levels[self.index * 8 + 1] + ), + ) + peak = vals[0] if vals[0] > vals[1] else vals[0] + self.level.set((0 if self.mute.get() else 100 + (peak - 18))) self.after( - 25 if not _base_vals.in_scale_button_1 else 100, self.watch_levels_step + _base_vals.ldelay if not _base_vals.in_scale_button_1 else 100, + self.watch_levels_step, ) @@ -364,7 +399,7 @@ class ChannelFrame(ttk.Frame): def watch_pdirty_step(self): if self._parent.pdirty: self.watch_labels() - self.after(1, self.watch_pdirty_step) + self.after(_base_vals.pdelay, self.watch_pdirty_step) def watch_labels(self): for i, labelframe in enumerate(self.labelframes): diff --git a/vmcompact/config.py b/vmcompact/config.py index 4a0cea0..0b3d4c1 100644 --- a/vmcompact/config.py +++ b/vmcompact/config.py @@ -67,7 +67,7 @@ class Config(ttk.Frame): """keeps params synced but ensures sliders are responsive""" if self._parent.pdirty and not _base_vals.in_scale_button_1: self.sync() - self.after(1, self.watch_pdirty_step) + self.after(_base_vals.pdelay, self.watch_pdirty_step) class StripConfig(Config): diff --git a/vmcompact/data.py b/vmcompact/data.py index 200ef78..a5c3c95 100644 --- a/vmcompact/data.py +++ b/vmcompact/data.py @@ -21,6 +21,10 @@ class BaseValues: using_theme: bool = False # bus assigned as current submix submixes: int = 0 + # pdirty delay + pdelay: int = 50 + # ldirty delay + ldelay: int = 50 _base_vals = BaseValues() diff --git a/vmcompact/gainlayer.py b/vmcompact/gainlayer.py index 88422e0..c6d0f44 100644 --- a/vmcompact/gainlayer.py +++ b/vmcompact/gainlayer.py @@ -1,6 +1,7 @@ import tkinter as tk from tkinter import ttk, messagebox as msg from functools import partial +from math import log from .data import _base_vals @@ -74,6 +75,11 @@ class GainLayer(ttk.LabelFrame): background=f'{"green" if self.on.get() else "white"}', ) + def convert_level(self, val): + if _base_vals.vban_connected: + return round(-val * 0.01, 1) + return round(20 * log(val, 10), 1) if val > 0 else -200.0 + def _make_widgets(self): """Creates a progressbar, scale, on button and config button for a single channel""" # Progress bar @@ -135,7 +141,7 @@ class GainLayer(ttk.LabelFrame): """keeps params synced but ensures sliders are responsive""" if self._parent._parent.pdirty and not _base_vals.in_scale_button_1: self.sync() - self.after(1, self.watch_pdirty_step) + self.after(_base_vals.pdelay, self.watch_pdirty_step) def sync(self): """sync params with voicemeeter""" @@ -156,18 +162,45 @@ class GainLayer(ttk.LabelFrame): def watch_levels_step(self): if not _base_vals.dragging: - vals = self._parent.target.strip[self.index].levels.prefader - val = vals[0] if vals[0] > vals[1] else vals[0] - self.level.set(val) - self.level.set( - ( - 0 - if self._parent._parent.channel_frame.strips[self.index].mute.get() - else 100 + (val - 18) + self.gain.get() + if self._parent._parent.ldirty: + if self.index <= self._parent.phys_in: + vals = ( + self.convert_level( + self._parent._parent.strip_levels[self.index * 2] + ), + self.convert_level( + self._parent._parent.strip_levels[self.index * 2 + 1] + ), + ) + else: + vals = ( + self.convert_level( + self._parent._parent.strip_levels[ + self._parent.phys_in * 2 + + (self.index - self._parent.phys_in) * 8 + ] + ), + self.convert_level( + self._parent._parent.strip_levels[ + self._parent.phys_in * 2 + + (self.index - self._parent.phys_in) * 8 + + 1 + ] + ), + ) + peak = vals[0] if vals[0] > vals[1] else vals[0] + self.level.set( + ( + 0 + if self._parent._parent.channel_frame.strips[ + self.index + ].mute.get() + else 100 + (peak - 18) + self.gain.get() + ) ) - ) self.after( - 25 if not _base_vals.in_scale_button_1 else 100, self.watch_levels_step + _base_vals.ldelay if not _base_vals.in_scale_button_1 else 100, + self.watch_levels_step, ) @@ -175,6 +208,7 @@ class SubMixFrame(ttk.Frame): def __init__(self, parent): super().__init__(parent) self._parent = parent + self.phys_in, self.virt_in = parent.kind.ins self.phys_out, self.virt_out = parent.kind.outs self.buses = tuple(f"A{i+1}" for i in range(self.phys_out)) + tuple( f"B{i+1}" for i in range(self.virt_out) @@ -232,7 +266,7 @@ class SubMixFrame(ttk.Frame): def watch_pdirty_step(self): if self._parent.pdirty: self.watch_labels() - self.after(1, self.watch_pdirty_step) + self.after(_base_vals.pdelay, self.watch_pdirty_step) def watch_labels(self): for i, gainlayer in enumerate(self.gainlayers):