mirror of
https://github.com/onyx-and-iris/vban-cmd-python.git
synced 2026-04-06 23:53:31 +00:00
major version bump due to dependency change.
now packaged with poetry. added to pypi. major version bump due to dependency change. interface reworked to match the remote-api interface. readme updated with changes to installation pre-commit hook temporarily removed
This commit is contained in:
@@ -1,16 +1,19 @@
|
||||
import tkinter as tk
|
||||
from tkinter import ttk
|
||||
from functools import partial
|
||||
from tkinter import ttk
|
||||
from typing import NamedTuple
|
||||
|
||||
import vbancmd
|
||||
from vbancmd import kinds
|
||||
import vban_cmd
|
||||
from vban_cmd import kinds
|
||||
|
||||
|
||||
class ExampleAppErrors(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class App(tk.Tk):
|
||||
""" Topmost Level of App """
|
||||
"""Topmost Level of App"""
|
||||
|
||||
@classmethod
|
||||
def make(cls, kind: NamedTuple):
|
||||
"""
|
||||
@@ -18,39 +21,50 @@ class App(tk.Tk):
|
||||
|
||||
Returns an App class of a kind
|
||||
"""
|
||||
APP_cls = type(f'App{kind.name}', (cls,), {
|
||||
'name': kind.name,
|
||||
'ins': kind.ins,
|
||||
'outs': kind.outs,
|
||||
}
|
||||
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.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.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}',
|
||||
"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)],
|
||||
"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)],
|
||||
"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)]
|
||||
[
|
||||
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()
|
||||
@@ -60,68 +74,86 @@ class App(tk.Tk):
|
||||
|
||||
@property
|
||||
def id_(self):
|
||||
return 'strip'
|
||||
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.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.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))
|
||||
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 """
|
||||
"""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 """
|
||||
"""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 """
|
||||
"""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()]
|
||||
[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.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.id: App.make(kind) for kind in kinds.all}
|
||||
_apps = {kind.id: App.make(kind) for kind in kinds.all}
|
||||
|
||||
|
||||
def connect(kind_id: str) -> App:
|
||||
""" return App of the kind requested """
|
||||
"""return App of the kind requested"""
|
||||
try:
|
||||
APP_cls = _apps[kind_id]
|
||||
return APP_cls()
|
||||
except KeyError:
|
||||
raise ExampleAppErrors(f'Invalid kind: {kind_id}')
|
||||
raise ExampleAppErrors(f"Invalid kind: {kind_id}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
kind_id = 'potato'
|
||||
kind_id = "potato"
|
||||
opts = {
|
||||
# make sure VBAN is configured on remote machine then set IP accordingly
|
||||
'ip': 'ws.local',
|
||||
'streamname': 'testing',
|
||||
'port': 6990,
|
||||
"ip": "ws.local",
|
||||
"streamname": "testing",
|
||||
"port": 6990,
|
||||
}
|
||||
|
||||
with vbancmd.connect(kind_id, **opts) as vban:
|
||||
with vban_cmd.connect(kind_id, **opts) as vban:
|
||||
app = connect(kind_id)
|
||||
app.mainloop()
|
||||
|
||||
Reference in New Issue
Block a user