diff --git a/examples/gui/README.md b/examples/gui/README.md deleted file mode 100644 index bc5b979..0000000 --- a/examples/gui/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# Simple Tkinter GUI -No dependencies required, Tkinter should come packaged with Python 3.9+. -This is a demonstration app with very limited control, showing strips across all three versions. - -### Use -Ensure VBAN is enabled and the TEXT incoming stream is configured and ON. - -Set the kind_id, ip, streamname and port in the code. diff --git a/examples/gui/__main__.py b/examples/gui/__main__.py deleted file mode 100644 index 2cdd80e..0000000 --- a/examples/gui/__main__.py +++ /dev/null @@ -1,159 +0,0 @@ -import tkinter as tk -from functools import partial -from tkinter import ttk -from typing import NamedTuple - -import vban_cmd -from vban_cmd import kinds - - -class ExampleAppErrors(Exception): - pass - - -class App(tk.Tk): - """Topmost Level of App""" - - @classmethod - def make(cls, kind: NamedTuple): - """ - Factory function for App - - Returns an App class of a kind - """ - APP_cls = type( - f"App{kind.name}", - (cls,), - { - "name": kind.name, - "ins": kind.ins, - "outs": kind.outs, - }, - ) - return APP_cls - - def __init__(self): - super().__init__() - self.title(f"Voicemeeter{self.name} Example Program") - self.phys_in, self.virt_in = self.ins - self.col = self.phys_in + self.virt_in - self.row = 3 - self.w = {"basic": 300, "banana": 600, "potato": 800} - self.h = 150 - self.defaultsizes = { - "basic": f"{self.w[self.name]}x{self.h}", - "banana": f"{self.w[self.name]}x{self.h}", - "potato": f"{self.w[self.name]}x{self.h}", - } - self.geometry(self.defaultsizes[self.name]) - - """ create tkinter variables, generate widgets and configure rows/cols """ - self.gains = { - "strip": [tk.DoubleVar() for i in range(self.phys_in + self.virt_in)], - } - self.levels = { - "strip": [tk.DoubleVar() for i in range(self.phys_in + self.virt_in)], - } - [ - self._make_single_channel(i, j) - for i, j in enumerate(i for i in range(0, self.col * 2, 2)) - ] - scales = [ - widget for widget in self.winfo_children() if isinstance(widget, tk.Scale) - ] - [ - scale.bind("", partial(self.reset_gain, index=i)) - for i, scale in enumerate(scales) - ] - - """ configure grid """ - self.col_row_configure() - - """ initiate watchers """ - [self.watch_levels(i) for i in range(self.col)] - - @property - def id_(self): - return "strip" - - def _make_single_channel(self, i, j): - """ - Creates a label, progressbar, scale, and mute - """ - ttk.Label(self, text=f"{vban.strip[i].label}").grid( - column=j, row=0, columnspan=2 - ) - - ttk.Progressbar( - self, - maximum=72, - orient="vertical", - mode="determinate", - variable=self.levels[self.id_][i], - ).grid(column=j, row=1) - ttk.Scale( - self, - from_=12.0, - to=-60.0, - orient="vertical", - variable=self.gains[self.id_][i], - command=partial(self.scale_callback, index=i), - ).grid(column=j + 1, row=1) - - ttk.Button( - self, - text="MUTE", - command=partial(self.toggle, "mute", i), - style=f"Mute{i}.TButton", - ).grid(column=j, row=2, columnspan=2, sticky=(tk.W, tk.E)) - - def scale_callback(self, *args, index=None): - """callback function for scale widgets""" - vban.strip[index].gain = self.gains[self.id_][index].get() - - def reset_gain(self, *args, index=None): - """reset gain to 0 when double click mouse""" - vban.strip[index].gain = 0 - self.gains[self.id_][index].set(0) - - def toggle(self, param, index): - """toggles a strip parameter""" - setattr(vban.strip[index], param, not getattr(vban.strip[index], param)) - - def col_row_configure(self): - [self.columnconfigure(i, weight=1) for i in range(self.col * 2)] - [child.grid_configure(padx=1, pady=1) for child in self.winfo_children()] - - def watch_levels(self, i): - self.after(1, self.watch_levels_step, i) - - def watch_levels_step(self, i): - val = vban.strip[i].levels.prefader[0] + vban.strip[i].gain - self.levels[self.id_][i].set((0 if vban.strip[i].mute else 100 + (val - 30))) - self.after(20, self.watch_levels_step, i) - - -_apps = {kind.name: App.make(kind) for kind in kinds.kinds_all} - - -def connect(kind_id: str) -> App: - """return App of the kind requested""" - try: - APP_cls = _apps[kind_id] - return APP_cls() - except KeyError: - raise ExampleAppErrors(f"Invalid kind: {kind_id}") - - -if __name__ == "__main__": - kind_id = "potato" - opts = { - # make sure VBAN is configured on remote machine then set IP accordingly - "ip": "ws.local", - "streamname": "workstation", - "port": 6990, - } - - with vban_cmd.api(kind_id, **opts) as vban: - app = connect(kind_id) - app.mainloop() diff --git a/examples/observer/__main__.py b/examples/observer/__main__.py new file mode 100644 index 0000000..cfb2e93 --- /dev/null +++ b/examples/observer/__main__.py @@ -0,0 +1,43 @@ +import vban_cmd + + +class Observer: + def __init__(self, vban): + self.vban = vban + + def on_update(self, subject): + if subject == "pdirty": + print("pdirty!") + if subject == "ldirty": + info = ( + f"[{self.vban.bus[0]} {self.vban.bus[0].levels.is_updated}]", + f"[{self.vban.bus[1]} {self.vban.bus[1].levels.is_updated}]", + f"[{self.vban.bus[2]} {self.vban.bus[2].levels.is_updated}]", + f"[{self.vban.bus[3]} {self.vban.bus[3].levels.is_updated}]", + f"[{self.vban.bus[4]} {self.vban.bus[4].levels.is_updated}]", + f"[{self.vban.bus[5]} {self.vban.bus[5].levels.is_updated}]", + f"[{self.vban.bus[6]} {self.vban.bus[6].levels.is_updated}]", + f"[{self.vban.bus[7]} {self.vban.bus[7].levels.is_updated}]", + ) + print(" ".join(info)) + + +def main(): + with vban_cmd.api(kind_id, **opts) as vban: + obs = Observer(vban) + vban.subject.add(obs) + + while cmd := input("Press to exit\n"): + if not cmd: + break + + +if __name__ == "__main__": + kind_id = "potato" + opts = { + "ip": "", + "streamname": "Command1", + "port": 6980, + } + + main()