Lab3_Gui code

Dependencies:   mbed

Revision:
1:faa8aa177069
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed_beat_new.py	Thu Sep 21 22:16:15 2017 -0700
@@ -0,0 +1,662 @@
+#*****************************************************************#
+#                                                                 #
+#   File: beatfactorygui.py                                       #
+#   Author: Ethan Takla                                           #
+#   Date Created: 10/6/14                                         #
+#   Description: A python GUI for graphically creating songs on   #
+#                the FDRM-KL46z                                       #
+#                                                                 #
+#*****************************************************************#
+# Last edit: Matthew Sessions
+
+#System Imports
+import sys
+
+#Serial Imports
+import serial
+from serial.tools import list_ports
+
+#Signal Imports
+import signal
+
+#Sound Imports
+
+# Uncomment for sound
+#import winsound
+
+#Threading imports
+import thread
+
+#PyQt Imports
+from PyQt4.QtGui import QApplication, QDialog, QMainWindow, QFileDialog
+from PyQt4 import QtCore, QtGui
+
+
+try:
+    _fromUtf8 = QtCore.QString.fromUtf8
+except AttributeError:
+    def _fromUtf8(s):
+        return s
+
+#Setup text encoding
+try:
+    _encoding = QtGui.QApplication.UnicodeUTF8
+    def _translate(context, text, disambig):
+        return QtGui.QApplication.translate(context, text, disambig, _encoding)
+except AttributeError:
+    def _translate(context, text, disambig):
+        return QtGui.QApplication.translate(context, text, disambig)
+
+#Create Note Classs
+class Note:
+    def __init__( self, note ):
+        self.note = note
+
+#Main Window Class
+class Ui_MainWindow(QtGui.QMainWindow):
+
+    def initializeUI(self, MainWindow):
+
+        #Initialize main window properties
+        MainWindow.setObjectName(_fromUtf8("FDRM-KL46z Beat Factory"))
+        MainWindow.resize(1200, 848)
+        MainWindow.setMaximumSize(QtCore.QSize(16777215, 848))
+
+        #Create central widget
+        self.centralwidget = QtGui.QWidget(MainWindow)
+        self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
+
+        #Create gridLayout_2
+        self.gridLayout_2 = QtGui.QGridLayout(self.centralwidget)
+        self.gridLayout_2.setObjectName(_fromUtf8("gridLayout_2"))
+
+        #Create and format a graphics view widget
+        self.graphicsView = QtGui.QGraphicsView(self.centralwidget)
+        self.graphicsView.setMinimumSize(QtCore.QSize(300, 120))
+        self.graphicsView.setMaximumSize(QtCore.QSize(300, 120))
+        self.graphicsView.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
+        self.graphicsView.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
+
+        #Set the graphics view image
+        self.scene = QtGui.QGraphicsScene();
+        self.pixmap = QtGui.QPixmap( "TekBots.png" )
+        self.scene.addPixmap(self.pixmap)
+        self.graphicsView.setScene( self.scene )
+        self.graphicsView.setObjectName(_fromUtf8("graphicsView"))
+
+        #Add the graphics view to gridLayout_2
+        self.gridLayout_2.addWidget(self.graphicsView, 0, 1, 1, 1)
+
+        #Create and format verticalLayout_2
+        self.verticalLayout_2 = QtGui.QVBoxLayout()
+        self.verticalLayout_2.setSpacing(7)
+        self.verticalLayout_2.setSizeConstraint(QtGui.QLayout.SetNoConstraint)
+        self.verticalLayout_2.setContentsMargins(-1, -1, -1, 0)
+        self.verticalLayout_2.setObjectName(_fromUtf8("verticalLayout_2"))
+
+        #Create a table view for beat editing
+        self.tableView = QtGui.QTableWidget(self.centralwidget)
+
+        #Add the table view to verticalLayout2
+        self.verticalLayout_2.addWidget(self.tableView)
+
+        #Add verticalLayout2 to gridLayout2
+        self.gridLayout_2.addLayout(self.verticalLayout_2, 0, 0, 7, 1)
+
+        #Create gridLayout
+        self.gridLayout = QtGui.QGridLayout()
+        self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
+
+        #Create and format pushButton, add them to gridLayout
+        self.pushButton = QtGui.QPushButton(self.centralwidget)
+        self.pushButton.setObjectName(_fromUtf8("pushButton"))
+        self.pushButton.setStyleSheet("color: black; background-color: red;")
+        self.gridLayout.addWidget(self.pushButton, 0, 2, 1, 1)
+        self.pushButton_2 = QtGui.QPushButton(self.centralwidget)
+        self.pushButton_2.setObjectName(_fromUtf8("pushButton_2"))
+        self.pushButton_2.setEnabled( False )
+        self.gridLayout.addWidget(self.pushButton_2, 3, 0, 1, 1)
+        self.pushButton_3 = QtGui.QPushButton(self.centralwidget)
+        self.pushButton_3.setObjectName(_fromUtf8("pushButton_3"))
+        self.pushButton_3.setEnabled( False )
+        self.gridLayout.addWidget(self.pushButton_3, 3, 1, 1, 1)
+
+        #Create labels and add them to gridLayout
+        self.label = QtGui.QLabel(self.centralwidget)
+        self.label.setObjectName(_fromUtf8("label"))
+        self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
+        self.label2 = QtGui.QLabel(self.centralwidget)
+        self.label2.setObjectName(_fromUtf8("label2"))
+        self.gridLayout.addWidget(self.label2, 1, 0, 1, 1)
+        self.label3 = QtGui.QLabel(self.centralwidget)
+        self.label3.setObjectName(_fromUtf8("label3"))
+        self.gridLayout.addWidget(self.label3, 2, 0, 1, 1)
+
+        #Create comboBoxs and add them to gridLayout
+        self.comboBox = QtGui.QComboBox(self.centralwidget)
+        self.comboBox.setObjectName(_fromUtf8("comboBox"))
+        self.gridLayout.addWidget(self.comboBox, 0, 1, 1, 1)
+        self.comboBox2 = QtGui.QComboBox(self.centralwidget)
+        self.comboBox2.setObjectName(_fromUtf8("comboBox2"))
+        self.gridLayout.addWidget(self.comboBox2, 1, 1, 1, 1)
+        self.comboBox3 = QtGui.QComboBox(self.centralwidget)
+        self.comboBox3.setObjectName(_fromUtf8("comboBox3"))
+        self.gridLayout.addWidget(self.comboBox3, 2, 1, 1, 1)
+        
+        #Add gridLayout to gridLayout_2 and format
+        self.gridLayout_2.addLayout(self.gridLayout, 1, 1, 1, 1)
+        MainWindow.setCentralWidget(self.centralwidget)
+
+        #Create and configure the menu bar
+        self.menubar = QtGui.QMenuBar(MainWindow)
+        self.menubar.setGeometry(QtCore.QRect(0, 0, 972, 26))
+        self.menubar.setObjectName(_fromUtf8("menubar"))
+        self.menuFile = QtGui.QMenu(self.menubar)
+        self.menuFile.setObjectName(_fromUtf8("menuFile"))
+        self.menuHelp = QtGui.QMenu(self.menubar)
+        self.menuHelp.setObjectName(_fromUtf8("menuHelp"))
+        MainWindow.setMenuBar(self.menubar)
+        self.statusbar = QtGui.QStatusBar(MainWindow)
+        self.statusbar.setObjectName(_fromUtf8("statusbar"))
+        MainWindow.setStatusBar(self.statusbar)
+
+        #Create a QAction for the Load and Save songs, and About button
+        self.actionLoad_Song = QtGui.QAction(MainWindow)
+        self.actionLoad_Song.setObjectName(_fromUtf8("actionLoad_Song"))
+        self.actionSave_Song = QtGui.QAction(MainWindow)
+        self.actionSave_Song.setObjectName(_fromUtf8("actionSave_Song"))
+        self.actionAbout = QtGui.QAction(MainWindow)
+        self.actionAbout.setObjectName(_fromUtf8("actionAbout"))
+        self.menuFile.addAction(self.actionLoad_Song)
+        self.menuFile.addAction(self.actionSave_Song)
+        self.menuHelp.addAction(self.actionAbout)
+        self.menubar.addAction(self.menuFile.menuAction())
+        self.menubar.addAction(self.menuHelp.menuAction())
+
+        #Set text of all UI elements
+        self.retranslateUI(MainWindow)
+
+        #Connect Slots
+        QtCore.QMetaObject.connectSlotsByName(MainWindow)
+
+        #Populate comboBox3 and configure tempo
+        self.comboBox3.clear()
+        self.comboBox3.addItems(self.tempoValues)
+        self.comboBox3.setCurrentIndex( 14 )
+        self.tempo = 120
+
+        #Populate Combobox 2
+        self.comboBox2.clear()
+        self.comboBox2.addItems(self.noteNumberValues)
+
+    def retranslateUI(self, MainWindow):
+
+        #Set the text of the UI elements
+        MainWindow.setWindowTitle(_translate("FDRM-KL46z Beat Factory", "FDRM-KL46z Beat Factory", None))
+        self.pushButton.setText(_translate("FDRM-KL46z Beat Factory", "Scan", None))
+        self.pushButton_2.setText(_translate("FDRM-KL46z Beat Factory", "Play", None))
+        self.pushButton_3.setText(_translate("FDRM-KL46z Beat Factory", "Clear", None))
+        self.label.setText(_translate("FDRM-KL46z Beat Factory", "COM Port:", None))
+        self.label2.setText(_translate("FDRM-KL46z Beat Factory", "Number of Notes:", None))
+        self.label3.setText(_translate("FDRM-KL46z Beat Factory", "Tempo:", None))
+        self.menuFile.setTitle(_translate("FDRM-KL46z Beat Factory", "File", None))
+        self.menuHelp.setTitle(_translate("FDRM-KL46z Beat Factory", "Help", None))
+        self.actionLoad_Song.setText(_translate("FDRM-KL46z Beat Factory", "Load Song", None))
+        self.actionSave_Song.setText(_translate("FDRM-KL46z Beat Factory", "Save Song", None))
+        self.actionAbout.setText(_translate("FDRM-KL46z Beat Factory", "About", None))
+
+    def initializeVariables( self ):
+
+        #Define cell selected/unselected variables
+        self.cellSelected = 1
+        self.cellUnselected = 0
+
+        #Set initial comm. state
+        self.comButtonState = "Scan"
+
+        #Create the song array
+        self.song_array = []    # delete all note elements
+                
+        #Set table row and column count variables
+        self.tableViewRowCount = 24
+        self.tableViewColumnCount = 16
+        self.selectedCells = [[0 for x in xrange(self.tableViewColumnCount)] for x in xrange(self.tableViewRowCount)]
+        self.noteFrequencies = [ 831, 784, 740, 698, 659, 622, 587, 554, 523, 494, 466, 440, 415, 392, 370, 349, 330, 311, 294, 277, 261, 247, 233, 220 ]
+
+        #Define tempo values
+        self.tempoValues = [ "50", "55", "60", "65", "70", "75", "80", "85", "90", "95", "100", "105", "110", "115", "120", "125", "130",
+                             "135", "140", "145", "150", "155", "160", "165", "170", "175", "180", "185", "190", "195", "200", "205",
+                             "210", "215", "220", "225", "230", "235", "240"]
+
+        #Define note number values
+        self.noteNumberValues = [ "16", "32", "48", "64" ]
+
+        #Define serial ports that are to be 'detected' 
+        self.ports = [ "Select",
+                       'COM1', 'COM2', 'COM3', 'COM4', 'COM5', 'COM6', 'COM7', 'COM8', 'COM9', 'COM10',
+                       'COM11', 'COM12', 'COM13', 'COM14', 'COM15', 'COM16', 'COM17', 'COM18',
+                       'COM19', 'COM20', 'COM21', '/dev/ttyACM0', '/dev/ttyACM1', '/dev/ttyACM2', '/dev/ttyACM3']
+        
+
+        
+    def initializeTable( self ):
+        
+        #Initialize beat table columns and rows
+        self.tableView.setColumnCount(self.tableViewColumnCount)
+        self.tableView.setRowCount(self.tableViewRowCount)
+
+        #Initialize beat table rows for notes
+        self.verticalHeaderLabels = [ "G#", "G", "F#", "F", "E", "D#", "D", "C#", "C(High)", "B", "A#", "A", "G#", "G", "F#", "F", "E", "D#", "D", "C#", "C (Middle)", "B", "A#", "A" ]
+
+        #Label vertical headers on table
+        self.tableView.setVerticalHeaderLabels( self.verticalHeaderLabels )
+        
+        #Make table ready only by creating items widgets in each cell and disabling them
+        for i in xrange(self.tableView.rowCount()):
+            for j in xrange(self.tableView.columnCount()):  
+                self.tableView.setItem(i,j, QtGui.QTableWidgetItem())
+                self.tableView.item(i,j).setFlags(QtCore.Qt.ItemIsEnabled)
+        
+    def initializeSerial( self ):
+
+        #Configure the serial port for 8-N-1, baudrate doesn't matter since the FDRM-KL46z is running a VCP
+        self.ser = serial.Serial()
+        self.ser.timeout = 1000
+        self.ser.baudrate = 9600
+        
+    def highlightColumn( self, column ):
+        
+        #Go through the unselected cells in each row and highlight them
+        for i in xrange(self.tableView.rowCount()):
+            if self.selectedCells[i][column] == self.cellUnselected:
+                self.tableView.item(i, column).setBackground(QtGui.QColor(255,179,0))
+                
+    def unhighlightColumn( self, column ):
+
+        #Go through the unselected cells in each row and unhighlight them
+        for i in xrange(self.tableView.rowCount()):
+            if self.selectedCells[i][column] == self.cellUnselected:
+                self.tableView.item(i, column).setBackground(QtGui.QColor(255,255,255))
+                
+    def handlePlayButton( self ):
+
+        #Disable play and clear buttons while song is playing
+        self.pushButton_2.setEnabled( False )
+        self.pushButton_3.setEnabled( False )
+
+        #Empty song array
+        del self.song_array[:]
+        emptyCells = 0
+
+        
+        for j in xrange(self.tableView.columnCount()):
+            for i in xrange(self.tableView.rowCount()):
+
+                #If a cell is selected, add the corresponding note to the song array
+                if self.selectedCells[i][j] == self.cellSelected:
+                    
+                    #Store the note index
+                    note_name = i # note name is letter A-G 
+            
+                    # create Note class and populate
+                    note = Note( note_name )
+                    self.song_array.append( note )                  # add Note to array of Notes        
+                else:
+                    emptyCells += 1
+
+                #If an empty column is found, add a rest (index 24) to the song array
+                if emptyCells == self.tableView.rowCount():
+                    
+                    # store user-inputted note into a Note class
+                    note_name = 24 # note name is letter A-G 
+            
+                    # create Note class and populate
+                    note = Note( note_name )
+                    self.song_array.append( note )                  # add Note to array of Notes
+
+            emptyCells = 0
+                
+        
+        try:
+            self.ser.open()
+        except:
+            self.serialScan()
+            return
+        self.ser.write( "$NEW\n" )                                  #Send new song packet
+        self.ser.write( "$T" )                                      #Send Tempo Packet
+        self.ser.write( "%d" % (self.tempo*4) )       
+        self.ser.write( '\n' )                          
+        self.ser.write( "$L" )                                      #Send song length packet
+        self.ser.write( "%d" % (self.tableView.columnCount() ) )   
+        self.ser.write( '\n' )                    
+        for i in range(self.tableView.columnCount()):               
+            self.ser.write( "$S" )                                  #Send note data packet
+            self.ser.write( "%d" % (self.song_array[i].note) )
+            self.ser.write( '\n' )                  
+        self.ser.write( "$PLAY\n" )                                 #Send play song packet
+        
+        data = 0
+        
+        while 1:
+
+            #Wait for serial data to be available
+            if self.ser.inWaiting() != 0:
+
+                #Read a line of data
+                data = int(self.ser.readline())
+
+                #Exit the while loop if a termination character (0xFF) is received
+                if data == 255:
+                    break;
+
+                #Highlight the column specified by the data
+                self.highlightColumn( data )
+
+                #Scroll to the column so we can see it
+                self.tableView.scrollToItem( self.tableView.item(0,data) )
+
+                #Unhighlight previous column
+                if data > 0:
+                    self.unhighlightColumn( data - 1 )
+
+                #Force a GUI uptdate
+                QApplication.processEvents()
+                
+        self.unhighlightColumn( self.tableView.columnCount()-1 )
+        self.ser.close()
+
+        #Enable play and clear buttons after song is song playing
+        self.pushButton_2.setEnabled( True )
+        self.pushButton_3.setEnabled( True )
+                
+    def handleClearButton( self ):
+
+        #Go through each cell, make it white, and set it as unselected
+        for i in xrange(self.tableView.rowCount()):
+            for j in xrange(self.tableView.columnCount()):  
+                self.tableView.item(i, j).setBackground(QtGui.QColor(255,255,255))
+                self.selectedCells[i][j] = self.cellUnselected
+
+    def serialScan( self ):
+
+        #Populate the combobox with ports
+        self.comboBox.clear()
+        self.comboBox.addItems( self.ports )
+
+        #Go through each port name to see if it exists
+        for i in self.ports[1:]:
+            self.ser.port = i
+            try:
+                self.ser.open()
+            except Exception, e:
+
+                #If the port name does not exist, remove it from the combobox
+                remove_port = self.comboBox.findText( self.ser.port )
+                self.comboBox.removeItem( remove_port )
+            self.ser.close()
+
+    def handleComButton( self ):
+
+        #If the comm. button is is Scan mode, scan the serial ports
+        if self.comButtonState == "Scan":
+
+            self.serialScan()
+
+            if self.comboBox.count() > 1:
+
+                #If we have detected a serial port, change the button name to "connect" and change color
+                self.pushButton.setText(_translate("MainWindow", "Connect", None))
+                self.pushButton.setStyleSheet("color: black; background-color: yellow;")
+                self.comButtonState = "Connect"
+
+                #Enable the play and clear buttons
+                self.pushButton_2.setEnabled( True )
+                self.pushButton_3.setEnabled( True )
+            else:
+
+                #Create a message box if there was no COM port detected
+                QtGui.QMessageBox.information(self, 'Error',"A serial device was not detected, please ensure that it is plugged into your computer.")
+                
+        elif self.comButtonState == "Connect":
+
+            #Create a new port
+            self.ser.close()
+            new_port = str(self.comboBox.currentText())
+            self.ser.port = new_port
+            
+            try:
+                if self.comboBox.currentText() != "Select":
+                    self.ser.open()
+                else:
+                    QtGui.QMessageBox.information(self, 'Error',"Please Select a COM port.")
+                    
+            except Exception ,e:
+
+                #If we can't connect, reset the button state to "scan"
+                self.pushButton.setText(_translate("MainWindow", "Disconnect", None))
+                self.pushButton.setStyleSheet("color: black; background-color: red;")
+                self.comButtonState = "Scan"
+            if self.ser.isOpen():
+
+                #If we can open the serial port, change the button name to "disconnect" and change color
+                self.pushButton.setText(_translate("MainWindow", "Disconnect", None))
+                self.pushButton.setStyleSheet("color: black; background-color: green;")
+                self.comButtonState = "Disconnect"
+                self.ser.close()
+                
+        elif self.comButtonState == "Disconnect":
+
+            #Change the button text to "Scan" once disconnect it pressed, and change color
+            self.pushButton.setText(_translate("MainWindow", "Scan", None))
+            self.pushButton.setStyleSheet("color: black; background-color: red;")
+            self.comButtonState = "Scan"
+
+            #Disable play and clear buttons
+            self.pushButton_2.setEnabled( False )
+            self.pushButton_3.setEnabled( False )
+
+    def beepThread( self, tone ):
+            print "No sound"
+            #Produce a tone using winsound
+            
+            # Uncomment below for sound
+            #winsound.Beep(tone, 150)
+            
+    def handleCellClicked(self, row, column):
+
+        self.noteExists = False
+
+        #Check to see if any notes are already selected in the row
+        for i in xrange(self.tableView.rowCount()):
+            if self.selectedCells[i][column] == self.cellSelected:
+                self.noteExists = True
+                
+            
+        #If a cell is clicked and unselected, change it's color, mark it as selected, and start the tone thread
+        if self.selectedCells[row][column] == self.cellUnselected:
+
+            #Do not select cell if a note already exists in the column
+            if self.noteExists == False:
+                
+                self.tableView.item(row, column).setBackground(QtGui.QColor(100,100,150))
+                self.selectedCells[row][column] = self.cellSelected
+                thread.start_new_thread(self.beepThread, (self.noteFrequencies[row],))
+
+        #If a cell is clicked and selected, change it's color and mark it as unselected
+        else:
+            self.tableView.item(row, column).setBackground(QtGui.QColor(255,255,255))
+            self.selectedCells[row][column] = self.cellUnselected
+
+    def handleSaveSongButton( self ):
+
+        #Create a save file dialog
+        self.fileName = QFileDialog.getSaveFileName(self,"Save File",
+                            "",
+                            "FDRM-KL46z Song (*.song)");
+        try:
+            #Create a file with the filename provided from the user
+            self.f = open(self.fileName, 'w')
+
+            #Write the note number index
+            self.f.write( str(self.comboBox2.currentIndex()) + '\n' )
+    
+            #Write each note as a coordinate on a newline
+            for i in xrange(self.tableView.rowCount()):
+                for j in xrange(self.tableView.columnCount()):  
+                    if self.selectedCells[i][j] == self.cellSelected:
+                        self.f.write( str(i)+ ',' + str(j) + '\n')
+
+            #Write the end of song marker
+            self.f.write( "end song")
+            self.f.close()
+
+        except Exception ,e:
+            print(e)
+            
+    def handleLoadSongButton( self ):
+
+        #Create and open file dialog
+        self.fileName = QFileDialog.getOpenFileName(self,"Open File",
+                            "",
+                            "FDRM-KL46z Song (*.song)");
+
+        try:
+            #Open the user defined file for reading
+            self.f = open(self.fileName, 'r')
+
+            #cleat all notes from tableview
+            self.handleClearButton();
+
+            #Read index number and change the note number combo box
+            index = int(self.f.readline())
+            self.handleNoteNumberChange(index)
+            self.comboBox2.setCurrentIndex(index)
+
+            #Read the first cell location
+            self.cellID = self.f.readline()
+
+            #Continue reading cell ID's and activate corresponding cells
+            while self.cellID != "end song":
+                i = 0
+                columnString = ""
+                rowString = ""
+
+                #Wait until we get a comma
+                while self.cellID[i] != ',':
+                    rowString += self.cellID[i]
+                    i += 1
+
+                #Go to the next data point after a newline character
+                while self.cellID[i+1] != '\n':
+                    columnString += self.cellID[i+1]
+                    i += 1
+
+                #Update the table view
+                self.tableView.item(int(rowString), int(columnString)).setBackground(QtGui.QColor(100,100,150))
+                self.selectedCells[int(rowString)][int(columnString)] = self.cellSelected
+                self.cellID = self.f.readline()
+        except Exception ,e:
+            print(e)
+
+    def handleNoteNumberChange( self, index ):
+
+        #Change the number of columns in the table if the song length changes 
+        self.tableViewColumnCount = int(self.noteNumberValues[int(index)])
+        self.selectedCells = [[0 for x in xrange(self.tableViewColumnCount)] for x in xrange(self.tableViewRowCount)]
+
+        #Reset the table
+        self.initializeTable()
+        self.handleClearButton()
+
+    def handleTempoChange( self, index ):
+
+        #Change necesarry variables if the tempo is chaged
+        self.tempo = int(self.tempoValues[int(index)])
+
+    def handleAboutButton( self ):
+
+        #Opens the about form if the about button is pressed
+        self.dialog = QtGui.QDialog(self)
+        self.dialog.ui = aboutForm()
+        self.dialog.ui.setupUi(self.dialog)
+        self.dialog.setAttribute(QtCore.Qt.WA_DeleteOnClose)
+        self.dialog.show()
+        
+        
+    def bind_events( self ):
+        #Bind events to handler functions      
+        self.pushButton.clicked.connect( self.handleComButton )                         
+        self.tableView.cellClicked.connect( self.handleCellClicked )
+        self.pushButton_3.clicked.connect( self.handleClearButton )
+        self.actionSave_Song.triggered.connect( self.handleSaveSongButton )
+        self.actionLoad_Song.triggered.connect( self.handleLoadSongButton )
+        self.pushButton_2.clicked.connect( self.handlePlayButton )
+        self.comboBox2.currentIndexChanged.connect( self.handleNoteNumberChange )
+        self.comboBox3.currentIndexChanged.connect( self.handleTempoChange )
+        self.actionAbout.triggered.connect( self.handleAboutButton )
+        
+class aboutForm(object):
+        
+    def setupUi(self, Form):
+
+        #Configure the form
+        Form.setObjectName(_fromUtf8("Form"))
+        Form.resize(381, 233)
+        Form.setMinimumSize(QtCore.QSize(381, 233))
+        Form.setMaximumSize(QtCore.QSize(381, 233))
+
+        #Create label
+        self.label = QtGui.QLabel(Form)
+        self.label.setGeometry(QtCore.QRect(140, 160, 121, 16))
+        self.label.setObjectName(_fromUtf8("label"))
+
+        #Create label_2
+        self.label_2 = QtGui.QLabel(Form)
+        self.label_2.setGeometry(QtCore.QRect(140, 180, 121, 16))
+        self.label_2.setObjectName(_fromUtf8("label_2"))
+
+        #Create label_3
+        self.label_3 = QtGui.QLabel(Form)
+        self.label_3.setGeometry(QtCore.QRect(160, 200, 121, 16))
+        self.label_3.setObjectName(_fromUtf8("label_3"))
+
+        #Create a graphics view
+        self.graphicsView = QtGui.QGraphicsView(Form)
+        self.graphicsView.setGeometry(QtCore.QRect(40, 20, 300, 120))
+        self.graphicsView.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
+        self.graphicsView.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
+        self.graphicsView.setObjectName(_fromUtf8("graphicsView"))
+
+        #Set the graphics view image
+        self.scene = QtGui.QGraphicsScene();
+        self.pixmap = QtGui.QPixmap( "TekBots.png" )
+        self.scene.addPixmap(self.pixmap)
+        self.graphicsView.setScene( self.scene )
+        self.graphicsView.setObjectName(_fromUtf8("graphicsView"))
+
+        #Set text of all UI elements
+        self.retranslateUi(Form)
+
+        #Connect Slots
+        QtCore.QMetaObject.connectSlotsByName(Form)
+
+    def retranslateUi(self, Form):
+
+        #Set text of all UI elements
+        Form.setWindowTitle(_translate("About", "About", None))
+        self.label.setText(_translate("About", "FDRM-KL46z Beat Factory", None))
+        self.label_2.setText(_translate("About", "Author: Ethan Takla", None))
+        self.label_3.setText(_translate("About", "Revision 0.1", None))
+        
+#Start the app        
+app = QApplication(sys.argv)
+window = QMainWindow()
+ui = Ui_MainWindow()
+ui.initializeVariables()
+ui.initializeUI(window)
+ui.initializeTable()
+ui.initializeSerial()
+ui.bind_events()
+
+window.show()
+sys.exit(app.exec_())