annotate NoveltyCurveProcessor.cpp @ 55:7a29d9ecd7d6

Added tag v1.0 for changeset 180624d62a4c
author Chris Cannam
date Thu, 16 Oct 2014 14:22:15 +0100
parents 4cf2d163127b
children
rev   line source
Chris@43 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@43 2
Chris@43 3 /*
Chris@43 4 Vamp Tempogram Plugin
Chris@43 5 Carl Bussey, Centre for Digital Music, Queen Mary University of London
Chris@43 6 Copyright 2014 Queen Mary University of London.
Chris@43 7
Chris@43 8 This program is free software; you can redistribute it and/or
Chris@43 9 modify it under the terms of the GNU General Public License as
Chris@43 10 published by the Free Software Foundation; either version 2 of the
Chris@43 11 License, or (at your option) any later version. See the file
Chris@43 12 COPYING included with this distribution for more information.
Chris@43 13 */
c@5 14
c@11 15 //Spectrogram dimensions should be flipped?
c@11 16
c@14 17 #include "NoveltyCurveProcessor.h"
c@5 18 using namespace std;
c@5 19
c@22 20 NoveltyCurveProcessor::NoveltyCurveProcessor(const float &samplingFrequency, const size_t &fftLength, const size_t &compressionConstant) :
c@5 21 m_samplingFrequency(samplingFrequency),
c@7 22 m_fftLength(fftLength),
c@7 23 m_blockSize(fftLength/2 + 1),
c@5 24 m_compressionConstant(compressionConstant),
c@5 25 m_numberOfBands(5),
c@13 26 m_pBandBoundaries(0),
c@13 27 m_pBandSum(0)
c@5 28 {
c@5 29 initialise();
c@5 30 }
c@5 31
c@14 32 NoveltyCurveProcessor::~NoveltyCurveProcessor(){
c@5 33 cleanup();
c@5 34 }
c@5 35
c@9 36 //allocate all space and set variable
c@5 37 void
c@14 38 NoveltyCurveProcessor::initialise(){
c@5 39
c@13 40 // for bandwise processing, the band is split into 5 bands. m_pBandBoundaries contains the upper and lower bin boundaries for each band.
c@13 41 m_pBandBoundaries = new int[m_numberOfBands+1];
c@13 42 m_pBandBoundaries[0] = 0;
c@13 43 for (unsigned int band = 1; band < m_numberOfBands; band++){
c@13 44 float lowFreq = 500*pow(2.5, (int)band-1);
c@13 45 m_pBandBoundaries[band] = m_fftLength*lowFreq/m_samplingFrequency;
Chris@33 46 if (m_pBandBoundaries[band] > (int)m_blockSize) {
Chris@33 47 m_pBandBoundaries[band] = m_blockSize;
Chris@33 48 }
c@5 49 }
c@13 50 m_pBandBoundaries[m_numberOfBands] = m_blockSize;
c@13 51 m_pBandSum = new float [m_numberOfBands];
c@5 52 }
c@5 53
c@9 54 //delete space allocated in initialise()
c@5 55 void
c@14 56 NoveltyCurveProcessor::cleanup(){
c@13 57 delete []m_pBandBoundaries;
c@13 58 m_pBandBoundaries = 0;
c@13 59 delete []m_pBandSum;
c@13 60 m_pBandSum = 0;
c@5 61 }
c@5 62
c@9 63 //subtract local average of novelty curve
c@9 64 //uses m_hannWindow as filter
c@14 65 void NoveltyCurveProcessor::subtractLocalAverage(vector<float> &noveltyCurve, const size_t &smoothLength) const
c@13 66 {
c@22 67 int numberOfBlocks = noveltyCurve.size();
c@22 68 vector<float> localAverage(numberOfBlocks);
c@5 69
c@13 70 float * m_hannWindow = new float[smoothLength];
c@13 71 WindowFunction::hanning(m_hannWindow, smoothLength, true);
c@9 72
c@22 73 FIRFilter filter(numberOfBlocks, smoothLength);
c@15 74 filter.process(&noveltyCurve[0], m_hannWindow, &localAverage[0], FIRFilter::middle);
c@5 75
c@22 76 for (int i = 0; i < numberOfBlocks; i++){
c@5 77 noveltyCurve[i] -= localAverage[i];
c@5 78 noveltyCurve[i] = noveltyCurve[i] >= 0 ? noveltyCurve[i] : 0;
c@5 79 }
c@9 80
c@11 81 delete []m_hannWindow;
c@13 82 m_hannWindow = 0;
c@5 83 }
c@5 84
c@9 85 //smoothed differentiator filter. Flips upper half of hanning window about y-axis to create coefficients.
c@22 86 void NoveltyCurveProcessor::smoothedDifferentiator(SpectrogramTransposed &spectrogramTransposed, const size_t &smoothLength) const
c@13 87 {
c@22 88 int numberOfBlocks = spectrogramTransposed[0].size();
c@22 89
c@7 90 float * diffHannWindow = new float [smoothLength];
c@7 91 WindowFunction::hanning(diffHannWindow, smoothLength, true);
c@7 92
c@7 93 if(smoothLength%2) diffHannWindow[(smoothLength+1)/2 - 1] = 0;
c@20 94 for(int i = (smoothLength+1)/2; i < (int)smoothLength; i++){
c@7 95 diffHannWindow[i] = -diffHannWindow[i];
c@7 96 }
c@7 97
c@22 98 FIRFilter smoothFilter(numberOfBlocks, smoothLength);
c@7 99
c@20 100 for (int i = 0; i < (int)m_blockSize; i++){
c@22 101 smoothFilter.process(&spectrogramTransposed[i][0], diffHannWindow, &spectrogramTransposed[i][0], FIRFilter::middle);
c@7 102 }
Chris@41 103
Chris@41 104 delete[] diffHannWindow;
c@7 105 }
c@7 106
c@9 107 //half rectification (set negative to zero)
c@24 108 void NoveltyCurveProcessor::halfWaveRectify(Spectrogram &spectrogram) const
c@13 109 {
c@24 110 int length = spectrogram.size();
c@25 111 int height = length > 0 ? spectrogram[0].size() : 0;
c@22 112
c@24 113 for (int i = 0; i < length; i++){
c@24 114 for (int j = 0; j < height; j++){
c@24 115 if (spectrogram[i][j] < 0.0) spectrogram[i][j] = 0.0;
c@7 116 }
c@7 117 }
c@7 118 }
c@7 119
c@9 120 //process method
c@5 121 vector<float>
c@22 122 NoveltyCurveProcessor::spectrogramToNoveltyCurve(const Spectrogram &spectrogram) const //make argument const &
c@13 123 {
c@22 124 int numberOfBlocks = spectrogram.size();
c@22 125 std::vector<float> noveltyCurve(numberOfBlocks);
c@25 126 SpectrogramTransposed spectrogramTransposed(m_blockSize, vector<float>(spectrogram.size()));
c@5 127
c@9 128 //normalise and log spectrogram
c@25 129 float normaliseScale = SpectrogramProcessor::calculateMax(spectrogram);
c@22 130 for (int block = 0; block < (int)numberOfBlocks; block++){
c@20 131 for (int k = 0; k < (int)m_blockSize; k++){
c@25 132 float magnitude = spectrogram[block][k];
c@25 133 if(normaliseScale != 0.0) magnitude /= normaliseScale; //normalise
c@25 134 spectrogramTransposed[k][block] = log(1+m_compressionConstant*magnitude);
c@7 135 }
c@7 136 }
c@24 137
c@9 138 //smooted differentiator
c@22 139 smoothedDifferentiator(spectrogramTransposed, 5); //make smoothLength a parameter!
c@9 140 //halfwave rectification
c@22 141 halfWaveRectify(spectrogramTransposed);
c@7 142
c@9 143 //bandwise processing
c@22 144 for (int block = 0; block < (int)numberOfBlocks; block++){
c@20 145 for (int band = 0; band < (int)m_numberOfBands; band++){
c@13 146 int k = m_pBandBoundaries[band];
c@13 147 int bandEnd = m_pBandBoundaries[band+1];
c@13 148 m_pBandSum[band] = 0;
c@5 149
c@7 150 while(k < bandEnd){
c@22 151 m_pBandSum[band] += spectrogramTransposed[k][block];
c@7 152 k++;
c@5 153 }
c@5 154 }
c@5 155 float total = 0;
c@20 156 for(int band = 0; band < (int)m_numberOfBands; band++){
c@13 157 total += m_pBandSum[band];
c@5 158 }
c@13 159 noveltyCurve[block] = total/m_numberOfBands;
c@5 160 }
c@5 161
c@9 162 //subtract local averages
c@29 163 subtractLocalAverage(noveltyCurve, 65); //maybe smaller?
c@5 164
c@13 165 return noveltyCurve;
c@7 166 }