c@380: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ c@380: c@380: /* c@380: QM DSP Library c@380: c@380: Centre for Digital Music, Queen Mary, University of London. c@380: c@380: This program is free software; you can redistribute it and/or c@380: modify it under the terms of the GNU General Public License as c@380: published by the Free Software Foundation; either version 2 of the c@380: License, or (at your option) any later version. See the file c@380: COPYING included with this distribution for more information. c@380: */ c@380: c@380: #include "DecimatorB.h" c@380: c@380: #include "maths/MathUtilities.h" c@380: c@380: #include c@380: c@380: using std::vector; c@380: c@380: DecimatorB::DecimatorB(int inLength, int decFactor) c@380: { c@380: m_inputLength = 0; c@380: m_outputLength = 0; c@380: m_decFactor = 1; c@380: m_aaBuffer = 0; c@380: m_tmpBuffer = 0; c@380: c@380: initialise(inLength, decFactor); c@380: } c@380: c@380: DecimatorB::~DecimatorB() c@380: { c@380: deInitialise(); c@380: } c@380: c@380: void DecimatorB::initialise(int inLength, int decFactor) c@380: { c@380: m_inputLength = inLength; c@380: m_decFactor = decFactor; c@380: m_outputLength = m_inputLength / m_decFactor; c@380: c@380: if (m_decFactor < 2 || !MathUtilities::isPowerOfTwo(m_decFactor)) { c@380: std::cerr << "ERROR: DecimatorB::initialise: Decimation factor must be a power of 2 and at least 2 (was: " << m_decFactor << ")" << std::endl; c@380: m_decFactor = 0; c@380: return; c@380: } c@380: c@380: if (m_inputLength % m_decFactor != 0) { c@380: std::cerr << "ERROR: DecimatorB::initialise: inLength must be a multiple of decimation factor (was: " << m_inputLength << ", factor is " << m_decFactor << ")" << std::endl; c@380: m_decFactor = 0; c@380: return; c@380: } c@380: c@380: m_aaBuffer = new double[m_inputLength]; c@380: m_tmpBuffer = new double[m_inputLength]; c@380: c@380: // Order 6 Butterworth lowpass filter c@380: // Calculated using e.g. MATLAB butter(6, 0.5, 'low') c@380: c@380: m_b[0] = 0.029588223638661; c@380: m_b[1] = 0.177529341831965; c@380: m_b[2] = 0.443823354579912; c@380: m_b[3] = 0.591764472773216; c@380: m_b[4] = 0.443823354579912; c@380: m_b[5] = 0.177529341831965; c@380: m_b[6] = 0.029588223638661; c@380: c@380: m_a[0] = 1.000000000000000; c@380: m_a[1] = 0.000000000000000; c@380: m_a[2] = 0.777695961855673; c@380: m_a[3] = 0.000000000000000; c@380: m_a[4] = 0.114199425062434; c@380: m_a[5] = 0.000000000000000; c@380: m_a[6] = 0.001750925956183; c@380: c@380: for (int factor = m_decFactor; factor > 1; factor /= 2) { c@380: m_o.push_back(vector(6, 0.0)); c@380: } c@380: } c@380: c@380: void DecimatorB::deInitialise() c@380: { c@380: delete [] m_aaBuffer; c@380: delete [] m_tmpBuffer; c@380: } c@380: c@380: void DecimatorB::doAntiAlias(const double *src, double *dst, int length, c@380: int filteridx) c@380: { c@380: vector &o = m_o[filteridx]; c@380: c@380: for (int i = 0; i < length; i++) { c@380: cannam@483: double input = src[i]; cannam@483: double output = input * m_b[0] + o[0]; c@380: cannam@483: o[0] = input * m_b[1] - output * m_a[1] + o[1]; cannam@483: o[1] = input * m_b[2] - output * m_a[2] + o[2]; cannam@483: o[2] = input * m_b[3] - output * m_a[3] + o[3]; cannam@483: o[3] = input * m_b[4] - output * m_a[4] + o[4]; cannam@483: o[4] = input * m_b[5] - output * m_a[5] + o[5]; cannam@483: o[5] = input * m_b[6] - output * m_a[6]; c@380: cannam@483: dst[i] = output; c@380: } c@380: } c@380: c@380: void DecimatorB::doProcess() c@380: { c@380: int filteridx = 0; c@380: int factorDone = 1; c@380: c@380: while (factorDone < m_decFactor) { c@380: c@380: doAntiAlias(m_tmpBuffer, m_aaBuffer, c@380: m_inputLength / factorDone, c@380: filteridx); c@380: c@380: filteridx ++; c@380: factorDone *= 2; c@380: c@380: for (int i = 0; i < m_inputLength / factorDone; ++i) { c@380: m_tmpBuffer[i] = m_aaBuffer[i * 2]; c@380: } c@380: } c@380: } c@380: c@380: void DecimatorB::process(const double *src, double *dst) c@380: { c@380: if (m_decFactor == 0) return; c@380: c@380: for (int i = 0; i < m_inputLength; ++i) { c@380: m_tmpBuffer[i] = src[i]; c@380: } c@380: c@380: doProcess(); c@380: c@380: for (int i = 0; i < m_outputLength; ++i) { c@380: dst[i] = m_tmpBuffer[i]; c@380: } c@380: } c@380: c@380: void DecimatorB::process(const float *src, float *dst) c@380: { c@380: if (m_decFactor == 0) return; c@380: c@380: for (int i = 0; i < m_inputLength; ++i) { c@380: m_tmpBuffer[i] = src[i]; c@380: } c@380: c@380: doProcess(); c@380: c@380: for (int i = 0; i < m_outputLength; ++i) { c@380: dst[i] = m_tmpBuffer[i]; c@380: } c@380: }