This one was just for fun; the article describes a project used to build a simple piano keyboard that plays some not too terrific sounding notes, courtesy of the Kernel32.dll’s
beep function. Whilst the notes are set to be roughly the correct frequency, the sound produced will not encourage you to sell your piano and take up a new career as a concert computer keyboardist. On the other hand, it is fun to mess with, and likely it would be entertaining for someone in the 8 year old range (at least, if you were not within earshot when the entertaining begins).
Figure 1: A Small Keyboard
I suppose that if you were to look hard enough, you could probably come up with something useful that you can do with this keyboard (like annoy your cat). It could probably be turned into something instructional that could be used to teach someone the notes associated with the keys or some swell thing like that (of course, that may well take the fun out of messing with it). Further, if you were to dodge using the
beep function and use the
PlaySound function from the winmm.dll, and if you had access to recorded wave files for each of the notes played on the piano, you could probably come up with something that sounds a lot better, without losing all of the charm and elegant styling associated with this project.
In order to get started, unzip the attachment, and load the solution into Visual Studio 2005. Examine the Solution Explorer, and note that the project contains a class:
Figure 2: The Solution Explorer Showing the Project Files
The small keyboard project’s single class is a Windows form; that form contains a collection of buttons used to simulate the appearance (if not the sound) of a piano keyboard.
I’m sure that it seems inconceivable that this much raw power can be packed into a single class, but it is true; I just suppose that is part of the awe-inspiring thing we know as .NET. To have a look at the magic going on behind the scenes, open up the class into the code view window, and take a look. The first thing that you will note is that the code imports
System.Runtime.InteropServices. This is necessary to support the
DllImport function used in the first section of code following the class declaration:
Public Class frmKeyboard
Public Shared Sub Beep(ByVal freq As Integer, ByVal dur As Integer)
The DLL import call made here is used to bring the Kernel32.dll library into the project; the Kernel32.dll contains the
beep function, and it is through this function that we can produce our simulated musical notes through this project’s magnificent piano keyboard emulation. The
beep function mercifully accepts only two arguments, the frequency and the duration. In this application, we will pass in the frequency associated with a specific keyboard key (which is actually a
Float, so we have to crop it off to make it fly here). I think that you will agree that this loss of precision in no way impairs the quality of the audio output. The duration passed in to the second argument is the same for each of the keys, it is arbitrary and sounded about right for a quick strike on a keyboard key (at least it sounds right if you bought your keyboard on sale at the dollar store).
Now onto the next bit of magic; the button handlers. This bit of code makes it possible to produce beautiful strains of high quality music through the keyboard:
Private Sub Play_KeyDown(ByVal sender As Object, _
ByVal e As System.Windows.Forms.KeyEventArgs) _
Handles btnMC.KeyDown, btnHA.KeyDown, btnHAs.KeyDown, _
btnHB.KeyDown, btnHC.KeyDown, btnHCs.KeyDown, _
btnHD.KeyDown, btnHDs.KeyDown, btnHE.KeyDown, _
btnHF.KeyDown, btnHFs.KeyDown, btnHG.KeyDown, _
btnHGs.KeyDown, btnLA.KeyDown, btnLAs.KeyDown, _
btnLB.KeyDown, btnLC.KeyDown, btnLCs.KeyDown, _
btnLD.KeyDown, btnLDs.KeyDown, btnLE.KeyDown, _
btnLF.KeyDown, btnLFs.KeyDown, btnLG.KeyDown, _
btnLGs.KeyDown, btnMA.KeyDown, btnMAs.KeyDown, _
btnMB.KeyDown, btnMC.KeyDown, btnMCs.KeyDown, _
btnMD.KeyDown, btnMDs.KeyDown, btnME.KeyDown, _
btnMF.KeyDown, btnMFs.KeyDown, btnMG.KeyDown, _
Select Case e.KeyData.ToString()
Taking a look at this code, you will note that it handles all of the key down events associated with each of the buttons. A
Select Case statement is used to figure out which keyboard button was pressed, and that in turn is used to figure which button click event to evoke. The click event handler will then call the
beep function, and pass to it the correct frequency and the canned duration (but all your user will know is that they are making beautiful music).
Next up is the button click event handlers; since they are all pretty much the same, I will only show one in this document, the event handler for middle C:
Private Sub btnMC_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnMC.Click
As advertised, this event handler evokes the
beep function, and passes the frequency and duration arguments to that function. I set the duration on all of the keys to be 150 milliseconds, but you can use any value of your choosing.
The project demonstrates a few useful things like using the DLL Import function supported by the InteropServices library, but overall, it is just for fun.