]> granicus.if.org Git - nethack/commitdiff
*** empty log message ***
authorjwalz <jwalz>
Sat, 5 Jan 2002 21:05:59 +0000 (21:05 +0000)
committerjwalz <jwalz>
Sat, 5 Jan 2002 21:05:59 +0000 (21:05 +0000)
sys/unix/snd86unx.shr [new file with mode: 0644]

diff --git a/sys/unix/snd86unx.shr b/sys/unix/snd86unx.shr
new file mode 100644 (file)
index 0000000..bfbae3f
--- /dev/null
@@ -0,0 +1,1064 @@
+# This is a shell archive.  Save it in a file, remove anything before
+# this line, and then unpack it by entering "sh file".  Note, it may
+# create directories; files and directories will be owned by you and
+# have default permissions.
+#
+# This archive contains:
+#
+#      READ.ME
+#      install.bsd
+#      spkr.7
+#      Makefile
+#      spkr.c
+#      spkr.h
+#      interp.c
+#      Files
+#      Install
+#      Master
+#      Name
+#      Node
+#      Remove
+#      Size
+#      System
+#      playtest
+#
+echo x - READ.ME
+sed 's/^X//' >READ.ME << 'END-of-READ.ME'
+X              Console Speaker Driver Package (v1.1)
+X
+X              by Eric S. Raymond (esr@snark.thyrsus.com)
+X
+XThis package gives 80386 machines running SVr3.2 or later the ability to play
+Xtunes on the console speaker.  It has been extended to 386BSD (and possibly
+XBSDI) by Andrew A. Chernov, and to SCO UNIX 3.2.4 (and possibly other VPIX
+Xsystems) by Andreas Arens.
+X
+XThe following files are contained in the kit:
+X
+XDocumentation and examples:
+XREAD.ME               -- this file
+Xspeaker.7     -- man page for the driver
+Xplaytest      -- test script exercising familiar tunes
+X
+XInstallable driver kit parts, for SVr3.2 or later:
+XFiles         -- list of driver package file locations
+XInstall               -- installation script for driver kit
+XMaster                -- mdevice entry for speaker driver
+XName          -- name entry foe speaker driver
+XNode          -- /dev node specification file
+XRemove                -- Driver removal script
+XSize          -- installation size data
+XSystem                -- sdevice entry for speaker driver
+X
+XDriver source code, for SVr3.2 or later and 386BSD:
+XMakefile      -- Makefile for driver code
+Xspkr.c                -- the driver source
+Xspeaker.h     -- ioctl interface file
+X
+XCommon source code:
+Xinterp.c      -- play string interpretation code
+X
+XFor SVr3.2 or later, simply type `make' and wait. Then type ./Install
+Xand follow its instructions. You will have to install the man pages by hand.
+XBe aware that the speaker.7 man page uses tbl(1) constructs.
+X
+XFor 386BSD, follow the installation instructions in install.bsd.
+X
+XFor SCO UNIX 3.2.4, no new kernel drivers are needed, and you need only
+Xcopy interp.c to your src directory and proceed with making NetHack, with
+XVPIX_MUSIC set in unixconf.h.
+X
+XInteresting tunes mailed to the author will be periodically posted in batches
+Xand added to the test script for future versions.
+X
+X                      Revision notes
+X
+X1.1 -- fixed minor bug in M[LSN] interpretation, added octave-tracking.
+X       Tweaked the playtest examples.
+END-of-READ.ME
+echo x - install.bsd
+sed 's/^X//' >install.bsd << 'END-of-install.bsd'
+XCopy spkr.c and interp.c to /sys/i386/isa
+XCopy spkr.h to /sys/sys
+X
+X-----------------------------------------------------------------------------
+X
+XFile /sys/i386/conf/YOUR_MACHINE_NAME
+Xadd following line:
+X
+Xpseudo-device   speaker
+X
+X-----------------------------------------------------------------------------
+X
+XFile /sys/i386/conf/files.i386
+Xadd following line:
+X
+Xi386/isa/spkr.c         optional speaker
+X
+X-----------------------------------------------------------------------------
+X
+XFile /sys/i386/i386/conf.c
+X[major number 20 (hex) is registered for spkr driver, don't change it]
+Xadd following code:
+X
+X#include "speaker.h"
+X#if NSPEAKER > 0
+Xint     spkropen(),spkrclose(),spkrwrite(),spkrioctl();
+X#else
+X#define spkropen  enxio
+X#define spkrclose enxio
+X#define spkrwrite enxio
+X#define spkrioctl enxio
+X#endif
+X      ...
+X
+Xstruct cdevsw cdevsw[] =
+X{
+X      ...
+X
+X      { spkropen,     spkrclose,      enxio,          spkrwrite,      /*20*/
+X        spkrioctl,    enxio,          enxio,          NULL,
+X        enxio,        enxio,          enxio },
+X      ...
+X
+X-----------------------------------------------------------------------------
+X
+XMake corresponding device:
+X
+X      mknod /dev/speaker c 32 0
+X
+X[major number 32 (20 hex) is registered for spkr driver, don't change it]
+X
+X-----------------------------------------------------------------------------
+X
+XGo to /sys/i386/conf and type
+X      config YOUR_MACHINE_NAME
+Xthen go to /sys/compile/YOUR_MACHINE_NAME and type
+X      make depend
+X      make
+X
+END-of-install.bsd
+echo x - spkr.7
+sed 's/^X//' >spkr.7 << 'END-of-spkr.7'
+X.TH SPKR 7
+X.SH NAME
+Xspkr \- console speaker device driver
+X.SH DESCRIPTION
+XThe speaker device driver allows applications to control the PC console
+Xspeaker on an IBM-PC-compatible machine running UNIX.
+X.PP
+XOnly one process may have this device open at any given time; open() and
+Xclose() are used to lock and relinquish it. An attempt to open() when
+Xanother process has the device locked will return -1 with an EBUSY error
+Xindication. Writes to the device are interpreted as 'play strings' in a
+Xsimple ASCII melody notation. An ioctl() for tone generation at arbitrary
+Xfrequencies is also supported.
+X.PP
+XSound-generation does \fInot\fR monopolize the processor; in fact, the driver
+Xspends most of its time sleeping while the PC hardware is emitting
+Xtones. Other processes may emit beeps while the driver is running.
+X.PP
+XApplications may call ioctl() on a speaker file descriptor to control the
+Xspeaker driver directly; definitions for the ioctl() interface are in
+Xsys/spkr.h. The tone_t structure used in these calls has two fields,
+Xspecifying a frequency (in hz) and a duration (in 1/100ths of a second).
+XA frequency of zero is interpreted as a rest.
+X.PP
+XAt present there are two such ioctls. SPKRTONE accepts a pointer to a
+Xsingle tone structure as third argument and plays it. SPKRTUNE accepts a
+Xpointer to the first of an array of tone structures and plays them in
+Xcontinuous sequence; this array must be terminated by a final member with
+Xa zero duration.
+X.PP
+XThe play-string language is modelled on the PLAY statement conventions of
+XIBM BASIC 2.0. The MB, MF and X primitives of PLAY are not useful in a UNIX 
+Xenvironment and are omitted. The `octave-tracking' feature is also new.
+X.PP
+XThere are 84 accessible notes numbered 1-83 in 7 octaves, each running from
+XC to B, numbered 0-6; the scale is equal-tempered A440 and octave 3 starts
+Xwith middle C. By default, the play function emits half-second notes with the
+Xlast 1/16th second being `rest time'.
+X.PP
+XPlay strings are interpreted left to right as a series of play command groups;
+Xletter case is ignored. Play command groups are as follows:
+X.PP
+XCDEFGAB -- letters A through G cause the corresponding note to be played in the
+Xcurrent octave. A note letter may optionally be followed by an \fIaccidental
+Xsign\fR, one of # + or -; the first two of these cause it to be sharped one
+Xhalf-tone, the last causes it to be flatted one half-tone. It may also be
+Xfollowed by a time value number and by sustain dots (see below). Time values
+Xare interpreted as for the L command below;.
+X.PP
+XO <n> -- if <n> is numeric, this sets the current octave. <n> may also be one
+Xof 'L' or 'N' to enable or disable octave-tracking (it is disabled by default).
+XWhen octave-tracking is on, interpretation of a pair of letter notes will
+Xchange octaves if necessary in order to make the smallest possible jump between
+Xnotes. Thus "olbc" will be played as "olb>c", and "olcb" as "olc<b". Octave
+Xlocking is disabled for one letter note following by >, < and O[0123456].
+X.PP
+X> -- bump the current octave up one.
+X.PP
+X< -- drop the current octave down one.
+X.PP
+XN <n> -- play note n, n being 1 to 84 or 0 for a rest of current time value.
+XMay be followedv by sustain dots.
+X.PP
+XL <n> -- sets the current time value for notes. The default is L4, quarter
+Xnotes. The lowest possible value is 1; values up to 64 are accepted. L1 sets
+Xwhole notes, L2 sets half notes, L4 sets quarter notes, etc..
+X.PP
+XP <n> -- pause (rest), with <n> interpreted as for L. May be followed by
+Xsustain dots. May also be written '~'.
+X.PP
+XT <n> -- Sets the number of quarter notes per minute; default is 120. Musical
+Xnames for common tempi are:
+X
+X.TS
+Xa a a.
+X              Tempo           Beats Per Minute
+Xvery slow     Larghissimo     
+X              Largo           40-60
+X              Larghetto       60-66
+X              Grave           
+X              Lento           
+X              Adagio          66-76
+Xslow          Adagietto       
+X              Andante         76-108
+Xmedium        Andantino       
+X              Moderato        108-120
+Xfast          Allegretto      
+X              Allegro         120-168
+X              Vivace          
+X              Veloce          
+X              Presto          168-208
+Xvery fast     Prestissimo     
+X.TE
+X.PP
+XM[LNS] -- set articulation. MN (N for normal) is the default; the last 1/8th of
+Xthe note's value is rest time. You can set ML for legato (no rest space) or
+XMS (staccato) 1/4 rest space.
+X.PP
+XNotes (that is, CDEFGAB or N command character groups) may be followed by
+Xsustain dots. Each dot causes the note's value to be lengthened by one-half
+Xfor each one. Thus, a note dotted once is held for 3/2 of its undotted value;
+Xdotted twice, it is held 9/4, and three times would give 27/8. 
+X.PP
+XWhitespace in play strings is simply skipped and may be used to separate
+Xmelody sections.
+X.SH BUGS
+XDue to roundoff in the pitch tables and slop in the tone-generation and timer
+Xhardware (neither of which was designed for precision), neither pitch accuracy
+Xnor timings will be mathematically exact. There is no volume control.
+X.PP
+XIn play strings which are very long (longer than your system's physical I/O
+Xblocks) note suffixes or numbers may occasionally be parsed incorrectly due
+Xto crossing a block boundary.
+X.SH FILES
+X/dev/speaker -- speaker device file
+X.SH AUTHOR
+XEric S. Raymond (esr@snark.thyrsus.com) Feb 1990
+END-of-spkr.7
+echo x - Makefile
+sed 's/^X//' >Makefile << 'END-of-Makefile'
+X#
+X# Speaker driver package makefile
+X#
+XCFLAGS = -I. -O # -DDEBUG
+XLDFLAGS = -s
+X
+Xall: Driver.o
+X
+Xinstall:
+X      ./Install
+X
+XDriver.o: spkr.c
+X      $(CC) $(CFLAGS) -c spkr.c
+X      mv spkr.o Driver.o
+X
+Xclean:
+X      rm -f Driver.o *~ speaker.shar
+X
+XDSP =  Files Install Master Name Node Remove Size System 
+Xshar:
+X      shar READ.ME install.bsd spkr.7 Makefile spkr.[ch] \
+X              interp.c $(DSP) playtest >speaker.shar
+END-of-Makefile
+echo x - spkr.c
+sed 's/^X//' >spkr.c << 'END-of-spkr.c'
+X/*
+X * spkr.c -- device driver for console speaker on 80386
+X *
+X * v1.1 by Eric S. Raymond (esr@snark.thyrsus.com) Feb 1990
+X *      modified for 386bsd by Andrew A. Chernov <ache@astral.msk.su>
+X */
+X
+X#ifdef __386BSD__
+X#include "speaker.h"
+X#endif
+X#if !defined(__386BSD__) || (NSPEAKER > 0)
+X
+X#ifdef __386BSD__
+X#include "types.h"
+X#include "param.h"
+X#include "errno.h"
+X#include "buf.h"
+X#include "uio.h"
+X
+X#define CADDR caddr_t
+X#define err_ret(x) return(x)
+X#else /* SYSV */
+X#include <sys/types.h>
+X#include <sys/param.h>
+X#include <sys/dir.h>
+X#include <sys/signal.h>
+X#include <sys/errno.h>
+X#include <sys/ioctl.h>
+X#include <sys/user.h>
+X#include <sys/sysmacros.h> 
+X#include <limits.h>
+X
+X#define CADDR char *
+X#define err_ret(x) u.u_error = (x)
+X#endif
+X
+X#include "spkr.h"
+X
+X/**************** MACHINE DEPENDENT PART STARTS HERE *************************
+X *
+X * This section defines a function tone() which causes a tone of given
+X * frequency and duration from the 80x86's console speaker.
+X * Another function endtone() is defined to force sound off, and there is
+X * also a rest() entry point to do pauses.
+X *
+X * Audible sound is generated using the Programmable Interval Timer (PIT) and
+X * Programmable Peripheral Interface (PPI) attached to the 80x86's speaker. The
+X * PPI controls whether sound is passed through at all; the PIT's channel 2 is
+X * used to generate clicks (a square wave) of whatever frequency is desired.
+X *
+X * The non-BSD code requires SVr3.2-compatible inb(), outb(), timeout(),
+X * sleep(), and wakeup().
+X */
+X
+X/*
+X * PIT and PPI port addresses and control values
+X *
+X * Most of the magic is hidden in the TIMER_PREP value, which selects PIT
+X * channel 2, frequency LSB first, square-wave mode and binary encoding.
+X * The encoding is as follows:
+X *
+X * +----------+----------+---------------+-----+
+X * |  1    0  |  1    1  |  0    1    1  |  0  |
+X * | SC1  SC0 | RW1  RW0 | M2   M1   M0  | BCD |
+X * +----------+----------+---------------+-----+
+X *   Counter     Write        Mode 3      Binary
+X *  Channel 2  LSB first,  (Square Wave) Encoding 
+X *             MSB second
+X */
+X#define PPI           0x61    /* port of Programmable Peripheral Interface */
+X#define PPI_SPKR      0x03    /* turn these PPI bits on to pass sound */
+X#define PIT_CTRL      0x43    /* PIT control address */
+X#define PIT_COUNT     0x42    /* PIT count address */
+X#define PIT_MODE      0xB6    /* set timer mode for sound generation */
+X
+X/*
+X * Magic numbers for timer control. 
+X */
+X#define TIMER_CLK     1193180L        /* corresponds to 18.2 MHz tick rate */
+X
+Xstatic int endtone()
+X/* turn off the speaker, ending current tone */
+X{
+X    wakeup((CADDR)endtone);
+X    outb(PPI, inb(PPI) & ~PPI_SPKR);
+X}
+X
+Xstatic void tone(hz, ticks)
+X/* emit tone of frequency hz for given number of ticks */
+Xunsigned int hz, ticks;
+X{
+X    unsigned int divisor = TIMER_CLK / hz;
+X    int sps;
+X
+X#ifdef DEBUG
+X    printf("tone: hz=%d ticks=%d\n", hz, ticks);
+X#endif /* DEBUG */
+X
+X    /* set timer to generate clicks at given frequency in Hertz */
+X#ifdef __386BSD__
+X    sps = spltty();
+X#else
+X    sps = spl5();
+X#endif
+X    outb(PIT_CTRL, PIT_MODE);         /* prepare timer */
+X    outb(PIT_COUNT, (unsigned char) divisor);  /* send lo byte */
+X    outb(PIT_COUNT, (divisor >> 8));  /* send hi byte */
+X    splx(sps);
+X
+X    /* turn the speaker on */
+X    outb(PPI, inb(PPI) | PPI_SPKR);
+X
+X    /*
+X     * Set timeout to endtone function, then give up the timeslice.
+X     * This is so other processes can execute while the tone is being
+X     * emitted.
+X     */
+X    timeout((CADDR)endtone, (CADDR)NULL, ticks);
+X    sleep((CADDR)endtone, PZERO - 1);
+X}
+X
+Xstatic int endrest()
+X/* end a rest */
+X{
+X    wakeup((CADDR)endrest);
+X}
+X
+Xstatic void rest(ticks)
+X/* rest for given number of ticks */
+Xint   ticks;
+X{
+X    /*
+X     * Set timeout to endrest function, then give up the timeslice.
+X     * This is so other processes can execute while the rest is being
+X     * waited out.
+X     */
+X#ifdef DEBUG
+X    printf("rest: %d\n", ticks);
+X#endif /* DEBUG */
+X    timeout((CADDR)endrest, (CADDR)NULL, ticks);
+X    sleep((CADDR)endrest, PZERO - 1);
+X}
+X
+X#include "interp.c"   /* playinit() and playstring() */
+X
+X/******************* UNIX DRIVER HOOKS BEGIN HERE **************************
+X *
+X * This section implements driver hooks to run playstring() and the tone(),
+X * endtone(), and rest() functions defined above.  For non-BSD systems,
+X * SVr3.2-compatible copyin() is also required.
+X */
+X
+Xstatic int spkr_active;       /* exclusion flag */
+X#ifdef __386BSD__
+Xstatic struct  buf *spkr_inbuf; /* incoming buf */
+X#endif
+X
+Xint spkropen(dev)
+Xdev_t dev;
+X{
+X#ifdef DEBUG
+X    printf("spkropen: entering with dev = %x\n", dev);
+X#endif /* DEBUG */
+X
+X    if (minor(dev) != 0)
+X      err_ret(ENXIO);
+X    else if (spkr_active)
+X      err_ret(EBUSY);
+X    else
+X    {
+X      playinit();
+X#ifdef __386BSD__
+X      spkr_inbuf = geteblk(DEV_BSIZE);
+X#endif
+X      spkr_active = 1;
+X    }
+X#ifdef __386BSD__
+X    return(0);
+X#endif
+X}
+X
+X#ifdef __386BSD__
+Xint spkrwrite(dev, uio)
+Xstruct uio *uio;
+X#else
+Xint spkrwrite(dev)
+X#endif
+Xdev_t dev;
+X{
+X#ifdef __386BSD__
+X    register unsigned n;
+X    char *cp;
+X    int error;
+X#endif
+X#ifdef DEBUG
+X#ifdef __386BSD__
+X    printf("spkrwrite: entering with dev = %x, count = %d\n",
+X              dev, uio->uio_resid);
+X#else
+X    printf("spkrwrite: entering with dev = %x, u.u_count = %d\n",
+X              dev, u.u_count);
+X#endif
+X#endif /* DEBUG */
+X
+X    if (minor(dev) != 0)
+X      err_ret(ENXIO);
+X    else
+X    {
+X#ifdef __386BSD__
+X      n = MIN(DEV_BSIZE, uio->uio_resid);
+X      cp = spkr_inbuf->b_un.b_addr;
+X      error = uiomove(cp, n, uio);
+X      if (!error)
+X              playstring(cp, n);
+X      return(error);
+X#else
+X      char    bfr[STD_BLK];
+X
+X      copyin(u.u_base, bfr, u.u_count);
+X      playstring(bfr, u.u_count);
+X      u.u_base += u.u_count;
+X      u.u_count = 0;
+X#endif
+X    }
+X}
+X
+Xint spkrclose(dev)
+Xdev_t dev;
+X{
+X#ifdef DEBUG
+X    printf("spkrclose: entering with dev = %x\n", dev);
+X#endif /* DEBUG */
+X
+X    if (minor(dev) != 0)
+X      err_ret(ENXIO);
+X    else
+X    {
+X      endtone();
+X#ifdef __386BSD__
+X      brelse(spkr_inbuf);
+X#endif
+X      spkr_active = 0;
+X    }
+X#ifdef __386BSD__
+X    return(0);
+X#endif
+X}
+X
+Xint spkrioctl(dev, cmd, cmdarg)
+Xdev_t dev;
+Xint   cmd;
+XCADDR   cmdarg;
+X{
+X#ifdef DEBUG
+X    printf("spkrioctl: entering with dev = %x, cmd = %x\n", dev, cmd);
+X#endif /* DEBUG */
+X
+X    if (minor(dev) != 0)
+X      err_ret(ENXIO);
+X    else if (cmd == SPKRTONE)
+X    {
+X      tone_t  *tp = (tone_t *)cmdarg;
+X
+X      if (tp->frequency == 0)
+X          rest(tp->duration);
+X      else
+X          tone(tp->frequency, tp->duration);
+X    }
+X    else if (cmd == SPKRTUNE)
+X    {
+X#ifdef __386BSD__
+X      tone_t  *tp = (tone_t *)(*(caddr_t *)cmdarg);
+X      tone_t ttp;
+X      int error;
+X
+X      for (; ; tp++) {
+X          error = copyin(tp, &ttp, sizeof(tone_t));
+X          if (error)
+X                  return(error);
+X          if (ttp.duration == 0)
+X                  break;
+X          if (ttp.frequency == 0)
+X              rest(ttp.duration);
+X          else
+X              tone(ttp.frequency, ttp.duration);
+X      }
+X#else
+X      tone_t  *tp = (tone_t *)cmdarg;
+X
+X      for (; tp->duration; tp++)
+X          if (tp->frequency == 0)
+X              rest(tp->duration);
+X          else
+X              tone(tp->frequency, tp->duration);
+X#endif
+X    }
+X    else
+X      err_ret(EINVAL);
+X#ifdef __386BSD__
+X    return(0);
+X#endif
+X}
+X
+X#endif  /* !defined(__386BSD__) || (NSPEAKER > 0) */
+X/* spkr.c ends here */
+END-of-spkr.c
+echo x - spkr.h
+sed 's/^X//' >spkr.h << 'END-of-spkr.h'
+X/*
+X * spkr.h -- interface definitions for speaker ioctl()
+X *
+X * v1.1 by Eric S. Raymond (esr@snark.thyrsus.com) Feb 1990
+X *      modified for 386bsd by Andrew A. Chernov <ache@astral.msk.su>
+X */
+X
+X#ifndef _SPKR_H_
+X#define _SPKR_H_
+X
+X#ifdef __386BSD__
+X#ifndef KERNEL
+X#include <sys/ioctl.h>
+X#else
+X#include "ioctl.h"
+X#endif
+X
+X#define SPKRTONE        _IOW('S', 1, tone_t)    /* emit tone */
+X#define SPKRTUNE        _IO('S', 2)             /* emit tone sequence*/
+X#else /* SYSV */
+X#define       SPKRIOC         ('S'<<8)
+X#define       SPKRTONE        (SPKRIOC|1)     /* emit tone */
+X#define       SPKRTUNE        (SPKRIOC|2)     /* emit tone sequence*/
+X#endif
+X
+Xtypedef struct
+X{
+X    int       frequency;      /* in hertz */
+X    int duration;     /* in 1/100ths of a second */
+X}
+Xtone_t;
+X
+X#endif /* _SPKR_H_ */
+X/* spkr.h ends here */
+END-of-spkr.h
+echo x - interp.c
+sed 's/^X//' >interp.c << 'END-of-interp.c'
+X/*
+X * interp.c -- device driver for console speaker on 80386
+X *
+X * v1.1 by Eric S. Raymond (esr@snark.thyrsus.com) Feb 1990
+X *
+X * this is the part of the code common to all 386 UNIX OSes
+X *
+X * playinit() and playstring() are called from the appropriate driver
+X */
+X
+X#ifdef __386BSD__
+X#include "param.h"
+X#else
+X#include <sys/param.h>
+X#endif
+X
+X#ifndef HZ
+X#define HZ 60
+X#endif
+X
+X
+X/**************** PLAY STRING INTERPRETER BEGINS HERE **********************
+X *
+X * Play string interpretation is modelled on IBM BASIC 2.0's PLAY statement;
+X * M[LNS] are missing and the ~ synonym and octave-tracking facility is added.
+X * Requires tone(), rest(), and endtone(). String play is not interruptible
+X * except possibly at physical block boundaries.
+X */
+X
+Xtypedef int   bool;
+X#ifndef TRUE
+X#define TRUE  1
+X#endif
+X#ifndef FALSE
+X#define FALSE 0
+X#endif
+X
+X#define toupper(c)    ((c) - ' ' * (((c) >= 'a') && ((c) <= 'z')))
+X#define isdigit(c)    (((c) >= '0') && ((c) <= '9'))
+X#define dtoi(c)               ((c) - '0')
+X
+Xstatic int octave;    /* currently selected octave */
+Xstatic int whole;     /* whole-note time at current tempo, in ticks */
+Xstatic int value;     /* whole divisor for note time, quarter note = 1 */
+Xstatic int fill;      /* controls spacing of notes */
+Xstatic bool octtrack; /* octave-tracking on? */
+Xstatic bool octprefix;        /* override current octave-tracking state? */
+X
+X/*
+X * Magic number avoidance...
+X */
+X#define SECS_PER_MIN  60      /* seconds per minute */
+X#define WHOLE_NOTE    4       /* quarter notes per whole note */
+X#define MIN_VALUE     64      /* the most we can divide a note by */
+X#define DFLT_VALUE    4       /* default value (quarter-note) */
+X#define FILLTIME      8       /* for articulation, break note in parts */
+X#define STACCATO      6       /* 6/8 = 3/4 of note is filled */
+X#define NORMAL                7       /* 7/8ths of note interval is filled */
+X#define LEGATO                8       /* all of note interval is filled */
+X#define DFLT_OCTAVE   4       /* default octave */
+X#define MIN_TEMPO     32      /* minimum tempo */
+X#define DFLT_TEMPO    120     /* default tempo */
+X#define MAX_TEMPO     255     /* max tempo */
+X#define NUM_MULT      3       /* numerator of dot multiplier */
+X#define DENOM_MULT    2       /* denominator of dot multiplier */
+X
+X/* letter to half-tone:  A   B  C  D  E  F  G */
+Xstatic int notetab[8] = {9, 11, 0, 2, 4, 5, 7};
+X
+X/*
+X * This is the American Standard A440 Equal-Tempered scale with frequencies
+X * rounded to nearest integer. Thank Goddess for the good ol' CRC Handbook...
+X * our octave 0 is standard octave 2.
+X */
+X#define OCTAVE_NOTES  12      /* semitones per octave */
+Xstatic int pitchtab[] =
+X{
+X/*        C     C#    D     D#    E     F     F#    G     G#    A     A#    B*/
+X/* 0 */   65,   69,   73,   78,   82,   87,   93,   98,  103,  110,  117,  123,
+X/* 1 */  131,  139,  147,  156,  165,  175,  185,  196,  208,  220,  233,  247,
+X/* 2 */  262,  277,  294,  311,  330,  349,  370,  392,  415,  440,  466,  494,
+X/* 3 */  523,  554,  587,  622,  659,  698,  740,  784,  831,  880,  932,  988,
+X/* 4 */ 1047, 1109, 1175, 1245, 1319, 1397, 1480, 1568, 1661, 1760, 1865, 1975,
+X/* 5 */ 2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951,
+X/* 6 */ 4186, 4435, 4698, 4978, 5274, 5588, 5920, 6272, 6644, 7040, 7459, 7902,
+X};
+X
+Xstatic void playinit()
+X{
+X    octave = DFLT_OCTAVE;
+X    whole = (HZ * SECS_PER_MIN * WHOLE_NOTE) / DFLT_TEMPO;
+X    fill = NORMAL;
+X    value = DFLT_VALUE;
+X    octtrack = FALSE;
+X    octprefix = TRUE; /* act as though there was an initial O(n) */
+X}
+X
+Xstatic void playtone(pitch, value, sustain)
+X/* play tone of proper duration for current rhythm signature */
+Xint   pitch, value, sustain;
+X{
+X    register int      sound, silence, snum = 1, sdenom = 1;
+X
+X    /* this weirdness avoids floating-point arithmetic */
+X    for (; sustain; sustain--)
+X    {
+X      snum *= NUM_MULT;
+X      sdenom *= DENOM_MULT;
+X    }
+X
+X    if (pitch == -1)
+X      rest(whole * snum / (value * sdenom));
+X    else
+X    {
+X      sound = (whole * snum) / (value * sdenom)
+X              - (whole * (FILLTIME - fill)) / (value * FILLTIME);
+X      silence = whole * (FILLTIME-fill) * snum / (FILLTIME * value * sdenom);
+X
+X#ifdef DEBUG
+X      printf("playtone: pitch %d for %d ticks, rest for %d ticks\n",
+X                      pitch, sound, silence);
+X#endif /* DEBUG */
+X
+X      tone(pitchtab[pitch], sound);
+X      if (fill != LEGATO)
+X          rest(silence);
+X    }
+X}
+X
+Xstatic int abs(n)
+Xint n;
+X{
+X    if (n < 0)
+X      return(-n);
+X    else
+X      return(n);
+X}
+X
+Xstatic void playstring(cp, slen)
+X/* interpret and play an item from a notation string */
+Xchar  *cp;
+Xsize_t        slen;
+X{
+X    int               pitch, lastpitch = OCTAVE_NOTES * DFLT_OCTAVE;
+X
+X#define GETNUM(cp, v) for(v=0; isdigit(cp[1]) && slen > 0; ) \
+X                              {v = v * 10 + (*++cp - '0'); slen--;}
+X    for (; slen--; cp++)
+X    {
+X      int             sustain, timeval, tempo;
+X      register char   c = toupper(*cp);
+X
+X#ifdef DEBUG
+X      printf("playstring: %c (%x)\n", c, c);
+X#endif /* DEBUG */
+X
+X      switch (c)
+X      {
+X      case 'A':  case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
+X
+X          /* compute pitch */
+X          pitch = notetab[c - 'A'] + octave * OCTAVE_NOTES;
+X
+X          /* this may be followed by an accidental sign */
+X          if (cp[1] == '#' || cp[1] == '+')
+X          {
+X              ++pitch;
+X              ++cp;
+X              slen--;
+X          }
+X          else if (cp[1] == '-')
+X          {
+X              --pitch;
+X              ++cp;
+X              slen--;
+X          }
+X
+X          /*
+X           * If octave-tracking mode is on, and there has been no octave-
+X           * setting prefix, find the version of the current letter note
+X           * closest to the last regardless of octave.
+X           */
+X          if (octtrack && !octprefix)
+X          {
+X              if (abs(pitch-lastpitch) > abs(pitch+OCTAVE_NOTES-lastpitch))
+X              {
+X                  ++octave;
+X                  pitch += OCTAVE_NOTES;
+X              }
+X
+X              if (abs(pitch-lastpitch) > abs((pitch-OCTAVE_NOTES)-lastpitch))
+X              {
+X                  --octave;
+X                  pitch -= OCTAVE_NOTES;
+X              }
+X          }
+X          octprefix = FALSE;
+X          lastpitch = pitch;
+X
+X          /* ...which may in turn be followed by an override time value */
+X          GETNUM(cp, timeval);
+X          if (timeval <= 0 || timeval > MIN_VALUE)
+X              timeval = value;
+X
+X          /* ...and/or sustain dots */
+X          for (sustain = 0; cp[1] == '.'; cp++)
+X          {
+X              slen--;
+X              sustain++;
+X          }
+X
+X          /* time to emit the actual tone */
+X          playtone(pitch, timeval, sustain);
+X          break;
+X
+X      case 'O':
+X          if (cp[1] == 'N' || cp[1] == 'n')
+X          {
+X              octprefix = octtrack = FALSE;
+X              ++cp;
+X              slen--;
+X          }
+X          else if (cp[1] == 'L' || cp[1] == 'l')
+X          {
+X              octtrack = TRUE;
+X              ++cp;
+X              slen--;
+X          }
+X          else
+X          {
+X              GETNUM(cp, octave);
+X              if (octave >= sizeof(pitchtab) / OCTAVE_NOTES)
+X                  octave = DFLT_OCTAVE;
+X              octprefix = TRUE;
+X          }
+X          break;
+X
+X      case '>':
+X          if (octave < sizeof(pitchtab) / OCTAVE_NOTES - 1)
+X              octave++;
+X          octprefix = TRUE;
+X          break;
+X
+X      case '<':
+X          if (octave > 0)
+X              octave--;
+X          octprefix = TRUE;
+X          break;
+X
+X      case 'N':
+X          GETNUM(cp, pitch);
+X          for (sustain = 0; cp[1] == '.'; cp++)
+X          {
+X              slen--;
+X              sustain++;
+X          }
+X          playtone(pitch - 1, value, sustain);
+X          break;
+X
+X      case 'L':
+X          GETNUM(cp, value);
+X          if (value <= 0 || value > MIN_VALUE)
+X              value = DFLT_VALUE;
+X          break;
+X
+X      case 'P':
+X      case '~':
+X          /* this may be followed by an override time value */
+X          GETNUM(cp, timeval);
+X          if (timeval <= 0 || timeval > MIN_VALUE)
+X              timeval = value;
+X          for (sustain = 0; cp[1] == '.'; cp++)
+X          {
+X              slen--;
+X              sustain++;
+X          }
+X          playtone(-1, timeval, sustain);
+X          break;
+X
+X      case 'T':
+X          GETNUM(cp, tempo);
+X          if (tempo < MIN_TEMPO || tempo > MAX_TEMPO)
+X              tempo = DFLT_TEMPO;
+X          whole = (HZ * SECS_PER_MIN * WHOLE_NOTE) / tempo;
+X          break;
+X
+X      case 'M':
+X          if (cp[1] == 'N' || cp[1] == 'n')
+X          {
+X              fill = NORMAL;
+X              ++cp;
+X              slen--;
+X          }
+X          else if (cp[1] == 'L' || cp[1] == 'l')
+X          {
+X              fill = LEGATO;
+X              ++cp;
+X              slen--;
+X          }
+X          else if (cp[1] == 'S' || cp[1] == 's')
+X          {
+X              fill = STACCATO;
+X              ++cp;
+X              slen--;
+X          }
+X          break;
+X      }
+X    }
+X}
+END-of-interp.c
+echo x - Files
+sed 's/^X//' >Files << 'END-of-Files'
+X/usr/include/sys/spkr.h
+END-of-Files
+echo x - Install
+sed 's/^X//' >Install << 'END-of-Install'
+X#
+X# Speaker driver installation script
+X#
+XTMP=/tmp/speaker.err
+XERR1=" Errors have been written to the file $TMP."
+XERR2=" The Speaker Driver software was not installed."
+X
+Xecho "Installing Speaker Driver Software Package"
+X
+X/etc/conf/bin/idcheck -p speaker 2>$TMP
+Xif [ $? != 0 ]
+Xthen
+X      echo "The speaker package is already at least partly installed.
+X      Removing the old version now..."
+X      /etc/conf/bin/idinstall -d speaker
+Xfi
+X
+X/etc/conf/bin/idinstall -a -k speaker 2>>$TMP
+Xif [ $? != 0 ]
+Xthen
+X      message "There was an error during package installation. $ERR1 $ERR2"
+X      exit 1
+Xfi
+X
+X/etc/conf/bin/idbuild 2>>$TMP
+Xif [ $? != 0 ]
+Xthen
+X      message "There was an error during kernel reconfiguration. $ERR1 $ERR2"
+X      exit 1
+Xfi
+X
+Xrm -f $TMP
+X
+Xcp spkr.h /usr/include/sys/spkr.h
+X
+Xecho "Performing shutdown..."
+Xcd /; exec /etc/shutdown -g0 -y
+END-of-Install
+echo x - Master
+sed 's/^X//' >Master << 'END-of-Master'
+Xspeaker       ocwi    iocH    spkr    0       0       1       1       -1
+END-of-Master
+echo x - Name
+sed 's/^X//' >Name << 'END-of-Name'
+X386 UNIX Speaker Device Driver Package
+END-of-Name
+echo x - Node
+sed 's/^X//' >Node << 'END-of-Node'
+Xspeaker       speaker c       0
+END-of-Node
+echo x - Remove
+sed 's/^X//' >Remove << 'END-of-Remove'
+X#
+X# Speaker driver remove script
+X#
+XTMP=/tmp/speaker.err
+XRERR="Errors have been written to the file $TMP."
+X
+Xecho "Removing Speaker Driver Software Package"
+X
+X/etc/conf/bin/idinstall -d speaker 2>$TMP
+Xif [ $? != 0 ]
+Xthen
+X      message "There was an error during package removal. $RERR"
+X      exit 1
+Xfi
+X
+X/etc/conf/bin/idbuild 2>>$TMP
+Xif [ $? != 0 ]
+Xthen
+X      message "There was an error during kernel reconfiguration. $RERR"
+X      exit 1
+Xfi
+X
+Xrm -f /dev/speaker $TMP /usr/include/sys/spkr.h
+X
+Xexit 0
+END-of-Remove
+echo x - Size
+sed 's/^X//' >Size << 'END-of-Size'
+XROOT=1400
+XUSR=100
+END-of-Size
+echo x - System
+sed 's/^X//' >System << 'END-of-System'
+Xspeaker       Y       1       0       0       0       0       0       0       0
+END-of-System
+echo x - playtest
+sed 's/^X//' >playtest << 'END-of-playtest'
+X:
+X# Test script for the speaker driver
+X#
+X# v1.0 by Eric S. Raymond (Feb 1990)
+X#      modified for 386bsd by Andrew A. Chernov <ache@astral.msk.su>
+X#
+Xreveille="t255l8c.f.afc~c.f.afc~c.f.afc.f.a..f.~c.f.afc~c.f.afc~c.f.afc~c.f.."
+Xcontact="<cd<a#~<a#>f"
+Xdance="t240<cfcfgagaa#b#>dc<a#a.~fg.gaa#.agagegc.~cfcfgagaa#b#>dc<a#a.~fg.gga.agfgfgf."
+Xloony="t255cf8f8edc<a.>~cf8f8edd#e.~ce8cdce8cd.<a>c8c8c#def8af8."
+X
+Xcase $1 in
+Xreveille) echo  $reveille >/dev/speaker;;
+Xcontact)  echo  $contact >/dev/speaker;;
+Xdance)  echo  $dance >/dev/speaker;;
+Xloony)  echo  $loony >/dev/speaker;;
+X*)
+X      echo "No such tune. Available tunes are:"
+X      echo
+X      echo "reveille -- Reveille"
+X      echo "contact -- Contact theme from Close Encounters"
+X      echo "dance -- Lord of the Dance (aka Simple Gifts)"
+X      echo "loony -- Loony Toons theme"
+X      ;;
+Xesac
+END-of-playtest
+exit