audioMux/gui/app.py

323 lines
7.9 KiB
Python
Executable File

#!/bin/python
import serial
import wx
import threading
import serial_ports
class AudioMuxConnection(threading.Thread):
def __init__(self, port=None):
super().__init__()
self.transport = None
self.buffer = ""
self.running = 0
if port:
self.open(port)
def open(self, portname):
self.transport = serial.Serial(portname, timeout=1)
self.buffer = ""
self.onConnected()
def close(self):
if self.transport:
self.stop()
self.transport.close()
self.transport = None
def write(self, msg):
if self.transport:
self.transport.write((str(msg) + "\n").encode("ASCII"))
def run(self):
self.running = 1
self.write("?") # query current state
while self.running:
self.onData(self.transport.read_all())
self.transport.close()
self.running = 0
def stop(self):
if self.running:
self.running = 0
self.join()
def onData(self, data):
""" Decodes all messages that are received from the audiomux """
self.buffer += data.decode("ASCII")
if "\n" in self.buffer:
lines = self.buffer.split("\n")
self.buffer = lines[-1]
for line in lines[:-1]:
self.onMessage(line)
def onMessage(self, msg):
""" The callback for a new message """
pass
def onConnected(self):
""" The Callback for a successfull connection """
pass
class ConnectionPanel(wx.Panel):
def __init__(self, parent, onAccepted=None):
super().__init__(parent)
self.choice = wx.Choice(self, choices=serial_ports.list_all())
self.button = wx.Button(self, label="Connect")
self.button.Bind(wx.EVT_BUTTON, self.onSelected)
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(self.choice, wx.EXPAND)
sizer.Add(self.button)
self.SetSizerAndFit(sizer)
self.onAccepted = onAccepted
def onSelected(self, evt):
self.value = self.choice.GetSelection()
if self.value and self.onAccepted:
self.onAccepted(self.value)
@property
def value(self):
if hasattr(self, "_value") and self._value != wx.NOT_FOUND:
return self.choice.GetString(self._value)
return None
@value.setter
def value(self, v):
self._value = v
def Success(self):
self.choice.Enable(0)
self.button.SetLabel("Disconnect")
def Clear(self):
self.choice.Clear()
self.choice.AppendItems(serial_ports.list_all())
self.choice.Enable(1)
self.button.SetLabel("Connect")
class InputButtons(wx.Panel):
def __init__(self, parent, onChange=None):
super().__init__(parent)
sizer = wx.BoxSizer(wx.HORIZONTAL)
self.onChange = onChange
self.buttons = {}
for i in range(6):
self.buttons[i] = wx.ToggleButton(self, size=(30,30), label="{}".format(i+1), id = i)
self.buttons[i].Bind(wx.EVT_TOGGLEBUTTON, lambda evt: self.onClick(evt.GetId()))
sizer.Add(self.buttons[i], wx.EXPAND | wx.SHAPED)
self.SetSizer(sizer)
def SetActive(self, num):
for i in self.buttons:
if num == i:
self.buttons[i].SetValue(1)
else:
self.buttons[i].SetValue(0)
def SetAll(self):
for button in self.buttons.values():
button.SetValue(1)
def onClick(self, num):
self.SetActive(num)
if self.onChange:
self.onChange(num)
class MainPanel(wx.Panel):
def __init__(self, parent):
super().__init__(parent)
self.parent = parent
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.Inputs(), 0, wx.EXPAND)
sizer.Add(wx.StaticLine(self), 0, wx.EXPAND)
sizer.Add(self.Sliders(), 1, wx.EXPAND)
sizer.Add(wx.StaticLine(self), 0, wx.EXPAND)
sizer.Add(self.Buttons())
self.SetSizer(sizer)
def Inputs(self):
self.inputs = InputButtons(self, lambda num: self.reqInputChange(num))
return self.inputs
def Sliders(self):
self.gain = wx.Slider(self, style=wx.SL_VERTICAL|wx.SL_INVERSE, minValue=0, maxValue=20, size=(30,100))
self.latt = wx.Slider(self, style=wx.SL_VERTICAL , minValue=0, maxValue=90, size=(30,100))
self.ratt = wx.Slider(self, style=wx.SL_VERTICAL , minValue=0, maxValue=90, size=(30,100))
self.bboost = wx.Slider(self, style=wx.SL_VERTICAL|wx.SL_INVERSE, minValue=0, maxValue=6, size=(30,100))
self.tboost = wx.Slider(self, style=wx.SL_VERTICAL|wx.SL_INVERSE, minValue=0, maxValue=6, size=(30,100))
self.SliderEvent(self.gain, "G")
self.SliderEvent(self.latt, "L")
self.SliderEvent(self.ratt, "R")
self.SliderEvent(self.bboost, "B")
self.SliderEvent(self.tboost, "T")
sizer = wx.BoxSizer(wx.HORIZONTAL)
self.SliderLabel(sizer, self.gain, "Gain")
self.SliderLabel(sizer, self.latt, "L")
self.SliderLabel(sizer, self.ratt, "R")
self.SliderLabel(sizer, self.bboost, "Bass Boost")
self.SliderLabel(sizer, self.tboost, "Treble Boost")
sizer.AddStretchSpacer()
return sizer
def SliderEvent(self, slider, command):
slider.Bind(wx.EVT_SLIDER, lambda evt: self.parent.write("{}{}".format(command, evt.GetInt())))
def SliderLabel(self, sizer, slider, label):
sizer.AddStretchSpacer()
temp = wx.BoxSizer(wx.VERTICAL)
temp.Add(slider, 1, wx.EXPAND|wx.ALL)
temp.Add(wx.StaticText(self, label=label, style=wx.ALIGN_CENTRE), 0, wx.ALL)
sizer.Add(temp, 0, wx.EXPAND | wx.ALL)
def Buttons(self):
self.muteBtn = wx.ToggleButton(self, label="Mute")
self.muteBtn.Bind(wx.EVT_TOGGLEBUTTON, lambda evt: self.parent.write("M{}".format(int(evt.IsChecked()))))
self.shortBtn = wx.ToggleButton(self, label="Short")
self.shortBtn.Bind(wx.EVT_TOGGLEBUTTON, lambda evt: self.parent.write("S{}".format(int(evt.IsChecked()))))
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(self.muteBtn)
sizer.Add(self.shortBtn)
sizer.AddStretchSpacer()
return sizer
def reqInputChange(self, num):
self.parent.write("C{}".format(num))
def setInput(self, num):
self.inputs.SetActive(num)
def setGain(self, num):
self.gain.setValue(num)
def setTreble(self, num):
self.tboost.SetValue(num)
def setBass(self, num):
self.bboost.SetValue(num)
def setLeftAtt(self, num):
self.latt.SetValue(num)
def setRightAtt(self, num):
self.ratt.SetValue(num)
def mute(self, m):
self.muteBtn.SetValue(m)
self.shortBtn.Enable(not m)
self.inputs.Enable(not m)
def short(self, m):
self.shortBtn.SetValue(m)
self.muteBtn.Enable(not m)
self.inputs.Enable(not m)
if m:
self.inputs.SetAll()
class Frame(wx.Frame, AudioMuxConnection):
def __init__(self):
# init parents
wx.Frame.__init__(self,None, title="AudioMux Control")
AudioMuxConnection.__init__(self)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.newConnectionPanel(), 0, wx.EXPAND)
sizer.Add(wx.StaticLine(self), 0, wx.EXPAND)
sizer.Add(self.newMainPanel(), 1, wx.EXPAND)
self.SetSizerAndFit(sizer)
def newMainPanel(self):
self.mainPanel = MainPanel(self)
self.mainPanel.Enable(0)
return self.mainPanel
def newConnectionPanel(self):
self.connectionPanel = ConnectionPanel(self, lambda choice: self.onConnectionRequest(choice))
return self.connectionPanel
def onConnectionRequest(self, choice):
if self.running:
# stop the connection and update connection dialog
self.close()
self.connectionPanel.Clear()
self.mainPanel.Enable(0)
else:
# try to start the serial connection
AudioMuxConnection.__init__(self, choice)
def onConnected(self):
# serial connection established
self.connectionPanel.Success()
self.start()
self.mainPanel.Enable(1)
def onMessage(self, msg):
msg = msg.strip("\r\n ")
if msg[0] == 'C':
num = int(msg.strip("C"))
self.mainPanel.setInput(num)
elif msg[0] == 'G':
num = int(msg.strip("G"))
self.mainPanel.setGain(num)
elif msg[0] == 'T':
num = int(msg.strip("T"))
self.mainPanel.setTreble(num)
elif msg[0] == 'B':
num = int(msg.strip("B"))
self.mainPanel.setBass(num)
elif msg[0] == 'M':
num = int(msg.strip("M"))
self.mainPanel.mute(num)
elif msg[0] == 'S':
num = int(msg.strip("S"))
self.mainPanel.short(num)
elif msg[0] == 'L':
num = int(msg.strip("L"))
self.mainPanel.setLeftAtt(num)
elif msg[0] == 'R':
num = int(msg.strip("R"))
self.mainPanel.setRightAtt(num)
if __name__ == "__main__":
app = wx.App()
frame = Frame()
try:
frame.Show()
app.MainLoop()
finally:
frame.close()