add queen mary DSP library
git-svn-id: svn://localhost/ardour2/branches/3.0@9029 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
144
libs/qm-dsp/dsp/tonal/ChangeDetectionFunction.cpp
Normal file
144
libs/qm-dsp/dsp/tonal/ChangeDetectionFunction.cpp
Normal file
@@ -0,0 +1,144 @@
|
||||
/* -*- 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;
|
||||
}
|
||||
Reference in New Issue
Block a user