diff options
Diffstat (limited to 'sms/harmDetection.c')
-rw-r--r-- | sms/harmDetection.c | 232 |
1 files changed, 119 insertions, 113 deletions
diff --git a/sms/harmDetection.c b/sms/harmDetection.c index 1612fc8..a2be13b 100644 --- a/sms/harmDetection.c +++ b/sms/harmDetection.c @@ -24,14 +24,11 @@ #include "sms.h" -#define N_FUND_HARM 6 /*!< number of harmonics to use for fundamental - detection */ -#define N_HARM_PEAKS 4 /*!< number of peaks to check as possible ref - harmonics */ -#define FREQ_DEV_THRES .07 /*!< threshold for deviation from perfect - harmonics */ -#define MAG_PERC_THRES .6 /*!< threshold for magnitude of harmonics - with respect to the total magnitude */ +#define N_FUND_HARM 6 /*!< number of harmonics to use for fundamental detection */ +#define N_HARM_PEAKS 4 /*!< number of peaks to check as possible ref harmonics */ +#define FREQ_DEV_THRES .07 /*!< threshold for deviation from perfect harmonics */ +#define MAG_PERC_THRES .6 /*!< threshold for magnitude of harmonics + with respect to the total magnitude */ #define HARM_RATIO_THRES .8 /*!< threshold for percentage of harmonics found */ /*! \brief get closest peak to a given harmonic of the possible fundamental @@ -43,33 +40,39 @@ * \param iRefHarmonic reference harmonic number * \return the number of the closest peak or -1 if not found */ -static int GetClosestPeak (int iPeakCandidate, int nHarm, SMS_Peak *pSpectralPeaks, - int *pICurrentPeak, int iRefHarmonic) +static int GetClosestPeak(int iPeakCandidate, int nHarm, SMS_Peak *pSpectralPeaks, + int *pICurrentPeak, int iRefHarmonic, int maxPeaks) { - int iBestPeak = *pICurrentPeak + 1, iNextPeak; + int iBestPeak = *pICurrentPeak + 1; + int iNextPeak = iBestPeak + 1; + + if((iBestPeak >= maxPeaks) || (iNextPeak >= maxPeaks)) + return -1; + sfloat fBestPeakFreq = pSpectralPeaks[iBestPeak].fFreq, - fHarmFreq = (1 + nHarm) * pSpectralPeaks[iPeakCandidate].fFreq / iRefHarmonic, - fMinDistance = fabs(fHarmFreq - fBestPeakFreq), - fMaxPeakDev = .5 * fHarmFreq / (nHarm + 1), fDistance; + fHarmFreq = (1 + nHarm) * pSpectralPeaks[iPeakCandidate].fFreq / iRefHarmonic, + fMinDistance = fabs(fHarmFreq - fBestPeakFreq), + fMaxPeakDev = .5 * fHarmFreq / (nHarm + 1), + fDistance = 0.0; - iNextPeak = iBestPeak + 1; fDistance = fabs(fHarmFreq - pSpectralPeaks[iNextPeak].fFreq); - while (fDistance < fMinDistance) + while((fDistance < fMinDistance) && (iNextPeak < maxPeaks - 1)) { iBestPeak = iNextPeak; fMinDistance = fDistance; iNextPeak++; - fDistance = fabs (fHarmFreq - pSpectralPeaks[iNextPeak].fFreq); + fDistance = fabs(fHarmFreq - pSpectralPeaks[iNextPeak].fFreq); } /* make sure the chosen peak is good */ fBestPeakFreq = pSpectralPeaks[iBestPeak].fFreq; + /* if best peak is not in the range */ - if (fabs (fBestPeakFreq - fHarmFreq) > fMaxPeakDev) - return (-1); + if(fabs(fBestPeakFreq - fHarmFreq) > fMaxPeakDev) + return -1; *pICurrentPeak = iBestPeak; - return (iBestPeak); + return iBestPeak; } /*! \brief checks if peak is substantial @@ -84,35 +87,35 @@ static int GetClosestPeak (int iPeakCandidate, int nHarm, SMS_Peak *pSpectralPea * \param fRefHarmMagDiffFromMax value to judge the peak based on the difference of its magnitude compared to the reference * \return 1 if big peak, -1 if too small , otherwise return 0 */ -static int ComparePeak (sfloat fRefHarmMag, SMS_Peak *pSpectralPeaks, int nCand, - sfloat fRefHarmMagDiffFromMax) +static int ComparePeak(sfloat fRefHarmMag, SMS_Peak *pSpectralPeaks, int nCand, + sfloat fRefHarmMagDiffFromMax, int maxPeaks) { int iPeak; sfloat fMag = 0; /* if peak is very large take it as possible fundamental */ - if (nCand == 0 && - fRefHarmMag > 80.) - return (1); + if(nCand == 0 && fRefHarmMag > 80.) + return 1; /* compare the peak with the first N_FUND_HARM peaks */ /* if too small forget it */ - for (iPeak = 0; iPeak < N_FUND_HARM; iPeak++) - if (pSpectralPeaks[iPeak].fMag > 0 && - fRefHarmMag - pSpectralPeaks[iPeak].fMag < - fRefHarmMagDiffFromMax) - return (-1); + for(iPeak = 0; (iPeak < N_FUND_HARM) && (iPeak < maxPeaks); iPeak++) + { + if(pSpectralPeaks[iPeak].fMag > 0 && + fRefHarmMag - pSpectralPeaks[iPeak].fMag < - fRefHarmMagDiffFromMax) + return -1; + } /* if it is much bigger than rest take it */ - for (iPeak = 0; iPeak < N_FUND_HARM; iPeak++) + for(iPeak = 0; (iPeak < N_FUND_HARM) && (iPeak < maxPeaks); iPeak++) { fMag = pSpectralPeaks[iPeak].fMag; - if (fMag <= 0 || - ((fMag != fRefHarmMag) && - (nCand > 0) && (fRefHarmMag - fMag < 30.0)) || + if(fMag <= 0 || + ((fMag != fRefHarmMag) && (nCand > 0) && (fRefHarmMag - fMag < 30.0)) || ((nCand == 0) && (fRefHarmMag - fMag < 15.0))) - return (0); + return 0; } - return (1); + return 1; } @@ -123,19 +126,19 @@ static int ComparePeak (sfloat fRefHarmMag, SMS_Peak *pSpectralPeaks, int nCand, * \param nCand location of las candidate * \return 1 if it is a harmonic, 0 if it is not */ -int CheckIfHarmonic (sfloat fFundFreq, SMS_HarmCandidate *pCHarmonic, int nCand) +static int CheckIfHarmonic(sfloat fFundFreq, SMS_HarmCandidate *pCHarmonic, int nCand) { int iPeak; - /* go through all the candidates checking if they are fundamentals */ - /* of the peak to be considered */ - for (iPeak = 0; iPeak < nCand; iPeak++) - if (fabs(floor((double)(fFundFreq - / pCHarmonic[iPeak].fFreq) + .5) - - (fFundFreq / pCHarmonic[iPeak].fFreq)) - <= .1) - return (1); - return (0); + /* go through all the candidates checking if they are fundamentals + * of the peak to be considered */ + for(iPeak = 0; iPeak < nCand; iPeak++) + { + if(fabs(floor((double)(fFundFreq / pCHarmonic[iPeak].fFreq) + .5) - + (fFundFreq / pCHarmonic[iPeak].fFreq)) <= .1) + return 1; + } + return 0; } @@ -152,13 +155,25 @@ int CheckIfHarmonic (sfloat fFundFreq, SMS_HarmCandidate *pCHarmonic, int nCand) * found a really good one, return 1 if the peak is a good candidate */ -static int GoodCandidate (int iPeak, SMS_Peak *pSpectralPeaks, SMS_HarmCandidate *pCHarmonic, - int nCand, int soundType, sfloat fRefFundamental, - sfloat minRefHarmMag, sfloat refHarmMagDiffFromMax, sfloat refHarmonic) +static int GoodCandidate(int iPeak, int maxPeaks, SMS_Peak *pSpectralPeaks, + SMS_HarmCandidate *pCHarmonic, int nCand, int soundType, sfloat fRefFundamental, + sfloat minRefHarmMag, sfloat refHarmMagDiffFromMax, sfloat refHarmonic) { - sfloat fHarmFreq, fRefHarmFreq, fRefHarmMag, fTotalMag = 0, fTotalDev = 0, - fTotalMaxMag = 0, fAvgMag = 0, fAvgDev = 0, fHarmRatio = 0; - int iHarm = 0, iChosenPeak = 0, iPeakComp, iCurrentPeak, nGoodHarm = 0, i; + sfloat fHarmFreq = 0.0, + fRefHarmFreq = 0.0, + fRefHarmMag = 0.0, + fTotalMag = 0.0, + fTotalDev = 0.0, + fTotalMaxMag = 0.0, + fAvgMag = 0.0, + fAvgDev = 0.0, + fHarmRatio = 0.0; + int iHarm = 0, + iChosenPeak = 0, + iPeakComp = 0, + iCurrentPeak = 0, + nGoodHarm = 0, + i = 0; fRefHarmFreq = fHarmFreq = pSpectralPeaks[iPeak].fFreq; @@ -167,79 +182,73 @@ static int GoodCandidate (int iPeak, SMS_Peak *pSpectralPeaks, SMS_HarmCandidate fTotalMag = fRefHarmMag; /* check if magnitude is big enough */ - /*! \bug sfloat comparison to 0 */ - if (((fRefFundamental > 0) && - (fRefHarmMag < minRefHarmMag - 10)) || - ((fRefFundamental <= 0) && - (fRefHarmMag < minRefHarmMag))) - return (-1); + /*! \bug sfloat comparison to 0 */ + if(((fRefFundamental > 0) && (fRefHarmMag < minRefHarmMag - 10)) || + ((fRefFundamental <= 0) && (fRefHarmMag < minRefHarmMag))) + return -1; /* check that it is not a harmonic of a previous candidate */ - if (nCand > 0 && - CheckIfHarmonic (fRefHarmFreq / refHarmonic, pCHarmonic, - nCand)) - return (-1); + if(nCand > 0 && + CheckIfHarmonic(fRefHarmFreq / refHarmonic, pCHarmonic, nCand)) + return -1; /* check if it is very big or very small */ - iPeakComp = ComparePeak (fRefHarmMag, pSpectralPeaks, nCand, refHarmMagDiffFromMax); + iPeakComp = ComparePeak(fRefHarmMag, pSpectralPeaks, nCand, refHarmMagDiffFromMax, maxPeaks); + /* too small */ - if (iPeakComp == -1) - return (-1); + if(iPeakComp == -1) + return -1; /* very big */ - else if (iPeakComp == 1) + else if(iPeakComp == 1) { pCHarmonic[nCand].fFreq = fRefHarmFreq; pCHarmonic[nCand].fMag = fRefHarmMag; pCHarmonic[nCand].fMagPerc = 1; pCHarmonic[nCand].fFreqDev = 0; pCHarmonic[nCand].fHarmRatio = 1; - return (-2); + return -2; } /* get a weight on the peak by comparing its harmonic series */ /* with the existing peaks */ - if (soundType != SMS_SOUND_TYPE_NOTE) + if(soundType != SMS_SOUND_TYPE_NOTE) { fHarmFreq = fRefHarmFreq; iCurrentPeak = iPeak; nGoodHarm = 0; - for (iHarm = refHarmonic; iHarm < N_FUND_HARM; iHarm++) + for(iHarm = refHarmonic; (iHarm < N_FUND_HARM) && (iHarm < maxPeaks); iHarm++) { fHarmFreq += fRefHarmFreq / refHarmonic; iChosenPeak = GetClosestPeak(iPeak, iHarm, pSpectralPeaks, - &iCurrentPeak, refHarmonic); - if (iChosenPeak > 0) + &iCurrentPeak, refHarmonic, + maxPeaks); + if(iChosenPeak > 0) { - fTotalDev += - fabs(fHarmFreq - pSpectralPeaks[iChosenPeak].fFreq) / - fHarmFreq; + fTotalDev += fabs(fHarmFreq - pSpectralPeaks[iChosenPeak].fFreq) / + fHarmFreq; fTotalMag += pSpectralPeaks[iChosenPeak].fMag; nGoodHarm++; } } - for (i = 0; i <= iCurrentPeak; i++) + for(i = 0; i <= iCurrentPeak; i++) fTotalMaxMag += pSpectralPeaks[i].fMag; fAvgDev = fTotalDev / (iHarm + 1); fAvgMag = fTotalMag / fTotalMaxMag; - fHarmRatio = (sfloat) nGoodHarm / (N_FUND_HARM - 1); - - } + fHarmRatio = (sfloat)nGoodHarm / (N_FUND_HARM - 1); - if (soundType != SMS_SOUND_TYPE_NOTE) - { - if (fRefFundamental > 0) + if(fRefFundamental > 0) { if(fAvgDev > FREQ_DEV_THRES || fAvgMag < MAG_PERC_THRES - .1 || fHarmRatio < HARM_RATIO_THRES - .1) - return (-1); + return -1; } else { - if (fAvgDev > FREQ_DEV_THRES || fAvgMag < MAG_PERC_THRES || - fHarmRatio < HARM_RATIO_THRES) - return (-1); + if(fAvgDev > FREQ_DEV_THRES || fAvgMag < MAG_PERC_THRES || + fHarmRatio < HARM_RATIO_THRES) + return -1; } } @@ -249,7 +258,7 @@ static int GoodCandidate (int iPeak, SMS_Peak *pSpectralPeaks, SMS_HarmCandidate pCHarmonic[nCand].fFreqDev = fAvgDev; pCHarmonic[nCand].fHarmRatio = fHarmRatio; - return (1); + return 1; } /*! \brief choose the best fundamental out of all the candidates @@ -260,52 +269,49 @@ static int GoodCandidate (int iPeak, SMS_Peak *pSpectralPeaks, SMS_HarmCandidate * \param fPrevFund reference fundamental * \return the integer number of the best candidate */ -static int GetBestCandidate (SMS_HarmCandidate *pCHarmonic, - int iRefHarmonic, int nGoodPeaks, sfloat fPrevFund) +static int GetBestCandidate(SMS_HarmCandidate *pCHarmonic, + int iRefHarmonic, int nGoodPeaks, sfloat fPrevFund) { int iBestCandidate = 0, iPeak; sfloat fBestFreq, fHarmFreq, fDev; /* if a fundamental existed in previous frame take the closest candidate */ - if (fPrevFund > 0) - for (iPeak = 1; iPeak < nGoodPeaks; iPeak++) + if(fPrevFund > 0) + { + for(iPeak = 1; iPeak < nGoodPeaks; iPeak++) { - if (fabs (fPrevFund - pCHarmonic[iPeak].fFreq / iRefHarmonic) < - fabs(fPrevFund - pCHarmonic[iBestCandidate].fFreq / iRefHarmonic)) + if(fabs(fPrevFund - pCHarmonic[iPeak].fFreq / iRefHarmonic) < + fabs(fPrevFund - pCHarmonic[iBestCandidate].fFreq / iRefHarmonic)) iBestCandidate = iPeak; } + } else + { /* try to find the best candidate */ - for (iPeak = 1; iPeak < nGoodPeaks; iPeak++) + for(iPeak = 1; iPeak < nGoodPeaks; iPeak++) { fBestFreq = pCHarmonic[iBestCandidate].fFreq / iRefHarmonic; - fHarmFreq = fBestFreq * - floor (.5 + - (pCHarmonic[iPeak].fFreq / iRefHarmonic) / - fBestFreq); - fDev = fabs (fHarmFreq - (pCHarmonic[iPeak].fFreq / - iRefHarmonic)) / fHarmFreq; + fHarmFreq = fBestFreq * floor(.5 + + (pCHarmonic[iPeak].fFreq / iRefHarmonic) / + fBestFreq); + fDev = fabs(fHarmFreq - (pCHarmonic[iPeak].fFreq / iRefHarmonic)) / fHarmFreq; - /* if candidate is far from harmonic from best candidate and */ - /* bigger, take it */ - if (fDev > .2 && - pCHarmonic[iPeak].fMag > - pCHarmonic[iBestCandidate].fMag) + /* if candidate is far from harmonic from best candidate and + * bigger, take it */ + if(fDev > .2 && + pCHarmonic[iPeak].fMag > pCHarmonic[iBestCandidate].fMag) iBestCandidate = iPeak; /* if frequency deviation is much smaller, take it */ - else if (pCHarmonic[iPeak].fFreqDev < - .2 * pCHarmonic[iBestCandidate].fFreqDev) + else if(pCHarmonic[iPeak].fFreqDev < .2 * pCHarmonic[iBestCandidate].fFreqDev) iBestCandidate = iPeak; /* if freq. deviation is smaller and bigger amplitude, take it */ - else if (pCHarmonic[iPeak].fFreqDev < - pCHarmonic[iBestCandidate].fFreqDev && - pCHarmonic[iPeak].fMagPerc > - pCHarmonic[iBestCandidate].fMagPerc && - pCHarmonic[iPeak].fMag > - pCHarmonic[iBestCandidate].fMag) + else if(pCHarmonic[iPeak].fFreqDev < pCHarmonic[iBestCandidate].fFreqDev && + pCHarmonic[iPeak].fMagPerc > pCHarmonic[iBestCandidate].fMagPerc && + pCHarmonic[iPeak].fMag > pCHarmonic[iBestCandidate].fMag) iBestCandidate = iPeak; } - return (iBestCandidate); + } + return iBestCandidate; } /*! \brief main harmonic detection function @@ -353,7 +359,7 @@ sfloat sms_harmDetection(int numPeaks, SMS_Peak* spectralPeaks, sfloat refFundam fabs(peakFreq - (refHarmonic * refFundamental)) / refFundamental > .5) continue; - iCandidate = GoodCandidate(iPeak, spectralPeaks, pCHarmonic, + iCandidate = GoodCandidate(iPeak, numPeaks, spectralPeaks, pCHarmonic, nGoodPeaks, soundType, refFundamental, minRefHarmMag, refHarmMagDiffFromMax, refHarmonic); |