summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2014-07-15 10:28:06 +0100
committerCarl Hetherington <cth@carlh.net>2014-07-15 10:28:06 +0100
commite5f79c57e1123754b1325f964123fcb56a2572b3 (patch)
treef8beeb63f02378f51f7ec7bb0698784b18839bec /src
parent3c4eb194c031950165ab63785368784a38bd752d (diff)
Add basic windowed-sinc audio filters.
Diffstat (limited to 'src')
-rw-r--r--src/lib/audio_filter.cc133
-rw-r--r--src/lib/audio_filter.h80
-rw-r--r--src/lib/wscript2
3 files changed, 214 insertions, 1 deletions
diff --git a/src/lib/audio_filter.cc b/src/lib/audio_filter.cc
new file mode 100644
index 000000000..0cd2b18fb
--- /dev/null
+++ b/src/lib/audio_filter.cc
@@ -0,0 +1,133 @@
+/*
+ Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
+
+ 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
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <cmath>
+#include "audio_filter.h"
+#include "audio_buffers.h"
+
+using std::vector;
+using std::min;
+using boost::shared_ptr;
+
+vector<float>
+AudioFilter::sinc_blackman (float cutoff, bool invert) const
+{
+ vector<float> ir (_M + 1);
+
+ /* Impulse response */
+
+ for (int i = 0; i <= _M; ++i) {
+ if (i == (_M / 2)) {
+ ir[i] = 2 * M_PI * cutoff;
+ } else {
+ /* sinc */
+ ir[i] = sin (2 * M_PI * cutoff * (i - _M / 2)) / (i - _M / 2);
+ /* Blackman window */
+ ir[i] *= (0.42 - 0.5 * cos (2 * M_PI * i / _M) + 0.08 * cos (4 * M_PI * i / _M));
+ }
+ }
+
+ /* Normalise */
+
+ float sum = 0;
+ for (int i = 0; i <= _M; ++i) {
+ sum += ir[i];
+ }
+
+ for (int i = 0; i <= _M; ++i) {
+ ir[i] /= sum;
+ }
+
+ /* Frequency inversion (swapping low-pass for high-pass, or whatever) */
+
+ if (invert) {
+ for (int i = 0; i <= _M; ++i) {
+ ir[i] = -ir[i];
+ }
+ ir[_M / 2] += 1;
+ }
+
+ return ir;
+}
+
+shared_ptr<AudioBuffers>
+AudioFilter::run (shared_ptr<AudioBuffers> in)
+{
+ shared_ptr<AudioBuffers> out (new AudioBuffers (in->channels(), in->frames()));
+
+ if (!_tail) {
+ _tail.reset (new AudioBuffers (in->channels(), _M + 1));
+ _tail->make_silent ();
+ }
+
+ for (int i = 0; i < in->channels(); ++i) {
+ for (int j = 0; j < in->frames(); ++j) {
+ float s = 0;
+ for (int k = 0; k <= _M; ++k) {
+ if ((j - k) < 0) {
+ s += _tail->data(i)[j - k + _M + 1] * _ir[k];
+ } else {
+ s += in->data(i)[j - k] * _ir[k];
+ }
+ }
+
+ out->data(i)[j] = s;
+ }
+ }
+
+ int const amount = min (in->frames(), _tail->frames());
+ if (amount < _tail->frames ()) {
+ _tail->move (amount, 0, _tail->frames() - amount);
+ }
+ _tail->copy_from (in.get(), amount, in->frames() - amount, _tail->frames () - amount);
+
+ return out;
+}
+
+LowPassAudioFilter::LowPassAudioFilter (float transition_bandwidth, float cutoff)
+ : AudioFilter (transition_bandwidth)
+{
+ _ir = sinc_blackman (cutoff, false);
+}
+
+
+HighPassAudioFilter::HighPassAudioFilter (float transition_bandwidth, float cutoff)
+ : AudioFilter (transition_bandwidth)
+{
+ _ir = sinc_blackman (cutoff, true);
+}
+
+BandPassAudioFilter::BandPassAudioFilter (float transition_bandwidth, float lower, float higher)
+ : AudioFilter (transition_bandwidth)
+{
+ vector<float> lpf = sinc_blackman (lower, false);
+ vector<float> hpf = sinc_blackman (higher, true);
+
+ _ir.resize (_M + 1);
+ for (int i = 0; i <= _M; ++i) {
+ _ir[i] = lpf[i] + hpf[i];
+ }
+
+ /* We now have a band-stop, so invert for band-pass */
+ for (int i = 0; i <= _M; ++i) {
+ _ir[i] = -_ir[i];
+ }
+
+ _ir[_M / 2] += 1;
+}
diff --git a/src/lib/audio_filter.h b/src/lib/audio_filter.h
new file mode 100644
index 000000000..9dfcec58b
--- /dev/null
+++ b/src/lib/audio_filter.h
@@ -0,0 +1,80 @@
+/*
+ Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
+
+ 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
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <vector>
+#include <boost/shared_ptr.hpp>
+
+class AudioBuffers;
+class audio_filter_impulse_kernel_test;
+class audio_filter_impulse_input_test;
+
+class AudioFilter
+{
+public:
+ AudioFilter (float transition_bandwidth)
+ {
+ _M = 4 / transition_bandwidth;
+ if (_M % 2) {
+ ++_M;
+ }
+ }
+
+ boost::shared_ptr<AudioBuffers> run (boost::shared_ptr<AudioBuffers> in);
+
+protected:
+ friend class audio_filter_impulse_kernel_test;
+ friend class audio_filter_impulse_input_test;
+
+ std::vector<float> sinc_blackman (float cutoff, bool invert) const;
+
+ std::vector<float> _ir;
+ int _M;
+ boost::shared_ptr<AudioBuffers> _tail;
+};
+
+class LowPassAudioFilter : public AudioFilter
+{
+public:
+ /** Construct a windowed-sinc low-pass filter using the Blackman window.
+ * @param transition_bandwidth Transition bandwidth as a fraction of the sampling rate.
+ * @param cutoff Cutoff frequency as a fraction of the sampling rate.
+ */
+ LowPassAudioFilter (float transition_bandwidth, float cutoff);
+};
+
+class HighPassAudioFilter : public AudioFilter
+{
+public:
+ /** Construct a windowed-sinc high-pass filter using the Blackman window.
+ * @param transition_bandwidth Transition bandwidth as a fraction of the sampling rate.
+ * @param cutoff Cutoff frequency as a fraction of the sampling rate.
+ */
+ HighPassAudioFilter (float transition_bandwidth, float cutoff);
+};
+
+class BandPassAudioFilter : public AudioFilter
+{
+public:
+ /** Construct a windowed-sinc band-pass filter using the Blackman window.
+ * @param transition_bandwidth Transition bandwidth as a fraction of the sampling rate.
+ * @param lower Lower cutoff frequency as a fraction of the sampling rate.
+ * @param higher Higher cutoff frequency as a fraction of the sampling rate.
+ */
+ BandPassAudioFilter (float transition_bandwidth, float lower, float higher);
+};
diff --git a/src/lib/wscript b/src/lib/wscript
index 9c929a671..ee8a59c0b 100644
--- a/src/lib/wscript
+++ b/src/lib/wscript
@@ -7,6 +7,7 @@ sources = """
audio_buffers.cc
audio_content.cc
audio_decoder.cc
+ audio_filter.cc
audio_mapping.cc
audio_processor.cc
cinema.cc
@@ -73,7 +74,6 @@ sources = """
single_stream_audio_content.cc
sndfile_content.cc
sndfile_decoder.cc
- sox_audio_processor.cc
subrip.cc
subrip_content.cc
subrip_decoder.cc