OSDN Git Service

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