diff options
author | Paul Davis <paul@linuxaudiosystems.com> | 2011-03-02 12:37:39 +0000 |
---|---|---|
committer | Paul Davis <paul@linuxaudiosystems.com> | 2011-03-02 12:37:39 +0000 |
commit | 3deba1921bcf5bddd8bea9846a203c92b6c9239d (patch) | |
tree | 8b2e00405337396918ff28e282df14e958b84bb9 /libs/qm-dsp/dsp/tonal | |
parent | fa41cfef580b2c8c04adec5b47d6cfa415ca6251 (diff) |
add queen mary DSP library
git-svn-id: svn://localhost/ardour2/branches/3.0@9029 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs/qm-dsp/dsp/tonal')
-rw-r--r-- | libs/qm-dsp/dsp/tonal/ChangeDetectionFunction.cpp | 144 | ||||
-rw-r--r-- | libs/qm-dsp/dsp/tonal/ChangeDetectionFunction.h | 48 | ||||
-rw-r--r-- | libs/qm-dsp/dsp/tonal/TCSgram.cpp | 77 | ||||
-rw-r--r-- | libs/qm-dsp/dsp/tonal/TCSgram.h | 49 | ||||
-rw-r--r-- | libs/qm-dsp/dsp/tonal/TonalEstimator.cpp | 103 | ||||
-rw-r--r-- | libs/qm-dsp/dsp/tonal/TonalEstimator.h | 105 |
6 files changed, 526 insertions, 0 deletions
diff --git a/libs/qm-dsp/dsp/tonal/ChangeDetectionFunction.cpp b/libs/qm-dsp/dsp/tonal/ChangeDetectionFunction.cpp new file mode 100644 index 0000000000..bcc661dd1d --- /dev/null +++ b/libs/qm-dsp/dsp/tonal/ChangeDetectionFunction.cpp @@ -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; +} diff --git a/libs/qm-dsp/dsp/tonal/ChangeDetectionFunction.h b/libs/qm-dsp/dsp/tonal/ChangeDetectionFunction.h new file mode 100644 index 0000000000..3a84b3096f --- /dev/null +++ b/libs/qm-dsp/dsp/tonal/ChangeDetectionFunction.h @@ -0,0 +1,48 @@ +/* -*- 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. +*/ + +#ifndef _CHANGEDETECTIONFUNCTION_ +#define _CHANGEDETECTIONFUNCTION_ + +//#define DEBUG_CHANGE_DETECTION_FUNCTION 1 + +#include "TCSgram.h" + +#include <valarray> +using std::valarray; + +typedef valarray<double> ChangeDistance; + +struct ChangeDFConfig +{ + int smoothingWidth; +}; + +class ChangeDetectionFunction +{ +public: + ChangeDetectionFunction(ChangeDFConfig); + ~ChangeDetectionFunction(); + ChangeDistance process(const TCSGram& rTCSGram); +private: + void setFilterWidth(const int iWidth); + +private: + valarray<double> m_vaGaussian; + double m_dFilterSigma; + int m_iFilterWidth; +}; + +#endif // _CHANGDETECTIONFUNCTION_ diff --git a/libs/qm-dsp/dsp/tonal/TCSgram.cpp b/libs/qm-dsp/dsp/tonal/TCSgram.cpp new file mode 100644 index 0000000000..8840872576 --- /dev/null +++ b/libs/qm-dsp/dsp/tonal/TCSgram.cpp @@ -0,0 +1,77 @@ +/* -*- 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 "TCSgram.h" + +#include <valarray> +#include <cmath> +#include <iostream> +#include <limits> + +#include "maths/MathUtilities.h" + +TCSGram::TCSGram() : + m_uNumBins(6) +{ +} + +TCSGram::~TCSGram() +{ +} + + +void TCSGram::getTCSVector(int iPosition, TCSVector& rTCSVector) const +{ + if (iPosition < 0) + rTCSVector = TCSVector(); + else if (iPosition >= m_VectorList.size()) + rTCSVector = TCSVector(); + else + rTCSVector = m_VectorList[iPosition].second; +} + +long TCSGram::getTime(size_t uPosition) const +{ + return m_VectorList[uPosition].first; +} + + +void TCSGram::addTCSVector(const TCSVector& rTCSVector) +{ + size_t uSize = m_VectorList.size(); + long lMilliSeconds = static_cast<long>(uSize*m_dFrameDurationMS); + std::pair<long, TCSVector> p; + p.first = lMilliSeconds; + p.second = rTCSVector; + + m_VectorList.push_back(p); +} + +long TCSGram::getDuration() const +{ + size_t uSize = m_VectorList.size(); + return static_cast<long>(uSize*m_dFrameDurationMS); +} + +void TCSGram::printDebug() +{ + vectorlist_t::iterator vectorIterator = m_VectorList.begin(); + + while (vectorIterator != m_VectorList.end()) + { + vectorIterator->second.printDebug(); + vectorIterator++; + } +} diff --git a/libs/qm-dsp/dsp/tonal/TCSgram.h b/libs/qm-dsp/dsp/tonal/TCSgram.h new file mode 100644 index 0000000000..83e8c93f8b --- /dev/null +++ b/libs/qm-dsp/dsp/tonal/TCSgram.h @@ -0,0 +1,49 @@ +/* -*- 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. +*/ + +#ifndef _TCSGram_ +#define _TCSGram_ + +#include <vector> +#include <valarray> +#include <utility> + +#include "TonalEstimator.h" + +typedef std::vector<std::pair<long, TCSVector> > vectorlist_t; + +class TCSGram +{ +public: + TCSGram(); + ~TCSGram(); + void getTCSVector(int, TCSVector&) const; + void addTCSVector(const TCSVector&); + long getTime(size_t) const; + long getDuration() const; + void printDebug(); + int getSize() const { return m_VectorList.size(); } + void reserve(size_t uSize) { m_VectorList.reserve(uSize); } + void clear() { m_VectorList.clear(); } + void setFrameDuration(const double dFrameDurationMS) { m_dFrameDurationMS = dFrameDurationMS; } + void setNumBins(const unsigned int uNumBins) { m_uNumBins = uNumBins; } + void normalize(); +protected: + vectorlist_t m_VectorList; + unsigned int m_uNumBins; + double m_dFrameDurationMS; +}; + +#endif diff --git a/libs/qm-dsp/dsp/tonal/TonalEstimator.cpp b/libs/qm-dsp/dsp/tonal/TonalEstimator.cpp new file mode 100644 index 0000000000..16d1aa8995 --- /dev/null +++ b/libs/qm-dsp/dsp/tonal/TonalEstimator.cpp @@ -0,0 +1,103 @@ +/* -*- 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 "TonalEstimator.h" + +#include <cmath> +#include <iostream> + +#ifndef PI +#define PI (3.14159265358979232846) +#endif + +TonalEstimator::TonalEstimator() +{ + m_Basis.resize(6); + + int i = 0; + + + // circle of fifths + m_Basis[i].resize(12); + for (int iP = 0; iP < 12; iP++) + { + m_Basis[i][iP] = std::sin( (7.0 / 6.0) * iP * PI); + } + + i++; + + m_Basis[i].resize(12); + for (int iP = 0; iP < 12; iP++) + { + m_Basis[i][iP] = std::cos( (7.0 / 6.0) * iP * PI); + } + + i++; + + + // circle of major thirds + m_Basis[i].resize(12); + for (int iP = 0; iP < 12; iP++) + { + m_Basis[i][iP] = 0.6 * std::sin( (2.0 / 3.0) * iP * PI); + } + + i++; + + m_Basis[i].resize(12); + for (int iP = 0; iP < 12; iP++) + { + m_Basis[i][iP] = 0.6 * std::cos( (2.0 / 3.0) * iP * PI); + } + + i++; + + + // circle of minor thirds + m_Basis[i].resize(12); + for (int iP = 0; iP < 12; iP++) + { + m_Basis[i][iP] = 1.1 * std::sin( (3.0 / 2.0) * iP * PI); + } + + i++; + + m_Basis[i].resize(12); + for (int iP = 0; iP < 12; iP++) + { + m_Basis[i][iP] = 1.1 * std::cos( (3.0 / 2.0) * iP * PI); + } + +} + +TonalEstimator::~TonalEstimator() +{ +} + +TCSVector TonalEstimator::transform2TCS(const ChromaVector& rVector) +{ + TCSVector vaRetVal; + vaRetVal.resize(6, 0.0); + + for (int i = 0; i < 6; i++) + { + for (int iP = 0; iP < 12; iP++) + { + vaRetVal[i] += m_Basis[i][iP] * rVector[iP]; + } + } + + return vaRetVal; +} diff --git a/libs/qm-dsp/dsp/tonal/TonalEstimator.h b/libs/qm-dsp/dsp/tonal/TonalEstimator.h new file mode 100644 index 0000000000..f555ef9e3b --- /dev/null +++ b/libs/qm-dsp/dsp/tonal/TonalEstimator.h @@ -0,0 +1,105 @@ +/* -*- 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. +*/ + +#ifndef _TONALESTIMATOR_ +#define _TONALESTIMATOR_ + + +#include <valarray> +#include <numeric> +#include <algorithm> +#include <iostream> + +class ChromaVector : public std::valarray<double> +{ +public: + ChromaVector(size_t uSize = 12) : std::valarray<double>() + { resize(uSize, 0.0f); } + + virtual ~ChromaVector() {}; + + void printDebug() + { + for (int i = 0; i < size(); i++) + { + std::cout << (*this)[i] << ";"; + } + + std::cout << std::endl; + } + + void normalizeL1() + { + // normalize the chroma vector (L1 norm) + double dSum = 0.0; + + for (size_t i = 0; i < 12; (dSum += std::abs((*this)[i++]))) ; + for (size_t i = 0; i < 12; dSum > 0.0000001?((*this)[i] /= dSum):(*this)[i]=0.0, i++) ; + + } + + void clear() + { + for (size_t i = 0; i < 12; ++i) (*this)[i] = 0.0; + } + + +}; + +class TCSVector : public std::valarray<double> +{ +public: + TCSVector() : std::valarray<double>() + { resize(6, 0.0f); } + + virtual ~TCSVector() {}; + + void printDebug() + { + for (int i = 0; i < size(); i++) + { + std::cout << (*this)[i] << ";"; + } + + std::cout << std::endl; + } + + double magnitude() const + { + double dMag = 0.0; + + for (size_t i = 0; i < 6; i++) + { + dMag += std::pow((*this)[i], 2.0); + } + + return std::sqrt(dMag); + } + +}; + + + +class TonalEstimator +{ +public: + TonalEstimator(); + virtual ~TonalEstimator(); + TCSVector transform2TCS(const ChromaVector& rVector); +protected: + std::valarray< std::valarray<double> > m_Basis; +}; + +#endif // _TONALESTIMATOR_ |