From e58ef91693dac5b3fc6228b37446873747f3126b Mon Sep 17 00:00:00 2001 From: "Eric S. Raymond" Date: Mon, 24 Jan 2005 14:32:01 +0000 Subject: [PATCH 1/1] Initial import --- Makefile | 142 ++++ README | 100 +++ alarm.c | 105 +++ alarm.h | 20 + beep.h | 59 ++ beepAdLib.c | 168 ++++ beepHP.c | 177 +++++ beepIndigo.c | 248 ++++++ beepLinux.c | 82 ++ beepOSS.c | 207 +++++ beepSun.c | 200 +++++ beepX11.c | 81 ++ morse.c | 2073 ++++++++++++++++++++++++++++++++++++++++++++++++ qso/Makefile | 20 + qso/QSO.c | 742 +++++++++++++++++ qso/antenna.h | 33 + qso/callsign.h | 108 +++ qso/city.h | 179 +++++ qso/cityh.h | 46 ++ qso/grammar.c | 32 + qso/heights.h | 37 + qso/init_str.c | 266 +++++++ qso/jobs.h | 71 ++ qso/make_fre.c | 28 + qso/misc.h | 293 +++++++ qso/names.h | 170 ++++ qso/newcity.h | 29 + qso/put_form.c | 130 +++ qso/rig.h | 69 ++ qso/util.c | 59 ++ qso/weather.h | 48 ++ test_input | 5 + 32 files changed, 6027 insertions(+) create mode 100644 Makefile create mode 100644 README create mode 100644 alarm.c create mode 100644 alarm.h create mode 100644 beep.h create mode 100644 beepAdLib.c create mode 100644 beepHP.c create mode 100644 beepIndigo.c create mode 100644 beepLinux.c create mode 100644 beepOSS.c create mode 100644 beepSun.c create mode 100644 beepX11.c create mode 100644 morse.c create mode 100644 qso/Makefile create mode 100644 qso/QSO.c create mode 100644 qso/antenna.h create mode 100644 qso/callsign.h create mode 100644 qso/city.h create mode 100644 qso/cityh.h create mode 100644 qso/grammar.c create mode 100644 qso/heights.h create mode 100644 qso/init_str.c create mode 100644 qso/jobs.h create mode 100644 qso/make_fre.c create mode 100644 qso/misc.h create mode 100644 qso/names.h create mode 100644 qso/newcity.h create mode 100644 qso/put_form.c create mode 100644 qso/rig.h create mode 100644 qso/util.c create mode 100644 qso/weather.h create mode 100644 test_input diff --git a/Makefile b/Makefile new file mode 100644 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 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 + + "+" over, end of message + "*" please stand by ( 5 Wait 5 Minutes) (".-...") + "=" (double dash) pause, break for text +CL going off the air (clear) +CQ calling any station +K go, invite any station to transmit + "(" go only, invite a specific station to transmit +R all received OK + "%" end of contact (sent before call) ("...-.-", known also as ) + +The following Procedural Signals (Prosigns) are included if one +defines ALLPROSIGNS : + + "^" new line (".-.-", the same as :a, ae) + "#" invite receiving station to transmit ("-...-.-") + "&" attention ("-.-.-") + "@" understood ("...-.") + +The following characters are included if one defines ALLINTERNATIONAL : + + :a .-.- (also for ae, the same as ) + `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 index 0000000..16a9ad2 --- /dev/null +++ b/alarm.c @@ -0,0 +1,105 @@ +/* alarm.c -- seligman 6/92 */ + +/* +-- Implementation of alarm.h +*/ + +#include +#include +#include + +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 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 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 index 0000000..57f4b17 --- /dev/null +++ b/beepAdLib.c @@ -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 +#include +#include +#include +#include + +#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 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 +#include +#include +#include +#include +#include +#include + + +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 index 0000000..59869ee --- /dev/null +++ b/beepIndigo.c @@ -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 +#include + +#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 index 0000000..add29bb --- /dev/null +++ b/beepLinux.c @@ -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 + * + */ + +/* beepLinux.c -- 11/94 */ + +#include +#include +#include +#include +#include +#include +#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 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 +#include +#include +#include +#include +#include + +#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 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 +#include +#include +#include +#include +#include + + +#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 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 +#include +#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 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 +#include +#include +#include +#include +#include +#include +#include +#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 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) '+'] = ".-.-."; /* end of message */ + code[(int) '*'] = ".-..."; /* wait, stand-by */ + code[(int) '='] = "-...-"; /* (double dash) pause, break for text */ + code[(int) '('] = "-.--."; /* over-specified station only */ + code[(int) '%'] = "...-.-"; /* end of contact, known also as */ + +#ifdef ALLPROSIGNS + /* Not so commonly used procedure signs ("prosigns") */ + code[(int) '^'] = ".-.-"; /* new line, the same as :a, ae */ + code[(int) '#'] = "-...-.-";/* invite receiving station to transmit */ + code[(int) '&'] = "-.-.-"; /* attention */ + code[(int) '@'] = "...-."; /* 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 */ + 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 (""); + } else { + printf ("%%"); + } + } + else if (c == '.' && showmorse) + printf (""); + else if (c == '-' && showmorse) + printf (""); + else if (c == '+' && showmorse) + printf (""); + else if (c == '*' && showmorse) + printf (""); + else if (c == '=' && showmorse) + printf (""); + else if (c == '(' && showmorse) + printf (""); + else if (c == '%' && showmorse) + printf (""); +#ifdef ALLPROSIGNS + else if (c == '^' && (code[(int) '^'] != NULL) && showmorse) + printf (""); + else if (c == '#' && showmorse) + printf (""); + else if (c == '&' && showmorse) + printf (""); + else if (c == '@' && showmorse) + printf (""); +#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 (""); + 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 +#include +#ifdef USG +#include +struct termio oldtermgtty; +struct termio termgtty; +#else +#include +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 index 0000000..fe85ef8 --- /dev/null +++ b/qso/Makefile @@ -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 index 0000000..64d1c20 --- /dev/null +++ b/qso/QSO.c @@ -0,0 +1,742 @@ +/* + * Return-Path: + * 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 +/* +#include + */ +#include + +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 index 0000000..1452605 --- /dev/null +++ b/qso/antenna.h @@ -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 index 0000000..ed69af0 --- /dev/null +++ b/qso/callsign.h @@ -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 index 0000000..b3c74b9 --- /dev/null +++ b/qso/city.h @@ -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 index 0000000..fa1979b --- /dev/null +++ b/qso/cityh.h @@ -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 index 0000000..173309d --- /dev/null +++ b/qso/grammar.c @@ -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 index 0000000..5b7788c --- /dev/null +++ b/qso/heights.h @@ -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 index 0000000..ae69660 --- /dev/null +++ b/qso/init_str.c @@ -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 index 0000000..6605174 --- /dev/null +++ b/qso/jobs.h @@ -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 index 0000000..baa9c93 --- /dev/null +++ b/qso/make_fre.c @@ -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 index 0000000..e10b2ce --- /dev/null +++ b/qso/misc.h @@ -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 index 0000000..125a1c3 --- /dev/null +++ b/qso/names.h @@ -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 index 0000000..b2c6634 --- /dev/null +++ b/qso/newcity.h @@ -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 index 0000000..30faa4d --- /dev/null +++ b/qso/put_form.c @@ -0,0 +1,130 @@ +#include + +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 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 index 0000000..5b70b62 --- /dev/null +++ b/qso/util.c @@ -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 index 0000000..757e798 --- /dev/null +++ b/qso/weather.h @@ -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 index 0000000..61ad59e --- /dev/null +++ b/test_input @@ -0,0 +1,5 @@ +Jocks find quartz glyph, vex BMW. + +testing, testing, 1 2 3  different tone now.  Back again. + +VVV VVV -- 2.43.0