#
# hello.mic.45.py
#
# plot microphone audio
#
# Neil Gershenfeld
# CBA MIT 10/28/07
#
# (c) Massachusetts Institute of Technology 2007
# Permission granted for experimental and personal use;
# license for commercial sale available from MIT
#

from Tkinter import *
import serial
import numpy
import scipy


NY = 500
barwidth = 100
nloop = 190
NX = nloop
nstart = 10
path = []
avgAmplitude = 0
avgZero = 0
maxPlotAmplitude = 80.0/1024.0
smoothCount = 12
smoothFreq = scipy.zeros(smoothCount)
freqConfidences = scipy.zeros(smoothCount)

def idle(parent,canvas):
   global path
   global smoothFreq
   global freqConfidences
   #
   # idle routine
   #
   # look for framing
   #
   byte2 = 0
   byte3 = 0
   byte4 = 0
   while 1:
      byte1 = byte2
      byte2 = byte3
      byte3 = byte4
      byte4 = ord(ser.read())
      if ((byte1 == 1) & (byte2 == 2) & (byte3 == 3) & (byte4 == 4)):
         break
   path = []
   valArray = []
   for i in range(nstart):
      lo = ord(ser.read())
      hi = ord(ser.read())
   avgAmplitude = 0
   avgZero = 0
   for i in range(nloop):
      lo = ord(ser.read())
      hi = ord(ser.read())
      reading = 256*hi + lo
      val = reading/1024.0
      valArray.append(val)
      # collect a running average to compute the zero line
      avgZero = (avgZero*i + val)/(i+1)
      amplitude = abs(val - avgZero)
      avgAmplitude = (avgAmplitude*i + amplitude)/(i+1)
      plotLocation = NY*(1.0-val)
      path.append(3*i)
      path.append(plotLocation)
   if avgAmplitude > maxPlotAmplitude:
      plotAmplitude = maxPlotAmplitude
   elif avgAmplitude < 0:
      plotAmplitude = 0
   else:
      plotAmplitude = avgAmplitude
   plotLocAvg = NY*(1.0-avgZero)
   avgLine = [0,plotLocAvg,3*nloop,plotLocAvg]
   canvas.delete("path")
   canvas.create_line(path,tag="path",width=3,fill="#00b000")
   canvas.delete("avgLine")
   canvas.create_line(avgLine,tag="avgLine",width=1,fill="#ff0000")
   y = (0.9 - 0.9*plotAmplitude/maxPlotAmplitude)*NY
   canvas.itemconfigure("ampValue", text="%1.5f" % avgAmplitude)
   canvas.coords('ampRed',3*NX,0,3*NX+barwidth,y)
   canvas.coords('ampBlue',3*NX,y,3*NX+barwidth,0.9*NY)

   freqData = scipy.fft(valArray).real
   freqNormalizer = freqData[0] / 10
   freqData = freqData[1:scipy.floor(nloop/2)]
   freqPath = []
   for i in range(freqData.size):
      freqPath.append(6*i)
      plotLocation = NY*(1.0 - (freqData[i] / freqNormalizer) )
      freqPath.append(plotLocation)
   canvas.delete("freqPath")
   canvas.create_line(freqPath,tag="freqPath",width=3,fill="#0000b0")


   # We attempt to smooth out the display of the dominant frequency by
   # averaging recent results. This is a weighted average with a stronger
   # weight given to those that had greater amplitude
   dominantFreq = scipy.argmax(freqData)
   confidence = freqData[dominantFreq]
   freqConfidences = numpy.concatenate((freqConfidences[1:], scipy.array([confidence])))
   
   dominantFreq = 1.0*dominantFreq / (freqData.size)
   #smoothFreq.append(dominantFreq)
   smoothFreq = numpy.concatenate((smoothFreq[1:], scipy.array([dominantFreq])))

   confidenceWeights = freqConfidences / freqConfidences.sum()
   weightedAvg = confidenceWeights * smoothFreq
   
   #dominantFreq = smoothFreq.mean()
   dominantFreq = weightedAvg.sum()
   y = (0.9 - 0.9*dominantFreq)*NY
   canvas.itemconfigure("freqValue", text="%1.5f" % dominantFreq)
   canvas.coords('freqRed',3*NX+barwidth,0,3*NX+2*barwidth,y)
   canvas.coords('freqBlue',3*NX+barwidth,y,3*NX+2*barwidth,0.9*NY)
   
   
   canvas.update()
   parent.after_idle(idle,parent,canvas)

#
# open serial port
#
#ser = serial.Serial('/dev/ttyS0',115200)
ser = serial.Serial('/dev/ttyUSB0',115200)
ser.setDTR()
#
# start plotting
#
root = Tk()
root.title('hello.mic.45.py')
root.bind('q','exit')
canvas = Canvas(root, width=3*NX+2*barwidth, height=NY, background='white')

canvas.create_rectangle(3*NX,0,3*NX+barwidth,.9*NY, tags='ampBlue', fill='#1000d0')
canvas.create_rectangle(3*NX,.9*NY,3*NX+barwidth,.9*NY, tags='ampRed', fill='#c03000')
canvas.create_rectangle(3*NX,.9*NY,3*NX+barwidth,NY, tags='amptextbox', fill='#eeeeee')
canvas.create_text(3*NX+barwidth/2,.95*NY,text="Amplitude",font=("Helvetica", 12),tags="ampLabel",fill="#000000")
canvas.create_text(3*NX+barwidth/2,.85*NY,text="0",font=("Helvetica", 12),tags="ampValue",fill="#ffffff")

canvas.create_rectangle(3*NX+barwidth,0,3*NX+2*barwidth,.9*NY, tags='freqBlue', fill='#1000d0')
canvas.create_rectangle(3*NX+barwidth,.9*NY,3*NX+2*barwidth,.9*NY, tags='freqRed', fill='#c03000')
canvas.create_rectangle(3*NX+barwidth,.9*NY,3*NX+2*barwidth,NY, tags='freqtextbox', fill='#eeeeee')
canvas.create_text(3*NX+3*barwidth/2,.95*NY,text="Freq.",font=("Helvetica", 12),tags="freqLabel",fill="#000000")
canvas.create_text(3*NX+3*barwidth/2,.85*NY,text="0",font=("Helvetica", 12),tags="freqValue",fill="#ffffff")

canvas.pack()
root.after(100,idle,root,canvas)
root.mainloop()