cannam@0: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ cannam@0: cannam@0: /* cannam@0: QM DSP Library cannam@0: cannam@0: Centre for Digital Music, Queen Mary, University of London. cannam@0: This file copyright 2006 Martin Gasser. Chris@84: Chris@84: This program is free software; you can redistribute it and/or Chris@84: modify it under the terms of the GNU General Public License as Chris@84: published by the Free Software Foundation; either version 2 of the Chris@84: License, or (at your option) any later version. See the file Chris@84: COPYING included with this distribution for more information. cannam@0: */ cannam@0: cannam@0: #include "ChangeDetectionFunction.h" cannam@0: cannam@0: #ifndef PI cannam@0: #define PI (3.14159265358979232846) cannam@0: #endif cannam@0: cannam@0: cannam@0: cannam@0: ChangeDetectionFunction::ChangeDetectionFunction(ChangeDFConfig config) : cannam@0: m_dFilterSigma(0.0), m_iFilterWidth(0) cannam@0: { cannam@0: setFilterWidth(config.smoothingWidth); cannam@0: } cannam@0: cannam@0: ChangeDetectionFunction::~ChangeDetectionFunction() cannam@0: { cannam@0: } cannam@0: cannam@0: void ChangeDetectionFunction::setFilterWidth(const int iWidth) cannam@0: { cannam@0: m_iFilterWidth = iWidth*2+1; cannam@0: cannam@0: // it is assumed that the gaussian is 0 outside of +/- FWHM cannam@0: // => filter width = 2*FWHM = 2*2.3548*sigma cannam@0: m_dFilterSigma = double(m_iFilterWidth) / double(2*2.3548); cannam@0: m_vaGaussian.resize(m_iFilterWidth); cannam@0: cannam@0: double dScale = 1.0 / (m_dFilterSigma*sqrt(2*PI)); cannam@0: cannam@0: for (int x = -(m_iFilterWidth-1)/2; x <= (m_iFilterWidth-1)/2; x++) cannam@0: { cannam@0: double w = dScale * std::exp ( -(x*x)/(2*m_dFilterSigma*m_dFilterSigma) ); cannam@0: m_vaGaussian[x + (m_iFilterWidth-1)/2] = w; cannam@0: } cannam@0: cannam@0: #ifdef DEBUG_CHANGE_DETECTION_FUNCTION cannam@50: std::cerr << "Filter sigma: " << m_dFilterSigma << std::endl; cannam@50: std::cerr << "Filter width: " << m_iFilterWidth << std::endl; cannam@0: #endif cannam@0: } cannam@0: cannam@0: cannam@0: ChangeDistance ChangeDetectionFunction::process(const TCSGram& rTCSGram) cannam@0: { cannam@0: ChangeDistance retVal; cannam@0: retVal.resize(rTCSGram.getSize(), 0.0); cannam@0: cannam@0: TCSGram smoothedTCSGram; cannam@0: cannam@0: for (int iPosition = 0; iPosition < rTCSGram.getSize(); iPosition++) cannam@0: { cannam@0: int iSkipLower = 0; cannam@0: cannam@0: int iLowerPos = iPosition - (m_iFilterWidth-1)/2; cannam@0: int iUpperPos = iPosition + (m_iFilterWidth-1)/2; cannam@0: cannam@0: if (iLowerPos < 0) cannam@0: { cannam@0: iSkipLower = -iLowerPos; cannam@0: iLowerPos = 0; cannam@0: } cannam@0: cannam@0: if (iUpperPos >= rTCSGram.getSize()) cannam@0: { cannam@0: int iMaxIndex = rTCSGram.getSize() - 1; cannam@0: iUpperPos = iMaxIndex; cannam@0: } cannam@0: cannam@0: TCSVector smoothedVector; cannam@0: cannam@0: // for every bin of the vector, calculate the smoothed value cannam@0: for (int iPC = 0; iPC < 6; iPC++) cannam@0: { cannam@0: size_t j = 0; cannam@0: double dSmoothedValue = 0.0; cannam@0: TCSVector rCV; cannam@0: cannam@0: for (int i = iLowerPos; i <= iUpperPos; i++) cannam@0: { cannam@0: rTCSGram.getTCSVector(i, rCV); cannam@0: dSmoothedValue += m_vaGaussian[iSkipLower + j++] * rCV[iPC]; cannam@0: } cannam@0: cannam@0: smoothedVector[iPC] = dSmoothedValue; cannam@0: } cannam@0: cannam@0: smoothedTCSGram.addTCSVector(smoothedVector); cannam@0: } cannam@0: cannam@0: for (int iPosition = 0; iPosition < rTCSGram.getSize(); iPosition++) cannam@0: { cannam@0: /* cannam@0: TODO: calculate a confidence measure for the current estimation cannam@0: if the current estimate is not confident enough, look further into the future/the past cannam@0: e.g., High frequency content, zero crossing rate, spectral flatness cannam@0: */ cannam@0: cannam@0: TCSVector nextTCS; cannam@0: TCSVector previousTCS; cannam@0: cannam@0: int iWindow = 1; cannam@0: cannam@0: // while (previousTCS.magnitude() < 0.1 && (iPosition-iWindow) > 0) cannam@0: { cannam@0: smoothedTCSGram.getTCSVector(iPosition-iWindow, previousTCS); cannam@0: // std::cout << previousTCS.magnitude() << std::endl; cannam@0: iWindow++; cannam@0: } cannam@0: cannam@0: iWindow = 1; cannam@0: cannam@0: // while (nextTCS.magnitude() < 0.1 && (iPosition+iWindow) < (rTCSGram.getSize()-1) ) cannam@0: { cannam@0: smoothedTCSGram.getTCSVector(iPosition+iWindow, nextTCS); cannam@0: iWindow++; cannam@0: } cannam@0: cannam@0: double distance = 0.0; cannam@0: // Euclidean distance cannam@0: for (size_t j = 0; j < 6; j++) cannam@0: { cannam@0: distance += std::pow(nextTCS[j] - previousTCS[j], 2.0); cannam@0: } cannam@0: cannam@0: retVal[iPosition] = std::pow(distance, 0.5); cannam@0: } cannam@0: cannam@0: return retVal; cannam@0: }