PC compatibles have a built-in capability to make sounds and music via the
small speaker attached to the system board.  This feature is very limited,
but creative programmers have performed miracles in the past, producing
beeps and squawks for games and even producing recognizable speech.

  BIOS Support  
The only BIOS-supported sound can be produced via INT 10H 0eH (Write
Character as TTY), passing AL=07H, to output a standard beep.

  Hardware Control  
The speaker is connected to PPI port B, port 61H (see PPI Ports).  Set
bit 1 to pulse the speaker out and clear bit 1 it to bring the speaker
back to normal.  For instance,

in    al,61H     ;get current value

again: or    al,02H     ;set bit 2 to pulse it out
out   61H, al

mov   cx,1000H
delay: loop  delay      ;wait a little while

and   al,0fdH    ;clear bit 2 to pulse it back in
out   61H, al
jmp   again

By pulsing it in and out at a given frequency, a specific tone is
produced.  The above example produces various tones, depending upon
the speed of the CPU.

For better control, you can use the PC internal timer to pulse it of and
on at a given frequency.  Timer channel 2 can be gated directly to the
speaker.  To make a specific tone:

1) Program timer channel 2 to output a square-wave pulse at the desired
frequency by writing b6H to port 43H.  Then output a divisor word to
port 42H (do that by writing first the low then the high byte -- see

The divisor word is a 16-bit value which, when divided into the
timer's frequency (1.19318 MHz), selects the desired output
frequency.  For instance, middle C has a frequency of about 261 Hz.
To obtain that output, use a divisor of 4560 (1,193,180/261 = 4560).

2) Enable the speaker by setting bit 1 of I/O port 61H.

3) Gate the channel-2 timer output into the speaker by setting bit 0 of
I/O port 61H.

4) After a while (say, half of a second), disable the speaker by
clearing bits 0-1 of I/O port 61H.

Step 4, above, determines the duration of the tone.  The standard way to
set the duration is by watching the tick count at 0040:006c in the
BIOS Data Area and counting the number of 55ms-interval that occur.  The
timer-tick interrupt occurs 18.2 times per second, so (for instance) 9
timer ticks occur in about 1/2 of a second.

On ATs, a more accurate duration can be obtained by using the BIOS timer
support.  See INT 15H 86H and INT 15H 8300H.  Another way to improve
accuracy has been used in the past by the orginal PC's BASIC:  It sped up
the standard timer tick by a factor of four whenever music was being
played.

  Example  
For instance...

mov   al,  0b6H
out   43H, al
mov   al,  0d0H   ;low-byte of divisor (11d0H = 4560 = middle C)
out   42H, al
mov   al,  11H    ;high-byte of divisor word
out   42H, al

in    al,  61H    ;get current value of PPI
or    al,  03H    ;send timer output to speaker and enable speaker
out   61H, al

mov   cx,  0007H  ;high-word for AT INT 15H (wait) service
mov   dx,  0a120H ;low-word  (0007a120H = 500,000ms = 1/2-second)
mov   ah,  86H
int   15H         ;see INT 15H 86H (wait)

in    al,  61H    ;get current value of PPI
and   al,  0fcH   ;clear bits 0 and 1
out   61H, al     ;turn off the speaker

...plays middle C for one half of a second.

See Also: Timer Ports
- -

PC Sounds / Speaker Support