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 2005-2006 Christian Landone. cannam@0: All rights reserved. cannam@0: */ cannam@0: cannam@0: cannam@0: #include "ChromaProcess.h" cannam@0: #include "dsp/maths/Histogram.h" cannam@0: #include cannam@0: ////////////////////////////////////////////////////////////////////// cannam@0: // Construction/Destruction cannam@0: ////////////////////////////////////////////////////////////////////// cannam@0: cannam@0: ChromaProcess::ChromaProcess() cannam@0: { cannam@0: cannam@0: } cannam@0: cannam@0: ChromaProcess::~ChromaProcess() cannam@0: { cannam@0: cannam@0: } cannam@0: cannam@0: int ChromaProcess::findChromaBias( vector chromaVector, unsigned int BPO, unsigned int frames ) cannam@0: { cannam@0: vector newChroma; cannam@0: vector peakIndex; cannam@0: vector modPeakIndex; cannam@0: cannam@0: unsigned int chromaLength = chromaVector.size(); cannam@0: cannam@0: unsigned int newLength = chromaLength + (2*BPO); cannam@0: cannam@0: newChroma.resize( newLength ); cannam@0: newChroma.clear(); cannam@0: cannam@0: modPeakIndex.resize( newLength ); cannam@0: modPeakIndex.clear(); cannam@0: cannam@0: //adds last row at the top and first row at the bottom to create cannam@0: //circularity - effectively adds 2 to the bpo-length of the vectors: cannam@0: cannam@0: for( unsigned int i = 0; i < BPO; i++ ) cannam@0: { cannam@0: newChroma.push_back( chromaVector[ chromaLength - BPO + i ] ); cannam@0: } cannam@0: cannam@0: for( unsigned i = 0; i < chromaLength; i++ ) cannam@0: { cannam@0: newChroma.push_back( chromaVector[ i ] ); cannam@0: } cannam@0: cannam@0: for( unsigned i = 0; i < BPO; i++ ) cannam@0: { cannam@0: newChroma.push_back( chromaVector[ i ] ); cannam@0: } cannam@0: cannam@0: // pick peaks in the chroma cannam@0: peakIndex = getPeaks( newChroma, BPO ); cannam@0: cannam@0: // modularises to res = bpo/12 bins: cannam@0: // corrects the mod value for bin 3 cannam@0: modPeakIndex = mod( peakIndex, 3 ); cannam@0: cannam@0: // finds the highest concentration of peaks on the bpo/12 bin resolution cannam@0: THistogram m_hist(3); cannam@0: cannam@0: double ave, adev, sdev, var, skew, ccurt; cannam@0: cannam@0: m_hist.compute(modPeakIndex); cannam@0: cannam@0: m_hist.getMoments( modPeakIndex, ave, adev, sdev, var, skew, ccurt ); cannam@0: cannam@0: vector histogram = m_hist.geTHistogramD(); cannam@0: ////////////////////////////////////////////////////////////////////////////// cannam@0: cannam@0: /////////////////////////////////////////////////////////////////////////// cannam@0: // Find actual bias from histogram cannam@0: int minIdx, maxIdx; cannam@0: double min, max; cannam@0: cannam@0: findHistMaxMin( histogram, &max, &maxIdx, &min, &minIdx ); cannam@0: cannam@0: /* cannam@0: FILE* foutchroma = fopen("../testdata/newchroma.bin","wb"); cannam@0: FILE* foutpeaks = fopen("../testdata/peaks.bin","wb"); cannam@0: cannam@0: cannam@0: fwrite( &chromaVector[0], sizeof(double), chromaVector.size(), foutchroma ); cannam@0: fwrite( &histogram[0], sizeof(double), histogram.size(), foutpeaks ); cannam@0: cannam@0: fclose( foutchroma ); cannam@0: fclose( foutpeaks ); cannam@0: */ cannam@0: return maxIdx - 1; cannam@0: } cannam@0: cannam@0: cannam@0: vector ChromaProcess::getPeaks(vector chroma, unsigned int BPO) cannam@0: { cannam@0: vector peaks; cannam@0: cannam@0: double pre = 0; cannam@0: double post = 0; cannam@0: double current = 0; cannam@0: cannam@0: unsigned int BPOCounter = 0; cannam@0: unsigned int mult = 0; cannam@0: unsigned int idx = 0; cannam@0: cannam@0: for( unsigned int i = 0; i < chroma.size() - 0; i++ ) cannam@0: { cannam@0: BPOCounter++; cannam@0: cannam@0: pre = chroma[ i ]; cannam@0: current = chroma[ i + 1 ]; cannam@0: post = chroma[ i + 2 ]; cannam@0: cannam@0: if( (current > 0) && (current > pre) && (current > post) ) cannam@0: { cannam@0: peaks.push_back( BPOCounter + 1); cannam@0: } cannam@0: cannam@0: cannam@0: if( BPOCounter == (BPO - 2 ) ) cannam@0: { cannam@0: BPOCounter = 0; cannam@0: i+=2; cannam@0: } cannam@0: cannam@0: } cannam@0: cannam@0: /* cannam@0: for( unsigned int i = 1; i < chroma.size() - 1; i++ ) cannam@0: { cannam@0: BPOCounter++ ; cannam@0: cannam@0: pre = chroma[ i - 1 ]; cannam@0: current = chroma[ i ]; cannam@0: post = chroma[ i + 1 ]; cannam@0: cannam@0: if( (current > 0) && (current > pre) && (current > post) ) cannam@0: { cannam@0: peaks.push_back( BPOCounter + 1 ); cannam@0: } cannam@0: cannam@0: if( BPOCounter == (PO - 1) ) cannam@0: { cannam@0: BPOCounter = 1; cannam@0: i+=2; cannam@0: } cannam@0: } cannam@0: */ cannam@0: return peaks; cannam@0: } cannam@0: cannam@0: vector ChromaProcess::mod(vector input, int res) cannam@0: { cannam@0: vector result; cannam@0: cannam@0: for( unsigned int i = 0; i < input.size(); i++ ) cannam@0: { cannam@0: int val = input[ i ]; cannam@0: int res = val - res * floor( (double)val / (double)res ); cannam@0: cannam@0: if( val != 0 ) cannam@0: { cannam@0: if( res == 0 ) cannam@0: res = 3; cannam@0: cannam@0: result.push_back( res ); cannam@0: } cannam@0: else cannam@0: { cannam@0: result.push_back( val ); cannam@0: } cannam@0: } cannam@0: return result; cannam@0: } cannam@0: cannam@0: void ChromaProcess::findHistMaxMin( vector hist, double* max, int* maxIdx, double* min, int* minIdx ) cannam@0: { cannam@0: double temp = 0.0; cannam@0: unsigned int vecLength = hist.size(); cannam@0: cannam@0: *minIdx = 0; cannam@0: *maxIdx = 0; cannam@0: cannam@0: *min = hist[0]; cannam@0: *max = *min; cannam@0: cannam@0: for( unsigned int u = 0; u < vecLength; u++ ) cannam@0: { cannam@0: temp = hist[ u ]; cannam@0: cannam@0: if( temp < *min ) cannam@0: { cannam@0: *min = temp ; cannam@0: *minIdx = u; cannam@0: } cannam@0: if( temp > *max ) cannam@0: { cannam@0: *max = temp ; cannam@0: *maxIdx = u; cannam@0: } cannam@0: cannam@0: } cannam@0: }