c@225: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ c@225: c@225: /* c@225: QM DSP Library c@225: c@225: Centre for Digital Music, Queen Mary, University of London. c@340: This file 2005-2006 Christian Landone, copyright 2013 QMUL. c@309: c@309: This program is free software; you can redistribute it and/or c@309: modify it under the terms of the GNU General Public License as c@309: published by the Free Software Foundation; either version 2 of the c@309: License, or (at your option) any later version. See the file c@309: COPYING included with this distribution for more information. c@225: */ c@225: c@225: #include "PhaseVocoder.h" c@225: #include "dsp/transforms/FFT.h" c@340: #include "maths/MathUtilities.h" c@225: #include c@225: c@344: #include c@344: c@340: #include c@340: using std::cerr; c@340: using std::endl; c@225: c@340: PhaseVocoder::PhaseVocoder(int n, int hop) : c@340: m_n(n), c@340: m_hop(hop) c@225: { c@289: m_fft = new FFTReal(m_n); c@344: m_time = new double[m_n]; c@340: m_real = new double[m_n]; c@340: m_imag = new double[m_n]; c@340: m_phase = new double[m_n/2 + 1]; c@340: m_unwrapped = new double[m_n/2 + 1]; c@340: c@340: for (int i = 0; i < m_n/2 + 1; ++i) { c@340: m_phase[i] = 0.0; c@340: m_unwrapped[i] = 0.0; c@340: } c@340: c@340: reset(); c@225: } c@225: c@225: PhaseVocoder::~PhaseVocoder() c@225: { c@344: delete[] m_unwrapped; c@344: delete[] m_phase; c@344: delete[] m_real; c@344: delete[] m_imag; c@344: delete[] m_time; c@289: delete m_fft; c@225: } c@225: c@340: void PhaseVocoder::FFTShift(double *src) c@225: { c@340: const int hs = m_n/2; c@280: for (int i = 0; i < hs; ++i) { c@280: double tmp = src[i]; c@280: src[i] = src[i + hs]; c@280: src[i + hs] = tmp; c@225: } c@225: } c@225: c@344: void PhaseVocoder::processTimeDomain(const double *src, c@344: double *mag, double *theta, c@344: double *unwrapped) c@225: { c@344: for (int i = 0; i < m_n; ++i) { c@344: m_time[i] = src[i]; c@344: } c@344: FFTShift(m_time); c@344: m_fft->forward(m_time, m_real, m_imag); c@344: getMagnitudes(mag); c@344: getPhases(theta); c@344: unwrapPhases(theta, unwrapped); c@344: } c@225: c@344: void PhaseVocoder::processFrequencyDomain(const double *reals, c@344: const double *imags, c@344: double *mag, double *theta, c@344: double *unwrapped) c@344: { c@344: for (int i = 0; i < m_n/2 + 1; ++i) { c@344: m_real[i] = reals[i]; c@344: m_imag[i] = imags[i]; c@344: } c@340: getMagnitudes(mag); c@340: getPhases(theta); c@340: unwrapPhases(theta, unwrapped); c@225: } c@225: c@340: void PhaseVocoder::reset() c@340: { c@340: for (int i = 0; i < m_n/2 + 1; ++i) { c@340: // m_phase stores the "previous" phase, so set to one step c@340: // behind so that a signal with initial phase at zero matches c@340: // the expected values. This is completely unnecessary for any c@340: // analytical purpose, it's just tidier. c@340: double omega = (2 * M_PI * m_hop * i) / m_n; c@340: m_phase[i] = -omega; c@340: m_unwrapped[i] = -omega; c@225: } c@225: } c@225: c@340: void PhaseVocoder::getMagnitudes(double *mag) c@340: { c@340: for (int i = 0; i < m_n/2 + 1; i++) { c@340: mag[i] = sqrt(m_real[i] * m_real[i] + m_imag[i] * m_imag[i]); c@340: } c@340: } c@340: c@340: void PhaseVocoder::getPhases(double *theta) c@225: { c@340: for (int i = 0; i < m_n/2 + 1; i++) { c@340: theta[i] = atan2(m_imag[i], m_real[i]); c@225: } c@225: } c@340: c@340: void PhaseVocoder::unwrapPhases(double *theta, double *unwrapped) c@340: { c@340: for (int i = 0; i < m_n/2 + 1; ++i) { c@340: c@340: double omega = (2 * M_PI * m_hop * i) / m_n; c@340: double expected = m_phase[i] + omega; c@340: double error = MathUtilities::princarg(theta[i] - expected); c@340: c@340: unwrapped[i] = m_unwrapped[i] + omega + error; c@340: c@340: m_phase[i] = theta[i]; c@340: m_unwrapped[i] = unwrapped[i]; c@340: } c@340: } c@340: