annotate dsp/tonal/ChangeDetectionFunction.cpp @ 84:e5907ae6de17

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