]> thyrsus.com Git - morse-classic.git/commitdiff
Initial import
authorEric S. Raymond <esr@thyrsus.com>
Mon, 24 Jan 2005 14:32:01 +0000 (14:32 +0000)
committerEric S. Raymond <esr@thyrsus.com>
Mon, 24 Jan 2005 14:32:01 +0000 (14:32 +0000)
32 files changed:
Makefile [new file with mode: 0644]
README [new file with mode: 0644]
alarm.c [new file with mode: 0644]
alarm.h [new file with mode: 0644]
beep.h [new file with mode: 0644]
beepAdLib.c [new file with mode: 0644]
beepHP.c [new file with mode: 0644]
beepIndigo.c [new file with mode: 0644]
beepLinux.c [new file with mode: 0644]
beepOSS.c [new file with mode: 0644]
beepSun.c [new file with mode: 0644]
beepX11.c [new file with mode: 0644]
morse.c [new file with mode: 0644]
qso/Makefile [new file with mode: 0644]
qso/QSO.c [new file with mode: 0644]
qso/antenna.h [new file with mode: 0644]
qso/callsign.h [new file with mode: 0644]
qso/city.h [new file with mode: 0644]
qso/cityh.h [new file with mode: 0644]
qso/grammar.c [new file with mode: 0644]
qso/heights.h [new file with mode: 0644]
qso/init_str.c [new file with mode: 0644]
qso/jobs.h [new file with mode: 0644]
qso/make_fre.c [new file with mode: 0644]
qso/misc.h [new file with mode: 0644]
qso/names.h [new file with mode: 0644]
qso/newcity.h [new file with mode: 0644]
qso/put_form.c [new file with mode: 0644]
qso/rig.h [new file with mode: 0644]
qso/util.c [new file with mode: 0644]
qso/weather.h [new file with mode: 0644]
test_input [new file with mode: 0644]

diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..10f8603
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,142 @@
+# 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
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..fc3f1e2
--- /dev/null
+++ b/README
@@ -0,0 +1,100 @@
+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
+
diff --git a/alarm.c b/alarm.c
new file mode 100644 (file)
index 0000000..16a9ad2
--- /dev/null
+++ b/alarm.c
@@ -0,0 +1,105 @@
+/* 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
diff --git a/alarm.h b/alarm.h
new file mode 100644 (file)
index 0000000..13aec54
--- /dev/null
+++ b/alarm.h
@@ -0,0 +1,20 @@
+/* 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();
diff --git a/beep.h b/beep.h
new file mode 100644 (file)
index 0000000..2de914e
--- /dev/null
+++ b/beep.h
@@ -0,0 +1,59 @@
+/* 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
diff --git a/beepAdLib.c b/beepAdLib.c
new file mode 100644 (file)
index 0000000..57f4b17
--- /dev/null
@@ -0,0 +1,168 @@
+/* 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;
+}
diff --git a/beepHP.c b/beepHP.c
new file mode 100644 (file)
index 0000000..4e9607c
--- /dev/null
+++ b/beepHP.c
@@ -0,0 +1,177 @@
+/* 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;
+}
diff --git a/beepIndigo.c b/beepIndigo.c
new file mode 100644 (file)
index 0000000..59869ee
--- /dev/null
@@ -0,0 +1,248 @@
+/* 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();
+}
diff --git a/beepLinux.c b/beepLinux.c
new file mode 100644 (file)
index 0000000..add29bb
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * 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
+ * ---------------------------------------------------------------------------
+ */
diff --git a/beepOSS.c b/beepOSS.c
new file mode 100644 (file)
index 0000000..6573539
--- /dev/null
+++ b/beepOSS.c
@@ -0,0 +1,207 @@
+/* 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;
+}
diff --git a/beepSun.c b/beepSun.c
new file mode 100644 (file)
index 0000000..a6340eb
--- /dev/null
+++ b/beepSun.c
@@ -0,0 +1,200 @@
+/*
+ * 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;
+}
diff --git a/beepX11.c b/beepX11.c
new file mode 100644 (file)
index 0000000..dc9c444
--- /dev/null
+++ b/beepX11.c
@@ -0,0 +1,81 @@
+/* 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;
+}
diff --git a/morse.c b/morse.c
new file mode 100644 (file)
index 0000000..b5ad376
--- /dev/null
+++ b/morse.c
@@ -0,0 +1,2073 @@
+/*
+ * 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;
+}
diff --git a/qso/Makefile b/qso/Makefile
new file mode 100644 (file)
index 0000000..fe85ef8
--- /dev/null
@@ -0,0 +1,20 @@
+# 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
diff --git a/qso/QSO.c b/qso/QSO.c
new file mode 100644 (file)
index 0000000..64d1c20
--- /dev/null
+++ b/qso/QSO.c
@@ -0,0 +1,742 @@
+/*
+ * 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;
+}
diff --git a/qso/antenna.h b/qso/antenna.h
new file mode 100644 (file)
index 0000000..1452605
--- /dev/null
@@ -0,0 +1,33 @@
+"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",
diff --git a/qso/callsign.h b/qso/callsign.h
new file mode 100644 (file)
index 0000000..ed69af0
--- /dev/null
@@ -0,0 +1,108 @@
+"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",
diff --git a/qso/city.h b/qso/city.h
new file mode 100644 (file)
index 0000000..b3c74b9
--- /dev/null
@@ -0,0 +1,179 @@
+"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",
diff --git a/qso/cityh.h b/qso/cityh.h
new file mode 100644 (file)
index 0000000..fa1979b
--- /dev/null
@@ -0,0 +1,46 @@
+"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",
diff --git a/qso/grammar.c b/qso/grammar.c
new file mode 100644 (file)
index 0000000..173309d
--- /dev/null
@@ -0,0 +1,32 @@
+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);
+}
diff --git a/qso/heights.h b/qso/heights.h
new file mode 100644 (file)
index 0000000..5b7788c
--- /dev/null
@@ -0,0 +1,37 @@
+"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",
diff --git a/qso/init_str.c b/qso/init_str.c
new file mode 100644 (file)
index 0000000..ae69660
--- /dev/null
@@ -0,0 +1,266 @@
+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
+};
diff --git a/qso/jobs.h b/qso/jobs.h
new file mode 100644 (file)
index 0000000..6605174
--- /dev/null
@@ -0,0 +1,71 @@
+"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",
diff --git a/qso/make_fre.c b/qso/make_fre.c
new file mode 100644 (file)
index 0000000..baa9c93
--- /dev/null
@@ -0,0 +1,28 @@
+#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;
+      }
+}
diff --git a/qso/misc.h b/qso/misc.h
new file mode 100644 (file)
index 0000000..e10b2ce
--- /dev/null
@@ -0,0 +1,293 @@
+"+%=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?",
diff --git a/qso/names.h b/qso/names.h
new file mode 100644 (file)
index 0000000..125a1c3
--- /dev/null
@@ -0,0 +1,170 @@
+"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",
diff --git a/qso/newcity.h b/qso/newcity.h
new file mode 100644 (file)
index 0000000..b2c6634
--- /dev/null
@@ -0,0 +1,29 @@
+"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",
diff --git a/qso/put_form.c b/qso/put_form.c
new file mode 100644 (file)
index 0000000..30faa4d
--- /dev/null
@@ -0,0 +1,130 @@
+#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");
+}
diff --git a/qso/rig.h b/qso/rig.h
new file mode 100644 (file)
index 0000000..29646d6
--- /dev/null
+++ b/qso/rig.h
@@ -0,0 +1,69 @@
+"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",
diff --git a/qso/util.c b/qso/util.c
new file mode 100644 (file)
index 0000000..5b70b62
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ ********************
+ * 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)]);
+}
diff --git a/qso/weather.h b/qso/weather.h
new file mode 100644 (file)
index 0000000..757e798
--- /dev/null
@@ -0,0 +1,48 @@
+"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",
diff --git a/test_input b/test_input
new file mode 100644 (file)
index 0000000..61ad59e
--- /dev/null
@@ -0,0 +1,5 @@
+Jocks find quartz glyph, vex BMW.
+
+testing, testing, 1 2 3 \a different tone now. \a Back again.
+
+VVV VVV