This patch modifies the AFSK modulator in version 0.16 of the soundmodem
application as it appears to be problematic, in particular at 300 baud
(in general, it might be buggy for bitrates slower than 1200 baud,
although proper testing has not been carried out at other bitrates).

In other words, this patch should fix the AFSK modulator for the problem
reported, for example, here:

- http://he.fi/archive/linux-hams/200608/0005.html
- http://marc.info/?l=linux-hams&m=129059468102018&w=2

This patch also introduces optional windowing functions (other than the
Hamming one) for experimentation, but at the moment they are completely
untested and they can only be selected during compilation. Finally, this
patch introduces tone filters at the receiver.

After applying this patch, the AFSK modulator should work normally at 300
baud (or in general at bitrates less than 1200 baud) and the user should
be able to select any value for the AFSK tone frequencies. Similar fixes
are also introduced by this patch for the AFSK demodulator although, for
successful reception at 300 baud, longer RX filters might be needed.

Signed-off-by: Guido Trentalancia <iz6rdb@trentalancia.com>
---
 afsk/modem.c |  284 +++++++++++++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 201 insertions(+), 83 deletions(-)

--- soundmodem-0.16-orig/afsk/modem.c	2004-04-13 17:44:40.000000000 +0200
+++ soundmodem-0.16/afsk/modem.c	2016-02-05 15:41:36.282279870 +0100
@@ -6,6 +6,9 @@
  *      Copyright (C) 1998-2000, 2003
  *        Thomas Sailer <t.sailer@alumni.ethz.ch>
  *
+ *      Copyright (C) 2012, 2016
+ *        Guido Trentalancia <iz6rdb@trentalancia.com>
+ *
  *      This program is free software; you can redistribute it and/or modify
  *      it under the terms of the GNU General Public License as published by
  *      the Free Software Foundation; either version 2 of the License, or
@@ -32,11 +35,85 @@
 #include "modem.h"
 #include "costab.h"
 
+#define max(a, b) (((a) > (b)) ? (a) : (b))
+
+/* Rx FIR Filter parameters */
+
+/*
+ * Rx FIR Filter length is normally equal
+ * to 16. Longer filters require more CPU.
+ */
+#define RXFILTLEN       16
+
+#define RXFILTOVERBITS	3
+
+#define RXFILTOVER      (1<<(RXFILTOVERBITS))
+#define RXFILTFIDX(x)   (((x)>>(16-(RXFILTOVERBITS)))&(RXFILTOVER-1))
+#define RXFILTFSAMP(x)  ((x)>>16)
+
 /* --------------------------------------------------------------------- */
 
+/*
+ * IZ6RDB 10/01/2016
+ * Force the use of a minimum value for the sampling
+ * rate, because otherwise some sound cards might 
+ * not work properly, when using the old OSS (i.e.
+ * "soundcard") driver and bitrates slower than 1200
+ * baud (such as 300 baud for HF).
+ *
+ * The Alsa driver does not suffer this limitation
+ * and should be preferred.
+ *
+ * Higher values require more CPU time.
+ *
+ * The recommended minimum value is 11025 Hz for most
+ * sound cards.
+ */
+#define MINIMUM_SAMPLERATE	11025
+
+/*
+ * IZ6RDB 01/03/2012: define different possible
+ * window types for the FIR filters and choose
+ * one of the available types:
+ * - NONE (minimum transition width)
+ * - HAMMING (window used up to version 0.16)
+ * - HANNING (low transition width)
+ * - BLACKMAN (maximum stopband attenuation)
+ */
+#define	NONE		0
+#define	HAMMING		1
+#define	HANNING		2
+#define	BLACKMAN	3
+
+#define	FIR_WINDOW	HAMMING
+
+/* --------------------------------------------------------------------- */
+
+#ifdef FIR_WINDOW
+#if (FIR_WINDOW == NONE)
+#define WINDOW_FUNCTION(x)	no_window(x)
+#define TRANSITION_WIDTH_CONST	0.92
+#elif (FIR_WINDOW == HAMMING)
+#define WINDOW_FUNCTION(x)	hamming_window(x)
+#define TRANSITION_WIDTH_CONST	3.32
+#elif (FIR_WINDOW == HANNING)
+#define WINDOW_FUNCTION(x)	hanning_window(x)
+#define TRANSITION_WIDTH_CONST	3.11
+#elif (FIR_WINDOW == BLACKMAN)
+#define WINDOW_FUNCTION(x)	blackman_window(x)
+#define TRANSITION_WIDTH_CONST	5.565
+#else
+#error "A valid FIR Window must be selected !"
+#endif
+#else // default to Hamming window
+#define WINDOW_FUNCTION(x)	hamming_window(x)
+#define TRANSITION_WIDTH_CONST	3.32
+#endif
+
 struct modstate {
 	struct modemchannel *chan;
-	unsigned int bps, f0, f1, notdiff, maxbitlen;
+	unsigned int samplerate;
+	unsigned int bps, f0, f1, notdiff;
 	unsigned int bitinc, bitph;
 	unsigned int dds, ddsinc[2];
 	unsigned int bit;
@@ -53,7 +130,10 @@ static const struct modemparams modparam
 static void *modconfig(struct modemchannel *chan, unsigned int *samplerate, const char *params[])
 {
 	struct modstate *s;
-	
+	unsigned int freq;
+	unsigned int required_samplerate;
+	unsigned int f_carrier, df;
+
 	if (!(s = malloc(sizeof(struct modstate))))
 		logprintf(MLOG_FATAL, "out of memory\n");
 	s->chan = chan;
@@ -63,22 +143,36 @@ static void *modconfig(struct modemchann
 			s->bps = 100;
 		if (s->bps > 9600)
 			s->bps= 9600;
-	} else
-		s->bps = 1200;
-	if (params[1]) {
+	}
+	if (params[1])
 		s->f0 = strtoul(params[1], NULL, 0);
-		if (s->f0 > s->bps * 4)
-			s->f0 = s->bps * 4;
-	} else
-		s->f0 = 1200;
-	if (params[2]) {
+	if (params[2])
 		s->f1 = strtoul(params[2], NULL, 0);
-		if (s->f1 > s->bps * 4)
-			s->f1 = s->bps * 4;
-	} else
-		s->f1 = 2200;
 	s->notdiff = params[3] ? !strtoul(params[3], NULL, 0) : 0;
-	*samplerate = 8 * s->bps;
+
+	/* Swap symbol frequencies, if necessary */
+	if (s->f0 > s->f1) {
+		freq = s->f0;
+		s->f0 = s->f1;
+		s->f1 = freq;
+	}
+
+	/* Calculate the (audio) carrier frequency */
+	f_carrier = (s->f0 + s->f1)/2;
+
+	/* Calculate symbol spacing */
+	df = abs(s->f1 - s->f0);
+
+	/* Nyquist criteria (minimum sampling rate) */
+	required_samplerate = 2 * f_carrier + df + 2 * s->bps;
+
+	/*
+	 * Make sure that the sampling rate is at least
+	 * equal to the minimum recommended value.
+	 */
+	*samplerate = max(required_samplerate, MINIMUM_SAMPLERATE);
+	s->samplerate = *samplerate;
+
 	return s;
 }
 
@@ -86,16 +180,18 @@ static void modinit(void *state, unsigne
 {
 	struct modstate *s = (struct modstate *)state;
 
-	s->maxbitlen = (samplerate + s->bps - 1) / s->bps;
 	s->bitinc = (s->bps << 16) / samplerate;
 	s->ddsinc[0] = (s->f0 << 16) / samplerate;
 	s->ddsinc[1] = (s->f1 << 16) / samplerate;
 	s->bit = 0;
+	s->dds = 0;
+	s->bitph = 0;
 }
 
 static void modsendbits(struct modstate *s, unsigned int bits, unsigned int nrsyms)
 {
-        int16_t sbuf[512];
+        unsigned int bufsize = ((s->samplerate*512)/48000)%2 == 0 ? ((s->samplerate*512)/48000) : ((s->samplerate*512)/48000) + 1;
+        int16_t sbuf[bufsize];
         int16_t *sptr = sbuf, *eptr = sbuf + sizeof(sbuf)/sizeof(sbuf[0]);
 
         while (nrsyms > 0) {
@@ -145,20 +241,9 @@ struct modulator afskmodulator = {
 
 /* --------------------------------------------------------------------- */
 
-#define max(a, b) (((a) > (b)) ? (a) : (b))
-
-/* RxFilter */
-#define WINDOWEXPAND  1.5
-#define RXFILTLEN       16
-#define RXFILTOVERBITS   3
-#define RXFILTOVER      (1<<(RXFILTOVERBITS))
-#define RXFILTFIDX(x)   (((x)>>(16-(RXFILTOVERBITS)))&(RXFILTOVER-1))
-#define RXFILTFSAMP(x)  ((x)>>16)
-
 struct demodstate {
 	struct modemchannel *chan;
 	unsigned int bps, f0, f1, notdiff, firlen;
-        unsigned int srate;
         unsigned int rxbits;
         unsigned int rxphase;
         unsigned int rxphinc;
@@ -201,40 +286,50 @@ static const struct modemparams demodpar
 
 static void *demodconfig(struct modemchannel *chan, unsigned int *samplerate, const char *params[])
 {
-	struct demodstate *s;
-	unsigned int f;
+        struct demodstate *s;
+        unsigned int freq;
+        unsigned int required_samplerate;
+        unsigned int f_carrier, df;
+
+        if (!(s = malloc(sizeof(struct demodstate))))
+                logprintf(MLOG_FATAL, "out of memory\n");
+        s->chan = chan;
+        if (params[0]) {
+                s->bps = strtoul(params[0], NULL, 0);
+                if (s->bps < 100)
+                        s->bps = 100;
+                if (s->bps > 9600)
+                        s->bps= 9600;
+        }
+        if (params[1])
+                s->f0 = strtoul(params[1], NULL, 0);
+        if (params[2])
+                s->f1 = strtoul(params[2], NULL, 0);
+        s->notdiff = params[3] ? !strtoul(params[3], NULL, 0) : 0;
+
+        /* Swap symbol frequencies, if necessary */
+        if (s->f0 > s->f1) {
+                freq = s->f0;
+                s->f0 = s->f1;
+                s->f1 = freq;
+        }
 
-	if (!(s = malloc(sizeof(struct demodstate))))
-		logprintf(MLOG_FATAL, "out of memory\n");
-	s->chan = chan;
-	if (params[0]) {
-		s->bps = strtoul(params[0], NULL, 0);
-		if (s->bps < 100)
-			s->bps = 100;
-		if (s->bps > 9600)
-			s->bps= 9600;
-	} else
-		s->bps = 1200;
-	if (params[1]) {
-		s->f0 = strtoul(params[1], NULL, 0);
-		if (s->f0 > s->bps * 4)
-			s->f0 = s->bps * 4;
-	} else
-		s->f0 = 1200;
-	if (params[2]) {
-		s->f1 = strtoul(params[2], NULL, 0);
-		if (s->f1 > s->bps * 4)
-			s->f1 = s->bps * 4;
-	} else
-		s->f1 = 2200;
-	s->notdiff = params[3] ? !strtoul(params[3], NULL, 0) : 0;
-	f = s->f0;
-	if (s->f1 > f)
-		f = s->f1;
-	f += s->bps/2;
-	f = (2*f) + (f >> 1);
-	*samplerate = f;
-	return s;
+        /* Calculate the (audio) carrier frequency */
+        f_carrier = (s->f0 + s->f1)/2;
+
+        /* Calculate symbol spacing */
+        df = abs(s->f1 - s->f0);
+
+        /* Nyquist criteria (minimum sampling rate) */
+        required_samplerate = 2 * f_carrier + df + 2 * s->bps;
+
+        /*
+         * Make sure that the sampling rate is at least
+         * equal to the minimum recommended value.
+         */
+        *samplerate = max(required_samplerate, MINIMUM_SAMPLERATE);
+
+        return s;
 }
 
 static int demfilter(struct demodstate *state, const int16_t *val, unsigned int phase)
@@ -317,7 +412,6 @@ static void demod8bits(struct demodstate
         s->rxphase += phase;
 }
 
-
 static void demoddemodulate(void *state)
 {
 	struct demodstate *s = (struct demodstate *)state;
@@ -355,18 +449,28 @@ static void demoddemodulate(void *state)
         }
 }
 
-static inline double sinc(double x)
+/*
+ * The Hamming window was the only window
+ * available in the original version.
+ */
+static inline double no_window(double x)
+{
+	return 1;
+}
+
+static inline double hamming_window(double x)
 {
-        double arg = x * M_PI;
+        return 0.54+0.46*cos((2*M_PI)*x);
+}
 
-        if (arg == 0)
-                return 1;
-        return sin(arg) / arg;
+static inline double hanning_window(double x)
+{
+        return 0.5+0.5*cos((2*M_PI)*x);
 }
 
-static inline double hamming(double x)
+static inline double blackman_window(double x)
 {
-        return 0.54-0.46*cos((2*M_PI)*x);
+        return 0.42+0.5*cos((2*M_PI)*x)+0.08*cos((4*M_PI)*x);
 }
 
 static void demodinit(void *state, unsigned int samplerate, unsigned int *bitrate)
@@ -376,24 +480,39 @@ static void demodinit(void *state, unsig
         float f0i[RXFILTLEN*RXFILTOVER];
         float f1r[RXFILTLEN*RXFILTOVER];
         float f1i[RXFILTLEN*RXFILTOVER];
-        double ph0, ph1, w, tscale;
+        double ph0, ph1, w;
+        float index, scaled_index;
         float max, max0, max1, max2, max3;
         unsigned int i, j;
 
-	tscale = (float)s->bps / (float)samplerate / RXFILTOVER / WINDOWEXPAND;
-        ph0 = 2.0 * M_PI * (float)s->f0 / (float)samplerate / RXFILTOVER;
-        ph1 = 2.0 * M_PI * (float)s->f1 / (float)samplerate / RXFILTOVER;
+        ph0 = 2.0 * M_PI * (float)s->f0 / (float)samplerate;
+        ph1 = 2.0 * M_PI * (float)s->f1 / (float)samplerate;
         for (i = 0; i < RXFILTLEN * RXFILTOVER; i++) {
-                w = i * tscale;
-                if (w > 1)
-                        w = 0;
-                else
-                        w = hamming(w);
-                f0r[i] = w * cos(ph0 * i);
-                f0i[i] = w * sin(ph0 * i);
-                f1r[i] = w * cos(ph1 * i);
-                f1i[i] = w * sin(ph1 * i);
+                index = i - (RXFILTLEN * RXFILTOVER)/2.0;
+                scaled_index = index / RXFILTOVER;
+
+                w = WINDOW_FUNCTION(scaled_index / RXFILTLEN);
+
+                if (index == 0) {
+                        f0r[i] = w * cos(ph0 * scaled_index) * s->bps / samplerate;
+                        f0i[i] = w * sin(ph0 * scaled_index) * s->bps / samplerate;
+                        f1r[i] = w * cos(ph1 * scaled_index) * s->bps / samplerate;
+                        f1i[i] = w * sin(ph1 * scaled_index) * s->bps / samplerate;
+                } else {
+                        f0r[i] = w * cos(ph0 * scaled_index) * sin(M_PI * scaled_index * s->bps / samplerate) / M_PI / scaled_index;
+                        f0i[i] = w * sin(ph0 * scaled_index) * sin(M_PI * scaled_index * s->bps / samplerate) / M_PI / scaled_index;
+                        f1r[i] = w * cos(ph1 * scaled_index) * sin(M_PI * scaled_index * s->bps / samplerate) / M_PI / scaled_index;
+                        f1i[i] = w * sin(ph1 * scaled_index) * sin(M_PI * scaled_index * s->bps / samplerate) / M_PI / scaled_index;
+                }
+        }
+
+        if (RXFILTLEN % 2 == 0) {
+                f0r[0] = 0.0;
+                f0i[0] = 0.0;
+                f1r[0] = 0.0;
+                f1i[0] = 0.0;
         }
+
         /* determine maximum */
         max = 0;
         for (i = 0; i < RXFILTOVER; i++) {
@@ -427,7 +546,6 @@ static void demodinit(void *state, unsig
 			s->f.f32.f1r[RXFILTOVER-1-i][j] = f1r[j*RXFILTOVER+i];
 			s->f.f32.f1i[RXFILTOVER-1-i][j] = f1i[j*RXFILTOVER+i];
 		}
-        s->srate = samplerate;
         s->rxphinc = ((samplerate << 16) + s->bps / 2) / s->bps;
 	*bitrate = s->bps;
 }
