Mercurial > hg > qm-dsp
diff dsp/phasevocoder/PhaseVocoder.cpp @ 340:c99d83236f0d
Do actual phase unwrapping in the phase vocoder!
author | Chris Cannam <c.cannam@qmul.ac.uk> |
---|---|
date | Wed, 02 Oct 2013 15:05:34 +0100 |
parents | d5014ab8b0e5 |
children | 2020c73dc997 |
line wrap: on
line diff
--- a/dsp/phasevocoder/PhaseVocoder.cpp Wed Oct 02 15:04:38 2013 +0100 +++ b/dsp/phasevocoder/PhaseVocoder.cpp Wed Oct 02 15:05:34 2013 +0100 @@ -4,7 +4,7 @@ QM DSP Library Centre for Digital Music, Queen Mary, University of London. - This file 2005-2006 Christian Landone. + This file 2005-2006 Christian Landone, copyright 2013 QMUL. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -15,30 +15,43 @@ #include "PhaseVocoder.h" #include "dsp/transforms/FFT.h" +#include "maths/MathUtilities.h" #include <math.h> -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// +#include <iostream> +using std::cerr; +using std::endl; -PhaseVocoder::PhaseVocoder(unsigned int n) : - m_n(n) +PhaseVocoder::PhaseVocoder(int n, int hop) : + m_n(n), + m_hop(hop) { m_fft = new FFTReal(m_n); - m_realOut = new double[m_n]; - m_imagOut = new double[m_n]; + m_real = new double[m_n]; + m_imag = new double[m_n]; + m_phase = new double[m_n/2 + 1]; + m_unwrapped = new double[m_n/2 + 1]; + + for (int i = 0; i < m_n/2 + 1; ++i) { + m_phase[i] = 0.0; + m_unwrapped[i] = 0.0; + } + + reset(); } PhaseVocoder::~PhaseVocoder() { - delete [] m_realOut; - delete [] m_imagOut; + delete [] m_unwrapped; + delete [] m_phase; + delete [] m_real; + delete [] m_imag; delete m_fft; } -void PhaseVocoder::FFTShift(unsigned int size, double *src) +void PhaseVocoder::FFTShift(double *src) { - const int hs = size/2; + const int hs = m_n/2; for (int i = 0; i < hs; ++i) { double tmp = src[i]; src[i] = src[i + hs]; @@ -46,34 +59,61 @@ } } -void PhaseVocoder::process(double *src, double *mag, double *theta) +void PhaseVocoder::process(double *src, double *mag, double *theta, + double *unwrapped) { - FFTShift( m_n, src); + FFTShift(src); - m_fft->process(0, src, m_realOut, m_imagOut); + m_fft->forward(src, m_real, m_imag); - getMagnitude( m_n/2, mag, m_realOut, m_imagOut); - getPhase( m_n/2, theta, m_realOut, m_imagOut); + getMagnitudes(mag); + getPhases(theta); + unwrapPhases(theta, unwrapped); } -void PhaseVocoder::getMagnitude(unsigned int size, double *mag, double *real, double *imag) -{ - unsigned int j; - - for( j = 0; j < size; j++) - { - mag[ j ] = sqrt( real[ j ] * real[ j ] + imag[ j ] * imag[ j ]); +void PhaseVocoder::reset() +{ + for (int i = 0; i < m_n/2 + 1; ++i) { + // m_phase stores the "previous" phase, so set to one step + // behind so that a signal with initial phase at zero matches + // the expected values. This is completely unnecessary for any + // analytical purpose, it's just tidier. + double omega = (2 * M_PI * m_hop * i) / m_n; + m_phase[i] = -omega; + m_unwrapped[i] = -omega; } } -void PhaseVocoder::getPhase(unsigned int size, double *theta, double *real, double *imag) +void PhaseVocoder::getMagnitudes(double *mag) +{ + for (int i = 0; i < m_n/2 + 1; i++) { + mag[i] = sqrt(m_real[i] * m_real[i] + m_imag[i] * m_imag[i]); + } +} + +void PhaseVocoder::getPhases(double *theta) { - unsigned int k; - - // Phase Angle "matlab" style - //Watch out for quadrant mapping !!! - for( k = 0; k < size; k++) - { - theta[ k ] = atan2( -imag[ k ], real[ k ]); + for (int i = 0; i < m_n/2 + 1; i++) { + theta[i] = atan2(m_imag[i], m_real[i]); } } + +void PhaseVocoder::unwrapPhases(double *theta, double *unwrapped) +{ + cerr << "PhaseVocoder::unwrapPhases" << endl; + + for (int i = 0; i < m_n/2 + 1; ++i) { + + double omega = (2 * M_PI * m_hop * i) / m_n; + double expected = m_phase[i] + omega; + double error = MathUtilities::princarg(theta[i] - expected); + + unwrapped[i] = m_unwrapped[i] + omega + error; + + cerr << "i = " << i << ", instantaneous phase = " << theta[i] << ", prev phase = " << m_phase[i] << ", omega = " << omega << ", expected = " << expected << ", error = " << error << ", unwrapped = " << unwrapped[i] << endl; + + m_phase[i] = theta[i]; + m_unwrapped[i] = unwrapped[i]; + } +} +