a3nm's blog

Playing a note with the PC speaker on Linux

— updated

At some point, I needed to design a command that you could use to play a note (identified by its scientific pitch notation) on the PC speaker. For instance, I would like to play an A-sharp, 3rd octave on the speaker with:

play_note 'a#3'

For this, we need the beep program which allows us to beep the PC speaker at a given frequency. We then need something to go from "a#3" to the frequency of that particular note (233.081879 Hz in this case). The main point of this post is actually to advertise a2freq, a small tool that I wrote to do precisely this, ie. convert scientific pitch notation to a frequency. It also supports MIDI note numbers (which it uses as an intermediate representation), if you ever need to convert a MIDI file to a beep sequence... For instance:

$ a2freq a4

Hopefully the next person who needs to do this can land here and save half an hour by using this code rather than writing it.

To put the pieces together, we can now define play_note as:

beep ${@:1:$(($#-1))} -f `a2freq ${!#}`

The complex crap that you see here is used to make it possible to pass additional arguments to beep, so that you can play a 100-millisecond A with:

play_note -l 100 a

The last parameter is taken to be a note, the rest is passed to beep. (Another decent solution would have been to play multiple arguments as a note sequence, rather than just playing one note and passing all previous arguments to beep.)

One caveat of this: sometimes frequencies get rounded in a bad way, meaning that the notes aren't right. This isn't a2freq's fault; it might be beep's, the kernel's, or the hardware's. On my machine, a#5 and b5 sound the same because of that. So don't assume that this will always work.

comments welcome at a3nm<REMOVETHIS>@a3nm.net