annotate dsp/tonal/ChangeDetectionFunction.cpp @ 309:d5014ab8b0e5

* Add GPL and README; some tidying
author Chris Cannam <c.cannam@qmul.ac.uk>
date Mon, 13 Dec 2010 14:55:28 +0000
parents cded679e12c2
children cbe668c7d724
rev   line source
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 #ifndef PI
c@225 19 #define PI (3.14159265358979232846)
c@225 20 #endif
c@225 21
c@225 22
c@225 23
c@225 24 ChangeDetectionFunction::ChangeDetectionFunction(ChangeDFConfig config) :
c@225 25 m_dFilterSigma(0.0), m_iFilterWidth(0)
c@225 26 {
c@225 27 setFilterWidth(config.smoothingWidth);
c@225 28 }
c@225 29
c@225 30 ChangeDetectionFunction::~ChangeDetectionFunction()
c@225 31 {
c@225 32 }
c@225 33
c@225 34 void ChangeDetectionFunction::setFilterWidth(const int iWidth)
c@225 35 {
c@225 36 m_iFilterWidth = iWidth*2+1;
c@225 37
c@225 38 // it is assumed that the gaussian is 0 outside of +/- FWHM
c@225 39 // => filter width = 2*FWHM = 2*2.3548*sigma
c@225 40 m_dFilterSigma = double(m_iFilterWidth) / double(2*2.3548);
c@225 41 m_vaGaussian.resize(m_iFilterWidth);
c@225 42
c@225 43 double dScale = 1.0 / (m_dFilterSigma*sqrt(2*PI));
c@225 44
c@225 45 for (int x = -(m_iFilterWidth-1)/2; x <= (m_iFilterWidth-1)/2; x++)
c@225 46 {
c@225 47 double w = dScale * std::exp ( -(x*x)/(2*m_dFilterSigma*m_dFilterSigma) );
c@225 48 m_vaGaussian[x + (m_iFilterWidth-1)/2] = w;
c@225 49 }
c@225 50
c@225 51 #ifdef DEBUG_CHANGE_DETECTION_FUNCTION
c@275 52 std::cerr << "Filter sigma: " << m_dFilterSigma << std::endl;
c@275 53 std::cerr << "Filter width: " << m_iFilterWidth << std::endl;
c@225 54 #endif
c@225 55 }
c@225 56
c@225 57
c@225 58 ChangeDistance ChangeDetectionFunction::process(const TCSGram& rTCSGram)
c@225 59 {
c@225 60 ChangeDistance retVal;
c@225 61 retVal.resize(rTCSGram.getSize(), 0.0);
c@225 62
c@225 63 TCSGram smoothedTCSGram;
c@225 64
c@225 65 for (int iPosition = 0; iPosition < rTCSGram.getSize(); iPosition++)
c@225 66 {
c@225 67 int iSkipLower = 0;
c@225 68
c@225 69 int iLowerPos = iPosition - (m_iFilterWidth-1)/2;
c@225 70 int iUpperPos = iPosition + (m_iFilterWidth-1)/2;
c@225 71
c@225 72 if (iLowerPos < 0)
c@225 73 {
c@225 74 iSkipLower = -iLowerPos;
c@225 75 iLowerPos = 0;
c@225 76 }
c@225 77
c@225 78 if (iUpperPos >= rTCSGram.getSize())
c@225 79 {
c@225 80 int iMaxIndex = rTCSGram.getSize() - 1;
c@225 81 iUpperPos = iMaxIndex;
c@225 82 }
c@225 83
c@225 84 TCSVector smoothedVector;
c@225 85
c@225 86 // for every bin of the vector, calculate the smoothed value
c@225 87 for (int iPC = 0; iPC < 6; iPC++)
c@225 88 {
c@225 89 size_t j = 0;
c@225 90 double dSmoothedValue = 0.0;
c@225 91 TCSVector rCV;
c@225 92
c@225 93 for (int i = iLowerPos; i <= iUpperPos; i++)
c@225 94 {
c@225 95 rTCSGram.getTCSVector(i, rCV);
c@225 96 dSmoothedValue += m_vaGaussian[iSkipLower + j++] * rCV[iPC];
c@225 97 }
c@225 98
c@225 99 smoothedVector[iPC] = dSmoothedValue;
c@225 100 }
c@225 101
c@225 102 smoothedTCSGram.addTCSVector(smoothedVector);
c@225 103 }
c@225 104
c@225 105 for (int iPosition = 0; iPosition < rTCSGram.getSize(); iPosition++)
c@225 106 {
c@225 107 /*
c@225 108 TODO: calculate a confidence measure for the current estimation
c@225 109 if the current estimate is not confident enough, look further into the future/the past
c@225 110 e.g., High frequency content, zero crossing rate, spectral flatness
c@225 111 */
c@225 112
c@225 113 TCSVector nextTCS;
c@225 114 TCSVector previousTCS;
c@225 115
c@225 116 int iWindow = 1;
c@225 117
c@225 118 // while (previousTCS.magnitude() < 0.1 && (iPosition-iWindow) > 0)
c@225 119 {
c@225 120 smoothedTCSGram.getTCSVector(iPosition-iWindow, previousTCS);
c@225 121 // std::cout << previousTCS.magnitude() << std::endl;
c@225 122 iWindow++;
c@225 123 }
c@225 124
c@225 125 iWindow = 1;
c@225 126
c@225 127 // while (nextTCS.magnitude() < 0.1 && (iPosition+iWindow) < (rTCSGram.getSize()-1) )
c@225 128 {
c@225 129 smoothedTCSGram.getTCSVector(iPosition+iWindow, nextTCS);
c@225 130 iWindow++;
c@225 131 }
c@225 132
c@225 133 double distance = 0.0;
c@225 134 // Euclidean distance
c@225 135 for (size_t j = 0; j < 6; j++)
c@225 136 {
c@225 137 distance += std::pow(nextTCS[j] - previousTCS[j], 2.0);
c@225 138 }
c@225 139
c@225 140 retVal[iPosition] = std::pow(distance, 0.5);
c@225 141 }
c@225 142
c@225 143 return retVal;
c@225 144 }