Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!seismo!ut-sally!husc6!Diamond!mlandau From: mlandau@Diamond.BBN.COM (Matt Landau) Newsgroups: net.micro.pc Subject: Re: How do you beep? Message-ID: <704@Diamond.BBN.COM> Date: Mon, 8-Sep-86 16:02:14 EDT Article-I.D.: Diamond.704 Posted: Mon Sep 8 16:02:14 1986 Date-Received: Tue, 9-Sep-86 06:03:46 EDT References: <23900032@siemens.UUCP> <268@neoucom.UUCP> Reply-To: mlandau@Diamond.BBN.COM (Matt Landau) Organization: BBN Labs, Cambridge, MA Lines: 210 Summary: Code to drive the speaker for Lattice 2.X/3.X Since so many people have remarked on how to make noises with your IBM PC, I thought I'd just take the simple approach and post the necessary code. The following shar file contains sources for a routine called "sound" which will drive the speaker at a given frequency for a given time. It relies on a processor-independent sleep() call, for which source is also supplied. This code has been used on PC's, AT's, and Compaq's, compiled with Lattice 2.15, but there's no reason it shouldn't work with any Lattice 2.x or 3.x compiler. Conversion to other compilers is straightforward. Note that the sleep() here is not compatible with the Unix sleep() call, since this one works in 1/100's of a second. Herewith, the source code: ------- CUT HERE ------------------------------------ CUT HERE -------- # This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # # Wrapped by slate!mlandau on Mon Sep 8 15:55:25 EDT 1986 # Contents: stdtypes.h sleep.c sound.c echo x - stdtypes.h sed 's/^XX//' > "stdtypes.h" <<'@//E*O*F stdtypes.h//' XX/* XX * S T D T Y P E S . H XX */ XX#include "dos.h" XXtypedef int void; XXtypedef int bool; XXtypedef union REGS REGS; XXtypedef struct SREGS SREGS; @//E*O*F stdtypes.h// chmod u=rw,g=rw,o=r stdtypes.h echo x - sleep.c sed 's/^XX//' > "sleep.c" <<'@//E*O*F sleep.c//' XX/* XX * S L E E P . C XX * XX * Sleep () call for IBM PC, XT, AT. Depends on timer tick working as XX * advertised, 18.2 ticks per second. XX * XX * This uses int 1A to read the time-of-day clock. Care is taken to do XX * something reasonable when the clock rolls over at midnight, so sleep () XX * does not bomb late at night. XX */ XX#include XX#include XX#define TIMER_INT 0x1A XX#define T_READTIME 0 XX#define SCALE 1000L XX#define TICKRATE 182L /* timer tick rate/100th sec. x scale */ XX#define ROLLOVER 1 /* est. # of ticks when clock rolls over */ XX#define MKLONG(hi, low) ((long)(((long)hi << 16) | (unsigned)low)) XXvoid sleep (how_long) XXunsigned how_long; /* Hundredths of a second */ XX{ XX long this_tick, last_tick; XX long ticks = 0L; XX long count = (long)(TICKRATE * how_long / SCALE); XX REGS r; XX XX r.h.ah = T_READTIME; XX int86 (TIMER_INT, &r, &r); XX last_tick = MKLONG (r.x.cx, r.x.dx); XX XX while (ticks < count) XX { XX r.h.ah = T_READTIME; XX int86 (TIMER_INT, &r, &r); XX this_tick = MKLONG (r.x.cx, r.x.dx); XX /* If midnight just passed, assume ROLLOVER ticks */ XX ticks += (r.h.al == 0) ? this_tick - last_tick : ROLLOVER; XX last_tick = this_tick; XX } XX} @//E*O*F sleep.c// chmod u=rw,g=rw,o=r sleep.c echo x - sound.c sed 's/^XX//' > "sound.c" <<'@//E*O*F sound.c//' XX/* LINTLIBRARY */ XX/* XX * S O U N D . C XX * XX * Routines for manipulating the PC speaker. Since there is no BIOS XX * interrupt for sound, this code is probably NOT portable. It relies on XX * directly controlling the 8255 Programmable Peripheral Interface chip. XX * XX * For reference, I suggest you look at the PC Technical Reference Manual XX * and at a good book on 8088 assembly language (Scanlon's IBM PC & XT XX * ASSEMBLY LANGUAGE contains a section on programming the speaker.) XX */ XX#include XX#include XX#define HZ 1193180 /* system clock is 1.19 MHz */ XX#define T_BASE 0x40 /* 8253 timer port 0 */ XX#define T_TONE (T_BASE + 2) /* 8253 port 2 controls spkr */ XX#define T_CONTROL (T_BASE + 3) /* 8253 control port addr. */ XX#define TIMERDIV(freq) ((unsigned)(HZ/freq)) /* Timer divisior */ XX#define ENABLE_TIMER 182 /* MAGIC NUM from BIOS listing */ XX#define OUT_8255 0x61 /* 8255 PPI output port address */ XX#define SPKRBITS 3 /* Bit 0 = control spkr by timer */ XX /* Bit 1 = speaker on/off */ XXextern byte inp(), outp(); /* Read, write ports */ XX/* XX * spkr_on -- turn on the speaker XX */ XXstatic XXvoid spkr_on (divisor) XXunsigned divisor; XX{ XX byte status, div; XX XX status = inp (OUT_8255); /* get current status */ XX outp (T_CONTROL, ENABLE_TIMER); XX div = divisor & 0xFF; /* low byte of divisor */ XX outp (T_TONE, div); XX div = (divisor >> 8) & 0xFF; /* high byte of divisor */ XX outp (T_TONE, div); XX outp (OUT_8255, (status | SPKRBITS)); /* turn on speaker */ XX} XX/* XX * spkr_off -- turn off the speaker XX */ XXstatic XXvoid spkr_off () XX{ XX byte status; XX XX status = inp (OUT_8255); /* get current status */ XX outp (OUT_8255, (status & ~SPKRBITS)); /* turn speaker off */ XX} XX/* XX * sound (freq, dur) XX * XX * Make a noise of the given frequency (which may be 37 - 32767 Hz) for the XX * given duration, in tenths of a second. XX */ XX XXvoid sound (freq, dur) XXunsigned freq, dur; XX{ XX extern void sleep(); XX XX spkr_on (TIMERDIV (freq)); XX sleep (dur); XX spkr_off (); XX} XXvoid beep_low () XX{ XX sound (440, 15); XX} XXvoid beep () XX{ XX sound (660, 15); XX} XXvoid beep_high () XX{ XX sound (880, 15); XX} @//E*O*F sound.c// chmod u=rw,g=rw,o=r sound.c echo Inspecting for damage in transit... temp=/tmp/shar$$; dtemp=/tmp/.shar$$ trap "rm -f $temp $dtemp; exit" 0 1 2 3 15 cat > $temp <<\!!! 9 29 139 stdtypes.h 46 196 1183 sleep.c 107 425 2491 sound.c 162 650 3813 total !!! wc stdtypes.h sleep.c sound.c | sed 's=[^ ]*/==' | diff -b $temp - >$dtemp if [ -s $dtemp ] then echo "Ouch [diff of wc output]:" ; cat $dtemp else echo "No problems found." fi exit 0 -- Matt Landau BBN Laboratories, Inc. mlandau@diamond.bbn.com 10 Moulton Street, Cambridge MA 02238 ...harvard!diamond.bbn.com!mlandau (617) 497-2429