Transceiver52M: Precompute fractional delay filters

Preallocate and compute a bank of fractional sample delay filters.
The number of filters to allocate is specified by the DELAYFILTS
preprocessor definition with a default value of 64. The filters
themselves are sinc pulse generated with 20 taps and Blackman-harris
windowed .

Signed-off-by: Thomas Tsou <tom@tsou.cc>
diff --git a/Transceiver52M/sigProcLib.cpp b/Transceiver52M/sigProcLib.cpp
index 24e984d..efa8f5d 100644
--- a/Transceiver52M/sigProcLib.cpp
+++ b/Transceiver52M/sigProcLib.cpp
@@ -37,7 +37,8 @@
 
 using namespace GSM;
 
-#define TABLESIZE 1024
+#define TABLESIZE		1024
+#define DELAYFILTS		64
 
 /** Lookup tables for trigonometric approximation */
 float cosTable[TABLESIZE+1]; // add 1 element for wrap around
@@ -54,6 +55,9 @@
 static signalVector *GMSKRotation1 = NULL;
 static signalVector *GMSKReverseRotation1 = NULL;
 
+/* Precomputed fractional delay filters */
+static signalVector *delayFilters[DELAYFILTS];
+
 /*
  * RACH and midamble correlation waveforms. Store the buffer separately
  * because we need to allocate it explicitly outside of the signal vector
@@ -116,6 +120,11 @@
     gMidambles[i] = NULL;
   }
 
+  for (int i = 0; i < DELAYFILTS; i++) {
+    delete delayFilters[i];
+    delayFilters[i] = NULL;
+  }
+
   delete GMSKRotationN;
   delete GMSKReverseRotationN;
   delete GMSKRotation1;
@@ -818,33 +827,67 @@
   return 1.0F;
 }
 
+/*
+ * Create fractional delay filterbank with Blackman-harris windowed
+ * sinc function generator. The number of filters generated is specified
+ * by the DELAYFILTS value.
+ */
+void generateDelayFilters()
+{
+  int h_len = 20;
+  complex *data;
+  signalVector *h;
+  signalVector::iterator itr;
+
+  float k, sum;
+  float a0 = 0.35875;
+  float a1 = 0.48829;
+  float a2 = 0.14128;
+  float a3 = 0.01168;
+
+  for (int i = 0; i < DELAYFILTS; i++) {
+    data = (complex *) convolve_h_alloc(h_len);
+    h = new signalVector(data, 0, h_len);
+    h->setAligned(true);
+    h->isReal(true);
+
+    sum = 0.0;
+    itr = h->end();
+    for (int n = 0; n < h_len; n++) {
+      k = (float) n;
+      *--itr = (complex) sinc(M_PI_F *
+                         (k - (float) h_len / 2.0 - (float) i / DELAYFILTS));
+      *itr *= a0 -
+        a1 * cos(2 * M_PI * n / (h_len - 1)) +
+        a2 * cos(4 * M_PI * n / (h_len - 1)) -
+        a3 * cos(6 * M_PI * n / (h_len - 1));
+
+      sum += itr->real();
+    }
+
+    itr = h->begin();
+    for (int n = 0; n < h_len; n++)
+      *itr++ /= sum;
+
+    delayFilters[i] = h;
+  }
+}
+
 bool delayVector(signalVector &wBurst, float delay)
 {
-  int whole, h_len = 20;
+  int whole, index;
   float frac;
-  complex *data;
   signalVector *h, *shift;
-  signalVector::iterator itr;
 
   whole = floor(delay);
   frac = delay - whole;
 
   /* Sinc interpolated fractional shift (if allowable) */
   if (fabs(frac) > 1e-2) {
-    data = (complex *) convolve_h_alloc(h_len);
-    h = new signalVector(data, 0, h_len);
-    h->setAligned(true);
-    h->isReal(true);
-
-    itr = h->end();
-    for (int i = 0; i < h_len; i++)
-      *--itr = (complex) sinc(M_PI_F * (i - h_len / 2 - frac));
+    index = floorf(frac * (float) DELAYFILTS);
+    h = delayFilters[index];
 
     shift = convolve(&wBurst, h, NULL, NO_DELAY);
-
-    delete h;
-    free(data);
-
     if (!shift)
       return false;
 
@@ -1653,5 +1696,7 @@
     return false;
   }
 
+  generateDelayFilters();
+
   return true;
 }