c@225
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
c@225
|
2
|
c@225
|
3 /*
|
c@225
|
4 QM DSP Library
|
c@225
|
5
|
c@225
|
6 Centre for Digital Music, Queen Mary, University of London.
|
c@225
|
7 This file copyright 2006 Martin Gasser.
|
c@309
|
8
|
c@309
|
9 This program is free software; you can redistribute it and/or
|
c@309
|
10 modify it under the terms of the GNU General Public License as
|
c@309
|
11 published by the Free Software Foundation; either version 2 of the
|
c@309
|
12 License, or (at your option) any later version. See the file
|
c@309
|
13 COPYING included with this distribution for more information.
|
c@225
|
14 */
|
c@225
|
15
|
c@225
|
16 #include "ChangeDetectionFunction.h"
|
c@225
|
17
|
c@225
|
18 ChangeDetectionFunction::ChangeDetectionFunction(ChangeDFConfig config) :
|
cannam@482
|
19 m_dFilterSigma(0.0), m_iFilterWidth(0)
|
c@225
|
20 {
|
cannam@482
|
21 setFilterWidth(config.smoothingWidth);
|
c@225
|
22 }
|
c@225
|
23
|
c@225
|
24 ChangeDetectionFunction::~ChangeDetectionFunction()
|
c@225
|
25 {
|
c@225
|
26 }
|
c@225
|
27
|
c@225
|
28 void ChangeDetectionFunction::setFilterWidth(const int iWidth)
|
c@225
|
29 {
|
cannam@482
|
30 m_iFilterWidth = iWidth*2+1;
|
cannam@482
|
31
|
cannam@482
|
32 // it is assumed that the gaussian is 0 outside of +/- FWHM
|
cannam@482
|
33 // => filter width = 2*FWHM = 2*2.3548*sigma
|
cannam@482
|
34 m_dFilterSigma = double(m_iFilterWidth) / double(2*2.3548);
|
cannam@482
|
35 m_vaGaussian.resize(m_iFilterWidth);
|
cannam@482
|
36
|
cannam@488
|
37 double dScale = 1.0 / (m_dFilterSigma*sqrt(2*M_PI));
|
cannam@482
|
38
|
cannam@482
|
39 for (int x = -(m_iFilterWidth-1)/2; x <= (m_iFilterWidth-1)/2; x++) {
|
cannam@482
|
40 double w = dScale * std::exp ( -(x*x)/(2*m_dFilterSigma*m_dFilterSigma) );
|
cannam@482
|
41 m_vaGaussian[x + (m_iFilterWidth-1)/2] = w;
|
cannam@482
|
42 }
|
cannam@482
|
43
|
c@225
|
44 #ifdef DEBUG_CHANGE_DETECTION_FUNCTION
|
cannam@482
|
45 std::cerr << "Filter sigma: " << m_dFilterSigma << std::endl;
|
cannam@482
|
46 std::cerr << "Filter width: " << m_iFilterWidth << std::endl;
|
c@225
|
47 #endif
|
c@225
|
48 }
|
c@225
|
49
|
c@225
|
50
|
c@225
|
51 ChangeDistance ChangeDetectionFunction::process(const TCSGram& rTCSGram)
|
c@225
|
52 {
|
cannam@482
|
53 ChangeDistance retVal;
|
cannam@482
|
54 retVal.resize(rTCSGram.getSize(), 0.0);
|
cannam@482
|
55
|
cannam@482
|
56 TCSGram smoothedTCSGram;
|
c@225
|
57
|
cannam@482
|
58 for (int iPosition = 0; iPosition < rTCSGram.getSize(); iPosition++) {
|
cannam@482
|
59
|
cannam@482
|
60 int iSkipLower = 0;
|
cannam@482
|
61
|
cannam@482
|
62 int iLowerPos = iPosition - (m_iFilterWidth-1)/2;
|
cannam@482
|
63 int iUpperPos = iPosition + (m_iFilterWidth-1)/2;
|
cannam@482
|
64
|
cannam@482
|
65 if (iLowerPos < 0) {
|
cannam@482
|
66 iSkipLower = -iLowerPos;
|
cannam@482
|
67 iLowerPos = 0;
|
cannam@482
|
68 }
|
cannam@482
|
69
|
cannam@482
|
70 if (iUpperPos >= rTCSGram.getSize()) {
|
cannam@482
|
71 int iMaxIndex = rTCSGram.getSize() - 1;
|
cannam@482
|
72 iUpperPos = iMaxIndex;
|
cannam@482
|
73 }
|
cannam@482
|
74
|
cannam@482
|
75 TCSVector smoothedVector;
|
c@225
|
76
|
cannam@482
|
77 // for every bin of the vector, calculate the smoothed value
|
cannam@482
|
78 for (int iPC = 0; iPC < 6; iPC++) {
|
c@225
|
79
|
cannam@482
|
80 size_t j = 0;
|
cannam@482
|
81 double dSmoothedValue = 0.0;
|
cannam@482
|
82 TCSVector rCV;
|
cannam@482
|
83
|
cannam@482
|
84 for (int i = iLowerPos; i <= iUpperPos; i++) {
|
cannam@482
|
85 rTCSGram.getTCSVector(i, rCV);
|
cannam@482
|
86 dSmoothedValue += m_vaGaussian[iSkipLower + j++] * rCV[iPC];
|
cannam@482
|
87 }
|
c@225
|
88
|
cannam@482
|
89 smoothedVector[iPC] = dSmoothedValue;
|
cannam@482
|
90 }
|
cannam@482
|
91
|
cannam@482
|
92 smoothedTCSGram.addTCSVector(smoothedVector);
|
cannam@482
|
93 }
|
c@225
|
94
|
cannam@482
|
95 for (int iPosition = 0; iPosition < rTCSGram.getSize(); iPosition++) {
|
cannam@482
|
96
|
cannam@482
|
97 /*
|
cannam@482
|
98 TODO: calculate a confidence measure for the current estimation
|
cannam@482
|
99 if the current estimate is not confident enough, look further into the future/the past
|
cannam@482
|
100 e.g., High frequency content, zero crossing rate, spectral flatness
|
cannam@482
|
101 */
|
cannam@482
|
102
|
cannam@482
|
103 TCSVector nextTCS;
|
cannam@482
|
104 TCSVector previousTCS;
|
cannam@482
|
105
|
cannam@482
|
106 int iWindow = 1;
|
c@225
|
107
|
cannam@482
|
108 // while (previousTCS.magnitude() < 0.1 && (iPosition-iWindow) > 0)
|
cannam@482
|
109 {
|
cannam@482
|
110 smoothedTCSGram.getTCSVector(iPosition-iWindow, previousTCS);
|
cannam@482
|
111 // std::cout << previousTCS.magnitude() << std::endl;
|
cannam@482
|
112 iWindow++;
|
cannam@482
|
113 }
|
cannam@482
|
114
|
cannam@482
|
115 iWindow = 1;
|
cannam@482
|
116
|
cannam@482
|
117 // while (nextTCS.magnitude() < 0.1 && (iPosition+iWindow) < (rTCSGram.getSize()-1) )
|
cannam@482
|
118 {
|
cannam@482
|
119 smoothedTCSGram.getTCSVector(iPosition+iWindow, nextTCS);
|
cannam@482
|
120 iWindow++;
|
cannam@482
|
121 }
|
c@225
|
122
|
cannam@482
|
123 double distance = 0.0;
|
cannam@482
|
124 // Euclidean distance
|
cannam@482
|
125 for (size_t j = 0; j < 6; j++) {
|
cannam@482
|
126 distance += std::pow(nextTCS[j] - previousTCS[j], 2.0);
|
cannam@482
|
127 }
|
cannam@482
|
128
|
cannam@482
|
129 retVal[iPosition] = std::pow(distance, 0.5);
|
cannam@482
|
130 }
|
cannam@482
|
131
|
cannam@482
|
132 return retVal;
|
c@225
|
133 }
|