Browse Source

added python sources

subDesTagesMitExtraKaese 4 years ago
parent
commit
4b91895eab
16 changed files with 4044 additions and 0 deletions
  1. 27 0
      README.md
  2. 199 0
      audio.py
  3. 221 0
      audioHandler.py
  4. 109 0
      audio_output.py
  5. 31 0
      beatDetection.py
  6. 44 0
      displayHandler.py
  7. 183 0
      gui.py
  8. BIN
      lc444_audio.png
  9. BIN
      lc444_control.png
  10. 190 0
      main.py
  11. 31 0
      mqttHandler.py
  12. 2 0
      run.bat
  13. 101 0
      serialHandler.py
  14. 65 0
      storage.py
  15. 804 0
      ui.py
  16. 2037 0
      ui.ui

+ 27 - 0
README.md

@@ -0,0 +1,27 @@
+# LC444 firmware
+
+[`cube_control.ino`](cube_control.ino)
+
+# LC444 Control GUI
+
+`$ python3 gui.py`
+
+![lc444_control](lc444_control.png)
+
+# LC444 Audio visualizer
+
+`$ python3 main.py`
+```bash
+main.py 
+  -s (shadow, no GUI) 
+  -i (use mic instead of loopback) 
+  -f --framerate <f=60>
+  -t --time <t=0.033> 
+  -b --brightness <b=15> 
+  -w --write <filename.wav>
+```
+![lc444_audio](lc444_audio.png)
+* audio FFT
+* beat detection
+* visualization on 4x4x4 LED cube
+* MQTT broadcast

+ 199 - 0
audio.py

@@ -0,0 +1,199 @@
+import pyaudio
+import serial
+from serial import SerialException
+import _thread
+import struct
+import numpy as np
+import math
+import time
+import random
+
+import paho.mqtt.client as mqtt
+from beatDetection import SimpleBeatDetection
+
+nFFT = 512
+CHUNKSIZE = nFFT * 4 # fixed chunk size
+SAMPLERATE = 44100
+FORMAT = pyaudio.paInt16
+
+# initialize portaudio
+p = pyaudio.PyAudio()
+MAX_y = 2.0 ** (p.get_sample_size(pyaudio.paInt16) * 8 - 1)
+
+ser = None
+portName="COM7"
+
+while not ser:
+	try:
+		ser = serial.Serial(portName, 115200)
+	except serial.SerialException:
+		print(portName, " not available")
+		portName="COM" + input("COM")
+
+print("Connected to ", ser.name)
+
+info = p.get_host_api_info_by_index(0)
+numdevices = info.get('deviceCount')
+#for each audio device, determine if is an input or an output and add it to the appropriate list and dictionary
+
+DEVICE = -1
+
+for i in range (0,numdevices):
+	info = p.get_device_info_by_host_api_device_index(0,i)
+	if info.get('maxInputChannels')>0:
+		print ("Input Device id ", i, " - ", info.get('name'))
+		if "High" in info.get('name'):
+			DEVICE = i
+
+	#if p.get_device_info_by_host_api_device_index(0,i).get('maxOutputChannels')>0:
+	#	print ("Output Device id ", i, " - ", p.get_device_info_by_host_api_device_index(0,i).get('name'))
+
+if DEVICE == -1:
+	DEVICE = int(input("Device? "))
+
+stream = p.open(format=pyaudio.paInt16, channels=2, rate=SAMPLERATE, input=True,input_device_index=DEVICE, frames_per_buffer=CHUNKSIZE)
+
+devinfo = p.get_device_info_by_index(DEVICE)
+print ("Selected device is ",devinfo.get('name'), " at ", SAMPLERATE, " Hz")
+if p.is_format_supported(SAMPLERATE,	# Sample rate
+												 input_device=devinfo["index"],
+												 input_channels=devinfo['maxInputChannels'],
+												 input_format=pyaudio.paInt16):
+	print ('Audio seems to be ok!')
+
+def read():
+		while 1:
+				if ser.inWaiting()>0:
+						print(ser.read(ser.inWaiting()).decode("utf-8"))
+				time.sleep(.1)
+_thread.start_new_thread( read, () )
+
+def write(val):
+		ser.write((int(val)&0xFF).to_bytes(1, byteorder='big', signed=False))
+def writeInt(val):
+		ser.write((int(val)&0xFFFF).to_bytes(2, byteorder='big', signed=False))
+def writeLng(val):
+		ser.write((int(val)&0xFFFFFFFF).to_bytes(4, byteorder='big', signed=False))
+
+		
+def on_message(mqttc, obj, msg):
+	print(msg)
+		
+def on_log(mqttc, obj, level, string):
+	print(string)
+
+def on_connect(client, userdata, flags, rc):
+	print("Connected with result code "+str(rc))
+	mqttc.subscribe("Timer/#", 2)
+	mqttc.subscribe("Pc/#", 2)
+
+# If you want to use a specific client id, use
+# mqttc = mqtt.Client("client-id")
+# but note that the client id must be unique on the broker. Leaving the client
+# id parameter empty will generate a random id for you.
+mqttc = mqtt.Client()
+
+mqttc.on_message = on_message
+mqttc.on_connect = on_connect
+
+# Uncomment to enable debug messages
+#mqttc.on_log = on_log
+
+mqttc.connect_async("192.168.0.2", 1883, 60)
+
+mqttc.loop_start()
+		
+		
+sbd = SimpleBeatDetection(100)
+		
+		
+val=[0]*64
+ser.write(b'~u~t~c ')
+timeout = 0
+oldBeat = False
+tBeat = 0
+nBeat = 0
+
+while 1:
+	#start = time.time()
+	N = int(max(stream.get_read_available() / nFFT, 1) * nFFT)
+	data = stream.read(N)
+	
+	y = np.array(struct.unpack("%dh" % (N * 2), data)) / MAX_y
+	y_L = y[::2]
+	y_R = y[1::2]
+	Y_L = np.fft.fft(y_L, nFFT)
+	Y_R = np.fft.fft(y_R, nFFT)
+	Y = abs(np.hstack((Y_L[int(-nFFT / 2):-1], Y_R[0:int(nFFT / 2)])))
+	
+	buf = []
+	
+	for z in range(4):
+		for y in range(4):
+			for x in range(4):
+				if x in [1,2]:
+					if y == 0:
+							a=np.sum(Y[259:266])/30*16 - z*4 + 32 #right channel
+					elif y == 1:
+							a=np.sum(Y[256:259])/40*16 - z*4 + 32
+					elif y == 2:
+							a=np.sum(Y[252:256])/40*16 - z*4 + 32 #left channel
+					else:
+							a=np.sum(Y[240:247])/30*16 - z*4 + 32
+				else:
+					if y == 0:
+							a=np.sum(Y[264:270])/20*16 - z*4 + 32 #right channel
+					elif y == 1:
+							a=np.sum(Y[258:264])/40*16 - z*4 + 32										
+					elif y == 2:
+							a=np.sum(Y[247:253])/40*16 - z*4 + 32 #left channel
+					else:
+							a=np.sum(Y[236:242])/20*16 - z*4 + 32
+						
+				if a>val[x+y*4+z*16]:
+						val[x+y*4+z*16]=a
+				else:
+						a=val[x+y*4+z*16]=val[x+y*4+z*16] * 0.8 + a * 0.2
+						
+				if a<32 : a = 32
+				elif a>47 : a = 47
+				buf.append(int(a))
+	ser.write(b'~a')
+	ser.write(bytearray(buf))
+	
+	s = sum(buf)
+	
+	if s == 32*64:
+		timeout += 1
+	else:
+		timeout = 0
+		
+	
+	signal = np.frombuffer(data, np.int16)
+	beat = sbd.detect_beat(signal)
+	
+
+	if beat == 0:
+		tBeat += 1	
+	
+	if beat == True and timeout == 0 and tBeat > 3:
+		
+		tBeat = 0
+		nBeat += 1
+		json = "{\"spot\":[{\"color\":" + str(256*256-1) + ",\"radius\":" + str(int(s/64-32)*3+2) + ",\"pos\":" + str(10 + nBeat%4 * 10) + ",\"keep\":0}],\"speed\":40}"
+		#print("  ------------------ " + json)
+		mqttc.publish("RgbLamp/spot", json)
+
+	oldBeat = beat
+	
+	if timeout > 1000:
+		time.sleep(0.3)
+	else:
+		time.sleep(0.015)
+
+		
+# close stream
+stream.stop_stream()
+stream.close()
+p.terminate()
+ser.close() 

+ 221 - 0
audioHandler.py

@@ -0,0 +1,221 @@
+import pyaudio
+import wave
+import os
+
+from collections import deque
+import numpy as np
+import struct
+
+class Listener:
+	def __init__(self, dataTime = 1/20, agcTime = 10, input = False):
+		self._dataTime = dataTime
+		self._agcTime = agcTime
+		self._input = input
+		self.buffersize = 512
+		self.p = pyaudio.PyAudio()
+		
+		self.left = self.right = self.fft = []
+		
+		self._agcMaxima = [0]
+		self._agcIndex = 0
+		self._agcLen = 0
+		self._beatCb = None
+		self._sampleRate = 0
+		self._hasNewData = False
+		
+	def start(self, dev = None):
+		self._device = dev or self.getDefaultOutputDeviceInfo()
+			
+		if self._device == None:
+			print("no device found")
+			return
+			
+		print(self._device["name"])
+			
+		if self._sampleRate != self._device["defaultSampleRate"]:
+			self._sampleRate = self._device["defaultSampleRate"]
+			self.buffersize = int(self._sampleRate * self._dataTime)
+			self.fft = self.right = self.left = np.ndarray((self.buffersize))
+			
+			self._agcLen = int(1 / self._dataTime * self._agcTime)
+			self._agcMaxima = np.ndarray((self._agcLen))
+			self._agcMaxima.fill(2**15 * 0.1)
+			self._agcIndex = 0
+			self._lastBeatTime = 0
+			self.meanAmp = 2**15 * 0.1
+		
+		try:
+			self._stream = self.openStream(self._device)
+		except OSError:
+			self._stream = None
+		
+		if not self._stream:
+			print("stream open failed")
+			return
+		
+		self._stream.start_stream()
+		
+		return self._stream.is_active()
+		
+	def stop(self):
+		if not self._stream:# or not self._stream.is_active():
+			return False
+		self._stream.stop_stream()
+		return True
+		
+	def setBeatCb(self, cb):
+		self._beatCb = cb
+	
+	def getDefaultOutputDeviceInfo(self):
+		#Set default to first in list or ask Windows
+		try:
+			self.p.terminate()
+			self.p.__init__()
+			if self._input:
+				info = self.p.get_default_input_device_info()
+			else:
+				info = self.p.get_default_output_device_info()
+		except IOError:
+			info = None
+		
+		#Handle no devices available
+		if info == None:
+				print ("No device available.")
+				return None
+
+		if (self.p.get_host_api_info_by_index(info["hostApi"])["name"]).find("WASAPI") == -1:
+			for i in range(0, self.p.get_device_count()):
+				x = self.p.get_device_info_by_index(i)
+				is_wasapi = (self.p.get_host_api_info_by_index(x["hostApi"])["name"]).find("WASAPI") != -1
+				if x["name"].find(info["name"]) >= 0 and is_wasapi:
+					info = x
+					break
+
+		#Handle no devices available
+		if info == None:
+			print ("Device doesn't support WASAPI")
+			return None
+			
+		info["channels"] = info["maxInputChannels"] if (info["maxOutputChannels"] < info["maxInputChannels"]) else info["maxOutputChannels"]
+			
+		return info
+		
+	def openStream(self, dev):
+	
+		is_input = dev["maxInputChannels"] > 0
+		is_wasapi = (self.p.get_host_api_info_by_index(dev["hostApi"])["name"]).find("WASAPI") != -1
+		
+		#print("is input: {} is wasapi: {}".format(is_input, is_wasapi))
+
+		if not is_input and not is_wasapi:
+			print ("Selection is output and does not support loopback mode.")
+			return None
+		if is_wasapi:
+			stream = self.p.open(
+				format = pyaudio.paInt16,
+				channels = dev["channels"],
+				rate = int(self._sampleRate),
+				input = True,
+				frames_per_buffer = self.buffersize,
+				input_device_index = dev["index"],
+				stream_callback=self.streamCallback,
+				as_loopback = False if is_input else is_wasapi)
+		else:
+			stream = self.p.open(
+				format = pyaudio.paInt16,
+				channels = dev["channels"],
+				rate = int(self._sampleRate),
+				input = True,
+				frames_per_buffer = self.buffersize,
+				input_device_index = dev["index"],
+				stream_callback=self.streamCallback)
+		return stream
+		
+	def closeStream(self):
+		if not self._stream:
+			return False
+		self._stream.close()
+		return True
+			
+	def streamCallback(self, buf, frame_count, time_info, flag):
+		self._buf = buf
+		arr = np.array(struct.unpack("%dh" % (len(buf)/2), buf))
+		
+		mx = arr.max()
+		self._agcIndex += 1
+		if self._agcIndex >= self._agcLen:
+			self._agcIndex = 0
+		self._agcMaxima[self._agcIndex] = mx
+			
+		self.meanAmp = np.mean(np.absolute(self._agcMaxima))
+		
+		if self.meanAmp > 2**15 * 0.02:
+			amp = 1 / self.meanAmp
+		else:
+			amp = 1 / (2**15 * 0.02)
+		
+		if self._device["channels"] == 2:
+			self.left, self.right  = arr[::2]  * amp, arr[1::2] * amp
+			self.fft = self.fftCalc((self.left+self.right)/2)
+		else:
+			self.left = self.right = arr * amp
+			self.fft = self.fftCalc(self.left)
+		
+		self._hasNewData = True
+		
+		self.agcFFT = np.fft.rfft(self._agcMaxima, self.beatnFFT) / self.beatnFFT
+		
+		if self._beatCb and mx * (time_info["current_time"] - self._lastBeatTime) > m * 0.5:
+			self._lastBeatTime = time_info["current_time"]
+			self._beatCb(self.fft)
+			
+		return (None, pyaudio.paContinue)
+	
+	def hasNewData(self):
+		if not self._hasNewData:
+			return False
+		self._hasNewData = False
+		return True
+	
+	def getSampleRate(self):
+		return int(self._sampleRate)
+	
+	def getAgc(self):
+		return self.meanAmp / 2**15
+		
+	def getVolume(self):
+		if self._agcMaxima.sum() == 0:
+			return 0
+		return self._agcMaxima[self._agcIndex] / self.meanAmp
+	
+	def isActive(self):
+		if not self._stream:
+			return False
+		return self._stream.is_active()
+	
+	def fftSetLimits(self, nFFT, fMin, fMax):
+		self.nFFT = nFFT
+		self.fftMin = int(fMin / self._sampleRate * nFFT)
+		self.fftMax = int(fMax / self._sampleRate * nFFT)
+		print("nFFT: {} \tfftMin: {} \tfftMax: {}".format(self.nFFT, self.fftMin, self.fftMax))
+
+	def agcFftSetLimits(self, fMin, fMax):
+		self.beatnFFT = self._agcLen
+		self.beatFftMin = int(fMin * self._dataTime * self.beatnFFT)
+		self.beatFftMax = int(fMax * self._dataTime * self.beatnFFT)
+		print("beat nFFT: {} \tfftMin: {} \tfftMax: {}".format(self.beatnFFT, self.beatFftMin, self.beatFftMax))
+		
+	def fftCalc(self, data):
+		return abs(np.fft.rfft(data, self.nFFT)[self.fftMin:self.fftMax]) / self.nFFT
+							
+	def fftGroup(self, fft, limits):
+		groups = []
+		for freqs in zip(limits, limits[1:]):
+			a = int(freqs[0] / self._sampleRate * self.nFFT)
+			b = int(freqs[1] / self._sampleRate * self.nFFT)
+			#groups.append(sum(fft[a:b]) / (b-a) if (b-a) > 0 else 0)
+			if b != a:
+				groups.append(max(fft[a:b]))
+			else:
+				groups.append(fft[a])
+		return groups

+ 109 - 0
audio_output.py

@@ -0,0 +1,109 @@
+import pyaudio
+import wave
+import os
+
+defaultframes = 512
+
+class textcolors:
+    if not os.name == 'nt':
+        blue = '\033[94m'
+        green = '\033[92m'
+        warning = '\033[93m'
+        fail = '\033[91m'
+        end = '\033[0m'
+    else:
+        blue = ''
+        green = ''
+        warning = ''
+        fail = ''
+        end = ''
+
+recorded_frames = []
+device_info = {}
+useloopback = False
+recordtime = 5
+
+#Use module
+p = pyaudio.PyAudio()
+
+#Set default to first in list or ask Windows
+try:
+    default_device_index = p.get_default_input_device_info()
+except IOError:
+    default_device_index = -1
+
+#Select Device
+print (textcolors.blue + "Available devices:\n" + textcolors.end)
+for i in range(0, p.get_device_count()):
+    info = p.get_device_info_by_index(i)
+    print (textcolors.green + str(info["index"]) + textcolors.end + ": \t %s \n \t %s \n" % (info["name"], p.get_host_api_info_by_index(info["hostApi"])["name"]))
+
+    if default_device_index == -1:
+        default_device_index = info["index"]
+
+#Handle no devices available
+if default_device_index == -1:
+    print (textcolors.fail + "No device available. Quitting." + textcolors.end)
+    exit()
+
+
+#Get input or default
+device_id = int(input("Choose device [" + textcolors.blue + str(default_device_index) + textcolors.end + "]: ") or default_device_index)
+print ("")
+
+#Get device info
+try:
+    device_info = p.get_device_info_by_index(device_id)
+except IOError:
+    device_info = p.get_device_info_by_index(default_device_index)
+    print (textcolors.warning + "Selection not available, using default." + textcolors.end)
+
+#Choose between loopback or standard mode
+is_input = device_info["maxInputChannels"] > 0
+is_wasapi = (p.get_host_api_info_by_index(device_info["hostApi"])["name"]).find("WASAPI") != -1
+if is_input:
+    print (textcolors.blue + "Selection is input using standard mode.\n" + textcolors.end)
+else:
+    if is_wasapi:
+        useloopback = True;
+        print (textcolors.green + "Selection is output. Using loopback mode.\n" + textcolors.end)
+    else:
+        print (textcolors.fail + "Selection is input and does not support loopback mode. Quitting.\n" + textcolors.end)
+        exit()
+
+recordtime = int(input("Record time in seconds [" + textcolors.blue + str(recordtime) + textcolors.end + "]: ") or recordtime)
+
+#Open stream
+channelcount = device_info["maxInputChannels"] if (device_info["maxOutputChannels"] < device_info["maxInputChannels"]) else device_info["maxOutputChannels"]
+stream = p.open(format = pyaudio.paInt16,
+                channels = channelcount,
+                rate = int(device_info["defaultSampleRate"]),
+                input = True,
+                frames_per_buffer = defaultframes,
+                input_device_index = device_info["index"],
+                as_loopback = useloopback)
+
+#Start Recording
+print (textcolors.blue + "Starting..." + textcolors.end)
+
+for i in range(0, int(int(device_info["defaultSampleRate"]) / defaultframes * recordtime)):
+    recorded_frames.append(stream.read(defaultframes))
+    print (".")
+
+print (textcolors.blue + "End." + textcolors.end)
+#Stop Recording
+
+stream.stop_stream()
+stream.close()
+
+#Close module
+p.terminate()
+
+filename = input("Save as [" + textcolors.blue + "out.wav" + textcolors.end + "]: ") or "out.wav"
+
+waveFile = wave.open(filename, 'wb')
+waveFile.setnchannels(channelcount)
+waveFile.setsampwidth(p.get_sample_size(pyaudio.paInt16))
+waveFile.setframerate(int(device_info["defaultSampleRate"]))
+waveFile.writeframes(b''.join(recorded_frames))
+waveFile.close()

+ 31 - 0
beatDetection.py

@@ -0,0 +1,31 @@
+import numpy
+
+class SimpleBeatDetection:
+		"""
+		Simple beat detection algorithm from
+		http://archive.gamedev.net/archive/reference/programming/features/beatdetection/index.html
+		"""
+		def __init__(self, history = 43):
+				self.local_energy = numpy.zeros(history) # a simple ring buffer
+				self.local_energy_index = 0 # the index of the oldest element
+
+		def detect_beat(self, signal):
+
+				samples = signal.astype(numpy.int) # make room for squares
+				# optimized sum of squares, i.e faster version of (samples**2).sum()
+				instant_energy = abs(numpy.dot(samples, samples) / float(0xffffffff)) # normalize
+
+				local_energy_average = self.local_energy.mean()
+				local_energy_variance = self.local_energy.var()
+														#-0.0025714
+				beat_sensibility = (-20 * local_energy_variance) +2#+ 1.15142857
+				beat = instant_energy > beat_sensibility * local_energy_average
+				
+				#print(" 1" if beat else "0 ", instant_energy/ beat_sensibility / local_energy_average, local_energy_variance)
+
+				self.local_energy[self.local_energy_index] = instant_energy
+				self.local_energy_index -= 1
+				if self.local_energy_index < 0:
+						self.local_energy_index = len(self.local_energy) - 1
+
+				return beat

+ 44 - 0
displayHandler.py

@@ -0,0 +1,44 @@
+import numpy as np
+import matplotlib.pyplot as plt
+from matplotlib import animation
+
+class Plot:
+	def __init__(self, count):
+		self.fig, self.plots = plt.subplots(nrows=count, ncols=1)
+		self.fig.tight_layout()
+		self.fig.canvas.set_window_title('FFT Cube')
+		
+		self.count = count
+		self.entities = []
+		
+	def addLabel(self, ax, title="", xlabel="", ylabel=""):
+		self.plots[ax].set_title(title)
+		self.plots[ax].set_xlabel(xlabel)
+		self.plots[ax].set_ylabel(ylabel)
+		
+	def addLine(self, ax, x, yMin, yMax, color = 'r-', xscale = 'linear'):
+		self.plots[ax].set_xlim(min(x), max(x))
+		self.plots[ax].set_ylim(yMin, yMax)
+		self.plots[ax].set_xscale(xscale)
+		line, = self.plots[ax].plot(x, [0]*len(x), color)
+		self.entities.append(line)
+		return line
+	
+	def addBars(self, ax, labels, yMin, yMax, width, offset, color = 'r'):
+		self.plots[ax].set_ylim(yMin, yMax)
+		self.plots[ax].set_xticklabels(labels)
+		x = range(len(labels))
+		y = [0] * (len(labels))
+		bars = self.plots[ax].bar([i+offset for i in x], y, width, color=color)
+		for bar in bars:
+			self.entities.append(bar)
+		return bars
+
+	def update(self, frame = None):
+		self._cb()
+		return self.entities
+		
+	def show(self, cb, framerate = 60):
+		self._cb = cb
+		self.animation = animation.FuncAnimation(self.fig, self.update, interval=1000/framerate, blit=True)
+		plt.show()

+ 183 - 0
gui.py

@@ -0,0 +1,183 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+import serial
+from serial import SerialException
+import _thread
+import sys
+import time
+from PyQt5.QtWidgets import (QApplication, QMainWindow)
+
+from ui import Ui_MainWindow
+	
+class AppWindow(QMainWindow):
+	selectedLED = 14
+	ledBuf = [0] * 64
+
+	ser = serial.Serial()
+	animations = []
+	
+	def __init__(self):
+		super().__init__()
+		self.ui = Ui_MainWindow()
+		self.ui.setupUi(self)
+		
+		self.ser.baudrate = 115200
+		_thread.start_new_thread( self.read, () )
+		self.connect()
+		
+		for i in range(1,65):
+			id = "radioButton_" + str(i)
+			getattr(self.ui, id).toggled.connect(self.selectLED)
+		
+		self.ui.horizontalSlider.valueChanged.connect(self.changeLED)
+		self.ui.comboBox.currentIndexChanged.connect(self.selectAnim)
+		self.ui.comboBox.addItems(str(i) for i in range(64))
+		self.ui.spinBox.valueChanged.connect(self.setFrame)
+		self.ui.spinBox_2.valueChanged.connect(self.setStart)
+		self.ui.spinBox_3.valueChanged.connect(self.setLength)
+		
+		self.ui.pushButton.clicked.connect(self.connect)
+		self.ui.pushButton_2.clicked.connect(self.startAnim)
+		self.ui.pushButton_3.clicked.connect(self.pauseAnim)
+		self.ui.pushButton_4.clicked.connect(self.stopAnim)
+		self.ui.pushButton_5.clicked.connect(self.saveFrame)
+		self.ui.pushButton_6.clicked.connect(self.clearFrame)
+		self.ui.pushButton_7.clicked.connect(self.getFrame)
+		self.ui.pushButton_8.clicked.connect(self.saveAnim)
+		
+		self.show()
+		
+	def setFrame(self):
+		if self.ser.is_open:
+			self.ser.write(b'~h')
+			self.writeLng(self.ui.spinBox.value())
+	
+	def setStart(self):
+		id = self.ui.comboBox.currentIndex()
+		self.animations[id][1] = self.sender().value()
+	
+	def setLength(self):
+		id = self.ui.comboBox.currentIndex()
+		self.animations[id][2] = self.sender().value()
+
+	def startAnim(self):
+		if self.ser.is_open:
+			self.ser.write(b'~s')
+			self.write(self.ui.comboBox.currentIndex())
+
+	def pauseAnim(self):
+		if self.ser.is_open:
+			self.ser.write(b'~t')
+	
+	def stopAnim(self):
+		if self.ser.is_open:
+			self.ser.write(b'~u~c ')	
+			
+	oldFrame = 0;
+	def saveFrame(self):
+		if self.ser.is_open:
+			newFrame = self.ui.spinBox.value()
+			if int(self.oldFrame/16) != int(newFrame/16):
+				self.ser.write(b'~x')# load page
+				self.writeInt(newFrame/16)
+			self.ser.write(b'~y')# write to buffer
+			self.write(newFrame%16)
+			if int(self.oldFrame/16) != int(newFrame/16):
+				self.ser.write(b'~z')# write page
+				self.writeInt(newFrame/16)
+				self.status("saved")
+			self.oldFrame = newFrame
+			self.ui.spinBox.setValue(newFrame+1)
+	
+	def clearFrame(self):
+		for i in range(64):
+			btn = getattr(self.ui, "radioButton_" + str(i+1))
+			btn.setStyleSheet("background-color:rgba(255,0,0,0)")
+			self.ledBuf[i] = 0
+		self.ui.horizontalSlider.setValue(0)
+	
+	def getFrame(self):
+		if self.ser.is_open:
+			self.ser.write(b'~g')
+			self.ui.spinBox.setValue(int(self.ser.readline()))
+	
+	def saveAnim(self):
+		id = self.ui.comboBox.currentIndex()
+		if self.ser.is_open:
+			self.ser.write(b'~b')
+			self.write(id)
+			self.writeLng(int(self.animations[id][1]))
+			self.writeLng(int(self.animations[id][2]))
+	
+	def selectAnim(self):
+		id = self.ui.comboBox.currentIndex()
+		if len(self.animations) > id:
+			self.ui.spinBox_2.setValue(int(self.animations[id][1]))
+			self.ui.spinBox_3.setValue(int(self.animations[id][2]))
+	
+	def loadAnim(self):
+		self.selectAnim();
+		print("loaded animations")
+	
+	def changeLED(self):
+		val = self.sender().value()
+		self.ledBuf[self.selectedLED] = val
+		if self.ser.is_open:
+			self.ser.write(b'~`')
+			self.write(self.selectedLED+32)
+			self.write(val+32)
+		self.ui.label_7.setText("Value: " + str(val))
+		for i in range(1,65):
+			btn = getattr(self.ui, "radioButton_" + str(i))
+			if btn.isChecked():
+				btn.setStyleSheet("background-color:rgba(255,0,0," + str(val*17) + ")")
+				break
+
+	def selectLED(self):
+		id = self.sender().text()
+		if id != "":
+			self.selectedLED = int(id)
+			self.ui.horizontalSlider.setValue(self.ledBuf[self.selectedLED])
+		
+	def connect(self):
+		port = self.ui.lineEdit.text()
+		
+		if self.ser.port == port and self.ser.is_open:
+			return
+		
+		try:
+			self.ser.port = port
+			self.ser.open()
+			self.animations = []
+			self.ser.write(b'~B~c ')
+			self.status("connected")
+		except serial.SerialException:
+			self.status(self.ser.port + " not available")
+			
+	def status(self,txt):
+		self.ui.label_6.setText(txt)
+
+	def read(self):
+		while 1:
+			if self.ser.is_open:
+				while self.ser.inWaiting()>0:
+					line = self.ser.readline().decode("utf-8")
+					print(line)
+					if len(self.animations) < 64:
+						self.animations.append(line.split(","))
+						if len(self.animations) == 64:
+							self.loadAnim()
+			time.sleep(.1)
+
+	def write(self,val):
+			self.ser.write((int(val)&0xFF).to_bytes(1, byteorder='big', signed=False))
+	def writeInt(self,val):
+			self.ser.write((int(val)&0xFFFF).to_bytes(2, byteorder='big', signed=False))
+	def writeLng(self,val):
+			self.ser.write((int(val)&0xFFFFFFFF).to_bytes(4, byteorder='big', signed=False))
+		
+app = QApplication(sys.argv)
+w = AppWindow()
+w.show()
+sys.exit(app.exec_())

BIN
lc444_audio.png


BIN
lc444_control.png


+ 190 - 0
main.py

@@ -0,0 +1,190 @@
+import audioHandler
+import serialHandler
+import mqttHandler
+
+import time
+import multiprocessing
+import numpy as np
+import sys, getopt
+
+
+framerate = 60 #Hz
+dataTime = 1/30
+graphs = True
+outDev = True
+brightness = 15
+filename = None
+
+try:
+	opts, args = getopt.getopt(sys.argv[1:],"hsif:t:b:w:",["shadow=","input=","framerate=","time=","brightness=","write="])
+except getopt.GetoptError:
+	print('main.py -s (shadow) -i (use input) -f --framerate <f=60>\n        -t --time <t=0.033> -b --brightness <b=15> -w --write <filename.wav>')
+	sys.exit(2)
+for opt, arg in opts:
+	if opt == '-h':
+		 print('main.py -s (shadow) -i (use input) -f --framerate <f=60>\n        -t --time <t=0.033> -b --brightness <b=15> -w --write <filename.wav>')
+		 sys.exit()
+	elif opt in ("-s", "--shadow"):
+		graphs = False
+	elif opt in ("-i", "--input"):
+		outDev = False
+	elif opt in ("-f", "--framerate"):
+		 framerate = float(arg)
+	elif opt in ("-t", "--time"):
+		 dataTime = float(arg)
+	elif opt in ("-b", "--brightness"):
+		brightness = int(arg)
+		if brightness > 15:
+			brightness = 15
+		elif brightness < 0:
+				brightness = 0
+	elif opt in ("-w", "--write"):
+		filename = arg
+		import wave
+		import pyaudio
+		
+audio = audioHandler.Listener(dataTime, 30, not outDev)
+cube = serialHandler.SerialConnection()
+vis = serialHandler.Visualization()
+lamp = mqttHandler.RgbLamp("<mqtt server ip>")
+
+#audio.setBeatCb(lamp.onBeat)
+intervalTime = time.time()
+
+if graphs:
+	import displayHandler
+	window = displayHandler.Plot(count=5)
+	window.addLabel(0, "x = f(t)", "t in s")
+	window.addLabel(1, "x = f(f)", "f in Hz")
+	window.addLabel(3, "Beat detection", "t in s")
+	window.addLabel(4, "", "bpm")
+
+
+pitches = [(2**(1/12))**n * 220 for n in range(-12*2, 12*5)]
+octaves = [(2**(1/12))**n * 220 for n in range(-12*2, 12*5, 12)]
+octCount = len(octaves)
+
+audio.start()
+nFFT = audio.buffersize
+audio.fftSetLimits(nFFT, min(pitches), max(pitches))
+audio.agcFftSetLimits(60/60, 300/60)
+cube.connect()
+
+cube.setBrightness(brightness)
+
+if filename:
+	wf = wave.open(filename, 'wb')
+	wf.setnchannels(audio._device["channels"])
+	wf.setsampwidth(audio.p.get_sample_size(pyaudio.paInt16))
+	wf.setframerate(audio.getSampleRate())
+
+if graphs:
+
+	x = [x / audio.getSampleRate() for x in range(len(audio.left ))]
+	lineAmpL = window.addLine(0, x, -1.5, 1.5, 'r-')
+	lineAmpR = window.addLine(0, x, -1.5, 1.5, 'g-')
+
+	x = [x * audio.getSampleRate() / nFFT for x in range(audio.fftMin, audio.fftMax)]
+	lineFft = window.addLine(1, x, 0, 1, 'r-', 'log')
+
+	x = ["{:.0f}\n{:.0f}".format(a, b) for a,b in zip(octaves, octaves[1:])]
+	#barsFft = window.addBars(2, x, 0, 1, 0.5, -0.25, 'r')
+
+	x = ['as','h','c','cis','d','es', 'e', 'f', 'fis', 'g', 'gis', 'a']
+	colors = ['r', 'g', 'b', 'y']
+	barsPitch = [window.addBars(2, x, 0, 1, 0.25, -0.5+1/4*(i+1), colors[i]) for i in range(4)]
+	
+	lineAgc = window.addLine(3, [x * audio._dataTime for x in range(audio._agcLen)], 0, 2)
+	x = [x / audio._dataTime / audio.beatnFFT * 60 for x in range(audio.beatFftMin, audio.beatFftMax)]
+	lineAgcFft = window.addLine(4, x, 0, 1, 'r-')
+
+#delay to gather sound data
+time.sleep(0.1)
+
+sums = np.zeros((4, 12))
+mean = (0,0)
+avg = [0]*len(octaves)
+
+def loop():
+	global intervalTime, avg, sums, mean
+	
+	if audio.hasNewData():
+	
+		left, right, fft = np.copy(audio.left), np.copy(audio.right), np.copy(audio.fft)
+		
+		avg = audio.fftGroup(fft, octaves)
+		mean = np.mean(np.absolute(left)),np.mean(np.absolute(right))
+		
+		if filename:
+			wf.writeframes(audio._buf)
+		
+		if graphs:
+			lineAmpL.set_ydata(left)
+			lineAmpR.set_ydata(right)
+			lineFft.set_ydata(fft[audio.fftMin-1:audio.fftMax])
+			#for b in range(octCount - 1):
+				#barsFft[b].set_height(avg[b])
+				
+			lineAgc.set_ydata(audio._agcMaxima / audio.meanAmp)
+			lineAgcFft.set_ydata(np.abs(audio.agcFFT[audio.beatFftMin:audio.beatFftMax]) / audio.meanAmp * 10)
+			
+		sums = np.zeros((4, 12))
+		
+		for i, p in enumerate(audio.fftGroup(fft, pitches)):
+			sums[int(i/12*4/octCount)][(i+1) % 12] += p
+			
+		#order = np.argsort(np.abs(audio.agcFFT[audio.beatFftMin:audio.beatFftMax]))
+		#print(order)
+	
+	vis.matrix *= 0.7
+	
+	
+	for k in range(4):
+		#mn = min(sums[k])
+		#diff = max(sums[k]) - mn
+		#sums[k] = (sums[k] - mn)
+	
+		if graphs:
+			for i in range(12):
+				barsPitch[k][i].set_height(sums[k][i])
+		
+		vis.matrix += vis.noteCircle(sums[k], 3-k)
+		vis.matrix += vis.ampPyramid((avg[0]*2,avg[1]*2,*mean))
+		np.clip(vis.matrix, 0, 1, out=vis.matrix)
+	cube.send(vis.matrix)
+		
+	if time.time() - intervalTime > 60:
+		if not cube.isConnected():
+			print("lost serial connection, retrying to connect...")
+			cube.connect()
+			
+		audio.stop()
+		audio.start()
+		intervalTime = time.time()
+		
+		
+try:
+	if graphs:
+		window.show(loop, framerate)
+	
+	else:
+		i = 0
+		while True:
+			startTime = time.time()
+			loop()
+			runTime = time.time() - startTime
+			if runTime < 1/framerate:
+				time.sleep(1/framerate-runTime)
+			i+=1
+			if i >= framerate/4:
+				print("agc: {:6.1%} \tvolume: {:7.1%}".format(audio.getAgc(), audio.getVolume()))
+				i = 1
+		
+except KeyboardInterrupt:
+	audio.closeStream()
+	if filename:
+		wf.close()
+except:
+	print("Unexpected error:", sys.exc_info()[0])
+	input("Press enter to continue...")
+	raise

+ 31 - 0
mqttHandler.py

@@ -0,0 +1,31 @@
+import paho.mqtt.client as mqtt
+import random
+
+class RgbLamp:
+	def __init__(self, host, port = 1883):
+		self.mqttc = mqtt.Client()
+		self.mqttc.on_message = self.onMessage
+		self.mqttc.on_connect = self.onConnect
+		
+		self.host = host
+		self.port = port
+		
+		self.mqttc.connect_async(self.host, self.port, 60)
+		self.mqttc.loop_start()
+		
+		self._nBeat = 0
+		
+		
+	def onMessage(self, mqttc, obj, msg):
+		print(msg)
+		
+	def onConnect(self, client, userdata, flags, rc):
+		print("Connected with result code "+str(rc))
+		self.mqttc.subscribe("Timer/#", 2)
+		self.mqttc.subscribe("Pc/#", 2)
+		
+	def onBeat(self, fft):
+		json = "{\"spot\":[{\"color\":" + str(0) + ",\"radius\":" + str(int(fft[1])*3+2) + ",\"pos\":" + str(10 + self._nBeat%4 * 10) + ",\"keep\":0}],\"speed\":40}"
+		self._nBeat += 1
+		#print("  ------------------ " + json)
+		self.mqttc.publish("RgbLamp/spot", json)

+ 2 - 0
run.bat

@@ -0,0 +1,2 @@
+pyuic5 ui.ui -o ui.py
+python gui.py || pause

+ 101 - 0
serialHandler.py

@@ -0,0 +1,101 @@
+import serial
+from serial import SerialException
+
+import numpy as np
+
+class SerialConnection:
+	def __init__(self):
+		self._ser = None
+		self._brightness = 15
+		self.port = None
+		
+	def connect(self, port = None):
+		if port == None:
+			port = self.port
+			
+		if port == None:
+			for port in ["COM{}".format(p) for p in range(3,20)]:
+				try:
+					self._ser = serial.Serial(port, 115200)
+					print("connected to " + port)
+					self.port = port
+					break
+				except serial.SerialException:
+					pass
+		else:
+			try:
+				self._ser = serial.Serial(port, 115200)
+				print("connected to " + port)
+				self.port = port
+			except serial.SerialException:
+				pass
+		if self._ser:
+			self._ser.write(b'~u~t~c ')
+		else:
+			print("connection to port {} failed".format(port))
+		
+	def send(self, matrix):
+		if not self._ser:
+			return
+		buf = [32] * (4**3)
+		
+		for z in range(4):
+			for y in range(4):
+				for x in range(4):
+					if matrix[x][y][z] >= 1:
+						b = self._brightness
+					elif matrix[x][y][z] >= 0:
+						b = min(int(matrix[x][y][z] * 15), self._brightness)
+					else:
+						b = 0
+					
+					buf[z*16+y*4+x] = b + 32
+		
+		try:
+			self._ser.write(b'~a')
+			self._ser.write(bytearray(buf))
+		except serial.SerialException:
+			self._ser = None
+		
+	def setBrightness(self, brightness):
+		self._brightness = brightness
+		
+	def isConnected(self):
+		return self._ser != None
+		
+class Visualization:
+	def __init__(self):
+		self.matrix = np.zeros((4,4,4))
+		
+	def clear(self):
+		self.matrix = np.zeros((4,4,4))
+		
+	def noteCircle(self, notes, z=0):
+		matrix = np.zeros((4,4,4))
+		map = [
+			[ 0, 1, 2, 3],
+			[11,-1,-1, 4],
+			[10,-1,-1, 5],
+			[ 9, 8, 7, 6],
+		]
+		for x, line in enumerate(map[::-1]):
+			for y, i in enumerate(line):
+				if i < 0:
+					continue
+				matrix[x][y][z] = notes[i]
+		return matrix
+	
+	def ampPyramid(self, vals):
+		matrix = np.zeros((4,4,4))
+		coords = [
+			(1,1),
+			(2,2),
+			(1,2),
+			(2,1)
+		]
+		for i, (x, y) in enumerate(coords):
+			for z in range(4):
+				if vals[i] > z * 0.25:
+					matrix[x][y][z] = (vals[i] * 4 - z) * 0.5
+		return matrix
+		

+ 65 - 0
storage.py

@@ -0,0 +1,65 @@
+import serial
+from serial import SerialException
+import _thread
+import struct
+import numpy as np
+import math
+import time
+from matplotlib import pyplot as plt
+
+ser = None
+portName="COM6"
+
+while not ser:
+	try:
+		ser = serial.Serial(portName, 115200)
+	except serial.SerialException:
+		print(portName, " not available")
+		portName="COM" + input("COM")
+
+print("Connected to ", ser.name)
+
+def read():
+    while 1:
+        if ser.inWaiting()>0:
+            print(ser.read(ser.inWaiting()).decode("utf-8"))
+        time.sleep(.1)
+_thread.start_new_thread( read, () )
+
+def write(val):
+    ser.write((int(val)&0xFF).to_bytes(1, byteorder='big', signed=False))
+def writeInt(val):
+    ser.write((int(val)&0xFFFF).to_bytes(2, byteorder='big', signed=False))
+def writeLng(val):
+    ser.write((int(val)&0xFFFFFFFF).to_bytes(4, byteorder='big', signed=False))
+
+ser.write(b'~t~c"')
+
+for i in range(64):
+	ser.write(b'~b')
+	write(i)
+	writeLng(i*65536/64)
+	writeLng(65536/64)
+	time.sleep(0.2)
+
+"""
+time.sleep(.5)
+    
+for i in range(65535):
+    for k in range(4):
+        ser.write(b'~a')
+        for n in range(4):
+            for m in range(16):
+                write(i+32+n*8-m*3)
+            time.sleep(0.015 / 4)
+        ser.write(b'~y')
+        write(k)
+        time.sleep(0.02)
+    ser.write(b'~z')
+    writeInt(i)
+    time.sleep(0.02)
+ser.write(b'~s')
+
+# close stream
+"""
+

+ 804 - 0
ui.py

@@ -0,0 +1,804 @@
+# -*- coding: utf-8 -*-
+
+# Form implementation generated from reading ui file 'ui.ui'
+#
+# Created by: PyQt5 UI code generator 5.10.1
+#
+# WARNING! All changes made in this file will be lost!
+
+from PyQt5 import QtCore, QtGui, QtWidgets
+
+class Ui_MainWindow(object):
+    def setupUi(self, MainWindow):
+        MainWindow.setObjectName("MainWindow")
+        MainWindow.resize(483, 688)
+        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
+        sizePolicy.setHorizontalStretch(0)
+        sizePolicy.setVerticalStretch(0)
+        sizePolicy.setHeightForWidth(MainWindow.sizePolicy().hasHeightForWidth())
+        MainWindow.setSizePolicy(sizePolicy)
+        self.centralwidget = QtWidgets.QWidget(MainWindow)
+        self.centralwidget.setObjectName("centralwidget")
+        self.gridLayout_3 = QtWidgets.QGridLayout(self.centralwidget)
+        self.gridLayout_3.setObjectName("gridLayout_3")
+        self.gridLayout_2 = QtWidgets.QGridLayout()
+        self.gridLayout_2.setSpacing(20)
+        self.gridLayout_2.setObjectName("gridLayout_2")
+        self.spinBox_2 = QtWidgets.QSpinBox(self.centralwidget)
+        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
+        sizePolicy.setHorizontalStretch(0)
+        sizePolicy.setVerticalStretch(0)
+        sizePolicy.setHeightForWidth(self.spinBox_2.sizePolicy().hasHeightForWidth())
+        self.spinBox_2.setSizePolicy(sizePolicy)
+        self.spinBox_2.setMaximumSize(QtCore.QSize(16777215, 75))
+        self.spinBox_2.setAlignment(QtCore.Qt.AlignCenter)
+        self.spinBox_2.setMaximum(65535)
+        self.spinBox_2.setObjectName("spinBox_2")
+        self.gridLayout_2.addWidget(self.spinBox_2, 2, 1, 1, 1)
+        self.pushButton_4 = QtWidgets.QPushButton(self.centralwidget)
+        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
+        sizePolicy.setHorizontalStretch(0)
+        sizePolicy.setVerticalStretch(0)
+        sizePolicy.setHeightForWidth(self.pushButton_4.sizePolicy().hasHeightForWidth())
+        self.pushButton_4.setSizePolicy(sizePolicy)
+        self.pushButton_4.setMaximumSize(QtCore.QSize(204, 16777215))
+        self.pushButton_4.setObjectName("pushButton_4")
+        self.gridLayout_2.addWidget(self.pushButton_4, 0, 3, 1, 1)
+        self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget)
+        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
+        sizePolicy.setHorizontalStretch(0)
+        sizePolicy.setVerticalStretch(0)
+        sizePolicy.setHeightForWidth(self.pushButton_2.sizePolicy().hasHeightForWidth())
+        self.pushButton_2.setSizePolicy(sizePolicy)
+        self.pushButton_2.setObjectName("pushButton_2")
+        self.gridLayout_2.addWidget(self.pushButton_2, 0, 1, 1, 1)
+        self.pushButton_7 = QtWidgets.QPushButton(self.centralwidget)
+        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
+        sizePolicy.setHorizontalStretch(0)
+        sizePolicy.setVerticalStretch(0)
+        sizePolicy.setHeightForWidth(self.pushButton_7.sizePolicy().hasHeightForWidth())
+        self.pushButton_7.setSizePolicy(sizePolicy)
+        self.pushButton_7.setObjectName("pushButton_7")
+        self.gridLayout_2.addWidget(self.pushButton_7, 3, 0, 1, 1)
+        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
+        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
+        sizePolicy.setHorizontalStretch(0)
+        sizePolicy.setVerticalStretch(0)
+        sizePolicy.setHeightForWidth(self.pushButton.sizePolicy().hasHeightForWidth())
+        self.pushButton.setSizePolicy(sizePolicy)
+        self.pushButton.setObjectName("pushButton")
+        self.gridLayout_2.addWidget(self.pushButton, 3, 3, 1, 1)
+        self.pushButton_3 = QtWidgets.QPushButton(self.centralwidget)
+        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
+        sizePolicy.setHorizontalStretch(0)
+        sizePolicy.setVerticalStretch(0)
+        sizePolicy.setHeightForWidth(self.pushButton_3.sizePolicy().hasHeightForWidth())
+        self.pushButton_3.setSizePolicy(sizePolicy)
+        self.pushButton_3.setMaximumSize(QtCore.QSize(203, 16777215))
+        self.pushButton_3.setObjectName("pushButton_3")
+        self.gridLayout_2.addWidget(self.pushButton_3, 0, 2, 1, 1)
+        self.label_7 = QtWidgets.QLabel(self.centralwidget)
+        self.label_7.setLayoutDirection(QtCore.Qt.LeftToRight)
+        self.label_7.setAlignment(QtCore.Qt.AlignCenter)
+        self.label_7.setObjectName("label_7")
+        self.gridLayout_2.addWidget(self.label_7, 1, 0, 1, 1)
+        self.pushButton_6 = QtWidgets.QPushButton(self.centralwidget)
+        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
+        sizePolicy.setHorizontalStretch(0)
+        sizePolicy.setVerticalStretch(0)
+        sizePolicy.setHeightForWidth(self.pushButton_6.sizePolicy().hasHeightForWidth())
+        self.pushButton_6.setSizePolicy(sizePolicy)
+        self.pushButton_6.setObjectName("pushButton_6")
+        self.gridLayout_2.addWidget(self.pushButton_6, 1, 3, 1, 1)
+        self.spinBox = QtWidgets.QSpinBox(self.centralwidget)
+        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
+        sizePolicy.setHorizontalStretch(0)
+        sizePolicy.setVerticalStretch(0)
+        sizePolicy.setHeightForWidth(self.spinBox.sizePolicy().hasHeightForWidth())
+        self.spinBox.setSizePolicy(sizePolicy)
+        self.spinBox.setMaximumSize(QtCore.QSize(16777215, 75))
+        self.spinBox.setAlignment(QtCore.Qt.AlignCenter)
+        self.spinBox.setMaximum(65535)
+        self.spinBox.setObjectName("spinBox")
+        self.gridLayout_2.addWidget(self.spinBox, 3, 1, 1, 1)
+        self.pushButton_5 = QtWidgets.QPushButton(self.centralwidget)
+        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
+        sizePolicy.setHorizontalStretch(0)
+        sizePolicy.setVerticalStretch(0)
+        sizePolicy.setHeightForWidth(self.pushButton_5.sizePolicy().hasHeightForWidth())
+        self.pushButton_5.setSizePolicy(sizePolicy)
+        self.pushButton_5.setMaximumSize(QtCore.QSize(204, 16777215))
+        self.pushButton_5.setObjectName("pushButton_5")
+        self.gridLayout_2.addWidget(self.pushButton_5, 0, 0, 1, 1)
+        self.horizontalSlider = QtWidgets.QSlider(self.centralwidget)
+        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
+        sizePolicy.setHorizontalStretch(0)
+        sizePolicy.setVerticalStretch(0)
+        sizePolicy.setHeightForWidth(self.horizontalSlider.sizePolicy().hasHeightForWidth())
+        self.horizontalSlider.setSizePolicy(sizePolicy)
+        self.horizontalSlider.setMaximumSize(QtCore.QSize(16777215, 42))
+        self.horizontalSlider.setMaximum(15)
+        self.horizontalSlider.setPageStep(5)
+        self.horizontalSlider.setOrientation(QtCore.Qt.Horizontal)
+        self.horizontalSlider.setObjectName("horizontalSlider")
+        self.gridLayout_2.addWidget(self.horizontalSlider, 1, 1, 1, 2)
+        self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
+        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
+        sizePolicy.setHorizontalStretch(0)
+        sizePolicy.setVerticalStretch(0)
+        sizePolicy.setHeightForWidth(self.lineEdit.sizePolicy().hasHeightForWidth())
+        self.lineEdit.setSizePolicy(sizePolicy)
+        self.lineEdit.setMaximumSize(QtCore.QSize(16777215, 68))
+        self.lineEdit.setAlignment(QtCore.Qt.AlignCenter)
+        self.lineEdit.setObjectName("lineEdit")
+        self.gridLayout_2.addWidget(self.lineEdit, 3, 2, 1, 1)
+        self.pushButton_8 = QtWidgets.QPushButton(self.centralwidget)
+        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
+        sizePolicy.setHorizontalStretch(0)
+        sizePolicy.setVerticalStretch(0)
+        sizePolicy.setHeightForWidth(self.pushButton_8.sizePolicy().hasHeightForWidth())
+        self.pushButton_8.setSizePolicy(sizePolicy)
+        self.pushButton_8.setObjectName("pushButton_8")
+        self.gridLayout_2.addWidget(self.pushButton_8, 2, 3, 1, 1)
+        self.comboBox = QtWidgets.QComboBox(self.centralwidget)
+        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
+        sizePolicy.setHorizontalStretch(0)
+        sizePolicy.setVerticalStretch(0)
+        sizePolicy.setHeightForWidth(self.comboBox.sizePolicy().hasHeightForWidth())
+        self.comboBox.setSizePolicy(sizePolicy)
+        self.comboBox.setMaximumSize(QtCore.QSize(16777215, 75))
+        self.comboBox.setCurrentText("")
+        self.comboBox.setMaxCount(64)
+        self.comboBox.setObjectName("comboBox")
+        self.gridLayout_2.addWidget(self.comboBox, 2, 0, 1, 1)
+        self.spinBox_3 = QtWidgets.QSpinBox(self.centralwidget)
+        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
+        sizePolicy.setHorizontalStretch(0)
+        sizePolicy.setVerticalStretch(0)
+        sizePolicy.setHeightForWidth(self.spinBox_3.sizePolicy().hasHeightForWidth())
+        self.spinBox_3.setSizePolicy(sizePolicy)
+        self.spinBox_3.setMaximumSize(QtCore.QSize(16777215, 75))
+        self.spinBox_3.setAlignment(QtCore.Qt.AlignCenter)
+        self.spinBox_3.setMaximum(65535)
+        self.spinBox_3.setObjectName("spinBox_3")
+        self.gridLayout_2.addWidget(self.spinBox_3, 2, 2, 1, 1)
+        self.gridLayout_3.addLayout(self.gridLayout_2, 1, 0, 1, 1)
+        self.groupBox = QtWidgets.QGroupBox(self.centralwidget)
+        self.groupBox.setObjectName("groupBox")
+        self.gridLayout_4 = QtWidgets.QGridLayout(self.groupBox)
+        self.gridLayout_4.setObjectName("gridLayout_4")
+        self.widget = QtWidgets.QWidget(self.groupBox)
+        self.widget.setMinimumSize(QtCore.QSize(391, 351))
+        self.widget.setMaximumSize(QtCore.QSize(391, 351))
+        self.widget.setObjectName("widget")
+        self.radioButton_9 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_9.setEnabled(True)
+        self.radioButton_9.setGeometry(QtCore.QRect(210, 230, 16, 20))
+        self.radioButton_9.setAutoFillBackground(False)
+        self.radioButton_9.setChecked(False)
+        self.radioButton_9.setObjectName("radioButton_9")
+        self.line = QtWidgets.QFrame(self.widget)
+        self.line.setGeometry(QtCore.QRect(20, 334, 291, 16))
+        self.line.setFrameShape(QtWidgets.QFrame.HLine)
+        self.line.setFrameShadow(QtWidgets.QFrame.Sunken)
+        self.line.setObjectName("line")
+        self.radioButton_28 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_28.setEnabled(True)
+        self.radioButton_28.setGeometry(QtCore.QRect(30, 220, 16, 20))
+        self.radioButton_28.setAutoFillBackground(False)
+        self.radioButton_28.setChecked(False)
+        self.radioButton_28.setObjectName("radioButton_28")
+        self.radioButton_34 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_34.setEnabled(True)
+        self.radioButton_34.setGeometry(QtCore.QRect(250, 110, 16, 20))
+        self.radioButton_34.setAutoFillBackground(False)
+        self.radioButton_34.setChecked(False)
+        self.radioButton_34.setObjectName("radioButton_34")
+        self.radioButton_2 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_2.setEnabled(True)
+        self.radioButton_2.setGeometry(QtCore.QRect(110, 30, 16, 20))
+        self.radioButton_2.setAutoFillBackground(False)
+        self.radioButton_2.setChecked(False)
+        self.radioButton_2.setObjectName("radioButton_2")
+        self.radioButton_52 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_52.setEnabled(True)
+        self.radioButton_52.setGeometry(QtCore.QRect(70, 100, 16, 20))
+        self.radioButton_52.setAutoFillBackground(False)
+        self.radioButton_52.setChecked(False)
+        self.radioButton_52.setObjectName("radioButton_52")
+        self.radioButton_57 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_57.setEnabled(True)
+        self.radioButton_57.setGeometry(QtCore.QRect(170, 0, 16, 20))
+        self.radioButton_57.setAutoFillBackground(False)
+        self.radioButton_57.setChecked(False)
+        self.radioButton_57.setObjectName("radioButton_57")
+        self.line_5 = QtWidgets.QFrame(self.widget)
+        self.line_5.setGeometry(QtCore.QRect(308, 40, 20, 301))
+        self.line_5.setFrameShape(QtWidgets.QFrame.VLine)
+        self.line_5.setFrameShadow(QtWidgets.QFrame.Sunken)
+        self.line_5.setObjectName("line_5")
+        self.radioButton_27 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_27.setEnabled(True)
+        self.radioButton_27.setGeometry(QtCore.QRect(330, 20, 16, 20))
+        self.radioButton_27.setAutoFillBackground(False)
+        self.radioButton_27.setChecked(False)
+        self.radioButton_27.setObjectName("radioButton_27")
+        self.radioButton_47 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_47.setEnabled(True)
+        self.radioButton_47.setGeometry(QtCore.QRect(350, 110, 16, 20))
+        self.radioButton_47.setAutoFillBackground(False)
+        self.radioButton_47.setChecked(False)
+        self.radioButton_47.setObjectName("radioButton_47")
+        self.radioButton_12 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_12.setEnabled(True)
+        self.radioButton_12.setGeometry(QtCore.QRect(310, 230, 16, 20))
+        self.radioButton_12.setAutoFillBackground(False)
+        self.radioButton_12.setChecked(False)
+        self.radioButton_12.setObjectName("radioButton_12")
+        self.radioButton_62 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_62.setEnabled(True)
+        self.radioButton_62.setGeometry(QtCore.QRect(270, 300, 16, 20))
+        self.radioButton_62.setAutoFillBackground(False)
+        self.radioButton_62.setChecked(False)
+        self.radioButton_62.setObjectName("radioButton_62")
+        self.radioButton_64 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_64.setEnabled(True)
+        self.radioButton_64.setGeometry(QtCore.QRect(70, 300, 16, 20))
+        self.radioButton_64.setAutoFillBackground(False)
+        self.radioButton_64.setChecked(False)
+        self.radioButton_64.setObjectName("radioButton_64")
+        self.radioButton_60 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_60.setEnabled(True)
+        self.radioButton_60.setGeometry(QtCore.QRect(70, 200, 16, 20))
+        self.radioButton_60.setAutoFillBackground(False)
+        self.radioButton_60.setChecked(False)
+        self.radioButton_60.setObjectName("radioButton_60")
+        self.radioButton_54 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_54.setEnabled(True)
+        self.radioButton_54.setGeometry(QtCore.QRect(170, 100, 16, 20))
+        self.radioButton_54.setAutoFillBackground(False)
+        self.radioButton_54.setChecked(False)
+        self.radioButton_54.setObjectName("radioButton_54")
+        self.radioButton_38 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_38.setEnabled(True)
+        self.radioButton_38.setGeometry(QtCore.QRect(150, 110, 16, 20))
+        self.radioButton_38.setAutoFillBackground(False)
+        self.radioButton_38.setChecked(False)
+        self.radioButton_38.setObjectName("radioButton_38")
+        self.radioButton_58 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_58.setEnabled(True)
+        self.radioButton_58.setGeometry(QtCore.QRect(170, 300, 16, 20))
+        self.radioButton_58.setAutoFillBackground(False)
+        self.radioButton_58.setChecked(False)
+        self.radioButton_58.setObjectName("radioButton_58")
+        self.line_9 = QtWidgets.QFrame(self.widget)
+        self.line_9.setGeometry(QtCore.QRect(349, 24, 20, 301))
+        self.line_9.setFrameShape(QtWidgets.QFrame.VLine)
+        self.line_9.setFrameShadow(QtWidgets.QFrame.Sunken)
+        self.line_9.setObjectName("line_9")
+        self.radioButton_35 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_35.setEnabled(True)
+        self.radioButton_35.setGeometry(QtCore.QRect(350, 310, 16, 20))
+        self.radioButton_35.setAutoFillBackground(False)
+        self.radioButton_35.setChecked(False)
+        self.radioButton_35.setObjectName("radioButton_35")
+        self.radioButton_4 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_4.setEnabled(True)
+        self.radioButton_4.setGeometry(QtCore.QRect(310, 30, 16, 20))
+        self.radioButton_4.setAutoFillBackground(False)
+        self.radioButton_4.setChecked(False)
+        self.radioButton_4.setObjectName("radioButton_4")
+        self.radioButton_6 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_6.setEnabled(True)
+        self.radioButton_6.setGeometry(QtCore.QRect(10, 130, 16, 20))
+        self.radioButton_6.setAutoFillBackground(False)
+        self.radioButton_6.setChecked(False)
+        self.radioButton_6.setObjectName("radioButton_6")
+        self.radioButton_63 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_63.setEnabled(True)
+        self.radioButton_63.setGeometry(QtCore.QRect(370, 100, 16, 20))
+        self.radioButton_63.setAutoFillBackground(False)
+        self.radioButton_63.setChecked(False)
+        self.radioButton_63.setObjectName("radioButton_63")
+        self.radioButton_56 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_56.setEnabled(True)
+        self.radioButton_56.setGeometry(QtCore.QRect(170, 200, 16, 20))
+        self.radioButton_56.setAutoFillBackground(False)
+        self.radioButton_56.setChecked(False)
+        self.radioButton_56.setObjectName("radioButton_56")
+        self.radioButton_59 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_59.setEnabled(True)
+        self.radioButton_59.setGeometry(QtCore.QRect(370, 0, 16, 20))
+        self.radioButton_59.setAutoFillBackground(False)
+        self.radioButton_59.setChecked(False)
+        self.radioButton_59.setObjectName("radioButton_59")
+        self.radioButton_20 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_20.setEnabled(True)
+        self.radioButton_20.setGeometry(QtCore.QRect(30, 120, 16, 20))
+        self.radioButton_20.setAutoFillBackground(False)
+        self.radioButton_20.setChecked(False)
+        self.radioButton_20.setObjectName("radioButton_20")
+        self.radioButton_36 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_36.setEnabled(True)
+        self.radioButton_36.setGeometry(QtCore.QRect(50, 110, 16, 20))
+        self.radioButton_36.setAutoFillBackground(False)
+        self.radioButton_36.setChecked(False)
+        self.radioButton_36.setObjectName("radioButton_36")
+        self.radioButton_39 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_39.setEnabled(True)
+        self.radioButton_39.setGeometry(QtCore.QRect(50, 10, 16, 20))
+        self.radioButton_39.setAutoFillBackground(False)
+        self.radioButton_39.setChecked(False)
+        self.radioButton_39.setObjectName("radioButton_39")
+        self.radioButton_42 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_42.setEnabled(True)
+        self.radioButton_42.setGeometry(QtCore.QRect(150, 310, 16, 20))
+        self.radioButton_42.setAutoFillBackground(False)
+        self.radioButton_42.setChecked(False)
+        self.radioButton_42.setObjectName("radioButton_42")
+        self.line_8 = QtWidgets.QFrame(self.widget)
+        self.line_8.setGeometry(QtCore.QRect(328, 33, 20, 301))
+        self.line_8.setFrameShape(QtWidgets.QFrame.VLine)
+        self.line_8.setFrameShadow(QtWidgets.QFrame.Sunken)
+        self.line_8.setObjectName("line_8")
+        self.radioButton_49 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_49.setEnabled(True)
+        self.radioButton_49.setGeometry(QtCore.QRect(270, 200, 16, 20))
+        self.radioButton_49.setAutoFillBackground(False)
+        self.radioButton_49.setChecked(False)
+        self.radioButton_49.setObjectName("radioButton_49")
+        self.radioButton_24 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_24.setEnabled(True)
+        self.radioButton_24.setGeometry(QtCore.QRect(130, 220, 16, 20))
+        self.radioButton_24.setAutoFillBackground(False)
+        self.radioButton_24.setChecked(False)
+        self.radioButton_24.setObjectName("radioButton_24")
+        self.radioButton_61 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_61.setEnabled(True)
+        self.radioButton_61.setGeometry(QtCore.QRect(370, 200, 16, 20))
+        self.radioButton_61.setAutoFillBackground(False)
+        self.radioButton_61.setChecked(False)
+        self.radioButton_61.setObjectName("radioButton_61")
+        self.radioButton_55 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_55.setEnabled(True)
+        self.radioButton_55.setGeometry(QtCore.QRect(70, 0, 16, 20))
+        self.radioButton_55.setAutoFillBackground(False)
+        self.radioButton_55.setChecked(False)
+        self.radioButton_55.setObjectName("radioButton_55")
+        self.radioButton_50 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_50.setEnabled(True)
+        self.radioButton_50.setGeometry(QtCore.QRect(270, 100, 16, 20))
+        self.radioButton_50.setAutoFillBackground(False)
+        self.radioButton_50.setChecked(False)
+        self.radioButton_50.setObjectName("radioButton_50")
+        self.line_4 = QtWidgets.QFrame(self.widget)
+        self.line_4.setGeometry(QtCore.QRect(8, 40, 20, 301))
+        self.line_4.setFrameShape(QtWidgets.QFrame.VLine)
+        self.line_4.setFrameShadow(QtWidgets.QFrame.Sunken)
+        self.line_4.setObjectName("line_4")
+        self.radioButton_23 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_23.setEnabled(True)
+        self.radioButton_23.setGeometry(QtCore.QRect(30, 20, 16, 20))
+        self.radioButton_23.setAutoFillBackground(False)
+        self.radioButton_23.setChecked(False)
+        self.radioButton_23.setObjectName("radioButton_23")
+        self.radioButton_8 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_8.setEnabled(True)
+        self.radioButton_8.setGeometry(QtCore.QRect(310, 130, 16, 20))
+        self.radioButton_8.setAutoFillBackground(False)
+        self.radioButton_8.setChecked(False)
+        self.radioButton_8.setObjectName("radioButton_8")
+        self.radioButton_22 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_22.setEnabled(True)
+        self.radioButton_22.setGeometry(QtCore.QRect(130, 120, 16, 20))
+        self.radioButton_22.setAutoFillBackground(False)
+        self.radioButton_22.setChecked(False)
+        self.radioButton_22.setObjectName("radioButton_22")
+        self.radioButton_25 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_25.setEnabled(True)
+        self.radioButton_25.setGeometry(QtCore.QRect(130, 20, 16, 20))
+        self.radioButton_25.setAutoFillBackground(False)
+        self.radioButton_25.setChecked(False)
+        self.radioButton_25.setObjectName("radioButton_25")
+        self.radioButton_16 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_16.setEnabled(True)
+        self.radioButton_16.setGeometry(QtCore.QRect(310, 330, 16, 20))
+        self.radioButton_16.setAutoFillBackground(False)
+        self.radioButton_16.setChecked(False)
+        self.radioButton_16.setObjectName("radioButton_16")
+        self.radioButton_37 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_37.setEnabled(True)
+        self.radioButton_37.setGeometry(QtCore.QRect(250, 10, 16, 20))
+        self.radioButton_37.setAutoFillBackground(False)
+        self.radioButton_37.setChecked(False)
+        self.radioButton_37.setObjectName("radioButton_37")
+        self.radioButton_13 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_13.setEnabled(True)
+        self.radioButton_13.setGeometry(QtCore.QRect(210, 330, 16, 20))
+        self.radioButton_13.setAutoFillBackground(False)
+        self.radioButton_13.setChecked(False)
+        self.radioButton_13.setObjectName("radioButton_13")
+        self.radioButton_11 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_11.setEnabled(True)
+        self.radioButton_11.setGeometry(QtCore.QRect(110, 230, 16, 20))
+        self.radioButton_11.setAutoFillBackground(False)
+        self.radioButton_11.setChecked(False)
+        self.radioButton_11.setObjectName("radioButton_11")
+        self.radioButton_31 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_31.setEnabled(True)
+        self.radioButton_31.setGeometry(QtCore.QRect(330, 120, 16, 20))
+        self.radioButton_31.setAutoFillBackground(False)
+        self.radioButton_31.setChecked(False)
+        self.radioButton_31.setObjectName("radioButton_31")
+        self.radioButton_21 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_21.setEnabled(True)
+        self.radioButton_21.setGeometry(QtCore.QRect(230, 20, 16, 20))
+        self.radioButton_21.setAutoFillBackground(False)
+        self.radioButton_21.setChecked(False)
+        self.radioButton_21.setObjectName("radioButton_21")
+        self.radioButton_14 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_14.setEnabled(True)
+        self.radioButton_14.setGeometry(QtCore.QRect(10, 330, 16, 20))
+        self.radioButton_14.setAutoFillBackground(False)
+        self.radioButton_14.setChecked(False)
+        self.radioButton_14.setObjectName("radioButton_14")
+        self.radioButton_32 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_32.setEnabled(True)
+        self.radioButton_32.setGeometry(QtCore.QRect(30, 320, 16, 20))
+        self.radioButton_32.setAutoFillBackground(False)
+        self.radioButton_32.setChecked(False)
+        self.radioButton_32.setObjectName("radioButton_32")
+        self.radioButton_33 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_33.setEnabled(True)
+        self.radioButton_33.setGeometry(QtCore.QRect(250, 210, 16, 20))
+        self.radioButton_33.setAutoFillBackground(False)
+        self.radioButton_33.setChecked(False)
+        self.radioButton_33.setObjectName("radioButton_33")
+        self.radioButton_1 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_1.setEnabled(True)
+        self.radioButton_1.setGeometry(QtCore.QRect(10, 30, 16, 20))
+        self.radioButton_1.setAutoFillBackground(False)
+        self.radioButton_1.setChecked(False)
+        self.radioButton_1.setObjectName("radioButton_1")
+        self.radioButton_43 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_43.setEnabled(True)
+        self.radioButton_43.setGeometry(QtCore.QRect(350, 10, 16, 20))
+        self.radioButton_43.setAutoFillBackground(False)
+        self.radioButton_43.setChecked(False)
+        self.radioButton_43.setObjectName("radioButton_43")
+        self.radioButton_45 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_45.setEnabled(True)
+        self.radioButton_45.setGeometry(QtCore.QRect(350, 210, 16, 20))
+        self.radioButton_45.setAutoFillBackground(False)
+        self.radioButton_45.setChecked(False)
+        self.radioButton_45.setObjectName("radioButton_45")
+        self.radioButton_40 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_40.setEnabled(True)
+        self.radioButton_40.setGeometry(QtCore.QRect(150, 210, 16, 20))
+        self.radioButton_40.setAutoFillBackground(False)
+        self.radioButton_40.setChecked(False)
+        self.radioButton_40.setObjectName("radioButton_40")
+        self.radioButton_10 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_10.setEnabled(True)
+        self.radioButton_10.setGeometry(QtCore.QRect(10, 230, 16, 20))
+        self.radioButton_10.setAutoFillBackground(False)
+        self.radioButton_10.setChecked(False)
+        self.radioButton_10.setObjectName("radioButton_10")
+        self.line_2 = QtWidgets.QFrame(self.widget)
+        self.line_2.setGeometry(QtCore.QRect(82, 4, 291, 16))
+        self.line_2.setFrameShape(QtWidgets.QFrame.HLine)
+        self.line_2.setFrameShadow(QtWidgets.QFrame.Sunken)
+        self.line_2.setObjectName("line_2")
+        self.radioButton_7 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_7.setEnabled(True)
+        self.radioButton_7.setGeometry(QtCore.QRect(110, 130, 16, 20))
+        self.radioButton_7.setAutoFillBackground(False)
+        self.radioButton_7.setChecked(False)
+        self.radioButton_7.setObjectName("radioButton_7")
+        self.radioButton_19 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_19.setEnabled(True)
+        self.radioButton_19.setGeometry(QtCore.QRect(330, 320, 16, 20))
+        self.radioButton_19.setAutoFillBackground(False)
+        self.radioButton_19.setChecked(False)
+        self.radioButton_19.setObjectName("radioButton_19")
+        self.radioButton_44 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_44.setEnabled(True)
+        self.radioButton_44.setGeometry(QtCore.QRect(50, 210, 16, 20))
+        self.radioButton_44.setAutoFillBackground(False)
+        self.radioButton_44.setChecked(False)
+        self.radioButton_44.setObjectName("radioButton_44")
+        self.radioButton_17 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_17.setEnabled(True)
+        self.radioButton_17.setGeometry(QtCore.QRect(230, 220, 16, 20))
+        self.radioButton_17.setAutoFillBackground(False)
+        self.radioButton_17.setChecked(False)
+        self.radioButton_17.setObjectName("radioButton_17")
+        self.radioButton_46 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_46.setEnabled(True)
+        self.radioButton_46.setGeometry(QtCore.QRect(250, 310, 16, 20))
+        self.radioButton_46.setAutoFillBackground(False)
+        self.radioButton_46.setChecked(False)
+        self.radioButton_46.setObjectName("radioButton_46")
+        self.radioButton_26 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_26.setEnabled(True)
+        self.radioButton_26.setGeometry(QtCore.QRect(130, 320, 16, 20))
+        self.radioButton_26.setAutoFillBackground(False)
+        self.radioButton_26.setChecked(False)
+        self.radioButton_26.setObjectName("radioButton_26")
+        self.radioButton_5 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_5.setEnabled(True)
+        self.radioButton_5.setGeometry(QtCore.QRect(210, 130, 16, 20))
+        self.radioButton_5.setAutoFillBackground(False)
+        self.radioButton_5.setChecked(False)
+        self.radioButton_5.setObjectName("radioButton_5")
+        self.line_6 = QtWidgets.QFrame(self.widget)
+        self.line_6.setGeometry(QtCore.QRect(63, 13, 291, 16))
+        self.line_6.setFrameShape(QtWidgets.QFrame.HLine)
+        self.line_6.setFrameShadow(QtWidgets.QFrame.Sunken)
+        self.line_6.setObjectName("line_6")
+        self.line_10 = QtWidgets.QFrame(self.widget)
+        self.line_10.setGeometry(QtCore.QRect(368, 11, 20, 301))
+        self.line_10.setFrameShape(QtWidgets.QFrame.VLine)
+        self.line_10.setFrameShadow(QtWidgets.QFrame.Sunken)
+        self.line_10.setObjectName("line_10")
+        self.radioButton_53 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_53.setEnabled(True)
+        self.radioButton_53.setGeometry(QtCore.QRect(270, 0, 16, 20))
+        self.radioButton_53.setAutoFillBackground(False)
+        self.radioButton_53.setChecked(False)
+        self.radioButton_53.setObjectName("radioButton_53")
+        self.radioButton_18 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_18.setEnabled(True)
+        self.radioButton_18.setGeometry(QtCore.QRect(230, 120, 16, 20))
+        self.radioButton_18.setAutoFillBackground(False)
+        self.radioButton_18.setChecked(False)
+        self.radioButton_18.setObjectName("radioButton_18")
+        self.radioButton_3 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_3.setEnabled(True)
+        self.radioButton_3.setGeometry(QtCore.QRect(210, 30, 16, 20))
+        self.radioButton_3.setAutoFillBackground(False)
+        self.radioButton_3.setChecked(False)
+        self.radioButton_3.setObjectName("radioButton_3")
+        self.radioButton_51 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_51.setEnabled(True)
+        self.radioButton_51.setGeometry(QtCore.QRect(370, 300, 16, 20))
+        self.radioButton_51.setAutoFillBackground(False)
+        self.radioButton_51.setChecked(False)
+        self.radioButton_51.setObjectName("radioButton_51")
+        self.radioButton_15 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_15.setEnabled(True)
+        self.radioButton_15.setGeometry(QtCore.QRect(110, 330, 16, 20))
+        self.radioButton_15.setAutoFillBackground(False)
+        self.radioButton_15.setChecked(False)
+        self.radioButton_15.setObjectName("radioButton_15")
+        self.radioButton_48 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_48.setEnabled(True)
+        self.radioButton_48.setGeometry(QtCore.QRect(50, 310, 16, 20))
+        self.radioButton_48.setAutoFillBackground(False)
+        self.radioButton_48.setChecked(True)
+        self.radioButton_48.setObjectName("radioButton_48")
+        self.radioButton_41 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_41.setEnabled(True)
+        self.radioButton_41.setGeometry(QtCore.QRect(150, 10, 16, 20))
+        self.radioButton_41.setAutoFillBackground(False)
+        self.radioButton_41.setChecked(False)
+        self.radioButton_41.setObjectName("radioButton_41")
+        self.radioButton_29 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_29.setEnabled(True)
+        self.radioButton_29.setGeometry(QtCore.QRect(330, 220, 16, 20))
+        self.radioButton_29.setAutoFillBackground(False)
+        self.radioButton_29.setChecked(False)
+        self.radioButton_29.setObjectName("radioButton_29")
+        self.radioButton_30 = QtWidgets.QRadioButton(self.widget)
+        self.radioButton_30.setEnabled(True)
+        self.radioButton_30.setGeometry(QtCore.QRect(230, 320, 16, 20))
+        self.radioButton_30.setAutoFillBackground(False)
+        self.radioButton_30.setChecked(False)
+        self.radioButton_30.setObjectName("radioButton_30")
+        self.line_7 = QtWidgets.QFrame(self.widget)
+        self.line_7.setGeometry(QtCore.QRect(42, 23, 291, 16))
+        self.line_7.setFrameShape(QtWidgets.QFrame.HLine)
+        self.line_7.setFrameShadow(QtWidgets.QFrame.Sunken)
+        self.line_7.setObjectName("line_7")
+        self.line_3 = QtWidgets.QFrame(self.widget)
+        self.line_3.setGeometry(QtCore.QRect(22, 33, 291, 16))
+        self.line_3.setFrameShape(QtWidgets.QFrame.HLine)
+        self.line_3.setFrameShadow(QtWidgets.QFrame.Sunken)
+        self.line_3.setObjectName("line_3")
+        self.line_7.raise_()
+        self.line_9.raise_()
+        self.line_10.raise_()
+        self.line_8.raise_()
+        self.line_5.raise_()
+        self.line_2.raise_()
+        self.line.raise_()
+        self.line_3.raise_()
+        self.line_4.raise_()
+        self.line_6.raise_()
+        self.radioButton_9.raise_()
+        self.radioButton_28.raise_()
+        self.radioButton_34.raise_()
+        self.radioButton_2.raise_()
+        self.radioButton_52.raise_()
+        self.radioButton_57.raise_()
+        self.radioButton_27.raise_()
+        self.radioButton_47.raise_()
+        self.radioButton_12.raise_()
+        self.radioButton_62.raise_()
+        self.radioButton_64.raise_()
+        self.radioButton_60.raise_()
+        self.radioButton_54.raise_()
+        self.radioButton_38.raise_()
+        self.radioButton_58.raise_()
+        self.radioButton_35.raise_()
+        self.radioButton_4.raise_()
+        self.radioButton_6.raise_()
+        self.radioButton_63.raise_()
+        self.radioButton_56.raise_()
+        self.radioButton_59.raise_()
+        self.radioButton_20.raise_()
+        self.radioButton_36.raise_()
+        self.radioButton_39.raise_()
+        self.radioButton_42.raise_()
+        self.radioButton_49.raise_()
+        self.radioButton_24.raise_()
+        self.radioButton_61.raise_()
+        self.radioButton_55.raise_()
+        self.radioButton_50.raise_()
+        self.radioButton_23.raise_()
+        self.radioButton_8.raise_()
+        self.radioButton_22.raise_()
+        self.radioButton_25.raise_()
+        self.radioButton_16.raise_()
+        self.radioButton_37.raise_()
+        self.radioButton_13.raise_()
+        self.radioButton_11.raise_()
+        self.radioButton_31.raise_()
+        self.radioButton_21.raise_()
+        self.radioButton_14.raise_()
+        self.radioButton_32.raise_()
+        self.radioButton_33.raise_()
+        self.radioButton_1.raise_()
+        self.radioButton_43.raise_()
+        self.radioButton_45.raise_()
+        self.radioButton_40.raise_()
+        self.radioButton_10.raise_()
+        self.radioButton_7.raise_()
+        self.radioButton_19.raise_()
+        self.radioButton_44.raise_()
+        self.radioButton_17.raise_()
+        self.radioButton_46.raise_()
+        self.radioButton_26.raise_()
+        self.radioButton_5.raise_()
+        self.radioButton_53.raise_()
+        self.radioButton_18.raise_()
+        self.radioButton_3.raise_()
+        self.radioButton_51.raise_()
+        self.radioButton_15.raise_()
+        self.radioButton_48.raise_()
+        self.radioButton_41.raise_()
+        self.radioButton_29.raise_()
+        self.radioButton_30.raise_()
+        self.gridLayout_4.addWidget(self.widget, 0, 0, 1, 1)
+        self.gridLayout_3.addWidget(self.groupBox, 0, 0, 1, 1)
+        self.groupBox_2 = QtWidgets.QGroupBox(self.centralwidget)
+        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
+        sizePolicy.setHorizontalStretch(0)
+        sizePolicy.setVerticalStretch(0)
+        sizePolicy.setHeightForWidth(self.groupBox_2.sizePolicy().hasHeightForWidth())
+        self.groupBox_2.setSizePolicy(sizePolicy)
+        self.groupBox_2.setMinimumSize(QtCore.QSize(0, 50))
+        self.groupBox_2.setObjectName("groupBox_2")
+        self.label = QtWidgets.QLabel(self.groupBox_2)
+        self.label.setGeometry(QtCore.QRect(10, 20, 91, 16))
+        self.label.setObjectName("label")
+        self.label_2 = QtWidgets.QLabel(self.groupBox_2)
+        self.label_2.setGeometry(QtCore.QRect(110, 20, 55, 16))
+        self.label_2.setObjectName("label_2")
+        self.label_5 = QtWidgets.QLabel(self.groupBox_2)
+        self.label_5.setGeometry(QtCore.QRect(190, 20, 51, 16))
+        self.label_5.setObjectName("label_5")
+        self.label_6 = QtWidgets.QLabel(self.groupBox_2)
+        self.label_6.setGeometry(QtCore.QRect(260, 20, 201, 16))
+        self.label_6.setObjectName("label_6")
+        self.gridLayout_3.addWidget(self.groupBox_2, 2, 0, 1, 1)
+        MainWindow.setCentralWidget(self.centralwidget)
+        self.menubar = QtWidgets.QMenuBar(MainWindow)
+        self.menubar.setGeometry(QtCore.QRect(0, 0, 483, 21))
+        self.menubar.setObjectName("menubar")
+        MainWindow.setMenuBar(self.menubar)
+        self.statusbar = QtWidgets.QStatusBar(MainWindow)
+        self.statusbar.setObjectName("statusbar")
+        MainWindow.setStatusBar(self.statusbar)
+
+        self.retranslateUi(MainWindow)
+        self.comboBox.setCurrentIndex(-1)
+        QtCore.QMetaObject.connectSlotsByName(MainWindow)
+
+    def retranslateUi(self, MainWindow):
+        _translate = QtCore.QCoreApplication.translate
+        MainWindow.setWindowTitle(_translate("MainWindow", "Cube Control"))
+        self.spinBox_2.setPrefix(_translate("MainWindow", "Start: "))
+        self.pushButton_4.setText(_translate("MainWindow", "Stop"))
+        self.pushButton_2.setText(_translate("MainWindow", "Play"))
+        self.pushButton_7.setText(_translate("MainWindow", "Goto Frame"))
+        self.pushButton.setText(_translate("MainWindow", "Connect"))
+        self.pushButton_3.setText(_translate("MainWindow", "Pause"))
+        self.label_7.setText(_translate("MainWindow", "Value: 0"))
+        self.pushButton_6.setText(_translate("MainWindow", "Clear Frame"))
+        self.spinBox.setPrefix(_translate("MainWindow", "Frame: "))
+        self.pushButton_5.setText(_translate("MainWindow", "Save Frame"))
+        self.lineEdit.setText(_translate("MainWindow", "COM6"))
+        self.pushButton_8.setText(_translate("MainWindow", "Save Animation"))
+        self.spinBox_3.setPrefix(_translate("MainWindow", "Length: "))
+        self.groupBox.setTitle(_translate("MainWindow", "LED-Cube"))
+        self.radioButton_9.setText(_translate("MainWindow", "20"))
+        self.radioButton_28.setText(_translate("MainWindow", "29"))
+        self.radioButton_34.setText(_translate("MainWindow", "38"))
+        self.radioButton_2.setText(_translate("MainWindow", "56"))
+        self.radioButton_52.setText(_translate("MainWindow", "47"))
+        self.radioButton_57.setText(_translate("MainWindow", "59"))
+        self.radioButton_27.setText(_translate("MainWindow", "49"))
+        self.radioButton_47.setText(_translate("MainWindow", "34"))
+        self.radioButton_12.setText(_translate("MainWindow", "16"))
+        self.radioButton_62.setText(_translate("MainWindow", "7"))
+        self.radioButton_64.setText(_translate("MainWindow", "15"))
+        self.radioButton_60.setText(_translate("MainWindow", "31"))
+        self.radioButton_54.setText(_translate("MainWindow", "43"))
+        self.radioButton_38.setText(_translate("MainWindow", "42"))
+        self.radioButton_58.setText(_translate("MainWindow", "11"))
+        self.radioButton_35.setText(_translate("MainWindow", "2"))
+        self.radioButton_4.setText(_translate("MainWindow", "48"))
+        self.radioButton_6.setText(_translate("MainWindow", "44"))
+        self.radioButton_63.setText(_translate("MainWindow", "35"))
+        self.radioButton_56.setText(_translate("MainWindow", "27"))
+        self.radioButton_59.setText(_translate("MainWindow", "51"))
+        self.radioButton_20.setText(_translate("MainWindow", "45"))
+        self.radioButton_36.setText(_translate("MainWindow", "46"))
+        self.radioButton_39.setText(_translate("MainWindow", "62"))
+        self.radioButton_42.setText(_translate("MainWindow", "10"))
+        self.radioButton_49.setText(_translate("MainWindow", "23"))
+        self.radioButton_24.setText(_translate("MainWindow", "25"))
+        self.radioButton_61.setText(_translate("MainWindow", "19"))
+        self.radioButton_55.setText(_translate("MainWindow", "63"))
+        self.radioButton_50.setText(_translate("MainWindow", "39"))
+        self.radioButton_23.setText(_translate("MainWindow", "61"))
+        self.radioButton_8.setText(_translate("MainWindow", "32"))
+        self.radioButton_22.setText(_translate("MainWindow", "41"))
+        self.radioButton_25.setText(_translate("MainWindow", "57"))
+        self.radioButton_16.setText(_translate("MainWindow", "0"))
+        self.radioButton_37.setText(_translate("MainWindow", "54"))
+        self.radioButton_13.setText(_translate("MainWindow", "4"))
+        self.radioButton_11.setText(_translate("MainWindow", "24"))
+        self.radioButton_31.setText(_translate("MainWindow", "33"))
+        self.radioButton_21.setText(_translate("MainWindow", "53"))
+        self.radioButton_14.setText(_translate("MainWindow", "12"))
+        self.radioButton_32.setText(_translate("MainWindow", "13"))
+        self.radioButton_33.setText(_translate("MainWindow", "22"))
+        self.radioButton_1.setText(_translate("MainWindow", "60"))
+        self.radioButton_43.setText(_translate("MainWindow", "50"))
+        self.radioButton_45.setText(_translate("MainWindow", "18"))
+        self.radioButton_40.setText(_translate("MainWindow", "26"))
+        self.radioButton_10.setText(_translate("MainWindow", "28"))
+        self.radioButton_7.setText(_translate("MainWindow", "40"))
+        self.radioButton_19.setText(_translate("MainWindow", "1"))
+        self.radioButton_44.setText(_translate("MainWindow", "30"))
+        self.radioButton_17.setText(_translate("MainWindow", "21"))
+        self.radioButton_46.setText(_translate("MainWindow", "6"))
+        self.radioButton_26.setText(_translate("MainWindow", "9"))
+        self.radioButton_5.setText(_translate("MainWindow", "36"))
+        self.radioButton_53.setText(_translate("MainWindow", "55"))
+        self.radioButton_18.setText(_translate("MainWindow", "37"))
+        self.radioButton_3.setText(_translate("MainWindow", "52"))
+        self.radioButton_51.setText(_translate("MainWindow", "3"))
+        self.radioButton_15.setText(_translate("MainWindow", "8"))
+        self.radioButton_48.setText(_translate("MainWindow", "14"))
+        self.radioButton_41.setText(_translate("MainWindow", "58"))
+        self.radioButton_29.setText(_translate("MainWindow", "17"))
+        self.radioButton_30.setText(_translate("MainWindow", "5"))
+        self.groupBox_2.setTitle(_translate("MainWindow", "Info"))
+        self.label.setText(_translate("MainWindow", "Current Frame: "))
+        self.label_2.setText(_translate("MainWindow", "0"))
+        self.label_5.setText(_translate("MainWindow", "Status:"))
+        self.label_6.setText(_translate("MainWindow", "disconnected"))
+

+ 2037 - 0
ui.ui

@@ -0,0 +1,2037 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>483</width>
+    <height>688</height>
+   </rect>
+  </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
+  <property name="windowTitle">
+   <string>Cube Control</string>
+  </property>
+  <widget class="QWidget" name="centralwidget">
+   <layout class="QGridLayout" name="gridLayout_3">
+    <item row="1" column="0">
+     <layout class="QGridLayout" name="gridLayout_2">
+      <property name="spacing">
+       <number>20</number>
+      </property>
+      <item row="2" column="1">
+       <widget class="QSpinBox" name="spinBox_2">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="maximumSize">
+         <size>
+          <width>16777215</width>
+          <height>75</height>
+         </size>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignCenter</set>
+        </property>
+        <property name="prefix">
+         <string>Start: </string>
+        </property>
+        <property name="maximum">
+         <number>65535</number>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="3">
+       <widget class="QPushButton" name="pushButton_4">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="maximumSize">
+         <size>
+          <width>204</width>
+          <height>16777215</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>Stop</string>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="1">
+       <widget class="QPushButton" name="pushButton_2">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="text">
+         <string>Play</string>
+        </property>
+       </widget>
+      </item>
+      <item row="3" column="0">
+       <widget class="QPushButton" name="pushButton_7">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="text">
+         <string>Goto Frame</string>
+        </property>
+       </widget>
+      </item>
+      <item row="3" column="3">
+       <widget class="QPushButton" name="pushButton">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="text">
+         <string>Connect</string>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="2">
+       <widget class="QPushButton" name="pushButton_3">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="maximumSize">
+         <size>
+          <width>203</width>
+          <height>16777215</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>Pause</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="0">
+       <widget class="QLabel" name="label_7">
+        <property name="layoutDirection">
+         <enum>Qt::LeftToRight</enum>
+        </property>
+        <property name="text">
+         <string>Value: 0</string>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignCenter</set>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="3">
+       <widget class="QPushButton" name="pushButton_6">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="text">
+         <string>Clear Frame</string>
+        </property>
+       </widget>
+      </item>
+      <item row="3" column="1">
+       <widget class="QSpinBox" name="spinBox">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="maximumSize">
+         <size>
+          <width>16777215</width>
+          <height>75</height>
+         </size>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignCenter</set>
+        </property>
+        <property name="prefix">
+         <string>Frame: </string>
+        </property>
+        <property name="maximum">
+         <number>65535</number>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="0">
+       <widget class="QPushButton" name="pushButton_5">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="maximumSize">
+         <size>
+          <width>204</width>
+          <height>16777215</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>Save Frame</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="1" colspan="2">
+       <widget class="QSlider" name="horizontalSlider">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="maximumSize">
+         <size>
+          <width>16777215</width>
+          <height>42</height>
+         </size>
+        </property>
+        <property name="maximum">
+         <number>15</number>
+        </property>
+        <property name="pageStep">
+         <number>5</number>
+        </property>
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+       </widget>
+      </item>
+      <item row="3" column="2">
+       <widget class="QLineEdit" name="lineEdit">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="maximumSize">
+         <size>
+          <width>16777215</width>
+          <height>68</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>COM6</string>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignCenter</set>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="3">
+       <widget class="QPushButton" name="pushButton_8">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="text">
+         <string>Save Animation</string>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="0">
+       <widget class="QComboBox" name="comboBox">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="maximumSize">
+         <size>
+          <width>16777215</width>
+          <height>75</height>
+         </size>
+        </property>
+        <property name="currentText">
+         <string/>
+        </property>
+        <property name="currentIndex">
+         <number>-1</number>
+        </property>
+        <property name="maxCount">
+         <number>64</number>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="2">
+       <widget class="QSpinBox" name="spinBox_3">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="maximumSize">
+         <size>
+          <width>16777215</width>
+          <height>75</height>
+         </size>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignCenter</set>
+        </property>
+        <property name="prefix">
+         <string>Length: </string>
+        </property>
+        <property name="maximum">
+         <number>65535</number>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </item>
+    <item row="0" column="0">
+     <widget class="QGroupBox" name="groupBox">
+      <property name="title">
+       <string>LED-Cube</string>
+      </property>
+      <layout class="QGridLayout" name="gridLayout_4">
+       <item row="0" column="0">
+        <widget class="QWidget" name="widget" native="true">
+         <property name="minimumSize">
+          <size>
+           <width>391</width>
+           <height>351</height>
+          </size>
+         </property>
+         <property name="maximumSize">
+          <size>
+           <width>391</width>
+           <height>351</height>
+          </size>
+         </property>
+         <widget class="QRadioButton" name="radioButton_9">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>210</x>
+            <y>230</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>20</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="Line" name="line">
+          <property name="geometry">
+           <rect>
+            <x>20</x>
+            <y>334</y>
+            <width>291</width>
+            <height>16</height>
+           </rect>
+          </property>
+          <property name="orientation">
+           <enum>Qt::Horizontal</enum>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_28">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>30</x>
+            <y>220</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>29</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_34">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>250</x>
+            <y>110</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>38</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_2">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>110</x>
+            <y>30</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>56</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_52">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>70</x>
+            <y>100</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>47</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_57">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>170</x>
+            <y>0</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>59</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="Line" name="line_5">
+          <property name="geometry">
+           <rect>
+            <x>308</x>
+            <y>40</y>
+            <width>20</width>
+            <height>301</height>
+           </rect>
+          </property>
+          <property name="orientation">
+           <enum>Qt::Vertical</enum>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_27">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>330</x>
+            <y>20</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>49</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_47">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>350</x>
+            <y>110</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>34</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_12">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>310</x>
+            <y>230</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>16</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_62">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>270</x>
+            <y>300</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>7</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_64">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>70</x>
+            <y>300</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>15</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_60">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>70</x>
+            <y>200</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>31</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_54">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>170</x>
+            <y>100</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>43</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_38">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>150</x>
+            <y>110</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>42</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_58">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>170</x>
+            <y>300</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>11</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="Line" name="line_9">
+          <property name="geometry">
+           <rect>
+            <x>349</x>
+            <y>24</y>
+            <width>20</width>
+            <height>301</height>
+           </rect>
+          </property>
+          <property name="orientation">
+           <enum>Qt::Vertical</enum>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_35">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>350</x>
+            <y>310</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>2</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_4">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>310</x>
+            <y>30</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>48</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_6">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>10</x>
+            <y>130</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>44</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_63">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>370</x>
+            <y>100</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>35</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_56">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>170</x>
+            <y>200</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>27</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_59">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>370</x>
+            <y>0</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>51</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_20">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>30</x>
+            <y>120</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>45</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_36">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>50</x>
+            <y>110</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>46</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_39">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>50</x>
+            <y>10</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>62</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_42">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>150</x>
+            <y>310</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>10</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="Line" name="line_8">
+          <property name="geometry">
+           <rect>
+            <x>328</x>
+            <y>33</y>
+            <width>20</width>
+            <height>301</height>
+           </rect>
+          </property>
+          <property name="orientation">
+           <enum>Qt::Vertical</enum>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_49">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>270</x>
+            <y>200</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>23</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_24">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>130</x>
+            <y>220</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>25</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_61">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>370</x>
+            <y>200</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>19</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_55">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>70</x>
+            <y>0</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>63</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_50">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>270</x>
+            <y>100</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>39</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="Line" name="line_4">
+          <property name="geometry">
+           <rect>
+            <x>8</x>
+            <y>40</y>
+            <width>20</width>
+            <height>301</height>
+           </rect>
+          </property>
+          <property name="orientation">
+           <enum>Qt::Vertical</enum>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_23">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>30</x>
+            <y>20</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>61</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_8">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>310</x>
+            <y>130</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>32</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_22">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>130</x>
+            <y>120</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>41</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_25">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>130</x>
+            <y>20</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>57</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_16">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>310</x>
+            <y>330</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>0</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_37">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>250</x>
+            <y>10</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>54</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_13">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>210</x>
+            <y>330</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>4</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_11">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>110</x>
+            <y>230</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>24</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_31">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>330</x>
+            <y>120</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>33</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_21">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>230</x>
+            <y>20</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>53</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_14">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>10</x>
+            <y>330</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>12</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_32">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>30</x>
+            <y>320</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>13</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_33">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>250</x>
+            <y>210</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>22</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_1">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>10</x>
+            <y>30</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>60</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_43">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>350</x>
+            <y>10</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>50</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_45">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>350</x>
+            <y>210</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>18</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_40">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>150</x>
+            <y>210</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>26</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_10">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>10</x>
+            <y>230</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>28</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="Line" name="line_2">
+          <property name="geometry">
+           <rect>
+            <x>82</x>
+            <y>4</y>
+            <width>291</width>
+            <height>16</height>
+           </rect>
+          </property>
+          <property name="orientation">
+           <enum>Qt::Horizontal</enum>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_7">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>110</x>
+            <y>130</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>40</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_19">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>330</x>
+            <y>320</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>1</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_44">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>50</x>
+            <y>210</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>30</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_17">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>230</x>
+            <y>220</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>21</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_46">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>250</x>
+            <y>310</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>6</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_26">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>130</x>
+            <y>320</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>9</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_5">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>210</x>
+            <y>130</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>36</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="Line" name="line_6">
+          <property name="geometry">
+           <rect>
+            <x>63</x>
+            <y>13</y>
+            <width>291</width>
+            <height>16</height>
+           </rect>
+          </property>
+          <property name="orientation">
+           <enum>Qt::Horizontal</enum>
+          </property>
+         </widget>
+         <widget class="Line" name="line_10">
+          <property name="geometry">
+           <rect>
+            <x>368</x>
+            <y>11</y>
+            <width>20</width>
+            <height>301</height>
+           </rect>
+          </property>
+          <property name="orientation">
+           <enum>Qt::Vertical</enum>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_53">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>270</x>
+            <y>0</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>55</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_18">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>230</x>
+            <y>120</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>37</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_3">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>210</x>
+            <y>30</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>52</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_51">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>370</x>
+            <y>300</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>3</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_15">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>110</x>
+            <y>330</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>8</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_48">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>50</x>
+            <y>310</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>14</string>
+          </property>
+          <property name="checked">
+           <bool>true</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_41">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>150</x>
+            <y>10</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>58</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_29">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>330</x>
+            <y>220</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>17</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="QRadioButton" name="radioButton_30">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="geometry">
+           <rect>
+            <x>230</x>
+            <y>320</y>
+            <width>16</width>
+            <height>20</height>
+           </rect>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>5</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+         <widget class="Line" name="line_7">
+          <property name="geometry">
+           <rect>
+            <x>42</x>
+            <y>23</y>
+            <width>291</width>
+            <height>16</height>
+           </rect>
+          </property>
+          <property name="orientation">
+           <enum>Qt::Horizontal</enum>
+          </property>
+         </widget>
+         <widget class="Line" name="line_3">
+          <property name="geometry">
+           <rect>
+            <x>22</x>
+            <y>33</y>
+            <width>291</width>
+            <height>16</height>
+           </rect>
+          </property>
+          <property name="orientation">
+           <enum>Qt::Horizontal</enum>
+          </property>
+         </widget>
+         <zorder>line_7</zorder>
+         <zorder>line_9</zorder>
+         <zorder>line_10</zorder>
+         <zorder>line_8</zorder>
+         <zorder>line_5</zorder>
+         <zorder>line_2</zorder>
+         <zorder>line</zorder>
+         <zorder>line_3</zorder>
+         <zorder>line_4</zorder>
+         <zorder>line_6</zorder>
+         <zorder>radioButton_9</zorder>
+         <zorder>radioButton_28</zorder>
+         <zorder>radioButton_34</zorder>
+         <zorder>radioButton_2</zorder>
+         <zorder>radioButton_52</zorder>
+         <zorder>radioButton_57</zorder>
+         <zorder>radioButton_27</zorder>
+         <zorder>radioButton_47</zorder>
+         <zorder>radioButton_12</zorder>
+         <zorder>radioButton_62</zorder>
+         <zorder>radioButton_64</zorder>
+         <zorder>radioButton_60</zorder>
+         <zorder>radioButton_54</zorder>
+         <zorder>radioButton_38</zorder>
+         <zorder>radioButton_58</zorder>
+         <zorder>radioButton_35</zorder>
+         <zorder>radioButton_4</zorder>
+         <zorder>radioButton_6</zorder>
+         <zorder>radioButton_63</zorder>
+         <zorder>radioButton_56</zorder>
+         <zorder>radioButton_59</zorder>
+         <zorder>radioButton_20</zorder>
+         <zorder>radioButton_36</zorder>
+         <zorder>radioButton_39</zorder>
+         <zorder>radioButton_42</zorder>
+         <zorder>radioButton_49</zorder>
+         <zorder>radioButton_24</zorder>
+         <zorder>radioButton_61</zorder>
+         <zorder>radioButton_55</zorder>
+         <zorder>radioButton_50</zorder>
+         <zorder>radioButton_23</zorder>
+         <zorder>radioButton_8</zorder>
+         <zorder>radioButton_22</zorder>
+         <zorder>radioButton_25</zorder>
+         <zorder>radioButton_16</zorder>
+         <zorder>radioButton_37</zorder>
+         <zorder>radioButton_13</zorder>
+         <zorder>radioButton_11</zorder>
+         <zorder>radioButton_31</zorder>
+         <zorder>radioButton_21</zorder>
+         <zorder>radioButton_14</zorder>
+         <zorder>radioButton_32</zorder>
+         <zorder>radioButton_33</zorder>
+         <zorder>radioButton_1</zorder>
+         <zorder>radioButton_43</zorder>
+         <zorder>radioButton_45</zorder>
+         <zorder>radioButton_40</zorder>
+         <zorder>radioButton_10</zorder>
+         <zorder>radioButton_7</zorder>
+         <zorder>radioButton_19</zorder>
+         <zorder>radioButton_44</zorder>
+         <zorder>radioButton_17</zorder>
+         <zorder>radioButton_46</zorder>
+         <zorder>radioButton_26</zorder>
+         <zorder>radioButton_5</zorder>
+         <zorder>radioButton_53</zorder>
+         <zorder>radioButton_18</zorder>
+         <zorder>radioButton_3</zorder>
+         <zorder>radioButton_51</zorder>
+         <zorder>radioButton_15</zorder>
+         <zorder>radioButton_48</zorder>
+         <zorder>radioButton_41</zorder>
+         <zorder>radioButton_29</zorder>
+         <zorder>radioButton_30</zorder>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+    </item>
+    <item row="2" column="0">
+     <widget class="QGroupBox" name="groupBox_2">
+      <property name="sizePolicy">
+       <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+        <horstretch>0</horstretch>
+        <verstretch>0</verstretch>
+       </sizepolicy>
+      </property>
+      <property name="minimumSize">
+       <size>
+        <width>0</width>
+        <height>50</height>
+       </size>
+      </property>
+      <property name="title">
+       <string>Info</string>
+      </property>
+      <widget class="QLabel" name="label">
+       <property name="geometry">
+        <rect>
+         <x>10</x>
+         <y>20</y>
+         <width>91</width>
+         <height>16</height>
+        </rect>
+       </property>
+       <property name="text">
+        <string>Current Frame: </string>
+       </property>
+      </widget>
+      <widget class="QLabel" name="label_2">
+       <property name="geometry">
+        <rect>
+         <x>110</x>
+         <y>20</y>
+         <width>55</width>
+         <height>16</height>
+        </rect>
+       </property>
+       <property name="text">
+        <string>0</string>
+       </property>
+      </widget>
+      <widget class="QLabel" name="label_5">
+       <property name="geometry">
+        <rect>
+         <x>190</x>
+         <y>20</y>
+         <width>51</width>
+         <height>16</height>
+        </rect>
+       </property>
+       <property name="text">
+        <string>Status:</string>
+       </property>
+      </widget>
+      <widget class="QLabel" name="label_6">
+       <property name="geometry">
+        <rect>
+         <x>260</x>
+         <y>20</y>
+         <width>201</width>
+         <height>16</height>
+        </rect>
+       </property>
+       <property name="text">
+        <string>disconnected</string>
+       </property>
+      </widget>
+     </widget>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QMenuBar" name="menubar">
+   <property name="geometry">
+    <rect>
+     <x>0</x>
+     <y>0</y>
+     <width>483</width>
+     <height>21</height>
+    </rect>
+   </property>
+  </widget>
+  <widget class="QStatusBar" name="statusbar"/>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>