示例#1
0
    def setUpWidgets(self):

        self.formantPlotFrame = Frame(self.parent,
                                      width=FORMANTPLOTFRAMEWIDTH,
                                      height=FORMANTPLOTFRAMEHEIGHT)
        self.formantPlotFrame.grid()

        self.formantPlotCanvas = SnackCanvas(self.formantPlotFrame,
                                             height=FORMANTPLOTHEIGHT,
                                             width=FORMANTPLOTWIDTH,
                                             bg='white')
        self.formantPlotCanvas.grid(row=0, column=0)

        self.loudnessMeterCanvas = SnackCanvas(self.formantPlotFrame,
                                               height=FORMANTPLOTHEIGHT,
                                               width=10)
        self.loudnessMeterCanvas.grid(row=0, column=1)

        self.formantPlotControlFrame = Frame(self.formantPlotFrame)
        self.formantPlotControlFrame.grid(row=1,
                                          column=0,
                                          sticky='w' + 'e',
                                          columnspan=2)

        self.formantPlotControlFrame.columnconfigure(0,
                                                     minsize=FORMANTPLOTWIDTH /
                                                     3)
        self.formantPlotControlFrame.columnconfigure(1,
                                                     minsize=FORMANTPLOTWIDTH /
                                                     3)
        self.formantPlotControlFrame.columnconfigure(2,
                                                     minsize=FORMANTPLOTWIDTH /
                                                     3)

        self.recButton = ttk.Button(self.formantPlotControlFrame,
                                    text='Record',
                                    command=self.record,
                                    style='Fun.TButton')
        self.recButton.grid(row=1, column=0, sticky='w' + 'e', padx=10)
        self.stopButton = ttk.Button(self.formantPlotControlFrame,
                                     text='Stop',
                                     command=self.stop,
                                     state='disabled',
                                     style='Fun.TButton')
        self.stopButton.grid(row=1, column=1, sticky='w' + 'e', padx=10)

        self.clearScreenButton = ttk.Button(self.formantPlotControlFrame,
                                            text='Clear Plot',
                                            command=self.clearUserFormants,
                                            state='normal',
                                            style='Fun.TButton')
        self.clearScreenButton.grid(row=1,
                                    column=2,
                                    sticky='w' + 'e' + 'n' + 's')

        self.loudnessMeter = LoudnessMeter(self.loudnessMeterCanvas)
示例#2
0
    def setupPlot(self):
        #Plot
        self.vowelPlotFrame = self.parent
        self.vowelPlotCanvas = Canvas(self.vowelPlotFrame,
                                      height=self.width,
                                      width=self.height,
                                      bg='white')
        self.vowelPlotCanvas.delete('Loudness')
        self.vowelPlotCanvas.delete('toLoud')
        self.vowelPlotCanvas.delete('toQuiet')
        self.vowelPlotCanvas.pack(fill='both', expand=1)

        #Creates the loudnessMeter on the formant plot canvas.
        self.loudnessMeter = LoudnessMeter(self.vowelPlotCanvas, YSHIFT)
        font = ('Arial', '14')
        boxWidth = 150
        self.font = font
        x1 = (self.height / 2) - (boxWidth)
        y1 = 2
        x2 = (self.height / 2)
        y2 = 32
        self.recordingBox = self.vowelPlotCanvas.create_rectangle(
            x1, y1, x2, y2, tag='recording', fill='red', outline='white')
        self.recordingBoxText = self.vowelPlotCanvas.create_text(
            (x1 + x2) / 2, (y1 + y2) / 2,
            tag='recordingText',
            text='Recording.',
            font=font,
            fill='black')
        self.vowelPlotCanvas.itemconfig('recording', state='hidden')
        self.vowelPlotCanvas.itemconfig('recordingText', state='hidden')

        x1 = (self.height / 2)
        y1 = 2
        x2 = (self.height / 2) + boxWidth
        y2 = 32
        self.recordingBox = self.vowelPlotCanvas.create_rectangle(
            x1, y1, x2, y2, tag='Loudness', outline='black')
        self.recordingBoxText = self.vowelPlotCanvas.create_text(
            (x1 + x2) / 2, (y1 + y2) / 2,
            tag='toLoud',
            text='Too Loud.',
            font=font,
            fill='black')
        self.recordingBoxText = self.vowelPlotCanvas.create_text(
            (x1 + x2) / 2, (y1 + y2) / 2,
            tag='toQuiet',
            text='Too Quiet.',
            font=font,
            fill='black')

        self.vowelPlotCanvas.itemconfig('Loudness', state='hidden')
        self.vowelPlotCanvas.itemconfig('toLoud', state='hidden')
        self.vowelPlotCanvas.itemconfig('toQuiet', state='hidden')
示例#3
0
    def setupPlot(self):
        #Plot
        self.formantPlotFrame = self.parent
        # self.formantPlotCanvas = Canvas(self.formantPlotFrame, height=PLOTHEIGHT-60, width=PLOTWIDTH, bg='white')
        self.formantPlotCanvas = Canvas(self.formantPlotFrame,
                                        height=PLOTHEIGHT,
                                        width=PLOTWIDTH,
                                        bg='white')

        #self.formantPlotCanvas.grid(row=0 ,column=0, sticky=N+S+E+W)
        self.formantPlotCanvas.pack(fill=BOTH, expand=YES)
        self.formantPlotCanvas.bind("<Button-1>", self.requestRecord)

        #Creates the loudnessMeter on the formant plot canvas.
        self.loudnessMeter = LoudnessMeter(self.formantPlotCanvas, YSHIFT)
        self.createBoxs()
示例#4
0
文件: FormantPlot.py 项目: MPAid/Main
        def setUpWidgets(self):

                self.formantPlotFrame = Frame(self.parent, width=FORMANTPLOTFRAMEWIDTH, height=FORMANTPLOTFRAMEHEIGHT)
                self.formantPlotFrame.grid()
                
		self.formantPlotCanvas = SnackCanvas(self.formantPlotFrame, height=FORMANTPLOTHEIGHT, width=FORMANTPLOTWIDTH, bg='white')
		self.formantPlotCanvas.grid(row=0,column=0)

		self.loudnessMeterCanvas = SnackCanvas(self.formantPlotFrame, height=FORMANTPLOTHEIGHT, width=FORMANTPLOTFRAMEWIDTH-FORMANTPLOTWIDTH, bg='white')
		self.loudnessMeterCanvas.grid(row=0,column=1)

		self.formantPlotControlFrame = Frame(self.formantPlotFrame)
		self.formantPlotControlFrame.grid(row=1,column=0,sticky='w'+'e',columnspan=2)

		self.formantPlotControlFrame.columnconfigure(0, minsize=FORMANTPLOTWIDTH/3)
		self.formantPlotControlFrame.columnconfigure(1, minsize=FORMANTPLOTWIDTH/3)
		self.formantPlotControlFrame.columnconfigure(2, minsize=FORMANTPLOTWIDTH/3)
		self.formantPlotControlFrame.columnconfigure(3, minsize=FORMANTPLOTFRAMEWIDTH-FORMANTPLOTWIDTH)

                self.isLabelsOn = BooleanVar()
                self.toggleLabelCheckbox = Checkbutton(self.formantPlotControlFrame,text='Show Labels',variable=self.isLabelsOn,onvalue=True,offvalue=False,state='active',command=(lambda:self.togglePlot(self.isLabelsOn.get(),'ellipseLabel')))
                self.toggleLabelCheckbox.grid(row=0,column=0)
                self.toggleLabelCheckbox.select()

                self.isEllipsesOn = BooleanVar()
                self.toggleEllipsesCheckbox = Checkbutton(self.formantPlotControlFrame,text='Show Ellipses',variable=self.isEllipsesOn,onvalue=True,offvalue=False,state='active',command=(lambda:self.togglePlot(self.isEllipsesOn.get(),'ellipses')))
                self.toggleEllipsesCheckbox.grid(row=0,column=1)
                self.toggleEllipsesCheckbox.select()

                self.isLoadedFormantsOn = BooleanVar()
                self.toggleLoadedFormantsCheckbox = Checkbutton(self.formantPlotControlFrame,text='Show Loaded Formants',variable=self.isLoadedFormantsOn,onvalue=True,offvalue=False,state='active',command=(lambda:self.togglePlot(self.isLoadedFormantsOn.get(),'loadedformants')))
                self.toggleLoadedFormantsCheckbox.grid(row=0,column=2)
                self.toggleLoadedFormantsCheckbox.select()

                self.recButton = ttk.Button(self.formantPlotControlFrame, text='Record', command=self.record,style='Fun.TButton')
		self.recButton.grid(row=1,column=0,sticky='w'+'e',padx=10)
		self.stopButton = ttk.Button(self.formantPlotControlFrame, text='Stop', command=self.stop,state='disabled',style='Fun.TButton')
		self.stopButton.grid(row=1,column=1,sticky='w'+'e',padx=10)
		self.playRecordButton = ttk.Button(self.formantPlotControlFrame, text='Play Last Recorded Sound', command=(lambda:(self.play(self.recordedAudio))),state='disabled',style='Fun.TButton')
		self.playRecordButton.grid(row=1,column=2,sticky='w'+'e',padx=10)
		

		self.loadAudioButton = ttk.Button(self.formantPlotControlFrame, text='Load Audio File', command=self.loadAudioFile,state='normal',style='Fun.TButton')
		self.loadAudioButton.grid(row=2,column=1,sticky='w'+'e',padx=10)
		self.saveButton = ttk.Button(self.formantPlotControlFrame, text='Save', command=self.save,state='disabled',style='Fun.TButton')
		self.saveButton.grid(row=2,column=0,sticky='w'+'e',padx=10)
		self.playLoadButton = ttk.Button(self.formantPlotControlFrame, text='Play Loaded File', command=(lambda:(self.play(self.loadedAudio))),state='disabled',style='Fun.TButton')
		self.playLoadButton.grid(row=2,column=2,sticky='w'+'e',padx=10)

		self.clearScreenButton = ttk.Button(self.formantPlotControlFrame, text='Clear Plot', command=self.clearUserFormants,state='normal',style='Fun.TButton')
		self.clearScreenButton.grid(row=1,column=3,sticky='w'+'e'+'n'+'s', rowspan=2)

		self.loudnessMeter = LoudnessMeter(self.loudnessMeterCanvas)
示例#5
0
    def setUpWidgets(self):

        self.formantPlotFrame = Frame(self.parent, width=FORMANTPLOTFRAMEWIDTH, height=FORMANTPLOTFRAMEHEIGHT)
        self.formantPlotFrame.grid()

        self.formantPlotCanvas = SnackCanvas(
            self.formantPlotFrame, height=FORMANTPLOTHEIGHT, width=FORMANTPLOTWIDTH, bg="white"
        )
        self.formantPlotCanvas.grid(row=0, column=0)

        self.loudnessMeterCanvas = SnackCanvas(self.formantPlotFrame, height=FORMANTPLOTHEIGHT, width=10)
        self.loudnessMeterCanvas.grid(row=0, column=1)

        self.formantPlotControlFrame = Frame(self.formantPlotFrame)
        self.formantPlotControlFrame.grid(row=1, column=0, sticky="w" + "e", columnspan=2)

        self.formantPlotControlFrame.columnconfigure(0, minsize=FORMANTPLOTWIDTH / 3)
        self.formantPlotControlFrame.columnconfigure(1, minsize=FORMANTPLOTWIDTH / 3)
        self.formantPlotControlFrame.columnconfigure(2, minsize=FORMANTPLOTWIDTH / 3)

        self.recButton = ttk.Button(
            self.formantPlotControlFrame, text="Record", command=self.record, style="Fun.TButton"
        )
        self.recButton.grid(row=1, column=0, sticky="w" + "e", padx=10)
        self.stopButton = ttk.Button(
            self.formantPlotControlFrame, text="Stop", command=self.stop, state="disabled", style="Fun.TButton"
        )
        self.stopButton.grid(row=1, column=1, sticky="w" + "e", padx=10)

        self.clearScreenButton = ttk.Button(
            self.formantPlotControlFrame,
            text="Clear Plot",
            command=self.clearUserFormants,
            state="normal",
            style="Fun.TButton",
        )
        self.clearScreenButton.grid(row=1, column=2, sticky="w" + "e" + "n" + "s")

        self.loudnessMeter = LoudnessMeter(self.loudnessMeterCanvas)
示例#6
0
class FormantPlot:
    def __init__(self, parent, path, root, plotID, formApp):

        self.plotHeight = PLOTHEIGHT
        self.plotWidth = PLOTWIDTH

        self.root = root
        self.formApp = formApp
        self.vowelType = formApp.vowelType

        self.parent = parent
        self.path = path
        self.id = plotID
        self.buttonCounter = 0

        if plotID == 0 or plotID == 1:
            self.gender = "male"
        else:
            self.gender = "female"

        self.hasFormants = False

        #plot Setup:
        self.updateRate = 30
        self.setupPlot()

        self.drawGoldStandardMonophthongs(True)

        self.createKey()
        self.createAxis()

        self.prevX = 0
        self.prevY = 0

        # sound Setup:
        self.initialiseSounds()
        self.formantRadius = 2
        self.formantColour = 'black'
        self.isRecording = False
        self.lineHiddens = False

        self.loadedPlots = False
        self.hasloadedPlots = False

        self.backgroundNoiseDistance = 50
        self.count = 0

        self.notStopped = False

    def setupPlot(self):
        #Plot
        self.formantPlotFrame = self.parent
        # self.formantPlotCanvas = Canvas(self.formantPlotFrame, height=PLOTHEIGHT-60, width=PLOTWIDTH, bg='white')
        self.formantPlotCanvas = Canvas(self.formantPlotFrame,
                                        height=PLOTHEIGHT,
                                        width=PLOTWIDTH,
                                        bg='white')

        #self.formantPlotCanvas.grid(row=0 ,column=0, sticky=N+S+E+W)
        self.formantPlotCanvas.pack(fill=BOTH, expand=YES)
        self.formantPlotCanvas.bind("<Button-1>", self.requestRecord)

        #Creates the loudnessMeter on the formant plot canvas.
        self.loudnessMeter = LoudnessMeter(self.formantPlotCanvas, YSHIFT)
        self.createBoxs()

    def createButtons(self):
        self.buttonCounter += 1
        self.formantPlotCanvas.delete('buttons')
        height = (int)((float)(2) * (self.plotHeight / PLOTHEIGHT))
        font = ('Arial', '12')

        self.formantPlotCanvas.create_rectangle(0,
                                                self.plotHeight - height * 30 -
                                                8,
                                                self.plotWidth + 10,
                                                self.plotHeight + 10,
                                                tags='buttons',
                                                fill='#d3d3d3')

        text = "  Back to Menu  "
        helpButton = Button(self.parent,
                            text=text,
                            command=self.goBackToMenu,
                            font=font)
        helpButton.configure(height=height,
                             activebackground='green',
                             anchor=W,
                             relief=GROOVE)
        helpButtonWindow = self.formantPlotCanvas.create_window(
            2,
            self.plotHeight - 4 * (self.plotHeight / PLOTHEIGHT),
            anchor=SW,
            tags=('backButton', 'buttons'),
            window=helpButton)

        text = text = 14 * " " + "Record" + 14 * " "
        self.recordButton = Button(self.parent,
                                   text=text,
                                   font=font,
                                   command=self.requestRecord)
        self.recordButton.configure(height=height,
                                    activebackground='green',
                                    anchor=W,
                                    relief=GROOVE,
                                    bd=3)
        self.formantPlotCanvas.create_window(
            (self.plotWidth / 2),
            self.plotHeight - 4 * (self.plotHeight / PLOTHEIGHT) - 25,
            anchor=CENTER,
            tags=('recordButton', 'buttons'),
            window=self.recordButton)

        if self.buttonCounter > 2 and self.formantPlotCanvas.winfo_height(
        ) <= 580:
            self.formantPlotCanvas.delete("recordButton")
            self.formantPlotCanvas.create_window(
                (self.plotWidth / 2),
                self.plotHeight - 4 * (self.plotHeight / PLOTHEIGHT) - 15,
                anchor=CENTER,
                tags=('recordButton', 'buttons'),
                window=self.recordButton)
        if self.vowelType == 'short':
            text = " Short Vowels "
        else:

            text = ' Long Vowels '

        self.vowelButton = Button(self.parent,
                                  text=text,
                                  font=font,
                                  command=self.toggleVowelType)
        self.vowelButton.configure(height=height,
                                   activebackground='green',
                                   anchor=W,
                                   relief=GROOVE,
                                   bd='3')
        self.formantPlotCanvas.create_window(self.plotWidth,
                                             self.plotHeight - 4 *
                                             (self.plotHeight / PLOTHEIGHT),
                                             anchor=SE,
                                             tags=('vowelButton', 'buttons'),
                                             window=self.vowelButton)

        self.formantPlotCanvas.itemconfig('buttons', state='normal')

    def goBackToMenu(self):
        self.formApp.backToMenu()

    def toggleVowelType(self, *event):
        if self.isRecording == False:

            self.formApp.toggleVowelType()

    def loadHelp(self):
        pass

    def createBoxs(self):
        self.formantPlotCanvas.delete('boxes')
        boxWidth = 150
        font = ('Arial', '15')

        x1 = (PLOTWIDTH / 2) * (self.plotWidth / PLOTWIDTH) - (boxWidth)
        y1 = 2
        x2 = (PLOTWIDTH / 2) * (self.plotWidth / PLOTWIDTH)
        y2 = 32

        self.recordingBox = self.formantPlotCanvas.create_rectangle(
            x1,
            y1,
            x2,
            y2,
            tag=('boxes', 'Recording'),
            fill='orange',
            outline='black')
        self.recordingBoxText = self.formantPlotCanvas.create_text(
            (x1 + x2) / 2, (y1 + y2) / 2,
            tag=('boxes', 'recordingText'),
            text='Loading...',
            font=font,
            fill='black')
        self.formantPlotCanvas.itemconfig('Recording', state='hidden')
        self.formantPlotCanvas.itemconfig('recordingText', state='hidden')

        x1 = (PLOTWIDTH / 2) * (self.plotWidth / PLOTWIDTH)
        y1 = 2
        x2 = (PLOTWIDTH / 2) * (self.plotWidth / PLOTWIDTH) + boxWidth
        y2 = 32
        self.recordingBox = self.formantPlotCanvas.create_rectangle(
            x1, y1, x2, y2, tag=('boxes', 'Loudness'), outline='black')
        self.recordingBoxText = self.formantPlotCanvas.create_text(
            (x1 + x2) / 2, (y1 + y2) / 2,
            tag=('boxes', 'toLoud'),
            text='Too Loud.',
            font=font,
            fill='black')
        self.recordingBoxText = self.formantPlotCanvas.create_text(
            (x1 + x2) / 2, (y1 + y2) / 2,
            tag=('boxes', 'toQuiet'),
            text='Too Quiet.',
            font=font,
            fill='black')
        self.formantPlotCanvas.itemconfig('toLoud', state='hidden')
        self.formantPlotCanvas.itemconfig('toQuiet', state='hidden')
        self.formantPlotCanvas.itemconfig('Loudness', state='hidden')

    def resize(self, width, height):
        print self.formantPlotCanvas.winfo_height()
        print self.formantPlotCanvas.winfo_width()

        self.plotWidth = (float)(width)
        self.plotHeight = (float)(height)
        self.drawGoldStandardMonophthongs(True)
        self.redrawPlotInfo()
        self.createBoxs()
        self.createButtons()

    def createKey(self, ):
        self.formantPlotCanvas.delete("legend")
        font = ('Arial', '13')
        radius = 4
        x = self.plotWidth - 160
        y = 15
        self.formantPlotCanvas.create_text(x + 80,
                                           y,
                                           text="Key:",
                                           tag='legend',
                                           font=font)
        self.formantPlotCanvas.create_oval(x - radius,
                                           y + 20 - radius,
                                           x + radius,
                                           y + 20 + radius,
                                           tag='legend',
                                           fill='black')
        self.formantPlotCanvas.create_text(x + 80,
                                           y + 20,
                                           text='Recorded Vowels',
                                           tag='legend',
                                           font=font)
        self.formantPlotCanvas.create_oval(x - radius,
                                           y + 40 - radius,
                                           x + radius,
                                           y + 40 + radius,
                                           tag='legend',
                                           fill='yellow')
        self.formantPlotCanvas.create_text(x + 80,
                                           y + 40,
                                           text='Loaded Vowels',
                                           tag='legend',
                                           font=font)

        self.formantPlotCanvas.create_line(x - 15,
                                           0,
                                           x - 15,
                                           y + 50,
                                           tag='legend')
        self.formantPlotCanvas.create_line(x - 15,
                                           y + 50,
                                           self.plotWidth + 50,
                                           y + 50,
                                           tag='legend')

    def createAxis(self):
        self.formantPlotCanvas.delete("formantAxes")
        xFrameScale = (self.plotWidth / PLOTWIDTH)
        yFrameScale = (self.plotHeight / PLOTHEIGHT)

        self.formantPlotCanvas.create_line(
            XSHIFT * xFrameScale, (self.plotHeight - YSHIFT * yFrameScale),
            self.plotWidth, (self.plotHeight - YSHIFT * yFrameScale),
            tags="formantAxes")
        yAxisCount = 15
        yIncrement = ((self.plotHeight - YSHIFT) / yAxisCount)
        for yIndex in range(yAxisCount):
            y = yIndex * yIncrement
            self.formantPlotCanvas.create_line(XSHIFT * xFrameScale - 8,
                                               y,
                                               XSHIFT * xFrameScale,
                                               y,
                                               tags="formantAxes")

        self.formantPlotCanvas.create_line(XSHIFT * xFrameScale,
                                           0,
                                           XSHIFT * xFrameScale,
                                           self.plotHeight -
                                           YSHIFT * yFrameScale,
                                           tags="formantAxes")
        xAxisCount = 20
        xIncrement = (self.plotWidth - XSHIFT * xFrameScale) / xAxisCount
        for xIndex in range(xAxisCount):
            x = xIndex * xIncrement
            self.formantPlotCanvas.create_line(
                XSHIFT * xFrameScale + x,
                self.plotHeight - YSHIFT * yFrameScale + 8,
                XSHIFT * xFrameScale + x,
                self.plotHeight - YSHIFT * yFrameScale,
                tags="formantAxes")

        self.formantPlotCanvas.create_text(
            (XSHIFT * xFrameScale + self.plotWidth) / 2,
            self.plotHeight - YSHIFT * yFrameScale + 20,
            text="Tongue Position",
            font=('Arial', '13'),
            tags="formantAxes")
        self.formantPlotCanvas.create_text(XSHIFT * xFrameScale + 22,
                                           self.plotHeight -
                                           YSHIFT * yFrameScale + 15,
                                           text="Front",
                                           font=('Arial', '13'),
                                           tags="formantAxes")
        self.formantPlotCanvas.create_text(self.plotWidth - 30,
                                           self.plotHeight -
                                           YSHIFT * yFrameScale + 15,
                                           text="Back",
                                           font=('Arial', '13'),
                                           tags="formantAxes")
        self.formantPlotCanvas.create_text(
            XSHIFT * xFrameScale / 2,
            (self.plotHeight - YSHIFT * yFrameScale) / 2,
            text="Mouth",
            font=('Arial', '13'),
            tags="formantAxes")
        self.formantPlotCanvas.create_text(
            XSHIFT * xFrameScale / 2,
            ((self.plotHeight - YSHIFT * yFrameScale) / 2) + 15,
            text="Openness",
            font=('Arial', '13'),
            tags="formantAxes")
        self.formantPlotCanvas.create_text(XSHIFT * xFrameScale / 2,
                                           self.plotHeight -
                                           YSHIFT * yFrameScale - 15,
                                           text="Open",
                                           font=('Arial', '13'),
                                           tags="formantAxes")
        self.formantPlotCanvas.create_text(XSHIFT * xFrameScale / 2,
                                           20,
                                           text="Closed",
                                           font=('Arial', '13'),
                                           tags="formantAxes")

    def drawGoldStandardMonophthongs(self, toFill):
        self.formantPlotCanvas.delete("ellipses")
        vowelType = self.vowelType
        (xScale, xShift, yScale, yShift) = self.getPlotScaleInfo(vowelType)
        data = self.goldStandardMonophthongs(self.id, vowelType)

        xFrameScale = (self.plotWidth / PLOTWIDTH)
        yFrameScale = (self.plotHeight / PLOTHEIGHT)

        std = 1
        for f1mean, f1sd, f2mean, f2sd, vowel in data:
            font = ('Arial', '20', 'bold')
            x1 = ((f2mean - std * f2sd) * xScale - xShift) * xFrameScale
            y1 = ((f1mean - std * f1sd) * yScale - yShift) * yFrameScale
            x2 = ((f2mean + std * f2sd) * xScale - xShift) * xFrameScale
            y2 = ((f1mean + std * f1sd) * yScale - yShift) * yFrameScale
            if toFill:
                currentOval = self.formantPlotCanvas.create_oval(
                    x1,
                    y1,
                    x2,
                    y2,
                    outline='black',
                    tag='ellipses',
                    fill='#ffffff',
                    activefill='#e3c5d6')
            else:
                currentOval = self.formantPlotCanvas.create_oval(
                    x1,
                    y1,
                    x2,
                    y2,
                    outline='black',
                    tag='ellipses',
                    activefill='#e3c5d6')

            ovalText = self.formantPlotCanvas.create_text(
                (f2mean * xScale - xShift) * xFrameScale,
                (f1mean * yScale - yShift) * yFrameScale,
                fill='red',
                font=font,
                tag='ellipses',
                text=vowel)

        #creating the overlap
        for f1mean, f1sd, f2mean, f2sd, vowel in data:
            x1 = ((f2mean - std * f2sd) * xScale - xShift) * xFrameScale
            y1 = ((f1mean - std * f1sd) * yScale - yShift) * yFrameScale
            x2 = ((f2mean + std * f2sd) * xScale - xShift) * xFrameScale
            y2 = ((f1mean + std * f1sd) * yScale - yShift) * yFrameScale
            currentOval = self.formantPlotCanvas.create_oval(x1,
                                                             y1,
                                                             x2,
                                                             y2,
                                                             outline='black',
                                                             tag='ellipses')

    def redrawPlotInfo(self):
        self.drawGoldStandardMonophthongs(False)
        self.createAxis()
        self.createKey()
        self.replotFormants()
        self.replotloadedPlots()

    def getPlotScaleInfo(self, vowelType):
        plotID = self.id

        if plotID == 0:
            if vowelType == 'short':
                xScale = 1.5
                xShift = 400
                yScale = 2
                yShift = 100
            else:
                xScale = 1.5
                xShift = 400
                yScale = 2
                yShift = 100
        elif plotID == 1:
            if vowelType == 'short':
                xScale = 1.5
                xShift = 400
                yScale = 3
                yShift = 200
            else:
                xScale = 1.5
                xShift = 400
                yScale = 3
                yShift = 200
        elif plotID == 2:
            if vowelType == 'short':
                xScale = 1.2
                xShift = 130
                yScale = 1.8
                yShift = 130
            else:
                xScale = 1.2
                xShift = 130
                yScale = 1.8
                yShift = 130
        elif plotID == 3:
            if vowelType == 'short':
                xScale = 1.2
                xShift = 150
                yScale = 2.3
                yShift = 175
            else:
                xScale = 1.2
                xShift = 150
                yScale = 2.3
                yShift = 175
        else:
            print "ERROR ID INVALID"
            xScale = 0
            xShift = 0
            yScale = 0
            yShift = 0
        return (xScale, xShift, yScale, yShift)

    def goldStandardMonophthongs(self, plotID, vowelType):
        path = self.path
        if plotID == 0:
            if vowelType == 'short':
                data = self.appendData(path,
                                       'data\maori\monDataNativeMale.txt')
            else:
                data = self.appendData(path,
                                       'data\maori\longVowelNativeMale.txt')
        elif plotID == 1:
            if vowelType == 'short':
                data = self.appendData(path,
                                       'data\maori\monDataModernMale.txt')
            else:
                data = self.appendData(path,
                                       'data\maori\longVowelModernMale.txt')
        elif plotID == 2:
            if vowelType == 'short':
                data = self.appendData(path,
                                       'data\maori\monDataNativeFemale.txt')
            else:
                data = self.appendData(path,
                                       'data\maori\longVowelNativeFemale.txt')
        elif plotID == 3:
            if vowelType == 'short':
                data = self.appendData(path,
                                       'data\maori\monDataModernFemale.txt')
            else:
                data = self.appendData(path,
                                       'data\maori\longVowelModernFemale.txt')
        return data

    def appendData(self, pat, str):
        MonophthongDataPath = os.path.join(pat, str)
        MonophthongFile = open(MonophthongDataPath, 'r')
        MonophthongData = []
        #Code from ywan478 2010 SoftEng206 Project
        #Load in the monophthong data for males
        for monophthongDataLine in MonophthongFile:
            monophthongDataLine = monophthongDataLine.split()
            #F1 mean and standard deviation
            monophthongDataLine[0] = (int(float(monophthongDataLine[0])) /
                                      SCALEDOWN)
            monophthongDataLine[1] = (int(float(monophthongDataLine[1])) /
                                      SCALEDOWN)
            #F2 mean and standard deviation
            monophthongDataLine[2] = PLOTWIDTH - (int(
                float(monophthongDataLine[2])) / SCALEDOWN) + XSHIFT + XOFFSET
            monophthongDataLine[3] = (int(float(monophthongDataLine[3])) /
                                      SCALEDOWN)
            MonophthongData.append(monophthongDataLine)
            #End code from ywan478
        return MonophthongData

#***********************************************************************************************************
# Sound

    '''
    Creates the Snack Sound objects used in the formant plot.
    '''
    def initialiseSounds(self):
        tkSnack.initializeSnack(self.root)
        self.recordedAudio = Sound()
        self.soundCopy = Sound()
        self.loadedAudio = Sound()

    def replotFormants(self):
        if (self.hasFormants == True):
            self.formantPlotCanvas.delete("userformants")
            radius = self.formantRadius
            color = self.formantColour

            for index in range(len(self.xPlotList)):

                x = self.xPlotList[index]
                y = self.yPlotList[index]
                self.formantPlotCanvas.create_oval(
                    x * (self.plotWidth / PLOTWIDTH) - radius,
                    y * (self.plotHeight / PLOTHEIGHT) - radius,
                    x * (self.plotWidth / PLOTWIDTH) + radius,
                    y * (self.plotHeight / PLOTHEIGHT) + radius,
                    fill=color,
                    tags="userformants")

    def replotloadedPlots(self):
        if (self.hasloadedPlots == True):
            self.formantPlotCanvas.delete("loadedPlots")
            self.formantPlotCanvas.delete("loadedLines")
            radius = self.formantRadius
            color = 'yellow'
            prevX = self.xLoadedPlotList[0]
            prevY = self.yLoadedPlotList[0]

            for index in range(len(self.xLoadedPlotList)):
                x = self.xLoadedPlotList[index]
                y = self.yLoadedPlotList[index]

                xScaled = x * (self.plotWidth / PLOTWIDTH)
                yScaled = y * (self.plotHeight / PLOTHEIGHT)
                prevXScaled = prevX * (self.plotWidth / PLOTWIDTH)
                prevYScaled = prevY * (self.plotHeight / PLOTHEIGHT)
                self.formantPlotCanvas.create_oval(
                    x * (self.plotWidth / PLOTWIDTH) - radius,
                    y * (self.plotHeight / PLOTHEIGHT) - radius,
                    x * (self.plotWidth / PLOTWIDTH) + radius,
                    y * (self.plotHeight / PLOTHEIGHT) + radius,
                    fill=color,
                    tags="loadedPlots")

                if ((((x - prevX)**2 +
                      (y - prevY)**2)**(0.5)) < self.backgroundNoiseDistance):
                    self.formantPlotCanvas.create_line(prevXScaled,
                                                       prevYScaled,
                                                       xScaled,
                                                       yScaled,
                                                       tags='loadedLines')

                prevX = x
                prevY = y

    """
    Plot Fomrants takes a sound file and plots the last formant in the file.
    """

    def plotFormants(self, sound):
        #Gets the probablity of sound being a voice for the last formant in the sound file. (false means last formant, true means all formants)
        probabilityOfVoicing = SoundProcessing.getProbabilityOfVoicing(
            sound, False)

        if probabilityOfVoicing == 1.0:

            formant = SoundProcessing.getFormants(sound, self.id, False)

            #Only plot the latest formants of the sound if there's a good chance that it is the user speaking instead of background noise.
            if formant != None:
                (xScale, xShift, yScale,
                 yShift) = self.getPlotScaleInfo(self.vowelType)
                #GetUser default or user defined colour and radius for the individual formants
                radius = self.formantRadius
                color = self.formantColour
                yPreScale = formant[0] / SCALEDOWN
                xPreScale = PLOTWIDTH - (formant[1] /
                                         SCALEDOWN) + XSHIFT + XOFFSET

                x = (xPreScale * xScale - xShift)
                y = (yPreScale * yScale - yShift)

                self.count += 1
                #Only plot of the Points are on the Grid. They can go over the axis though.
                if (x > 0) and (y < PLOTHEIGHT):
                    distance = (((x - self.prevX)**2 +
                                 (y - self.prevY)**2)**(0.5))

                    if (distance <
                            self.backgroundNoiseDistance) and distance > 0:
                        self.hasFormants = True
                        self.formantPlotCanvas.create_oval(
                            x * (self.plotWidth / PLOTWIDTH) - radius,
                            y * (self.plotHeight / PLOTHEIGHT) - radius,
                            x * (self.plotWidth / PLOTWIDTH) + radius,
                            y * (self.plotHeight / PLOTHEIGHT) + radius,
                            fill=color,
                            tags="userformants")
                        self.xPlotList.append(x)
                        self.yPlotList.append(y)
                    self.prevX = x
                    self.prevY = y

                if not self.isRecording:
                    if formant != None:
                        pass

    """
    Determines if to record or stop.
    """

    def requestRecord(self, *event):
        if self.isRecording:
            if self.isLoading:
                pass
            else:
                self.stop()
        else:
            self.record()

    """
    record is called when the record button is pressed it starts recording the users sounds
    and makes the formant plot react accordingly.
    """

    def record(self):
        self.isLoading = True
        text = 15 * " " + "Stop" + 15 * " "
        self.recordButton.config(text=text, bg='orange', state='disabled')
        self.vowelButton.config(state='disabled')
        self.hasFormants = True
        self.xPlotList = []
        self.yPlotList = []
        self.root.resizable(
            False, False
        )  #DISALLOWS the window to be resized both verically and horizonally.

        self.notStopped = True
        self.recordedAudio.record()
        self.isRecording = True

        #self.stopButton.config(state='normal')
        #self.clearScreenButton.config(state='disabled')
        self.formantPlotCanvas.itemconfig('Recording',
                                          state='normal',
                                          fill='orange')
        self.formantPlotCanvas.itemconfig('recordingText',
                                          state='normal',
                                          text='Loading...')
        thread.start_new_thread(self.multiThreadUpdateCanvas,
                                ("Thread-1", self.notStopped))

        self.count2 = 0

    def multiThreadUpdateCanvas(self, threadName, notStopped):
        self.clear()
        sleep(1.2)
        self.isLoading = False
        text = 15 * " " + "Stop" + 15 * " "
        self.recordButton.config(text=text, bg='#CE2029', state='normal')

        self.formantPlotCanvas.itemconfig('Recording', fill='red')
        self.formantPlotCanvas.itemconfig('recordingText', text='Recording')

        try:
            while self.notStopped:
                self.count2 += 1
                self.soundCopy.copy(self.recordedAudio)
                SoundProcessing.crop(self.soundCopy)
                self.plotFormants(self.soundCopy)
                if self.count2 % 10 == 0:
                    self.updateLoudnessMeter(self.soundCopy)

        except Exception:
            import traceback
            print traceback.format_exc()

    def stop(self):
        self.isRecording = False

        self.recordButton.config(text=" Record ", bg='white')
        self.notStopped = False
        self.formantPlotCanvas.itemconfig('boxes', state='hidden')

        self.loudnessMeter.clearMeter
        self.recordedAudio.stop()

        self.root.after(200, self.removeLoudness)
        self.count = 0
        self.root.resizable(
            True, True
        )  #Allows the window to be resized both verically and horizonally.
        self.vowelButton.config(state='normal')

    def removeLoudness(self):
        self.loudnessMeter.clearMeter()
        self.formantPlotCanvas.itemconfig('toLoud', state='hidden')
        self.formantPlotCanvas.itemconfig('toQuiet', state='hidden')
        self.formantPlotCanvas.itemconfig('Loudness', state='hidden')

    """
    Clears the screen of all plots, lines and loaded plots.
    """

    def clear(self):
        self.hasFormants = False
        self.hasloadedPlots = False
        self.formantPlotCanvas.delete('userformants')
        self.formantPlotCanvas.delete('loadedPlots')
        self.formantPlotCanvas.delete('loadedLines')

    def changeColor(self):
        self.formantColour = 'pink'

    '''
        Update the formant plot and loudness meter if the user is still recording.
    '''

    def updateAllCanvases(self):
        self.soundCopy.copy(self.recordedAudio)
        SoundProcessing.crop(self.soundCopy)
        self.plotFormants(self.soundCopy)

        self.updateLoudnessMeter(self.soundCopy)
        if self.isRecording:

            self.updateAllCanvases()

    def updateLoudnessMeter(self, sound):
        try:
            self.loudnessMeter.updateMeter(sound)

        except IndexError:
            pass

    def playAudioFile(self):
        self.loadedAudio.play()

    def loadAudioFile(self):
        self.formantPlotCanvas.delete("loadedLines")

        os.chdir("../..")
        self.xLoadedPlotList = []
        self.yLoadedPlotList = []

        self.loadedPlots = True
        print os.getcwd()
        filename = tkFileDialog.askopenfilename(initialdir="Recording")
        radius = self.formantRadius
        self.formantPlotCanvas.delete('loadedPlots')

        self.loadedAudio.config(load=filename)
        os.chdir("Formant/dist")
        import wave
        import contextlib
        fname = filename
        with contextlib.closing(wave.open(fname, 'r')) as f:
            frames = f.getnframes()

            rate = f.getframerate()
            duration = float(frames) / float(rate)

        loadedPlots = SoundProcessing.getFormants(self.loadedAudio,
                                                  self.gender, True)
        probabilityOfVoicingList = SoundProcessing.getProbabilityOfVoicing(
            self.loadedAudio, True)
        self.formantPlotCanvas.delete('loadedPlots')

        sleeptime = float(duration) / len(probabilityOfVoicingList)

        thread.start_new_thread(
            self.multiThreadLoader,
            ("Thread-2", sleeptime, probabilityOfVoicingList, loadedPlots))

    def multiThreadPlayer(self, threadName, sound):
        sound.play()

    '''
    multiThreadLoader plots the formant plots onto the formant plot using an additional thread to allow the application not to freeze
    especially if the audio file is very large.
    '''

    def multiThreadLoader(self, threadName, delay, probabilityOfVoicingList,
                          loadedPlots):
        self.hasloadedPlots = True
        self.count = 0
        try:
            radius = self.formantRadius
            for i in range(0, len(loadedPlots)):

                probabilityOfVoicing = probabilityOfVoicingList[i]
                if probabilityOfVoicing == 1.0:
                    formant = loadedPlots[i]
                    latestF1 = formant[0] / SCALEDOWN
                    latestF2 = PLOTWIDTH - (formant[1] /
                                            SCALEDOWN) + XSHIFT + XOFFSET

                    (xScale, xShift, yScale,
                     yShift) = self.getPlotScaleInfo(self.vowelType)

                    if latestF2 > XSHIFT and latestF1 < PLOTHEIGHT - YSHIFT:

                        self.prevplotted = True
                        self.prevX = latestF2 * xScale - xShift
                        self.prevY = latestF1 * yScale - yShift
                        break
            for i in range(0, len(loadedPlots)):

                probabilityOfVoicing = probabilityOfVoicingList[i]
                if probabilityOfVoicing == 1.0:
                    formant = loadedPlots[i]
                    latestF1 = formant[0] / SCALEDOWN
                    latestF2 = PLOTWIDTH - (formant[1] /
                                            SCALEDOWN) + XSHIFT + XOFFSET

                    (xScale, xShift, yScale,
                     yShift) = self.getPlotScaleInfo(self.vowelType)

                    if latestF2 > XSHIFT and latestF1 < PLOTHEIGHT - YSHIFT:

                        x = latestF2 * xScale - xShift
                        y = latestF1 * yScale - yShift

                        if ((((x - self.prevX)**2 + (y - self.prevY)**2)
                             **(0.5)) < self.backgroundNoiseDistance):
                            self.xLoadedPlotList.append(x)
                            self.yLoadedPlotList.append(y)

                            x1 = x * (self.plotWidth / PLOTWIDTH) - radius
                            y1 = y * (self.plotHeight / PLOTHEIGHT) - radius
                            x2 = x * (self.plotWidth / PLOTWIDTH) + radius
                            y2 = y * (self.plotHeight / PLOTHEIGHT) + radius

                            if (self.prevplotted == True):
                                self.formantPlotCanvas.create_line(
                                    self.prevX * (self.plotWidth / PLOTWIDTH),
                                    self.prevY *
                                    (self.plotHeight / PLOTHEIGHT),
                                    x * (self.plotWidth / PLOTWIDTH),
                                    y * (self.plotHeight / PLOTHEIGHT),
                                    fill='black',
                                    tags='loadedLines')
                                pass

                            xCoord = x1

                            self.formantPlotCanvas.create_oval(
                                x1,
                                y1,
                                x2,
                                y2,
                                fill='yellow',
                                tags="loadedPlots")
                            self.prevplotted = True

                            self.count += 1
                        else:
                            self.prevplotter = False

                        self.prevX = x
                        self.prevY = y

        except Exception:
            import traceback
            print traceback.format_exc()
        self.formantPlotCanvas.itemconfig("loadedLines", state='hidden')
        self.lineHiddens = True

        self.redrawPlotInfo()
        self.count = 0

    def toggleLoadedPlots(self):
        if self.loadedPlots:
            self.formantPlotCanvas.itemconfig("loadedPlots", state="hidden")
            self.loadedPlots = False
        else:
            self.formantPlotCanvas.itemconfig("loadedPlots", state="normal")
            self.loadedPlots = True

    def toggleLines(self):
        if self.lineHiddens:
            self.formantPlotCanvas.itemconfig("loadedLines", state="normal")
            self.lineHiddens = False
        else:
            self.formantPlotCanvas.itemconfig("loadedLines", state="hidden")
            self.lineHiddens = True

    def toggleBackgroundNoise(self, level):
        if level == 0:
            self.backgroundNoiseDistance = 10000
        elif level == 1:
            self.backgroundNoiseDistance = 100
        elif level == 2:
            self.backgroundNoiseDistance = 50

        elif level == 3:
            self.backgroundNoiseDistance = 30
        else:
            self.backgroundNoiseDistance = 10

    def callback(self, event):
        print "canvas clicked"
示例#7
0
文件: FormantPlot.py 项目: MPAid/Main
class FormantPlot:

        '''
        Initialise the formant plot.
        Arguments: parent - the widget that the formant plot is contained in.
                   path - the directory path where the application is in.
                   root - the Tk widget which is the base of all the other widgets.
                   gender - user's gender
        '''
        def __init__(self, parent, path, root,gender):

                self.root = root
                self.parent = parent
                self.gender=gender
                self.appDirectory = path
                

                self.setUpWidgets()

                self.getGoldStandardMonophthongs(path)
                self.drawGoldStandardMonophthongs(gender)
                self.drawFormantPlotAxes()
                self.drawFormantPlotLegend()

                self.initialiseSounds()
                self.initialiseKeyboardShortcuts()

                self.isRecording=False
                self.previousF1 = 0
                self.previousF2 = 0

        '''
        Initialises all the widgets that are associated with the formant plot.
        '''
        def setUpWidgets(self):

                self.formantPlotFrame = Frame(self.parent, width=FORMANTPLOTFRAMEWIDTH, height=FORMANTPLOTFRAMEHEIGHT)
                self.formantPlotFrame.grid()
                
		self.formantPlotCanvas = SnackCanvas(self.formantPlotFrame, height=FORMANTPLOTHEIGHT, width=FORMANTPLOTWIDTH, bg='white')
		self.formantPlotCanvas.grid(row=0,column=0)

		self.loudnessMeterCanvas = SnackCanvas(self.formantPlotFrame, height=FORMANTPLOTHEIGHT, width=FORMANTPLOTFRAMEWIDTH-FORMANTPLOTWIDTH, bg='white')
		self.loudnessMeterCanvas.grid(row=0,column=1)

		self.formantPlotControlFrame = Frame(self.formantPlotFrame)
		self.formantPlotControlFrame.grid(row=1,column=0,sticky='w'+'e',columnspan=2)

		self.formantPlotControlFrame.columnconfigure(0, minsize=FORMANTPLOTWIDTH/3)
		self.formantPlotControlFrame.columnconfigure(1, minsize=FORMANTPLOTWIDTH/3)
		self.formantPlotControlFrame.columnconfigure(2, minsize=FORMANTPLOTWIDTH/3)
		self.formantPlotControlFrame.columnconfigure(3, minsize=FORMANTPLOTFRAMEWIDTH-FORMANTPLOTWIDTH)

                self.isLabelsOn = BooleanVar()
                self.toggleLabelCheckbox = Checkbutton(self.formantPlotControlFrame,text='Show Labels',variable=self.isLabelsOn,onvalue=True,offvalue=False,state='active',command=(lambda:self.togglePlot(self.isLabelsOn.get(),'ellipseLabel')))
                self.toggleLabelCheckbox.grid(row=0,column=0)
                self.toggleLabelCheckbox.select()

                self.isEllipsesOn = BooleanVar()
                self.toggleEllipsesCheckbox = Checkbutton(self.formantPlotControlFrame,text='Show Ellipses',variable=self.isEllipsesOn,onvalue=True,offvalue=False,state='active',command=(lambda:self.togglePlot(self.isEllipsesOn.get(),'ellipses')))
                self.toggleEllipsesCheckbox.grid(row=0,column=1)
                self.toggleEllipsesCheckbox.select()

                self.isLoadedFormantsOn = BooleanVar()
                self.toggleLoadedFormantsCheckbox = Checkbutton(self.formantPlotControlFrame,text='Show Loaded Formants',variable=self.isLoadedFormantsOn,onvalue=True,offvalue=False,state='active',command=(lambda:self.togglePlot(self.isLoadedFormantsOn.get(),'loadedformants')))
                self.toggleLoadedFormantsCheckbox.grid(row=0,column=2)
                self.toggleLoadedFormantsCheckbox.select()

                self.recButton = ttk.Button(self.formantPlotControlFrame, text='Record', command=self.record,style='Fun.TButton')
		self.recButton.grid(row=1,column=0,sticky='w'+'e',padx=10)
		self.stopButton = ttk.Button(self.formantPlotControlFrame, text='Stop', command=self.stop,state='disabled',style='Fun.TButton')
		self.stopButton.grid(row=1,column=1,sticky='w'+'e',padx=10)
		self.playRecordButton = ttk.Button(self.formantPlotControlFrame, text='Play Last Recorded Sound', command=(lambda:(self.play(self.recordedAudio))),state='disabled',style='Fun.TButton')
		self.playRecordButton.grid(row=1,column=2,sticky='w'+'e',padx=10)
		

		self.loadAudioButton = ttk.Button(self.formantPlotControlFrame, text='Load Audio File', command=self.loadAudioFile,state='normal',style='Fun.TButton')
		self.loadAudioButton.grid(row=2,column=1,sticky='w'+'e',padx=10)
		self.saveButton = ttk.Button(self.formantPlotControlFrame, text='Save', command=self.save,state='disabled',style='Fun.TButton')
		self.saveButton.grid(row=2,column=0,sticky='w'+'e',padx=10)
		self.playLoadButton = ttk.Button(self.formantPlotControlFrame, text='Play Loaded File', command=(lambda:(self.play(self.loadedAudio))),state='disabled',style='Fun.TButton')
		self.playLoadButton.grid(row=2,column=2,sticky='w'+'e',padx=10)

		self.clearScreenButton = ttk.Button(self.formantPlotControlFrame, text='Clear Plot', command=self.clearUserFormants,state='normal',style='Fun.TButton')
		self.clearScreenButton.grid(row=1,column=3,sticky='w'+'e'+'n'+'s', rowspan=2)

		self.loudnessMeter = LoudnessMeter(self.loudnessMeterCanvas)

	'''
        Creates the Snack Sound objects used in the formant plot.
        '''
	def initialiseSounds(self):
		initializeSnack(self.root)
		self.recordedAudio = Sound()
		self.soundCopy = Sound()
		self.loadedAudio = Sound()


	def initialiseKeyboardShortcuts(self):
                self.root.bind('<space>',self.executeSpacebarInput)
                
	'''
        Draw the axes for the formant plot.
        '''
	def drawFormantPlotAxes(self):
                #X axis
		self.formantPlotCanvas.create_line(XSHIFT,FORMANTPLOTHEIGHT-YSHIFT,FORMANTPLOTWIDTH,FORMANTPLOTHEIGHT-YSHIFT, tags="formantAxes")
		#Y axis
		self.formantPlotCanvas.create_line(XSHIFT,0,XSHIFT,FORMANTPLOTHEIGHT-YSHIFT, tags="formantAxes")

		#X axis label
		self.formantPlotCanvas.create_text((XSHIFT+FORMANTPLOTWIDTH)/2, FORMANTPLOTHEIGHT-YSHIFT+30,text = "Tongue Position", tags="formantAxes")
		self.formantPlotCanvas.create_text(XSHIFT+12, FORMANTPLOTHEIGHT-YSHIFT+10,text = "Front", tags="formantAxes")
		self.formantPlotCanvas.create_text(FORMANTPLOTWIDTH-15, FORMANTPLOTHEIGHT-YSHIFT+10,text = "Back", tags="formantAxes")

		#Y axis label
		self.formantPlotCanvas.create_text(XSHIFT/2, (FORMANTPLOTHEIGHT-YSHIFT)/2,text = "Mouth", tags="formantAxes")
		self.formantPlotCanvas.create_text(XSHIFT/2, ((FORMANTPLOTHEIGHT-YSHIFT)/2)+20,text = "Openness", tags="formantAxes")
		self.formantPlotCanvas.create_text(XSHIFT/2, FORMANTPLOTHEIGHT-YSHIFT-10,text = "Open", tags="formantAxes")
                self.formantPlotCanvas.create_text(XSHIFT/2, 10,text = "Closed", tags="formantAxes")
                                                   

        def drawFormantPlotLegend(self):
                self.formantPlotCanvas.create_oval(FORMANTPLOTWIDTH-120-3,10-3,FORMANTPLOTWIDTH-120+3,10+3,tag='legend',fill='black')
                self.formantPlotCanvas.create_text(FORMANTPLOTWIDTH-60,10,text='Recorded Formants',tag='legend')
                self.formantPlotCanvas.create_oval(FORMANTPLOTWIDTH-120-3,30-3,FORMANTPLOTWIDTH-120+3,30+3,tag='legend',fill='red')
                self.formantPlotCanvas.create_text(FORMANTPLOTWIDTH-64,30,text='Loaded Formants',tag='legend')
                                                   
        '''
	Loads the monophthong data.
	Arguments: path - directory path of where the application is stored in.
	'''
	def getGoldStandardMonophthongs(self, path):
		#Initialise the male data
		self.maleMonophthongData = []
		maleMonophthongDataPath = os.path.join(path, 'data\maori\monDataMale.txt')
		maleMonophthongFile = open(maleMonophthongDataPath,'r')
		
		#Initialise the female data
		self.femaleMonophthongData = []
		femaleMonophthongDataPath = os.path.join(path, 'data\maori\monDataFemale.txt')
		femaleMonophthongFile = open(femaleMonophthongDataPath,'r')
		
		#Code from ywan478 2010 SoftEng206 Project
		#Load in the monophthong data for males
		for monophthongDataLine in maleMonophthongFile:
			monophthongDataLine = monophthongDataLine.split()
			
			#F1 mean and standard deviation
			monophthongDataLine[0]= (int(float(monophthongDataLine[0]))/SCALEDOWN)
			monophthongDataLine[1]= (int(float(monophthongDataLine[1]))/SCALEDOWN)
			
			#F2 mean and standard deviation
			monophthongDataLine[2]= FORMANTPLOTWIDTH - (int(float(monophthongDataLine[2]))/SCALEDOWN) + XSHIFT + XOFFSET
			monophthongDataLine[3]= (int(float(monophthongDataLine[3]))/SCALEDOWN)

			self.maleMonophthongData.append(monophthongDataLine)
			
		#Load in the monophthong data for females
		for monophthongDataLine in femaleMonophthongFile:
			monophthongDataLine = monophthongDataLine.split()
			
			#F1 mean and standard deviation
			monophthongDataLine[0]= (int(float(monophthongDataLine[0]))/SCALEDOWN)
			monophthongDataLine[1]= (int(float(monophthongDataLine[1]))/SCALEDOWN)
			
			#F2 mean and standard deviation
			monophthongDataLine[2]= FORMANTPLOTWIDTH - (int(float(monophthongDataLine[2]))/SCALEDOWN) + XSHIFT + XOFFSET
			monophthongDataLine[3]= (int(float(monophthongDataLine[3]))/SCALEDOWN)
		
			self.femaleMonophthongData.append(monophthongDataLine)
                			
			#End code from ywan478

        '''
        Draw the gold standard monophthong data into the formant plot.
	Arguments: gender - gender of the user. True if male. False if female.
	'''
        def drawGoldStandardMonophthongs(self, gender):

                if gender==True:
                        data = self.maleMonophthongData
                else:
                        data = self.femaleMonophthongData
                #Code from ywan478 2010 SoftEng206 Project
                for f1mean, f1sd, f2mean, f2sd, vowel in data:
                        font = ('Arial','10','bold')
			self.formantPlotCanvas.create_oval(f2mean-f2sd,f1mean-f1sd,f2mean+f2sd,f1mean+f1sd, outline='black', tag='ellipses')
			self.formantPlotCanvas.create_text(f2mean,f1mean,fill='red',font=font,tag='ellipseLabel', text=vowel)
			
		#End code from ywan478

	'''
        Plots the last formant of the recording sound into the formant plot.
        Arguments: sound - the sound that is being recorded.
        '''
	def plotFormants(self, sound):
		

		probabilityOfVoicing = SoundProcessing.getProbabilityOfVoicing(sound,False)

                if probabilityOfVoicing == 1.0:
                        
                        formants = SoundProcessing.getFormants(sound,self.gender,False)

                
                        #Only plot the latest formants of the sound if there's a good chance that it is the user speaking instead of background noise.
                        if formants != None:
                                #self.f1List.append(formants[0])
                                #self.f2List.append(formants[1])
                        
                                latestF1 = formants[0]/SCALEDOWN
                                latestF2 = FORMANTPLOTWIDTH - (formants[1]/SCALEDOWN) + XSHIFT + XOFFSET
                                #if abs(self.previousF1-latestF1) < 150 and abs(self.previousF2-latestF2) < 150:
                                #print latestF1
                                #print latestF2
                                #print "\n\n"
                                if latestF2 > XSHIFT and latestF1 < FORMANTPLOTHEIGHT-YSHIFT:
                                        self.formantPlotCanvas.create_oval(latestF2-2,latestF1-2,latestF2+2,latestF1+2, fill='black', tags="userformants")

                                #self.previousF1 = latestF1
                                #self.previousF2 = latestF2
                
                        if not self.isRecording:
                                if formants != None:
                                        #print self.soundCopy.formant()
                                        #print self.f1List
                                        #print self.f2List
                                        print ""

        '''
        Update the loudness level in the loudness meter.
        Arguments: sound - the sound that is currently being recorded.
        '''
        def updateLoudnessMeter(self, sound):
                try:
                        self.loudnessMeter.updateMeter(sound)
                        
                except IndexError:
                        print "No sound available to get loudness yet"


        '''
        Update the formant plot and loudness meter if the user is still recording.
        '''
        def updateAllCanvases(self):
                self.soundCopy.copy(self.recordedAudio)
                SoundProcessing.crop(self.soundCopy)
                self.plotFormants(self.soundCopy)
                self.updateLoudnessMeter(self.soundCopy)
                if self.isRecording:
                        self.root.after(30,self.updateAllCanvases)

        '''
        Clears the user's formant data from the formant plot.
        '''
        def clearUserFormants(self):
                self.formantPlotCanvas.delete('userformants')

        '''
        Clears the gold standard data from the formant plot.
        '''
        def clearGoldStandard(self):
                self.formantPlotCanvas.delete('ellipseLabel')
                self.formantPlotCanvas.delete('ellipses')

        '''
        Redraws the gold standard data on the formant plot if the user's gender is changed.
        Arguments: gender - user's gender.
        '''
        def updateGoldStandard(self, gender):
                self.clearGoldStandard()
                self.drawGoldStandardMonophthongs(gender)

        def updateGender(self,gender):
                self.gender = gender

        def play(self,sound):
                sound.play(blocking=True)
                
                
                
        '''
        Stops the recording.
        '''
	def stop(self):
                
		self.recordedAudio.stop()
		self.recButton.config(state='normal')
		self.saveButton.config(state='normal')
		self.playRecordButton.config(state='normal')
		self.stopButton.config(state='disabled')
		self.isRecording = False
		self.root.after(200,self.loudnessMeter.clearMeter)

	'''
	Start recording the user's sounds and make the formant plot react accordingly.
	'''
 	def record(self): #Record sound file
                self.clearUserFormants();
		self.recordedAudio.record()
		self.isRecording = True
		self.recButton.config(state='disabled')
		self.stopButton.config(state='normal')

		self.root.after(200,self.updateAllCanvases)
		
        '''
        Saves the latest recording from the user.
        '''
	def save(self):
		saveName = tkFileDialog.asksaveasfilename(defaultextension=".wav")
		self.recordedAudio.write(saveName,start=0,end=-1)

	def loadAudioFile(self):
                filename = tkFileDialog.askopenfilename(initialdir=self.appDirectory)
                
                self.formantPlotCanvas.delete('loadedformants')
                
                self.loadedAudio.config(load=filename)
                self.playLoadButton.config(state='normal')
                loadedFormants = SoundProcessing.getFormants(self.loadedAudio,self.gender,True)
                probabilityOfVoicingList = SoundProcessing.getProbabilityOfVoicing(self.loadedAudio,True)
                self.formantPlotCanvas.delete('loadedformants')
                #print len(loadedFormants)
                #print len(probabilityOfVoicingList)
                try:
                    for i in range(0,len(loadedFormants)):
                        probabilityOfVoicing = probabilityOfVoicingList[i]
                        if probabilityOfVoicing == 1.0:
                            formant = loadedFormants[i]
                            f1 = formant[0]/SCALEDOWN
                            f2 = FORMANTPLOTWIDTH - (formant[1]/SCALEDOWN) + XSHIFT + XOFFSET
                            self.formantPlotCanvas.create_oval(f2-2,f1-2,f2+2,f1+2, fill='red', tags="loadedformants")
                except IndexError:
                    print ""
                        

        '''
        Displays/hides a specified aspect of the formant plot presentation.
	Arguments: boolean - true/false indicates whether the plot should display/hide the specified thing.
		    tag - the thing that is going to be displayed/hidden.
	'''
        def togglePlot(self,boolean,tag):
                if boolean:
                        self.formantPlotCanvas.itemconfig(tag, state='normal')
                else:
                       self.formantPlotCanvas.itemconfig(tag, state='hidden')

        def executeSpacebarInput(self,event):
                if self.isRecording == False:
                        self.record()
                else:
                        self.stop()
示例#8
0
class FormantPlot:
    '''
        Initialise the formant plot.
        Arguments: parent - the widget that the formant plot is contained in.
                   path - the directory path where the application is in.
                   root - the Tk widget which is the base of all the other widgets.
                   gender - user's gender
        '''
    def __init__(self, parent, path, root, gender, id):

        self.root = root
        self.parent = parent
        self.gender = gender
        self.appDirectory = path
        self.id = id

        self.setUpWidgets()

        self.getGoldStandardMonophthongs(path)
        self.drawGoldStandardMonophthongs(id)
        self.drawFormantPlotAxes()
        self.drawFormantPlotLegend()

        self.initialiseSounds()
        #self.initialiseKeyboardShortcuts()

        self.isRecording = False
        self.previousF1 = 0
        self.previousF2 = 0

    '''
        Initialises all the widgets that are associated with the formant plot.
        '''

    def setUpWidgets(self):

        self.formantPlotFrame = Frame(self.parent,
                                      width=FORMANTPLOTFRAMEWIDTH,
                                      height=FORMANTPLOTFRAMEHEIGHT)
        self.formantPlotFrame.grid()

        self.formantPlotCanvas = SnackCanvas(self.formantPlotFrame,
                                             height=FORMANTPLOTHEIGHT,
                                             width=FORMANTPLOTWIDTH,
                                             bg='white')
        self.formantPlotCanvas.grid(row=0, column=0)

        self.loudnessMeterCanvas = SnackCanvas(self.formantPlotFrame,
                                               height=FORMANTPLOTHEIGHT,
                                               width=10)
        self.loudnessMeterCanvas.grid(row=0, column=1)

        self.formantPlotControlFrame = Frame(self.formantPlotFrame)
        self.formantPlotControlFrame.grid(row=1,
                                          column=0,
                                          sticky='w' + 'e',
                                          columnspan=2)

        self.formantPlotControlFrame.columnconfigure(0,
                                                     minsize=FORMANTPLOTWIDTH /
                                                     3)
        self.formantPlotControlFrame.columnconfigure(1,
                                                     minsize=FORMANTPLOTWIDTH /
                                                     3)
        self.formantPlotControlFrame.columnconfigure(2,
                                                     minsize=FORMANTPLOTWIDTH /
                                                     3)

        self.recButton = ttk.Button(self.formantPlotControlFrame,
                                    text='Record',
                                    command=self.record,
                                    style='Fun.TButton')
        self.recButton.grid(row=1, column=0, sticky='w' + 'e', padx=10)
        self.stopButton = ttk.Button(self.formantPlotControlFrame,
                                     text='Stop',
                                     command=self.stop,
                                     state='disabled',
                                     style='Fun.TButton')
        self.stopButton.grid(row=1, column=1, sticky='w' + 'e', padx=10)

        self.clearScreenButton = ttk.Button(self.formantPlotControlFrame,
                                            text='Clear Plot',
                                            command=self.clearUserFormants,
                                            state='normal',
                                            style='Fun.TButton')
        self.clearScreenButton.grid(row=1,
                                    column=2,
                                    sticky='w' + 'e' + 'n' + 's')

        self.loudnessMeter = LoudnessMeter(self.loudnessMeterCanvas)

    '''
        Creates the Snack Sound objects used in the formant plot.
        '''

    def initialiseSounds(self):
        initializeSnack(self.root)
        self.recordedAudio = Sound()
        self.soundCopy = Sound()
        self.loadedAudio = Sound()

    def initialiseKeyboardShortcuts(self):
        self.root.bind('<space>', self.executeSpacebarInput)

    '''
        Draw the axes for the formant plot.
        '''

    def drawFormantPlotAxes(self):
        self.formantPlotCanvas.create_line(XSHIFT,
                                           FORMANTPLOTHEIGHT - YSHIFT,
                                           FORMANTPLOTWIDTH,
                                           FORMANTPLOTHEIGHT - YSHIFT,
                                           tags="formantAxes")
        for y in range(0, FORMANTPLOTHEIGHT - YSHIFT, 20):
            self.formantPlotCanvas.create_line(XSHIFT - 8,
                                               0 + y,
                                               XSHIFT,
                                               0 + y,
                                               tags="formantAxes")
        self.formantPlotCanvas.create_line(XSHIFT,
                                           0,
                                           XSHIFT,
                                           FORMANTPLOTHEIGHT - YSHIFT,
                                           tags="formantAxes")
        for x in range(0, 900, 20):
            self.formantPlotCanvas.create_line(XSHIFT + x,
                                               FORMANTPLOTHEIGHT - YSHIFT,
                                               XSHIFT + x,
                                               FORMANTPLOTHEIGHT - YSHIFT + 8)
        self.formantPlotCanvas.create_text((XSHIFT + FORMANTPLOTWIDTH) / 2,
                                           FORMANTPLOTHEIGHT - YSHIFT + 25,
                                           text="Tongue Position",
                                           font=('Arial', '13'),
                                           tags="formantAxes")
        self.formantPlotCanvas.create_text(XSHIFT + 22,
                                           FORMANTPLOTHEIGHT - YSHIFT + 20,
                                           text="Front",
                                           font=('Arial', '13'),
                                           tags="formantAxes")
        self.formantPlotCanvas.create_text(FORMANTPLOTWIDTH - 30,
                                           FORMANTPLOTHEIGHT - YSHIFT + 20,
                                           text="Back",
                                           font=('Arial', '13'),
                                           tags="formantAxes")
        self.formantPlotCanvas.create_text(XSHIFT / 2,
                                           (FORMANTPLOTHEIGHT - YSHIFT) / 2,
                                           text="Mouth",
                                           font=('Arial', '13'),
                                           tags="formantAxes")
        self.formantPlotCanvas.create_text(
            XSHIFT / 2, ((FORMANTPLOTHEIGHT - YSHIFT) / 2) + 20,
            text="Openness",
            font=('Arial', '13'),
            tags="formantAxes")
        self.formantPlotCanvas.create_text(XSHIFT / 2,
                                           FORMANTPLOTHEIGHT - YSHIFT - 20,
                                           text="Open",
                                           font=('Arial', '13'),
                                           tags="formantAxes")
        self.formantPlotCanvas.create_text(XSHIFT / 2,
                                           20,
                                           text="Closed",
                                           font=('Arial', '13'),
                                           tags="formantAxes")

    def drawFormantPlotLegend(self):
        font = ('Arial', '13')
        self.formantPlotCanvas.create_oval(FORMANTPLOTWIDTH - 160 - 3,
                                           10 - 3,
                                           FORMANTPLOTWIDTH - 160 + 3,
                                           10 + 3,
                                           tag='legend',
                                           fill='black')
        self.formantPlotCanvas.create_text(FORMANTPLOTWIDTH - 80,
                                           10,
                                           text='Recorded Vowels',
                                           tag='legend',
                                           font=font)
        self.formantPlotCanvas.create_oval(FORMANTPLOTWIDTH - 160 - 3,
                                           30 - 3,
                                           FORMANTPLOTWIDTH - 160 + 3,
                                           30 + 3,
                                           tag='legend',
                                           fill='red')
        self.formantPlotCanvas.create_text(FORMANTPLOTWIDTH - 80,
                                           30,
                                           text='Loaded Vowels',
                                           tag='legend',
                                           font=font)

    def appendData(self, pat, str):
        MonophthongDataPath = os.path.join(pat, str)
        MonophthongFile = open(MonophthongDataPath, 'r')

        MonophthongData = []

        #Code from ywan478 2010 SoftEng206 Project
        #Load in the monophthong data for males
        for monophthongDataLine in MonophthongFile:
            monophthongDataLine = monophthongDataLine.split()

            #F1 mean and standard deviation
            monophthongDataLine[0] = (int(float(monophthongDataLine[0])) /
                                      SCALEDOWN)
            monophthongDataLine[1] = (int(float(monophthongDataLine[1])) /
                                      SCALEDOWN)

            #F2 mean and standard deviation
            monophthongDataLine[2] = FORMANTPLOTWIDTH - (int(
                float(monophthongDataLine[2])) / SCALEDOWN) + XSHIFT + XOFFSET
            monophthongDataLine[3] = (int(float(monophthongDataLine[3])) /
                                      SCALEDOWN)

            MonophthongData.append(monophthongDataLine)
        #End code from ywan478

        return MonophthongData

    '''
	Loads the monophthong data.
	Arguments: path - directory path of where the application is stored in.
	'''

    def getGoldStandardMonophthongs(self, path):
        #Initialise the male data
        self.maleMonophthongData = self.appendData(
            path, 'data\maori\monDataMale.txt')
        self.maleMonophthongData1 = self.appendData(
            path, 'data\maori\monDataMaleYoung.txt')

        #Initialise the female data
        self.femaleMonophthongData = self.appendData(
            path, 'data\maori\monDataFemale.txt')
        self.femaleMonophthongData1 = self.appendData(
            path, 'data\maori\monDataFemaleYoung.txt')

    '''
        Draw the gold standard monophthong data into the formant plot.
	Arguments: gender - gender of the user. True if male. False if female.
	'''

    def drawGoldStandardMonophthongs(self, id):

        if id == 0:
            data = self.maleMonophthongData
            for f1mean, f1sd, f2mean, f2sd, vowel in data:
                font = ('Arial', '20', 'bold')
                self.formantPlotCanvas.create_oval(
                    (f2mean - f2sd) * 1.5 - 400, (f1mean - f1sd) * 2 - 100,
                    (f2mean + f2sd) * 1.5 - 400, (f1mean + f1sd) * 2 - 100,
                    outline='black',
                    tag='ellipses')
                self.formantPlotCanvas.create_text(f2mean * 1.5 - 400,
                                                   f1mean * 2 - 100,
                                                   fill='red',
                                                   font=font,
                                                   tag='ellipseLabel',
                                                   text=vowel)
        elif id == 1:
            data = self.maleMonophthongData1
            for f1mean, f1sd, f2mean, f2sd, vowel in data:
                font = ('Arial', '20', 'bold')
                self.formantPlotCanvas.create_oval(
                    (f2mean - f2sd) * 1.5 - 400, (f1mean - f1sd) * 2.7 - 300,
                    (f2mean + f2sd) * 1.5 - 400, (f1mean + f1sd) * 2.7 - 300,
                    outline='black',
                    tag='ellipses')
                self.formantPlotCanvas.create_text(f2mean * 1.5 - 400,
                                                   f1mean * 2.7 - 300,
                                                   fill='red',
                                                   font=font,
                                                   tag='ellipseLabel',
                                                   text=vowel)
        elif id == 2:
            data = self.femaleMonophthongData
            for f1mean, f1sd, f2mean, f2sd, vowel in data:
                font = ('Arial', '20', 'bold')
                self.formantPlotCanvas.create_oval(
                    (f2mean - f2sd) * 1.2 - 130, (f1mean - f1sd) * 1.8 - 130,
                    (f2mean + f2sd) * 1.2 - 130, (f1mean + f1sd) * 1.8 - 130,
                    outline='black',
                    tag='ellipses')
                self.formantPlotCanvas.create_text(f2mean * 1.2 - 130,
                                                   f1mean * 1.8 - 130,
                                                   fill='red',
                                                   font=font,
                                                   tag='ellipseLabel',
                                                   text=vowel)
        else:
            data = self.femaleMonophthongData1
            for f1mean, f1sd, f2mean, f2sd, vowel in data:
                font = ('Arial', '20', 'bold')
                self.formantPlotCanvas.create_oval(
                    (f2mean - f2sd) * 1.5 - 330, (f1mean - f1sd) * 2.7 - 300,
                    (f2mean + f2sd) * 1.5 - 330, (f1mean + f1sd) * 2.7 - 300,
                    outline='black',
                    tag='ellipses')
                self.formantPlotCanvas.create_text(f2mean * 1.5 - 330,
                                                   f1mean * 2.7 - 300,
                                                   fill='red',
                                                   font=font,
                                                   tag='ellipseLabel',
                                                   text=vowel)
        #Code from ywan478 2010 SoftEng206 Project

#End code from ywan478

    '''
        Plots the last formant of the recording sound into the formant plot.
        Arguments: sound - the sound that is being recorded.
        '''
    def plotFormants(self, sound):

        probabilityOfVoicing = SoundProcessing.getProbabilityOfVoicing(
            sound, False)

        if probabilityOfVoicing == 1.0:

            formants = SoundProcessing.getFormants(sound, self.gender, False)

            #Only plot the latest formants of the sound if there's a good chance that it is the user speaking instead of background noise.
            if formants != None:

                latestF1 = formants[0] / SCALEDOWN
                latestF2 = FORMANTPLOTWIDTH - (formants[1] /
                                               SCALEDOWN) + XSHIFT + XOFFSET

                if self.id == 0:
                    latestF2 = latestF2 * 1.5 - 400
                    latestF1 = latestF1 * 2 - 100
                elif self.id == 1:
                    latestF2 = latestF2 * 1.5 - 400
                    latestF1 = latestF1 * 2.7 - 300
                elif self.id == 2:
                    latestF2 = latestF2 * 1.2 - 130
                    latestF1 = latestF1 * 1.8 - 130
                elif self.id == 3:
                    latestF2 = latestF2 * 1.5 - 330
                    latestF1 = latestF1 * 2.7 - 300

                if latestF2 > XSHIFT and latestF1 < FORMANTPLOTHEIGHT - YSHIFT:
                    self.formantPlotCanvas.create_oval(latestF2 - 2,
                                                       latestF1 - 2,
                                                       latestF2 + 2,
                                                       latestF1 + 2,
                                                       fill='black',
                                                       tags="userformants")

            if not self.isRecording:
                if formants != None:
                    print ""

    '''
        Update the loudness level in the loudness meter.
        Arguments: sound - the sound that is currently being recorded.
        '''

    def updateLoudnessMeter(self, sound):
        try:
            self.loudnessMeter.updateMeter(sound)

        except IndexError:
            print "No sound available to get loudness yet"

    '''
        Update the formant plot and loudness meter if the user is still recording.
        '''

    def updateAllCanvases(self):
        self.soundCopy.copy(self.recordedAudio)
        SoundProcessing.crop(self.soundCopy)
        self.plotFormants(self.soundCopy)
        self.updateLoudnessMeter(self.soundCopy)
        if self.isRecording:
            self.root.after(30, self.updateAllCanvases)

    '''
        Clears the user's formant data from the formant plot.
        '''

    def clearUserFormants(self):
        self.formantPlotCanvas.delete('userformants')

    '''
        Clears the gold standard data from the formant plot.
        '''

    def clearGoldStandard(self):
        self.formantPlotCanvas.delete('ellipseLabel')
        self.formantPlotCanvas.delete('ellipses')

    '''
        Redraws the gold standard data on the formant plot if the user's gender is changed.
        Arguments: gender - user's gender.
        '''

    def updateGoldStandard(self, id):
        self.clearGoldStandard()
        self.drawGoldStandardMonophthongs(id)

    def updateGender(self, gender):
        self.gender = gender

    def play(self, sound, id):
        sound.play(blocking=True)

    '''
        Stops the recording.
        '''

    def stop(self):

        self.recordedAudio.stop()
        self.recButton.config(state='normal')
        self.stopButton.config(state='disabled')
        self.isRecording = False
        self.root.after(200, self.loudnessMeter.clearMeter)

    '''
	Start recording the user's sounds and make the formant plot react accordingly.
	'''

    def record(self):  #Record sound file
        self.clearUserFormants()
        self.recordedAudio.record()
        self.isRecording = True
        self.recButton.config(state='disabled')
        self.stopButton.config(state='normal')

        self.root.after(200, self.updateAllCanvases)

    '''
        Saves the latest recording from the user.
        '''

    def save(self):
        saveName = tkFileDialog.asksaveasfilename(defaultextension=".wav")
        self.recordedAudio.write(saveName, start=0, end=-1)

    def loadAudioFile(self):
        filename = tkFileDialog.askopenfilename(initialdir=self.appDirectory)

        self.formantPlotCanvas.delete('loadedformants')

        self.loadedAudio.config(load=filename)
        #self.playLoadButton.config(state='normal')
        loadedFormants = SoundProcessing.getFormants(self.loadedAudio,
                                                     self.gender, True)
        probabilityOfVoicingList = SoundProcessing.getProbabilityOfVoicing(
            self.loadedAudio, True)
        self.formantPlotCanvas.delete('loadedformants')
        try:
            for i in range(0, len(loadedFormants)):
                probabilityOfVoicing = probabilityOfVoicingList[i]
                if probabilityOfVoicing == 1.0:
                    formant = loadedFormants[i]
                    f1 = formant[0] / SCALEDOWN
                    f2 = FORMANTPLOTWIDTH - (formant[1] /
                                             SCALEDOWN) + XSHIFT + XOFFSET
                    if f2 - 100 > XSHIFT and f1 + 100 < FORMANTPLOTHEIGHT - YSHIFT:
                        self.formantPlotCanvas.create_oval(
                            f2 - 100 - 2,
                            f1 + 100 - 2,
                            f2 - 100 + 2,
                            f1 + 100 + 2,
                            fill='yellow',
                            tags="loadedformants")
        except IndexError:
            print ""

    '''
        Displays/hides a specified aspect of the formant plot presentation.
	Arguments: boolean - true/false indicates whether the plot should display/hide the specified thing.
		    tag - the thing that is going to be displayed/hidden.
	
        def togglePlot(self,boolean,tag):
                if boolean:
                    self.formantPlotCanvas.itemconfig(tag, state='normal')
                else:
                    self.formantPlotCanvas.itemconfig(tag, state='hidden')
        
     '''

    def executeSpacebarInput(self, event):
        if self.isRecording == False:
            self.record()
        else:
            self.stop()
示例#9
0
class FormantPlot:

    """
        Initialise the formant plot.
        Arguments: parent - the widget that the formant plot is contained in.
                   path - the directory path where the application is in.
                   root - the Tk widget which is the base of all the other widgets.
                   gender - user's gender
        """

    def __init__(self, parent, path, root, gender, id):

        self.root = root
        self.parent = parent
        self.gender = gender
        self.appDirectory = path
        self.id = id

        self.setUpWidgets()

        self.getGoldStandardMonophthongs(path)
        self.drawGoldStandardMonophthongs(id)
        self.drawFormantPlotAxes()
        self.drawFormantPlotLegend()

        self.initialiseSounds()
        # self.initialiseKeyboardShortcuts()

        self.isRecording = False
        self.previousF1 = 0
        self.previousF2 = 0

    """
        Initialises all the widgets that are associated with the formant plot.
        """

    def setUpWidgets(self):

        self.formantPlotFrame = Frame(self.parent, width=FORMANTPLOTFRAMEWIDTH, height=FORMANTPLOTFRAMEHEIGHT)
        self.formantPlotFrame.grid()

        self.formantPlotCanvas = SnackCanvas(
            self.formantPlotFrame, height=FORMANTPLOTHEIGHT, width=FORMANTPLOTWIDTH, bg="white"
        )
        self.formantPlotCanvas.grid(row=0, column=0)

        self.loudnessMeterCanvas = SnackCanvas(self.formantPlotFrame, height=FORMANTPLOTHEIGHT, width=10)
        self.loudnessMeterCanvas.grid(row=0, column=1)

        self.formantPlotControlFrame = Frame(self.formantPlotFrame)
        self.formantPlotControlFrame.grid(row=1, column=0, sticky="w" + "e", columnspan=2)

        self.formantPlotControlFrame.columnconfigure(0, minsize=FORMANTPLOTWIDTH / 3)
        self.formantPlotControlFrame.columnconfigure(1, minsize=FORMANTPLOTWIDTH / 3)
        self.formantPlotControlFrame.columnconfigure(2, minsize=FORMANTPLOTWIDTH / 3)

        self.recButton = ttk.Button(
            self.formantPlotControlFrame, text="Record", command=self.record, style="Fun.TButton"
        )
        self.recButton.grid(row=1, column=0, sticky="w" + "e", padx=10)
        self.stopButton = ttk.Button(
            self.formantPlotControlFrame, text="Stop", command=self.stop, state="disabled", style="Fun.TButton"
        )
        self.stopButton.grid(row=1, column=1, sticky="w" + "e", padx=10)

        self.clearScreenButton = ttk.Button(
            self.formantPlotControlFrame,
            text="Clear Plot",
            command=self.clearUserFormants,
            state="normal",
            style="Fun.TButton",
        )
        self.clearScreenButton.grid(row=1, column=2, sticky="w" + "e" + "n" + "s")

        self.loudnessMeter = LoudnessMeter(self.loudnessMeterCanvas)

    """
        Creates the Snack Sound objects used in the formant plot.
        """

    def initialiseSounds(self):
        initializeSnack(self.root)
        self.recordedAudio = Sound()
        self.soundCopy = Sound()
        self.loadedAudio = Sound()

    def initialiseKeyboardShortcuts(self):
        self.root.bind("<space>", self.executeSpacebarInput)

    """
        Draw the axes for the formant plot.
        """

    def drawFormantPlotAxes(self):
        self.formantPlotCanvas.create_line(
            XSHIFT, FORMANTPLOTHEIGHT - YSHIFT, FORMANTPLOTWIDTH, FORMANTPLOTHEIGHT - YSHIFT, tags="formantAxes"
        )
        for y in range(0, FORMANTPLOTHEIGHT - YSHIFT, 20):
            self.formantPlotCanvas.create_line(XSHIFT - 8, 0 + y, XSHIFT, 0 + y, tags="formantAxes")
        self.formantPlotCanvas.create_line(XSHIFT, 0, XSHIFT, FORMANTPLOTHEIGHT - YSHIFT, tags="formantAxes")
        for x in range(0, 900, 20):
            self.formantPlotCanvas.create_line(
                XSHIFT + x, FORMANTPLOTHEIGHT - YSHIFT, XSHIFT + x, FORMANTPLOTHEIGHT - YSHIFT + 8
            )
        self.formantPlotCanvas.create_text(
            (XSHIFT + FORMANTPLOTWIDTH) / 2,
            FORMANTPLOTHEIGHT - YSHIFT + 25,
            text="Tongue Position",
            font=("Arial", "13"),
            tags="formantAxes",
        )
        self.formantPlotCanvas.create_text(
            XSHIFT + 22, FORMANTPLOTHEIGHT - YSHIFT + 20, text="Front", font=("Arial", "13"), tags="formantAxes"
        )
        self.formantPlotCanvas.create_text(
            FORMANTPLOTWIDTH - 30,
            FORMANTPLOTHEIGHT - YSHIFT + 20,
            text="Back",
            font=("Arial", "13"),
            tags="formantAxes",
        )
        self.formantPlotCanvas.create_text(
            XSHIFT / 2, (FORMANTPLOTHEIGHT - YSHIFT) / 2, text="Mouth", font=("Arial", "13"), tags="formantAxes"
        )
        self.formantPlotCanvas.create_text(
            XSHIFT / 2,
            ((FORMANTPLOTHEIGHT - YSHIFT) / 2) + 20,
            text="Openness",
            font=("Arial", "13"),
            tags="formantAxes",
        )
        self.formantPlotCanvas.create_text(
            XSHIFT / 2, FORMANTPLOTHEIGHT - YSHIFT - 20, text="Open", font=("Arial", "13"), tags="formantAxes"
        )
        self.formantPlotCanvas.create_text(XSHIFT / 2, 20, text="Closed", font=("Arial", "13"), tags="formantAxes")

    def drawFormantPlotLegend(self):
        font = ("Arial", "13")
        self.formantPlotCanvas.create_oval(
            FORMANTPLOTWIDTH - 160 - 3, 10 - 3, FORMANTPLOTWIDTH - 160 + 3, 10 + 3, tag="legend", fill="black"
        )
        self.formantPlotCanvas.create_text(FORMANTPLOTWIDTH - 80, 10, text="Recorded Vowels", tag="legend", font=font)
        self.formantPlotCanvas.create_oval(
            FORMANTPLOTWIDTH - 160 - 3, 30 - 3, FORMANTPLOTWIDTH - 160 + 3, 30 + 3, tag="legend", fill="red"
        )
        self.formantPlotCanvas.create_text(FORMANTPLOTWIDTH - 80, 30, text="Loaded Vowels", tag="legend", font=font)

    def appendData(self, pat, str):
        MonophthongDataPath = os.path.join(pat, str)
        MonophthongFile = open(MonophthongDataPath, "r")

        MonophthongData = []

        # Code from ywan478 2010 SoftEng206 Project
        # Load in the monophthong data for males
        for monophthongDataLine in MonophthongFile:
            monophthongDataLine = monophthongDataLine.split()

            # F1 mean and standard deviation
            monophthongDataLine[0] = int(float(monophthongDataLine[0])) / SCALEDOWN
            monophthongDataLine[1] = int(float(monophthongDataLine[1])) / SCALEDOWN

            # F2 mean and standard deviation
            monophthongDataLine[2] = (
                FORMANTPLOTWIDTH - (int(float(monophthongDataLine[2])) / SCALEDOWN) + XSHIFT + XOFFSET
            )
            monophthongDataLine[3] = int(float(monophthongDataLine[3])) / SCALEDOWN

            MonophthongData.append(monophthongDataLine)
        # End code from ywan478

        return MonophthongData

    """
	Loads the monophthong data.
	Arguments: path - directory path of where the application is stored in.
	"""

    def getGoldStandardMonophthongs(self, path):
        # Initialise the male data
        self.maleMonophthongData = self.appendData(path, "data\maori\monDataMale.txt")
        self.maleMonophthongData1 = self.appendData(path, "data\maori\monDataMaleYoung.txt")

        # Initialise the female data
        self.femaleMonophthongData = self.appendData(path, "data\maori\monDataFemale.txt")
        self.femaleMonophthongData1 = self.appendData(path, "data\maori\monDataFemaleYoung.txt")

    """
        Draw the gold standard monophthong data into the formant plot.
	Arguments: gender - gender of the user. True if male. False if female.
	"""

    def drawGoldStandardMonophthongs(self, id):

        if id == 0:
            data = self.maleMonophthongData
            for f1mean, f1sd, f2mean, f2sd, vowel in data:
                font = ("Arial", "20", "bold")
                self.formantPlotCanvas.create_oval(
                    (f2mean - f2sd) * 1.5 - 400,
                    (f1mean - f1sd) * 2 - 100,
                    (f2mean + f2sd) * 1.5 - 400,
                    (f1mean + f1sd) * 2 - 100,
                    outline="black",
                    tag="ellipses",
                )
                self.formantPlotCanvas.create_text(
                    f2mean * 1.5 - 400, f1mean * 2 - 100, fill="red", font=font, tag="ellipseLabel", text=vowel
                )
        elif id == 1:
            data = self.maleMonophthongData1
            for f1mean, f1sd, f2mean, f2sd, vowel in data:
                font = ("Arial", "20", "bold")
                self.formantPlotCanvas.create_oval(
                    (f2mean - f2sd) * 1.5 - 400,
                    (f1mean - f1sd) * 2.7 - 300,
                    (f2mean + f2sd) * 1.5 - 400,
                    (f1mean + f1sd) * 2.7 - 300,
                    outline="black",
                    tag="ellipses",
                )
                self.formantPlotCanvas.create_text(
                    f2mean * 1.5 - 400, f1mean * 2.7 - 300, fill="red", font=font, tag="ellipseLabel", text=vowel
                )
        elif id == 2:
            data = self.femaleMonophthongData
            for f1mean, f1sd, f2mean, f2sd, vowel in data:
                font = ("Arial", "20", "bold")
                self.formantPlotCanvas.create_oval(
                    (f2mean - f2sd) * 1.2 - 130,
                    (f1mean - f1sd) * 1.8 - 130,
                    (f2mean + f2sd) * 1.2 - 130,
                    (f1mean + f1sd) * 1.8 - 130,
                    outline="black",
                    tag="ellipses",
                )
                self.formantPlotCanvas.create_text(
                    f2mean * 1.2 - 130, f1mean * 1.8 - 130, fill="red", font=font, tag="ellipseLabel", text=vowel
                )
        else:
            data = self.femaleMonophthongData1
            for f1mean, f1sd, f2mean, f2sd, vowel in data:
                font = ("Arial", "20", "bold")
                self.formantPlotCanvas.create_oval(
                    (f2mean - f2sd) * 1.5 - 330,
                    (f1mean - f1sd) * 2.7 - 300,
                    (f2mean + f2sd) * 1.5 - 330,
                    (f1mean + f1sd) * 2.7 - 300,
                    outline="black",
                    tag="ellipses",
                )
                self.formantPlotCanvas.create_text(
                    f2mean * 1.5 - 330, f1mean * 2.7 - 300, fill="red", font=font, tag="ellipseLabel", text=vowel
                )
        # Code from ywan478 2010 SoftEng206 Project

    # End code from ywan478

    """
        Plots the last formant of the recording sound into the formant plot.
        Arguments: sound - the sound that is being recorded.
        """

    def plotFormants(self, sound):

        probabilityOfVoicing = SoundProcessing.getProbabilityOfVoicing(sound, False)

        if probabilityOfVoicing == 1.0:

            formants = SoundProcessing.getFormants(sound, self.gender, False)

            # Only plot the latest formants of the sound if there's a good chance that it is the user speaking instead of background noise.
            if formants != None:

                latestF1 = formants[0] / SCALEDOWN
                latestF2 = FORMANTPLOTWIDTH - (formants[1] / SCALEDOWN) + XSHIFT + XOFFSET

                if self.id == 0:
                    latestF2 = latestF2 * 1.5 - 400
                    latestF1 = latestF1 * 2 - 100
                elif self.id == 1:
                    latestF2 = latestF2 * 1.5 - 400
                    latestF1 = latestF1 * 2.7 - 300
                elif self.id == 2:
                    latestF2 = latestF2 * 1.2 - 130
                    latestF1 = latestF1 * 1.8 - 130
                elif self.id == 3:
                    latestF2 = latestF2 * 1.5 - 330
                    latestF1 = latestF1 * 2.7 - 300

                if latestF2 > XSHIFT and latestF1 < FORMANTPLOTHEIGHT - YSHIFT:
                    self.formantPlotCanvas.create_oval(
                        latestF2 - 2, latestF1 - 2, latestF2 + 2, latestF1 + 2, fill="black", tags="userformants"
                    )

            if not self.isRecording:
                if formants != None:
                    print ""

    """
        Update the loudness level in the loudness meter.
        Arguments: sound - the sound that is currently being recorded.
        """

    def updateLoudnessMeter(self, sound):
        try:
            self.loudnessMeter.updateMeter(sound)

        except IndexError:
            print "No sound available to get loudness yet"

    """
        Update the formant plot and loudness meter if the user is still recording.
        """

    def updateAllCanvases(self):
        self.soundCopy.copy(self.recordedAudio)
        SoundProcessing.crop(self.soundCopy)
        self.plotFormants(self.soundCopy)
        self.updateLoudnessMeter(self.soundCopy)
        if self.isRecording:
            self.root.after(30, self.updateAllCanvases)

    """
        Clears the user's formant data from the formant plot.
        """

    def clearUserFormants(self):
        self.formantPlotCanvas.delete("userformants")

    """
        Clears the gold standard data from the formant plot.
        """

    def clearGoldStandard(self):
        self.formantPlotCanvas.delete("ellipseLabel")
        self.formantPlotCanvas.delete("ellipses")

    """
        Redraws the gold standard data on the formant plot if the user's gender is changed.
        Arguments: gender - user's gender.
        """

    def updateGoldStandard(self, id):
        self.clearGoldStandard()
        self.drawGoldStandardMonophthongs(id)

    def updateGender(self, gender):
        self.gender = gender

    def play(self, sound, id):
        sound.play(blocking=True)

    """
        Stops the recording.
        """

    def stop(self):

        self.recordedAudio.stop()
        self.recButton.config(state="normal")
        self.stopButton.config(state="disabled")
        self.isRecording = False
        self.root.after(200, self.loudnessMeter.clearMeter)

    """
	Start recording the user's sounds and make the formant plot react accordingly.
	"""

    def record(self):  # Record sound file
        self.clearUserFormants()
        self.recordedAudio.record()
        self.isRecording = True
        self.recButton.config(state="disabled")
        self.stopButton.config(state="normal")

        self.root.after(200, self.updateAllCanvases)

    """
        Saves the latest recording from the user.
        """

    def save(self):
        saveName = tkFileDialog.asksaveasfilename(defaultextension=".wav")
        self.recordedAudio.write(saveName, start=0, end=-1)

    def loadAudioFile(self):
        filename = tkFileDialog.askopenfilename(initialdir=self.appDirectory)

        self.formantPlotCanvas.delete("loadedformants")

        self.loadedAudio.config(load=filename)
        # self.playLoadButton.config(state='normal')
        loadedFormants = SoundProcessing.getFormants(self.loadedAudio, self.gender, True)
        probabilityOfVoicingList = SoundProcessing.getProbabilityOfVoicing(self.loadedAudio, True)
        self.formantPlotCanvas.delete("loadedformants")
        try:
            for i in range(0, len(loadedFormants)):
                probabilityOfVoicing = probabilityOfVoicingList[i]
                if probabilityOfVoicing == 1.0:
                    formant = loadedFormants[i]
                    f1 = formant[0] / SCALEDOWN
                    f2 = FORMANTPLOTWIDTH - (formant[1] / SCALEDOWN) + XSHIFT + XOFFSET
                    if f2 - 100 > XSHIFT and f1 + 100 < FORMANTPLOTHEIGHT - YSHIFT:
                        self.formantPlotCanvas.create_oval(
                            f2 - 100 - 2, f1 + 100 - 2, f2 - 100 + 2, f1 + 100 + 2, fill="yellow", tags="loadedformants"
                        )
        except IndexError:
            print ""

    """
        Displays/hides a specified aspect of the formant plot presentation.
	Arguments: boolean - true/false indicates whether the plot should display/hide the specified thing.
		    tag - the thing that is going to be displayed/hidden.
	
        def togglePlot(self,boolean,tag):
                if boolean:
                    self.formantPlotCanvas.itemconfig(tag, state='normal')
                else:
                    self.formantPlotCanvas.itemconfig(tag, state='hidden')
        
     """

    def executeSpacebarInput(self, event):
        if self.isRecording == False:
            self.record()
        else:
            self.stop()
示例#10
0
class VowelPlot:
    def __init__(self, parent, path, root, id, formApp, vowelScorer, vowel,
                 width, height):
        configValues = VowelFileHandler.getDataFromFile()
        self.centreOval = configValues[0]
        self.middleOval = configValues[1]
        self.outerOval = configValues[2]
        self.targetSizeRatio = configValues[3]

        self.axisButtonClicked = False
        self.vowelScorer = vowelScorer
        self.width = width
        self.height = height
        self.root = root
        self.formApp = formApp
        self.parent = parent
        self.path = path
        self.id = id
        self.vowel = vowel
        self.hasPlots = False

        self.hasScore = False
        self.firstTime = True
        #plot Setup:
        self.setupPlot()

        self.plottedInfo = [0, 0, 0, 0, 0]

        self.prevX = 0
        self.prevY = 0
        # sound Setup:
        self.initialiseSounds()
        self.Recording = False
        self.Waiting = False

        self.drawTarget(vowel)

    '''
    switchCoorSystems is a function which converts coordinates in the vowel space
    into the target space. Its purpose is to remove the need for individual functions
    to handle there own shifting and scaling.

    This is done via first reflecting in the x Axis, then shifting so the
    new top left corner is at the origin of the target space.

    Then scales to the width and height of the target space.
    '''

    def switchCoorSystems(self, x, y):
        #Reflex in Y Axis
        x = (-1) * x

        #calculate vowel space size
        xSize, ySize = self.vowelSpaceSize()

        #calculate shifts
        xShift, yShift = self.calculateShift(xSize, ySize)

        #shift coords onto the target space origin.
        x = x + xShift + xSize  # + as we reflected in x, which means to get to the 1st Quadrant(in the target coord system) we need to add its width
        y = y - yShift  # - as we do not need to reflect in y, do to the nature of the python canvas already have small at the top and large at the bottom as required.

        #As the target space coord system is our normal x,y coord system just reflected in x.
        #scale
        xScale, yScale = self.calculateScale(xSize, ySize)
        x = x * xScale
        y = y * yScale

        return x, y

    def vowelSpaceSize(self):
        return self.outerOval * 2 * self.f2sd * (
            1 / self.targetSizeRatio), self.outerOval * 2 * self.f1sd * (
                1 / self.targetSizeRatio)

    def calculateShift(self, xSize, ySize):
        #XSHIFT
        topLeftXCoord = self.f2mean - xSize / 2
        #YSHIFT
        topLeftYCoord = self.f1mean - ySize / 2
        return topLeftXCoord, topLeftYCoord

    def calculateScale(self, xSize, ySize):
        #xScale
        xScale = self.width / xSize
        #yScale
        yScale = self.height / ySize
        return xScale, yScale

    def setupPlot(self):
        #Plot
        self.vowelPlotFrame = self.parent
        self.vowelPlotCanvas = Canvas(self.vowelPlotFrame,
                                      height=self.width,
                                      width=self.height,
                                      bg='white')
        self.vowelPlotCanvas.delete('Loudness')
        self.vowelPlotCanvas.delete('toLoud')
        self.vowelPlotCanvas.delete('toQuiet')
        self.vowelPlotCanvas.pack(fill='both', expand=1)

        #Creates the loudnessMeter on the formant plot canvas.
        self.loudnessMeter = LoudnessMeter(self.vowelPlotCanvas, YSHIFT)
        font = ('Arial', '14')
        boxWidth = 150
        self.font = font
        x1 = (self.height / 2) - (boxWidth)
        y1 = 2
        x2 = (self.height / 2)
        y2 = 32
        self.recordingBox = self.vowelPlotCanvas.create_rectangle(
            x1, y1, x2, y2, tag='recording', fill='red', outline='white')
        self.recordingBoxText = self.vowelPlotCanvas.create_text(
            (x1 + x2) / 2, (y1 + y2) / 2,
            tag='recordingText',
            text='Recording.',
            font=font,
            fill='black')
        self.vowelPlotCanvas.itemconfig('recording', state='hidden')
        self.vowelPlotCanvas.itemconfig('recordingText', state='hidden')

        x1 = (self.height / 2)
        y1 = 2
        x2 = (self.height / 2) + boxWidth
        y2 = 32
        self.recordingBox = self.vowelPlotCanvas.create_rectangle(
            x1, y1, x2, y2, tag='Loudness', outline='black')
        self.recordingBoxText = self.vowelPlotCanvas.create_text(
            (x1 + x2) / 2, (y1 + y2) / 2,
            tag='toLoud',
            text='Too Loud.',
            font=font,
            fill='black')
        self.recordingBoxText = self.vowelPlotCanvas.create_text(
            (x1 + x2) / 2, (y1 + y2) / 2,
            tag='toQuiet',
            text='Too Quiet.',
            font=font,
            fill='black')

        self.vowelPlotCanvas.itemconfig('Loudness', state='hidden')
        self.vowelPlotCanvas.itemconfig('toLoud', state='hidden')
        self.vowelPlotCanvas.itemconfig('toQuiet', state='hidden')

    def createText(self):
        self.vowelPlotCanvas.delete('helptext')
        self.vowelPlotCanvas.delete('tophelptext')

        self.vowelPlotCanvas.create_text(self.width / 2,
                                         self.height - 50,
                                         tag='helptext',
                                         font=self.font,
                                         text="Click on the target to begin.")
        self.vowelPlotCanvas.create_text(
            self.width / 2,
            self.height - 30,
            tag='helptext',
            font=self.font,
            text="After 250 Plots the round will finish.")
        self.vowelPlotCanvas.create_text(self.width / 2,
                                         10,
                                         tag='tophelptext',
                                         font=self.font,
                                         text="Choose a Vowel to practice.")

    def setUpButtonsFirstTime(self):
        self.vowelPlotCanvas.delete("firstButtons")
        font = ('Arial', '20')
        vowel = ['a:', 'e:', 'i:', 'o:', 'u:']

        aButton = Button(self.parent,
                         text=vowel[0],
                         font=font,
                         command=lambda vow=vowel[0]: self.changeVowel(vow))
        aButton.configure(activebackground="#FA4A4A", relief=GROOVE)
        aButtonWindow = self.vowelPlotCanvas.create_window(self.width / 2 -
                                                           160,
                                                           50,
                                                           window=aButton,
                                                           tags="firstButtons")

        eButton = Button(self.parent,
                         text=vowel[1],
                         font=font,
                         command=lambda vow=vowel[1]: self.changeVowel(vow))
        eButton.configure(activebackground="#FA4A4A", relief=GROOVE)
        eButtonWindow = self.vowelPlotCanvas.create_window(self.width / 2 - 80,
                                                           50,
                                                           window=eButton,
                                                           tags="firstButtons")

        iButton = Button(self.parent,
                         text=vowel[2] + " ",
                         font=font,
                         command=lambda vow=vowel[2]: self.changeVowel(vow))
        iButton.configure(activebackground="#FA4A4A", relief=GROOVE)
        iButtonWindow = self.vowelPlotCanvas.create_window(self.width / 2,
                                                           50,
                                                           window=iButton,
                                                           tags="firstButtons")

        oButton = Button(self.parent,
                         text=vowel[3],
                         font=font,
                         command=lambda vow=vowel[3]: self.changeVowel(vow))
        oButton.configure(activebackground="#FA4A4A", relief=GROOVE)
        oButtonWindow = self.vowelPlotCanvas.create_window(self.width / 2 + 80,
                                                           50,
                                                           window=oButton,
                                                           tags="firstButtons")

        uButton = Button(self.parent,
                         text=vowel[4],
                         font=font,
                         command=lambda vow=vowel[4]: self.changeVowel(vow))
        uButton.configure(activebackground="#FA4A4A", relief=GROOVE)
        uButtonWindow = self.vowelPlotCanvas.create_window(self.width / 2 +
                                                           160,
                                                           50,
                                                           window=uButton,
                                                           tags="firstButtons")

        if self.vowel == 'a:':
            aButton.config(bg='#FA4A4A', relief="sunken")
        elif self.vowel == 'e:':
            eButton.config(bg='#FA4A4A', relief="sunken")
        elif self.vowel == 'i:':
            iButton.config(bg='#FA4A4A', relief="sunken")
        elif self.vowel == 'o:':
            oButton.config(bg='#FA4A4A', relief="sunken")
        elif self.vowel == 'u:':
            uButton.config(bg='#FA4A4A', relief="sunken")

        analysisButton = Button(self.parent,
                                text="    Analysis    \nand\ngo back",
                                command=self.requestQuit,
                                font=('Arial', '15'))
        analysisButton.configure(activebackground='#FA4A4A',
                                 anchor=W,
                                 relief=GROOVE)
        analysisButtonWindow = self.vowelPlotCanvas.create_window(
            4,
            self.height - 4,
            anchor=SW,
            tags=('analysisButton', 'firstButtons'),
            window=analysisButton)

    def requestQuit(self):
        self.formApp.quitApp()

    #handles the Resizing of the application and all its child. currently disabled.
    def onResize(self, width, height):

        self.width = width
        self.height = height

        self.drawTarget(self.vowel)
        self.createText()

        self.setUpButtonsFirstTime()
        #rebind configure event being fired from root changes.
        if (self.hasScore):
            self.redrawScore()

        if (self.hasPlots):
            self.replotFormants()

    def changeVowel(self, vowel):
        self.formApp.loadVowelPlot(self.id, vowel, self.width, self.height)

    """
    setUpScore Sets the current score to be 0, creates the score text.
    """

    def setUpScore(self):
        self.hasScore = True
        font = ('Arial', '18')
        self.vowelPlotCanvas.delete('score')
        self.textID = self.vowelPlotCanvas.create_text(self.width / 2,
                                                       self.height - 60,
                                                       font=font,
                                                       tag='score',
                                                       text=" ---- %")
        self.score = 0
        self.rawScore = 0
        self.scoreCounter = 0

    def redrawScore(self):
        font = ('Arial', '18')
        self.vowelPlotCanvas.delete('score')
        if self.score == 0:
            scoreText = ' ---- %'
        else:
            scoreText = (str)(self.score) + " %"

        self.textID = self.vowelPlotCanvas.create_text(
            self.width / 2,
            self.height - (60 * (self.height / DEFAULTHEIGHT)),
            tag='score',
            font=font,
            text=scoreText)

    def updateScore(self, score):
        self.hasScore = True
        self.scoreCounter += 1
        self.rawScore += score
        self.score = (int)((float)(self.rawScore) / (float)(self.scoreCounter))
        scoreText = (str)(self.score) + " %"
        self.vowelPlotCanvas.itemconfig(self.textID, text=scoreText)

    def displayFinalScore(self, score):
        scoreText = "Score: " + (str)(score) + " %"
        self.vowelPlotCanvas.itemconfig(self.textID, text=scoreText)
        self.score = score
        self.vowelPlotCanvas.itemconfig('Loudness', state='hidden')
        self.vowelPlotCanvas.itemconfig('toLoud', state='hidden')
        self.vowelPlotCanvas.itemconfig('toQuiet', state='hidden')

    '''
    Converts a distance on the vowel space to score.
    '''

    def distanceToScore(self, xCoord, yCoord):
        self.plottedInfo[0] += 1
        x, y = self.switchCoorSystems(xCoord, yCoord)
        distance = ((x - self.width / 2)**2 + (y - self.height / 2)**2)**0.5
        scoringZoneDistance = distance - self.width * self.targetSizeRatio * 0.5 * self.centreOval / self.outerOval
        scoringZone = self.width * self.targetSizeRatio * 0.5 - self.width * self.targetSizeRatio * 0.5 * self.centreOval / self.outerOval
        if distance < self.width * self.targetSizeRatio * 0.5 * self.centreOval / self.outerOval:
            score = 100
        elif distance < self.width * self.targetSizeRatio * 0.5:
            self.plottedInfo[1] += 1
            score = (1 - (scoringZoneDistance / scoringZone)) * 100
        else:
            self.plottedInfo[1] -= 1
            return 0

        self.updateScore((int)(score))

    def drawTarget(self, letter):
        self.vowelPlotCanvas.delete("vowelOval")
        id = self.id
        font = ('Arial', '20')

        data = self.goldStandardDiphthongs(id)
        for f1mean, f1sd, f2mean, f2sd, vowel in data:
            if vowel == letter:
                vowel = letter

                self.f1sd = f1sd
                self.f2sd = f2sd
                self.f1mean = f1mean
                self.f2mean = f2mean
                xSd, ySd = self.switchCoorSystems(f2sd, f1sd)

                #DistanceTo OuterOval
                self.xIdeal = self.outerOval * xSd
                self.yIdeal = self.outerOval * ySd

                #MEAN
                self.x = self.width / 2
                self.y = self.height / 2
                colour = ['#ADD8E6', '#ff4c4c', '#ffff66']
                activeColour = ['#DFFFFF', '#ff7f7f', '#ffff99']
                i = 0
                for scale in [
                        self.outerOval, self.middleOval, self.centreOval
                ]:

                    x1, y1 = self.switchCoorSystems(f2mean - scale * f2sd,
                                                    f1mean - scale * f1sd)
                    x2, y2 = self.switchCoorSystems(f2mean + scale * f2sd,
                                                    f1mean + scale * f1sd)
                    self.vowelPlotCanvas.create_oval(
                        x1,
                        y1,
                        x2,
                        y2,
                        outline='black',
                        tag='vowelOval',
                        fill=colour[i],
                        activefill=activeColour[i])
                    i += 1
                self.vowelPlotCanvas.create_text(self.width / 2,
                                                 self.height / 2,
                                                 fill='#00007f',
                                                 font=font,
                                                 tag='vowelOval',
                                                 text=vowel)
                self.vowelPlotCanvas.tag_bind(
                    'vowelOval', "<Button-1>",
                    lambda event, : self.toggleRecord(event))

                self.vowelPlotCanvas.delete('questionMarkButton')
                self.questionMarkButton = Button(self.parent,
                                                 text=" Show Axis",
                                                 command=self.showAxisClicked,
                                                 font=('Arial', '13'))
                self.questionMarkButton.configure(activebackground='#FA4A4A',
                                                  bg='white',
                                                  anchor=W,
                                                  relief=GROOVE)
                questionMarkButtonWindow = self.vowelPlotCanvas.create_window(
                    self.width - 2,
                    self.height - 2,
                    anchor=SE,
                    tags=('questionMarkButton'),
                    window=self.questionMarkButton)
                self.questionMarkButton.bind("<Enter>", self.showAxisHoovering)
                self.questionMarkButton.bind("<Leave>", self.hideAxisHoovering)

                self.drawAxis()

    def showAxisHoovering(self, *args):
        if not self.axisButtonClicked:
            self.questionMarkButton.config(relief=SUNKEN)
            self.showAxis()

    def hideAxisHoovering(self, *args):
        if not self.axisButtonClicked:
            self.questionMarkButton.config(relief=GROOVE, bg='white')
            self.hideAxis()

    def showAxisClicked(self, *args):
        if self.axisButtonClicked:
            self.questionMarkButton.config(bg='white')

            self.hideAxis
            self.axisButtonClicked = False
        else:
            self.questionMarkButton.config(relief=SUNKEN, bg='#FA4A4A')
            self.showAxis
            self.axisButtonClicked = True

    def showAxis(self):
        self.vowelPlotCanvas.itemconfig('axis', state='normal')

    def hideAxis(self):
        self.vowelPlotCanvas.itemconfig('axis', state='hidden')

    def drawAxis(self):
        xSd, ySd = self.switchCoorSystems(self.f2sd, self.f1sd)
        self.vowelPlotCanvas.delete('axis')
        axisFont = ('Arial', '13')

        #Draw y Axis
        xAxis = self.width / 2
        yAxis1 = (self.height /
                  2) - self.targetSizeRatio * self.height / 2 - 25
        yAxis2 = (self.height /
                  2) - self.targetSizeRatio * self.height * self.centreOval / (
                      self.outerOval * 2)
        yAxis3 = (self.height /
                  2) + self.targetSizeRatio * self.height * self.centreOval / (
                      self.outerOval * 2)
        yAxis4 = (self.height /
                  2) + self.targetSizeRatio * self.height / 2 + 25

        self.vowelPlotCanvas.create_line(xAxis,
                                         yAxis1,
                                         xAxis,
                                         yAxis2,
                                         tags='axis',
                                         width=2)
        self.vowelPlotCanvas.create_line(xAxis,
                                         yAxis3,
                                         xAxis,
                                         yAxis4,
                                         tags='axis',
                                         width=2)

        # for index in range(2,10):
        #     yCoor = index * ((self.yIdeal*self.outerOval)/10)
        #     self.vowelPlotCanvas.create_line( xAxis, self.height/2 + yCoor, xAxis-6, self.height/2 + yCoor, tags = 'axis', width = 2)
        #     self.vowelPlotCanvas.create_line( xAxis, self.height/2 - yCoor, xAxis-6, self.height/2 - yCoor, tags = 'axis', width = 2)

        self.vowelPlotCanvas.create_text(xAxis + 10,
                                         yAxis1 - 15,
                                         text="Mouth Less Open",
                                         tags='axis',
                                         font=axisFont,
                                         anchor=CENTER)
        self.vowelPlotCanvas.create_text(xAxis + 10,
                                         yAxis4 + 10,
                                         text="Mouth More Open",
                                         tags='axis',
                                         font=axisFont,
                                         anchor=CENTER)

        #ArrowHead y
        self.vowelPlotCanvas.create_polygon(
            (self.width / 2, yAxis4 + 3, self.width / 2 - 10, yAxis4 - 17,
             self.width / 2 + 10, yAxis4 - 17),
            tags='axis',
            fill='#000000')
        self.vowelPlotCanvas.create_polygon(
            (self.width / 2, yAxis1 - 3, self.width / 2 - 10, yAxis1 + 17,
             self.width / 2 + 10, yAxis1 + 17),
            tags='axis',
            fill='#000000')

        #Draw x Axis
        yAxis = self.height / 2
        xAxis1 = (self.width / 2) - self.targetSizeRatio * self.width / 2 - 25
        xAxis2 = (self.width /
                  2) - self.targetSizeRatio * self.width * self.centreOval / (
                      self.outerOval * 2)
        xAxis3 = (self.width /
                  2) + self.targetSizeRatio * self.width * self.centreOval / (
                      self.outerOval * 2)
        xAxis4 = (self.width / 2) + self.targetSizeRatio * self.width / 2 + 25
        self.vowelPlotCanvas.create_line(xAxis1,
                                         yAxis,
                                         xAxis2,
                                         yAxis,
                                         tags='axis',
                                         width=2)
        self.vowelPlotCanvas.create_line(xAxis3,
                                         yAxis,
                                         xAxis4,
                                         yAxis,
                                         tags='axis',
                                         width=2)

        # for index in range(2,10):
        #     xCoor = index * ((self.xIdeal*self.outerOval)/10)
        #     self.vowelPlotCanvas.create_line(self.width/2 + xCoor, yAxis, self.width/2 + xCoor, yAxis+6,tags = 'axis', width = 2)
        #     self.vowelPlotCanvas.create_line(self.width/2 - xCoor, yAxis, self.width/2 - xCoor, yAxis+6,tags = 'axis', width = 2)

        self.vowelPlotCanvas.create_text(xAxis4 + 40,
                                         yAxis - 20,
                                         text="Tongue",
                                         tags='axis',
                                         font=axisFont,
                                         anchor=CENTER)
        self.vowelPlotCanvas.create_text(xAxis4 + 40,
                                         yAxis,
                                         text="Less",
                                         tags='axis',
                                         font=axisFont,
                                         anchor=CENTER)
        self.vowelPlotCanvas.create_text(xAxis4 + 40,
                                         yAxis + 20,
                                         text="Forward",
                                         tags='axis',
                                         font=axisFont,
                                         anchor=CENTER)

        self.vowelPlotCanvas.create_text(xAxis1 - 40,
                                         yAxis - 20,
                                         text="Tongue",
                                         tags='axis',
                                         font=axisFont,
                                         anchor=CENTER)
        self.vowelPlotCanvas.create_text(xAxis1 - 40,
                                         yAxis,
                                         text="More",
                                         tags='axis',
                                         font=axisFont,
                                         anchor=CENTER)
        self.vowelPlotCanvas.create_text(xAxis1 - 40,
                                         yAxis + 20,
                                         text="Forward",
                                         tags='axis',
                                         font=axisFont,
                                         anchor=CENTER)

        #ArrowHead x
        self.vowelPlotCanvas.create_polygon(
            (xAxis1 - 3, self.height / 2, xAxis1 + 17, self.height / 2 - 10,
             xAxis1 + 17, self.height / 2 + 10),
            tags='axis',
            fill='#000000')
        self.vowelPlotCanvas.create_polygon(
            (xAxis4 + 3, self.height / 2, xAxis4 - 17, self.height / 2 - 10,
             xAxis4 - 17, self.height / 2 + 10),
            tags='axis',
            fill='#000000')

        if self.axisButtonClicked:
            self.vowelPlotCanvas.itemconfig('axis', state='normal')
            self.questionMarkButton.config(relief=SUNKEN, bg='#FA4A4A')

        else:
            self.vowelPlotCanvas.itemconfig('axis', state='hidden')
            self.questionMarkButton.config(relief=GROOVE, bg='white')

    def toggleRecord(self, event):
        if self.Recording:
            self.stop()
        else:
            self.record()

    def goldStandardDiphthongs(self, id):
        path = self.path
        if id == 0:
            data = self.appendData(path, 'data\maori\longVowelNativeMale.txt')
        elif id == 1:
            data = self.appendData(path, 'data\maori\longVowelModernMale.txt')
        elif id == 2:
            data = self.appendData(path,
                                   'data\maori\longVowelNativeFemale.txt')
        elif id == 3:
            data = self.appendData(path,
                                   'data\maori\longVowelModernFemale.txt')
        return data

    """
    appendData retrieves the data from the longVowelFile for a langType and voiceType.
    This code was edited from code written by ywan478 during his SoftEng206 Project 2010.
    """

    def appendData(self, path, str):
        longVowelDataPath = os.path.join(path, str)
        longVowelFile = open(longVowelDataPath, 'r')
        longVowelData = []
        #Load in the longVowel data
        for longVowelDataLine in longVowelFile:
            longVowelDataLine = longVowelDataLine.split()
            #F1 mean and standard deviation
            longVowelDataLine[0] = (float)(longVowelDataLine[0])
            longVowelDataLine[1] = (float)(longVowelDataLine[1])
            #F2 mean and standard deviation
            longVowelDataLine[2] = (float)(longVowelDataLine[2])
            longVowelDataLine[3] = (float)(longVowelDataLine[3])
            longVowelData.append(longVowelDataLine)
        return longVowelData

#***********************************************************************************************************
# Sound

    '''
    Creates the Snack Sound objects used in the formant plot.
    '''
    def initialiseSounds(self):
        tkSnack.initializeSnack(self.root)
        self.recordedAudio = Sound()
        self.soundCopy = Sound()
        self.loadedAudio = Sound()

    """
    Plot Fomrants takes a sound file and plots the last formant in the file.
    """

    def plotFormants(self, sound):
        #SCALEREFIXTHIS
        self.hasPlots = True

        self.vowelPlotCanvas.delete('arrow')
        #Gets the probablity of sound being a voice for the last formant in the sound file. (false means last formant, true means all formants)
        probabilityOfVoicing = SoundProcessing.getProbabilityOfVoicing(
            sound, False)

        if True:  #probabilityOfVoicing == 1.0:
            formant = SoundProcessing.getFormants(sound, self.id, False)

            #Only plot the latest formants of the sound if there's a good chance that it is the user speaking instead of background noise.
            if formant != None:
                radius = 3
                color = 'black'

                yFormant = formant[0]
                xFormant = formant[1]

                (x, y) = self.switchCoorSystems(xFormant, yFormant)

                #Remove some background noise.
                if ((self.prevX - x)**2 + (self.prevY - y)**2)**0.5 < 28:

                    self.vowelPlotCanvas.create_oval(x - radius,
                                                     y - radius,
                                                     x + radius,
                                                     y + radius,
                                                     fill=color,
                                                     tags="userformants")

                    self.xFormantList.append(xFormant)
                    self.yFormantList.append(yFormant)

                    self.plotCount += 1

                    if self.plotCount > 250:
                        self.stop()
                        #self.root.after(100 , self.displayFinalScore)

                    self.distanceToScore(xFormant, yFormant)

                    if (abs(y - self.y) > self.height):
                        pass

                self.prevX = x
                self.prevY = y

    def replotFormants(self):
        #SCALEREFIXTHIS
        self.vowelPlotCanvas.delete("userformants")
        color = 'black'
        radius = 3
        for index in range(len(self.xFormantList)):
            xFormant = self.xFormantList[index]
            yFormant = self.yFormantList[index]
            (x, y) = self.switchCoorSystems(xFormant, yFormant)
            self.vowelPlotCanvas.create_oval(x - radius,
                                             y - radius,
                                             x + radius,
                                             y + radius,
                                             fill=color,
                                             tags="userformants")

    """
    record is called whent eh record button is pressed it starts recording the users sounds
    and makes the formant plot react accordingly.
    """

    def record(self):
        try:
            if self.vowelScorer.safeToRecord():
                self.Recording = True
                self.Waiting = False
                self.vowelPlotCanvas.itemconfig('questionMarkButton',
                                                state='hidden')
                self.formApp.preventResizing()
                self.xFormantList = []
                self.yFormantList = []
                self.recordedAudio = Sound()
                self.clear()

                self.plotCount = 0
                self.notStopped = True
                self.vowelPlotCanvas.itemconfig('waitingText', state='hidden')
                #self.vowelPlotCanvas.itemconfig('axis', state='normal')
                self.vowelPlotCanvas.itemconfig('analysisButton',
                                                state='hidden')
                self.vowelPlotCanvas.itemconfig('firstButtons', state='hidden')
                self.vowelPlotCanvas.itemconfig('recording', state='normal')
                self.vowelPlotCanvas.itemconfig('Loudness', state='hidden')
                self.vowelPlotCanvas.itemconfig('tophelptext', state='hidden')
                self.vowelPlotCanvas.itemconfig('helptext', state='hidden')
                self.vowelPlotCanvas.itemconfig('score', state='hidden')

                self.recordedAudio.record()
                self.count2 = 0

                self.vowelPlotCanvas.itemconfig('recording',
                                                state='normal',
                                                fill='orange')
                self.vowelPlotCanvas.itemconfig('recordingText',
                                                state='normal',
                                                text='Loading...')

                #LOADING AXIS.

                thread.start_new_thread(self.multiThreadUpdateCanvas,
                                        ("Thread-1", self.notStopped))
            else:
                print "Not SafeToRecord, please Wait..."
        except Exception:
            self.requestQuit()

    def multiThreadUpdateCanvas(self, threadName, notStopped):
        sleep(1.2)
        self.setUpScore()
        self.isLoading = False
        #self.vowelPlotCanvas.itemconfig('axis', state='hidden')
        self.vowelPlotCanvas.itemconfig('score', state='normal')

        try:
            self.vowelPlotCanvas.itemconfig('recording', fill='red')
            self.vowelPlotCanvas.itemconfig('recordingText', text='Recording')
            while self.notStopped:
                self.count2 += 1
                self.soundCopy.copy(self.recordedAudio)
                SoundProcessing.crop(self.soundCopy)
                self.plotFormants(self.soundCopy)
                if self.count2 % 10 == 0:
                    self.updateLoudnessMeter(self.soundCopy)
        except Exception:
            import traceback
            print traceback.format_exc()

    def stop(self):
        if self.vowelScorer.safeToRecord():

            self.notStopped = False
            self.vowelPlotCanvas.itemconfig('recording', state='hidden')
            self.vowelPlotCanvas.itemconfig('recordingText', state='hidden')
            self.vowelPlotCanvas.itemconfig('waitingText', state='normal')
            self.vowelPlotCanvas.itemconfig('toLoud', state='hidden')
            self.vowelPlotCanvas.itemconfig('toQuiet', state='hidden')
            self.vowelPlotCanvas.itemconfig('Loudness', state='hidden')
            self.vowelPlotCanvas.itemconfig('analysisButton', state='normal')
            self.vowelPlotCanvas.itemconfig('firstButtons', state='normal')
            self.vowelPlotCanvas.itemconfig('tophelptext', state='hidden')
            self.vowelPlotCanvas.itemconfig('helptext', state='hidden')
            self.vowelPlotCanvas.itemconfig('score', state='normal')
            self.vowelPlotCanvas.itemconfig('questionMarkButton',
                                            state='normal')
            self.recordedAudio.stop()
            self.root.after(100, self.loudnessMeter.clearMeter)
            self.Recording = False
            self.Waiting = True
            self.vowelScorer.updateScore(self.vowel, self.rawScore,
                                         self.plottedInfo)
            self.rawScore = 0
            self.plotCounter = 0
            self.plottedInfo = [0, 0, 0, 0, 0]
            self.root.after(500, self.requestFinalScore)
            self.vowelPlotCanvas.itemconfig('toLoud', state='hidden')
            self.vowelPlotCanvas.itemconfig('toQuiet', state='hidden')
            self.vowelPlotCanvas.itemconfig('Loudness', state='hidden')

    def requestFinalScore(self):
        self.displayFinalScore(self.vowelScorer.getLastScore())
        self.vowelPlotCanvas.itemconfig('toLoud', state='hidden')
        self.vowelPlotCanvas.itemconfig('toQuiet', state='hidden')
        self.vowelPlotCanvas.itemconfig('Loudness', state='hidden')

    def clear(self):
        self.vowelPlotCanvas.delete('userformants')
        self.hasPlots = False

    def updateLoudnessMeter(self, sound):
        try:
            self.loudnessMeter.updateMeter(sound)

        except IndexError:
            print "No sound available to get loudness yet"