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@275: std::cerr << "Filter sigma: " << m_dFilterSigma << std::endl; c@275: std::cerr << "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: }