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