fwb@siemens.UUCP (09/03/86)
How do you program the sound on an IBM AT or XT? The technical reference manual does not help much. The PLAY and SOUND instructions of BASIC are not useful in a C program. (No, I don't want to fork BASICA to make a beep :-) Would somebody send me the port address and values for different notes, or a simple C program, or a simple Pascal program, or some other helpful program which does not rely on library routines to do the real work. If there is sufficient interest I will summarize the most useful information to the net. Thanks, Fred ----------------------------------------------------- Frederic W. Brehm (ihnp4!princeton!siemens!fwb) Siemens Research and Technology Laboratories 105 College Road East Princeton, NJ 08540 (609) 734-3336
thj@hpcnof.UUCP (Thomas Hjellming) (09/04/86)
>How do you program the sound on an IBM AT or XT? The technical reference >manual does not help much. The PLAY and SOUND instructions of BASIC are not >useful in a C program. (No, I don't want to fork BASICA to make a beep :-) > >Would somebody send me the port address and values for different notes, or a >simple C program, or a simple Pascal program, or some other helpful program >which does not rely on library routines to do the real work. If there is >sufficient interest I will summarize the most useful information to the net. > >Thanks, >Fred The 'Programmers Guide to the IBM PC' by Peter Norton contains an entire chapter about sound generation on the PC family. It contains all the information you are requesting. Tom Hjellming Colorado Networks Division Hewlett-Packard ihnp4!hpfcla!thj
wtm@neoucom.UUCP (Bill Mayhew) (09/05/86)
The following information is based on Appendix H of the book, "C Primer Plus"; Waite, Prata & Martin; Sams Books. I. The speaker is connected to an 8255 Parallel Interface Controller chip in an IBM xt. It should be in the same place on true clones. The port number for the speaker connection is 97 decimal. (Anyone know if the 8255 is in the same place on the AT?, I'm pretty sure it is.) II. Bits 0 and 1 of the above port both have to be set to logic state 1 to move the cone of the speaker in and conversely, setting those bits to 0 reverses the direction of the cone. III. Note that the above register is bidirectional. The keyboard strobe and cassette motor are also hooked there, so you want to preserve the state of the bits other than the ones you are playing with. IV. The basic process is something like: for (duration = tone_length; duration > 0; duration--) { state = inp(97) ^ 0x03; */complement lower 2 bits /* outp(97, state); for (clik_wdth = pitch_const; clik_wdth >0; clik_wdth--){ */waste some time /* }; } V. Obviously, the sound that you get with the above is going to be processor speed dependent. What you can do is in the initialization part of your program is to call the DOS time interrupt (sorry don't remember the number at the moment) and then count to some big number in a tight loop (10,000 would be good). Call the dos time interrupt again and see how long it took you to count. You'll then know the clock speed of the processor that you are running on. It's easiest to have a table of note valuse for "pitch_const" already calculated before hand, and have the results of your test select the correct table. In theory, you could count the number of CPU cycles in your loop, and thus you'd be able to compute the table values so that you could normalize to weirdo clock speeds. VI. There is also an 8253 Counter/Timer chip in a Pee-cee that you can use to set the durrations of things. See the book I referenced for instructions on using the 8253. On the XT, the 8253 counts down at a rate of 1.190 MHz. Beware that the counting rate is a little faster on the original models of PC. I suppose it is something odd on ATs as well, but I haven't had any reason to check. VII. Of course, if you could care less about what pitch you're making just send a 0x07 (control G) with the DOS console print interrupt. Normally DOS will take care of beeping the speaker for you. I don't normally hack C for a living, so I apologise if there are any typos in the C example I stuck in. I think you get the gist of it any way, right? --Bill Bill Mayhew Division of Basic Medical Sciences Northeastern Ohio Universities College of Medicine Rootstown, OH 44272 USA (216) 325-2511 (wtm@neoucom.UUCP)
bright@dataio.UUCP (Walter Bright) (09/08/86)
In article <960003@hpcnof.UUCP> thj@hpcnof.UUCP (Thomas Hjellming) writes: >>How do you program the sound on an IBM AT or XT? The technical reference >>manual does not help much. The PLAY and SOUND instructions of BASIC are not >>useful in a C program. (No, I don't want to fork BASICA to make a beep :-) > The 'Programmers Guide to the IBM PC' by Peter Norton contains >an entire chapter about sound generation on the PC family. It contains >all the information you are requesting. Also, try 'Bluebook of Assembly Routines for the IBM PC and XT' by Christopher L. Morgan.
mlandau@Diamond.BBN.COM (Matt Landau) (09/08/86)
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 <stdio.h> XX#include <stdtypes.h> 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 <stdio.h> XX#include <stdtypes.h> 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