323 lines
7.9 KiB
Python
Executable File
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()
|
|
|
|
|
|
|