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: #include "DetectionFunction.h" cannam@0: cannam@0: ////////////////////////////////////////////////////////////////////// cannam@0: // Construction/Destruction cannam@0: ////////////////////////////////////////////////////////////////////// cannam@0: cannam@0: DetectionFunction::DetectionFunction( DFConfig Config ) : cannam@0: m_window(0) cannam@0: { cannam@2: m_magHistory = NULL; cannam@2: m_phaseHistory = NULL; cannam@2: m_phaseHistoryOld = NULL; cannam@0: cannam@0: initialise( Config ); cannam@0: } cannam@0: cannam@0: DetectionFunction::~DetectionFunction() cannam@0: { cannam@0: deInitialise(); cannam@0: } cannam@0: cannam@0: cannam@0: void DetectionFunction::initialise( DFConfig Config ) cannam@0: { cannam@0: m_dataLength = Config.frameLength; cannam@0: m_halfLength = m_dataLength/2; cannam@0: m_DFType = Config.DFType; cannam@13: m_stepSecs = Config.stepSecs; cannam@13: m_stepSize = Config.stepSize; cannam@0: cannam@2: m_magHistory = new double[ m_halfLength ]; cannam@2: memset(m_magHistory,0, m_halfLength*sizeof(double)); cannam@0: cannam@2: m_phaseHistory = new double[ m_halfLength ]; cannam@2: memset(m_phaseHistory,0, m_halfLength*sizeof(double)); cannam@0: cannam@2: m_phaseHistoryOld = new double[ m_halfLength ]; cannam@2: memset(m_phaseHistoryOld,0, m_halfLength*sizeof(double)); cannam@0: cannam@0: m_phaseVoc = new PhaseVocoder; cannam@0: cannam@0: m_DFWindowedFrame = new double[ m_dataLength ]; cannam@0: m_magnitude = new double[ m_halfLength ]; cannam@0: m_thetaAngle = new double[ m_halfLength ]; cannam@0: cannam@0: m_window = new Window(HanningWindow, m_dataLength); cannam@0: } cannam@0: cannam@0: void DetectionFunction::deInitialise() cannam@0: { cannam@2: delete [] m_magHistory ; cannam@2: delete [] m_phaseHistory ; cannam@2: delete [] m_phaseHistoryOld ; cannam@0: cannam@0: delete m_phaseVoc; cannam@0: cannam@0: delete [] m_DFWindowedFrame; cannam@0: delete [] m_magnitude; cannam@0: delete [] m_thetaAngle; cannam@0: cannam@0: delete m_window; cannam@0: } cannam@0: cannam@0: double DetectionFunction::process( double *TDomain ) cannam@0: { cannam@0: m_window->cut( TDomain, m_DFWindowedFrame ); cannam@0: cannam@0: m_phaseVoc->process( m_dataLength, m_DFWindowedFrame, m_magnitude, m_thetaAngle ); cannam@0: cannam@2: return runDF(); cannam@2: } cannam@2: cannam@2: double DetectionFunction::process( double *magnitudes, double *phases ) cannam@2: { cannam@2: for (size_t i = 0; i < m_halfLength; ++i) { cannam@2: m_magnitude[i] = magnitudes[i]; cannam@2: m_thetaAngle[i] = phases[i]; cannam@2: } cannam@2: cannam@2: return runDF(); cannam@2: } cannam@2: cannam@2: double DetectionFunction::runDF() cannam@2: { cannam@2: double retVal = 0; cannam@2: cannam@0: switch( m_DFType ) cannam@0: { cannam@0: case DF_HFC: cannam@0: retVal = HFC( m_halfLength, m_magnitude); cannam@0: break; cannam@0: cannam@13: case DF_SPECDIFF: cannam@0: retVal = specDiff( m_halfLength, m_magnitude); cannam@0: break; cannam@0: cannam@0: case DF_PHASEDEV: cannam@0: retVal = phaseDev( m_halfLength, m_magnitude, m_thetaAngle); cannam@0: break; cannam@0: cannam@0: case DF_COMPLEXSD: cannam@0: retVal = complexSD( m_halfLength, m_magnitude, m_thetaAngle); cannam@0: break; cannam@12: cannam@12: case DF_BROADBAND: cannam@12: retVal = broadband( m_halfLength, m_magnitude, m_thetaAngle); cannam@0: } cannam@0: cannam@0: return retVal; cannam@0: } cannam@0: cannam@0: double DetectionFunction::HFC(unsigned int length, double *src) cannam@0: { cannam@0: unsigned int i; cannam@0: double val = 0; cannam@0: cannam@0: for( i = 0; i < length; i++) cannam@0: { cannam@0: val += src[ i ] * ( i + 1); cannam@0: } cannam@0: return val; cannam@0: } cannam@0: cannam@0: double DetectionFunction::specDiff(unsigned int length, double *src) cannam@0: { cannam@0: unsigned int i; cannam@0: double val = 0.0; cannam@0: double temp = 0.0; cannam@0: double diff = 0.0; cannam@0: cannam@0: for( i = 0; i < length; i++) cannam@0: { cannam@2: temp = fabs( (src[ i ] * src[ i ]) - (m_magHistory[ i ] * m_magHistory[ i ]) ); cannam@0: cannam@0: diff= sqrt(temp); cannam@0: cannam@13: // (See note in phaseDev below.) cannam@13: cannam@13: val += diff; cannam@0: cannam@2: m_magHistory[ i ] = src[ i ]; cannam@0: } cannam@0: cannam@0: return val; cannam@0: } cannam@0: cannam@0: cannam@0: double DetectionFunction::phaseDev(unsigned int length, double *srcMagnitude, double *srcPhase) cannam@0: { cannam@0: unsigned int i; cannam@0: double tmpPhase = 0; cannam@0: double tmpVal = 0; cannam@0: double val = 0; cannam@0: cannam@0: double dev = 0; cannam@0: cannam@0: for( i = 0; i < length; i++) cannam@0: { cannam@2: tmpPhase = (srcPhase[ i ]- 2*m_phaseHistory[ i ]+m_phaseHistoryOld[ i ]); cannam@0: dev = MathUtilities::princarg( tmpPhase ); cannam@13: cannam@13: // A previous version of this code only counted the value here cannam@13: // if the magnitude exceeded 0.1. My impression is that cannam@13: // doesn't greatly improve the results for "loud" music (so cannam@13: // long as the peak picker is reasonably sophisticated), but cannam@13: // does significantly damage its ability to work with quieter cannam@13: // music, so I'm removing it and counting the result always. cannam@13: // Same goes for the spectral difference measure above. cannam@0: cannam@13: tmpVal = fabs(dev); cannam@13: val += tmpVal ; cannam@0: cannam@2: m_phaseHistoryOld[ i ] = m_phaseHistory[ i ] ; cannam@2: m_phaseHistory[ i ] = srcPhase[ i ]; cannam@0: } cannam@0: cannam@0: cannam@0: return val; cannam@0: } cannam@0: cannam@0: cannam@0: double DetectionFunction::complexSD(unsigned int length, double *srcMagnitude, double *srcPhase) cannam@0: { cannam@0: unsigned int i; cannam@0: double val = 0; cannam@0: double tmpPhase = 0; cannam@0: double tmpReal = 0; cannam@0: double tmpImag = 0; cannam@0: cannam@0: double dev = 0; cannam@0: ComplexData meas = ComplexData( 0, 0 ); cannam@2: ComplexData j = ComplexData( 0, 1 ); cannam@0: cannam@0: for( i = 0; i < length; i++) cannam@0: { cannam@2: tmpPhase = (srcPhase[ i ]- 2*m_phaseHistory[ i ]+m_phaseHistoryOld[ i ]); cannam@0: dev= MathUtilities::princarg( tmpPhase ); cannam@0: cannam@2: meas = m_magHistory[i] - ( srcMagnitude[ i ] * exp( j * dev) ); cannam@0: cannam@0: tmpReal = real( meas ); cannam@0: tmpImag = imag( meas ); cannam@0: cannam@0: val += sqrt( (tmpReal * tmpReal) + (tmpImag * tmpImag) ); cannam@0: cannam@2: m_phaseHistoryOld[ i ] = m_phaseHistory[ i ] ; cannam@2: m_phaseHistory[ i ] = srcPhase[ i ]; cannam@2: m_magHistory[ i ] = srcMagnitude[ i ]; cannam@0: } cannam@0: cannam@0: return val; cannam@0: } cannam@0: cannam@12: double DetectionFunction::broadband(unsigned int length, double *srcMagnitude, double *srcPhase) cannam@12: { cannam@12: double val = 0; cannam@12: for (unsigned int i = 0; i < length; ++i) { cannam@12: double sqrmag = srcMagnitude[i] * srcMagnitude[i]; cannam@12: if (m_magHistory[i] > 0.0) { cannam@12: double diff = 10.0 * log10(sqrmag / m_magHistory[i]); cannam@12: if (diff > m_dbRise) val = val + 1; cannam@12: } cannam@12: m_magHistory[i] = sqrmag; cannam@12: } cannam@12: return val; cannam@12: } cannam@12: cannam@0: double* DetectionFunction::getSpectrumMagnitude() cannam@0: { cannam@0: return m_magnitude; cannam@0: } cannam@0: