]> code.bitgloo.com Git - clyne/stmdspgui.git/commitdiff
small changes; sig gen square(), triangle(), pulse()
authorClyne Sullivan <clyne@bitgloo.com>
Sun, 9 Jan 2022 17:28:19 +0000 (12:28 -0500)
committerClyne Sullivan <clyne@bitgloo.com>
Sun, 9 Jan 2022 17:28:19 +0000 (12:28 -0500)
25 files changed:
examples/1_convolve_simple.cpp [new file with mode: 0644]
examples/2_convolve_overlap_save.cpp [new file with mode: 0644]
examples/3_fir.cpp [new file with mode: 0644]
examples/4_fir_pro.cpp [new file with mode: 0644]
examples/5_fir_differentiator.cpp [new file with mode: 0644]
examples/6_iir_test.cpp [new file with mode: 0644]
examples/7_iir_echo.cpp [new file with mode: 0644]
source/circular.hpp
source/code.cpp
source/device.cpp
source/device_formula.cpp
source/file.cpp
source/gui.cpp
source/gui_code.cpp
source/gui_device.cpp
source/imgui/TextEditor.cpp
source/logview.cpp
source/main.cpp
templates/1_convolve_simple.cpp [deleted file]
templates/2_convolve_overlap_save.cpp [deleted file]
templates/3_fir.cpp [deleted file]
templates/4_fir_pro.cpp [deleted file]
templates/5_fir_differentiator.cpp [deleted file]
templates/6_iir_test.cpp [deleted file]
templates/7_iir_echo.cpp [deleted file]

diff --git a/examples/1_convolve_simple.cpp b/examples/1_convolve_simple.cpp
new file mode 100644 (file)
index 0000000..8de05d3
--- /dev/null
@@ -0,0 +1,29 @@
+/**
+ * 1_convolve_simple.cpp
+ * Written by Clyne Sullivan.
+ *
+ * Computes a convolution in the simplest way possible. While the code is brief, it lacks many
+ * possible optimizations. The convolution's result will not fill the output buffer either, as the
+ * transient response is not calculated.
+ */
+
+Sample *process_data(Samples samples)
+{
+    // Define our output buffer. SIZE is the largest size of the 'samples' buffer.
+    static Sample buffer[samples.size()];
+
+    // Define our filter
+    constexpr unsigned int filter_size = 3;
+       float filter[filter_size] = {
+        0.3333, 0.3333, 0.3333
+    };
+
+    // Begin convolving:
+    for (int n = 0; n < samples.size() - (filter_size - 1); n++) {
+        buffer[n] = 0;
+        for (int k = 0; k < filter_size; k++)
+            buffer[n] += samples[n + k] * filter[k];
+    }
+
+    return buffer;
+}
diff --git a/examples/2_convolve_overlap_save.cpp b/examples/2_convolve_overlap_save.cpp
new file mode 100644 (file)
index 0000000..57c020a
--- /dev/null
@@ -0,0 +1,47 @@
+/**
+ * 2_convolve_overlap_save.cpp
+ * Written by Clyne Sullivan.
+ *
+ * This convolution examples takes an overlap-save approach, where samples from the previous run
+ * are saved so that the overall operation is not interrupted (i.e. the observed output will
+ * transition smoothly between processed "chunks").
+ *
+ * Note that there are still improvements that can be made to the code; for example, notice every
+ * spot where an integer/float conversion is necessary. Operations like these may slow down the
+ * computation.
+ */
+
+Sample *process_data(Samples samples)
+{
+    static Sample buffer[samples.size()];
+
+    constexpr unsigned int filter_size = 3;
+       float filter[filter_size] = {
+        0.3333, 0.3333, 0.3333
+    };
+
+    // Keep a buffer of extra samples for overlap-save
+    static Sample prev[filter_size];
+
+    for (int n = 0; n < samples.size(); n++) {
+        buffer[n] = 0;
+
+        for (int k = 0; k < filter_size; k++) {
+            int i = n - (filter_size - 1) + k;
+
+            // If i is >= 0, access current sample buffer.
+            // If i is < 0, provide the previous samples from the 'prev' buffer
+            if (i >= 0)
+                buffer[n] += samples[i] * filter[k];
+            else
+                buffer[n] += prev[filter_size - 1 + i] * filter[k];
+        }
+    }
+
+    // Save samples for the next convolution run
+    for (int i = 0; i < filter_size; i++)
+        prev[i] = samples[samples.size() - filter_size + i];
+
+    return buffer;
+}
+
diff --git a/examples/3_fir.cpp b/examples/3_fir.cpp
new file mode 100644 (file)
index 0000000..3a68500
--- /dev/null
@@ -0,0 +1,47 @@
+/**
+ * 3_fir.cpp
+ * Written by Clyne Sullivan.
+ *
+ * The below code was written for applying FIR filters. While this is still essentially an overlap-
+ * save convolution, other optimizations have been made to allow for larger filters to be applied
+ * within the available execution time. Samples are also normalized so that they center around zero.
+ */
+
+Sample *process_data(Samples samples)
+{
+    static Sample buffer[samples.size()];
+
+       // Define the filter:
+       constexpr unsigned int filter_size = 3;
+       static float filter[filter_size] = {
+        // Put filter values here (note: precision will be truncated for 'float' size).
+        0.3333, 0.3333, 0.3333
+       };
+
+    // Do an overlap-save convolution
+    static Sample prev[filter_size];
+
+    for (int n = 0; n < samples.size(); n++) {
+        // Using a float variable for accumulation allows for better code optimization
+        float v = 0;
+
+        for (int k = 0; k < filter_size; k++) {
+            int i = n - (filter_size - 1) + k;
+
+            auto s = i >= 0 ? samples[i] : prev[filter_size - 1 + i];
+                       // Sample values are 0 to 4095. Below, the original sample is normalized to a -1.0 to
+            // 1.0 range for calculation.
+            v += (s / 2048.f - 1) * filter[k];
+        }
+
+        // Return value to sample range of 0-4095.
+        buffer[n] = (v + 1) * 2048.f;
+    }
+
+    // Save samples for next convolution
+    for (int i = 0; i < filter_size; i++)
+        prev[i] = samples[samples.size() - filter_size + i];
+
+    return buffer;
+}
+
diff --git a/examples/4_fir_pro.cpp b/examples/4_fir_pro.cpp
new file mode 100644 (file)
index 0000000..b1a6832
--- /dev/null
@@ -0,0 +1,478 @@
+#include <cstdint>
+using float32_t = float;
+
+typedef struct
+{
+    uint16_t numTaps;     /**< number of filter coefficients in the filter. */
+    float32_t *pState;    /**< points to the state variable array. The array is of length numTaps+blockSize-1. */
+    float32_t *pCoeffs;   /**< points to the coefficient array. The array is of length numTaps. */
+} arm_fir_instance_f32;
+
+static void arm_fir_f32(const arm_fir_instance_f32 * S, float32_t * pSrc, float32_t * pDst, uint32_t blockSize);
+
+Sample *process_data(Samples samples)
+{
+       // 1. Define our array sizes (Be sure to set Run > Set buffer size... to below value!)
+       constexpr unsigned int buffer_size = 500;
+       constexpr unsigned int filter_size = 100;
+
+       // 2. Define our filter and the working arrays
+       static float filter[filter_size] = {
+               .01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,
+               .01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,
+               .01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,
+               .01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,
+               .01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,
+               .01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,
+               .01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,
+               .01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,
+               .01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,
+               .01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f
+       };
+       static float input[buffer_size];
+       static float output[buffer_size];
+       static float working[buffer_size + filter_size];
+
+       // 3. Scale 0-4095 interger sample values to +/- 1.0 floats
+       for (unsigned int i = 0; i < samples.size(); i++)
+               input[i] = (samples[i] - 2048) / 2048.f;
+
+       // 4. Compute the FIR
+       arm_fir_instance_f32 fir { filter_size, working, filter };
+       arm_fir_f32(&fir, input, output, samples.size());
+
+       // 5. Convert float results back to 0-4095 range for output
+       for (unsigned int i = 0; i < samples.size(); i++)
+               samples[i] = output[i] * 2048.f + 2048;
+
+    return samples.data();
+}
+
+// Below taken from the CMSIS DSP Library (find it on GitHub)
+void arm_fir_f32(
+       const arm_fir_instance_f32 * S,
+       float32_t * pSrc,
+       float32_t * pDst,
+       uint32_t blockSize)
+{
+   float32_t *pState = S->pState;                 /* State pointer */
+   float32_t *pCoeffs = S->pCoeffs;               /* Coefficient pointer */
+   float32_t *pStateCurnt;                        /* Points to the current sample of the state */
+   float32_t *px, *pb;                            /* Temporary pointers for state and coefficient buffers */
+   float32_t acc0, acc1, acc2, acc3, acc4, acc5, acc6, acc7;     /* Accumulators */
+   float32_t x0, x1, x2, x3, x4, x5, x6, x7, c0;  /* Temporary variables to hold state and coefficient values */
+   uint32_t numTaps = S->numTaps;                 /* Number of filter coefficients in the filter */
+   uint32_t i, tapCnt, blkCnt;                    /* Loop counters */
+   float32_t p0,p1,p2,p3,p4,p5,p6,p7;             /* Temporary product values */
+
+   /* S->pState points to state array which contains previous frame (numTaps - 1) samples */
+   /* pStateCurnt points to the location where the new input data should be written */
+   pStateCurnt = &(S->pState[(numTaps - 1u)]);
+
+   /* Apply loop unrolling and compute 8 output values simultaneously.  
+    * The variables acc0 ... acc7 hold output values that are being computed:  
+    *  
+    *    acc0 =  b[numTaps-1] * x[n-numTaps-1] + b[numTaps-2] * x[n-numTaps-2] + b[numTaps-3] * x[n-numTaps-3] +...+ b[0] * x[0]  
+    *    acc1 =  b[numTaps-1] * x[n-numTaps] +   b[numTaps-2] * x[n-numTaps-1] + b[numTaps-3] * x[n-numTaps-2] +...+ b[0] * x[1]  
+    *    acc2 =  b[numTaps-1] * x[n-numTaps+1] + b[numTaps-2] * x[n-numTaps] +   b[numTaps-3] * x[n-numTaps-1] +...+ b[0] * x[2]  
+    *    acc3 =  b[numTaps-1] * x[n-numTaps+2] + b[numTaps-2] * x[n-numTaps+1] + b[numTaps-3] * x[n-numTaps]   +...+ b[0] * x[3]  
+    */
+   blkCnt = blockSize >> 3;
+
+   /* First part of the processing with loop unrolling.  Compute 8 outputs at a time.  
+   ** a second loop below computes the remaining 1 to 7 samples. */
+   while(blkCnt > 0u)
+   {
+      /* Copy four new input samples into the state buffer */
+      *pStateCurnt++ = *pSrc++;
+      *pStateCurnt++ = *pSrc++;
+      *pStateCurnt++ = *pSrc++;
+      *pStateCurnt++ = *pSrc++;
+
+      /* Set all accumulators to zero */
+      acc0 = 0.0f;
+      acc1 = 0.0f;
+      acc2 = 0.0f;
+      acc3 = 0.0f;
+      acc4 = 0.0f;
+      acc5 = 0.0f;
+      acc6 = 0.0f;
+      acc7 = 0.0f;             
+
+      /* Initialize state pointer */
+      px = pState;
+
+      /* Initialize coeff pointer */
+      pb = (pCoeffs);          
+   
+      /* This is separated from the others to avoid 
+       * a call to __aeabi_memmove which would be slower
+       */
+      *pStateCurnt++ = *pSrc++;
+      *pStateCurnt++ = *pSrc++;
+      *pStateCurnt++ = *pSrc++;
+      *pStateCurnt++ = *pSrc++;
+
+      /* Read the first seven samples from the state buffer:  x[n-numTaps], x[n-numTaps-1], x[n-numTaps-2] */
+      x0 = *px++;
+      x1 = *px++;
+      x2 = *px++;
+      x3 = *px++;
+      x4 = *px++;
+      x5 = *px++;
+      x6 = *px++;
+
+      /* Loop unrolling.  Process 8 taps at a time. */
+      tapCnt = numTaps >> 3u;
+      
+      /* Loop over the number of taps.  Unroll by a factor of 8.  
+       ** Repeat until we've computed numTaps-8 coefficients. */
+      while(tapCnt > 0u)
+      {
+         /* Read the b[numTaps-1] coefficient */
+         c0 = *(pb++);
+
+         /* Read x[n-numTaps-3] sample */
+         x7 = *(px++);
+
+         /* acc0 +=  b[numTaps-1] * x[n-numTaps] */
+         p0 = x0 * c0;
+
+         /* acc1 +=  b[numTaps-1] * x[n-numTaps-1] */
+         p1 = x1 * c0;
+
+         /* acc2 +=  b[numTaps-1] * x[n-numTaps-2] */
+         p2 = x2 * c0;
+
+         /* acc3 +=  b[numTaps-1] * x[n-numTaps-3] */
+         p3 = x3 * c0;
+
+         /* acc4 +=  b[numTaps-1] * x[n-numTaps-4] */
+         p4 = x4 * c0;
+
+         /* acc1 +=  b[numTaps-1] * x[n-numTaps-5] */
+         p5 = x5 * c0;
+
+         /* acc2 +=  b[numTaps-1] * x[n-numTaps-6] */
+         p6 = x6 * c0;
+
+         /* acc3 +=  b[numTaps-1] * x[n-numTaps-7] */
+         p7 = x7 * c0;
+         
+         /* Read the b[numTaps-2] coefficient */
+         c0 = *(pb++);
+
+         /* Read x[n-numTaps-4] sample */
+         x0 = *(px++);
+         
+         acc0 += p0;
+         acc1 += p1;
+         acc2 += p2;
+         acc3 += p3;
+         acc4 += p4;
+         acc5 += p5;
+         acc6 += p6;
+         acc7 += p7;
+
+
+         /* Perform the multiply-accumulate */
+         p0 = x1 * c0;
+         p1 = x2 * c0;   
+         p2 = x3 * c0;   
+         p3 = x4 * c0;   
+         p4 = x5 * c0;   
+         p5 = x6 * c0;   
+         p6 = x7 * c0;   
+         p7 = x0 * c0;   
+         
+         /* Read the b[numTaps-3] coefficient */
+         c0 = *(pb++);
+
+         /* Read x[n-numTaps-5] sample */
+         x1 = *(px++);
+         
+         acc0 += p0;
+         acc1 += p1;
+         acc2 += p2;
+         acc3 += p3;
+         acc4 += p4;
+         acc5 += p5;
+         acc6 += p6;
+         acc7 += p7;
+
+         /* Perform the multiply-accumulates */      
+         p0 = x2 * c0;
+         p1 = x3 * c0;   
+         p2 = x4 * c0;   
+         p3 = x5 * c0;   
+         p4 = x6 * c0;   
+         p5 = x7 * c0;   
+         p6 = x0 * c0;   
+         p7 = x1 * c0;   
+
+         /* Read the b[numTaps-4] coefficient */
+         c0 = *(pb++);
+
+         /* Read x[n-numTaps-6] sample */
+         x2 = *(px++);
+         
+         acc0 += p0;
+         acc1 += p1;
+         acc2 += p2;
+         acc3 += p3;
+         acc4 += p4;
+         acc5 += p5;
+         acc6 += p6;
+         acc7 += p7;
+
+         /* Perform the multiply-accumulates */      
+         p0 = x3 * c0;
+         p1 = x4 * c0;   
+         p2 = x5 * c0;   
+         p3 = x6 * c0;   
+         p4 = x7 * c0;   
+         p5 = x0 * c0;   
+         p6 = x1 * c0;   
+         p7 = x2 * c0;   
+
+         /* Read the b[numTaps-4] coefficient */
+         c0 = *(pb++);
+
+         /* Read x[n-numTaps-6] sample */
+         x3 = *(px++);
+         
+         acc0 += p0;
+         acc1 += p1;
+         acc2 += p2;
+         acc3 += p3;
+         acc4 += p4;
+         acc5 += p5;
+         acc6 += p6;
+         acc7 += p7;
+
+         /* Perform the multiply-accumulates */      
+         p0 = x4 * c0;
+         p1 = x5 * c0;   
+         p2 = x6 * c0;   
+         p3 = x7 * c0;   
+         p4 = x0 * c0;   
+         p5 = x1 * c0;   
+         p6 = x2 * c0;   
+         p7 = x3 * c0;   
+
+         /* Read the b[numTaps-4] coefficient */
+         c0 = *(pb++);
+
+         /* Read x[n-numTaps-6] sample */
+         x4 = *(px++);
+         
+         acc0 += p0;
+         acc1 += p1;
+         acc2 += p2;
+         acc3 += p3;
+         acc4 += p4;
+         acc5 += p5;
+         acc6 += p6;
+         acc7 += p7;
+
+         /* Perform the multiply-accumulates */      
+         p0 = x5 * c0;
+         p1 = x6 * c0;   
+         p2 = x7 * c0;   
+         p3 = x0 * c0;   
+         p4 = x1 * c0;   
+         p5 = x2 * c0;   
+         p6 = x3 * c0;   
+         p7 = x4 * c0;   
+
+         /* Read the b[numTaps-4] coefficient */
+         c0 = *(pb++);
+
+         /* Read x[n-numTaps-6] sample */
+         x5 = *(px++);
+         
+         acc0 += p0;
+         acc1 += p1;
+         acc2 += p2;
+         acc3 += p3;
+         acc4 += p4;
+         acc5 += p5;
+         acc6 += p6;
+         acc7 += p7;
+
+         /* Perform the multiply-accumulates */      
+         p0 = x6 * c0;
+         p1 = x7 * c0;   
+         p2 = x0 * c0;   
+         p3 = x1 * c0;   
+         p4 = x2 * c0;   
+         p5 = x3 * c0;   
+         p6 = x4 * c0;   
+         p7 = x5 * c0;   
+
+         /* Read the b[numTaps-4] coefficient */
+         c0 = *(pb++);
+
+         /* Read x[n-numTaps-6] sample */
+         x6 = *(px++);
+         
+         acc0 += p0;
+         acc1 += p1;
+         acc2 += p2;
+         acc3 += p3;
+         acc4 += p4;
+         acc5 += p5;
+         acc6 += p6;
+         acc7 += p7;
+
+         /* Perform the multiply-accumulates */      
+         p0 = x7 * c0;
+         p1 = x0 * c0;   
+         p2 = x1 * c0;   
+         p3 = x2 * c0;   
+         p4 = x3 * c0;   
+         p5 = x4 * c0;   
+         p6 = x5 * c0;   
+         p7 = x6 * c0;   
+
+         tapCnt--;
+         
+         acc0 += p0;
+         acc1 += p1;
+         acc2 += p2;
+         acc3 += p3;
+         acc4 += p4;
+         acc5 += p5;
+         acc6 += p6;
+         acc7 += p7;
+      }
+
+      /* If the filter length is not a multiple of 8, compute the remaining filter taps */
+      tapCnt = numTaps % 0x8u;
+
+      while(tapCnt > 0u)
+      {
+         /* Read coefficients */
+         c0 = *(pb++);
+
+         /* Fetch 1 state variable */
+         x7 = *(px++);
+
+         /* Perform the multiply-accumulates */      
+         p0 = x0 * c0;
+         p1 = x1 * c0;   
+         p2 = x2 * c0;   
+         p3 = x3 * c0;   
+         p4 = x4 * c0;   
+         p5 = x5 * c0;   
+         p6 = x6 * c0;   
+         p7 = x7 * c0;   
+
+         /* Reuse the present sample states for next sample */
+         x0 = x1;
+         x1 = x2;
+         x2 = x3;
+         x3 = x4;
+         x4 = x5;
+         x5 = x6;
+         x6 = x7;
+         
+         acc0 += p0;
+         acc1 += p1;
+         acc2 += p2;
+         acc3 += p3;
+         acc4 += p4;
+         acc5 += p5;
+         acc6 += p6;
+         acc7 += p7;
+
+         /* Decrement the loop counter */
+         tapCnt--;
+      }
+
+      /* Advance the state pointer by 8 to process the next group of 8 samples */
+      pState = pState + 8;
+
+      /* The results in the 8 accumulators, store in the destination buffer. */
+      *pDst++ = acc0;
+      *pDst++ = acc1;
+      *pDst++ = acc2;
+      *pDst++ = acc3;
+      *pDst++ = acc4;
+      *pDst++ = acc5;
+      *pDst++ = acc6;
+      *pDst++ = acc7;
+
+      blkCnt--;
+   }
+
+   /* If the blockSize is not a multiple of 8, compute any remaining output samples here.  
+   ** No loop unrolling is used. */
+   blkCnt = blockSize % 0x8u;
+
+   while(blkCnt > 0u)
+   {
+      /* Copy one sample at a time into state buffer */
+      *pStateCurnt++ = *pSrc++;
+
+      /* Set the accumulator to zero */
+      acc0 = 0.0f;
+
+      /* Initialize state pointer */
+      px = pState;
+
+      /* Initialize Coefficient pointer */
+      pb = (pCoeffs);
+
+      i = numTaps;
+
+      /* Perform the multiply-accumulates */
+      do
+      {
+         acc0 += *px++ * *pb++;
+         i--;
+
+      } while(i > 0u);
+
+      /* The result is store in the destination buffer. */
+      *pDst++ = acc0;
+
+      /* Advance state pointer by 1 for the next sample */
+      pState = pState + 1;
+
+      blkCnt--;
+   }
+
+   /* Processing is complete.  
+   ** Now copy the last numTaps - 1 samples to the start of the state buffer.  
+   ** This prepares the state buffer for the next function call. */
+
+   /* Points to the start of the state buffer */
+   pStateCurnt = S->pState;
+
+   tapCnt = (numTaps - 1u) >> 2u;
+
+   /* copy data */
+   while(tapCnt > 0u)
+   {
+      *pStateCurnt++ = *pState++;
+      *pStateCurnt++ = *pState++;
+      *pStateCurnt++ = *pState++;
+      *pStateCurnt++ = *pState++;
+
+      /* Decrement the loop counter */
+      tapCnt--;
+   }
+
+   /* Calculate remaining number of copies */
+   tapCnt = (numTaps - 1u) % 0x4u;
+
+   /* Copy the remaining q31_t data */
+   while(tapCnt > 0u)
+   {
+      *pStateCurnt++ = *pState++;
+
+      /* Decrement the loop counter */
+      tapCnt--;
+   }
+}
diff --git a/examples/5_fir_differentiator.cpp b/examples/5_fir_differentiator.cpp
new file mode 100644 (file)
index 0000000..72415c6
--- /dev/null
@@ -0,0 +1,30 @@
+/**
+ * 5_fir_differentiator.cpp
+ * Written by Clyne Sullivan.
+ *
+ * Does an FIR differentiation on the incoming signal, so that the output is representative of the
+ * rate of change of the input.
+ * A scaling factor is applied so that the output's form is more clearly visible.
+ */
+
+Sample *process_data(Samples samples)
+{
+    constexpr int scaling_factor = 4;
+       static Sample output[samples.size()];
+    static Sample prev = 2048;
+
+    // Compute the first output value using the saved sample.
+    output[0] = 2048 + ((samples[0] - prev) * scaling_factor);
+
+       for (unsigned int i = 1; i < samples.size(); i++) {
+        // Take the rate of change and scale it.
+        // 2048 is added as the output should be centered in the voltage range.
+               output[i] = 2048 + ((samples[i] - samples[i - 1]) * scaling_factor);
+    }
+
+       // Save the last sample for the next iteration.
+    prev = samples[samples.size() - 1];
+
+    return output;
+}
+
diff --git a/examples/6_iir_test.cpp b/examples/6_iir_test.cpp
new file mode 100644 (file)
index 0000000..116a680
--- /dev/null
@@ -0,0 +1,13 @@
+Sample *process_data(Samples samples)
+{
+       constexpr float alpha = 0.7;
+
+       static Sample prev = 2048;
+
+       samples[0] = (1 - alpha) * samples[0] + alpha * prev;
+       for (unsigned int i = 1; i < samples.size(); i++)
+               samples[i] = (1 - alpha) * samples[i] + alpha * samples[i - 1];
+       prev = samples[samples.size() - 1];
+
+       return samples.data();
+}
diff --git a/examples/7_iir_echo.cpp b/examples/7_iir_echo.cpp
new file mode 100644 (file)
index 0000000..57e5605
--- /dev/null
@@ -0,0 +1,22 @@
+Sample *process_data(Samples samples)
+{
+       constexpr float alpha = 0.75;
+       constexpr unsigned int D = 100;
+
+       static Sample output[samples.size()];
+       static Sample prev[D]; // prev[0] = output[0 - D]
+
+       // Do calculations with previous output
+       for (unsigned int i = 0; i < D; i++)
+               output[i] = samples[i] + alpha * (prev[i] - 2048);
+
+       // Do calculations with current samples
+       for (unsigned int i = D; i < samples.size(); i++)
+               output[i] = samples[i] + alpha * (output[i - D] - 2048);
+
+       // Save outputs for next computation
+       for (unsigned int i = 0; i < D; i++)
+               prev[i] = output[samples.size() - (D - i)];
+
+       return output;
+}
index 33b8ee0a847c136571f3bae7d3133faf45ae4644..6b820683454690878b80479f144ca52c26068b43 100644 (file)
@@ -1,3 +1,14 @@
+/**
+ * @file circular.hpp
+ * @brief Small utility for filling a buffer in a circular manner.
+ *
+ * Copyright (C) 2021 Clyne Sullivan
+ *
+ * Distributed under the GNU GPL v3 or later. You should have received a copy of
+ * the GNU General Public License along with this program.
+ * If not, see <https://www.gnu.org/licenses/>.
+ */
+
 #ifndef CIRCULAR_HPP
 #define CIRCULAR_HPP
 
index 7a9afaaf61e0d46b2d5843a7580cf618cb8d8afc..14f603c4b92fb9f8cb3311c2b72d2828b111c53c 100644 (file)
@@ -1,3 +1,14 @@
+/**
+ * @file code.cpp
+ * @brief Functionality for compiling and disassembling source code.
+ *
+ * Copyright (C) 2021 Clyne Sullivan
+ *
+ * Distributed under the GNU GPL v3 or later. You should have received a copy of
+ * the GNU General Public License along with this program.
+ * If not, see <https://www.gnu.org/licenses/>.
+ */
+
 #include "stmdsp.hpp"
 #include "stmdsp_code.hpp"
 
 #include <string>
 
 extern std::shared_ptr<stmdsp::device> m_device;
-extern void log(const std::string& str);
+void log(const std::string& str);
 
-std::string tempFileName; // device.cpp
+std::ifstream compileOpenBinaryFile();
+void compileEditorCode(const std::string& code);
+void disassembleCode();
 
+static std::string tempFileName;
 static std::string newTempFileName();
 static bool codeExecuteCommand(
     const std::string& command,
@@ -22,6 +36,14 @@ static void stringReplaceAll(
     const std::string& what,
     const std::string& with);
 
+std::ifstream compileOpenBinaryFile()
+{
+    if (!tempFileName.empty())
+        return std::ifstream(tempFileName + ".o");
+    else
+        return std::ifstream();
+}
+
 void compileEditorCode(const std::string& code)
 {
     log("Compiling...");
index abcc88ab1979176feb12c54518c9b752640633ad..11e181e8a3671b43597788337713685731938034 100644 (file)
@@ -30,9 +30,9 @@
 #include <thread>
 #include <vector>
 
-extern std::string tempFileName;
 extern void log(const std::string& str);
 extern std::vector<stmdsp::dacsample_t> deviceGenLoadFormulaEval(const std::string&);
+extern std::ifstream compileOpenBinaryFile();
 
 std::shared_ptr<stmdsp::device> m_device;
 
@@ -224,15 +224,21 @@ void deviceLoadLogFile(const std::string& file)
 bool deviceGenStartToggle()
 {
     if (m_device) {
-        bool running = m_device->is_siggening();
+        const bool running = m_device->is_siggening();
+
         if (!running) {
-            if (wavOutput.valid())
+            if (wavOutput.valid()) {
                 std::thread(feedSigGenTask, m_device).detach();
-            else
+            } else {
+                std::scoped_lock dlock (mutexDeviceLoad);
                 m_device->siggen_start();
+            }
             log("Generator started.");
         } else {
-            m_device->siggen_stop();
+            {
+                std::scoped_lock dlock (mutexDeviceLoad);
+                m_device->siggen_stop();
+            }
             log("Generator stopped.");
         }
 
@@ -332,7 +338,7 @@ void deviceAlgorithmUpload()
         log("No device connected.");
     } else if (m_device->is_running()) {
         log("Cannot upload algorithm while running.");
-    } else if (std::ifstream algo (tempFileName + ".o"); algo.is_open()) {
+    } else if (auto algo = compileOpenBinaryFile(); algo.is_open()) {
         std::ostringstream sstr;
         sstr << algo.rdbuf();
         auto str = sstr.str();
index c94eab74de1c6e115760b5213128a2e3f8e0be6b..a70f4652ca60f3b3834ecd72d7ae0450be548c53 100644 (file)
@@ -1,31 +1,63 @@
+/**
+ * @file device_formula.cpp
+ * @brief Function for filling generator buffer using a mathematical formula.
+ * This is kept in its own file as exprtk.hpp takes forever to compile.
+ *
+ * Copyright (C) 2021 Clyne Sullivan
+ *
+ * Distributed under the GNU GPL v3 or later. You should have received a copy of
+ * the GNU General Public License along with this program.
+ * If not, see <https://www.gnu.org/licenses/>.
+ */
+
 #include "stmdsp.hpp"
 #include "exprtk.hpp"
 
 #include <algorithm>
+#include <random>
 #include <string_view>
 #include <vector>
 
+static std::random_device randomDevice;
+
 std::vector<stmdsp::dacsample_t> deviceGenLoadFormulaEval(const std::string& formulaString)
 {
     double x = 0;
 
     exprtk::symbol_table<double> symbol_table;
+    exprtk::function_compositor<double> compositor (symbol_table);
     exprtk::expression<double> expression;
     exprtk::parser<double> parser;
 
-    symbol_table.add_variable("x", x);
     symbol_table.add_constants();
+    symbol_table.add_variable("x", x);
+    symbol_table.add_function("random",
+        [](double l, double h) -> double {
+            return std::uniform_real_distribution<double>(l, h)(randomDevice);
+        });
+    compositor.add(exprtk::function_compositor<double>::function()
+                       .name("square")
+                       .var("X")
+                       .expression("ceil(sin(pi*X))"));
+    compositor.add(exprtk::function_compositor<double>::function()
+                       .name("triangle")
+                       .var("X")
+                       .expression("ceil(sin(pi*X))*(X-floor(X))+ceil(-sin(pi*X))*(-X-floor(-X))"));
+    compositor.add(exprtk::function_compositor<double>::function()
+                       .name("pulse")
+                       .var("L")
+                       .var("X")
+                       .expression("if(X<=L,1,0)"));
     expression.register_symbol_table(symbol_table);
     parser.compile(formulaString, expression);
 
-    std::vector<stmdsp::dacsample_t> samples (stmdsp::SAMPLES_MAX);
-
-    auto genFun = [&x, &expression] {
-        stmdsp::dacsample_t s = expression.value();
+    const auto genFun = [&x, &expression] {
+        const auto s = std::clamp(expression.value(), -1., 1.) * 2048. + 2048.;
         ++x;
-        return s;
+        return static_cast<stmdsp::dacsample_t>(std::min(s, 4095.));
     };
 
+    std::vector<stmdsp::dacsample_t> samples (stmdsp::SAMPLES_MAX);
     std::generate(samples.begin(), samples.end(), genFun);
     return samples;
 }
index a5ef1d8cb156a2faf5b7c8d3f25d9b6a09524268..fe5dafb09abce7b6b9647d7732c9d3858ddb0c04 100644 (file)
@@ -40,7 +40,7 @@ enum class FileAction {
 
 static FileAction fileAction = FileAction::None;
 static std::string fileCurrentPath;
-static std::vector<std::filesystem::path> fileTemplateList;
+static std::vector<std::filesystem::path> fileExampleList;
 
 static void saveCurrentFile()
 {
@@ -66,9 +66,9 @@ static void openNewFile()
     editor.SetText(stmdsp::file_content);
 }
 
-static std::vector<std::filesystem::path> fileScanTemplates()
+static std::vector<std::filesystem::path> fileScanExamples()
 {
-    const auto path = std::filesystem::current_path() / "templates";
+    const auto path = std::filesystem::current_path() / "examples";
     const std::filesystem::recursive_directory_iterator rdi (path);
 
     std::vector<std::filesystem::path> list;
@@ -83,7 +83,7 @@ static std::vector<std::filesystem::path> fileScanTemplates()
 
 void fileInit()
 {
-    fileTemplateList = fileScanTemplates();
+    fileExampleList = fileScanExamples();
     openNewFile();
 }
 
@@ -102,8 +102,8 @@ void fileRenderMenu()
                 "ChooseFileOpenSave", "Choose File", ".cpp", ".");
         }
 
-        if (ImGui::BeginMenu("Open Template")) {
-            for (const auto& file : fileTemplateList) {
+        if (ImGui::BeginMenu("Open Example")) {
+            for (const auto& file : fileExampleList) {
                 if (ImGui::MenuItem(file.filename().c_str())) {
                     fileCurrentPath = file.string();
                     openCurrentFile();
index 515d4718537f741efc419e10967ddf9e332773f4..80120c47d56b729a353c5fa1386be6b9f4950a69 100644 (file)
 #include <SDL2/SDL.h>
 #include <SDL2/SDL_opengl.h>
 
-ImFont *fontSans = nullptr;
-ImFont *fontMono = nullptr;
-static ImGuiIO *io = nullptr;
+bool guiInitialize();
+void guiRender();
+bool guiHandleEvents();
+void guiShutdown();
+
 static SDL_Window *window = nullptr;
-static decltype(SDL_GL_CreateContext(nullptr)) gl_context;
+static SDL_GLContext gl_context;
 
 bool guiInitialize()
 {
-    if (SDL_Init(/*SDL_INIT_VIDEO*/0) != 0) {
+    if (SDL_Init(0) != 0) {
         printf("Error: %s\n", SDL_GetError());
         return false;
     }
@@ -42,6 +44,12 @@ bool guiInitialize()
         SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
         WINDOW_WIDTH, WINDOW_HEIGHT,
         SDL_WINDOW_OPENGL /*| SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI*/);
+
+    if (window == nullptr) {
+        puts("Error: Could not create the window!");
+        return false;
+    }
+
     gl_context = SDL_GL_CreateContext(window);
     SDL_GL_MakeCurrent(window, gl_context);
     SDL_GL_SetSwapInterval(1); // Enable vsync
@@ -49,10 +57,7 @@ bool guiInitialize()
     // Setup Dear ImGui context
     IMGUI_CHECKVERSION();
     ImGui::CreateContext();
-    io = &ImGui::GetIO();
     //io->ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
-    fontSans = io->Fonts->AddFontFromFileTTF("fonts/Roboto-Regular.ttf", 20);
-    fontMono = io->Fonts->AddFontFromFileTTF("fonts/RobotoMono-Regular.ttf", 20);
 
     ImGui_ImplSDL2_InitForOpenGL(window, gl_context);
     ImGui_ImplOpenGL2_Init();
@@ -99,13 +104,19 @@ bool guiInitialize()
     return true;
 }
 
-void guiRender(void (*func)())
+void guiRender()
 {
-   glViewport(0, 0, (int)io->DisplaySize.x, (int)io->DisplaySize.y);
-   glClearColor(1, 1, 1, 1);
-   glClear(GL_COLOR_BUFFER_BIT);
-   func();
-   SDL_GL_SwapWindow(window);
+    ImGui::Render();
+
+    const auto& displaySize = ImGui::GetIO().DisplaySize;
+    const int sizeX = static_cast<int>(displaySize.x);
+    const int sizeY = static_cast<int>(displaySize.y);
+
+    glViewport(0, 0, sizeX, sizeY);
+    glClearColor(1, 1, 1, 1);
+    glClear(GL_COLOR_BUFFER_BIT);
+    ImGui_ImplOpenGL2_RenderDrawData(ImGui::GetDrawData());
+    SDL_GL_SwapWindow(window);
 }
 
 bool guiHandleEvents()
@@ -114,10 +125,14 @@ bool guiHandleEvents()
 
     for (SDL_Event event; SDL_PollEvent(&event);) {
         ImGui_ImplSDL2_ProcessEvent(&event);
-        if (event.type == SDL_QUIT)
-            done = true;
-        if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window))
+        if (event.type == SDL_QUIT) {
             done = true;
+        } else if (event.type == SDL_WINDOWEVENT) {
+            const auto& ew = event.window;
+            const auto wid = SDL_GetWindowID(window);
+            if (ew.event == SDL_WINDOWEVENT_CLOSE && ew.windowID == wid)
+                done = true;
+        }
     }
 
     return done;
index 6917c72d3943f60fc9da0ecb74bfb3d72495d687..19fa572910b1e2f537548fe92d8e04d0d403210c 100644 (file)
@@ -37,9 +37,9 @@ void codeEditorInit()
 void codeRenderMenu()
 {
     if (ImGui::BeginMenu("Code")) {
-        if (ImGui::MenuItem("Compile code"))
+        if (ImGui::MenuItem("Compile"))
             codeCompile();
-        if (ImGui::MenuItem("Show disassembly"))
+        if (ImGui::MenuItem("Disassemble"))
             codeDisassemble();
 
         ImGui::EndMenu();
index a1d05552ffef32ee5c6ec6cc5d7c2be9cff27683..43c0a581bae35a1c4c8c0dea35ad03c209db3074 100644 (file)
@@ -55,7 +55,7 @@ void deviceRenderMenu()
         }
     };
 
-    if (ImGui::BeginMenu("Run")) {
+    if (ImGui::BeginMenu("Device")) {
         static std::string connectLabel ("Connect");
         addMenuItem(connectLabel, !m_device || !m_device->is_running(), [&] {
                 if (deviceConnect()) {
@@ -199,11 +199,6 @@ void deviceRenderWidgets()
             ImGui::PopStyleColor();
         }
 
-        if (ImGui::Button("Cancel")) {
-            siggenInput.clear();
-            ImGui::CloseCurrentPopup();
-        }
-
         if (ImGui::Button("Save")) {
             switch (siggenOption) {
             case 0:
@@ -219,6 +214,12 @@ void deviceRenderWidgets()
             ImGui::CloseCurrentPopup();
         }
 
+        ImGui::SameLine();
+        if (ImGui::Button("Cancel")) {
+            siggenInput.clear();
+            ImGui::CloseCurrentPopup();
+        }
+
         ImGui::EndPopup();
     }
 
@@ -387,12 +388,22 @@ void deviceRenderDraw()
         if (mouse.x > p0.x && mouse.x < p0.x + size.x &&
             mouse.y > p0.y && mouse.y < p0.y + size.y)
         {
-            const std::size_t si = (mouse.x - p0.x) / size.x * buffer.size();
-            const float s = buffer[si] / 4095.f * 6.6f - 3.3f;
-            char buf[12];
-            snprintf(buf, 16, "   %1.3fV", s);
+            char buf[16];
             drawList->AddLine({mouse.x, p0.y}, {mouse.x, p0.y + size.y}, IM_COL32(255, 255, 0, 255));
-            drawList->AddText(ImGui::GetMousePos(), IM_COL32(210, 210, 0, 255), buf);
+
+            {
+                const std::size_t si = (mouse.x - p0.x) / size.x * buffer.size();
+                const float s = buffer[si] / 4095.f * 6.6f - 3.3f;
+                snprintf(buf, sizeof(buf), "   %1.3fV", s);
+                drawList->AddText(mouse, IM_COL32(255, 0, 0, 255), buf);
+            }
+
+            if (drawSamplesInput) {
+                const std::size_t si = (mouse.x - p0.x) / size.x * bufferInput.size();
+                const float s = bufferInput[si] / 4095.f * 6.6f - 3.3f;
+                snprintf(buf, sizeof(buf), "   %1.3fV", s);
+                drawList->AddText({mouse.x, mouse.y + 20}, IM_COL32(0, 0, 255, 255), buf);
+            }
         }
 
         ImGui::End();
index b45a21ea75d7f13fc8a4bd99711a6eb9dd425fab..85bff7409ae221c4b939afdfd6b2c5c4242b86ab 100644 (file)
@@ -46,7 +46,7 @@ TextEditor::TextEditor()
        , mHandleKeyboardInputs(true)
        , mHandleMouseInputs(true)
        , mIgnoreImGuiChild(false)
-       , mShowWhitespaces(true)
+       , mShowWhitespaces(false)
        , mStartTime(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count())
 {
        SetPalette(GetDarkPalette());
index 267cecb9add422f942eefee0ef8024eb22e26887..5a771bf18b6fe3481c33182ce899bd6877978c5a 100644 (file)
@@ -41,7 +41,7 @@ void LogView::Draw(const char* title, bool* p_open, ImGuiWindowFlags flags)
     }
 
     ImGui::Text("Log ");
-    ImGui::SameLine();
+    ImGui::SameLine(ImGui::GetWindowWidth() - 120);
     if (ImGui::Button("Clear"))
         Clear();
     ImGui::SameLine();
index 5eac3389106b68c689ead8437208de0023bf98e5..e8641bc77a38eacaf16ae4f537bc93a50008a607 100644 (file)
 
 #include <chrono>
 #include <cmath>
+#include <iostream>
 #include <string>
 #include <thread>
 
-extern ImFont *fontSans;
-extern ImFont *fontMono;
-
-bool guiInitialize();
-bool guiHandleEvents();
-void guiShutdown();
-void guiRender(void (*func)());
-
-void fileRenderMenu();
-void fileRenderDialog();
-void fileInit();
-
 void codeEditorInit();
 void codeRenderMenu();
 void codeRenderToolbar();
 void codeRenderWidgets();
-
 void deviceRenderDraw();
 void deviceRenderMenu();
 void deviceRenderToolbar();
 void deviceRenderWidgets();
+void fileRenderMenu();
+void fileRenderDialog();
+void fileInit();
+bool guiInitialize();
+bool guiHandleEvents();
+void guiShutdown();
+void guiRender();
 
-static LogView logView;
+void log(const std::string& str);
 
-void log(const std::string& str)
-{
-    logView.AddLog(str);
-}
+static LogView logView;
+static ImFont *fontSans = nullptr;
+static ImFont *fontMono = nullptr;
 
 static void renderWindow();
 
@@ -58,6 +52,14 @@ int main(int, char **)
     if (!guiInitialize())
         return -1;
 
+    auto& io = ImGui::GetIO();
+    fontSans = io.Fonts->AddFontFromFileTTF("fonts/Roboto-Regular.ttf", 20);
+    fontMono = io.Fonts->AddFontFromFileTTF("fonts/RobotoMono-Regular.ttf", 20);
+    if (fontSans == nullptr || fontMono == nullptr) {
+        std::cout << "Failed to load fonts!" << std::endl;
+        return -1;
+    }
+
     codeEditorInit();
     fileInit();
 
@@ -78,6 +80,11 @@ int main(int, char **)
     return 0;
 }
 
+void log(const std::string& str)
+{
+    logView.AddLog(str);
+}
+
 void renderWindow()
 {
     // Start the new window frame and render the menu bar.
@@ -124,9 +131,6 @@ void renderWindow()
     deviceRenderDraw();
 
     // Draw everything to the screen.
-    ImGui::Render();
-    guiRender([] {
-        ImGui_ImplOpenGL2_RenderDrawData(ImGui::GetDrawData());
-    });
+    guiRender();
 }
 
diff --git a/templates/1_convolve_simple.cpp b/templates/1_convolve_simple.cpp
deleted file mode 100644 (file)
index 8de05d3..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/**
- * 1_convolve_simple.cpp
- * Written by Clyne Sullivan.
- *
- * Computes a convolution in the simplest way possible. While the code is brief, it lacks many
- * possible optimizations. The convolution's result will not fill the output buffer either, as the
- * transient response is not calculated.
- */
-
-Sample *process_data(Samples samples)
-{
-    // Define our output buffer. SIZE is the largest size of the 'samples' buffer.
-    static Sample buffer[samples.size()];
-
-    // Define our filter
-    constexpr unsigned int filter_size = 3;
-       float filter[filter_size] = {
-        0.3333, 0.3333, 0.3333
-    };
-
-    // Begin convolving:
-    for (int n = 0; n < samples.size() - (filter_size - 1); n++) {
-        buffer[n] = 0;
-        for (int k = 0; k < filter_size; k++)
-            buffer[n] += samples[n + k] * filter[k];
-    }
-
-    return buffer;
-}
diff --git a/templates/2_convolve_overlap_save.cpp b/templates/2_convolve_overlap_save.cpp
deleted file mode 100644 (file)
index 57c020a..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/**
- * 2_convolve_overlap_save.cpp
- * Written by Clyne Sullivan.
- *
- * This convolution examples takes an overlap-save approach, where samples from the previous run
- * are saved so that the overall operation is not interrupted (i.e. the observed output will
- * transition smoothly between processed "chunks").
- *
- * Note that there are still improvements that can be made to the code; for example, notice every
- * spot where an integer/float conversion is necessary. Operations like these may slow down the
- * computation.
- */
-
-Sample *process_data(Samples samples)
-{
-    static Sample buffer[samples.size()];
-
-    constexpr unsigned int filter_size = 3;
-       float filter[filter_size] = {
-        0.3333, 0.3333, 0.3333
-    };
-
-    // Keep a buffer of extra samples for overlap-save
-    static Sample prev[filter_size];
-
-    for (int n = 0; n < samples.size(); n++) {
-        buffer[n] = 0;
-
-        for (int k = 0; k < filter_size; k++) {
-            int i = n - (filter_size - 1) + k;
-
-            // If i is >= 0, access current sample buffer.
-            // If i is < 0, provide the previous samples from the 'prev' buffer
-            if (i >= 0)
-                buffer[n] += samples[i] * filter[k];
-            else
-                buffer[n] += prev[filter_size - 1 + i] * filter[k];
-        }
-    }
-
-    // Save samples for the next convolution run
-    for (int i = 0; i < filter_size; i++)
-        prev[i] = samples[samples.size() - filter_size + i];
-
-    return buffer;
-}
-
diff --git a/templates/3_fir.cpp b/templates/3_fir.cpp
deleted file mode 100644 (file)
index 3a68500..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/**
- * 3_fir.cpp
- * Written by Clyne Sullivan.
- *
- * The below code was written for applying FIR filters. While this is still essentially an overlap-
- * save convolution, other optimizations have been made to allow for larger filters to be applied
- * within the available execution time. Samples are also normalized so that they center around zero.
- */
-
-Sample *process_data(Samples samples)
-{
-    static Sample buffer[samples.size()];
-
-       // Define the filter:
-       constexpr unsigned int filter_size = 3;
-       static float filter[filter_size] = {
-        // Put filter values here (note: precision will be truncated for 'float' size).
-        0.3333, 0.3333, 0.3333
-       };
-
-    // Do an overlap-save convolution
-    static Sample prev[filter_size];
-
-    for (int n = 0; n < samples.size(); n++) {
-        // Using a float variable for accumulation allows for better code optimization
-        float v = 0;
-
-        for (int k = 0; k < filter_size; k++) {
-            int i = n - (filter_size - 1) + k;
-
-            auto s = i >= 0 ? samples[i] : prev[filter_size - 1 + i];
-                       // Sample values are 0 to 4095. Below, the original sample is normalized to a -1.0 to
-            // 1.0 range for calculation.
-            v += (s / 2048.f - 1) * filter[k];
-        }
-
-        // Return value to sample range of 0-4095.
-        buffer[n] = (v + 1) * 2048.f;
-    }
-
-    // Save samples for next convolution
-    for (int i = 0; i < filter_size; i++)
-        prev[i] = samples[samples.size() - filter_size + i];
-
-    return buffer;
-}
-
diff --git a/templates/4_fir_pro.cpp b/templates/4_fir_pro.cpp
deleted file mode 100644 (file)
index b1a6832..0000000
+++ /dev/null
@@ -1,478 +0,0 @@
-#include <cstdint>
-using float32_t = float;
-
-typedef struct
-{
-    uint16_t numTaps;     /**< number of filter coefficients in the filter. */
-    float32_t *pState;    /**< points to the state variable array. The array is of length numTaps+blockSize-1. */
-    float32_t *pCoeffs;   /**< points to the coefficient array. The array is of length numTaps. */
-} arm_fir_instance_f32;
-
-static void arm_fir_f32(const arm_fir_instance_f32 * S, float32_t * pSrc, float32_t * pDst, uint32_t blockSize);
-
-Sample *process_data(Samples samples)
-{
-       // 1. Define our array sizes (Be sure to set Run > Set buffer size... to below value!)
-       constexpr unsigned int buffer_size = 500;
-       constexpr unsigned int filter_size = 100;
-
-       // 2. Define our filter and the working arrays
-       static float filter[filter_size] = {
-               .01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,
-               .01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,
-               .01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,
-               .01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,
-               .01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,
-               .01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,
-               .01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,
-               .01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,
-               .01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,
-               .01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f
-       };
-       static float input[buffer_size];
-       static float output[buffer_size];
-       static float working[buffer_size + filter_size];
-
-       // 3. Scale 0-4095 interger sample values to +/- 1.0 floats
-       for (unsigned int i = 0; i < samples.size(); i++)
-               input[i] = (samples[i] - 2048) / 2048.f;
-
-       // 4. Compute the FIR
-       arm_fir_instance_f32 fir { filter_size, working, filter };
-       arm_fir_f32(&fir, input, output, samples.size());
-
-       // 5. Convert float results back to 0-4095 range for output
-       for (unsigned int i = 0; i < samples.size(); i++)
-               samples[i] = output[i] * 2048.f + 2048;
-
-    return samples.data();
-}
-
-// Below taken from the CMSIS DSP Library (find it on GitHub)
-void arm_fir_f32(
-       const arm_fir_instance_f32 * S,
-       float32_t * pSrc,
-       float32_t * pDst,
-       uint32_t blockSize)
-{
-   float32_t *pState = S->pState;                 /* State pointer */
-   float32_t *pCoeffs = S->pCoeffs;               /* Coefficient pointer */
-   float32_t *pStateCurnt;                        /* Points to the current sample of the state */
-   float32_t *px, *pb;                            /* Temporary pointers for state and coefficient buffers */
-   float32_t acc0, acc1, acc2, acc3, acc4, acc5, acc6, acc7;     /* Accumulators */
-   float32_t x0, x1, x2, x3, x4, x5, x6, x7, c0;  /* Temporary variables to hold state and coefficient values */
-   uint32_t numTaps = S->numTaps;                 /* Number of filter coefficients in the filter */
-   uint32_t i, tapCnt, blkCnt;                    /* Loop counters */
-   float32_t p0,p1,p2,p3,p4,p5,p6,p7;             /* Temporary product values */
-
-   /* S->pState points to state array which contains previous frame (numTaps - 1) samples */
-   /* pStateCurnt points to the location where the new input data should be written */
-   pStateCurnt = &(S->pState[(numTaps - 1u)]);
-
-   /* Apply loop unrolling and compute 8 output values simultaneously.  
-    * The variables acc0 ... acc7 hold output values that are being computed:  
-    *  
-    *    acc0 =  b[numTaps-1] * x[n-numTaps-1] + b[numTaps-2] * x[n-numTaps-2] + b[numTaps-3] * x[n-numTaps-3] +...+ b[0] * x[0]  
-    *    acc1 =  b[numTaps-1] * x[n-numTaps] +   b[numTaps-2] * x[n-numTaps-1] + b[numTaps-3] * x[n-numTaps-2] +...+ b[0] * x[1]  
-    *    acc2 =  b[numTaps-1] * x[n-numTaps+1] + b[numTaps-2] * x[n-numTaps] +   b[numTaps-3] * x[n-numTaps-1] +...+ b[0] * x[2]  
-    *    acc3 =  b[numTaps-1] * x[n-numTaps+2] + b[numTaps-2] * x[n-numTaps+1] + b[numTaps-3] * x[n-numTaps]   +...+ b[0] * x[3]  
-    */
-   blkCnt = blockSize >> 3;
-
-   /* First part of the processing with loop unrolling.  Compute 8 outputs at a time.  
-   ** a second loop below computes the remaining 1 to 7 samples. */
-   while(blkCnt > 0u)
-   {
-      /* Copy four new input samples into the state buffer */
-      *pStateCurnt++ = *pSrc++;
-      *pStateCurnt++ = *pSrc++;
-      *pStateCurnt++ = *pSrc++;
-      *pStateCurnt++ = *pSrc++;
-
-      /* Set all accumulators to zero */
-      acc0 = 0.0f;
-      acc1 = 0.0f;
-      acc2 = 0.0f;
-      acc3 = 0.0f;
-      acc4 = 0.0f;
-      acc5 = 0.0f;
-      acc6 = 0.0f;
-      acc7 = 0.0f;             
-
-      /* Initialize state pointer */
-      px = pState;
-
-      /* Initialize coeff pointer */
-      pb = (pCoeffs);          
-   
-      /* This is separated from the others to avoid 
-       * a call to __aeabi_memmove which would be slower
-       */
-      *pStateCurnt++ = *pSrc++;
-      *pStateCurnt++ = *pSrc++;
-      *pStateCurnt++ = *pSrc++;
-      *pStateCurnt++ = *pSrc++;
-
-      /* Read the first seven samples from the state buffer:  x[n-numTaps], x[n-numTaps-1], x[n-numTaps-2] */
-      x0 = *px++;
-      x1 = *px++;
-      x2 = *px++;
-      x3 = *px++;
-      x4 = *px++;
-      x5 = *px++;
-      x6 = *px++;
-
-      /* Loop unrolling.  Process 8 taps at a time. */
-      tapCnt = numTaps >> 3u;
-      
-      /* Loop over the number of taps.  Unroll by a factor of 8.  
-       ** Repeat until we've computed numTaps-8 coefficients. */
-      while(tapCnt > 0u)
-      {
-         /* Read the b[numTaps-1] coefficient */
-         c0 = *(pb++);
-
-         /* Read x[n-numTaps-3] sample */
-         x7 = *(px++);
-
-         /* acc0 +=  b[numTaps-1] * x[n-numTaps] */
-         p0 = x0 * c0;
-
-         /* acc1 +=  b[numTaps-1] * x[n-numTaps-1] */
-         p1 = x1 * c0;
-
-         /* acc2 +=  b[numTaps-1] * x[n-numTaps-2] */
-         p2 = x2 * c0;
-
-         /* acc3 +=  b[numTaps-1] * x[n-numTaps-3] */
-         p3 = x3 * c0;
-
-         /* acc4 +=  b[numTaps-1] * x[n-numTaps-4] */
-         p4 = x4 * c0;
-
-         /* acc1 +=  b[numTaps-1] * x[n-numTaps-5] */
-         p5 = x5 * c0;
-
-         /* acc2 +=  b[numTaps-1] * x[n-numTaps-6] */
-         p6 = x6 * c0;
-
-         /* acc3 +=  b[numTaps-1] * x[n-numTaps-7] */
-         p7 = x7 * c0;
-         
-         /* Read the b[numTaps-2] coefficient */
-         c0 = *(pb++);
-
-         /* Read x[n-numTaps-4] sample */
-         x0 = *(px++);
-         
-         acc0 += p0;
-         acc1 += p1;
-         acc2 += p2;
-         acc3 += p3;
-         acc4 += p4;
-         acc5 += p5;
-         acc6 += p6;
-         acc7 += p7;
-
-
-         /* Perform the multiply-accumulate */
-         p0 = x1 * c0;
-         p1 = x2 * c0;   
-         p2 = x3 * c0;   
-         p3 = x4 * c0;   
-         p4 = x5 * c0;   
-         p5 = x6 * c0;   
-         p6 = x7 * c0;   
-         p7 = x0 * c0;   
-         
-         /* Read the b[numTaps-3] coefficient */
-         c0 = *(pb++);
-
-         /* Read x[n-numTaps-5] sample */
-         x1 = *(px++);
-         
-         acc0 += p0;
-         acc1 += p1;
-         acc2 += p2;
-         acc3 += p3;
-         acc4 += p4;
-         acc5 += p5;
-         acc6 += p6;
-         acc7 += p7;
-
-         /* Perform the multiply-accumulates */      
-         p0 = x2 * c0;
-         p1 = x3 * c0;   
-         p2 = x4 * c0;   
-         p3 = x5 * c0;   
-         p4 = x6 * c0;   
-         p5 = x7 * c0;   
-         p6 = x0 * c0;   
-         p7 = x1 * c0;   
-
-         /* Read the b[numTaps-4] coefficient */
-         c0 = *(pb++);
-
-         /* Read x[n-numTaps-6] sample */
-         x2 = *(px++);
-         
-         acc0 += p0;
-         acc1 += p1;
-         acc2 += p2;
-         acc3 += p3;
-         acc4 += p4;
-         acc5 += p5;
-         acc6 += p6;
-         acc7 += p7;
-
-         /* Perform the multiply-accumulates */      
-         p0 = x3 * c0;
-         p1 = x4 * c0;   
-         p2 = x5 * c0;   
-         p3 = x6 * c0;   
-         p4 = x7 * c0;   
-         p5 = x0 * c0;   
-         p6 = x1 * c0;   
-         p7 = x2 * c0;   
-
-         /* Read the b[numTaps-4] coefficient */
-         c0 = *(pb++);
-
-         /* Read x[n-numTaps-6] sample */
-         x3 = *(px++);
-         
-         acc0 += p0;
-         acc1 += p1;
-         acc2 += p2;
-         acc3 += p3;
-         acc4 += p4;
-         acc5 += p5;
-         acc6 += p6;
-         acc7 += p7;
-
-         /* Perform the multiply-accumulates */      
-         p0 = x4 * c0;
-         p1 = x5 * c0;   
-         p2 = x6 * c0;   
-         p3 = x7 * c0;   
-         p4 = x0 * c0;   
-         p5 = x1 * c0;   
-         p6 = x2 * c0;   
-         p7 = x3 * c0;   
-
-         /* Read the b[numTaps-4] coefficient */
-         c0 = *(pb++);
-
-         /* Read x[n-numTaps-6] sample */
-         x4 = *(px++);
-         
-         acc0 += p0;
-         acc1 += p1;
-         acc2 += p2;
-         acc3 += p3;
-         acc4 += p4;
-         acc5 += p5;
-         acc6 += p6;
-         acc7 += p7;
-
-         /* Perform the multiply-accumulates */      
-         p0 = x5 * c0;
-         p1 = x6 * c0;   
-         p2 = x7 * c0;   
-         p3 = x0 * c0;   
-         p4 = x1 * c0;   
-         p5 = x2 * c0;   
-         p6 = x3 * c0;   
-         p7 = x4 * c0;   
-
-         /* Read the b[numTaps-4] coefficient */
-         c0 = *(pb++);
-
-         /* Read x[n-numTaps-6] sample */
-         x5 = *(px++);
-         
-         acc0 += p0;
-         acc1 += p1;
-         acc2 += p2;
-         acc3 += p3;
-         acc4 += p4;
-         acc5 += p5;
-         acc6 += p6;
-         acc7 += p7;
-
-         /* Perform the multiply-accumulates */      
-         p0 = x6 * c0;
-         p1 = x7 * c0;   
-         p2 = x0 * c0;   
-         p3 = x1 * c0;   
-         p4 = x2 * c0;   
-         p5 = x3 * c0;   
-         p6 = x4 * c0;   
-         p7 = x5 * c0;   
-
-         /* Read the b[numTaps-4] coefficient */
-         c0 = *(pb++);
-
-         /* Read x[n-numTaps-6] sample */
-         x6 = *(px++);
-         
-         acc0 += p0;
-         acc1 += p1;
-         acc2 += p2;
-         acc3 += p3;
-         acc4 += p4;
-         acc5 += p5;
-         acc6 += p6;
-         acc7 += p7;
-
-         /* Perform the multiply-accumulates */      
-         p0 = x7 * c0;
-         p1 = x0 * c0;   
-         p2 = x1 * c0;   
-         p3 = x2 * c0;   
-         p4 = x3 * c0;   
-         p5 = x4 * c0;   
-         p6 = x5 * c0;   
-         p7 = x6 * c0;   
-
-         tapCnt--;
-         
-         acc0 += p0;
-         acc1 += p1;
-         acc2 += p2;
-         acc3 += p3;
-         acc4 += p4;
-         acc5 += p5;
-         acc6 += p6;
-         acc7 += p7;
-      }
-
-      /* If the filter length is not a multiple of 8, compute the remaining filter taps */
-      tapCnt = numTaps % 0x8u;
-
-      while(tapCnt > 0u)
-      {
-         /* Read coefficients */
-         c0 = *(pb++);
-
-         /* Fetch 1 state variable */
-         x7 = *(px++);
-
-         /* Perform the multiply-accumulates */      
-         p0 = x0 * c0;
-         p1 = x1 * c0;   
-         p2 = x2 * c0;   
-         p3 = x3 * c0;   
-         p4 = x4 * c0;   
-         p5 = x5 * c0;   
-         p6 = x6 * c0;   
-         p7 = x7 * c0;   
-
-         /* Reuse the present sample states for next sample */
-         x0 = x1;
-         x1 = x2;
-         x2 = x3;
-         x3 = x4;
-         x4 = x5;
-         x5 = x6;
-         x6 = x7;
-         
-         acc0 += p0;
-         acc1 += p1;
-         acc2 += p2;
-         acc3 += p3;
-         acc4 += p4;
-         acc5 += p5;
-         acc6 += p6;
-         acc7 += p7;
-
-         /* Decrement the loop counter */
-         tapCnt--;
-      }
-
-      /* Advance the state pointer by 8 to process the next group of 8 samples */
-      pState = pState + 8;
-
-      /* The results in the 8 accumulators, store in the destination buffer. */
-      *pDst++ = acc0;
-      *pDst++ = acc1;
-      *pDst++ = acc2;
-      *pDst++ = acc3;
-      *pDst++ = acc4;
-      *pDst++ = acc5;
-      *pDst++ = acc6;
-      *pDst++ = acc7;
-
-      blkCnt--;
-   }
-
-   /* If the blockSize is not a multiple of 8, compute any remaining output samples here.  
-   ** No loop unrolling is used. */
-   blkCnt = blockSize % 0x8u;
-
-   while(blkCnt > 0u)
-   {
-      /* Copy one sample at a time into state buffer */
-      *pStateCurnt++ = *pSrc++;
-
-      /* Set the accumulator to zero */
-      acc0 = 0.0f;
-
-      /* Initialize state pointer */
-      px = pState;
-
-      /* Initialize Coefficient pointer */
-      pb = (pCoeffs);
-
-      i = numTaps;
-
-      /* Perform the multiply-accumulates */
-      do
-      {
-         acc0 += *px++ * *pb++;
-         i--;
-
-      } while(i > 0u);
-
-      /* The result is store in the destination buffer. */
-      *pDst++ = acc0;
-
-      /* Advance state pointer by 1 for the next sample */
-      pState = pState + 1;
-
-      blkCnt--;
-   }
-
-   /* Processing is complete.  
-   ** Now copy the last numTaps - 1 samples to the start of the state buffer.  
-   ** This prepares the state buffer for the next function call. */
-
-   /* Points to the start of the state buffer */
-   pStateCurnt = S->pState;
-
-   tapCnt = (numTaps - 1u) >> 2u;
-
-   /* copy data */
-   while(tapCnt > 0u)
-   {
-      *pStateCurnt++ = *pState++;
-      *pStateCurnt++ = *pState++;
-      *pStateCurnt++ = *pState++;
-      *pStateCurnt++ = *pState++;
-
-      /* Decrement the loop counter */
-      tapCnt--;
-   }
-
-   /* Calculate remaining number of copies */
-   tapCnt = (numTaps - 1u) % 0x4u;
-
-   /* Copy the remaining q31_t data */
-   while(tapCnt > 0u)
-   {
-      *pStateCurnt++ = *pState++;
-
-      /* Decrement the loop counter */
-      tapCnt--;
-   }
-}
diff --git a/templates/5_fir_differentiator.cpp b/templates/5_fir_differentiator.cpp
deleted file mode 100644 (file)
index 72415c6..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/**
- * 5_fir_differentiator.cpp
- * Written by Clyne Sullivan.
- *
- * Does an FIR differentiation on the incoming signal, so that the output is representative of the
- * rate of change of the input.
- * A scaling factor is applied so that the output's form is more clearly visible.
- */
-
-Sample *process_data(Samples samples)
-{
-    constexpr int scaling_factor = 4;
-       static Sample output[samples.size()];
-    static Sample prev = 2048;
-
-    // Compute the first output value using the saved sample.
-    output[0] = 2048 + ((samples[0] - prev) * scaling_factor);
-
-       for (unsigned int i = 1; i < samples.size(); i++) {
-        // Take the rate of change and scale it.
-        // 2048 is added as the output should be centered in the voltage range.
-               output[i] = 2048 + ((samples[i] - samples[i - 1]) * scaling_factor);
-    }
-
-       // Save the last sample for the next iteration.
-    prev = samples[samples.size() - 1];
-
-    return output;
-}
-
diff --git a/templates/6_iir_test.cpp b/templates/6_iir_test.cpp
deleted file mode 100644 (file)
index 116a680..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-Sample *process_data(Samples samples)
-{
-       constexpr float alpha = 0.7;
-
-       static Sample prev = 2048;
-
-       samples[0] = (1 - alpha) * samples[0] + alpha * prev;
-       for (unsigned int i = 1; i < samples.size(); i++)
-               samples[i] = (1 - alpha) * samples[i] + alpha * samples[i - 1];
-       prev = samples[samples.size() - 1];
-
-       return samples.data();
-}
diff --git a/templates/7_iir_echo.cpp b/templates/7_iir_echo.cpp
deleted file mode 100644 (file)
index 57e5605..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-Sample *process_data(Samples samples)
-{
-       constexpr float alpha = 0.75;
-       constexpr unsigned int D = 100;
-
-       static Sample output[samples.size()];
-       static Sample prev[D]; // prev[0] = output[0 - D]
-
-       // Do calculations with previous output
-       for (unsigned int i = 0; i < D; i++)
-               output[i] = samples[i] + alpha * (prev[i] - 2048);
-
-       // Do calculations with current samples
-       for (unsigned int i = D; i < samples.size(); i++)
-               output[i] = samples[i] + alpha * (output[i - D] - 2048);
-
-       // Save outputs for next computation
-       for (unsigned int i = 0; i < D; i++)
-               prev[i] = output[samples.size() - (D - i)];
-
-       return output;
-}