c@225: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
c@225: 
c@225: /*
c@225:     QM DSP Library
c@225: 
c@225:     Centre for Digital Music, Queen Mary, University of London.
c@225:     This file copyright 2006 Martin Gasser.
c@225:     All rights reserved.
c@225: */
c@225: 
c@225: #include "ChangeDetectionFunction.h"
c@225: 
c@225: #ifndef PI
c@225: #define PI (3.14159265358979232846)
c@225: #endif
c@225: 
c@225: 
c@225: 
c@225: ChangeDetectionFunction::ChangeDetectionFunction(ChangeDFConfig config) :
c@225: 	m_dFilterSigma(0.0), m_iFilterWidth(0)
c@225: {
c@225: 	setFilterWidth(config.smoothingWidth);
c@225: }
c@225: 
c@225: ChangeDetectionFunction::~ChangeDetectionFunction()
c@225: {
c@225: }
c@225: 
c@225: void ChangeDetectionFunction::setFilterWidth(const int iWidth)
c@225: {
c@225: 	m_iFilterWidth = iWidth*2+1;
c@225: 	
c@225: 	// it is assumed that the gaussian is 0 outside of +/- FWHM
c@225: 	// => filter width = 2*FWHM = 2*2.3548*sigma
c@225: 	m_dFilterSigma = double(m_iFilterWidth) / double(2*2.3548);
c@225: 	m_vaGaussian.resize(m_iFilterWidth);
c@225: 	
c@225: 	double dScale = 1.0 / (m_dFilterSigma*sqrt(2*PI));
c@225: 	
c@225: 	for (int x = -(m_iFilterWidth-1)/2; x <= (m_iFilterWidth-1)/2; x++)
c@225: 	{
c@225: 		double w = dScale * std::exp ( -(x*x)/(2*m_dFilterSigma*m_dFilterSigma) );
c@225: 		m_vaGaussian[x + (m_iFilterWidth-1)/2] = w;
c@225: 	}
c@225: 	
c@225: #ifdef DEBUG_CHANGE_DETECTION_FUNCTION
c@225: 	std::cout << "Filter sigma: " << m_dFilterSigma << std::endl;
c@225: 	std::cout << "Filter width: " << m_iFilterWidth << std::endl;
c@225: #endif
c@225: }
c@225: 
c@225: 
c@225: ChangeDistance ChangeDetectionFunction::process(const TCSGram& rTCSGram)
c@225: {
c@225: 	ChangeDistance retVal;
c@225: 	retVal.resize(rTCSGram.getSize(), 0.0);
c@225: 	
c@225: 	TCSGram smoothedTCSGram;
c@225: 
c@225: 	for (int iPosition = 0; iPosition < rTCSGram.getSize(); iPosition++)
c@225: 	{
c@225: 		int iSkipLower = 0;
c@225: 	
c@225: 		int iLowerPos = iPosition - (m_iFilterWidth-1)/2;
c@225: 		int iUpperPos = iPosition + (m_iFilterWidth-1)/2;
c@225: 	
c@225: 		if (iLowerPos < 0)
c@225: 		{
c@225: 			iSkipLower = -iLowerPos;
c@225: 			iLowerPos = 0;
c@225: 		}
c@225: 	
c@225: 		if (iUpperPos >= rTCSGram.getSize())
c@225: 		{
c@225: 			int iMaxIndex = rTCSGram.getSize() - 1;
c@225: 			iUpperPos = iMaxIndex;
c@225: 		}
c@225: 	
c@225: 		TCSVector smoothedVector;
c@225: 
c@225: 		// for every bin of the vector, calculate the smoothed value
c@225: 		for (int iPC = 0; iPC < 6; iPC++)
c@225: 		{	
c@225: 			size_t j = 0;
c@225: 			double dSmoothedValue = 0.0;
c@225: 			TCSVector rCV;
c@225: 		
c@225: 			for (int i = iLowerPos; i <= iUpperPos; i++)
c@225: 			{
c@225: 				rTCSGram.getTCSVector(i, rCV);
c@225: 				dSmoothedValue += m_vaGaussian[iSkipLower + j++] * rCV[iPC];
c@225: 			}
c@225: 
c@225: 			smoothedVector[iPC] = dSmoothedValue;
c@225: 		}
c@225: 		
c@225: 		smoothedTCSGram.addTCSVector(smoothedVector);
c@225: 	}
c@225: 
c@225: 	for (int iPosition = 0; iPosition < rTCSGram.getSize(); iPosition++)
c@225: 	{
c@225: 		/*
c@225: 			TODO: calculate a confidence measure for the current estimation
c@225: 			if the current estimate is not confident enough, look further into the future/the past
c@225: 			e.g., High frequency content, zero crossing rate, spectral flatness
c@225: 		*/
c@225: 		
c@225: 		TCSVector nextTCS;
c@225: 		TCSVector previousTCS;
c@225: 		
c@225: 		int iWindow = 1;
c@225: 
c@225: 		// while (previousTCS.magnitude() < 0.1 && (iPosition-iWindow) > 0)
c@225: 		{
c@225: 			smoothedTCSGram.getTCSVector(iPosition-iWindow, previousTCS);
c@225: 			// std::cout << previousTCS.magnitude() << std::endl;
c@225: 			iWindow++;
c@225: 		}
c@225: 		
c@225: 		iWindow = 1;
c@225: 		
c@225: 		// while (nextTCS.magnitude() < 0.1 && (iPosition+iWindow) < (rTCSGram.getSize()-1) )
c@225: 		{
c@225: 			smoothedTCSGram.getTCSVector(iPosition+iWindow, nextTCS);
c@225: 			iWindow++;
c@225: 		}
c@225: 
c@225: 		double distance = 0.0;
c@225: 		// Euclidean distance
c@225: 		for (size_t j = 0; j < 6; j++)
c@225: 		{
c@225: 			distance += std::pow(nextTCS[j] - previousTCS[j], 2.0);
c@225: 		}
c@225: 	
c@225: 		retVal[iPosition] = std::pow(distance, 0.5);
c@225: 	}
c@225: 
c@225: 	return retVal;
c@225: }