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