diff dsp/tonal/ChangeDetectionFunction.cpp @ 0:d7116e3183f8

* Queen Mary C++ DSP library
author cannam
date Wed, 05 Apr 2006 17:35:59 +0000
parents
children 980b1a3b9cbe
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dsp/tonal/ChangeDetectionFunction.cpp	Wed Apr 05 17:35:59 2006 +0000
@@ -0,0 +1,139 @@
+/* -*- 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.
+    All rights reserved.
+*/
+
+#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::cout << "Filter sigma: " << m_dFilterSigma << std::endl;
+	std::cout << "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;
+}