1# This is a shell archive. Save it in a file, remove anything before 2# this line, and then unpack it by entering "sh file". Note, it may 3# create directories; files and directories will be owned by you and 4# have default permissions. 5# 6# This archive contains: 7# 8# READ.ME 9# install.bsd 10# spkr.7 11# Makefile 12# spkr.c 13# spkr.h 14# interp.c 15# Files 16# Install 17# Master 18# Name 19# Node 20# Remove 21# Size 22# System 23# playtest 24# 25echo x - READ.ME 26sed 's/^X//' >READ.ME << 'END-of-READ.ME' 27X Console Speaker Driver Package (v1.1) 28X 29X by Eric S. Raymond (esr@snark.thyrsus.com) 30X 31XThis package gives 80386 machines running SVr3.2 or later the ability to play 32Xtunes on the console speaker. It has been extended to 386BSD (and possibly 33XBSDI) by Andrew A. Chernov, and to SCO UNIX 3.2.4 (and possibly other VPIX 34Xsystems) by Andreas Arens. 35X 36XThe following files are contained in the kit: 37X 38XDocumentation and examples: 39XREAD.ME -- this file 40Xspeaker.7 -- man page for the driver 41Xplaytest -- test script exercising familiar tunes 42X 43XInstallable driver kit parts, for SVr3.2 or later: 44XFiles -- list of driver package file locations 45XInstall -- installation script for driver kit 46XMaster -- mdevice entry for speaker driver 47XName -- name entry foe speaker driver 48XNode -- /dev node specification file 49XRemove -- Driver removal script 50XSize -- installation size data 51XSystem -- sdevice entry for speaker driver 52X 53XDriver source code, for SVr3.2 or later and 386BSD: 54XMakefile -- Makefile for driver code 55Xspkr.c -- the driver source 56Xspeaker.h -- ioctl interface file 57X 58XCommon source code: 59Xinterp.c -- play string interpretation code 60X 61XFor SVr3.2 or later, simply type `make' and wait. Then type ./Install 62Xand follow its instructions. You will have to install the man pages by hand. 63XBe aware that the speaker.7 man page uses tbl(1) constructs. 64X 65XFor 386BSD, follow the installation instructions in install.bsd. 66X 67XFor SCO UNIX 3.2.4, no new kernel drivers are needed, and you need only 68Xcopy interp.c to your src directory and proceed with making NetHack, with 69XVPIX_MUSIC set in unixconf.h. 70X 71XInteresting tunes mailed to the author will be periodically posted in batches 72Xand added to the test script for future versions. 73X 74X Revision notes 75X 76X1.1 -- fixed minor bug in M[LSN] interpretation, added octave-tracking. 77X Tweaked the playtest examples. 78END-of-READ.ME 79echo x - install.bsd 80sed 's/^X//' >install.bsd << 'END-of-install.bsd' 81XCopy spkr.c and interp.c to /sys/i386/isa 82XCopy spkr.h to /sys/sys 83X 84X----------------------------------------------------------------------------- 85X 86XFile /sys/i386/conf/YOUR_MACHINE_NAME 87Xadd following line: 88X 89Xpseudo-device speaker 90X 91X----------------------------------------------------------------------------- 92X 93XFile /sys/i386/conf/files.i386 94Xadd following line: 95X 96Xi386/isa/spkr.c optional speaker 97X 98X----------------------------------------------------------------------------- 99X 100XFile /sys/i386/i386/conf.c 101X[major number 20 (hex) is registered for spkr driver, don't change it] 102Xadd following code: 103X 104X#include "speaker.h" 105X#if NSPEAKER > 0 106Xint spkropen(),spkrclose(),spkrwrite(),spkrioctl(); 107X#else 108X#define spkropen enxio 109X#define spkrclose enxio 110X#define spkrwrite enxio 111X#define spkrioctl enxio 112X#endif 113X ... 114X 115Xstruct cdevsw cdevsw[] = 116X{ 117X ... 118X 119X { spkropen, spkrclose, enxio, spkrwrite, /*20*/ 120X spkrioctl, enxio, enxio, NULL, 121X enxio, enxio, enxio }, 122X ... 123X 124X----------------------------------------------------------------------------- 125X 126XMake corresponding device: 127X 128X mknod /dev/speaker c 32 0 129X 130X[major number 32 (20 hex) is registered for spkr driver, don't change it] 131X 132X----------------------------------------------------------------------------- 133X 134XGo to /sys/i386/conf and type 135X config YOUR_MACHINE_NAME 136Xthen go to /sys/compile/YOUR_MACHINE_NAME and type 137X make depend 138X make 139X 140END-of-install.bsd 141echo x - spkr.7 142sed 's/^X//' >spkr.7 << 'END-of-spkr.7' 143X.TH SPKR 7 144X.SH NAME 145Xspkr \- console speaker device driver 146X.SH DESCRIPTION 147XThe speaker device driver allows applications to control the PC console 148Xspeaker on an IBM-PC-compatible machine running UNIX. 149X.PP 150XOnly one process may have this device open at any given time; open() and 151Xclose() are used to lock and relinquish it. An attempt to open() when 152Xanother process has the device locked will return -1 with an EBUSY error 153Xindication. Writes to the device are interpreted as 'play strings' in a 154Xsimple ASCII melody notation. An ioctl() for tone generation at arbitrary 155Xfrequencies is also supported. 156X.PP 157XSound-generation does \fInot\fR monopolize the processor; in fact, the driver 158Xspends most of its time sleeping while the PC hardware is emitting 159Xtones. Other processes may emit beeps while the driver is running. 160X.PP 161XApplications may call ioctl() on a speaker file descriptor to control the 162Xspeaker driver directly; definitions for the ioctl() interface are in 163Xsys/spkr.h. The tone_t structure used in these calls has two fields, 164Xspecifying a frequency (in hz) and a duration (in 1/100ths of a second). 165XA frequency of zero is interpreted as a rest. 166X.PP 167XAt present there are two such ioctls. SPKRTONE accepts a pointer to a 168Xsingle tone structure as third argument and plays it. SPKRTUNE accepts a 169Xpointer to the first of an array of tone structures and plays them in 170Xcontinuous sequence; this array must be terminated by a final member with 171Xa zero duration. 172X.PP 173XThe play-string language is modelled on the PLAY statement conventions of 174XIBM BASIC 2.0. The MB, MF and X primitives of PLAY are not useful in a UNIX 175Xenvironment and are omitted. The `octave-tracking' feature is also new. 176X.PP 177XThere are 84 accessible notes numbered 1-83 in 7 octaves, each running from 178XC to B, numbered 0-6; the scale is equal-tempered A440 and octave 3 starts 179Xwith middle C. By default, the play function emits half-second notes with the 180Xlast 1/16th second being `rest time'. 181X.PP 182XPlay strings are interpreted left to right as a series of play command groups; 183Xletter case is ignored. Play command groups are as follows: 184X.PP 185XCDEFGAB -- letters A through G cause the corresponding note to be played in the 186Xcurrent octave. A note letter may optionally be followed by an \fIaccidental 187Xsign\fR, one of # + or -; the first two of these cause it to be sharped one 188Xhalf-tone, the last causes it to be flatted one half-tone. It may also be 189Xfollowed by a time value number and by sustain dots (see below). Time values 190Xare interpreted as for the L command below;. 191X.PP 192XO <n> -- if <n> is numeric, this sets the current octave. <n> may also be one 193Xof 'L' or 'N' to enable or disable octave-tracking (it is disabled by default). 194XWhen octave-tracking is on, interpretation of a pair of letter notes will 195Xchange octaves if necessary in order to make the smallest possible jump between 196Xnotes. Thus "olbc" will be played as "olb>c", and "olcb" as "olc<b". Octave 197Xlocking is disabled for one letter note following by >, < and O[0123456]. 198X.PP 199X> -- bump the current octave up one. 200X.PP 201X< -- drop the current octave down one. 202X.PP 203XN <n> -- play note n, n being 1 to 84 or 0 for a rest of current time value. 204XMay be followedv by sustain dots. 205X.PP 206XL <n> -- sets the current time value for notes. The default is L4, quarter 207Xnotes. The lowest possible value is 1; values up to 64 are accepted. L1 sets 208Xwhole notes, L2 sets half notes, L4 sets quarter notes, etc.. 209X.PP 210XP <n> -- pause (rest), with <n> interpreted as for L. May be followed by 211Xsustain dots. May also be written '~'. 212X.PP 213XT <n> -- Sets the number of quarter notes per minute; default is 120. Musical 214Xnames for common tempi are: 215X 216X.TS 217Xa a a. 218X Tempo Beats Per Minute 219Xvery slow Larghissimo 220X Largo 40-60 221X Larghetto 60-66 222X Grave 223X Lento 224X Adagio 66-76 225Xslow Adagietto 226X Andante 76-108 227Xmedium Andantino 228X Moderato 108-120 229Xfast Allegretto 230X Allegro 120-168 231X Vivace 232X Veloce 233X Presto 168-208 234Xvery fast Prestissimo 235X.TE 236X.PP 237XM[LNS] -- set articulation. MN (N for normal) is the default; the last 1/8th of 238Xthe note's value is rest time. You can set ML for legato (no rest space) or 239XMS (staccato) 1/4 rest space. 240X.PP 241XNotes (that is, CDEFGAB or N command character groups) may be followed by 242Xsustain dots. Each dot causes the note's value to be lengthened by one-half 243Xfor each one. Thus, a note dotted once is held for 3/2 of its undotted value; 244Xdotted twice, it is held 9/4, and three times would give 27/8. 245X.PP 246XWhitespace in play strings is simply skipped and may be used to separate 247Xmelody sections. 248X.SH BUGS 249XDue to roundoff in the pitch tables and slop in the tone-generation and timer 250Xhardware (neither of which was designed for precision), neither pitch accuracy 251Xnor timings will be mathematically exact. There is no volume control. 252X.PP 253XIn play strings which are very long (longer than your system's physical I/O 254Xblocks) note suffixes or numbers may occasionally be parsed incorrectly due 255Xto crossing a block boundary. 256X.SH FILES 257X/dev/speaker -- speaker device file 258X.SH AUTHOR 259XEric S. Raymond (esr@snark.thyrsus.com) Feb 1990 260END-of-spkr.7 261echo x - Makefile 262sed 's/^X//' >Makefile << 'END-of-Makefile' 263X# 264X# Speaker driver package makefile 265X# 266XCFLAGS = -I. -O # -DDEBUG 267XLDFLAGS = -s 268X 269Xall: Driver.o 270X 271Xinstall: 272X ./Install 273X 274XDriver.o: spkr.c 275X $(CC) $(CFLAGS) -c spkr.c 276X mv spkr.o Driver.o 277X 278Xclean: 279X rm -f Driver.o *~ speaker.shar 280X 281XDSP = Files Install Master Name Node Remove Size System 282Xshar: 283X shar READ.ME install.bsd spkr.7 Makefile spkr.[ch] \ 284X interp.c $(DSP) playtest >speaker.shar 285END-of-Makefile 286echo x - spkr.c 287sed 's/^X//' >spkr.c << 'END-of-spkr.c' 288X/* 289X * spkr.c -- device driver for console speaker on 80386 290X * 291X * v1.1 by Eric S. Raymond (esr@snark.thyrsus.com) Feb 1990 292X * modified for 386bsd by Andrew A. Chernov <ache@astral.msk.su> 293X */ 294X 295X#ifdef __386BSD__ 296X#include "speaker.h" 297X#endif 298X#if !defined(__386BSD__) || (NSPEAKER > 0) 299X 300X#ifdef __386BSD__ 301X#include "types.h" 302X#include "param.h" 303X#include "errno.h" 304X#include "buf.h" 305X#include "uio.h" 306X 307X#define CADDR caddr_t 308X#define err_ret(x) return(x) 309X#else /* SYSV */ 310X#include <sys/types.h> 311X#include <sys/param.h> 312X#include <sys/dir.h> 313X#include <sys/signal.h> 314X#include <sys/errno.h> 315X#include <sys/ioctl.h> 316X#include <sys/user.h> 317X#include <sys/sysmacros.h> 318X#include <limits.h> 319X 320X#define CADDR char * 321X#define err_ret(x) u.u_error = (x) 322X#endif 323X 324X#include "spkr.h" 325X 326X/**************** MACHINE DEPENDENT PART STARTS HERE ************************* 327X * 328X * This section defines a function tone() which causes a tone of given 329X * frequency and duration from the 80x86's console speaker. 330X * Another function endtone() is defined to force sound off, and there is 331X * also a rest() entry point to do pauses. 332X * 333X * Audible sound is generated using the Programmable Interval Timer (PIT) and 334X * Programmable Peripheral Interface (PPI) attached to the 80x86's speaker. The 335X * PPI controls whether sound is passed through at all; the PIT's channel 2 is 336X * used to generate clicks (a square wave) of whatever frequency is desired. 337X * 338X * The non-BSD code requires SVr3.2-compatible inb(), outb(), timeout(), 339X * sleep(), and wakeup(). 340X */ 341X 342X/* 343X * PIT and PPI port addresses and control values 344X * 345X * Most of the magic is hidden in the TIMER_PREP value, which selects PIT 346X * channel 2, frequency LSB first, square-wave mode and binary encoding. 347X * The encoding is as follows: 348X * 349X * +----------+----------+---------------+-----+ 350X * | 1 0 | 1 1 | 0 1 1 | 0 | 351X * | SC1 SC0 | RW1 RW0 | M2 M1 M0 | BCD | 352X * +----------+----------+---------------+-----+ 353X * Counter Write Mode 3 Binary 354X * Channel 2 LSB first, (Square Wave) Encoding 355X * MSB second 356X */ 357X#define PPI 0x61 /* port of Programmable Peripheral Interface */ 358X#define PPI_SPKR 0x03 /* turn these PPI bits on to pass sound */ 359X#define PIT_CTRL 0x43 /* PIT control address */ 360X#define PIT_COUNT 0x42 /* PIT count address */ 361X#define PIT_MODE 0xB6 /* set timer mode for sound generation */ 362X 363X/* 364X * Magic numbers for timer control. 365X */ 366X#define TIMER_CLK 1193180L /* corresponds to 18.2 MHz tick rate */ 367X 368Xstatic int endtone() 369X/* turn off the speaker, ending current tone */ 370X{ 371X wakeup((CADDR)endtone); 372X outb(PPI, inb(PPI) & ~PPI_SPKR); 373X} 374X 375Xstatic void tone(hz, ticks) 376X/* emit tone of frequency hz for given number of ticks */ 377Xunsigned int hz, ticks; 378X{ 379X unsigned int divisor = TIMER_CLK / hz; 380X int sps; 381X 382X#ifdef DEBUG 383X printf("tone: hz=%d ticks=%d\n", hz, ticks); 384X#endif /* DEBUG */ 385X 386X /* set timer to generate clicks at given frequency in Hertz */ 387X#ifdef __386BSD__ 388X sps = spltty(); 389X#else 390X sps = spl5(); 391X#endif 392X outb(PIT_CTRL, PIT_MODE); /* prepare timer */ 393X outb(PIT_COUNT, (unsigned char) divisor); /* send lo byte */ 394X outb(PIT_COUNT, (divisor >> 8)); /* send hi byte */ 395X splx(sps); 396X 397X /* turn the speaker on */ 398X outb(PPI, inb(PPI) | PPI_SPKR); 399X 400X /* 401X * Set timeout to endtone function, then give up the timeslice. 402X * This is so other processes can execute while the tone is being 403X * emitted. 404X */ 405X timeout((CADDR)endtone, (CADDR)NULL, ticks); 406X sleep((CADDR)endtone, PZERO - 1); 407X} 408X 409Xstatic int endrest() 410X/* end a rest */ 411X{ 412X wakeup((CADDR)endrest); 413X} 414X 415Xstatic void rest(ticks) 416X/* rest for given number of ticks */ 417Xint ticks; 418X{ 419X /* 420X * Set timeout to endrest function, then give up the timeslice. 421X * This is so other processes can execute while the rest is being 422X * waited out. 423X */ 424X#ifdef DEBUG 425X printf("rest: %d\n", ticks); 426X#endif /* DEBUG */ 427X timeout((CADDR)endrest, (CADDR)NULL, ticks); 428X sleep((CADDR)endrest, PZERO - 1); 429X} 430X 431X#include "interp.c" /* playinit() and playstring() */ 432X 433X/******************* UNIX DRIVER HOOKS BEGIN HERE ************************** 434X * 435X * This section implements driver hooks to run playstring() and the tone(), 436X * endtone(), and rest() functions defined above. For non-BSD systems, 437X * SVr3.2-compatible copyin() is also required. 438X */ 439X 440Xstatic int spkr_active; /* exclusion flag */ 441X#ifdef __386BSD__ 442Xstatic struct buf *spkr_inbuf; /* incoming buf */ 443X#endif 444X 445Xint spkropen(dev) 446Xdev_t dev; 447X{ 448X#ifdef DEBUG 449X printf("spkropen: entering with dev = %x\n", dev); 450X#endif /* DEBUG */ 451X 452X if (minor(dev) != 0) 453X err_ret(ENXIO); 454X else if (spkr_active) 455X err_ret(EBUSY); 456X else 457X { 458X playinit(); 459X#ifdef __386BSD__ 460X spkr_inbuf = geteblk(DEV_BSIZE); 461X#endif 462X spkr_active = 1; 463X } 464X#ifdef __386BSD__ 465X return(0); 466X#endif 467X} 468X 469X#ifdef __386BSD__ 470Xint spkrwrite(dev, uio) 471Xstruct uio *uio; 472X#else 473Xint spkrwrite(dev) 474X#endif 475Xdev_t dev; 476X{ 477X#ifdef __386BSD__ 478X register unsigned n; 479X char *cp; 480X int error; 481X#endif 482X#ifdef DEBUG 483X#ifdef __386BSD__ 484X printf("spkrwrite: entering with dev = %x, count = %d\n", 485X dev, uio->uio_resid); 486X#else 487X printf("spkrwrite: entering with dev = %x, u.u_count = %d\n", 488X dev, u.u_count); 489X#endif 490X#endif /* DEBUG */ 491X 492X if (minor(dev) != 0) 493X err_ret(ENXIO); 494X else 495X { 496X#ifdef __386BSD__ 497X n = MIN(DEV_BSIZE, uio->uio_resid); 498X cp = spkr_inbuf->b_un.b_addr; 499X error = uiomove(cp, n, uio); 500X if (!error) 501X playstring(cp, n); 502X return(error); 503X#else 504X char bfr[STD_BLK]; 505X 506X copyin(u.u_base, bfr, u.u_count); 507X playstring(bfr, u.u_count); 508X u.u_base += u.u_count; 509X u.u_count = 0; 510X#endif 511X } 512X} 513X 514Xint spkrclose(dev) 515Xdev_t dev; 516X{ 517X#ifdef DEBUG 518X printf("spkrclose: entering with dev = %x\n", dev); 519X#endif /* DEBUG */ 520X 521X if (minor(dev) != 0) 522X err_ret(ENXIO); 523X else 524X { 525X endtone(); 526X#ifdef __386BSD__ 527X brelse(spkr_inbuf); 528X#endif 529X spkr_active = 0; 530X } 531X#ifdef __386BSD__ 532X return(0); 533X#endif 534X} 535X 536Xint spkrioctl(dev, cmd, cmdarg) 537Xdev_t dev; 538Xint cmd; 539XCADDR cmdarg; 540X{ 541X#ifdef DEBUG 542X printf("spkrioctl: entering with dev = %x, cmd = %x\n", dev, cmd); 543X#endif /* DEBUG */ 544X 545X if (minor(dev) != 0) 546X err_ret(ENXIO); 547X else if (cmd == SPKRTONE) 548X { 549X tone_t *tp = (tone_t *)cmdarg; 550X 551X if (tp->frequency == 0) 552X rest(tp->duration); 553X else 554X tone(tp->frequency, tp->duration); 555X } 556X else if (cmd == SPKRTUNE) 557X { 558X#ifdef __386BSD__ 559X tone_t *tp = (tone_t *)(*(caddr_t *)cmdarg); 560X tone_t ttp; 561X int error; 562X 563X for (; ; tp++) { 564X error = copyin(tp, &ttp, sizeof(tone_t)); 565X if (error) 566X return(error); 567X if (ttp.duration == 0) 568X break; 569X if (ttp.frequency == 0) 570X rest(ttp.duration); 571X else 572X tone(ttp.frequency, ttp.duration); 573X } 574X#else 575X tone_t *tp = (tone_t *)cmdarg; 576X 577X for (; tp->duration; tp++) 578X if (tp->frequency == 0) 579X rest(tp->duration); 580X else 581X tone(tp->frequency, tp->duration); 582X#endif 583X } 584X else 585X err_ret(EINVAL); 586X#ifdef __386BSD__ 587X return(0); 588X#endif 589X} 590X 591X#endif /* !defined(__386BSD__) || (NSPEAKER > 0) */ 592X/* spkr.c ends here */ 593END-of-spkr.c 594echo x - spkr.h 595sed 's/^X//' >spkr.h << 'END-of-spkr.h' 596X/* 597X * spkr.h -- interface definitions for speaker ioctl() 598X * 599X * v1.1 by Eric S. Raymond (esr@snark.thyrsus.com) Feb 1990 600X * modified for 386bsd by Andrew A. Chernov <ache@astral.msk.su> 601X */ 602X 603X#ifndef _SPKR_H_ 604X#define _SPKR_H_ 605X 606X#ifdef __386BSD__ 607X#ifndef KERNEL 608X#include <sys/ioctl.h> 609X#else 610X#include "ioctl.h" 611X#endif 612X 613X#define SPKRTONE _IOW('S', 1, tone_t) /* emit tone */ 614X#define SPKRTUNE _IO('S', 2) /* emit tone sequence*/ 615X#else /* SYSV */ 616X#define SPKRIOC ('S'<<8) 617X#define SPKRTONE (SPKRIOC|1) /* emit tone */ 618X#define SPKRTUNE (SPKRIOC|2) /* emit tone sequence*/ 619X#endif 620X 621Xtypedef struct 622X{ 623X int frequency; /* in hertz */ 624X int duration; /* in 1/100ths of a second */ 625X} 626Xtone_t; 627X 628X#endif /* _SPKR_H_ */ 629X/* spkr.h ends here */ 630END-of-spkr.h 631echo x - interp.c 632sed 's/^X//' >interp.c << 'END-of-interp.c' 633X/* 634X * interp.c -- device driver for console speaker on 80386 635X * 636X * v1.1 by Eric S. Raymond (esr@snark.thyrsus.com) Feb 1990 637X * 638X * this is the part of the code common to all 386 UNIX OSes 639X * 640X * playinit() and playstring() are called from the appropriate driver 641X */ 642X 643X#ifdef __386BSD__ 644X#include "param.h" 645X#else 646X#include <sys/param.h> 647X#endif 648X 649X#ifndef HZ 650X#define HZ 60 651X#endif 652X 653X 654X/**************** PLAY STRING INTERPRETER BEGINS HERE ********************** 655X * 656X * Play string interpretation is modelled on IBM BASIC 2.0's PLAY statement; 657X * M[LNS] are missing and the ~ synonym and octave-tracking facility is added. 658X * Requires tone(), rest(), and endtone(). String play is not interruptible 659X * except possibly at physical block boundaries. 660X */ 661X 662Xtypedef int bool; 663X#ifndef TRUE 664X#define TRUE 1 665X#endif 666X#ifndef FALSE 667X#define FALSE 0 668X#endif 669X 670X#define toupper(c) ((c) - ' ' * (((c) >= 'a') && ((c) <= 'z'))) 671X#define isdigit(c) (((c) >= '0') && ((c) <= '9')) 672X#define dtoi(c) ((c) - '0') 673X 674Xstatic int octave; /* currently selected octave */ 675Xstatic int whole; /* whole-note time at current tempo, in ticks */ 676Xstatic int value; /* whole divisor for note time, quarter note = 1 */ 677Xstatic int fill; /* controls spacing of notes */ 678Xstatic bool octtrack; /* octave-tracking on? */ 679Xstatic bool octprefix; /* override current octave-tracking state? */ 680X 681X/* 682X * Magic number avoidance... 683X */ 684X#define SECS_PER_MIN 60 /* seconds per minute */ 685X#define WHOLE_NOTE 4 /* quarter notes per whole note */ 686X#define MIN_VALUE 64 /* the most we can divide a note by */ 687X#define DFLT_VALUE 4 /* default value (quarter-note) */ 688X#define FILLTIME 8 /* for articulation, break note in parts */ 689X#define STACCATO 6 /* 6/8 = 3/4 of note is filled */ 690X#define NORMAL 7 /* 7/8ths of note interval is filled */ 691X#define LEGATO 8 /* all of note interval is filled */ 692X#define DFLT_OCTAVE 4 /* default octave */ 693X#define MIN_TEMPO 32 /* minimum tempo */ 694X#define DFLT_TEMPO 120 /* default tempo */ 695X#define MAX_TEMPO 255 /* max tempo */ 696X#define NUM_MULT 3 /* numerator of dot multiplier */ 697X#define DENOM_MULT 2 /* denominator of dot multiplier */ 698X 699X/* letter to half-tone: A B C D E F G */ 700Xstatic int notetab[8] = {9, 11, 0, 2, 4, 5, 7}; 701X 702X/* 703X * This is the American Standard A440 Equal-Tempered scale with frequencies 704X * rounded to nearest integer. Thank Goddess for the good ol' CRC Handbook... 705X * our octave 0 is standard octave 2. 706X */ 707X#define OCTAVE_NOTES 12 /* semitones per octave */ 708Xstatic int pitchtab[] = 709X{ 710X/* C C# D D# E F F# G G# A A# B*/ 711X/* 0 */ 65, 69, 73, 78, 82, 87, 93, 98, 103, 110, 117, 123, 712X/* 1 */ 131, 139, 147, 156, 165, 175, 185, 196, 208, 220, 233, 247, 713X/* 2 */ 262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494, 714X/* 3 */ 523, 554, 587, 622, 659, 698, 740, 784, 831, 880, 932, 988, 715X/* 4 */ 1047, 1109, 1175, 1245, 1319, 1397, 1480, 1568, 1661, 1760, 1865, 1975, 716X/* 5 */ 2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951, 717X/* 6 */ 4186, 4435, 4698, 4978, 5274, 5588, 5920, 6272, 6644, 7040, 7459, 7902, 718X}; 719X 720Xstatic void playinit() 721X{ 722X octave = DFLT_OCTAVE; 723X whole = (HZ * SECS_PER_MIN * WHOLE_NOTE) / DFLT_TEMPO; 724X fill = NORMAL; 725X value = DFLT_VALUE; 726X octtrack = FALSE; 727X octprefix = TRUE; /* act as though there was an initial O(n) */ 728X} 729X 730Xstatic void playtone(pitch, value, sustain) 731X/* play tone of proper duration for current rhythm signature */ 732Xint pitch, value, sustain; 733X{ 734X register int sound, silence, snum = 1, sdenom = 1; 735X 736X /* this weirdness avoids floating-point arithmetic */ 737X for (; sustain; sustain--) 738X { 739X snum *= NUM_MULT; 740X sdenom *= DENOM_MULT; 741X } 742X 743X if (pitch == -1) 744X rest(whole * snum / (value * sdenom)); 745X else 746X { 747X sound = (whole * snum) / (value * sdenom) 748X - (whole * (FILLTIME - fill)) / (value * FILLTIME); 749X silence = whole * (FILLTIME-fill) * snum / (FILLTIME * value * sdenom); 750X 751X#ifdef DEBUG 752X printf("playtone: pitch %d for %d ticks, rest for %d ticks\n", 753X pitch, sound, silence); 754X#endif /* DEBUG */ 755X 756X tone(pitchtab[pitch], sound); 757X if (fill != LEGATO) 758X rest(silence); 759X } 760X} 761X 762Xstatic int abs(n) 763Xint n; 764X{ 765X if (n < 0) 766X return(-n); 767X else 768X return(n); 769X} 770X 771Xstatic void playstring(cp, slen) 772X/* interpret and play an item from a notation string */ 773Xchar *cp; 774Xsize_t slen; 775X{ 776X int pitch, lastpitch = OCTAVE_NOTES * DFLT_OCTAVE; 777X 778X#define GETNUM(cp, v) for(v=0; isdigit(cp[1]) && slen > 0; ) \ 779X {v = v * 10 + (*++cp - '0'); slen--;} 780X for (; slen--; cp++) 781X { 782X int sustain, timeval, tempo; 783X register char c = toupper(*cp); 784X 785X#ifdef DEBUG 786X printf("playstring: %c (%x)\n", c, c); 787X#endif /* DEBUG */ 788X 789X switch (c) 790X { 791X case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': 792X 793X /* compute pitch */ 794X pitch = notetab[c - 'A'] + octave * OCTAVE_NOTES; 795X 796X /* this may be followed by an accidental sign */ 797X if (cp[1] == '#' || cp[1] == '+') 798X { 799X ++pitch; 800X ++cp; 801X slen--; 802X } 803X else if (cp[1] == '-') 804X { 805X --pitch; 806X ++cp; 807X slen--; 808X } 809X 810X /* 811X * If octave-tracking mode is on, and there has been no octave- 812X * setting prefix, find the version of the current letter note 813X * closest to the last regardless of octave. 814X */ 815X if (octtrack && !octprefix) 816X { 817X if (abs(pitch-lastpitch) > abs(pitch+OCTAVE_NOTES-lastpitch)) 818X { 819X ++octave; 820X pitch += OCTAVE_NOTES; 821X } 822X 823X if (abs(pitch-lastpitch) > abs((pitch-OCTAVE_NOTES)-lastpitch)) 824X { 825X --octave; 826X pitch -= OCTAVE_NOTES; 827X } 828X } 829X octprefix = FALSE; 830X lastpitch = pitch; 831X 832X /* ...which may in turn be followed by an override time value */ 833X GETNUM(cp, timeval); 834X if (timeval <= 0 || timeval > MIN_VALUE) 835X timeval = value; 836X 837X /* ...and/or sustain dots */ 838X for (sustain = 0; cp[1] == '.'; cp++) 839X { 840X slen--; 841X sustain++; 842X } 843X 844X /* time to emit the actual tone */ 845X playtone(pitch, timeval, sustain); 846X break; 847X 848X case 'O': 849X if (cp[1] == 'N' || cp[1] == 'n') 850X { 851X octprefix = octtrack = FALSE; 852X ++cp; 853X slen--; 854X } 855X else if (cp[1] == 'L' || cp[1] == 'l') 856X { 857X octtrack = TRUE; 858X ++cp; 859X slen--; 860X } 861X else 862X { 863X GETNUM(cp, octave); 864X if (octave >= sizeof(pitchtab) / OCTAVE_NOTES) 865X octave = DFLT_OCTAVE; 866X octprefix = TRUE; 867X } 868X break; 869X 870X case '>': 871X if (octave < sizeof(pitchtab) / OCTAVE_NOTES - 1) 872X octave++; 873X octprefix = TRUE; 874X break; 875X 876X case '<': 877X if (octave > 0) 878X octave--; 879X octprefix = TRUE; 880X break; 881X 882X case 'N': 883X GETNUM(cp, pitch); 884X for (sustain = 0; cp[1] == '.'; cp++) 885X { 886X slen--; 887X sustain++; 888X } 889X playtone(pitch - 1, value, sustain); 890X break; 891X 892X case 'L': 893X GETNUM(cp, value); 894X if (value <= 0 || value > MIN_VALUE) 895X value = DFLT_VALUE; 896X break; 897X 898X case 'P': 899X case '~': 900X /* this may be followed by an override time value */ 901X GETNUM(cp, timeval); 902X if (timeval <= 0 || timeval > MIN_VALUE) 903X timeval = value; 904X for (sustain = 0; cp[1] == '.'; cp++) 905X { 906X slen--; 907X sustain++; 908X } 909X playtone(-1, timeval, sustain); 910X break; 911X 912X case 'T': 913X GETNUM(cp, tempo); 914X if (tempo < MIN_TEMPO || tempo > MAX_TEMPO) 915X tempo = DFLT_TEMPO; 916X whole = (HZ * SECS_PER_MIN * WHOLE_NOTE) / tempo; 917X break; 918X 919X case 'M': 920X if (cp[1] == 'N' || cp[1] == 'n') 921X { 922X fill = NORMAL; 923X ++cp; 924X slen--; 925X } 926X else if (cp[1] == 'L' || cp[1] == 'l') 927X { 928X fill = LEGATO; 929X ++cp; 930X slen--; 931X } 932X else if (cp[1] == 'S' || cp[1] == 's') 933X { 934X fill = STACCATO; 935X ++cp; 936X slen--; 937X } 938X break; 939X } 940X } 941X} 942END-of-interp.c 943echo x - Files 944sed 's/^X//' >Files << 'END-of-Files' 945X/usr/include/sys/spkr.h 946END-of-Files 947echo x - Install 948sed 's/^X//' >Install << 'END-of-Install' 949X# 950X# Speaker driver installation script 951X# 952XTMP=/tmp/speaker.err 953XERR1=" Errors have been written to the file $TMP." 954XERR2=" The Speaker Driver software was not installed." 955X 956Xecho "Installing Speaker Driver Software Package" 957X 958X/etc/conf/bin/idcheck -p speaker 2>$TMP 959Xif [ $? != 0 ] 960Xthen 961X echo "The speaker package is already at least partly installed. 962X Removing the old version now..." 963X /etc/conf/bin/idinstall -d speaker 964Xfi 965X 966X/etc/conf/bin/idinstall -a -k speaker 2>>$TMP 967Xif [ $? != 0 ] 968Xthen 969X message "There was an error during package installation. $ERR1 $ERR2" 970X exit 1 971Xfi 972X 973X/etc/conf/bin/idbuild 2>>$TMP 974Xif [ $? != 0 ] 975Xthen 976X message "There was an error during kernel reconfiguration. $ERR1 $ERR2" 977X exit 1 978Xfi 979X 980Xrm -f $TMP 981X 982Xcp spkr.h /usr/include/sys/spkr.h 983X 984Xecho "Performing shutdown..." 985Xcd /; exec /etc/shutdown -g0 -y 986END-of-Install 987echo x - Master 988sed 's/^X//' >Master << 'END-of-Master' 989Xspeaker ocwi iocH spkr 0 0 1 1 -1 990END-of-Master 991echo x - Name 992sed 's/^X//' >Name << 'END-of-Name' 993X386 UNIX Speaker Device Driver Package 994END-of-Name 995echo x - Node 996sed 's/^X//' >Node << 'END-of-Node' 997Xspeaker speaker c 0 998END-of-Node 999echo x - Remove 1000sed 's/^X//' >Remove << 'END-of-Remove' 1001X# 1002X# Speaker driver remove script 1003X# 1004XTMP=/tmp/speaker.err 1005XRERR="Errors have been written to the file $TMP." 1006X 1007Xecho "Removing Speaker Driver Software Package" 1008X 1009X/etc/conf/bin/idinstall -d speaker 2>$TMP 1010Xif [ $? != 0 ] 1011Xthen 1012X message "There was an error during package removal. $RERR" 1013X exit 1 1014Xfi 1015X 1016X/etc/conf/bin/idbuild 2>>$TMP 1017Xif [ $? != 0 ] 1018Xthen 1019X message "There was an error during kernel reconfiguration. $RERR" 1020X exit 1 1021Xfi 1022X 1023Xrm -f /dev/speaker $TMP /usr/include/sys/spkr.h 1024X 1025Xexit 0 1026END-of-Remove 1027echo x - Size 1028sed 's/^X//' >Size << 'END-of-Size' 1029XROOT=1400 1030XUSR=100 1031END-of-Size 1032echo x - System 1033sed 's/^X//' >System << 'END-of-System' 1034Xspeaker Y 1 0 0 0 0 0 0 0 1035END-of-System 1036echo x - playtest 1037sed 's/^X//' >playtest << 'END-of-playtest' 1038X: 1039X# Test script for the speaker driver 1040X# 1041X# v1.0 by Eric S. Raymond (Feb 1990) 1042X# modified for 386bsd by Andrew A. Chernov <ache@astral.msk.su> 1043X# 1044Xreveille="t255l8c.f.afc~c.f.afc~c.f.afc.f.a..f.~c.f.afc~c.f.afc~c.f.afc~c.f.." 1045Xcontact="<cd<a#~<a#>f" 1046Xdance="t240<cfcfgagaa#b#>dc<a#a.~fg.gaa#.agagegc.~cfcfgagaa#b#>dc<a#a.~fg.gga.agfgfgf." 1047Xloony="t255cf8f8edc<a.>~cf8f8edd#e.~ce8cdce8cd.<a>c8c8c#def8af8." 1048X 1049Xcase $1 in 1050Xreveille) echo $reveille >/dev/speaker;; 1051Xcontact) echo $contact >/dev/speaker;; 1052Xdance) echo $dance >/dev/speaker;; 1053Xloony) echo $loony >/dev/speaker;; 1054X*) 1055X echo "No such tune. Available tunes are:" 1056X echo 1057X echo "reveille -- Reveille" 1058X echo "contact -- Contact theme from Close Encounters" 1059X echo "dance -- Lord of the Dance (aka Simple Gifts)" 1060X echo "loony -- Loony Toons theme" 1061X ;; 1062Xesac 1063END-of-playtest 1064exit 1065