/* -*- 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; }