Split the filter code into a class.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Thu, 12 Mar 2015 19:00:28 +0000 (20:00 +0100)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Thu, 12 Mar 2015 19:00:28 +0000 (20:00 +0100)
Makefile
filter.cpp [new file with mode: 0644]
filter.h [new file with mode: 0644]
level.cpp

index fe8c404..a3cf95f 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -6,12 +6,12 @@ all: synth decode sync cleaner
 %.o: %.cpp
        $(CXX) -MMD -MP $(CPPFLAGS) $(CXXFLAGS) -o $@ -c $<
 
-OBJS=decode.o synth.o synth_main.o interpolate.o sync.o level.o
+OBJS=decode.o synth.o synth_main.o interpolate.o sync.o level.o filter.o
 
 DEPS=$(OBJS:.o=.d)
 -include $(DEPS)
 
-decode: interpolate.o audioreader.o decode.o level.o
+decode: interpolate.o audioreader.o decode.o level.o filter.o
        $(CXX) -o $@ $^ $(LDLIBS) $(LDFLAGS)
 
 synth: synth.o synth_main.o
diff --git a/filter.cpp b/filter.cpp
new file mode 100644 (file)
index 0000000..d8f9701
--- /dev/null
@@ -0,0 +1,25 @@
+#include <math.h>
+
+#include "filter.h"
+
+void Filter::reset()
+{
+       d0 = d1 = 0.0f;
+}
+
+Filter Filter::lpf(float cutoff_radians)
+{
+       float resonance = 1.0f / sqrt(2.0f);
+       float sn = sin(cutoff_radians), cs = cos(cutoff_radians);
+       float alpha = float(sn / (2 * resonance));
+
+       // coefficients for lowpass filter
+        float a0 = 1 + alpha;
+       float b0 = (1 - cs) * 0.5f;
+       float b1 = 1 - cs;
+       float b2 = b0;
+        float a1 = -2 * cs;
+        float a2 = 1 - alpha;
+
+       return Filter(a0, a1, a2, b0, b1, b2);
+}
diff --git a/filter.h b/filter.h
new file mode 100644 (file)
index 0000000..a67f98a
--- /dev/null
+++ b/filter.h
@@ -0,0 +1,26 @@
+#ifndef _FILTER_H
+#define _FILTER_H 1
+
+class Filter {
+public:
+       Filter(float a0, float a1, float a2, float b0, float b1, float b2)
+               : a1(a1 / a0), a2(a2 / a0), b0(b0 / a0), b1(b1 / a0), b2(b2 / a0), d0(0.0f), d1(0.0f) {}
+
+       inline float update(float in)
+       {
+               float out = b0*in + d0;
+               d0 = b1 * in - a1 * out + d1;
+               d1 = b2 * in - a2 * out;
+               return out;
+       }
+
+       void reset();
+
+       static Filter lpf(float cutoff_radians);
+
+private:
+       float a1, a2, b0, b1, b2;
+       float d0, d1;
+};
+
+#endif  // !defined(_FILTER_H)
index e95b48e..6e63d26 100644 (file)
--- a/level.cpp
+++ b/level.cpp
@@ -6,6 +6,8 @@
 #include <vector>
 #include <algorithm>
 
+#include "filter.h"
+
 // The frequency to filter on, in Hertz. Larger values makes the
 // compressor react faster, but if it is too large, you'll
 // ruin the waveforms themselves.
 // 6dB/oct per round.
 #define FILTER_DEPTH 4
 
-static float a1, a2, b0, b1, b2;
-static float d0, d1;
-
-static void filter_init(float cutoff_radians)
-{
-       float resonance = 1.0f / sqrt(2.0f);
-       float sn = sin(cutoff_radians), cs = cos(cutoff_radians);
-       float alpha = float(sn / (2 * resonance));
-
-       // coefficients for lowpass filter
-        float a0 = 1 + alpha;
-       b0 = (1 - cs) * 0.5f;
-       b1 = 1 - cs;
-       b2 = b0;
-        a1 = -2 * cs;
-        a2 = 1 - alpha;
-
-       b0 /= a0;
-       b1 /= a0;
-       b2 /= a0;
-       a1 /= a0;
-       a2 /= a0;
-
-       // reset filter delays
-       d0 = d1 = 0.0f;
-}
-
-static float filter_update(float in)
-{
-       float out = b0*in + d0;
-       d0 = b1 * in - a1 * out + d1;
-       d1 = b2 * in - a2 * out;
-       return out;
-}
-
 std::vector<float> level_samples(const std::vector<float> &pcm, float min_level, int sample_rate)
 {
        // filter forwards, then backwards (perfect phase filtering)
@@ -61,23 +28,23 @@ std::vector<float> level_samples(const std::vector<float> &pcm, float min_level,
        refiltered_samples.resize(pcm.size());
        leveled_samples.resize(pcm.size());
 
-       filter_init(M_PI * LPFILTER_FREQ / sample_rate);
+       Filter filter = Filter::lpf(M_PI * LPFILTER_FREQ / sample_rate);
        for (unsigned i = 0; i < pcm.size(); ++i) {
-               filtered_samples[i] = filter_update(fabs(pcm[i]));
+               filtered_samples[i] = filter.update(fabs(pcm[i]));
        }
-       filter_init(M_PI * LPFILTER_FREQ / sample_rate);
+       filter.reset();
        for (unsigned i = pcm.size(); i --> 0; ) {
-               refiltered_samples[i] = filter_update(filtered_samples[i]);
+               refiltered_samples[i] = filter.update(filtered_samples[i]);
        }
 
        for (int i = 1; i < FILTER_DEPTH; ++i) {
-               filter_init(M_PI * LPFILTER_FREQ / sample_rate);
+               filter.reset();
                for (unsigned i = 0; i < pcm.size(); ++i) {
-                       filtered_samples[i] = filter_update(refiltered_samples[i]);
+                       filtered_samples[i] = filter.update(refiltered_samples[i]);
                }
-               filter_init(M_PI * LPFILTER_FREQ / sample_rate);
+               filter.reset();
                for (unsigned i = pcm.size(); i --> 0; ) {
-                       refiltered_samples[i] = filter_update(filtered_samples[i]);
+                       refiltered_samples[i] = filter.update(filtered_samples[i]);
                }
        }