The PC has an internal speaker which is capable of generating beeps of different frequencies. You control the speaker by providing a frequency number which determines the pitch of the beep, then turning the speaker on for the duration of the beep.
The frequency number you provide is actually a counter value. The PC uses it to determine how long to wait between sending pulses to the speaker. A smaller frequency number will cause the pulses to be sent quicker, resulting in a higher pitch. The PC uses a base rate of 1,193,180 Hz (this frequency is generated by an oscillator chip). The frequency number tells the PC how many of these cycles to wait before sending another pulse. Thus, you can calculate the frequency number required to generate a specific frequency by the following formula:
The frequency number is a word value, so it can take values between 0 and 65,535 inclusive. This means you can generate any frequency between 18.21 Hz (frequency number = 65,535) and 1,193,180 Hz (frequency number = 1).
Figure 10-1 is a diagram of the hardware for driving the built-in speaker. OUT2 is the output of Channel 2 of the 8253-5 timer chip, GATE2 (= bit 1 of port 61h) is the enable/trigger control for the Channel 2 counter, and SPEAKER DATA (= bit 0 of port 61h) is a line that may be used independently to modulate the output waveform, e.g., to control the speaker volume.
The count and load modes selected for Channel 2 during BIOS initialization are probably the best to use for tone production. In Mode 3, the counter output is a continuous symmetrical square wave as long as the GATE line of the channel is enabled; the other modes either produce outputs that are too asymmetrical or require retriggering for each count cycle.
The frequency count is loaded into the Channel 2 COUNT register at I/O port 42h. GATE2 (bit 1 of I/O port 61h) must be set to 1 to get an output on OUT2; the SPEAKER DATA line (bit 0 of I/O port 61h) must also be set to 1 to produce a tone. Note that the remaining bits of port 61h must not be changed since they control RAM enable, keyboard clock, etc. To silence the speaker, bits 1 or 0 of port 61h are set to 0 (without disturbing the remaining bits of port 61h).
You can communicate with the speaker controller using IN and OUT instructions. The following lists the steps in generating a beep:
Send the value 182 to port 43h. This sets up the speaker.
Send the frequency number to port 42h. Since this is an 8-bit port, you must use two OUT instructions to do this. Send the least significant byte first, then the most significant byte.
To start the beep, bits 1 and 0 of port 61h must be set to 1. Since the other bits of port 61h have other uses, they must not be modified. Therefore, you must use an IN instruction first to get the value from the port, then do an OR to set the two bits, then use an OUT instruction to send the new value to the port.
Pause for the duration of the beep.
Turn off the beep by resetting bits 1 and 0 of port 61h to 0. Remember that since the other bits of this port must not be modified, you must read the value, set just bits 1 and 0 to 0, then output the new value.
Another way to control the length of beeps is to use the timer interrupt. This gives you better control over the duration of the note and it also allows your program to perform other tasks while the note is playing.
The following table lists frequencies and frequency numbers for the three octaves around middle C on a piano keyboard.