mirror of
https://github.com/onyx-and-iris/vban-cmd-python.git
synced 2024-11-15 17:10:46 +00:00
remove gui from example (will readd later)
add observer to example
This commit is contained in:
parent
079bf177a1
commit
845ef2441e
@ -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.
|
|
@ -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("<Double-Button-1>", 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()
|
|
43
examples/observer/__main__.py
Normal file
43
examples/observer/__main__.py
Normal file
@ -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 <Enter> to exit\n"):
|
||||||
|
if not cmd:
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
kind_id = "potato"
|
||||||
|
opts = {
|
||||||
|
"ip": "<ip address>",
|
||||||
|
"streamname": "Command1",
|
||||||
|
"port": 6980,
|
||||||
|
}
|
||||||
|
|
||||||
|
main()
|
Loading…
Reference in New Issue
Block a user