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