Mercurial > hg > qm-dsp
comparison 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 |
comparison
equal
deleted
inserted
replaced
339:9c8ee77db9de | 340:c99d83236f0d |
---|---|
2 | 2 |
3 /* | 3 /* |
4 QM DSP Library | 4 QM DSP Library |
5 | 5 |
6 Centre for Digital Music, Queen Mary, University of London. | 6 Centre for Digital Music, Queen Mary, University of London. |
7 This file 2005-2006 Christian Landone. | 7 This file 2005-2006 Christian Landone, copyright 2013 QMUL. |
8 | 8 |
9 This program is free software; you can redistribute it and/or | 9 This program is free software; you can redistribute it and/or |
10 modify it under the terms of the GNU General Public License as | 10 modify it under the terms of the GNU General Public License as |
11 published by the Free Software Foundation; either version 2 of the | 11 published by the Free Software Foundation; either version 2 of the |
12 License, or (at your option) any later version. See the file | 12 License, or (at your option) any later version. See the file |
13 COPYING included with this distribution for more information. | 13 COPYING included with this distribution for more information. |
14 */ | 14 */ |
15 | 15 |
16 #include "PhaseVocoder.h" | 16 #include "PhaseVocoder.h" |
17 #include "dsp/transforms/FFT.h" | 17 #include "dsp/transforms/FFT.h" |
18 #include "maths/MathUtilities.h" | |
18 #include <math.h> | 19 #include <math.h> |
19 | 20 |
20 ////////////////////////////////////////////////////////////////////// | 21 #include <iostream> |
21 // Construction/Destruction | 22 using std::cerr; |
22 ////////////////////////////////////////////////////////////////////// | 23 using std::endl; |
23 | 24 |
24 PhaseVocoder::PhaseVocoder(unsigned int n) : | 25 PhaseVocoder::PhaseVocoder(int n, int hop) : |
25 m_n(n) | 26 m_n(n), |
27 m_hop(hop) | |
26 { | 28 { |
27 m_fft = new FFTReal(m_n); | 29 m_fft = new FFTReal(m_n); |
28 m_realOut = new double[m_n]; | 30 m_real = new double[m_n]; |
29 m_imagOut = new double[m_n]; | 31 m_imag = new double[m_n]; |
32 m_phase = new double[m_n/2 + 1]; | |
33 m_unwrapped = new double[m_n/2 + 1]; | |
34 | |
35 for (int i = 0; i < m_n/2 + 1; ++i) { | |
36 m_phase[i] = 0.0; | |
37 m_unwrapped[i] = 0.0; | |
38 } | |
39 | |
40 reset(); | |
30 } | 41 } |
31 | 42 |
32 PhaseVocoder::~PhaseVocoder() | 43 PhaseVocoder::~PhaseVocoder() |
33 { | 44 { |
34 delete [] m_realOut; | 45 delete [] m_unwrapped; |
35 delete [] m_imagOut; | 46 delete [] m_phase; |
47 delete [] m_real; | |
48 delete [] m_imag; | |
36 delete m_fft; | 49 delete m_fft; |
37 } | 50 } |
38 | 51 |
39 void PhaseVocoder::FFTShift(unsigned int size, double *src) | 52 void PhaseVocoder::FFTShift(double *src) |
40 { | 53 { |
41 const int hs = size/2; | 54 const int hs = m_n/2; |
42 for (int i = 0; i < hs; ++i) { | 55 for (int i = 0; i < hs; ++i) { |
43 double tmp = src[i]; | 56 double tmp = src[i]; |
44 src[i] = src[i + hs]; | 57 src[i] = src[i + hs]; |
45 src[i + hs] = tmp; | 58 src[i + hs] = tmp; |
46 } | 59 } |
47 } | 60 } |
48 | 61 |
49 void PhaseVocoder::process(double *src, double *mag, double *theta) | 62 void PhaseVocoder::process(double *src, double *mag, double *theta, |
63 double *unwrapped) | |
50 { | 64 { |
51 FFTShift( m_n, src); | 65 FFTShift(src); |
52 | 66 |
53 m_fft->process(0, src, m_realOut, m_imagOut); | 67 m_fft->forward(src, m_real, m_imag); |
54 | 68 |
55 getMagnitude( m_n/2, mag, m_realOut, m_imagOut); | 69 getMagnitudes(mag); |
56 getPhase( m_n/2, theta, m_realOut, m_imagOut); | 70 getPhases(theta); |
71 unwrapPhases(theta, unwrapped); | |
57 } | 72 } |
58 | 73 |
59 void PhaseVocoder::getMagnitude(unsigned int size, double *mag, double *real, double *imag) | 74 void PhaseVocoder::reset() |
60 { | 75 { |
61 unsigned int j; | 76 for (int i = 0; i < m_n/2 + 1; ++i) { |
62 | 77 // m_phase stores the "previous" phase, so set to one step |
63 for( j = 0; j < size; j++) | 78 // behind so that a signal with initial phase at zero matches |
64 { | 79 // the expected values. This is completely unnecessary for any |
65 mag[ j ] = sqrt( real[ j ] * real[ j ] + imag[ j ] * imag[ j ]); | 80 // analytical purpose, it's just tidier. |
81 double omega = (2 * M_PI * m_hop * i) / m_n; | |
82 m_phase[i] = -omega; | |
83 m_unwrapped[i] = -omega; | |
66 } | 84 } |
67 } | 85 } |
68 | 86 |
69 void PhaseVocoder::getPhase(unsigned int size, double *theta, double *real, double *imag) | 87 void PhaseVocoder::getMagnitudes(double *mag) |
88 { | |
89 for (int i = 0; i < m_n/2 + 1; i++) { | |
90 mag[i] = sqrt(m_real[i] * m_real[i] + m_imag[i] * m_imag[i]); | |
91 } | |
92 } | |
93 | |
94 void PhaseVocoder::getPhases(double *theta) | |
70 { | 95 { |
71 unsigned int k; | 96 for (int i = 0; i < m_n/2 + 1; i++) { |
72 | 97 theta[i] = atan2(m_imag[i], m_real[i]); |
73 // Phase Angle "matlab" style | |
74 //Watch out for quadrant mapping !!! | |
75 for( k = 0; k < size; k++) | |
76 { | |
77 theta[ k ] = atan2( -imag[ k ], real[ k ]); | |
78 } | 98 } |
79 } | 99 } |
100 | |
101 void PhaseVocoder::unwrapPhases(double *theta, double *unwrapped) | |
102 { | |
103 cerr << "PhaseVocoder::unwrapPhases" << endl; | |
104 | |
105 for (int i = 0; i < m_n/2 + 1; ++i) { | |
106 | |
107 double omega = (2 * M_PI * m_hop * i) / m_n; | |
108 double expected = m_phase[i] + omega; | |
109 double error = MathUtilities::princarg(theta[i] - expected); | |
110 | |
111 unwrapped[i] = m_unwrapped[i] + omega + error; | |
112 | |
113 cerr << "i = " << i << ", instantaneous phase = " << theta[i] << ", prev phase = " << m_phase[i] << ", omega = " << omega << ", expected = " << expected << ", error = " << error << ", unwrapped = " << unwrapped[i] << endl; | |
114 | |
115 m_phase[i] = theta[i]; | |
116 m_unwrapped[i] = unwrapped[i]; | |
117 } | |
118 } | |
119 |