How to Make Anything

well, almost...

Week 12: Interface and Aplication Programming

I continued my input device from a couple weeks ago (the piano circuit), and extented the Tkinter load sense python file so that you can visually see what note is being played. I never fully fixed the bugs in my circuit, so it doesn't work quite like I'd want it to, but the basic idea is here.

  • Assignment: Write an application that interfaces with an input and/or output device
  • Made: piano player
  • Programs Used: Python (Tkinter)
  • Tools Used: None

#tbt

The piano board from a couple weeks ago. The 2 2x2 headers on the right hand side are the 8 sense pins that are used to connect to 8 keys and play notes.

Cardbaord piano

I'd like to eventually mill out my piano, so it looks more professional, but I decided to first make a cardboard version to test things out. I just grabbed some cardboard, cut out 8 pieces of copper tape, put them on the board, and connected the 8 individual wires to the keys with electrical tape.

All together

My C code from a couple weeks ago programs the circuit so that each pin sense it's number (0 to 7), followed by the value that pin is reading. I then made a python file that reads these identifying numbers, then checks the next number to see if it's less than some threshold value -- this means that the pin has been touched.

from Tkinter import *
import serial
import winsound

WINDOW = 300 # window size
WIDTH = 2*WINDOW
HEIGHT = WINDOW
eps = 0.5 # filter time constant
filters = [0] * 8
values = [0]*8
sounds = [261,293,329,349,392,440,494,523]

def idle(parent,canvas):
   global eps
   ser.flush()

   while True:
      key = ord(ser.read())
      if key < len(values):
         values[key] = ord(ser.read())
      if key == 7: # last value to be read in a sequence
         break
   for i in range(8):
      canvas.delete("text" + str(i))
      if values[i] < 100:
         canvas.create_text(.125*WIDTH*(i+.5),.95*HEIGHT,text=str(values[i]),font=("Helvetica", 24),tags="text" + str(i),fill="#b00000")
         if i != 4 and i != 6: # 4 and 6 don't seem to be working :(
            winsound.Beep(sounds[i],75)
            canvas.create_rectangle(.125*i*WIDTH,.1*HEIGHT,.125*i*WIDTH+.125*WIDTH,.9*HEIGHT, tags='rect' + str(i), fill='#b00000')
      else:
         canvas.create_text(.125*WIDTH*(i+.5),.95*HEIGHT,text=str(values[i]),font=("Helvetica", 24),tags="text" + str(i),fill="#0000b0")
         canvas.create_rectangle(.125*i*WIDTH,.1*HEIGHT,.125*i*WIDTH+.125*WIDTH,.9*HEIGHT, tags='rect' + str(i), fill='#0000b0')

   parent.after_idle(idle,parent,canvas)

port = 'COM5'#sys.argv[1]
#
# open serial port
#
ser = serial.Serial(port,9600)
ser.setDTR()
#
# set up GUI
#
root = Tk()
root.title('piano.py (q to exit)')
root.bind('q','exit')
canvas = Canvas(root, width=WIDTH, height=HEIGHT, background='white')
canvas.create_text(.5*WIDTH,.05*HEIGHT,text="circuit piano",font=("Helvetica", 24),tags="title",fill="#0000b0")
for i in range(8):
   #x0, y0, x1, Y1
   canvas.create_text(.125*WIDTH*(i+.5),.95*HEIGHT,text=str(i),font=("Helvetica", 24),tags="text" + str(i),fill="#0000b0")
   canvas.create_rectangle(.125*i*WIDTH,.1*HEIGHT,.125*i*WIDTH+.125*WIDTH,.9*HEIGHT, tags='rect' + str(i), fill='#0000b0')

canvas.pack()
#
# start idle loop
#
root.after(100,idle,root,canvas)
root.mainloop()

Almost there

The sensing seems to be noisy unfortunately. I think I'll change the C or python code so that it smooths this out, turning a key "on" or "off" based on multiple timesteps instead of one. I also need to double check the connection for keys 4 and 6, as they didn't seem to work consistenly (and are ignored in the code). I ran the python file with an octave of notes (looked up the frequencies online), so it just does a beep for each key pressed. This could easily be changed to play any music file instead, like real piano notes, or bird calls. Really, anything.