summaryrefslogtreecommitdiff
path: root/sms/harmDetection.c
diff options
context:
space:
mode:
authorJohn Glover <glover.john@gmail.com>2011-06-24 18:17:23 +0100
committerJohn Glover <glover.john@gmail.com>2011-06-24 18:17:23 +0100
commit416bd737074a287ea47106c73ea6bcfde40a75a8 (patch)
tree74562303d4f4f2f2e010f7e13cba41dc4852b50c /sms/harmDetection.c
parentd26519464dcbf8c3682348167c29454961facefe (diff)
downloadsimpl-416bd737074a287ea47106c73ea6bcfde40a75a8.tar.gz
simpl-416bd737074a287ea47106c73ea6bcfde40a75a8.tar.bz2
simpl-416bd737074a287ea47106c73ea6bcfde40a75a8.zip
Change to using distutils.
Currently only builds the simplsndobj module
Diffstat (limited to 'sms/harmDetection.c')
-rw-r--r--sms/harmDetection.c390
1 files changed, 0 insertions, 390 deletions
diff --git a/sms/harmDetection.c b/sms/harmDetection.c
deleted file mode 100644
index bf99729..0000000
--- a/sms/harmDetection.c
+++ /dev/null
@@ -1,390 +0,0 @@
-/*
- * Copyright (c) 2008 MUSIC TECHNOLOGY GROUP (MTG)
- * UNIVERSITAT POMPEU FABRA
- *
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-/*! \file harmDetection.c
- * \brief Detection of a given harmonic
- */
-
-#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 HARM_RATIO_THRES .8 /*!< threshold for percentage of harmonics found */
-
-/*! \brief get closest peak to a given harmonic of the possible fundamental
- *
- * \param iPeakCandidate peak number of possible fundamental
- * \param nHarm number of harmonic
- * \param pSpectralPeaks pointer to all the peaks
- * \param pICurrentPeak pointer to the last peak taken
- * \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, int maxPeaks)
-{
- 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 = 0.0;
-
- fDistance = fabs(fHarmFreq - pSpectralPeaks[iNextPeak].fFreq);
- while((fDistance < fMinDistance) && (iNextPeak < maxPeaks - 1))
- {
- iBestPeak = iNextPeak;
- fMinDistance = fDistance;
- iNextPeak++;
- 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;
-
- *pICurrentPeak = iBestPeak;
- return iBestPeak;
-}
-
-/*! \brief checks if peak is substantial
- *
- * check if peak is larger enough to be considered a fundamental
- * without any further testing or too small to be considered
- *
-
- * \param fRefHarmMag magnitude of possible fundamental
- * \param pSpectralPeaks all the peaks
- * \param nCand number of existing candidates
- * \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, int maxPeaks)
-{
- int iPeak;
- sfloat fMag = 0;
-
- /* if peak is very large take it as possible fundamental */
- 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 < 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 < maxPeaks); iPeak++)
- {
- fMag = pSpectralPeaks[iPeak].fMag;
- if(fMag <= 0 ||
- ((fMag != fRefHarmMag) && (nCand > 0) && (fRefHarmMag - fMag < 30.0)) ||
- ((nCand == 0) && (fRefHarmMag - fMag < 15.0)))
- return 0;
- }
- return 1;
-}
-
-
-/*! \brief check if the current peak is a harmonic of one of the candidates
- *
- * \param fFundFreq frequency of peak to be tested
- * \param pCHarmonic all candidates accepted
- * \param nCand location of las candidate
- * \return 1 if it is a harmonic, 0 if it is not
- */
-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;
-}
-
-
-/*! \brief consider a peak as a possible candidate and give it a weight value,
- *
- * \param iPeak iPeak number to be considered
- * \param pSpectralPeaks all the peaks
- * \param pCHarmonic all the candidates
- * \param nCand candidate number that is to be filled
- * \param pPeakParams analysis parameters
- * \param fRefFundamental previous fundamental
- * \return -1 if not good enough for a candidate, return 0 if reached
- * the top frequency boundary, return -2 if stop checking because it
- * found a really good one, return 1 if the peak is a good candidate
- */
-
-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 = 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;
-
- fTotalDev = 0;
- fRefHarmMag = pSpectralPeaks[iPeak].fMag;
- 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;
-
- /* check that it is not a harmonic of a previous candidate */
- 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, maxPeaks);
-
- /* too small */
- if(iPeakComp == -1)
- return -1;
- /* very big */
- 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;
- }
-
- /* get a weight on the peak by comparing its harmonic series */
- /* with the existing peaks */
- if(soundType != SMS_SOUND_TYPE_NOTE)
- {
- fHarmFreq = fRefHarmFreq;
- iCurrentPeak = iPeak;
- nGoodHarm = 0;
- for(iHarm = refHarmonic; (iHarm < N_FUND_HARM) && (iHarm < maxPeaks); iHarm++)
- {
- fHarmFreq += fRefHarmFreq / refHarmonic;
- iChosenPeak = GetClosestPeak(iPeak, iHarm, pSpectralPeaks,
- &iCurrentPeak, refHarmonic,
- maxPeaks);
- if(iChosenPeak > 0)
- {
- fTotalDev += fabs(fHarmFreq - pSpectralPeaks[iChosenPeak].fFreq) /
- fHarmFreq;
- fTotalMag += pSpectralPeaks[iChosenPeak].fMag;
- nGoodHarm++;
- }
- }
-
- for(i = 0; i <= iCurrentPeak; i++)
- fTotalMaxMag += pSpectralPeaks[i].fMag;
-
- fAvgDev = fTotalDev / (iHarm + 1);
- fAvgMag = fTotalMag / fTotalMaxMag;
- fHarmRatio = (sfloat)nGoodHarm / (N_FUND_HARM - 1);
-
- if(fRefFundamental > 0)
- {
- if(fAvgDev > FREQ_DEV_THRES || fAvgMag < MAG_PERC_THRES - .1 ||
- fHarmRatio < HARM_RATIO_THRES - .1)
- return -1;
- }
- else
- {
- if(fAvgDev > FREQ_DEV_THRES || fAvgMag < MAG_PERC_THRES ||
- fHarmRatio < HARM_RATIO_THRES)
- return -1;
- }
- }
-
- pCHarmonic[nCand].fFreq = fRefHarmFreq;
- pCHarmonic[nCand].fMag = fRefHarmMag;
- pCHarmonic[nCand].fMagPerc = fAvgMag;
- pCHarmonic[nCand].fFreqDev = fAvgDev;
- pCHarmonic[nCand].fHarmRatio = fHarmRatio;
-
- return 1;
-}
-
-/*! \brief choose the best fundamental out of all the candidates
- *
- * \param pCHarmonic array of candidates
- * \param iRefHarmonic reference harmonic number
- * \param nGoodPeaks number of candiates
- * \param fPrevFund reference fundamental
- * \return the integer number of the best candidate
- */
-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(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++)
- {
- fBestFreq = pCHarmonic[iBestCandidate].fFreq / iRefHarmonic;
- 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)
- iBestCandidate = iPeak;
- /* if frequency deviation is much smaller, take it */
- 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)
- iBestCandidate = iPeak;
- }
- }
- return iBestCandidate;
-}
-
-/*! \brief main harmonic detection function
- *
- * find a given harmonic peak from a set of spectral peaks,
- * put the frequency of the fundamental in the current frame
- *
- * \param pFrame pointer to current frame
- * \param fRefFundamental frequency of previous frame
- * \param pPeakParams pointer to analysis parameters
- * \todo is it possible to use pSpectralPeaks instead of SMS_AnalFrame?
- * \todo move pCHarmonic array to SMS_AnalFrame structure
- - this will allow for analysis of effectiveness from outside this file
- * This really should only be for sms_analyzeFrame
- */
-sfloat sms_harmDetection(int numPeaks, SMS_Peak* spectralPeaks, sfloat refFundamental,
- sfloat refHarmonic, sfloat lowestFreq, sfloat highestFreq,
- int soundType, sfloat minRefHarmMag, sfloat refHarmMagDiffFromMax)
-{
- int iPeak = -1, nGoodPeaks = 0, iCandidate, iBestCandidate;
- sfloat peakFreq=0;
- SMS_HarmCandidate pCHarmonic[N_HARM_PEAKS];
-
- /* find all possible candidates to use as harmonic reference */
- lowestFreq = lowestFreq * refHarmonic;
- highestFreq = highestFreq * refHarmonic;
-
- while((peakFreq < highestFreq) && (iPeak < numPeaks - 1))
- {
- iPeak++;
- peakFreq = spectralPeaks[iPeak].fFreq;
- if(peakFreq > highestFreq)
- break;
-
- /* no more peaks */
- if(spectralPeaks[iPeak].fMag <= 0) /*!< \bug sfloat comparison to zero */
- break;
-
- /* peak too low */
- if(peakFreq < lowestFreq)
- continue;
-
- /* if previous fundamental look only around it */
- if(refFundamental > 0 &&
- fabs(peakFreq - (refHarmonic * refFundamental)) / refFundamental > .5)
- continue;
-
- iCandidate = GoodCandidate(iPeak, numPeaks, spectralPeaks, pCHarmonic,
- nGoodPeaks, soundType, refFundamental,
- minRefHarmMag, refHarmMagDiffFromMax, refHarmonic);
-
- /* good candiate found */
- if(iCandidate == 1)
- nGoodPeaks++;
-
- /* a perfect candiate found */
- else if(iCandidate == -2)
- {
- nGoodPeaks++;
- break;
- }
- }
-
- /* if no candidate for fundamental, continue */
- if(nGoodPeaks == 0)
- return -1;
- /* if only 1 candidate for fundamental take it */
- else if(nGoodPeaks == 1)
- return pCHarmonic[0].fFreq / refHarmonic;
- /* if more than one candidate choose the best one */
- else
- {
- iBestCandidate = GetBestCandidate(pCHarmonic, refHarmonic, nGoodPeaks, refFundamental);
- return pCHarmonic[iBestCandidate].fFreq / refHarmonic;
- }
-}