Mercurial > hg > qm-dsp
view dsp/phasevocoder/PhaseVocoder.cpp @ 115:f3c69325cca2 pvoc
Do actual phase unwrapping in the phase vocoder!
author | Chris Cannam |
---|---|
date | Wed, 02 Oct 2013 15:05:34 +0100 |
parents | e5907ae6de17 |
children | 2020c73dc997 |
line wrap: on
line source
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ /* QM DSP Library Centre for Digital Music, Queen Mary, University of London. 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 published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. See the file COPYING included with this distribution for more information. */ #include "PhaseVocoder.h" #include "dsp/transforms/FFT.h" #include "maths/MathUtilities.h" #include <math.h> #include <iostream> using std::cerr; using std::endl; PhaseVocoder::PhaseVocoder(int n, int hop) : m_n(n), m_hop(hop) { m_fft = new FFTReal(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_unwrapped; delete [] m_phase; delete [] m_real; delete [] m_imag; delete m_fft; } void PhaseVocoder::FFTShift(double *src) { const int hs = m_n/2; for (int i = 0; i < hs; ++i) { double tmp = src[i]; src[i] = src[i + hs]; src[i + hs] = tmp; } } void PhaseVocoder::process(double *src, double *mag, double *theta, double *unwrapped) { FFTShift(src); m_fft->forward(src, m_real, m_imag); getMagnitudes(mag); getPhases(theta); unwrapPhases(theta, unwrapped); } 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::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) { 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]; } }