Pull morse(6) into the new millenium and teach it to use sound(4).
authorSimon Schubert <corecode@dragonflybsd.org>
Sun, 22 Apr 2007 10:22:32 +0000 (10:22 +0000)
committerSimon Schubert <corecode@dragonflybsd.org>
Sun, 22 Apr 2007 10:22:32 +0000 (10:22 +0000)
Feedback-by: swildner@
games/morse/Makefile
games/morse/morse.6
games/morse/morse.c

index 9a6ad06..148e2e4 100644 (file)
@@ -1,12 +1,10 @@
 #      @(#)Makefile    8.1 (Berkeley) 5/31/93
 # $FreeBSD: src/games/morse/Makefile,v 1.4.6.5 2001/04/25 09:28:58 ru Exp $
-# $DragonFly: src/games/morse/Makefile,v 1.4 2006/10/08 16:22:36 pavalos Exp $
+# $DragonFly: src/games/morse/Makefile,v 1.5 2007/04/22 10:22:32 corecode Exp $
 
 PROG=  morse
 MAN=   morse.6
-
-.if ${MACHINE_ARCH} == "i386"
-CFLAGS += -DSPEAKER=\"/dev/speaker\"
-.endif
+LDADD= -lm
+DPADD= ${LIBM}
 
 .include <bsd.prog.mk>
index ed4e195..698b9f3 100644 (file)
@@ -32,9 +32,9 @@
 .\"
 .\"    @(#)bcd.6       8.1 (Berkeley) 5/31/93
 .\" $FreeBSD: src/games/morse/morse.6,v 1.4.2.7 2003/01/26 02:57:27 keramida Exp $
-.\" $DragonFly: src/games/morse/morse.6,v 1.3 2006/02/17 19:33:31 swildner Exp $
+.\" $DragonFly: src/games/morse/morse.6,v 1.4 2007/04/22 10:22:32 corecode Exp $
 .\"
-.Dd December 7, 2000
+.Dd April 22, 2007
 .Dt MORSE 6
 .Os
 .Sh NAME
@@ -43,6 +43,7 @@
 .Sh SYNOPSIS
 .Nm
 .Op Fl p
+.Op Fl P Ar dspdevice
 .Op Fl d Ar device
 .Op Fl e
 .Op Fl w Ar speed
@@ -63,8 +64,11 @@ The
 option produces dots and dashes rather than words.
 .It Fl p
 Send morse the real way. This only works if your system has
-.Xr speaker 4
+.Xr sound 4
 support.
+.It Fl P Ar dspdevice
+Select a different dsp device from the default
+.Pa /dev/dsp .
 .It Fl w Ar speed
 Set the sending speed in words per minute. If not specified the default
 speed of 20 WPM is used.
@@ -148,18 +152,17 @@ they are interpreted
 as belonging to the
 .Ql ISO-8859-1
 character set.
-.Sh FILES
-.Bl -tag -width /dev/speaker -compact
-.It Pa /dev/speaker
-speaker device file
-.El
 .Sh SEE ALSO
-.Xr speaker 4
+.Xr sound 4
 .Sh HISTORY
 Sound support for
 .Nm
 added by
-.An Lyndon Nerenberg (VE7TCP/VE6BBM) Aq lyndon@orthanc.com .
+.An Lyndon Nerenberg (VE7TCP/VE6BBM) Aq lyndon@orthanc.com
+and later converted to use
+.Xr sound
+by
+.An Simon 'corecode' Schubert Aq corecode@fs.ei.tum.de .
 .Pp
 Ability to key an external device added by
 .An J\(:org Wunsch
index 07a82d9..a0fa476 100644 (file)
@@ -33,7 +33,7 @@
  * @(#) Copyright (c) 1988, 1993 The Regents of the University of California.  All rights reserved.
  * @(#)morse.c 8.1 (Berkeley) 5/31/93
  * $FreeBSD: src/games/morse/morse.c,v 1.12.2.2 2002/03/12 17:45:15 phantom Exp $
- * $DragonFly: src/games/morse/morse.c,v 1.3 2005/04/25 16:10:24 liamfoy Exp $
+ * $DragonFly: src/games/morse/morse.c,v 1.4 2007/04/22 10:22:32 corecode Exp $
  */
 
 /*
  */
 
 #include <sys/time.h>
+#include <sys/soundcard.h>
 
 #include <ctype.h>
+#include <err.h>
 #include <fcntl.h>
 #include <langinfo.h>
 #include <locale.h>
+#include <math.h>
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <termios.h>
 #include <unistd.h>
 
-#ifdef SPEAKER
-#include <machine/speaker.h>
-#endif
-
 struct morsetab {
        char            inchar;
        const char      *morse;
@@ -189,13 +188,19 @@ static const struct morsetab koi8rtab[] = {
        {'\0', ""}
 };
 
+struct tone_data {
+       int16_t *data;
+       size_t  len;
+};
+
+void           alloc_soundbuf(struct tone_data *, double, int);
 void            show(const char *), play(const char *), morse(char);
 void           ttyout(const char *);
 void           sighandler(int);
 
-#define GETOPTOPTS "d:ef:sw:"
+#define GETOPTOPTS "d:ef:pP:sw:"
 #define USAGE \
-"usage: morse [-s] [-e] [-d device] [-w speed] [-f frequency] [string ...]\n"
+"usage: morse [-s] [-e] [-p] [-P device] [-d device] [-w speed] [-f frequency] [string ...]\n"
 
 static int      pflag, sflag, eflag;
 static int      wpm = 20;      /* words per minute */
@@ -203,23 +208,18 @@ static int      wpm = 20; /* words per minute */
 static int      freq = FREQUENCY;
 static char    *device;        /* for tty-controlled generator */
 
+static struct tone_data tone_dot, tone_dash, tone_silence;
+#define DSP_RATE 44100
+static const char *snddev = "/dev/dsp";
+
 #define DASH_LEN 3
 #define CHAR_SPACE 3
-#define WORD_SPACE (7 - CHAR_SPACE - 1)
+#define WORD_SPACE (7 - CHAR_SPACE)
 static float    dot_clock;
 int             spkr, line;
 struct termios otty, ntty;
 int            olflags;
 
-#ifdef SPEAKER
-tone_t          sound;
-#undef GETOPTOPTS
-#define GETOPTOPTS "d:ef:psw:"
-#undef USAGE
-#define USAGE \
-"usage: morse [-s] [-p] [-e] [-d device] [-w speed] [-f frequency] [string ...]\n"
-#endif
-
 static const struct morsetab *hightab;
 
 int
@@ -240,11 +240,12 @@ main(int argc, char **argv)
                case 'f':
                        freq = atoi(optarg);
                        break;
-#ifdef SPEAKER
                case 'p':
                        pflag = 1;
                        break;
-#endif
+               case 'P':
+                       snddev = optarg;
+                       break;
                case 's':
                        sflag = 1;
                        break;
@@ -266,15 +267,28 @@ main(int argc, char **argv)
        }
        if ((pflag || device) && (freq == 0))
                freq = FREQUENCY;
+       if (pflag || device) {
+               dot_clock = wpm / 2.4;          /* dots/sec */
+               dot_clock = 1 / dot_clock;      /* duration of a dot */
+               dot_clock = dot_clock / 2;      /* dot_clock runs at twice */
+                                               /* the dot rate */
+       }
 
-#ifdef SPEAKER
        if (pflag) {
-               if ((spkr = open(SPEAKER, O_WRONLY, 0)) == -1) {
-                       perror(SPEAKER);
-                       exit(1);
-               }
+               snd_chan_param param;
+
+               if ((spkr = open(snddev, O_WRONLY, 0)) == -1)
+                       err(1, "%s", snddev);
+               param.play_rate = DSP_RATE;
+               param.play_format = AFMT_S16_NE;
+               param.rec_rate = 0;
+               param.rec_format = 0;
+               if (ioctl(spkr, AIOSFMT, &param) != 0)
+                       err(1, "%s: set format", snddev);
+               alloc_soundbuf(&tone_dot, dot_clock, 1);
+               alloc_soundbuf(&tone_dash, DASH_LEN * dot_clock, 1);
+               alloc_soundbuf(&tone_silence, dot_clock, 0);
        } else
-#endif
        if (device) {
                if ((line = open(device, O_WRONLY | O_NONBLOCK)) == -1) {
                        perror("open tty line");
@@ -299,13 +313,6 @@ main(int argc, char **argv)
                (void)signal(SIGQUIT, sighandler);
                (void)signal(SIGTERM, sighandler);
        }
-       if (pflag || device) {
-               dot_clock = wpm / 2.4;          /* dots/sec */
-               dot_clock = 1 / dot_clock;      /* duration of a dot */
-               dot_clock = dot_clock / 2;      /* dot_clock runs at twice */
-                                               /* the dot rate */
-               dot_clock = dot_clock * 100;    /* scale for ioctl */
-       }
 
        argc -= optind;
        argv += optind;
@@ -343,6 +350,56 @@ main(int argc, char **argv)
 }
 
 void
+alloc_soundbuf(struct tone_data *tone, double len, int on)
+{
+       int samples, i;
+
+       samples = DSP_RATE * len;
+       tone->len = samples * sizeof(*tone->data);
+       tone->data = malloc(tone->len);
+       if (tone->data == NULL)
+               err(1, NULL);
+       if (!on) {
+               bzero(tone->data, tone->len);
+               return;
+       }
+
+       /*
+        * We create a sinus with the specified frequency and smooth
+        * the edges to reduce key clicks.
+        */
+       for (i = 0; i < samples; i++) {
+               double filter = 1;
+
+#define FILTER_SAMPLES 100
+               if (i < FILTER_SAMPLES || i > samples - FILTER_SAMPLES) {
+                       /*
+                        * Gauss window
+                        */
+#if 0
+                       int fi = i;
+
+                       if (i > FILTER_SAMPLES)
+                               fi = samples - i;
+                       filter = exp(-0.5 *
+                                    pow((double)(fi - FILTER_SAMPLES) /
+                                        (0.4 * FILTER_SAMPLES), 2));
+#else
+                       /*
+                        * Triangle window
+                        */
+                       if (i < FILTER_SAMPLES)
+                               filter = (double)i / FILTER_SAMPLES;
+                       else
+                               filter = (double)(samples - i) / FILTER_SAMPLES;
+#endif
+               }
+               tone->data[i] = 32767 * sin((double)i / samples * len * freq * 2 * M_PI) *
+                   filter;
+       }
+}
+
+void
 morse(char c)
 {
        const struct morsetab *m;
@@ -391,43 +448,37 @@ show(const char *s)
 void
 play(const char *s)
 {
-#ifdef SPEAKER
        const char *c;
+       int duration;
+       struct tone_data *tone;
 
+       /*
+        * We don't need to usleep() here, as the sound device blocks.
+        */
        for (c = s; *c != '\0'; c++) {
                switch (*c) {
                case '.':
-                       sound.frequency = freq;
-                       sound.duration = dot_clock;
+                       duration = 1;
+                       tone = &tone_dot;
                        break;
                case '-':
-                       sound.frequency = freq;
-                       sound.duration = dot_clock * DASH_LEN;
+                       duration = 1;
+                       tone = &tone_dash;
                        break;
                case ' ':
-                       sound.frequency = 0;
-                       sound.duration = dot_clock * WORD_SPACE;
+                       duration = WORD_SPACE;
+                       tone = &tone_silence;
                        break;
                default:
-                       sound.duration = 0;
-               }
-               if (sound.duration) {
-                       if (ioctl(spkr, SPKRTONE, &sound) == -1) {
-                               perror("ioctl play");
-                               exit(1);
-                       }
-               }
-               sound.frequency = 0;
-               sound.duration = dot_clock;
-               if (ioctl(spkr, SPKRTONE, &sound) == -1) {
-                       perror("ioctl rest");
-                       exit(1);
+                       errx(1, "invalid morse digit");
                }
+               while (duration-- > 0)
+                       write(spkr, tone->data, tone->len);
+               write(spkr, tone_silence.data, tone_silence.len);
        }
-       sound.frequency = 0;
-       sound.duration = dot_clock * CHAR_SPACE;
-       ioctl(spkr, SPKRTONE, &sound);
-#endif
+       duration = CHAR_SPACE - 1;  /* we already waited 1 after the last symbol */
+       while (duration-- > 0)
+               write(spkr, tone_silence.data, tone_silence.len);
 }
 
 void
@@ -459,16 +510,16 @@ ttyout(const char *s)
                        lflags |= TIOCM_RTS;
                        ioctl(line, TIOCMSET, &lflags);
                }
-               duration *= 10000;
+               duration *= 1000000;
                if (duration)
                        usleep(duration);
                ioctl(line, TIOCMGET, &lflags);
                lflags &= ~TIOCM_RTS;
                ioctl(line, TIOCMSET, &lflags);
-               duration = dot_clock * 10000;
+               duration = dot_clock * 1000000;
                usleep(duration);
        }
-       duration = dot_clock * CHAR_SPACE * 10000;
+       duration = dot_clock * CHAR_SPACE * 1000000;
        usleep(duration);
 }