--- /dev/null
+# Select your audio output device. Current choices are:
+#
+# Sun: Sun workstation with audio hardware.
+# HP: HP9000s700 with audio hardware.
+# X11: The X11 window system.
+# Indigo: SGI Indigo workstation.
+# Linux: IBM PC Console running Linux.
+# AdLib: AdLib/SoundBlaster FM chip.
+# OSS: Open Sound System /dev/dsp device.
+#
+# Adding a new device is as simple as creating a new implementation of the
+# beep.h interface. See beep*.c for examples. Please send any additions
+# to the authors!
+#
+#DEVICE = Sun
+#DEVICE = HP
+#DEVICE = X11
+#DEVICE = Indigo
+DEVICE = Linux
+#DEVICE = AdLib
+#DEVICE = OSS
+
+#
+# For termio a la System V, add -DUSG to DEFINES. (Linux in particular needs
+# this.)
+#
+# For alternate random number generator, add either -DUSELRAND for lrand48(),
+# or -DUSERAND for (ugh) rand(). Default is -DUSERANDOM for random().
+#
+# Define SIGRET to be your signal handler return type if not "void".
+#
+# Define BSDSIGS or POSIXSIGS, depending on what kind of signals you
+# have. "Old-style" signals are not currently supported. Default is BSDSIGS.
+#
+# If the same speaker making the morse code beeps will also make ^G beeps
+# (which occur when you get a letter wrong), you may want to #define
+# ERROR_VOLUME to be 1.; this will cause the ^G beeps to be made using
+# the same routines that do the morse-code beeps, possibly preventing
+# conflicts. (If you prefer quieter error beeps, you can use anything
+# between 0. and 1.; if you want it the same volume as the morse-code
+# beeps, use "-DERROR_VOLUME=volume". If you don't like the pitch of
+# the error tone, you can override the default by #defining ERROR_FREQ to
+# be your favorite wake-up alarm frequency, in hertz.)
+#
+# On a Sun workstation you may want to compile with -DFULLVOLUME (see beepSun.c
+# for more details).
+#
+# If you want the morse to generate all punctuation marks, compile
+# with -DALLPUNCTUATION (see README and morse.c for details).
+# If you want the morse to generate all procedure signs, compile
+# with -DALLPROSIGNS (see README and morse.c for details).
+# If you want the morse to generate all international extensions,
+# compile with -DALLINTERNATIONAL (see README and morse.c for details).
+#
+#DEFINES = -DUSG -DUSELRAND -DPOSIXSIGS
+DEFINES = -DUSG
+#DEFINES = -DUSG -DERROR_VOLUME=1. -DERROR_FREQ=2000.
+#DEFINES = -DFULLVOLUME
+#DEFINES =
+
+# The flags necessary to link with the X11 libraries.
+#X11LIBS = -L/usr/X11/lib -lX11 -lsocket -lnsl
+X11LIBS = -L/usr/X11/lib -lX11
+
+# Your favorite C compiler
+CC = gcc
+#CC = cc
+
+# Any additional flags your favorite C compiler requires to work.
+#CFLAGS = -O -I/usr/X11/include -DSVR4 -DSYSV386 ${DEFINES}
+CFLAGS = -O3 -m486 ${DEFINES}
+
+default:
+ make test
+
+morse: morse${DEVICE}
+ rm -f $@
+ ln morse${DEVICE} $@
+
+morseSun: morse.o beepSun.o
+ $(CC) -o $@ morse.o beepSun.o -L/usr/demo/SOUND -laudio -lm
+
+morseHP: morse.o beepHP.o alarm.o
+ $(CC) -o $@ morse.o beepHP.o alarm.o -lm
+
+morseX11: morse.o beepX11.o alarm.o
+ $(CC) -o $@ morse.o beepX11.o alarm.o $(X11LIBS)
+
+morseIndigo: morse.o beepIndigo.o
+ $(CC) -o $@ morse.o beepIndigo.o -laudio -lm
+
+morseLinux: morse.o beepLinux.o alarm.o
+ $(CC) -o $@ morse.o beepLinux.o alarm.o -lm
+
+morseAdLib: morse.o beepAdLib.o alarm.o
+ $(CC) $(CFLAGS) -o $@ morse.o beepAdLib.o alarm.o -lm
+ strip $@
+ chown root:root $@
+ chmod a+sx $@
+
+morseOSS: morse.o beepOSS.o
+ $(CC) $(CFLAGS) -o $@ morse.o beepOSS.o -lm
+
+QSO:
+ cd qso; make
+ ln qso/QSO ./QSO
+
+#
+# "Jocks find quartz glyph, vex BMW." is my attempt to win Stephen J. Gould's
+# prize (a copy of all his books) for the first person who can come up with a
+# "perfect pangram": a meaningful sentence consisting entirely of common
+# English words, with no abbreviations or proper names, that contains each
+# letter exactly once. He rejected it because it contains "BMW", alas, but
+# he did say it's the closest he's seen so far. - Joe Dellinger
+#
+test: morse QSO
+ \rm -f junk
+ cat test_input > junk
+ qso/QSO >> junk
+ # ./morse -v .04 -w 24 -l -e < junk
+ \rm -f junk
+
+testqso: morse QSO
+ qso/QSO | ./morse -v .04 -w 20 -l -e
+
+all: morse QSO
+
+clean:
+ rm -f *.o morse QSO morseSun morseHP morseX11 morseIndigo morseLinux morseAdLib morseOSS
+ rm -f junk
+ cd qso; make clean
+
+
+morse.o: beep.h Makefile
+beepSun.o: beep.h
+beepHP.o: beep.h alarm.h
+beepX11.o: beep.h alarm.h
+beepIndigo.o: beep.h
+beepLinux.o: beep.h alarm.h
+beepAdLib.o: beep.h alarm.h
+beepOSS.o: beep.h
+alarm.o: alarm.h
--- /dev/null
+A generic morse-code practice utility for Unix systems.
+
+Currently supported devices:
+ Sun: Sun workstation with audio hardware.
+ HP: HP9000s700 with audio hardware.
+ X11: The X11 window system. (Warning: not all X11 implementations handle
+ duration and frequency of beeps properly!)
+ Indigo: The SGI Indigo workstation. (See comments in beepIndigo.c about
+ caveats and limitations.)
+ Linux: The IBM PC console speaker.
+ AdLib: AdLib/SoundBlaster FM chip. (See comments in beepAdLib.c about
+ caveats and limitations.)
+ OSS: Open Sound System /dev/dsp device.
+
+Adding a new device is as simple as creating a new implementation of the
+beep.h interface. See beep*.[ch] for examples and documentation.
+Please send any additions to the authors!!
+
+A modified version of the program "QSO" by Paul J. Drongowski is also included.
+
+ Morse Code Table
+
+ A .- N -. 1 .---- . .-.-.-
+ B -... O --- 2 ..--- , --..--
+ C -.-. P .--. 3 ...-- ? ..--..
+ D -.. Q --.- 4 ....- ( -.--.
+ E . R .-. 5 ..... - -....-
+ F ..-. S ... 6 -....
+ G --. T - 7 --...
+ H .... U ..- 8 ---..
+ I .. V ...- 9 ----.
+ J .--- W .-- 0 -----
+ K -.- X -..- / -..-.
+ L .-.. Y -.-- + .-.-.
+ M -- Z --.. = -...-
+
+The following characters are included if one defines ALLPUNCTUATION :
+
+ ) -.--.- " .-..-. _ ..--.- ' .----.
+ : ---... ; -.-.-. $ ...-..- ! -.-.--
+
+ Procedural Signals (Prosigns) for Morse Code
+
+<AR> "+" over, end of message
+<AS> "*" please stand by (<AS> 5 Wait 5 Minutes) (".-...")
+<BT> "=" (double dash) pause, break for text
+CL going off the air (clear)
+CQ calling any station
+K go, invite any station to transmit
+<KN> "(" go only, invite a specific station to transmit
+R all received OK
+<SK> "%" end of contact (sent before call) ("...-.-", known also as <VA>)
+
+The following Procedural Signals (Prosigns) are included if one
+defines ALLPROSIGNS :
+
+<AA> "^" new line (".-.-", the same as :a, ae)
+<BK> "#" invite receiving station to transmit ("-...-.-")
+<KA> "&" attention ("-.-.-")
+<SN> "@" understood ("...-.")
+
+The following characters are included if one defines ALLINTERNATIONAL :
+
+ :a .-.- (also for ae, the same as <AA>)
+ `a .--.- (also oa, danish a with ring over it)
+ ch ---- (bar-ch ?, bar-h ?, ISO 8859-1 code 199 and 231 ?)
+ -d ..--. (eth, overstrike d with -, ISO 8859-1 code 208 and 240)
+ `e ..-..
+ ~n --.--
+ :o ---. (also for oe)
+ :u ..-- (also for ue)
+ ]p .--.. (thorn, overstrike ] with p, ISO 8859-1 code 222 and 254)
+ paragraph .-.-.. (ISO 8859-1 code 167 ?)
+
+Special Characters and Groups (never included, placed here for completeness) :
+
+Multiplication sign -..- (the same as x, ISO 8859-1 code 215 ?)
+
+"Mistake, delete the last word" ........ (actually six or more dots are
+used for this purpose, eight dots are recommended).
+
+Cut Numbers :
+1 .- 6 -... 1 .- 6 -....
+2 ..- 7 --. 2 ..- 7 -...
+3 .-- 8 -.. 3 ...- 8 -..
+4 ...- 9 -. 4 ....- 9 -.
+5 ... 0 - 5 . 0 -
+
+Written by:
+ Joe Dellinger, Hawaii Institute of Geophysics, University of Hawaii at Manoa
+ submitted to comp.sources.misc Dec 15 1993
+ Revised version submitted to comp.sources.misc Nov 22 1994
+
+- joe@sep.stanford.edu
+ jdellinger@trc.amoco.com
+ joe@soest.hawaii.edu
+
+This version dated:
+ Wed Jan 17 09:43:16 CET 2001
+
--- /dev/null
+/* alarm.c -- seligman 6/92 */
+
+/*
+-- Implementation of alarm.h
+*/
+
+#include <stdio.h>
+#include <signal.h>
+#include <sys/time.h>
+
+static int alarmPending = 0; /* Nonzero when the alarm is set. */
+
+static void ualarm();
+static void AlarmHandler();
+
+/* Default BSDSIGS for backwards compatibility of makefile */
+#ifndef BSDSIGS
+#ifndef POSIXSIGS
+#ifndef OTHERSIGS
+#define BSDSIGS
+#endif
+#endif
+#endif
+
+void AlarmSet(time)
+ int time;
+{
+ alarmPending = 1;
+#ifdef BSDSIGS
+ signal(SIGALRM, AlarmHandler);
+#else
+#ifdef POSIXSIGS
+ sigset(SIGALRM, AlarmHandler);
+#else
+ /* You're on your own... */
+# endif /*POSIXSIGS*/
+#endif /*BSDSIGS*/
+ ualarm(1000 * time, 0);
+}
+
+
+/*
+-- If an alarm signal is lurking (due to a prior call to SetAlarm), then
+-- pause until it arrives. This procedure could have simply been written:
+-- if (alarmPending) pause();
+-- but that allows a potential race condition.
+*/
+void AlarmWait()
+{
+#ifdef BSDSIGS
+ long savemask = sigblock(sigmask(SIGALRM));
+ if (alarmPending)
+ sigpause(savemask);
+ sigsetmask(savemask);
+#else
+#ifdef POSIXSIGS
+ sighold(SIGALRM);
+ if (alarmPending)
+ sigpause(SIGALRM);
+ sigrelse(SIGALRM);
+#else
+ /* You're on your own */
+#endif /*POSIXSIGS*/
+#endif /*BSDSIGS*/
+
+}
+
+
+static void ualarm(us)
+ unsigned us;
+{
+ struct itimerval rttimer, old_rttimer;
+
+ rttimer.it_value.tv_sec = us / 1000000;
+ rttimer.it_value.tv_usec = us % 1000000;
+ rttimer.it_interval.tv_sec = 0;
+ rttimer.it_interval.tv_usec = 0;
+ if (setitimer(ITIMER_REAL, &rttimer, &old_rttimer)) {
+ perror("ualarm");
+ exit(1);
+ }
+}
+
+
+#ifdef __hpux
+
+static void AlarmHandler(sig, code, scp)
+ int sig;
+ int code;
+ struct sigcontext *scp;
+{
+ alarmPending = 0;
+ /* Prevent alarm signal from interrupting any pending read. */
+ if (scp->sc_syscall == SYS_READ)
+ scp->sc_syscall_action = SIG_RESTART;
+}
+
+#else
+
+static void AlarmHandler()
+{
+ alarmPending = 0;
+}
+
+#endif __hpux
--- /dev/null
+/* alarm.h -- seligman 6/92 */
+
+/*
+-- Routines for using the system interval timer to time beeps. Useful
+-- for implementing the functions in beep.h on systems that don't provide
+-- a more straightforward BeepWait() equivalent.
+--
+-- These routines use the ALRM signal.
+*/
+
+
+/*
+-- Set the alarm for a time specified in ms.
+*/
+void AlarmSet(/*int time*/);
+
+/*
+-- Wait for the alarm, or return immediately if the alarm isn't set.
+*/
+void AlarmWait();
--- /dev/null
+/* beep.h -- seligman 5/92 */
+
+/*
+-- Machine-dependent code for sounding a beep.
+*/
+
+#ifndef _BEEP_H
+#define _BEEP_H
+
+
+/*
+-- Called exactly once, before any other function in this interface.
+-- Returns nonzero on error.
+*/
+int BeepInit();
+
+
+/*
+-- Sound a beep for a time specified in ms.
+-- The volume is in the range [0..100], and the pitch is in Hz.
+--
+-- May return immediately, after the sounding of the beep is completed,
+-- or any time in between. May be called while a previous beep is still
+-- sounding, in which case the previous beep finishes before the new one
+-- begins. Overall timing will be much better if this routine can return
+-- during the sounding of the beep, especially if it's a "zero-volume beep",
+-- meaning it's really just the timed pause of silence between tones.
+-- ("morse.c" tries to do all its thinking during the pauses between beeps,
+-- mostly in the longer ones between words.)
+--
+-- May use the ALRM signal for timing.
+--
+-- Returns nonzero on error.
+*/
+int Beep(/*int time, int volume, int pitch*/);
+
+
+/*
+-- Wait until any currently sounding beeps have completed.
+-- Returns nonzero on error.
+*/
+int BeepWait();
+
+
+/*
+-- Clean up any altered state before exiting or suspending the program.
+-- Returns nonzero on error.
+*/
+int BeepCleanup();
+
+
+/*
+-- Restore the world when program is resumed after having been suspended.
+-- Returns nonzero on error.
+*/
+int BeepResume();
+
+
+#endif _BEEP_H
--- /dev/null
+/* beepAdLib.c -- Jacek M. Holeczek 3/2000 */
+/* A lot of code taken from the sccw Linux Morse program by */
+/* Steven J. Merrifield VK3ESM sjm@ee.latrobe.edu.au */
+
+/*
+ Implementation of beep for the AdLib/SoundBlaster FM chip.
+
+ Warning: All low-level access is achieved by writing directly to the
+ IO ports of the soundcard, hence this program must be compiled using
+ at least -O2 and run setuid root. Hence, this program must be installed
+ by root, but can then be run by a normal user.
+
+ Must compile with -O2 -lm and optionally -DDEBUG_FREQ
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <math.h>
+#include <sys/io.h>
+
+#include "alarm.h"
+#include "beep.h"
+
+/* Define it if you want to reset the AdLib/SoundBlaster FM chip. */
+#undef RESET_ADLIB
+
+/* The port addresses for the FM chip is always the same. */
+#define reg_port 0x0388
+#define data_port reg_port+1
+
+void wr_register(int index, int data) /* See the PC Game Programmers Encyclopedia */
+{
+ int i,temp;
+ outb(index,reg_port);
+ for (i=1;i<7;i++)
+ temp = inb(reg_port);
+ outb(data,data_port);
+ for (i=1;i<36;i++)
+ temp = inb(reg_port);
+}
+
+int AdLib_found(void) /* See the PC Game Programmers Encyclopedia */
+{
+ long temp1,temp2;
+ wr_register(4,0x60);
+ wr_register(4,0x80);
+ temp1 = inb(reg_port);
+ wr_register(2,0xFF);
+ wr_register(4,0x21);
+ sleep(1);
+ temp2 = inb(reg_port);
+ wr_register(4,0x60);
+ wr_register(4,0x80);
+ if (((temp1 & 0xE0) == 0) && ((temp2 & 0xE0) == 0xC0))
+ {
+ return 0; /* card found and no errors */
+ } else {
+ return 1; /* card not found or errors */
+ }
+}
+
+#ifdef RESET_ADLIB
+void Reset_AdLib(void) /* Set all registers to 0 */
+{
+ int i;
+ for (i=1;i<245;i++)
+ wr_register(i,0);
+}
+#endif
+
+int BeepInit(void)
+{
+ if (geteuid())
+ {
+ fprintf(stderr,"This program must run as root (setuid root).\n");
+ return 1;
+ }
+ ioperm(reg_port,17,1);
+ ioperm(data_port,17,1);
+ if (AdLib_found())
+ {
+ fprintf(stderr,"The AdLib/SoundBlaster card not found.\n");
+ ioperm(reg_port,17,0);
+ ioperm(data_port,17,0);
+ return 2;
+ }
+#ifdef RESET_ADLIB
+ Reset_AdLib();
+#else
+ wr_register(0xB0,0x00); /* Turn off sound, was 0x11 */
+#endif
+ return 0;
+}
+
+int Beep(int time, int volume, int pitch)
+{
+ int blk = -1;
+ int f_num;
+ int A0_reg,B0_reg,B0_reg10,B0_reg432;
+
+ BeepWait();
+ AlarmSet(time);
+
+ if (volume > 0 && pitch > 0)
+ {
+ wr_register(0x20,1); /* Play sound at fundamental freq. */
+ wr_register(0x23,1); /* Carrier at specified freq. */
+ wr_register(0x43,(64*(100-volume)/100)); /* Volume 0-64 */
+
+ wr_register(0x63,0xF0); /* Carrier attack = fast, decay = slow */
+ wr_register(0x83,0xFF); /* Carrier sustain = soft, release = fast */
+
+ /* Would you belive it took three days to work out how to do this ? */
+ do
+ {
+ blk++;
+ f_num = (int)(((float)pitch / 50000.0) / (1/(pow(2,abs(blk-20)))));
+ } while (f_num > 1023);
+ A0_reg = f_num & 0x00FF;
+ B0_reg10 = (f_num & 0x0300) >> 8;
+ B0_reg432 = (blk << 2) & 0x00FF; /* Do I really need to & 0x00ff ?? */
+ B0_reg = (32 | B0_reg432 | B0_reg10) & 0x00FF;
+
+ wr_register(0xA0,A0_reg);
+ wr_register(0xB0,B0_reg);
+
+#ifdef DEBUG_FREQ
+ printf("blk = %d f_num = %d\n",blk,f_num);
+ printf("B0_reg432 = %2x\n",B0_reg432); /* bits 4 3 2 */
+ printf("B0_reg10 = %2x\n",B0_reg10); /* bits 1 0 */
+ printf("B0_reg = %2x A0_reg = %2x\n\n\n",B0_reg,A0_reg);
+#endif
+ }
+
+ return 0;
+}
+
+int BeepWait(void)
+{
+ AlarmWait();
+ wr_register(0xB0,0x00); /* Turn off sound, was 0x11 */
+ return 0;
+}
+
+int BeepCleanup(void)
+{
+#ifdef RESET_ADLIB
+ Reset_AdLib();
+#else
+ wr_register(0xB0,0x00); /* Turn off sound, was 0x11 */
+#endif
+ ioperm(reg_port,17,0);
+ ioperm(data_port,17,0);
+ return 0;
+}
+
+int BeepResume(void)
+{
+ ioperm(reg_port,17,1);
+ ioperm(data_port,17,1);
+#ifdef RESET_ADLIB
+ Reset_AdLib();
+#else
+ wr_register(0xB0,0x00); /* Turn off sound, was 0x11 */
+#endif
+ return 0;
+}
--- /dev/null
+/* beepHP.c -- seligman 5/92 */
+
+/*
+-- Implementation of beep.h for HP9000s700 with audio hardware.
+--
+-- If the environment variable SPEAKER begins with "E", the external
+-- audio connection is used. If it begins with "I", the internal speaker
+-- is used. Otherwise both are used.
+--
+-- Compile with the math library "-lm".
+*/
+
+#include "beep.h"
+#include "alarm.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include <fcntl.h>
+#include <malloc.h>
+
+
+static char *AudioDev;
+
+static int DoBeep();
+
+
+int BeepInit()
+{
+ char *speaker = getenv("SPEAKER");
+ int fd;
+
+ AudioDev = speaker && toupper(speaker[0])=='E' ? "/dev/audioEL"
+ : speaker && toupper(speaker[0])=='I' ? "/dev/audioIL"
+ : "/dev/audioBL";
+
+ /*
+ -- A quick check to ensure that we can open the device.
+ */
+ if ((fd = open(AudioDev, O_WRONLY)) < 0) {
+ perror("?? Error opening audio device");
+ return 1;
+ }
+ close(fd);
+ return 0;
+}
+
+
+/*
+-- Optimized for the case where volume & pitch don't change (except possibly
+-- to zero and back) between successive calls.
+*/
+int Beep(time, volume, pitch)
+ int time, volume, pitch;
+{
+ int rc;
+
+ AlarmWait();
+ if (volume != 0 && pitch != 0)
+ if ((rc = DoBeep(time, volume, pitch)) != 0)
+ return rc;
+ AlarmSet(time);
+ return 0;
+}
+
+
+int BeepWait()
+{
+ AlarmWait();
+ return 0;
+}
+
+
+int BeepCleanup()
+{
+ return 0;
+}
+
+
+int BeepResume()
+{
+ return 0;
+}
+
+
+/*----------------------------------------*/
+
+#define SamplingRate 8000 /* audio device samples per second */
+#define NumRamp (SamplingRate / 200) /* # samples in 5ms ramp up/down */
+
+typedef short int Sample;
+#define MaxSample (Sample)0x7FFF
+
+
+/*
+-- Sound a beep.
+-- Optimized for the case where volume & pitch don't change between successive
+-- calls.
+*/
+static int DoBeep(time, volume, pitch)
+ int time, volume, pitch;
+{
+ static int audioDevFD = -1; /* -1 indicates not yet open. */
+
+ /* Save sample buffer from call to call, and reuse it when possible. */
+ static Sample *buf = NULL;
+ static int bufLen = 0;
+ static int bufVolume = 0;
+ static int bufPitch = 0;
+
+ Sample rampbuf[NumRamp]; /* Sample buffer for ramp-down. */
+
+ /* Are volume and pitch same as previous call? */
+ int sameVP = (volume == bufVolume && pitch == bufPitch);
+
+ int i, j;
+ int numSamples = SamplingRate * time / 1000;
+
+ /*
+ -- It seems that the first write to the audio device after it's
+ -- been opened must be the longest.
+ */
+ if (numSamples > bufLen) {
+ if (audioDevFD >= 0) close(audioDevFD);
+ audioDevFD = -1;
+ }
+ if (audioDevFD < 0) {
+ if ((audioDevFD = open(AudioDev, O_WRONLY)) < 0) {
+ perror("?? Error opening audio device");
+ return 1;
+ }
+ }
+
+ /*
+ -- Allocate space for sample buffer. Set "i" to lowest index in
+ -- need of updating.
+ */
+ i = sameVP ? bufLen : 0;
+ if (numSamples > bufLen) {
+ if (sameVP) {
+ buf = realloc(buf, numSamples * sizeof(Sample));
+ } else {
+ if (buf != NULL) free(buf);
+ bufVolume = volume;
+ bufPitch = pitch;
+ buf = malloc(numSamples * sizeof(Sample));
+ }
+ if (buf == NULL) {
+ fprintf(stderr, "?? Buy more memory.\n");
+ return 1;
+ }
+ bufLen = numSamples;
+ }
+
+ /*
+ -- Update any newly-allocated tail of sample buffer. The ramp-up is
+ -- handled here (since it always occurs at the same place); the ramp-down
+ -- is handled later.
+ */
+ while (i < bufLen) {
+ double rampScale = (i < NumRamp) ? (double) i / NumRamp : 1;
+ double t = (double) i / SamplingRate;
+ buf[i++] =
+ sin(2 * M_PI * pitch * t) * MaxSample * rampScale * volume / 100;
+ }
+
+ /* Sound the beep, except for the ramp-down. */
+ write(audioDevFD, buf, (numSamples - NumRamp) * sizeof(Sample));
+
+ /* Ramp-down */
+ for (i = 0, j = numSamples-NumRamp; i < NumRamp; i++, j++)
+ rampbuf[i] = buf[j] * ((double) (NumRamp - i) / NumRamp);
+ write(audioDevFD, rampbuf, sizeof rampbuf);
+
+ return 0;
+}
--- /dev/null
+/* beepIndigo.c John R. Murray murray@scri.fsu.edu Jan. 4, 1994. Implementation
+ * of beep.h for SGI Indigos. Basically a quick rewrite of beepSun.c, written
+ * by seligman et al 6/92
+ */
+
+/*
+ * If the audio library or audio include files are missing, you need
+ * to get sound support off the SGI distribution tapes or CD.
+ *
+ * Defining FULLVOLUME has no effect. See notes below.
+ */
+
+/* NOTES: This will not compile on the older Personal Irises (4D/20 and 4D/25).
+-- It should work for newer PIs (4D/30 and 4D/35) on SGI models newer than the
+-- Indigo (Indy and Indigo^2), but has not been tested. Basically, anything
+-- that uses the Audio Library (ALwhatever function names), and *not* the
+-- /dev/audio interface, should work.
+--
+-- The sound library on my machine is only a partial implementation, so some
+-- functionality in beep.h is missing. Notably:
+--
+-- 1) No software volume control. (relative volume with -v still works, tho)
+--
+-- 2) No software control of sampling rate.
+--
+-- These parameters are controllable through the Audio Control Panel,
+-- accessible through the Tools submenu, or by running /usr/sbin/apanel.
+-- NOTE: This code assumes you have the output sampling rate set to 48 KHz
+-- (the default). If the tone is too low and the code timing is too slow,
+-- your output sampling rate is incorrect and will need to be set to 48 KHz.
+--
+-- If you implement volume and sampling rate control, please be sure to send
+-- the updated code to the writer of morse.c, joe@montebello.soest.hawaii.edu,
+-- or to me and I'll forward it.
+*/
+
+#include "beep.h"
+#include <audio.h>
+#include <math.h>
+
+#define ABUFSIZ (100000) /* 100000 is default buffer size */
+#define RATE (48000) /*48 K samples = 1 second (assuming it's set to the default)*/
+#define RAMP (RATE * 10 / 1000) /* 10 millisecond ramp */
+#define MAXTIME (ABUFSIZ) /* If STEREO, MAXTIME = ABUFSIZ / 2 */
+#define ASCALE (100) /* multiplier to size waveform to port width (assuming 8bit) */
+
+ALport outPort;
+
+void writeSound(port, buffer, len)
+ALport port;
+signed char buffer[];
+unsigned long len;
+{
+ signed char *bufp;
+ unsigned long len2, fill;
+
+ bufp = buffer;
+ len2 = len;
+ while ((fill = ALgetfillable(port)) < len2)
+ {
+ if (fill)
+ {
+ /* write as much as we can */
+ ALwritesamps(port, bufp, fill);
+ bufp += fill;
+ len2 -= fill;
+ }
+ else
+ {
+ /* wait 1/CLK_TCK seconds (1/100 sec on my machine) */
+ sginap(1);
+ }
+ }
+ ALwritesamps(port, bufp, len2);
+}
+
+int
+BeepInit ()
+{
+
+ ALconfig config;
+
+ config = ALnewconfig();
+ /* starting with default config (stereo, 16 bit wide samples, 100k buffer) */
+ /* NOTE: we're assuming the sampling rate is set to the default (48K) */
+ /* (software control of sampling rate is not fully implemented by SGI yet */
+
+ if (config == 0)
+ {
+ /* Uh oh! */
+ return 1;
+ }
+ else
+ {
+ /* this is just to avoid rewriting much of Beep, we could
+ * run 24 bit stereo if we wanted.
+ */
+ ALsetwidth(config, AL_SAMPLE_8);
+ ALsetchannels(config, AL_MONO); /* if STEREO, fix the #define of MAXTIME */
+ ALsetqueuesize(config, ABUFSIZ);
+
+#ifdef FULLVOLUME
+ /* software volume control not fully implemented by SGI yet */
+#endif
+
+ if (0 == (outPort = ALopenport("morse", "w", config)))
+ /* another problem */
+ return 1;
+ ALfreeconfig(config);
+ return 0;
+ }
+}
+
+
+int
+Beep (time, volume, pitch)
+ int time, volume, pitch;
+{
+static signed char silence[MAXTIME];
+static signed char soundbuf[MAXTIME - RAMP];
+static signed char ramp_down[RAMP];
+static long last_n = 0xFFFFFFFFL;
+static int last_pitch = -1, last_volume = -1;
+static int first_time = 1;
+
+int i, cycle;
+unsigned long n, first_len, down_len;
+double dt;
+
+/*
+ * Initialize the sound of silence
+ */
+ if (first_time == 1)
+ {
+ for (i = 0; i < MAXTIME; i++)
+ silence[i] = 0;
+ first_time = 0;
+ }
+
+
+/*
+ * Finagle the number of samples
+ */
+ n = (time / 1000.) * RATE; /* Number samples in tone time */
+ n = n < MAXTIME ? n : MAXTIME; /* clip to buffer size */
+ n = n < 2 * RAMP ? 2 * RAMP : n; /* leave room for ramps */
+
+/*
+ * Catch stupidity
+ */
+ if (pitch <= 0)
+ volume = 0;
+
+
+ if (volume <= 0)
+ {
+ writeSound(outPort, silence, n);
+ }
+ else
+ {
+/*
+ * clip to Nyquist
+ * (Of course this means that if you ask for too high a frequency you
+ * just get silence, since you sample all the zero-crossings of the
+ * sine wave.)
+ */
+ pitch = pitch < RATE / 2 ? pitch : RATE / 2;
+ cycle = ((RATE + 1.e-6) / pitch); /* samples per cycle */
+
+ if (cycle > MAXTIME / 2)
+ cycle = MAXTIME / 2;
+
+ /* round down length of (rampup + mesa top) to integral cycle */
+ first_len = ((n - RAMP) / cycle) * cycle;
+ if (first_len < cycle)
+ first_len = cycle;
+ if (first_len > MAXTIME - RAMP)
+ first_len = MAXTIME - RAMP;
+
+ /* round down length of (rampdown) to integral cycle */
+ down_len = ((RAMP) / cycle) * cycle;
+ if (down_len < cycle)
+ down_len = cycle;
+ if (down_len > RAMP)
+ down_len = RAMP;
+
+/*
+ * Can we just reuse what we had before?
+ */
+ if (pitch != last_pitch || n > last_n || volume != last_volume)
+ {
+ last_pitch = pitch;
+ last_n = n;
+ last_volume = volume;
+
+ dt = 2. * 3.14159 / cycle; /* sine scale factor */
+
+/* Ramp up; begin with silence */
+
+ for (i = 0; i < RAMP; i++)
+ {
+ soundbuf[i] = ASCALE * ((float) i / RAMP) * (volume / 100.)
+ * sin (i * dt);
+ }
+
+/* Mesa top */
+ for (i = RAMP; i < first_len; i++)
+ {
+ soundbuf[i] = ASCALE * 1. * (volume / 100.) * sin (i * dt);
+ }
+
+/* Ramp down; end with silence */
+ for (i = 0; i < down_len; i++)
+ {
+ ramp_down[i] = ASCALE * (1. - (float) (i + 1) / down_len)
+ * (volume / 100.) * sin (i * dt);
+ }
+ }
+ writeSound(outPort, soundbuf, first_len);
+ writeSound(outPort, ramp_down, down_len);
+ }
+
+ return 0;
+}
+
+
+int
+BeepWait ()
+{
+ while (ALgetfilled(outPort) > 0)
+ sginap(1); /* wait 1/CLK_TCK seconds (1/100th second on my machine) */
+ return 0;
+}
+
+
+int
+BeepCleanup ()
+{
+ ALcloseport(outPort);
+ return 0;
+}
+
+
+int
+BeepResume ()
+{
+ return BeepInit();
+}
--- /dev/null
+/*
+ * From: jmorriso@bogomips.ee.ubc.ca (John Paul Morrison)
+ * Subject: beepLinux.c
+ * To: joe@montebello.soest.hawaii.edu
+ * Date: Fri, 18 Nov 1994 15:32:33 -0800 (PST)
+ * X-Linux: watch for it: Linux 94 aka "Helsinki"
+ *
+ * beepLinux.c for morse (lightly tested, seems to work fine)
+ */
+
+/*
+ * beep for the Linux console (PC Speaker)
+ *
+ * (beepSun.c might work if you have a sound card installed and /dev/audio)
+ *
+ * by John Paul Morrison <jmorriso@ve7jpm.ampr.org>
+ *
+ */
+
+/* beepLinux.c -- 11/94 */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/kd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include "alarm.h"
+#include "beep.h"
+
+
+static int fd;
+
+int BeepInit()
+{
+ if ((fd = open("/dev/console",O_WRONLY)) == -1)
+ {
+ fprintf(stderr,"You have no permissions to use /dev/console (chmod a+w).\n");
+ return 1;
+ }
+ return 0;
+}
+
+int Beep(time, volume, pitch)
+int time, volume, pitch;
+{
+ int count;
+
+ AlarmWait();
+ if (volume == 0)
+ count = 0;
+ else
+ count = (1193180 / pitch) & 0xffff;
+
+ ioctl(fd, KDMKTONE, (time << 16) | count);
+ AlarmSet(time);
+ return 0;
+}
+
+int BeepWait()
+{
+ AlarmWait();
+ return 0;
+}
+
+int BeepCleanup()
+{
+ close(fd);
+ return 0;
+}
+
+int BeepResume()
+{
+ return 0;
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ * BogoMIPS Research Labs -- bogosity research & simulation -- VE7JPM --
+ * jmorriso@bogomips.ee.ubc.ca ve7jpm@ve7jpm.ampr.org jmorriso@ve7ubc.ampr.org
+ * ---------------------------------------------------------------------------
+ */
--- /dev/null
+/* beepOSS.c -- Jacek M. Holeczek 3/2000 */
+/* A lot of code taken from the beepSun.c */
+
+/*
+ Implementation of beep for the Open Sound System /dev/dsp device.
+*/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <sys/soundcard.h>
+#include <math.h>
+
+#include "beep.h"
+
+#define DEVICE_NAME "/dev/dsp"
+#define RATE (8000) /* 8 K samples = 1 second */
+#define RAMP (RATE * 5 / 1000) /* 5 millisecond ramp */
+#define MAXTIME (2 * RATE) /* 2 seconds max tone time */
+
+static int audio = 0;
+static int channels = 0; /* 1=mono, 2=stereo */
+static unsigned char silence[2*MAXTIME];
+static unsigned char soundbuf[2*(MAXTIME - RAMP)];
+static unsigned char ramp_down[2*RAMP];
+
+int BeepInit (void)
+{
+ int i;
+
+ /*
+ * Initialize the sound of silence
+ */
+ for (i = 0; i < 2*MAXTIME; i++)
+ silence[i] = 128;
+
+ audio = open(DEVICE_NAME, O_WRONLY, 0);
+ if (audio < 0)
+ {
+ return 1; /* not o.k. */
+ } else {
+
+ i = 0x00ff0008; /* 255 fragments, 256 bytes each */
+ if (ioctl(audio, SNDCTL_DSP_SETFRAGMENT, &i))
+ {
+ fprintf(stderr, "SNDCTL_DSP_SETFRAGMENT error : 0x%08x\n", i);
+ return 2;
+ }
+
+ channels = 1; /* 1 channel = mono */
+ if (ioctl(audio, SNDCTL_DSP_CHANNELS, &channels)==-1)
+ {
+ fprintf(stderr, "SNDCTL_DSP_CHANNELS error : %i\n", channels);
+ return 3;
+ }
+ if (channels != 1)
+ {
+ channels = 2; /* 2 channels = stereo */
+ if (ioctl(audio, SNDCTL_DSP_CHANNELS, &channels)==-1)
+ {
+ fprintf(stderr, "SNDCTL_DSP_CHANNELS error : %i\n", channels);
+ return 4;
+ }
+ }
+ if (!(channels == 1 || channels == 2))
+ {
+ fprintf(stderr, "Neither mono nor stereo mode could be set.\n");
+ return 5;
+ }
+
+ i = AFMT_U8; /* standard unsigned 8 bit audio encoding */
+ if (ioctl(audio, SNDCTL_DSP_SETFMT, &i)==-1)
+ {
+ fprintf(stderr, "SNDCTL_DSP_SETFMT error : %i\n", i);
+ return 6;
+ }
+
+ i = RATE; /* sampling rate RATE */
+ if (ioctl(audio, SNDCTL_DSP_SPEED, &i)==-1)
+ {
+ fprintf(stderr, "SNDCTL_DSP_SPEED error : %i\n", i);
+ return 7;
+ }
+
+ write (audio, silence, channels*2);
+ BeepWait();
+ return 0; /* o.k. */
+ }
+}
+
+int Beep (int time, int volume, int pitch)
+{
+ static int last_pitch = -1, last_n = -1, last_volume = -1;
+ int i, n, first_len, down_len, cycle;
+ double dt;
+
+ /*
+ * Finagle the number of samples
+ */
+ n = (time / 1000.) * RATE; /* Number samples in tone time */
+ n = n < MAXTIME ? n : MAXTIME; /* clip to buffer size */
+ n = n < 2 * RAMP ? 2 * RAMP : n; /* leave room for ramps */
+
+ /*
+ * Catch stupidity
+ */
+ if (pitch <= 0)
+ volume = 0;
+
+ if (volume <= 0)
+ {
+ write (audio, silence, channels*n);
+ }
+ else
+ {
+ /*
+ * clip to Nyquist
+ * (Of course this means that if you ask for too high a frequency you
+ * just get silence, since you sample all the zero-crossings of the
+ * sine wave.)
+ */
+ pitch = pitch < RATE / 2 ? pitch : RATE / 2;
+ cycle = ((RATE + 1.e-6) / pitch); /* samples per cycle */
+
+ if (cycle > MAXTIME / 2)
+ cycle = MAXTIME / 2;
+
+ /* round down length of (rampup + mesa top) to integral cycle */
+ first_len = ((n - RAMP) / cycle) * cycle;
+ if (first_len < cycle)
+ first_len = cycle;
+ if (first_len > MAXTIME - RAMP)
+ first_len = MAXTIME - RAMP;
+
+ /* round down length of (rampdown) to integral cycle */
+ down_len = ((RAMP) / cycle) * cycle;
+ if (down_len < cycle)
+ down_len = cycle;
+ if (down_len > RAMP)
+ down_len = RAMP;
+
+ /*
+ * Can we just reuse what we had before?
+ */
+ if (pitch != last_pitch || n > last_n || volume != last_volume)
+ {
+ last_pitch = pitch;
+ last_n = n;
+ last_volume = volume;
+
+ dt = 2. * M_PI / cycle; /* sine scale factor */
+
+ /* Ramp up; begin with silence */
+
+ for (i = 0; i < RAMP; i++)
+ {
+ soundbuf[i*channels] = rint( 128. +
+ ((float) i / RAMP) * (volume * 1.26) * sin (i * dt)
+ );
+ if (channels == 2)
+ soundbuf[i*channels+1] = soundbuf[i*channels];
+ }
+
+ /* Mesa top */
+ for (i = RAMP; i < first_len; i++)
+ {
+ soundbuf[i*channels] = rint( 128. +
+ 1. * (volume * 1.26) * sin (i * dt)
+ );
+ if (channels == 2)
+ soundbuf[i*channels+1] = soundbuf[i*channels];
+ }
+
+ /* Ramp down; end with silence */
+ for (i = 0; i < down_len; i++)
+ {
+ ramp_down[i*channels] = rint( 128. +
+ (1. - (float) (i + 1) / down_len) * (volume * 1.26) * sin (i * dt)
+ );
+ if (channels == 2)
+ ramp_down[i*channels+1] = ramp_down[i*channels];
+ }
+ }
+
+ write (audio, soundbuf, channels*first_len);
+ write (audio, ramp_down, channels*down_len);
+ }
+
+ return 0;
+}
+
+int BeepWait (void)
+{
+ ioctl (audio, SNDCTL_DSP_SYNC, 0);
+ return 0;
+}
+
+int BeepCleanup (void)
+{
+ return 0;
+}
+
+int BeepResume (void)
+{
+ return 0;
+}
--- /dev/null
+/*
+ * If the audio library or audio include files are missing, you need
+ * to get /usr/demo/SOUND off the Sun OS tapes or CD.
+ *
+ * If FULLVOLUME is defined this routine will turn your audio device up to
+ * full volume; it will not attempt to reset the current speaker / jack choice.
+ */
+
+/* beepSun.c -- seligman 6/92 */
+
+/*
+-- Implementation of beep.h for Sun.
+-- Rick to Joe to Scott to Joe.
+*/
+
+/* Date: Fri, 2 Aug 91 08:26:08 PDT */
+/* From: rick@st.unocal.com (Richard Ottolini) */
+
+/* Revised: Joe Dellinger */
+/* Sat Nov 28 02:30:32 HST 1992 */
+
+/* Revised: Brian Suggs (fixed the "annoying click" bug) */
+/* Fri Sep 16 12:29:13 PDT 1994 */
+
+#include "beep.h"
+#include <sun/audioio.h>
+#include </usr/demo/SOUND/multimedia/libaudio.h>
+#include </usr/demo/SOUND/multimedia/ulaw2linear.h>
+#include <stropts.h>
+#include <math.h>
+#include <fcntl.h>
+
+
+#define RATE (8000) /* 8 K samples = 1 second */
+#define RAMP (RATE * 5 / 1000) /* 5 millisecond ramp */
+#define MAXTIME (2 * RATE) /* 2 seconds max tone time */
+
+static int audio;
+static audio_info_t audio_stat;
+
+int
+BeepInit ()
+{
+ audio = open ("/dev/audio", O_WRONLY);
+
+ if (audio < 0)
+ /* Uh oh! */
+ return 1;
+ else
+ {
+#ifdef FULLVOLUME
+ /*
+ * Turn the speaker (or headphone, whichever the user has it set to)
+ * up to full volume.
+ */
+ AUDIO_INITINFO(&audio_stat);
+ audio_stat.play.gain = AUDIO_MAX_GAIN;
+ ioctl (audio, AUDIO_SETINFO, &audio_stat);
+#endif
+
+ return 0;
+ }
+}
+
+
+int
+Beep (time, volume, pitch)
+ int time, volume, pitch;
+{
+static unsigned char silence[MAXTIME];
+static unsigned char soundbuf[MAXTIME - RAMP];
+static unsigned char ramp_down[RAMP];
+static int last_pitch = -1, last_n = -1, last_volume = -1;
+static int first_time = 1;
+
+int i, n, first_len, down_len, cycle;
+double dt;
+
+/*
+ * Initialize the sound of silence
+ */
+ if (first_time == 1)
+ {
+ for (i = 0; i < MAXTIME; i++)
+ silence[i] = audio_l2u (0);
+ first_time = 0;
+ }
+
+
+/*
+ * Finagle the number of samples
+ */
+ n = (time / 1000.) * RATE; /* Number samples in tone time */
+ n = n < MAXTIME ? n : MAXTIME; /* clip to buffer size */
+ n = n < 2 * RAMP ? 2 * RAMP : n; /* leave room for ramps */
+
+/*
+ * Catch stupidity
+ */
+ if (pitch <= 0)
+ volume = 0;
+
+
+ if (volume <= 0)
+ {
+ write (audio, silence, n);
+ }
+ else
+ {
+/*
+ * clip to Nyquist
+ * (Of course this means that if you ask for too high a frequency you
+ * just get silence, since you sample all the zero-crossings of the
+ * sine wave.)
+ */
+ pitch = pitch < RATE / 2 ? pitch : RATE / 2;
+ cycle = ((RATE + 1.e-6) / pitch); /* samples per cycle */
+
+ if (cycle > MAXTIME / 2)
+ cycle = MAXTIME / 2;
+
+ /* round down length of (rampup + mesa top) to integral cycle */
+ first_len = ((n - RAMP) / cycle) * cycle;
+ if (first_len < cycle)
+ first_len = cycle;
+ if (first_len > MAXTIME - RAMP)
+ first_len = MAXTIME - RAMP;
+
+ /* round down length of (rampdown) to integral cycle */
+ down_len = ((RAMP) / cycle) * cycle;
+ if (down_len < cycle)
+ down_len = cycle;
+ if (down_len > RAMP)
+ down_len = RAMP;
+
+/*
+ * Can we just reuse what we had before?
+ */
+ if (pitch != last_pitch || n > last_n || volume != last_volume)
+ {
+ last_pitch = pitch;
+ last_n = n;
+ last_volume = volume;
+
+ dt = 2. * M_PI / cycle; /* sine scale factor */
+
+/* Ramp up; begin with silence */
+
+ for (i = 0; i < RAMP; i++)
+ {
+ soundbuf[i] = audio_l2u (audio_d2l (
+ ((float) i / RAMP) * (volume / 100.) * sin (i * dt)
+ ));
+ }
+
+/* Mesa top */
+ for (i = RAMP; i < first_len; i++)
+ {
+ soundbuf[i] = audio_l2u (audio_d2l (
+ 1. * (volume / 100.) * sin (i * dt)
+ ));
+ }
+
+/* Ramp down; end with silence */
+ for (i = 0; i < down_len; i++)
+ {
+ ramp_down[i] = audio_l2u (audio_d2l (
+ (1. - (float) (i + 1) / down_len) * (volume / 100.) * sin (i * dt)
+ ));
+ }
+ }
+
+ write (audio, soundbuf, first_len);
+ write (audio, ramp_down, down_len);
+ }
+
+ return 0;
+}
+
+
+int
+BeepWait ()
+{
+ ioctl (audio, AUDIO_DRAIN);
+ return 0;
+}
+
+
+int
+BeepCleanup ()
+{
+ return 0;
+}
+
+
+int
+BeepResume ()
+{
+ return 0;
+}
--- /dev/null
+/* beepX11.c -- seligman 5/92 */
+
+/*
+-- Implementation of beep.h for X11.
+--
+-- Compile with the library "-lX11".
+*/
+
+#include <stdio.h>
+#include <X11/Xlib.h>
+#include "alarm.h"
+#include "beep.h"
+
+static Display *dpy = 0;
+static XKeyboardControl initialState;
+
+#define BellFlags (KBBellPercent | KBBellPitch | KBBellDuration)
+
+
+int BeepInit()
+{
+ XKeyboardState state;
+
+ if (! (dpy = XOpenDisplay(0))) {
+ perror("Couldn't open display");
+ return 1;
+ }
+
+ /* Save initial state so it can be restored later. */
+ XGetKeyboardControl(dpy, &state);
+ initialState.bell_duration = state.bell_duration;
+ initialState.bell_percent = state.bell_percent;
+ initialState.bell_pitch = state.bell_pitch;
+
+ return 0;
+}
+
+
+int Beep(time, volume, pitch)
+ int time, volume, pitch;
+{
+ XKeyboardControl values;
+
+ AlarmWait();
+
+ if (volume != 0 && pitch != 0) {
+ values.bell_duration = time;
+ values.bell_percent = 100;
+ values.bell_pitch = pitch;
+
+ XChangeKeyboardControl(dpy, BellFlags, &values);
+ XBell(dpy, volume - 100);
+ XFlush(dpy);
+ }
+
+ AlarmSet(time);
+ return 0;
+}
+
+
+int BeepWait()
+{
+ AlarmWait();
+ return 0;
+}
+
+
+int BeepCleanup()
+{
+ if (dpy != 0) {
+ XChangeKeyboardControl(dpy, BellFlags, &initialState);
+ XFlush(dpy);
+ }
+ return 0;
+}
+
+
+int BeepResume()
+{
+ return 0;
+}
--- /dev/null
+/*
+ * A morse code practice utility. (Contains those characters that can appear
+ * on the FCC ham license exam.)
+ *
+ * Running "morse" without arguments or input gives self-doc.
+ *
+ * It doesn't keep PERFECT time, but it seems reasonably close
+ * for reasonable word speeds on my slow SUN IPC!
+ *
+ * Joe Dellinger
+ * Tue Aug 11 14:01:02 HST 1992
+ * University of Hawaii at Manoa
+ *
+ * Revised by Joe:
+ * Thu Nov 26 03:24:19 HST 1992
+ *
+ * Finally got around to getting my license, April 1994: WH6UR
+ * Moved to Tulsa, Oklahoma: July 1994
+ *
+ * Legal stuff:
+ * This code is (ridiculously) heavily modified from morse.c from the Reno UNIX
+ * distribution. I (Joe) also used slightly modified versions of a subroutine
+ * from Richard Ottolini at Unocal for Sun workstation tone generation.
+ * Scott Seligman at Stanford added support for other sorts of devices and
+ * made several other changes. John Shalamskas helped test and made comments.
+ *
+ * I don't think anybody cares if you redistribute this, modify it, etc...
+ * But don't claim you wrote it, try to sell it, or take anyone's name out
+ * of the code! If you modify it, PLEASE INDICATE WHEN, WHERE, AND HOW
+ * YOU MODIFIED IT IN THE COMMENT BELOW. Please.
+ */
+/*
+ * Joe Dellinger, UH Manoa, joe@montebello.soest.hawaii.edu, June 1992:
+ * inserted this sample modification log entry.
+ *
+ * Marc Unangst, N8VRH, mju@mudos.ann-arbor.mi.us, Dec 1992:
+ * added System V support.
+ *
+ * Joe Dellinger, Nov 1994:
+ * Fixed a bug in the termio calls for the -DUSG case.
+ * Added an option to make the "error" beep come out via the beep
+ * routines instead of by printing a control-G.
+ *
+ * Jacek M. Holeczek, March/April 2000:
+ * Fixed some source code files so that no warnings from -Wall appear.
+ * The character set made compatible with the International Morse Code.
+ * Added the -n NUM, -R NUM, -N NUM, -C 'STRING', -q options.
+ * Added beep for the AdLib/SoundBlaster FM chip and for the Open Sound
+ * System (OSS) /dev/dsp device.
+ * Note: The code uses directly ANSI sequences "\E[7m" to turn the inverse
+ * video mode on and "\E[0m" to turn all video attributes off.
+ * One should rewrite the openterminal function to provide the
+ * enter_standout_mode "smso/so" and exit_standout_mode "rmso/se"
+ * terminfo/termcap terminal string capabilities.
+ */
+
+/*
+ * The following stuff is here because this started life as a routine from
+ * the Reno UNIX distribution. (It's also a good boilerplate bit of legalese
+ * to have in there anyway.)
+ */
+/*
+ * Copyright (c) 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1988 Regents of the University of California.\n\
+ All rights reserved.\n";
+char copyleftjoe[] =
+"@(#) Copyright (c) 1992 Joe Dellinger, University of Hawaii at Manoa.\n";
+#endif /* not lint */
+
+/*
+ *============================================================================
+ * Here starts the code!
+ *============================================================================
+ */
+/*
+ * Useful for seeing what the interleaved reading and writing loops are
+ * really up to.
+ *
+ * #define DEBUG
+ *
+ * If you want to be overwhelmed with information about the probabilities
+ * of each letter being chosen.
+ *
+ * #define DEBUGG
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <ctype.h>
+#include <signal.h>
+#include "beep.h"
+/* Define USG for termio a la System V. */
+#ifdef __hpux
+#define USG
+#endif
+/*
+ * Define the return type of a signal handler. Defaults to void, which is
+ * what most modern systems are using these days.
+ */
+#ifndef SIGRET
+#define SIGRET void
+#endif
+
+#define FREQUENCY 800.
+#define FREQUENCY2 602.
+#define VOLUME .5
+#define WORDS_PER_MINUTE 20.
+#define MAX_BEHINDNESS 0
+
+static int whichfrequ = 0;
+static float frequency1 = FREQUENCY;
+static float frequency2 = FREQUENCY2;
+static float frequency;
+static float volume = VOLUME;
+static float dot_time;
+static float dash_time;
+static float intra_char_time;
+static float inter_char_time;
+static float inter_word_time;
+static float catchup_time;
+static int showletters = 0;
+static int showmorse = 0;
+static int wordsbefore = 0;
+static int wordsafter = 0;
+static int fancyending = 1;
+static int noticebad = 0;
+static int testing = 0;
+static int showtesting = 0;
+static int keepquiet = 0;
+static int dynamicspeed = 0;
+static int charbychar = 0;
+static int tryagaincount = 1;
+static float words_per_minute;
+static float fwords_per_minute;
+static int randomletters = 0;
+#define LETMESEE 2
+static int typeaway = 0;
+
+static int totalhitcount = 0;
+static int totalmisscount = 0;
+static int helpmeflag = 0;
+
+#define MAXWORDLEN 20
+#define TESTBUFSZ ((MAXWORDLEN+1)*10)
+static int wordlen = MAXWORDLEN;
+static int wordcount = -1;
+static time_t starttime;
+static int timeout = -1;
+static int testpointer = -1;
+static int testlength = 0;
+static int behindness = 0;
+static int max_behindness = MAX_BEHINDNESS;
+static char teststring[TESTBUFSZ];
+static int yourpointer = -1;
+static int yourlength = 0;
+static char yourstring[TESTBUFSZ];
+static int linepos = 0;
+
+/*
+ * How many times can a given character not be asked before
+ * kicking up the probability of asking that one by one randomfactor unit.
+ */
+#define RIPECOUNT 64
+
+#define TWOFIFTYSIX 256
+static char *(code[TWOFIFTYSIX]);
+static int errorlog[TWOFIFTYSIX];
+static int randomfactor[TWOFIFTYSIX];
+static int randomripe[TWOFIFTYSIX];
+extern int testterminal ();
+extern int randomletter ();
+
+/*
+ * Pointers to termcap/terminfo "smso/so" (enter_standout_mode) and "rmso/se"
+ * (exit_standout_mode) terminal string capabilities (initialized respectively
+ * with ANSI sequences "\E[7m" to turn the inverse video mode on and "\E[0m"
+ * to turn all video attributes off).
+ */
+char *enter_standout_mode = "\033[7m";
+char *exit_standout_mode = "\033[0m";
+
+/*
+ * Value of (Wrong - Right), which, if exceeded, will cause the program
+ * to start prompting you. Above MAX_ERROR_THRESHOLD it will never prompt.
+ * Don't let the user bank too much credit for past correct answers;
+ * limit it by min(ERROR_FLOOR, error_threshold).
+ */
+#define MAX_ERROR_THRESHOLD 1000
+#define ERROR_FLOOR -3
+static int error_threshold = MAX_ERROR_THRESHOLD;
+static int error_floor = ERROR_FLOOR;
+
+/*
+ * How many characters behind before it decides you're having
+ * trouble keeping up.
+ */
+#define BEHIND 1
+#define WAYBEHIND 3
+#define TOOFARBEHIND 6
+/*
+ * If SLOWPOKE or more wpm ticks go by, then it decides you are having lots
+ * of trouble remembering this character, and need to be asked it more
+ * often.
+ */
+#define SLOWPOKE 10
+/* You aren't slow -- you left and came back! */
+#define SLOWPOKEMAX (50 * SLOWPOKE)
+/*
+ * If FASTPOKE or less wpm ticks go by, then it decides you are good at this
+ * character, and need to be asked it less often.
+ */
+#define FASTPOKE 4
+
+/*
+ * These control how quickly the dynamicspeed option acts when you are
+ * fast or slow. Easier to slow down than speed up!
+ */
+#define ERRORSLOWER 1.04
+#define ALOTSLOWER 1.15
+#define ALITTLESLOWER 1.02
+#define ALITTLEFASTER 1.02
+
+/*
+ * How many inter_char_time's to give you to answer after the end of
+ * a word before considering that you are not keeping up.
+ * Maximum of 2.3, minimum of 0.
+ * The bigger the value, the easier it is to kick in the "automatic
+ * speedup" when using the "-d" option. The maximum means you have (almost)
+ * right up to the beginning of the next word to answer and still have it
+ * count as keeping up.
+ */
+#define SPORTING_RATIO 1.5
+
+/*
+ * The bigger, the more evenly things start out.
+ * (Must be at least 2)
+ */
+#define RANDOMBASELEVEL 7
+/*
+ * RANDOMINCWORSE scales how badly you are punished for being wrong
+ * or taking too long. RANDOMINCBETTER scales how you are rewarded for
+ * answering quickly or being right.
+ */
+#define RANDOMINCWORSE 6
+#define RANDOMINCBETTER 7
+#define RANDOMMAX (30 * RANDOMBASELEVEL)
+/*
+ * The average length of a random word (chosen using exponential distribution).
+ * After implementing this I'm not so sure an exponential distribution
+ * actually models the distribution of real word lengths in English very well.
+ * It's not too bad, though, and the words themselves are all garbage anyway,
+ * so what the heck.
+ */
+#define RANDWORDLEN 3.5
+
+/* Put in a newline instead of a space when past this column */
+#define LINELENGTH 78
+
+/* An EOF without the EOF (%) sound */
+#define SILENTEOF -2
+/* Toggle tone frequency on control-G within input file */
+#define FREQU_TOGGLE ((int)'\007')
+
+/*
+ * If you want the morse code to come out synchronized with the printing
+ * of dots and dashes with the -m option, then define this. The problem
+ * is that then the morse code sounds ratty on slower CPU's.
+ * John Shalamskas (KJ9U) suggested turning the precise morse-code printing
+ * synching off because he didn't like the resulting code quality!
+ */
+#undef FLUSHCODE
+
+/*
+ * Choose your favorite random number generator!
+ */
+#ifndef USERANDOM
+#ifndef USELRAND
+#ifndef USERAND
+#define USERANDOM /* USELRAND or USERAND are the other choices */
+#endif
+#endif
+#endif
+
+#ifdef USERANDOM
+#define RANDOM() random()
+#define SEEDRANDOM(s) srandom((int)s)
+#endif
+#ifdef USELRAND
+#define RANDOM() lrand48()
+#define SEEDRANDOM(s) srand48((long)(s))
+long lrand48 ();
+#endif
+#ifdef USERAND
+/*
+ * UGH, are you really sure you want to use this one?
+ * This one really stinks!
+ */
+#define RANDOM() rand()
+#define SEEDRANDOM(s) srand((int)(s))
+int rand ();
+#endif
+
+void new_words_per_minute (void);
+void dowords (int c);
+void morse (int c);
+void show (char *s);
+void testaddchar (char c);
+void youraddchar (char c);
+void pollyou (void);
+void tone (float hertz, float duration, float amplitude);
+void toneflush (void);
+void openterminal (void);
+int readterminal (char **string);
+void closeterminal (void);
+void report (void);
+
+SIGRET die (), suspend ();
+void cleanup ();
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+extern char *optarg;
+extern int optind;
+int ch;
+char *p;
+int ii, jj;
+int firsttime, notdoneyet;
+int yourchar;
+float randexp, randnum;
+extern time_t time ();
+
+ if (argc == 1 && isatty (fileno (stdin)))
+ {
+/*
+ * SELF DOC
+ */
+ printf ("Usage:\n");
+ printf ("morse [options] < text_file\n");
+ printf ("morse [options] words words words\n");
+ printf ("morse [options] -r\n");
+ printf ("morse [options] -i\n");
+ printf ("Options:\n");
+ printf ("-i Play what you type.\n");
+ printf ("-I Like -i but don't turn off keyboard echoing.\n");
+ printf ("-r Generate random text. Starts out slanted towards easy\n");
+ printf (" letters, then slants towards ones you get wrong.\n");
+ printf ("-n NUM (default %d means random length)\n", MAXWORDLEN);
+ printf (" Make words (groups) NUM characters long.\n");
+ printf (" Valid values are between %d and %d.\n", 1, MAXWORDLEN);
+ printf ("-R NUM (default 0 means unlimited)\n");
+ printf (" Set the total time (in minutes) to generate text.\n");
+ printf ("-N NUM (default 0 means unlimited)\n");
+ printf (" Set the total number of words (groups) to generate.\n");
+ printf ("-C \'STRING\' (default all available characters)\n");
+ printf (" Select characters to send from this STRING only.\n");
+ printf ("-w words_per_minute (default %g)\n-f frequency_in_hertz (default %g)\n-v volume (zero to one, rather nonlinear, default %g)\n",
+ WORDS_PER_MINUTE, FREQUENCY, VOLUME);
+ printf ("-g alternate_frequency (default %g)\n (toggles via control-G in input FILE at a word break)\n", FREQUENCY2);
+ printf ("-F Farnsworth_character_words_per_minute\n");
+ printf ("-e leave off the <SK> sound at the end\n");
+ printf ("-c complain about illegal characters instead of just ignoring them\n");
+ printf ("-b print each word before doing it\n");
+ printf ("-a print each word after doing it\n");
+ printf ("-l print each letter just before doing it\n");
+ printf ("-m print morse dots and dashes as they sound\n");
+#ifdef FLUSHCODE
+ printf (" (this printing-intensive option slows the wpm down!)\n");
+#endif
+ printf ("-t Type along with the morse, but don't see what\n");
+ printf (" you're typing (unless you make a mistake).\n");
+ printf (" You are allowed to get ahead as much as you want.\n");
+ printf (" If you get too far behind it will stop and resync with you.\n");
+ printf (" You can force it to resync at the next word end by hitting control-H.\n");
+ printf (" Hit ESC to see how you are doing, control-D to end.\n");
+ printf (" (The rightmost space in the printout marks where the average is.\n");
+ printf (" Farther left spaces separate off blocks of letters that are\n");
+ printf (" about twice as probable as the average to occur, three times, etc.)\n");
+ printf ("-T Like -t but see your characters (after they are played).\n");
+ printf ("-s Stop after each character and make sure you get it right. (implies -t)\n");
+ printf ("-q Quietly resyncs with your input (after you make a mistake).\n");
+ printf ("-p NUM (default 0)\n");
+ printf (" Make you get it right NUM times, for penance. (implies -s)\n");
+ printf (" (Yes, NUM = 0 means you can sin all you want.)\n");
+ printf ("-E NUM (default %d)\n", MAX_ERROR_THRESHOLD);
+ printf (" If your count of wrong answers minus right answers for a given character\n");
+ printf (" exceeds this, the program will start prompting you.\n");
+ printf (" If %d or above, it will never prompt. (implies -t)\n", MAX_ERROR_THRESHOLD);
+ printf ("-M NUM (default %d)\n", MAX_BEHINDNESS);
+ printf (" If you get more than this number of characters behind, pause until you\n");
+ printf (" do your next letter. (1 behind is normal, 0 behind means never pause.)\n");
+ printf (" (implies -t)\n");
+ printf ("-d Dynamically speed up or slow down depending on how you are doing.\n");
+ printf (" (if also -s, then -d _only speeds up_!)\n");
+ printf ("\n");
+ printf ("\n");
+ printf ("\n");
+ printf ("For the raw beginner trying to learn morse code I recommend\n");
+ printf ("the following sequence:\n");
+ printf ("\n");
+ printf ("Start learning the alphabet:\n");
+ printf (" morse -r -s -T -d -w 5 -F 15 -p 5 -E -10\n");
+ printf ("Then drill drill drill:\n");
+ printf (" morse -r -s -T -d -w 5 -F 15 -p 5 -E 0\n");
+ printf ("Real-time drill, with hints if you really need it:\n");
+ printf (" morse -r -T -d -w 5 -F 15 -M 2 -E 4\n");
+ printf ("Simulated test:\n");
+ printf (" QSO | morse -e -T -d -w 5 -F 15\n");
+ printf ("The dreaded random-letter test:\n");
+ printf (" morse -r -T -d -w 5 -F 15\n");
+ printf ("Finally try for greater and greater speed:\n");
+ printf (" morse -r -T -d -w 13 -F 24\n");
+ printf ("\n");
+/* printf ("Written by (mostly) joe@montebello.soest.hawaii.edu\n"); */
+ printf ("Please send updates/comments to joe@sep.stanford.edu\n");
+ printf ("Get the latest revision from sepftp.stanford.edu before hacking!\n");
+ exit (0);
+ }
+
+ for (ii = 0; ii < TWOFIFTYSIX; ii++)
+ code[ii] = NULL;
+
+/* Load in the morse code code */
+ code[(int) 'a'] = ".-";
+ code[(int) 'b'] = "-...";
+ code[(int) 'c'] = "-.-.";
+ code[(int) 'd'] = "-..";
+ code[(int) 'e'] = ".";
+ code[(int) 'f'] = "..-.";
+ code[(int) 'g'] = "--.";
+ code[(int) 'h'] = "....";
+ code[(int) 'i'] = "..";
+ code[(int) 'j'] = ".---";
+ code[(int) 'k'] = "-.-";
+ code[(int) 'l'] = ".-..";
+ code[(int) 'm'] = "--";
+ code[(int) 'n'] = "-.";
+ code[(int) 'o'] = "---";
+ code[(int) 'p'] = ".--.";
+ code[(int) 'q'] = "--.-";
+ code[(int) 'r'] = ".-.";
+ code[(int) 's'] = "...";
+ code[(int) 't'] = "-";
+ code[(int) 'u'] = "..-";
+ code[(int) 'v'] = "...-";
+ code[(int) 'w'] = ".--";
+ code[(int) 'x'] = "-..-";
+ code[(int) 'y'] = "-.--";
+ code[(int) 'z'] = "--..";
+
+ code[(int) '1'] = ".----";
+ code[(int) '2'] = "..---";
+ code[(int) '3'] = "...--";
+ code[(int) '4'] = "....-";
+ code[(int) '5'] = ".....";
+ code[(int) '6'] = "-....";
+ code[(int) '7'] = "--...";
+ code[(int) '8'] = "---..";
+ code[(int) '9'] = "----.";
+ code[(int) '0'] = "-----";
+
+ /* Punctuation marks */
+ code[(int) '.'] = ".-.-.-";
+ code[(int) ','] = "--..--";
+ code[(int) '?'] = "..--..";
+ code[(int) '/'] = "-..-.";
+ code[(int) '-'] = "-....-";
+
+#ifdef ALLPUNCTUATION
+ /* Not so commonly used punctuation marks */
+ code[(int) ')'] = "-.--.-";
+ code[(int) '\"'] = ".-..-.";
+ code[(int) '_'] = "..--.-";
+ code[(int) '\''] = ".----.";
+ code[(int) ':'] = "---...";
+ code[(int) ';'] = "-.-.-.";
+ code[(int) '$'] = "...-..-";
+ code[(int) '!'] = "-.-.--";
+#endif
+
+ /* Commonly used procedure signs ("prosigns") */
+ code[(int) '+'] = ".-.-."; /* <AR> end of message */
+ code[(int) '*'] = ".-..."; /* <AS> wait, stand-by */
+ code[(int) '='] = "-...-"; /* <BT> (double dash) pause, break for text */
+ code[(int) '('] = "-.--."; /* <KN> over-specified station only */
+ code[(int) '%'] = "...-.-"; /* <SK> end of contact, known also as <VA> */
+
+#ifdef ALLPROSIGNS
+ /* Not so commonly used procedure signs ("prosigns") */
+ code[(int) '^'] = ".-.-"; /* <AA> new line, the same as :a, ae */
+ code[(int) '#'] = "-...-.-";/* <BK> invite receiving station to transmit */
+ code[(int) '&'] = "-.-.-"; /* <KA> attention */
+ code[(int) '@'] = "...-."; /* <SN> understood */
+#endif
+
+#ifdef ALLINTERNATIONAL
+ /* Not so commonly used international extensions (ISO 8859-1) */
+ code[(int) ((unsigned char)'\344')] = ".-.-"; /* :a (also for ae), the same as <AA> */
+ if (code[(int) '^'] != NULL) code[(int) '^'] = NULL;
+ code[(int) ((unsigned char)'\340')] = ".--.-"; /* `a, oa (danish a with ring over it) */
+ code[(int) ((unsigned char)'\347')] = "----"; /* ch (bar-ch) */
+ code[(int) ((unsigned char)'\360')] = "..--."; /* -d (eth, overstrike d with -) */
+ code[(int) ((unsigned char)'\350')] = "..-.."; /* `e */
+ code[(int) ((unsigned char)'\361')] = "--.--"; /* ~n */
+ code[(int) ((unsigned char)'\366')] = "---."; /* :o (also for oe) */
+ code[(int) ((unsigned char)'\374')] = "..--"; /* :u (also for ue) */
+ code[(int) ((unsigned char)'\376')] = ".--.."; /* ]p (thorn, overstrike ] with p) */
+ code[(int) ((unsigned char)'\247')] = ".-.-.."; /* paragraph */
+#endif
+
+ for (ii = 0; ii < TWOFIFTYSIX; ii++)
+ {
+ /* Everything starts equally fresh */
+ randomripe[ii] = 0;
+ /* Start out assuming you know how everything sounds */
+ errorlog[ii] = 0;
+
+ if (code[ii] == NULL)
+ {
+ /* Ensures these will never be chosen */
+ randomfactor[ii] = 0;
+ }
+ else
+ {
+ /* Start out favoring easy ones */
+ randomfactor[ii] = RANDOMBASELEVEL - strlen (code[ii]);
+ if (randomfactor[ii] < 1)
+ randomfactor[ii] = 1;
+ }
+ }
+
+ words_per_minute = WORDS_PER_MINUTE;
+ fwords_per_minute = -1.;
+
+ while ((ch = getopt (argc, argv, "F:w:lbamf:g:v:tTdesp:riIcM:E:n:R:N:C:q")) != EOF)
+ switch ((char) ch)
+ {
+ case 'i':
+ typeaway = 1;
+ break;
+ case 'I':
+ typeaway = LETMESEE;
+ break;
+ case 'r':
+ randomletters = 1;
+ break;
+ case 'n':
+ sscanf (optarg, "%d", &wordlen);
+ if (wordlen < 1) wordlen = 1;
+ if (wordlen > MAXWORDLEN) wordlen = MAXWORDLEN;
+ break;
+ case 'R':
+ sscanf (optarg, "%d", &timeout);
+ timeout *= 60;
+ if (timeout < 1) timeout = -1;
+ break;
+ case 'N':
+ sscanf (optarg, "%d", &wordcount);
+ if (wordcount < 1) wordcount = -1;
+ break;
+ case 'C':
+ for (ii = 0; ii < strlen(optarg); ii++)
+ {
+ *(optarg+ii) = tolower(*(optarg+ii));
+ }
+ for (ii = 0; ii < TWOFIFTYSIX; ii++)
+ {
+ if (code[ii] != NULL)
+ {
+ if (strchr(optarg, ii) != NULL)
+ {
+ randomfactor[ii] = RANDOMBASELEVEL - 1;
+ } else {
+ code[ii] = NULL;
+ randomfactor[ii] = 0;
+ }
+ }
+ }
+ break;
+ case 'c':
+ noticebad = 1;
+ break;
+ case 'e':
+ fancyending = 0;
+ break;
+ case 'T':
+ testing = 1;
+ showtesting = 1;
+ break;
+ case 't':
+ testing = 1;
+ break;
+ case 's':
+ charbychar = 1;
+ testing = 1;
+ break;
+ case 'q':
+ keepquiet = 1;
+ break;
+ case 'p':
+ charbychar = 1;
+ testing = 1;
+ sscanf (optarg, "%d", &tryagaincount);
+ break;
+ case 'M':
+ testing = 1;
+ sscanf (optarg, "%d", &max_behindness);
+ if (max_behindness < 1)
+ max_behindness = 0;
+ break;
+ case 'E':
+ testing = 1;
+ sscanf (optarg, "%d", &error_threshold);
+ if (error_threshold < error_floor)
+ error_floor = error_threshold;
+ break;
+ case 'd':
+ dynamicspeed = 1;
+ break;
+ case 'w':
+ sscanf (optarg, "%f", &words_per_minute);
+ break;
+ case 'F':
+ sscanf (optarg, "%f", &fwords_per_minute);
+ break;
+ case 'l':
+ showletters = 1;
+ break;
+ case 'b':
+ wordsbefore = 1;
+ break;
+ case 'a':
+ wordsafter = 1;
+ break;
+ case 'm':
+ showmorse = 1;
+ break;
+ case 'f':
+ sscanf (optarg, "%f", &frequency1);
+ break;
+ case 'g':
+ sscanf (optarg, "%f", &frequency2);
+ break;
+ case 'v':
+ sscanf (optarg, "%f", &volume);
+ if (volume < 0.)
+ volume = 0.;
+ if (volume > 1.)
+ volume = 1.;
+ break;
+ default:
+ fprintf (stderr, "Type \"morse\" without arguments to get self-doc!\n");
+ exit (1);
+ break;
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (fwords_per_minute <= 0.)
+ fwords_per_minute = words_per_minute;
+ new_words_per_minute ();
+
+ frequency = frequency1;
+
+ if (BeepInit () != 0)
+ {
+ fprintf (stderr, "Can't access speaker.\n");
+ exit (1);
+ }
+
+ time(&starttime);
+
+ signal (SIGINT, die);
+ signal (SIGTERM, die);
+ signal (SIGQUIT, die);
+ signal (SIGTSTP, suspend);
+
+ if (testing || typeaway)
+ {
+ openterminal ();
+ }
+
+/*
+ * Do .25 seconds of silence initially to give the workstation time to
+ * get settled after the stress of starting this program and opening
+ * up everything.
+ */
+ tone (frequency, .25, 0.);
+ toneflush ();
+
+ if (typeaway)
+ {
+ testing = 0;
+ showtesting = 0;
+ charbychar = 0;
+ wordsbefore = 0;
+ wordsafter = 0;
+ randomletters = 0;
+
+ notdoneyet = 1;
+
+ while (notdoneyet)
+ {
+ pollyou ();
+
+ for (jj = 0; jj < yourlength; jj++)
+ {
+ yourchar = yourstring[(yourpointer - yourlength + 1 + jj + TESTBUFSZ) % TESTBUFSZ];
+
+ /* Control-D: finished */
+ if (yourchar == (int) '\004')
+ {
+ toneflush ();
+ notdoneyet = 0;
+ break;
+ }
+
+ if (isspace (yourchar))
+ {
+ if (showletters)
+ {
+ toneflush ();
+ printf ("%c", yourchar);
+ fflush (stdout);
+ }
+
+ tone (frequency, inter_word_time, 0.);
+
+ continue;
+ }
+
+ morse (yourchar);
+ }
+ yourlength -= jj;
+
+ if (timeout > 0)
+ if (difftime(time(NULL),starttime) > (double)timeout)
+ break;
+ }
+ }
+ else if (randomletters)
+ {
+ SEEDRANDOM (time (NULL));
+ randexp = 1. / (1. - 1. / (float) (RANDWORDLEN));
+ while (1)
+ {
+ if ((wordcount == 0) || timeout == 0) break;
+
+ dowords (randomletter ());
+
+ if (wordlen == MAXWORDLEN)
+ {
+ /* Knock a few bits off the top so we're sure it won't overflow */
+ /* Shift a few bits because the lower bits stink */
+ /* Add in the time so it doesn't repeat from run to run */
+ randnum = (float) (
+ (((RANDOM () >> 9) + (long) (time (NULL))) >> 4)
+ & 0x00FFFFFF);
+ randnum = randnum - randexp * (int) (randnum / randexp);
+ if ((randnum >= 1.) && (linepos != 0)) dowords ((int) ' ');
+ }
+ }
+ }
+ else
+ {
+ if (*argv)
+ {
+ firsttime = 1;
+
+ do
+ {
+ if (!firsttime)
+ {
+ dowords ((int) ' ');
+ }
+ else
+ firsttime = 0;
+
+ if ((wordcount == 0) || timeout == 0) break;
+
+ for (p = *argv; *p; ++p)
+ {
+ dowords ((int) *p);
+ if ((wordcount == 0) || timeout == 0) break;
+ }
+ if ((wordcount == 0) || timeout == 0) break;
+
+ } while (*++argv);
+ }
+ else
+ {
+ while ((ch = getchar ()) != EOF)
+ {
+ dowords (ch);
+ if ((wordcount == 0) || timeout == 0) break;
+ }
+ }
+ }
+
+ if (fancyending)
+ dowords (EOF);
+ else
+ dowords (SILENTEOF);
+
+ fflush (stdout);
+
+ if (testing)
+ {
+ /*
+ * WE'RE completely done, and YOU aren't! Force catch up. (Note if
+ * charbychar = YES we won't get here, since we're always caught up
+ * after each character as it comes out.)
+ */
+ while (testlength > 0)
+ {
+ tone (frequency, catchup_time, 0.);
+ toneflush ();
+ testterminal ();
+ }
+ }
+
+ /* Just to be sure! */
+ toneflush ();
+
+ if (showmorse || wordsbefore || wordsafter || showletters || showtesting)
+ printf ("\n");
+ fflush (stdout);
+
+ if (testing)
+ report ();
+
+/* If you make any mistakes exit with a return code! */
+ cleanup ();
+ return (totalmisscount > 0);
+}
+
+void
+new_words_per_minute ()
+{
+float wtick, ftick, tick;
+
+ tick = 60. / (words_per_minute * 50);
+
+ /*
+ * In the limit as wpm goes past fwpm, Farnsworth becomes kosher PARIS
+ */
+ if (fwords_per_minute <= words_per_minute)
+ ftick = 60. / (words_per_minute * 50);
+ else
+ ftick = 60. / (fwords_per_minute * 50);
+
+ wtick = (50. * tick - 31. * ftick) / 19.;
+
+ /*
+ * This time is used when the computer is waiting on you to hit a key; it
+ * is useful to scale the granularity with the real overrall words per
+ * minute. This also serves as a measuring rod to see if you are
+ * responding "fast enough". If you are too slow, then obviously you are
+ * having trouble with that character, and should be given it more OFTEN.
+ * Heh heh heh...
+ */
+ catchup_time = tick;
+
+ /*
+ * Things between characters and words go at the "remainder" speed,
+ * whatever space you need to make the sped-up Farnsworth characters come
+ * out with the correct overall words per minute.
+ */
+ inter_char_time = wtick * 3.;
+ inter_word_time = wtick * 7.;
+
+ /* Things within the character go at the Farnsworth speed */
+ intra_char_time = ftick;
+ dot_time = ftick;
+ dash_time = ftick * 3.;
+}
+
+static int tryingagain = 0, slowpoke = 0;
+
+void
+dowords (c)
+ int c;
+{
+static int wordc = 0;
+static char word[MAXWORDLEN+1];
+char *wordp;
+int ii;
+int againcount = 0;
+int are_we_repeating;
+
+/*
+ * Increment the line position counter.
+ * If a line gets too long, just cut it off by inserting a new line.
+ */
+ if (c != EOF && c != SILENTEOF && c != FREQU_TOGGLE) linepos++;
+ if (isspace (c) && ((linepos + wordlen) >= LINELENGTH)) c = '\n';
+ if (c == '\n') linepos = 0;
+
+ if (isspace (c) || c == EOF || c == SILENTEOF || c == FREQU_TOGGLE)
+ {
+ if (wordc > 0)
+ {
+ if (wordcount > 0) wordcount--;
+ if (timeout > 0)
+ if (difftime(time(NULL),starttime) > (double)timeout)
+ timeout = 0;
+
+ word[wordc] = '\0';
+
+/*
+ * We have just read in a new complete word from the input, (hopefully)
+ * during the time of an inter-word space minus an inter-char space.
+ * Now let's go back and see what happened with the PREVIOUS word,
+ * the one that we had just finished playing. Did the user keep
+ * up with us?
+ */
+#ifdef DEBUG
+ fprintf (stderr, " [%d] ", behindness);
+#endif
+ if (testing && dynamicspeed && !charbychar)
+ {
+ /*
+ * (If charbychar then behindness is ALWAYS 0 at this
+ * point...)
+ */
+ if (behindness == 0)
+ {
+ /* You're a speed demon! Speed up a bit, then! */
+ words_per_minute *= ALITTLEFASTER;
+ new_words_per_minute ();
+ }
+ else if (behindness > WAYBEHIND)
+ {
+ /* You're way behind! Slow way down. */
+ words_per_minute /= ALOTSLOWER;
+ new_words_per_minute ();
+ }
+ else if (behindness > BEHIND)
+ {
+ /* You're behind! Slow down a bit. */
+ words_per_minute /= ALITTLESLOWER;
+ new_words_per_minute ();
+ }
+ }
+
+
+/*
+ * If the user was WAY too far behind stop and catch up with
+ * the "new" word as the first one.
+ */
+ if (testing && (behindness > TOOFARBEHIND || helpmeflag))
+ {
+ if (helpmeflag)
+ printf ("\nOK, let's restart.\n");
+ else
+ printf ("\nYou are too far behind! Let's restart.\n");
+ fflush (stdout);
+
+ toneflush ();
+
+ /* Flush the keyboard buffer */
+ pollyou ();
+
+ /* Forget the past */
+ helpmeflag = 0;
+ behindness = 0;
+ testlength = 0;
+ yourlength = 0;
+
+ /* Give the user a little rest. */
+ sleep (2);
+ printf ("\nWPM now %d\n", (int) (words_per_minute + .5));
+ fflush (stdout);
+ sleep (2);
+ printf ("\nREADY?\n");
+ fflush (stdout);
+ sleep (1);
+ printf ("\nSET\n");
+ fflush (stdout);
+ sleep (1);
+ printf ("\nGO!\n");
+ fflush (stdout);
+ linepos = 0;
+ }
+
+/*
+ * Start treating the new word.
+ */
+ if (wordsbefore)
+ {
+ /* Try to keep your out-of-sync text from getting swirled in */
+ if (showtesting)
+ {
+ printf ("\n");
+ linepos = 0;
+ }
+
+ printf ("%s", word);
+
+ if (showmorse || showletters || wordsafter || showtesting)
+ {
+ printf (" ");
+ for (ii = 0; ii < 16 - (wordc + 2); ii++)
+ {
+ printf (" ");
+ }
+ }
+
+ fflush (stdout);
+ }
+
+ if (testing && charbychar)
+ {
+ againcount = 0;
+ }
+
+ for (wordp = word; *wordp != '\0'; wordp++)
+ {
+ tryingagain = 0;
+
+ tryagain:
+ if (testing && !tryingagain && !showletters &&
+ error_threshold < MAX_ERROR_THRESHOLD &&
+ errorlog[(int) *wordp] > error_threshold)
+ {
+ toneflush ();
+ /* Give them a quick hint */
+ printf ("[%c]", *wordp);
+ fflush (stdout);
+
+ morse (*wordp);
+
+ toneflush ();
+ if (!showmorse)
+ {
+ /* Erase the hint */
+ printf ("\b\b\b \b\b\b");
+ fflush (stdout);
+ }
+ }
+ else
+ {
+ morse (*wordp);
+ }
+
+ if (testing)
+ {
+ if (charbychar)
+ {
+ toneflush ();
+ /* Force catchup */
+ slowpoke = 0;
+ while (behindness > 0)
+ {
+ if (testterminal () && tryagaincount > 0)
+ {
+ /*
+ * OOPS! They got it WRONG! MAKE THEM TRY
+ * AGAIN!
+ */
+ printf ("Try again.\n");
+ linepos = 0;
+ /*
+ * Yeah I know gotos are inelegant but I
+ * don't feel like figuring out the "elegant"
+ * way to do this right now.
+ */
+ againcount = tryagaincount - 1;
+ tryingagain = 1;
+ goto tryagain;
+ }
+ else
+ {
+ /*
+ * They got it right, or they didn't answer
+ * yet.
+ */
+ if (behindness > 0)
+ {
+ /*
+ * They are STILL thinking, the
+ * slowpokes. Wait a bit before trying
+ * again.
+ */
+ tone (frequency, catchup_time, 0.);
+ /*
+ * Keep track of how long they're taking
+ * to answer!
+ */
+ if (slowpoke < SLOWPOKEMAX)
+ slowpoke++;
+ toneflush ();
+ }
+ else if (dynamicspeed && !slowpoke && !tryingagain)
+ {
+ /*
+ * They got it right without errors the
+ * first time and we didn't have to wait
+ * for them! A speed demon! Speed up a
+ * bit, then!
+ */
+ words_per_minute *= ALITTLEFASTER;
+ new_words_per_minute ();
+ }
+ }
+ }
+
+ /* Insufficient penance? */
+ if (againcount > 0)
+ {
+ againcount--;
+ goto tryagain;
+ }
+ }
+ else
+ {
+ testterminal ();
+ /*
+ * Stop if we get more than max_behindness ahead.
+ * max_behindness == 0 means don't worry about them,
+ * they can be as far behind as they want and we
+ * won't stop!
+ */
+ if (max_behindness > 0)
+ {
+ are_we_repeating = 0;
+ while (behindness >= max_behindness)
+ {
+#ifdef DEBUG
+ fprintf (stderr, " (%d) ", behindness);
+#endif
+ if (are_we_repeating)
+ {
+ /*
+ * Pause for a bit so we don't loop too
+ * fast
+ */
+ tone (frequency, catchup_time, 0.);
+ }
+ else
+ {
+ are_we_repeating = 1;
+ }
+ /* Finish playing whatever we're playing */
+ toneflush ();
+ /* And give them another chance */
+ testterminal ();
+ }
+ }
+ }
+ }
+ }
+
+ toneflush ();
+ if (testing)
+ testterminal ();
+
+ if (wordsafter)
+ {
+ printf (" (%s)", word);
+ }
+
+ if (wordsbefore || wordsafter || showmorse)
+ {
+ if (!showmorse && !testing && linepos)
+ {
+ if (wordsafter)
+ linepos += 3;
+ else
+ printf (" ");
+ } else {
+ printf ("\n");
+ linepos = 0;
+ }
+ }
+ else if (showletters || showtesting)
+ {
+ if (c != EOF && c != SILENTEOF && c != FREQU_TOGGLE)
+ {
+ if (showletters)
+ printf ("%c", c);
+
+ if (showtesting)
+ testaddchar (c);
+ }
+ }
+
+/*
+ * WHEW! FINISHED QUEUEING THE WORD FOR PLAYING!
+ * Now finish up all the other sundry details...
+ */
+
+ /* Flush the output printing queue... */
+ fflush (stdout);
+ /*
+ * Pause for a bit; this gives the user a sporting chance at
+ * catching up with us.
+ */
+ tone (frequency, SPORTING_RATIO * inter_char_time, 0.);
+ toneflush ();
+ /* Start sounding an inter-word space */
+ tone (frequency, inter_word_time - SPORTING_RATIO * inter_char_time, 0.);
+
+ /* While that silence is playing check if the user has caught up. */
+ if (testing)
+ testterminal ();
+
+ /* We finished this word; reset the word character count */
+ wordc = 0;
+ }
+ else if (!(wordsbefore || wordsafter || showmorse)
+ &&
+ (showletters || showtesting))
+ {
+ if (c != EOF && c != SILENTEOF && c != FREQU_TOGGLE)
+ {
+ if (showletters)
+ printf ("%c", c);
+
+ if (showtesting)
+ testaddchar (c);
+ }
+ }
+
+ if (c == EOF)
+ {
+ morse (EOF);
+ toneflush ();
+ }
+ else if (c == SILENTEOF)
+ {
+ toneflush ();
+ }
+ else if (c == FREQU_TOGGLE)
+ {
+ /* Switch to the other frequency */
+ /* (Won't work from keyboard, only from a file.) */
+ whichfrequ = 1 - whichfrequ;
+ switch (whichfrequ)
+ {
+ case 1:
+ frequency = frequency2;
+ break;
+ case 0:
+ default:
+ frequency = frequency1;
+ break;
+ }
+ }
+ }
+ else
+ {
+ word[wordc++] = c;
+ }
+
+/*
+ * If a word gets too long, just cut it off by inserting a space.
+ * Just call ourselves with the character we wish we'd gotten...
+ */
+ if (wordc == wordlen && !(isspace (c) || c == EOF || c == SILENTEOF || c == FREQU_TOGGLE))
+ dowords ((int) ' ');
+}
+
+/*
+ * Don't try to test the person DURING the call into morse!
+ */
+void
+morse (c)
+ int c;
+{
+ if ((isalpha (c) && (code[tolower(c)] == NULL)) || ((code[(int) '%'] == NULL) && ((c == EOF) || (c == '\004'))))
+ c = ' ';
+
+ if (showletters)
+ {
+ if ((c == EOF) || (c == '\004'))
+ {
+ if (showmorse)
+ {
+ printf ("<SK>");
+ } else {
+ printf ("%%");
+ }
+ }
+ else if (c == '.' && showmorse)
+ printf ("<DOT>");
+ else if (c == '-' && showmorse)
+ printf ("<DASH>");
+ else if (c == '+' && showmorse)
+ printf ("<AR>");
+ else if (c == '*' && showmorse)
+ printf ("<AS>");
+ else if (c == '=' && showmorse)
+ printf ("<BT>");
+ else if (c == '(' && showmorse)
+ printf ("<KN>");
+ else if (c == '%' && showmorse)
+ printf ("<SK>");
+#ifdef ALLPROSIGNS
+ else if (c == '^' && (code[(int) '^'] != NULL) && showmorse)
+ printf ("<AA>");
+ else if (c == '#' && showmorse)
+ printf ("<BK>");
+ else if (c == '&' && showmorse)
+ printf ("<KA>");
+ else if (c == '@' && showmorse)
+ printf ("<SN>");
+#endif
+ else
+ printf ("%c", c);
+
+ fflush (stdout);
+ }
+
+ if (isalpha (c))
+ {
+ if (testing)
+ testaddchar (c - (isupper (c) ? 'A' : 'a') + 'a');
+ show (code[c - (isupper (c) ? 'A' : 'a') + 'a']);
+ }
+ else if ((c == EOF) || (c == '\004'))
+ {
+ show (code[(int) '%']);
+ }
+ else if (code[c] != NULL)
+ {
+ if (testing)
+ testaddchar (c);
+ show (code[c]);
+ }
+ else
+ {
+ /* Oops! This letter is junk! */
+
+ if (noticebad)
+ {
+ if (showletters)
+ {
+ fflush (stdout);
+ }
+
+ /* Simulate a stumble */
+ tone (frequency, 2. * inter_word_time, 0.);
+ toneflush ();
+ }
+
+ if (showletters)
+ {
+ /* Wipe out what we just printed */
+ fflush (stdout);
+ printf ("\b");
+ printf (" ");
+ printf ("\b");
+ fflush (stdout);
+ }
+
+ if (noticebad)
+ {
+ if (showletters)
+ {
+ /* And replace it with an error message */
+ printf ("<UNKNOWN_CHARACTER>");
+ fflush (stdout);
+ }
+
+ /* Give the error call */
+ show ("........");
+
+ /* Regroup */
+ tone (frequency, inter_word_time, 0.);
+ }
+ }
+
+ if (showmorse)
+ printf (" ");
+ fflush (stdout);
+ toneflush ();
+ tone (frequency, inter_char_time - intra_char_time, 0.);
+}
+
+
+/*
+ * Don't try to test the person WHILE doing dots and dashes!
+ */
+void
+show (s)
+ char *s;
+{
+char c;
+
+ while ((c = *s++) != '\0')
+ {
+ tone (frequency, intra_char_time, 0.);
+
+#ifdef FLUSHCODE
+ if (showmorse)
+ toneflush ();
+#endif
+
+ switch (c)
+ {
+ case '.':
+ tone (frequency, dot_time, volume);
+ break;
+ case '-':
+ tone (frequency, dash_time, volume);
+ break;
+ }
+
+ if (showmorse)
+ {
+ printf ("%c", c);
+ fflush (stdout);
+#ifdef FLUSHCODE
+ toneflush ();
+#endif
+ }
+ }
+}
+
+/*
+ * This only gets passed valid characters: ones
+ * that have a morse code associated with them
+ * or ones for which isspace(c) is true.
+ */
+void
+testaddchar (c)
+ char c;
+{
+ testpointer = (testpointer + 1) % TESTBUFSZ;
+ teststring[testpointer] = c;
+#ifdef DEBUG
+ fprintf (stderr, " (%c,%d,%d) ", c, testlength, behindness);
+#endif
+ testlength++;
+ if (testlength > TESTBUFSZ)
+ {
+ fprintf (stderr, "\n\nInput buffer queue overflow! Make TESTBUFSZ bigger!\n");
+ fprintf (stderr, "(Or don't fall so far behind)\n");
+
+ die ();
+ }
+
+/*
+ * Since you are never asked to type spaces (you can type them if
+ * you want, but they are ignored) spaces in the input file don't
+ * count against your "behindness".
+ */
+ if (!isspace (c))
+ behindness++;
+}
+
+void
+youraddchar (c)
+ char c;
+{
+ yourpointer = (yourpointer + 1) % TESTBUFSZ;
+ yourstring[yourpointer] = c;
+#ifdef DEBUG
+ fprintf (stderr, " <%c,%d> ", c, yourlength);
+#endif
+ yourlength++;
+ if (yourlength > TESTBUFSZ)
+ {
+ fprintf (stderr, "\n\nKeyboard typeahead buffer queue overflow! Make TESTBUFSZ bigger!\n");
+ fprintf (stderr, "(Or don't type so far ahead... how did you expect to get them right anyway?)\n");
+
+ die ();
+ }
+}
+
+void
+pollyou ()
+{
+int ii, num;
+char *string;
+
+ num = readterminal (&string);
+
+ for (ii = 0; ii < num; ii++)
+ youraddchar (string[ii]);
+}
+
+int
+testterminal ()
+{
+int testinc, yourinc;
+int correctchar, yourchar, yourcharnocase;
+int errorcount;
+int resync;
+
+ errorcount = 0;
+
+/*
+ * There is nothing in the input file queue right now,
+ * so we can't process any of your keystrokes.
+ * Defer processing until we can catch up with YOU!
+ */
+ if (testlength == 0)
+ return errorcount;
+
+ /* We're ready for you; but are you ready for us? */
+ pollyou ();
+
+/*
+ * Process your entries and the input queue entries in parallel
+ */
+ if (yourlength > 0 && testlength > 0)
+ {
+ for (testinc = 0, yourinc = 0;
+ testinc < testlength && yourinc < yourlength;
+ testinc++, yourinc++)
+ {
+ correctchar = teststring[(testpointer - testlength + 1 + testinc + TESTBUFSZ) % TESTBUFSZ];
+
+ /*
+ * The latter half of this if shouldn't be necessary, but just in
+ * case...
+ */
+ if (isspace (correctchar) || code[correctchar] == NULL)
+ {
+ if (showtesting)
+ {
+ printf ("%c", correctchar);
+ fflush (stdout);
+ }
+
+ /* White space doesn't count for "behindness" */
+ behindness++;
+ /* The _other_ pointer wasn't used; don't increment it. */
+ yourinc--;
+
+ /* Short circuit the loop */
+ continue;
+ }
+
+
+ yourchar = yourstring[(yourpointer - yourlength + 1 + yourinc + TESTBUFSZ) % TESTBUFSZ];
+ if (isalpha (yourchar))
+ yourcharnocase = yourchar - (isupper (yourchar) ? 'A' : 'a') + 'a';
+ else
+ yourcharnocase = yourchar;
+
+ /* Did you type something rude? If so, just ignore it. */
+ if (isspace (yourchar) || code[yourcharnocase] == NULL)
+ {
+ /* ESCAPE: dump status info */
+ /* Control-D: dump status info and then bye bye */
+ /* Control-H: force restart */
+ if (yourchar == '\033' || yourchar == (int) '\004')
+ {
+ report ();
+
+ if (yourchar == (int) '\004')
+ die ();
+ }
+ else if (yourchar == '\b')
+ {
+ helpmeflag = 1;
+ }
+
+ /* The _other_ pointer wasn't used; don't increment it. */
+ testinc--;
+ /* Short circuit the loop */
+ continue;
+ }
+
+ if (keepquiet > 1)
+ {
+ for (resync = testinc; resync < testlength; resync++)
+ if ( yourcharnocase == teststring[(testpointer - testlength + 1 + resync + TESTBUFSZ) % TESTBUFSZ])
+ {
+ for (; testinc < resync; testinc++)
+ {
+ correctchar = teststring[(testpointer - testlength + 1 + testinc + TESTBUFSZ) % TESTBUFSZ];
+ if (isspace (correctchar) || code[correctchar] == NULL)
+ {
+ if (showtesting) printf ("%c", correctchar);
+ } else {
+ printf("%s%c%s", enter_standout_mode, correctchar, exit_standout_mode);
+ }
+ }
+ fflush (stdout);
+ correctchar = teststring[(testpointer - testlength + 1 + testinc + TESTBUFSZ) % TESTBUFSZ];
+ keepquiet = 1;
+ break;
+ }
+ }
+
+ if (yourcharnocase != correctchar)
+ {
+ errorcount++;
+ totalmisscount++;
+
+ /*
+ * Record that you are having trouble with these.
+ */
+ errorlog[correctchar]++;
+ if (code[yourcharnocase] != NULL &&
+ errorlog[yourcharnocase] < MAX_ERROR_THRESHOLD)
+ errorlog[yourcharnocase]++;
+
+ if (keepquiet > 0)
+ {
+ printf("%s%c%s", enter_standout_mode, correctchar, exit_standout_mode);
+ fflush (stdout);
+ keepquiet++;
+ } else {
+ /*
+ * Scold them for their mistake.
+ */
+ printf ("\n");
+#ifdef ERROR_VOLUME
+#ifndef ERROR_FREQ
+#define ERROR_FREQ 2000.
+#endif
+ /* Beep using the tone generator */
+ toneflush ();
+ tone ((float) (ERROR_FREQ), .1, (float) (ERROR_VOLUME));
+#else
+ /* Beep using control-G */
+ printf ("\007");
+#endif
+ printf ("%c (%s) for %c (%s)\n",
+ yourchar, code[yourcharnocase],
+ correctchar, code[correctchar]);
+ fflush (stdout);
+ linepos = 0;
+ }
+
+ if (charbychar)
+ {
+ /* Give them a bit of time to think about their error */
+ tone (frequency, inter_word_time, 0.);
+ toneflush ();
+ }
+ if (dynamicspeed && !charbychar)
+ {
+ /*
+ * Slow down. Doesn't make sense to slow down for errors,
+ * though, if you've got all the time you want to think
+ * about each one.
+ */
+ words_per_minute /= ERRORSLOWER;
+ new_words_per_minute ();
+ }
+ if (randomletters && !tryingagain)
+ {
+ /*
+ * Ask ones that confused you more often!
+ */
+ if (code[yourcharnocase] != NULL)
+ {
+ randomfactor[yourcharnocase] += (3 * RANDOMINCWORSE / 2);
+ if (randomfactor[yourcharnocase] > RANDOMMAX)
+ randomfactor[yourcharnocase] = RANDOMMAX;
+ }
+
+ randomfactor[correctchar] += RANDOMINCWORSE * 2;
+ if (randomfactor[correctchar] > RANDOMMAX)
+ randomfactor[correctchar] = RANDOMMAX;
+ }
+ }
+ else
+ {
+ /*
+ * Record that you got this right.
+ */
+ if (!tryingagain)
+ {
+ totalhitcount++;
+ if (errorlog[correctchar] > error_floor)
+ errorlog[correctchar]--;
+ }
+
+ if (showtesting)
+ {
+ printf ("%c", yourchar);
+ fflush (stdout);
+ }
+
+ if (randomletters && !tryingagain)
+ {
+ if (slowpoke == SLOWPOKEMAX)
+ {
+ printf ("\nNice to have you back again, I was getting bored!\n");
+ linepos = 0;
+ }
+ else if (slowpoke >= SLOWPOKE * 3)
+ {
+ /*
+ * Did you take too long thinking about it? If so,
+ * you probably need to be asked this one more
+ * often...
+ */
+ randomfactor[correctchar] += (3 * RANDOMINCWORSE / 2);
+ if (randomfactor[correctchar] > RANDOMMAX)
+ randomfactor[correctchar] = RANDOMMAX;
+
+ /*
+ * Hits this slow shouldn't count! You were obviously
+ * just guessing! (But it doesn't count as an error
+ * either.)
+ */
+ totalhitcount--;
+ }
+ else if (slowpoke > FASTPOKE)
+ {
+ randomfactor[correctchar] +=
+ (slowpoke * RANDOMINCWORSE) / (2 * SLOWPOKE);
+ if (randomfactor[correctchar] > RANDOMMAX)
+ randomfactor[correctchar] = RANDOMMAX;
+ }
+ else if (slowpoke <= (FASTPOKE / 2))
+ {
+ /*
+ * Ask ones that you quickly answer correctly less
+ * often!
+ */
+ randomfactor[correctchar] -= (3 * RANDOMINCBETTER / 2);
+ /*
+ * Don't let randomfactor hit 0, or you'll NEVER be
+ * asked this one AGAIN!
+ */
+ if (randomfactor[correctchar] < 1)
+ randomfactor[correctchar] = 1;
+ }
+ else if (slowpoke <= FASTPOKE)
+ {
+ randomfactor[correctchar] -= (RANDOMINCBETTER / 2);
+ if (randomfactor[correctchar] < 1)
+ randomfactor[correctchar] = 1;
+ }
+ }
+ }
+
+ }
+ testlength -= testinc;
+ behindness -= testinc;
+ yourlength -= yourinc;
+ }
+
+/*
+ * If there are some extra white space characters in the input queue
+ * it's OK, we'll get to them next time or we'll clean them out at the
+ * end.
+ */
+ return errorcount;
+}
+
+
+/*----------------------------------------*/
+
+void
+tone (hertz, duration, amplitude)
+ float hertz, duration, amplitude;
+{
+ Beep ((int) (duration * 1000), (int) (amplitude * 100), (int) hertz);
+}
+
+
+void
+toneflush ()
+{
+ BeepWait ();
+}
+
+
+/*----------------------------------------*/
+
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#ifdef USG
+#include <termio.h>
+struct termio oldtermgtty;
+struct termio termgtty;
+#else
+#include <sys/file.h>
+struct sgttyb oldtermgtty;
+struct sgttyb termgtty;
+#endif
+static char *terminal = "/dev/tty";
+static int termfd;
+static int termopen = 0;
+
+#ifndef USG
+static int oldflgs, newflgs;
+#endif
+
+void
+openterminal ()
+{
+ /* get parameters and open terminal */
+
+#ifdef USG
+ termfd = open (terminal, O_RDWR | O_NDELAY, 0);
+ ioctl (termfd, TCGETA, &termgtty);
+ oldtermgtty = termgtty;
+ if (typeaway != LETMESEE)
+ termgtty.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
+ termgtty.c_lflag &= ~ICANON;
+ termgtty.c_cc[VMIN] = 1;
+ termgtty.c_cc[VTIME] = 0;
+ ioctl (termfd, TCSETAW, &termgtty);
+#else
+ termfd = open (terminal, O_RDWR, 0);
+ ioctl (termfd, TIOCGETP, &termgtty);
+ oldtermgtty = termgtty;
+ if (typeaway != LETMESEE)
+ termgtty.sg_flags &= ~ECHO;
+ termgtty.sg_flags |= CBREAK;
+ ioctl (termfd, TIOCSETP, &termgtty);
+ oldflgs = fcntl (termfd, F_GETFL);
+ newflgs = oldflgs | FNDELAY;
+#endif
+
+ termopen = 1;
+}
+
+int
+readterminal (string)
+ char **string;
+{
+/* This must be declared static! */
+static char line[TESTBUFSZ];
+int n;
+
+#ifndef USG
+ fcntl (termfd, F_SETFL, newflgs);
+#endif
+ n = read (termfd, line, sizeof (line) - 1);
+#ifndef USG
+ fcntl (termfd, F_SETFL, oldflgs);
+#endif
+
+ if (n > 0)
+ {
+ line[n] = '\0';
+ *string = line;
+ }
+ else
+ *string = NULL;
+
+ return n;
+}
+
+void
+closeterminal ()
+{
+#ifdef USG
+ ioctl (termfd, TCSETAW, &oldtermgtty);
+#else
+ ioctl (termfd, TIOCSETP, &oldtermgtty);
+#endif
+ close (termfd);
+}
+
+SIGRET
+die ()
+{
+ cleanup ();
+ exit (1);
+}
+
+void
+cleanup ()
+{
+ if (termopen)
+ closeterminal ();
+ BeepCleanup ();
+}
+
+SIGRET
+suspend ()
+{
+ signal (SIGTSTP, suspend);
+ cleanup ();
+ kill (getpid (), SIGSTOP);
+ if (termopen)
+ openterminal ();
+ BeepResume ();
+}
+
+
+/*----------------------------------------*/
+
+int
+randomletter ()
+{
+int ii;
+int sum, sum2;
+long ranspot;
+extern time_t time ();
+static int lasttime = -1;
+static long norepeat;
+
+/*
+ * This keeps the not-so-random random number generator from ignoring
+ * certain characters forever!
+ */
+ norepeat = ((long) time (NULL) / 31) % 17291;
+
+/*
+ * All the usable letters get one unit riper.
+ */
+ for (ii = 0; ii < TWOFIFTYSIX; ii++)
+ {
+ if (randomfactor[ii] > 0)
+ {
+#ifdef DEBUGG
+ fprintf (stderr, "%c: %d %d\n",
+ (char) ii, randomfactor[ii], randomripe[ii]);
+#endif
+ randomripe[ii]++;
+ }
+ }
+
+ sum = 0;
+ for (ii = 0; ii < TWOFIFTYSIX; ii++)
+ sum += (randomfactor[ii] + (int) (randomripe[ii] / RIPECOUNT));
+
+/*
+ * The low bits of random aren't very random, I don't care WHAT
+ * the manual claims.
+ */
+ do
+ {
+ ranspot = ((RANDOM () >> 4) % sum + norepeat) % sum;
+
+ sum2 = 0;
+ for (ii = 0; ii < TWOFIFTYSIX - 1; ii++)
+ {
+ sum2 += (randomfactor[ii] + (int) (randomripe[ii] / RIPECOUNT));
+
+ if (sum2 > ranspot)
+ break;
+ }
+ /* Do it again if you got the same as last time! */
+ } while (ii == lasttime);
+
+ /* This one is FRESH again. */
+ randomripe[ii] = 0;
+ /* Remember for next time. */
+ lasttime = ii;
+
+ return ii;
+}
+
+void
+report ()
+{
+int ii, jj, count;
+float sum;
+int randomstr[TWOFIFTYSIX];
+extern int rancomp ();
+
+ printf ("\nCurrent words per minute: %.1f\n", words_per_minute);
+
+ printf ("Total hits %d, misses %d", totalhitcount, totalmisscount);
+ if (totalmisscount > 0)
+ printf (", hit per miss ratio %.1f\n", (float) totalhitcount / (float) totalmisscount);
+ else
+ printf ("\n");
+
+ if (randomletters)
+ {
+ printf ("Most to least frequent choices:\n");
+ count = 0;
+ sum = 0.;
+ for (ii = 0; ii < TWOFIFTYSIX; ii++)
+ {
+ if (randomfactor[ii] > 0)
+ {
+ sum += (randomfactor[ii] + (randomripe[ii] / (float) RIPECOUNT));
+ randomstr[count] = ii;
+ count++;
+ }
+ }
+
+ qsort ((char *) randomstr, count, sizeof (randomstr[0]), rancomp);
+
+ for (ii = 0; ii < count; ii++)
+ {
+/*
+ * Insert a space for each jump across an integer.
+ * The normalization (count/sum) ensures that if all
+ * letters were equally probable, they would all have value 1.
+ * Since they are not generally equally probable, then 1 is just the average.
+ * Thus the rightmost space in the printout marks where the average is.
+ * Further left spaces separate off blocks of letters that are approximately
+ * twice as probable as the average, three times, etc.
+ */
+ if (ii > 0)
+ {
+ for (jj = 0; jj <
+ (int) (
+ (randomfactor[randomstr[ii - 1]] + (randomripe[randomstr[ii - 1]] / (float) RIPECOUNT))
+ * count / sum) -
+ (int) (
+ (randomfactor[randomstr[ii]] + (randomripe[randomstr[ii]] / (float) RIPECOUNT))
+ * count / sum);
+ jj++)
+ printf (" ");
+ }
+ printf ("%c", (char) randomstr[ii]);
+ }
+ printf ("\n");
+ }
+
+ /*
+ * So you don't get penalized for being "slow" after this.
+ */
+ if (charbychar)
+ slowpoke = SLOWPOKEMAX + 1;
+
+ fflush (stdout);
+}
+
+int
+rancomp (elem1, elem2)
+ int *elem1, *elem2;
+{
+float a, b;
+
+ a = (randomfactor[(*elem1)] + (randomripe[(*elem1)] / (float) RIPECOUNT));
+ b = (randomfactor[(*elem2)] + (randomripe[(*elem2)] / (float) RIPECOUNT));
+
+ if (a == b)
+ return 0;
+ else if (a > b)
+ return -1;
+ else
+ return 1;
+}
--- /dev/null
+# Your favorite C compiler
+CC = gcc
+#CC = cc
+
+# The flags your favorite C compiler requires to work.
+CFLAGS = -O3 -m486
+
+OBJECTS = QSO.o put_form.o make_fre.o grammar.o util.o init_str.o
+INCLUDES = antenna.h callsign.h city.h cityh.h heights.h jobs.h misc.h \
+ names.h newcity.h rig.h weather.h
+
+all: QSO
+
+QSO: $(OBJECTS)
+ $(CC) -o $@ $(OBJECTS)
+
+init_str.o: $(INCLUDES)
+
+clean:
+ rm -f *.o QSO
--- /dev/null
+/*
+ * Return-Path: <pjd@cadillac.siemens.com>
+ * Received: from cadillac.siemens.com by montebello.soest.hawaii.edu (4.1/montebello-MX-1.9)
+ * id AA01487; Mon, 10 Aug 92 03:21:41 HST
+ * Received: from kevin.siemens.com by cadillac.siemens.com (4.1/SMI-4.0)
+ * id AA25847; Mon, 10 Aug 92 09:21:37 EDT
+ * Date: Mon, 10 Aug 92 09:21:37 EDT
+ * From: pjd@cadillac.siemens.com (paul j. drongowski)
+ * Message-Id: <9208101321.AA25847@cadillac.siemens.com>
+ * To: joe@montebello.soest.hawaii.edu
+ * Status: RO
+ */
+
+/*
+ * This copy is slightly hacked by Joe Dellinger, August 1992
+ * And some more... November 1992
+ *
+ * Partially re-written by "murray@vs6.scri.fsu.edu"
+ * to use better grammar and to avoid some nonsensical
+ * responses (like claiming to be a person who's been licensed
+ * longer than they've been alive!), Jan 1994
+ *
+ * Those improvements merged with others by Joe Dellinger, Oct 1994
+ */
+
+/*
+ * Generate QSO
+ */
+
+/*
+ * Author: Paul J. Drongowski / N2OQT
+ * Address: 1 Allen Court
+ * Plainsboro, New Jersey 08536
+ * Date: 10 October 1991
+ *
+ * Copyright (c) 1991 Paul J. Drongowski
+ */
+
+/*
+ * When run, this program generates a single QSO. The form of the
+ * QSO is similar to QSO's one would expect to hear at a code test.
+ * It begins with a series of V's (commented out in this version),
+ * callsigns of the receiver and
+ * sender, followed by a few sentences about weather, name,
+ * occupation, etc. The QSO ends with the callsigns of the receiver
+ * and sender.
+ *
+ * All output is produced using "printf." This should make the
+ * program easy to port. Output can be piped into another program
+ * such as sparc-morse on the Sun or it can be redirected into
+ * a file (without viewing the contents of course!)
+ *
+ * The program design is similar to a "random poetry generator"
+ * or "mad-libs." Each QSO form is generated by its own C function,
+ * such as "PutForm1." Each function calls other C functions to
+ * produce the sentences in the QSO. The sentence forms are
+ * selected somewhat randomly as well as any blanks to be filled.
+ * Words and phrases are selected from several lists such as
+ * "Transceiver," "Antenna," "Job," etc. Sometimes this scheme is
+ * clever as in the formation of city names. Sometimes it is
+ * stupidly simple-minded and grammatical agreement is lost.
+ * By the way, the callsigns are real and were picked from
+ * rec.radio.amateur.misc on USENET.
+ *
+ * The program was constructed in C for Sun workstations. It uses
+ * the library function "drand48" in function "Roll" to produce
+ * pseudo-random numbers. The library function "srand48" and "time"
+ * in "main" are used to set the pseudo-random number seed.
+ *
+ * Known problems and caveats? Hey, it`s software! All Morse
+ * training programs handle the procedural signs (e.g., AR, SK)
+ * differently. The function "PutQSO" currently prints "+ %"
+ * for the AR and SK at the end of the QSO. These may be ignored,
+ * mapped into something else, or just plain cause your training
+ * program to roll over and play dead. I don`t know. This is a
+ * cheap hack.
+ *
+ * And speaking of cheap... The program will not generate all
+ * characters and pro-signs that are found on an "official" code
+ * test. This program is for practice only and should be supplemented
+ * with lots of random code.
+ *
+ * Please note that I retain the copyright
+ * to this program. You may use it for any non-commercial purposes.
+ * This is roughly equivalent to "fair use."
+ *
+ * Always have fun!
+ */
+
+
+#include <sys/types.h>
+/*
+#include <sys/time.h>
+ */
+#include <time.h>
+
+char *A_Or_An ();
+
+int License_Seed ();
+
+int their_age; /* PERSON'S AGE, SO THEY AREN'T LICENSED MORE
+ * THAN THEIR AGE */
+
+
+extern char *Transceiver[];
+extern char *Antenna[];
+extern char *UpFeet[];
+extern char *Weather1[];
+extern char *Weather2[];
+extern char *Power[];
+extern char *Job[];
+extern char *Name[];
+extern char *CallSign[];
+extern char *License[];
+extern char *City[];
+extern char *NewCity[];
+extern char *CityHeights[];
+extern char *New[];
+extern char *Heights[];
+extern char *State[];
+extern char *Frqmisc[];
+extern char *Callmisc[];
+extern char *NumMisc[];
+extern char *Miscellaneous[];
+extern char *RST[];
+
+int NXCVR;
+int NANTENNA;
+int NUPFEET;
+int NWX1;
+int NWX2;
+int NPOWER;
+int NJOB;
+int NNAME;
+int NCALLSIGN;
+char *Sender, *Receiver;
+int NLICENSE;
+int NCITY;
+int NNEWCITY;
+int NCITYHTS;
+int NNEW;
+int NHEIGHTS;
+int NSTATE;
+int NFRQMISC;
+int NFRQCALLMISC;
+
+char *FrqCallmisc[] =
+{
+ "QRW %s %d",
+ "QRZ %s %d",
+ "QSN %s %d",
+ "QSX %s %d",
+ "QRW %s %d?",
+ "QRZ %s %d?",
+ "QSN %s %d?",
+ "QSX %s %d?",
+ 0
+};
+
+char *Choose ();
+int NCALLMISC;
+int NNUMMISC;
+int NMISC;
+int NRST;
+
+
+/*
+ *************************************
+ * Routines to put sentences/clauses *
+ *************************************
+ */
+
+void
+PutMisc ()
+{
+ printf ("%s\n", Choose (Miscellaneous, NMISC));
+}
+
+void
+PutThanks ()
+{
+ switch (Roll (6))
+ {
+ case 2:
+ printf ("Thanks for your call.\n");
+ break;
+
+ case 3:
+ printf ("Tnx for ur call.\n");
+ break;
+
+ case 4:
+ printf ("Tnx for the call.\n");
+ break;
+
+ case 5:
+ printf ("Thanks for the call.\n");
+ break;
+
+ default:
+ printf ("Thanks %s for the call.\n", Choose (Name, NNAME));
+ break;
+ }
+}
+
+void
+PutName ()
+{
+ switch (Roll (6))
+ {
+ case 2:
+ printf ("Name is %s.\n", Choose (Name, NNAME));
+ break;
+
+ case 4:
+ printf ("This is %s.\n", Choose (Name, NNAME));
+ break;
+
+ case 5:
+ printf ("%s here.\n", Choose (Name, NNAME));
+ break;
+
+ default:
+ printf ("My name is %s.\n", Choose (Name, NNAME));
+ break;
+ }
+}
+
+void
+PutJob ()
+{
+ switch (Roll (20))
+ {
+ case 2:
+ case 3:
+ printf ("My occupation is %s.\n", Choose (Job, NJOB));
+ break;
+
+ case 4:
+ case 5:
+ printf ("I work as %s.\n", A_Or_An (Choose (Job, NJOB)));
+ break;
+
+ case 6:
+ printf ("I was %s, now unemployed.\n", A_Or_An (Choose (Job, NJOB)));
+ break;
+
+ case 11:
+ case 12:
+ printf ("Occupation is %s.\n", Choose (Job, NJOB));
+ break;
+
+ default:
+ printf ("I am %s.\n", A_Or_An (Choose (Job, NJOB)));
+ break;
+ }
+}
+
+void
+PutAge ()
+{
+
+ their_age = Roll (60) + 16;
+
+ switch (Roll (5))
+ {
+ case 3:
+ printf ("My age is %d.\n", their_age);
+ break;
+
+ case 4:
+ printf ("I am %d years old.\n", their_age);
+ break;
+
+ default:
+ printf ("Age is %d.\n", their_age);
+ break;
+ }
+}
+
+void
+PutLicense ()
+{
+int get_years_licence;
+
+ get_years_licence = Roll (License_Seed ());
+ if (get_years_licence < 2)
+ get_years_licence = 2;
+
+ switch (Roll (12))
+ {
+ case 1:
+ printf ("I have %s class licence.\n",
+ A_Or_An (Choose (License, NLICENSE)));
+ break;
+
+ case 2:
+ printf ("I am %s license ham.\n",
+ A_Or_An (Choose (License, NLICENSE)));
+ break;
+
+ case 3:
+ printf ("I am %s licence ham.\n",
+ A_Or_An (Choose (License, NLICENSE)));
+ break;
+
+ case 4:
+ printf ("I have been licenced %d years as %s class.\n",
+ get_years_licence, Choose (License, NLICENSE));
+ break;
+
+ case 5:
+ printf ("I have %s class license.\n",
+ A_Or_An (Choose (License, NLICENSE)));
+ break;
+
+ case 6:
+ printf ("I am %s class ham.\n",
+ A_Or_An (Choose (License, NLICENSE)));
+ break;
+
+ case 7:
+ printf ("I have been licensed %d years as %s class.\n",
+ get_years_licence, Choose (License, NLICENSE));
+ break;
+
+ default:
+ printf ("I have been %s class ham for %d years.\n",
+ A_Or_An (Choose (License, NLICENSE)), get_years_licence);
+ break;
+ }
+}
+
+void
+PutTemperature ()
+{
+ printf ("Temperature is %d.\n", Roll (80) + 10);
+}
+
+void
+PutWeather1 ()
+{
+ switch (Roll (17))
+ {
+ case 2:
+ printf ("WX is %s.\n", Choose (Weather1, NWX1));
+ PutTemperature ();
+ break;
+
+ case 3:
+ printf ("Weather here is %s.\n", Choose (Weather1, NWX1));
+ break;
+
+ case 4:
+ printf ("Weather is %s.\n", Choose (Weather1, NWX1));
+ break;
+
+ case 5:
+ printf ("WX is %s.\n", Choose (Weather1, NWX1));
+ break;
+
+ case 6:
+ PutTemperature ();
+ printf ("Weather here is %s.\n", Choose (Weather1, NWX1));
+ break;
+
+ case 7:
+ PutTemperature ();
+ printf ("Weather is %s.\n", Choose (Weather1, NWX1));
+ break;
+
+ case 8:
+ PutTemperature ();
+ printf ("WX is %s.\n", Choose (Weather1, NWX1));
+ break;
+
+ case 9:
+ printf ("Weather here is %s and temperature is %d.\n",
+ Choose (Weather1, NWX1), Roll (80) + 10);
+ break;
+
+ case 10:
+ printf ("Weather is %s, temperature %d.\n",
+ Choose (Weather1, NWX1), Roll (80) + 10);
+ break;
+
+ case 11:
+ printf ("WX is %d degrees and %s.\n",
+ Roll (80) + 10, Choose (Weather1, NWX1));
+ break;
+
+ case 12:
+ printf ("The WX is %s and the temp is %d degrees.\n",
+ Choose (Weather1, NWX1), Roll (80) + 10);
+ break;
+
+ case 14:
+ printf ("Weather is %s.\n", Choose (Weather1, NWX1));
+ PutTemperature ();
+ break;
+
+ case 15:
+ printf ("Weather here is %s.\n", Choose (Weather1, NWX1));
+ PutTemperature ();
+ break;
+
+ default:
+ printf ("WX is %s and %d degrees.\n",
+ Choose (Weather1, NWX1), Roll (80) + 10);
+ }
+}
+
+void
+PutWeather2 ()
+{
+
+ switch (Roll (10))
+ {
+ case 0:
+ printf ("It is %s.\n", Choose (Weather2, NWX2));
+ break;
+
+ case 1:
+ printf ("It is %s and %d degrees.\n",
+ Choose (Weather2, NWX2), Roll (80) + 10);
+ break;
+
+ case 2:
+ printf ("The WX is %s and the temp is %d degrees.\n",
+ Choose (Weather2, NWX2), Roll (80) + 10);
+ break;
+
+ case 3:
+ printf ("WX is %s and the temp is %d degrees.\n",
+ Choose (Weather2, NWX2), Roll (80) + 10);
+ break;
+
+ case 4:
+ printf ("It is %s today.\n", Choose (Weather2, NWX2));
+ break;
+
+ case 5:
+ printf ("It is %s and %d degrees.\n",
+ Choose (Weather2, NWX2), Roll (100) + 3);
+ break;
+
+ case 6:
+ printf ("The WX is %s and the temp is %d degrees.\n",
+ Choose (Weather2, NWX2), Roll (90) + 10);
+ break;
+
+ case 7:
+ printf ("WX is %s and the temp is %d degrees.\n",
+ Choose (Weather2, NWX2), Roll (80) + 10);
+ break;
+
+ default:
+ printf ("It is %s here.\n", Choose (Weather2, NWX2));
+ break;
+ }
+}
+
+void
+PutWeather ()
+{
+ switch (Roll (4))
+ {
+ case 3:
+ PutWeather1 ();
+ break;
+
+ default:
+ PutWeather2 ();
+ break;
+ }
+}
+
+void
+PutCityState ()
+{
+ switch (Roll (6))
+ {
+ case 4:
+ printf ("%s %s, ",
+ Choose (CityHeights, NCITYHTS), Choose (Heights, NHEIGHTS));
+ break;
+
+ case 5:
+ printf ("%s %s, ", Choose (New, NNEW), Choose (NewCity, NNEWCITY));
+ break;
+
+ default:
+ printf ("%s, ", Choose (City, NCITY));
+ break;
+ }
+ printf ("%s.\n", Choose (State, NSTATE));
+}
+
+void
+PutLocation ()
+{
+
+ switch (Roll (5))
+ {
+ case 3:
+ printf ("My QTH is ");
+ break;
+
+ case 4:
+ printf ("My location is ");
+ break;
+
+ default:
+ printf ("QTH is ");
+ break;
+
+ }
+ PutCityState ();
+}
+
+void
+PutRig ()
+
+{
+ switch (Roll (19))
+ {
+ case 0:
+ case 1:
+ printf ("My rig runs %s watts into %s up %s feet.\n",
+ Choose (Power, NPOWER), A_Or_An (Choose (Antenna, NANTENNA)),
+ Choose (UpFeet, NUPFEET));
+ break;
+
+ case 2:
+ case 3:
+ printf ("Rig is a %s watt %s and antenna is %s.\n",
+ Choose (Power, NPOWER), Choose (Transceiver, NXCVR),
+ A_Or_An (Choose (Antenna, NANTENNA)));
+ break;
+
+ case 4:
+ case 5:
+ printf ("My transceiver is %s.\n", A_Or_An (Choose (Transceiver, NXCVR)));
+ printf ("It runs %s watts into %s.\n",
+ Choose (Power, NPOWER), A_Or_An (Choose (Antenna, NANTENNA)));
+ break;
+
+ case 6:
+ case 7:
+ printf ("The rig is %s running %s watts.\n",
+ A_Or_An (Choose (Transceiver, NXCVR)), Choose (Power, NPOWER));
+ printf ("Antenna is %s up %s m.\n",
+ A_Or_An (Choose (Antenna, NANTENNA)), Choose (UpFeet, NUPFEET));
+ break;
+
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ printf ("My rig runs %s watts into %s up %s meters.\n",
+ Choose (Power, NPOWER), A_Or_An (Choose (Antenna, NANTENNA)),
+ Choose (UpFeet, NUPFEET));
+ break;
+
+ case 12:
+ printf ("My rig runs %s watts into %s up %s feet, but\nthe antenna has partly fallen.\n",
+ Choose (Power, NPOWER), A_Or_An (Choose (Antenna, NANTENNA)),
+ Choose (UpFeet, NUPFEET));
+ break;
+
+ case 13:
+ printf ("Rig is %s running %s watts into %s up %s ft.\n",
+ A_Or_An (Choose (Transceiver, NXCVR)), Choose (Power, NPOWER),
+ A_Or_An (Choose (Antenna, NANTENNA)), Choose (UpFeet, NUPFEET));
+ break;
+
+ case 14:
+ printf ("My rig runs %s watts into %s up %s feet.\n",
+ Choose (Power, NPOWER), A_Or_An (Choose (Antenna, NANTENNA)),
+ Choose (UpFeet, NUPFEET));
+ break;
+
+ case 15:
+ printf ("Rig is %s watt %s and antenna is %s.\n",
+ A_Or_An (Choose (Power, NPOWER)),
+ Choose (Transceiver, NXCVR),
+ Choose (Antenna, NANTENNA));
+ break;
+
+ case 16:
+ printf ("My transceiver is %s.\n",
+ A_Or_An (Choose (Transceiver, NXCVR)));
+ printf ("It runs %s watts into %s.\n",
+ Choose (Power, NPOWER),
+ A_Or_An (Choose (Antenna, NANTENNA)));
+ break;
+
+ case 17:
+ printf ("The rig is %s running %s watts.\n",
+ A_Or_An (Choose (Transceiver, NXCVR)),
+ Choose (Power, NPOWER));
+ printf ("Antenna is %s up %s feet.\n",
+ A_Or_An (Choose (Antenna, NANTENNA)),
+ Choose (UpFeet, NUPFEET));
+ break;
+
+ default:
+ printf ("Rig is %s ",
+ A_Or_An (Choose (Transceiver, NXCVR)));
+ printf ("running %s watts into %s up %s feet.\n",
+ Choose (Power, NPOWER),
+ A_Or_An (Choose (Antenna, NANTENNA)),
+ Choose (UpFeet, NUPFEET));
+ break;
+ }
+}
+
+void
+PutRST ()
+{
+register char *TheRST;
+
+ TheRST = Choose (RST, NRST);
+
+ switch (Roll (8))
+ {
+ case 0:
+ printf ("UR RST %s=%s.\n", TheRST, TheRST);
+ break;
+
+ case 1:
+ printf ("RST is %s=%s.\n", TheRST, TheRST);
+ break;
+
+ case 2:
+ printf ("RST %s=%s.\n", TheRST, TheRST);
+ break;
+
+ case 3:
+ printf ("Your RST %s=%s.\n", TheRST, TheRST);
+ break;
+
+ case 4:
+ printf ("Your RST is %s=%s.\n", TheRST, TheRST);
+ break;
+
+ case 5:
+ printf ("Your signal is RST %s/%s.\n", TheRST, TheRST);
+ break;
+
+ case 6:
+ printf ("UR signal is RST %s,%s.\n", TheRST, TheRST);
+ break;
+
+ default:
+ printf ("Your RST is %s/%s.\n", TheRST, TheRST);
+ break;
+ }
+}
+
+
+void
+PutQ_And_Freq ()
+{
+ switch (Roll (8))
+ {
+ case 2:
+ printf (Frqmisc[Roll (NFRQMISC)], make_freq ());
+ printf ("\n");
+ break;
+
+ case 3:
+ printf (Callmisc[Roll (NFRQMISC)],
+ Choose (CallSign, NCALLSIGN));
+ printf ("\n");
+ break;
+
+ case 4:
+ printf (FrqCallmisc[Roll (NFRQCALLMISC)],
+ Choose (CallSign, NCALLSIGN),
+ make_freq ());
+ printf ("\n");
+ break;
+
+ case 5:
+ printf (NumMisc[Roll (NNUMMISC)],
+ Roll (3) + Roll (2) + 1);
+ printf ("\n");
+ break;
+
+ default:
+ break;
+
+ }
+}
+
+void
+PutFirstCallsign ()
+{
+ Sender = Choose (CallSign, NCALLSIGN);
+ Receiver = Choose (CallSign, NCALLSIGN);
+ printf ("%s de %s\n", Receiver, Sender);
+}
+
+void
+PutLastCallsign ()
+{
+ printf ("%s de %s\n", Receiver, Sender);
+}
+
+main ()
+{
+
+ NXCVR = CountStrings (Transceiver);
+ NANTENNA = CountStrings (Antenna);
+ NUPFEET = CountStrings (UpFeet);
+ NPOWER = CountStrings (Power);
+ NRST = CountStrings (RST);
+ NWX1 = CountStrings (Weather1);
+ NWX2 = CountStrings (Weather2);
+ NJOB = CountStrings (Job);
+ NNAME = CountStrings (Name);
+ NSTATE = CountStrings (State);
+ NCITY = CountStrings (City);
+ NCITYHTS = CountStrings (CityHeights);
+ NNEW = CountStrings (New);
+ NHEIGHTS = CountStrings (Heights);
+ NNEWCITY = CountStrings (NewCity);
+ NLICENSE = CountStrings (License);
+ NMISC = CountStrings (Miscellaneous);
+ NCALLSIGN = CountStrings (CallSign);
+ NFRQMISC = CountStrings (Frqmisc);
+ NFRQCALLMISC = CountStrings (FrqCallmisc);
+ NCALLMISC = CountStrings (Callmisc);
+ NNUMMISC = CountStrings (NumMisc);
+
+ srand48 ((long) time (0));
+
+ PutQSO ();
+
+ return 0;
+}
--- /dev/null
+"10 meter dipole",
+"10 meter whip",
+"3 element beam",
+"5 band vertical",
+"5 element loop",
+"7 band beam",
+"beam",
+"delta loop",
+"dipole",
+"doublet zepp",
+"dummy load",
+"ground=plane",
+"half wave dipole",
+"inverted V",
+"light bulb",
+"log periodic",
+"long=wire",
+"monobander",
+"parasitic beam",
+"quad loop",
+"quad vertical",
+"quagi",
+"quarter wave vertical",
+"random wire up 2 kite",
+"random wire up to kite",
+"random wire",
+"rhombic",
+"symmetrical delta loop",
+"trap doublet",
+"tribander",
+"whip",
+"yagi",
+"zepp",
--- /dev/null
+"AA0ET",
+"AA4LR",
+"AA5BT",
+"AA6NP",
+"AA6YD",
+"AA9BK",
+"AB5AP",
+"AB6FI",
+"AC4HF",
+"G0GWA",
+"GM4ZNX",
+"I5FLN",
+"IK5AAX",
+"JA1BLV",
+"JY1",
+"K2WK",
+"K5RC",
+"K6OCK",
+"K6XO",
+"K9ALD",
+"KA0WCH",
+"KA1AXY",
+"KA1CV",
+"KA1UTU",
+"KA1ZGC",
+"KA2RAF",
+"KA6S",
+"KB0CY",
+"KB2NRH",
+"KB6CSP",
+"KB6JXT",
+"KC6SKV",
+"KC6SSS",
+"KC6TDR",
+"KC6VWV",
+"KD3FU",
+"KD4AUS",
+"KD4CPL",
+"KE2TP",
+"KE4ZV",
+"KF6BZF",
+"KF8NH",
+"KJ6NN",
+"KJ9U",
+"KJ9U/KH6",
+"KK6JQ",
+"KM3T",
+"KT7H",
+"N1AL",
+"N1JCX",
+"N4PBK",
+"N4VRN",
+"N5IAL",
+"N5OP",
+"N6BIS",
+"N6MWC",
+"N6TTO",
+"N8EMR",
+"N9FZX",
+"N9JRV",
+"N9LFF",
+"N9MYI",
+"NE3X",
+"NH6EG",
+"NH6EG/5",
+"NH6ZW",
+"NJ7E",
+"NR3Z",
+"NT1G",
+"OD5NG",
+"OH3BK",
+"OH8NUP",
+"TG9VT",
+"UT5RP",
+"VE6MGS",
+"VE7EMD",
+"VK2BQS",
+"VK2EG",
+"W0PBV",
+"W0RIJ",
+"W0RSB",
+"W2FG",
+"W2JGR",
+"W3GRG",
+"W3OTC",
+"WA1UXA",
+"WA2AGE",
+"WA3EEC",
+"WA3TBL",
+"WA3UQV",
+"WA5RPF",
+"WA6DGX",
+"WA7VYJ",
+"WA8ZGO",
+"WB2CJL",
+"WB4JCM",
+"WB5FDP",
+"WB5FKH",
+"WB5NRN",
+"WB7CJO",
+"WB7EEL",
+"WB7TZA",
+"WB8EOH",
+"WB9IVR",
+"WD0EIB",
+"WH6UR",
+"WH6UR/5",
+"WX9T",
--- /dev/null
+"Agassiz",
+"Aiea",
+"Alexander",
+"Asbury",
+"Baker",
+"Bayaney",
+"Beckley",
+"Bedford",
+"Bixby",
+"Branyan",
+"Brazoria",
+"Broken Arrow",
+"Brunswick",
+"Bryan",
+"Burnsville",
+"Buzzard",
+"Cambridge",
+"Carrizo",
+"Catoosa",
+"Chamizal",
+"Charleston",
+"Chepiwanoxet",
+"Chesuncook",
+"Chinquapin",
+"Circleville",
+"Claquato",
+"Clarksburg",
+"Clarksville",
+"Clear Lake",
+"Cleveland",
+"College",
+"Crystal",
+"Duncanville",
+"Elizabeth",
+"Enid",
+"Ewa",
+"Faalaaga",
+"Fairbanks",
+"Fairfax",
+"Fairfield",
+"Flamboyant Gardens",
+"Flint",
+"Gahanna",
+"Gappas",
+"Glenpool",
+"Grant",
+"Greensburg",
+"Guyandotte",
+"Guyanoga",
+"Harper Valley",
+"Harper",
+"Harquahala",
+"Hells Crossing",
+"Hill Valley",
+"Hillsdale",
+"Honolulu",
+"Hyannis",
+"Iraan",
+"Iyanbito",
+"Jamestown",
+"Jefferson",
+"Jenks",
+"Juncos",
+"Kaaawa",
+"Kohlsaat",
+"Kona",
+"Laager",
+"Lakewood",
+"Lancaster",
+"Lawrenceville",
+"Leyan",
+"Lincoln",
+"Litchfield",
+"London",
+"Long Branch",
+"Luxello",
+"Lyndale",
+"Lyndhurst",
+"Lynnville",
+"Maaloon",
+"Maitwan",
+"Manasquan",
+"Mansfield",
+"Maple",
+"Meadows",
+"Melbourne",
+"Mentor",
+"Mercer",
+"Mesquite",
+"Midland",
+"Milldale",
+"Milltown",
+"Moorestown",
+"Moscow",
+"Mountain View",
+"Moxee",
+"Murray",
+"Muskogee",
+"Musquiz",
+"Naxera",
+"New London",
+"Newfield",
+"Newport",
+"Nipgen",
+"Nisqually",
+"Nome",
+"Noname",
+"Noxubee",
+"Nutzotin",
+"Oak",
+"Occoquan",
+"Olmstead",
+"Owasso",
+"Oxford",
+"Oxnard",
+"Paradise",
+"Paris",
+"Pattaquattic",
+"Pawtuxet",
+"Perry",
+"Piscataquis",
+"Potter",
+"Pottsville",
+"Praag",
+"Quanah",
+"Quebec",
+"Redwood",
+"Rueechayaam",
+"Russellville",
+"Salem",
+"San Pasqual",
+"Sandy",
+"Sapulpa",
+"Saratoga",
+"Sequatchie",
+"Smithville",
+"Snoqualmie",
+"Springdale",
+"Springfield",
+"Squaxin",
+"Starkville",
+"Sunnyvale",
+"Sunset Valley",
+"Suquamish",
+"Tahlequah",
+"Tahquamenon",
+"Texoma",
+"Texum",
+"Tinker",
+"Trenton",
+"Tulsa",
+"Twisp",
+"Umpqua",
+"Union",
+"Uruguay",
+"Utica",
+"Vancouver",
+"Verona",
+"Viroqua",
+"Vista",
+"Waldberggaard",
+"Walnut",
+"Warners Landing",
+"Warren",
+"Warsaw",
+"Washington",
+"Wesleyanna",
+"Weston",
+"Wheatfield",
+"Williamson",
+"Worchester",
+"Wyandanch",
+"Xanthus",
+"Xenia",
+"Yangtze",
+"Yellowstone",
+"Yreka",
+"Zolton",
+"Zuni",
--- /dev/null
+"Apple",
+"Ashford",
+"Baker",
+"Baldwin",
+"Banner",
+"Barnard",
+"Benton",
+"Cabbot",
+"Carson",
+"Chester",
+"College",
+"Conway",
+"Cornwall",
+"Crystal",
+"Duxbury",
+"Fletcher",
+"Franklin",
+"Granite",
+"Grant",
+"Guyan",
+"Hamilton",
+"Harper",
+"Hickory",
+"Hoosick",
+"Jefferson",
+"Lincoln",
+"Maple",
+"Mercer",
+"Morgan",
+"Morris",
+"Murray",
+"Oak",
+"Orwell",
+"Oswego",
+"Perry",
+"Potter",
+"Quail",
+"Salem",
+"Stafford",
+"Stone",
+"Tinker",
+"Walnut",
+"Warren",
+"Washington",
+"Weston",
+"Wilton",
--- /dev/null
+int
+is_vowel (first_char)
+ char first_char;
+{
+ if (
+ first_char == 'A' ||
+ first_char == 'E' ||
+ first_char == 'I' ||
+ first_char == 'O' ||
+ first_char == 'U' ||
+ first_char == 'a' ||
+ first_char == 'e' ||
+ first_char == 'i' ||
+ first_char == 'o' ||
+ first_char == 'u'
+ )
+ return (1);
+ return (0);
+}
+
+char buffer[200];
+
+char *
+A_Or_An (string)
+ char *string;
+{
+ if (is_vowel (string[0]) == 1)
+ sprintf (buffer, "an %s", string);
+ else
+ sprintf (buffer, "a %s", string);
+ return ((char *) buffer);
+}
--- /dev/null
+"Beach",
+"Canyon",
+"Castle",
+"City",
+"Corner",
+"Cove",
+"Creek",
+"Estates",
+"Forest",
+"Gardens",
+"Glen",
+"Grove",
+"Harbor",
+"Heights",
+"Hill",
+"Hills",
+"Hole",
+"Island",
+"Knob",
+"Lake",
+"Meadow",
+"Meadows",
+"Mill",
+"Mountain",
+"Neck",
+"Palisades",
+"Park",
+"Pass",
+"Plantation",
+"Ridge",
+"River",
+"Springs",
+"Station",
+"Swale",
+"Terrace",
+"Valley",
+"Wood",
--- /dev/null
+char *Transceiver[] =
+{
+#include "rig.h"
+ 0
+};
+
+char *Antenna[] =
+{
+#include "antenna.h"
+ 0
+};
+
+char *UpFeet[] =
+{
+ "10", "15", "20", "25", "30", "35", "40", "45",
+ "50", "55", "60", "65", "70", "75", "80", "85",
+ "90", "95", "100",
+ "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20",
+ "10 1/2", "11 1/2", "25", "29 1/2", "30", "35", "40", "42",
+ "45", "45 1/2", "45.5",
+ "50", "55", "60", "62", "65", "70", "75", "80", "85", "87 1/3",
+ "90", "95", "100", "103", "137", "189 1/2", "210", "246", "250",
+ 0
+};
+
+char *Weather1[] =
+{
+ "sunny",
+ "rain",
+ "freezing rain",
+ "sleet",
+ "snow",
+ "cloudy",
+ "partly cloudy",
+ "partly sunny",
+ "clear",
+ 0
+};
+
+char *Weather2[] =
+{
+#include "weather.h"
+ 0
+};
+
+char *Power[] =
+{
+ "2", "5", "10", "20", "25", "40", "50", "80", "100",
+ "125", "140", "150", "170", "200", "250", "270", "300",
+ 0
+};
+
+char *Job[] =
+{
+#include "jobs.h"
+ 0
+};
+
+char *Name[] =
+{
+#include "names.h"
+ 0
+};
+
+char *CallSign[] =
+{
+#include "callsign.h"
+ 0
+};
+
+char *License[] =
+{
+ "Novice",
+ "Technician",
+ "Tech",
+ "Tech plus",
+ "Tech plus",
+ "Tech plus",
+ "Tech plus",
+ "Tech no code",
+ "General",
+ "Advanced",
+ "Extra",
+ "Extra",
+ "Extra",
+ 0
+};
+
+char *City[] =
+{
+#include "city.h"
+ 0
+};
+
+char *NewCity[] =
+{
+#include "newcity.h"
+ 0
+};
+
+char *CityHeights[] =
+{
+#include "cityh.h"
+ 0
+};
+
+char *New[] =
+{
+ "New",
+ "Old",
+ "North",
+ "South",
+ "East",
+ "West",
+ "New",
+ "Old",
+ "North",
+ "Northeast",
+ "Northwest",
+ "South",
+ "Southwest",
+ "Southeast",
+ "East",
+ "West",
+ "Upper",
+ "Lower",
+ 0
+};
+
+char *Heights[] =
+{
+#include "heights.h"
+ 0
+};
+
+char *State[] =
+{
+ "Alabama",
+ "Alaska",
+ "Arizona",
+ "Arkansas",
+ "California",
+ "Colorado",
+ "Connecticut",
+ "District of Columbia",
+ "Delaware",
+ "Florida",
+ "Georgia",
+ "Guam",
+ "Hawaii",
+ "Idaho",
+ "Illinois",
+ "Indiana",
+ "Iowa",
+ "Kansas",
+ "Kentucky",
+ "Louisiana",
+ "Maine",
+ "Maryland",
+ "Massachusetts",
+ "Michigan",
+ "Midway",
+ "Minnesota",
+ "Mississippi",
+ "Missouri",
+ "Montana",
+ "Nebraska",
+ "Nevada",
+ "New Hampshire",
+ "New Jersey",
+ "New Mexico",
+ "New York",
+ "North Carolina",
+ "North Dakota",
+ "Ohio",
+ "Oklahoma",
+ "Oregon",
+ "Pennsylvania",
+ "Puerto Rico",
+ "Rhode Island",
+ "Saipan",
+ "American Samoa",
+ "South Carolina",
+ "South Dakota",
+ "Tennessee",
+ "Texas",
+ "Utah",
+ "Vermont",
+ "Virginia",
+ "Virgin Islands",
+ "Wake Island",
+ "Washington",
+ "West Virginia",
+ "Wisconsin",
+ "Wyoming",
+ 0
+};
+
+char *Frqmisc[] =
+{
+ "QSN %d?",
+ "QSU %d?",
+ "QSW %d?",
+ "QSN %d",
+ "QSU %d",
+ "QSW %d",
+ 0
+};
+
+char *Callmisc[] =
+{
+ "QRK %s",
+ "QRL %s",
+ "QRZ %s",
+ "QSP %s",
+ "QRK %s?",
+ "QRL %s?",
+ "QRZ %s?",
+ "QSP %s?",
+ 0
+};
+
+char *NumMisc[] =
+{
+ "QRI %d",
+ "QRK %d",
+ "QRM %d",
+ "QRN %d",
+ "QRS %d",
+ "QRY %d",
+ "QSG %d",
+ "QTA %d",
+ "QTC %d",
+ "QRI %d?",
+ "QRK %d?",
+ "QRM %d?",
+ "QRN %d?",
+ "QRS %d?",
+ "QRY %d?",
+ "QSG %d?",
+ "QTA %d?",
+ "QTC %d?",
+ 0
+};
+
+char *Miscellaneous[] =
+{
+#include "misc.h"
+ 0
+};
+
+char *RST[] =
+{
+ "555",
+ "577",
+ "578",
+ "579",
+ "588",
+ "589",
+ "599",
+ "478",
+ "354",
+ "248",
+ "126",
+ 0
+};
--- /dev/null
+"administrator",
+"airline pilot",
+"artist",
+"attorney",
+"bricklayer",
+"bus driver",
+"carpenter",
+"chemist",
+"clerk",
+"clown",
+"college student",
+"consultant",
+"cook",
+"corporate liquidator",
+"curator",
+"dentist",
+"designer",
+"director",
+"doctor",
+"driver",
+"electrician",
+"engineer",
+"farmer",
+"fireman",
+"gardener",
+"geophysicist",
+"guard",
+"high school student",
+"hs student",
+"human resource consultant",
+"investment banker",
+"janitor",
+"jr college student",
+"juggler and unicyclist",
+"junior college student",
+"lawyer",
+"letter carrier",
+"librarian",
+"mafia killer",
+"mathematician",
+"mechanic",
+"midwife",
+"milkman",
+"nurse",
+"orthodontist",
+"pacifist",
+"painter",
+"petroleum engineer",
+"physician",
+"physicist",
+"police officer",
+"politician",
+"prison guard",
+"professor",
+"programmer",
+"researcher",
+"sailor",
+"sanitation worker",
+"sculptor",
+"secretary",
+"security guard",
+"semiotician",
+"soldier",
+"sql programmer",
+"stock broker",
+"student",
+"systems analyst",
+"teacher",
+"teller",
+"vulcanologist",
+"writer",
--- /dev/null
+#define M80 2
+#define M40 3
+#define M15 4
+#define M10 5
+#define NUM_BAND 4
+
+int
+make_freq ()
+{
+ switch (Roll (NUM_BAND + 2))
+ {
+ case M80:
+ return (3675 + Roll (50));
+ break;
+ case M40:
+ return (7100 + Roll (50));
+ break;
+ case M15:
+ return (21100 + Roll (100));
+ break;
+ case M10:
+ return (28100 + Roll (200));
+ break;
+ default:
+ return (7100 + Roll (50));
+ break;
+ }
+}
--- /dev/null
+"+%=x/,? 73 just testing you.",
+",?/=+9% 73 just testing you.",
+",?/=q+% 73 just testing u.",
+"8y67fvgb oops cat on keyboard.",
+"9p0ojgbhnw23 oops cat on keyboard.",
+"%w=+/,? 73 just testing you.",
+"A clumsy gecko just fell on my hand.",
+"Are you a communist?",
+"Are you a democrat?",
+"Are you a libertarian?",
+"Are you a republican?",
+"Are you divorced?",
+"Are you good at auto repair?",
+"Are you good at calculus? I have a question for you.",
+"Are you good at car repair? I have a question for you.",
+"Are you good at group theory? I have a question for you.",
+"Are you good at summing infinite series?",
+"Are you married?",
+"Are you on daylight savings time?",
+"Are you single?",
+"Are you using a linear amplifier?",
+"Are you using an iambic key?",
+"Are you widowed?",
+"Aye, laddie, have you ever been to sea?",
+"Can you pick kryptonite locks? Those are tricky.",
+"Can you pick kryptonite locks?",
+"Can you pick master locks? Those are supposed to be easy.",
+"Can you think of something else interesting to say?",
+"Copy?",
+"Cpy?",
+"Did you attend ORU?",
+"Did you hear news?",
+"Did you hear the news?",
+"Do u understand English?",
+"Do you have a baby?",
+"Do you have a cat?",
+"Do you have a dog?",
+"Do you have a ferret?",
+"Do you have a gecko?",
+"Do you have a horse?",
+"Do you know morse code?",
+"Do you know the word copacetic?",
+"Do you know the word garrulous?",
+"Do you know the word prosy?",
+"Do you know what a pangram is?",
+"Do you like bach?",
+"Do you like bernstein?",
+"Do you like c and w music?",
+"Do you like classical music?",
+"Do you like country music?",
+"Do you like hawaiian music?",
+"Do you like jawaiian music?",
+"Do you like modern rock?",
+"Do you like mozart?",
+"Do you like pop music?",
+"Do you like reggae music?",
+"Do you like rock music?",
+"Do you like swing music?",
+"Do you listen to Deutsche Welle?",
+"Do you listen to Radio Australia?",
+"Do you listen to Radio Moscow?",
+"Do you listen to Radio New Zealand Intl?",
+"Do you listen to Radio Peace Peoples Republic of Korea?",
+"Do you listen to VOA?",
+"Do you listen to click and clack on PBS?",
+"Do you listen to the BBC?",
+"Do you prefer metric units?",
+"Do you recycle often?",
+"Do you understand English?",
+"Do you watch Quantum Leap?",
+"Do you watch STTNG?",
+"Do you watch Simpsons?",
+"Gaverete Ruskie?",
+"Habla espanol?",
+"Has the war started yet?",
+"Have a nice T day.",
+"Have a nice thanksgiving.",
+"Have you been to Hawaii recently?",
+"Have you been to Kauai since Iniki?",
+"Have you ever been to New Madrid, Missouri?",
+"Have you ever been to the Chatham islands?",
+"Have you ever contacted Kalawao county, Molokai?",
+"Have you ever contacted Loving county, Texas?",
+"Have you ever played lemmings?",
+"Have you ever played tetris?",
+"Have you ever seen a computer virus?",
+"How copy so far?",
+"How copy?",
+"How did you learn morse code?",
+"How is my signal?",
+"How is the weather?",
+"How long have you been a radio amateur?",
+"How old is your rig?",
+"Hows my signal?",
+"Hows the weather?",
+"I am mobile and am going to the office.",
+"I am mobile and am going to work.",
+"I am mobile and driving to work.",
+"I am mobile, driving cross country.",
+"I am mobile, driving home from work.",
+"I am mobile, riding a Peruvian Paso Fino horse.",
+"I am mobile, riding a Peruvian Paso horse.",
+"I am mobile, stuck in traffic.",
+"I am using a linear amplifier.",
+"I am using an iambic key.",
+"I just saw a bolide.",
+"I live at 10 Downing.",
+"I live at 1010 Springwood.",
+"I live at 1620 Keeaumoku.",
+"I live at 2500 Pennsylvania.",
+"I live at 61C Escondido.",
+"I sometimes monitor ULF for earthquake precursors.",
+"I sometimes monitor ulf for earthquake precursors.",
+"I sometimes work packet on vhf.",
+"Is it green there or brown?",
+"Is the bad news true?",
+"Is your state the one that doesnt have any city governments?",
+"Is your state the one that has a unicameral legislature?",
+"Is your state the one that has boroughs instead of counties?",
+"Is your state the one that has parishes instead of counties?",
+"Is your state the one that has townships instead of counties?",
+"Ive fallen and I cant get up.",
+"Jocks find quartz glyph, vex BMW.",
+"Jocks find quartz glyph, vex BMW.",
+"Jocks find quartz glyph, vex BMW.",
+"Lots of QRM.",
+"Mele kelikimaka and hauoli makahiki hou 1995.",
+"Must QRT for Babylon V.",
+"Must QRT for Star Trek.",
+"Must QRT for bathroom break.",
+"Must QRT for breakfast.",
+"Must QRT for cold breakfast.",
+"Must QRT for cold dinner.",
+"Must QRT for cold supper.",
+"Must QRT for diarreah break.",
+"Must QRT for dinner.",
+"Must QRT for hot breakfast.",
+"Must QRT for hot dinner.",
+"Must QRT for hot lunch.",
+"Must QRT for hot supper.",
+"Must QRT for lunch.",
+"Must QRT for sleep.",
+"Must QRT for some sleep.",
+"Must QRT for supper.",
+"Must QRT invading tanks making too much noise outside to hear you.",
+"Must QRT occupation forces knocking at door.",
+"Must QRT to hear news about approaching hurricane.",
+"Must QRT wind has blown door open again.",
+"Must QRT, lightning storm has started.",
+"Must QRT, lightning threatens.",
+"Must QRT, nuclear attack?",
+"Must QRT, tornado sirens sounding.",
+"Must QRT, tsunami sirens sounding.",
+"Must QRT, weather radio warbling.",
+"Our neighbors have a horse named morse code.",
+"Our neighbors have a horse named morse.",
+"Please QRS.",
+"Propagation is good.",
+"Propagation is poor.",
+"Propagation is very good.",
+"Propagation is very poor.",
+"QLF?",
+"QRG",
+"QRH",
+"QRI 1",
+"QRI 2",
+"QRI 3",
+"QRI",
+"QRJ",
+"QRK 1",
+"QRK 2",
+"QRK 3",
+"QRK 4",
+"QRK 5",
+"QRK",
+"QRL",
+"QRM",
+"QRM?",
+"QRN 1",
+"QRN 2",
+"QRN 3",
+"QRN 4",
+"QRN 5",
+"QRN",
+"QRO",
+"QRP",
+"QRP?",
+"QRQ 10",
+"QRQ 15",
+"QRQ 20",
+"QRQ 5",
+"QRQ",
+"QRS 10",
+"QRS 15",
+"QRS 20",
+"QRS 5",
+"QRS",
+"QRS?",
+"QRU",
+"QRV",
+"QRW",
+"QRX 0300",
+"QRX 0500",
+"QRX 2000",
+"QRX 2300",
+"QRX",
+"QRX?",
+"QRY 1",
+"QRY 2",
+"QRY 3",
+"QRY",
+"QRZ",
+"QSA 1",
+"QSA 2",
+"QSA 3",
+"QSA 4",
+"QSA 5",
+"QSA",
+"QSB",
+"QSD",
+"QSG 1",
+"QSG 2",
+"QSG",
+"QSK",
+"QSK?",
+"QSL",
+"QSM",
+"QSN",
+"QSO",
+"QSP",
+"QST",
+"QSU",
+"QSW",
+"QSX",
+"QSY",
+"QSY?",
+"QSZ",
+"QTB",
+"QTC",
+"QTH?",
+"QTR",
+"QTR?",
+"Should we QSY?",
+"So how is the weather?",
+"Sorry, stack of books just fell over.",
+"Sprechen Sie Deutsch?",
+"Thanks for the call.",
+"There is a rainbow outside the window.",
+"There is an eclipse of the moon right now.",
+"Tnx for the call.",
+"Tnx for the report.",
+"Tnx for ur call.",
+"We are on vacation and I am mobile.",
+"We just felt a small quake here.",
+"What are your hobbies?",
+"What is the air pressure there?",
+"What is the air quality there?",
+"What is the air temperature there?",
+"What is the humidity there?",
+"What is your QTH?",
+"What is your elevation?",
+"What is your hobby?",
+"What is your job?",
+"What is your sign? I am a cancer.",
+"What is your sign? I am a centaur.",
+"What is your sign? I am a fish.",
+"What time zone are you in?",
+"Whats your job?",
+"When did you start to learn morse code?",
+"Where do you live now?",
+"Where do you live?",
+"Where is Hollister, California anyway?",
+"Where is Parkfield, California anyway?",
+"Whoa, we are having an earthquake here. A real roller.",
+"Would you have given Morse a Nobel prize?",
+"You are my first contact today.",
+"You are my last contact today.",
+"You are my second contact today.",
+"You are using a nonlinear amplifier?",
+"You are using an iambic key?",
+"Your contest sequence no is 1035.",
+"Your contest sequence no is 12.",
+"Your contest sequence no is 17.",
+"Your contest sequence no is 479.",
+"Your contest sequence no is 73.",
+"Your contest sequence no is 7v.",
+"Your contest sequence no is 826.",
+"Your contest sequence no is 99.",
+"Your job is?",
+"Your signal is chirpy.",
+"am using a linear amplifier.",
+"ewsqgbhjolpi oops cat on keyboard.",
+"ru using linear amplifier?",
--- /dev/null
+"Al",
+"Alan",
+"Alen",
+"Alex",
+"Alexander",
+"Alexandra",
+"Alexeev",
+"Alice",
+"Allen",
+"Alma",
+"Amber",
+"Angel",
+"Anne",
+"Art",
+"Barbara",
+"Barbie",
+"Bart",
+"Bea",
+"Betty",
+"Bill",
+"Bob",
+"Bruce",
+"Bryant",
+"Bud",
+"Carl",
+"Carol",
+"Cathy",
+"Cheryl",
+"Chris",
+"Christy",
+"Chuck",
+"Dale",
+"Dan",
+"Dave",
+"David",
+"Dennis",
+"Diane",
+"Dick",
+"Don",
+"Ed",
+"Edmund",
+"Edward",
+"Elaine",
+"Eleuterio",
+"Ellen",
+"Francie",
+"Frank",
+"Fred",
+"Gary",
+"George",
+"Gilda",
+"Gus",
+"Hadassah",
+"Harry",
+"Hedwig",
+"Heika",
+"Helen",
+"Helmut",
+"Henry",
+"Heriberto",
+"Ingrid",
+"Isaac",
+"Israel",
+"Jack",
+"Jacob",
+"Jake",
+"Jakob",
+"James",
+"Janae",
+"Jane",
+"Janet",
+"Jeff",
+"Jenni",
+"Jessica",
+"Jill",
+"Jim",
+"JimBob",
+"Joan",
+"Joe",
+"John",
+"Jon",
+"Kaahumanu",
+"Karen",
+"Karl",
+"Kathy",
+"Keith",
+"Ken",
+"Kent",
+"Kevin",
+"Kristen",
+"Kurt",
+"Larry",
+"Lauren",
+"Liholiho",
+"Linda",
+"Lou",
+"Lourdes",
+"Lynda",
+"Lynn",
+"Marc",
+"Margaret",
+"Maria",
+"Mariam",
+"Mark",
+"Marty",
+"Marv",
+"Mary",
+"Mike",
+"Monica",
+"Moses",
+"Mosha",
+"Nancy",
+"Nathan",
+"Neil",
+"Noelani",
+"Oliver",
+"Olivia",
+"Pal",
+"Pat",
+"Patrick",
+"Paul",
+"Paula",
+"Peter",
+"Peto",
+"Phil",
+"Pieter",
+"Quimby",
+"Rachel",
+"Ralph",
+"Ray",
+"Rebekkah",
+"Reiko",
+"Rex",
+"Reza",
+"Rich",
+"Rick",
+"Ron",
+"Roy",
+"Sally",
+"Sam",
+"Sara",
+"Sarah",
+"Scott",
+"Scottie",
+"Spencer",
+"Steve",
+"Stew",
+"Stu",
+"Sue",
+"Tello",
+"Terry",
+"Thomas",
+"Tim",
+"Timothy",
+"Todd",
+"Tom",
+"Tony",
+"Umberto",
+"Vicente",
+"Victor",
+"Wallace",
+"Wally",
+"Walt",
+"Walter",
+"Wendy",
+"William",
+"Xavier",
+"Yaohui",
+"Yolanda",
+"Zelda",
--- /dev/null
+"Albany",
+"Avalon",
+"Barnard",
+"Bedford",
+"Bethel",
+"Boston",
+"Brunswick",
+"Canaan",
+"Chester",
+"Conway",
+"Dime Box",
+"Franklin",
+"Granville",
+"Hamilton",
+"London",
+"Morris",
+"Oxford",
+"Salisbury",
+"Scarborough",
+"Stafford",
+"Stanton",
+"Trenton",
+"Troy",
+"Walpole",
+"Warren",
+"Weston",
+"Wilton",
+"Windsor",
+"Zulch",
--- /dev/null
+#include <stdio.h>
+
+void
+PutForm0 ()
+{
+ PutRST ();
+ PutName ();
+ PutLocation ();
+ PutMisc ();
+ PutRig ();
+ PutWeather ();
+ PutJob ();
+ PutAge ();
+ PutMisc ();
+ PutQ_And_Freq ();
+ PutLicense ();
+}
+
+void
+PutForm1 ()
+{
+ PutLocation ();
+ PutRST ();
+ PutRig ();
+ PutWeather ();
+ PutMisc ();
+ PutName ();
+ PutLicense ();
+ PutMisc ();
+ PutQ_And_Freq ();
+ PutAge ();
+ PutJob ();
+}
+
+void
+PutForm2 ()
+{
+ PutThanks ();
+ PutRST ();
+ PutName ();
+ PutWeather ();
+ PutLocation ();
+ PutJob ();
+ PutLicense ();
+ PutRig ();
+ PutAge ();
+ PutQ_And_Freq ();
+}
+
+void
+PutForm3 ()
+{
+ PutLocation ();
+ PutRST ();
+ PutRig ();
+ PutMisc ();
+ PutName ();
+ PutMisc ();
+ PutAge ();
+ PutJob ();
+ PutLicense ();
+ PutMisc ();
+ PutWeather ();
+ PutMisc ();
+ PutQ_And_Freq ();
+}
+
+void
+PutForm4 ()
+
+{
+ PutThanks ();
+ PutRST ();
+ PutJob ();
+ PutMisc ();
+ PutMisc ();
+ PutName ();
+ PutAge ();
+ PutLicense ();
+ PutRig ();
+ PutLocation ();
+ PutWeather ();
+ PutMisc ();
+}
+
+void
+PutForm5 ()
+{
+ PutLocation ();
+ PutRST ();
+ PutRig ();
+ PutName ();
+ PutJob ();
+ PutAge ();
+ PutMisc ();
+ PutLicense ();
+ PutWeather ();
+ PutMisc ();
+ PutQ_And_Freq ();
+}
+
+PutQSO ()
+{
+ /* printf("VVV VVV\n") ; */
+ PutFirstCallsign ();
+ switch (Roll (6))
+ {
+ case 0:
+ PutForm0 ();
+ break;
+ case 1:
+ PutForm1 ();
+ break;
+ case 2:
+ PutForm2 ();
+ break;
+ case 3:
+ PutForm3 ();
+ break;
+ case 4:
+ PutForm4 ();
+ break;
+ default:
+ PutForm5 ();
+ break;
+ }
+ printf ("+ %%\n");
+ PutLastCallsign ();
+ printf ("\n");
+}
--- /dev/null
+"Collins 75S=3",
+"Collins KWM=2",
+"Drake T=4XB",
+"Drake TR3",
+"Drake TR4",
+"Eico 753",
+"Hallicrafters SR150",
+"Hallicrafters SR160",
+"Hallicrafters SR2000",
+"Hallicrafters SR400",
+"Hallicrafters SR500",
+"Heathkit DX=660B",
+"Heathkit HG=10B",
+"Heathkit HR=10",
+"Heathkit HW100",
+"Heathkit HW12",
+"Heathkit HW12A",
+"Heathkit HW22",
+"Heathkit HW22A",
+"Heathkit HW32",
+"Heathkit HW32A",
+"Heathkit HW8",
+"Heathkit SB100",
+"Homebrew",
+"Icom IC=1275",
+"Icom IC=275",
+"Icom IC=475",
+"Icom IC=575",
+"Icom IC=725",
+"Icom IC=726",
+"Icom IC=730",
+"Icom IC=735",
+"Icom IC=751",
+"Icom IC=751A",
+"Icom IC=765",
+"Icom IC=781",
+"Kenwood TR=450",
+"Kenwood TR=751",
+"Kenwood TR=850",
+"Kenwood TR=851",
+"Kenwood TS=140",
+"Kenwood TS=440",
+"Kenwood TS=680",
+"Kenwood TS=711",
+"Kenwood TS=77",
+"Kenwood TS=850",
+"National NCL 200",
+"National NCX3",
+"National NCX5",
+"RS HTX=100",
+"Radio Shack HTX=100",
+"Swan 120",
+"Swan 140",
+"Swan 180",
+"Swan 240",
+"Swan 350",
+"Ten Tec 562",
+"Ten Tec 585",
+"Ten Tec Argonaut",
+"Ten Tec Delta",
+"Ten Tec Omni",
+"Yaesu FT=1000",
+"Yaesu FT=101",
+"Yaesu FT=736",
+"Yaesu FT=747",
+"Yaesu FT=757",
+"Yaesu FT=767",
+"Yaesu FT=840",
+"Yaesu FT=990",
--- /dev/null
+/*
+ ********************
+ * Utility routines *
+ ********************
+ */
+extern int their_age;
+
+int
+CountStrings (StringVector)
+ char *StringVector[];
+ /*
+ * Count the number of string values in the supplied vector
+ * of pointers. Start with the first pointer and stop when
+ * NIL (0) is encountered.
+ */
+{
+register char **SV;
+register int Count;
+
+ Count = 0;
+
+ for (SV = StringVector; *SV; SV++)
+ {
+ Count++;
+ }
+ return (Count);
+}
+
+int
+Roll (Number)
+ int Number;
+{
+int new_tmp;
+double tmp_val;
+double drand48 ();
+ tmp_val = ((int) (drand48 () * (Number /*-1*/ )));
+ new_tmp = (int) tmp_val % 32767;
+ if (new_tmp < 2)
+ tmp_val = 2;
+ return ((int) new_tmp);
+}
+
+int
+License_Seed ()
+{
+ if (their_age > 20)
+ return (20);
+ if (their_age < 10)
+ return (10);
+ return (their_age - 8);
+}
+
+char *
+Choose (Words, Number)
+ char *Words[];
+ int Number;
+{
+ return (Words[Roll (Number)]);
+}
--- /dev/null
+"a blue norther",
+"a noreaster",
+"a siberia express",
+"chinook winds",
+"cloudy",
+"cold and windy",
+"cold/dry",
+"cool/windy",
+"damp",
+"drizzling",
+"fog/drizzle",
+"foggy",
+"gale force winds",
+"gentle rain",
+"gusting trade winds",
+"hailing",
+"horizontal rain",
+"hot and humid",
+"hot and windy",
+"hot",
+"hot/dry",
+"hot/humid",
+"hot/muggy",
+"hot/smoggy",
+"humid",
+"kona winds",
+"pleasantly cool",
+"pleasantly warm",
+"raining cats and dogs",
+"raining",
+"santa anna winds",
+"sleeting",
+"smoggy",
+"snowing",
+"spitting rain",
+"sunny",
+"tornadic winds",
+"trade winds",
+"uncomfortably hot",
+"very cold",
+"very hot",
+"very windy",
+"warm",
+"wet",
+"wet/foggy",
+"wet/windy",
+"windy and warm",
+"windy",
--- /dev/null
+Jocks find quartz glyph, vex BMW.
+
+testing, testing, 1 2 3 \a different tone now. \a Back again.
+
+VVV VVV