PC Sounds / Speaker Support

  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
      Timer Ports).

      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
          I/O Port Map
                                    -♦-