Piano

1  Getting the Frequencies for the Notes

After an internet search, I found the webpage http://www.phy.mtu.edu/ suits/notefreqs.html which has a table of notes and their frequencies. I scraped the data from the html with the following program:
x = readLines('http://www.phy.mtu.edu/~suits/notefreqs.html')

mylines = grep('<TD ALIGN=CENTER>',x,value=TRUE)
mylines = matrix(mylines,ncol=3,byrow=TRUE)[,-3]
mylines = apply(mylines,2,function(x)sub('<TD ALIGN=CENTER>(.*)</TD>','\\1',x))
mylines[,1] = sub('^([^0-9]+[0-9]).*$','\\1',mylines[,1])

notes = data.frame(gsub('</?su[pb]>','',mylines[,1]),as.numeric(mylines[,2]))
names(notes) = c('notes','freq')

library(sound)

thenotes = lapply(notes$freq,function(x)cutSampleEnds(Sawtooth(x,.3)))
names(thenotes) = notes$notes
save(thenotes,file='thenotes.rda')

It takes a bit of computation to set up all the notes properly, so I saved the list of notes that I created with the save command. This produces a binary representation of the data which R can load very quickly. So instead of reading and calculating the frequencies every time, I can quickly read them in when I need them.

2  The Piano

The first step is reading back the sounds stored in the last section using the load command. I wrote a little wrapper around the play command, because I needed to specify a program that was capable of playing back the .wav files generated by the play function that comes with the sound package. If you're going to run this on your own computer, you can try to call play without the command= argument, but you may have to find a command line program to play back the wave files.
Here's the program:

require(tcltk)
require(sound)

load('thenotes.rda')  # saved by the getfreq.r script

pnotes = c('C4','D4','E4','F4','G4','A4','B4','C5')

myplay = function(x)play(x,command='mplayer')

mfun = function(i){
   ii = i
   function(...)myplay(thenotes[[pnotes[ii]]])
}

main = tktoplevel()

black = tkframe(main)

tkpack(tklabel(black,width=2,height=4),side='left')
tkpack(tkbutton(black,width=2,height=4,bg='black',activebackground='black',command=function(...)myplay(thenotes[['C#4']])),side='left')
tkpack(tklabel(black,width=2,height=4),side='left')
tkpack(tkbutton(black,width=2,height=4,bg='black',activebackground='black',command=function(...)myplay(thenotes[['D#4']])),side='left')
tkpack(tklabel(black,width=7,height=4),side='left')
tkpack(tkbutton(black,width=2,height=4,bg='black',activebackground='black',command=function(...)myplay(thenotes[['F#4']])),side='left')
tkpack(tklabel(black,width=2,height=4),side='left')
tkpack(tkbutton(black,width=2,height=4,bg='black',activebackground='black',command=function(...)myplay(thenotes[['G#4']])),side='left')
tkpack(tklabel(black,width=2,height=4),side='left')
tkpack(tkbutton(black,width=2,height=4,bg='black',activebackground='black',command=function(...)myplay(thenotes[['A#4']])),side='left')
tkpack(tklabel(black,width=6,height=4),side='left')

tkpack(black)

white = tkframe(main)

for(i in 1:8)tkpack(tkbutton(white,width=4,height=8,command=mfun(i)),side='left')

tkpack(white)

I created the piano with two main frames, black and white, to hold the black keys and the white keys, respectively. To get (approximately) correct spacing of the black keys, I inserted empty labels between the buttons that represent the black keys. Each button has a command associated with it to play the note of the appropriate frequency.
Here's how the piano looks:



File translated from TEX by TTH, version 3.67.
On 13 Apr 2009, 15:42.