FundFreqDetect.cxx

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2004 MUSIC TECHNOLOGY GROUP (MTG)
00003  *                         UNIVERSITAT POMPEU FABRA
00004  *
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  *
00020  */
00021 
00022 #include "Complex.hxx"
00023 #include "FundFreqDetect.hxx"
00024 #include "Fundamental.hxx"
00025 #include "SpectralPeakArray.hxx"
00026 #include <cmath>
00027 
00028 #define INFINITE_MAGNITUD 1000000
00029 
00030 namespace CLAM 
00031 {
00032 
00033         FundFreqDetect::FundFreqDetect()
00034                 : mInput( "Input", this),
00035                   mOutput( "Output", this ),
00036                   mFundFreqValue( "Fund Freq Value", this )
00037         {
00038                 Configure(FundFreqDetectConfig());
00039         }
00040 
00041         FundFreqDetect::FundFreqDetect(const FundFreqDetectConfig &c )
00042                 : mInput( "Input", this ),
00043                   mOutput( "Output", this ),
00044                   mFundFreqValue( "Fund Freq Value", this )
00045         {
00046                 Configure(c);
00047         }
00048 
00049         FundFreqDetect::~FundFreqDetect()       {}
00050 
00051         /* Configure the Processing Object according to the Config object */
00052         bool FundFreqDetect::ConcreteConfigure(const ProcessingConfig& c)
00053         {
00054                 CopyAsConcreteConfig(mConfig, c);
00055 
00056                 mReferenceFundFreq = mConfig.GetReferenceFundFreq();
00057                 mLowestFundFreq    = mConfig.GetLowestFundFreq();
00058                 mHighestFundFreq   = mConfig.GetHighestFundFreq();
00059                 mMaxCandMagDiff    = mConfig.GetMaxCandMagDiff();
00060                 mMaxFundFreqError  = mConfig.GetMaxFundFreqError(); 
00061                 mnInt              = mConfig.GetNInt();
00062                 mPMp = mConfig.GetPMp();
00063                 mPMq = mConfig.GetPMq();
00064                 mPMr = mConfig.GetPMr();
00065                 mMPp = mConfig.GetMPp();
00066                 mMPq = mConfig.GetMPq();
00067                 mMPr = mConfig.GetMPr();
00068                 mPMnPeaks = mConfig.GetPMnPeaks();
00069                 mMPnPeaks = mConfig.GetMPnPeaks();
00070                 mPMCont = mConfig.GetPMCont();
00071                 mMPCont = mConfig.GetMPCont();
00072                 mnMaxCandidates= TData(mConfig.GetNMaxCandidates());
00073                 
00074                 return true;
00075         }
00076 
00077         const ProcessingConfig &FundFreqDetect::GetConfig() const
00078         {               
00079                 mConfig.SetMaxCandMagDiff(mMaxCandMagDiff);
00080                 mConfig.SetMaxFundFreqError(mMaxFundFreqError); 
00081                 mConfig.SetNInt(mnInt);
00082                 mConfig.SetPMp(mPMp);
00083                 mConfig.SetPMq(mPMq);
00084                 mConfig.SetPMr(mPMr);
00085                 mConfig.SetMPp(mMPp);
00086                 mConfig.SetMPq(mMPq);
00087                 mConfig.SetMPr(mMPr);
00088                 mConfig.SetPMnPeaks(mPMnPeaks);
00089                 mConfig.SetMPnPeaks(mMPnPeaks);
00090                 mConfig.SetPMCont(mPMCont);
00091                 mConfig.SetMPCont(mMPCont);
00092                 mConfig.SetNMaxCandidates(TSize(mnMaxCandidates));
00093                 return mConfig;
00094         }
00095 
00096         /* The supervised Do() function */
00097         bool FundFreqDetect::Do(void)
00098         {
00099                 mOutput.GetData().SetnMaxCandidates(1);
00100 
00101                 bool result = Do( mInput.GetData(), mOutput.GetData() );
00102                 mInput.Consume();
00103                 mOutput.Produce();
00104 
00105                 return result;
00106         }
00107 
00108         /* The unsupervised Do() function */
00109         bool FundFreqDetect::Do(SpectralPeakArray& peaks,Fundamental& outFreq)
00110         {
00111                 outFreq.Init();
00112 
00113                 // Check Number of Candidates required
00114                 CLAM_ASSERT (outFreq.GetnMaxCandidates() > 0, 
00115                         "FundFreqDet::Detection: negative number of candidates wanted");
00116 
00117                 // See if the number of best candidates to be calculated is less than the maximum permitted
00118                 CLAM_ASSERT (outFreq.GetnMaxCandidates() <= mnMaxCandidates,
00119                         "FundFreqDet::Detection:Number of candidates wanted bigger "
00120                         "than the maximum configured on the algorithm"); 
00121 
00122                 // not enough peak information available for fundamental frequency detection");
00123                 if (peaks.GetnPeaks() <= 0)
00124                 {
00125                         mFundFreqValue.SendControl(0.0f);
00126                         return false;
00127                 }
00128 
00129                 // Calculate Maximun Magnitude Peak
00130                 TIndex nMaxMagPeak = peaks.GetMaxMagPos();
00131                 TData maxMag       = peaks.GetMag(nMaxMagPeak);
00132 
00133                 // 1.- SELECT PEAKS
00134                 // Add an index to the PeakArray
00135                 if(!peaks.HasIndexArray())
00136                 {
00137                         peaks.AddIndexArray();
00138                         peaks.UpdateData();
00139                         peaks.SetnMaxPeaks(peaks.GetnMaxPeaks());
00140                 }
00141 
00142                 // Reset indices in the peak array
00143                 peaks.ResetIndices();
00144 
00145                 // Delete peaks below the lowest pitch
00146                 DataArray& peakMagnitudes=peaks.GetMagBuffer();
00147                 DataArray& peakFrequencies=peaks.GetFreqBuffer();
00148                 DataArray& peakBinPosBuffer=peaks.GetBinPosBuffer();
00149 
00150                 const TData spectralRes = peakFrequencies[nMaxMagPeak]/peakBinPosBuffer[nMaxMagPeak];
00151                 
00152                 TData lowestFundFreqBinPos = mLowestFundFreq/spectralRes;
00153                 TIndex z=0;
00154                 while((z<peaks.GetnPeaks()) && (peakBinPosBuffer[z]<lowestFundFreqBinPos)) 
00155                 {
00156                         peaks.DeleteIndex(z);
00157                         z++;
00158                 }
00159 
00160                 // Before the maximum magnitude peak
00161                 for(int i=z; i<nMaxMagPeak; i++) 
00162                 {
00163                         if(peakMagnitudes[i] < maxMag - 30)
00164                                 peaks.DeleteIndex(i);
00165                 }
00166 
00167                 // Delete peaks above 3000
00168                 TData peaklimitBinPos = 3000.0/spectralRes;
00169                 for (int i=peaks.GetnPeaks()-1; i > nMaxMagPeak; i--)
00170                 {
00171                         if (peakBinPosBuffer[i] <= peaklimitBinPos) break;
00172                         peaks.DeleteIndex(i);
00173                 }
00174                         
00175                 // After the maximum magnitude peak
00176                 TData x,y,a,b;
00177                 a = - 10*spectralRes/TData(1000.0);
00178                 b = maxMag - 50 - a*(TData)peakBinPosBuffer[nMaxMagPeak];
00179                 for(int i=nMaxMagPeak+1; i<z; i++) 
00180                 {
00181                         y = peakMagnitudes[i];
00182                         x = peakBinPosBuffer[i];
00183                         if(y < (a*x+b)) 
00184                         {
00185                                 peaks.DeleteIndex(i);
00186                         }
00187                 }               
00188 
00189                 const IndexArray & peakIndexes = peaks.GetIndexArray();
00190                 // If there no valid peaks for calculate a fundamental frequency
00191                 if (peakIndexes.Size() <= 0)
00192                 {
00193                         mFundFreqValue.SendControl(0.0f);
00194                         return false;
00195                 }
00196           
00197                 // Find maximun magnitude peak from the selected ones
00198                 nMaxMagPeak = peaks.GetMaxMagIndex(); // only indexed peaks
00199                 maxMag      = peakMagnitudes[peakIndexes[nMaxMagPeak]];
00200 
00201                 // 2.- FIND mnMaxCandidates CANDIDATES
00202           
00203                 Fundamental tmpFreq; // this will be used throughout the algorithm to allocate new candidates
00204                 tmpFreq.AddCandidatesFreq();
00205                 tmpFreq.AddCandidatesErr();
00206                 tmpFreq.UpdateData();
00207                 tmpFreq.SetnCandidates(0);
00208                 tmpFreq.SetnMaxCandidates(int(mnMaxCandidates));
00209 
00210                 DataArray & candidatesFrequency = tmpFreq.GetCandidatesFreq();
00211                 DataArray & candidatesError = tmpFreq.GetCandidatesErr();
00212 
00213                 // 2.0.- Reference Fundamental Frequency
00214                 if( IsGoodCandidate(mReferenceFundFreq) ) 
00215                         tmpFreq.AddElem(mReferenceFundFreq);
00216           
00217                 // 2.1.- Three maximum magnitude peaks and its integer ratios
00218                 TIndex nMaxMagPeak2 = nMaxMagPeak;
00219                 TIndex nMaxMagPeak3 = nMaxMagPeak;
00220                 if(peakIndexes.Size() >= 2)
00221                 {
00222                         // find second max magnitude peak
00223                         peakMagnitudes[peakIndexes[nMaxMagPeak]]=-2000;
00224                         nMaxMagPeak2 = peaks.GetMaxMagIndex();
00225                         if(peakIndexes.Size() >= 3)
00226                         {
00227                                 TData aux;
00228                                 // find third max magnitude peak
00229                                 aux = peakMagnitudes[peakIndexes[nMaxMagPeak2]];
00230                                 peakMagnitudes[peakIndexes[nMaxMagPeak2]]=-2000;
00231                                 nMaxMagPeak3 = peaks.GetMaxMagIndex();
00232                                 // add candidate
00233                                 if ( IsGoodCandidate(peakFrequencies[peakIndexes[nMaxMagPeak3]]) )
00234                                         tmpFreq.AddElem(peakFrequencies[peakIndexes[nMaxMagPeak3]]);
00235                                 // restore second peak information
00236                                 peakMagnitudes[peakIndexes[nMaxMagPeak2]]=aux;
00237                         }
00238                         // add candidate
00239                         if ( IsGoodCandidate(peakFrequencies[peakIndexes[nMaxMagPeak2]]) )
00240                                 tmpFreq.AddElem(peakFrequencies[peakIndexes[nMaxMagPeak2]]);
00241                         
00242                         // restore first peak information
00243                         peakMagnitudes[peakIndexes[nMaxMagPeak]]=maxMag;
00244                 }         
00245                 // Add peaks as candidates
00246                 if ( IsGoodCandidate(peakFrequencies[peakIndexes[nMaxMagPeak]]) )
00247                         tmpFreq.AddElem(peakFrequencies[peakIndexes[nMaxMagPeak]]);     
00248           
00249                 // 2.2.- Peaks below the maximum magnitude peak (except for the 3 max peaks)
00250                 for (int i=0; i < nMaxMagPeak; i++ )
00251                 { 
00252                         // be careful not to exceed the maximun permitted
00253                         if (candidatesFrequency.Size() >= mnMaxCandidates) break;
00254                         if (i==nMaxMagPeak2) continue;
00255                         if (i==nMaxMagPeak3) continue;
00256                         if (peakMagnitudes[peakIndexes[i]] <= maxMag - mMaxCandMagDiff ) continue;
00257                         if (! IsGoodCandidate(peakFrequencies[peakIndexes[i]]) ) continue;
00258                         tmpFreq.AddElem(peakFrequencies[peakIndexes[i]]);
00259                 }
00260                 
00261                 // 2.3.- Frequency offset between peaks above the maximun magnitude peak and the maximun magnitude peak
00262                 TData freq;
00263                 for (int i = nMaxMagPeak+1; i<peakIndexes.Size(); i++)
00264                 {
00265                         // be careful not to exceed the maximun permitted
00266                         if (candidatesFrequency.Size() >= mnMaxCandidates) break;
00267                         freq = peakFrequencies[peakIndexes[i]] - peakFrequencies[peakIndexes[nMaxMagPeak]];
00268                         if (freq >= peakFrequencies[peakIndexes[nMaxMagPeak]]*1.1) continue;
00269                         if (!IsGoodCandidate(freq)) continue;
00270                         tmpFreq.AddElem(freq);
00271                 }
00272                 
00273                 // 2.4.- Frequency offset between peaks
00274                 for (int i = 0; i<peakIndexes.Size(); i++ )
00275                 {
00276                         if (i==nMaxMagPeak) continue;
00277                         for (int j = i+1; j<peakIndexes.Size(); j++)
00278                         {
00279                                 // be careful not to exceed the maximun permitted
00280                                 if (candidatesFrequency.Size() >= mnMaxCandidates) break;
00281                                 freq = peakFrequencies[peakIndexes[j]] - peakFrequencies[peakIndexes[i]];
00282                                 if (freq < peakFrequencies[peakIndexes[nMaxMagPeak]]*1.1)
00283                                         if (IsGoodCandidate(freq))
00284                                                 tmpFreq.AddElem(freq);
00285                         }
00286                 }
00287           
00288                 // 2.5.- Frequencies related to peaks by integer ratios (before: except for the 3 maximun peaks. not now)       
00289                 for (int i=0; i<peakIndexes.Size(); i++ )
00290                 {
00291                         for (int j=1; j <= mnInt; j++)
00292                         {
00293                                 // be careful not to exceed the maximun permitted
00294                                 if (candidatesFrequency.Size() >= mnMaxCandidates) break;
00295                                 freq = peakFrequencies[peakIndexes[i]]/j;
00296                                 if (freq < peakFrequencies[peakIndexes[nMaxMagPeak]]*1.1)
00297                                         if (IsGoodCandidate(freq))
00298                                                 tmpFreq.AddElem(freq);
00299                         }
00300                 }
00301         
00302                 if(candidatesFrequency.Size() <= 0)
00303                 {
00304                         mFundFreqValue.SendControl(0.0f);
00305                         return false;
00306                 }
00307 
00308                 // 3.- CALCULATE ERRORS (TMW procedure)
00309                 TData oneOverSeventyFive = 0.013333333333f;
00310                 
00311                 const int nPeaks = peaks.GetIndexArray().Size();
00312                 
00313                 int i;
00314                 
00315                 //These are all needed by the WeightCandidate and it is much better to compute just once                                
00316                 DataArray magFactor(nPeaks);
00317                 DataArray magFactor3(nPeaks);
00318                 DataArray magFactor4(nPeaks);
00319                 DataArray magFactor4r(nPeaks);
00320                 DataArray magFactor4q(nPeaks);
00321                 DataArray magFactor34q(nPeaks);
00322                                 
00323                 for (i=0; i<nPeaks; i++)
00324                 {
00325                         TData Mag = peakMagnitudes[peakIndexes[i]];
00326                         TData tmpMagFactor = TData(CLAM_max(0.0,maxMag - Mag + 20.0));
00327                         tmpMagFactor = TData(1.0) - tmpMagFactor*oneOverSeventyFive;
00328                         if (tmpMagFactor < 0)
00329                                 tmpMagFactor = 0;
00330                         magFactor[i] = tmpMagFactor;
00331                         magFactor3[i] = tmpMagFactor*tmpMagFactor*tmpMagFactor;
00332                         magFactor4[i] = magFactor3[i]*tmpMagFactor;
00333                         magFactor4r[i] = magFactor4[i]*mMPr;
00334                         magFactor4q[i] = magFactor4[i]*mMPq;
00335                         magFactor34q[i] = magFactor3[i] + magFactor4q[i];
00336                 }
00337                 
00338                 int maxNMP = CLAM_min(mMPnPeaks,nPeaks);
00339                 // predicted to measured mismatch error
00340                 int maxNPM = 10;
00341                 //xamat: does not depend on variable data: compute out of the loop!!
00342                 if (nPeaks > 4)
00343                         maxNPM = CLAM_min(mPMnPeaks,nPeaks);
00344                         
00345                 for (int i=0; i<candidatesFrequency.Size(); i++)
00346                 {
00347                         TData myFrequency = candidatesFrequency[i];
00348                         TData myError = WeightCandidate(myFrequency,peaks, magFactor, magFactor34q, magFactor4r, maxNMP, maxNPM);
00349                         candidatesError[i] = myError;
00350                 }
00351                 
00352                 // 4.- CHOOSE THE BEST CANDIDATES: choose the FundFreq.NCandidates() candidates with the smallest error
00353                 
00354                 tmpFreq.SortByError();
00355                 Fundamental tmpFreq2;
00356                 tmpFreq2.SetnMaxCandidates(candidatesFrequency.Size());
00357                 DataArray & candidates2Frequency = tmpFreq2.GetCandidatesFreq();
00358                 DataArray & candidates2Error = tmpFreq2.GetCandidatesErr();
00359 
00360                 for (int i=0;i<candidatesFrequency.Size();i++)
00361                 {
00362                         if (i<=0)
00363                         {
00364                                 tmpFreq2.AddElem(candidatesFrequency[i],candidatesError[i]);
00365                                 continue;
00366                         }
00367                         bool addedNearOne=false;
00368                         for(int j=0; j<candidates2Frequency.Size(); j++)
00369                         {
00370                                 if (candidatesFrequency[i]<=0.95*candidates2Frequency[j]) continue;
00371                                 if (candidatesFrequency[i]>=1.1*candidates2Frequency[j]) continue;
00372                                 addedNearOne = true;
00373                                 if(candidates2Error[j] > candidatesError[i])
00374                                 {
00375                                         candidates2Frequency[j] = candidatesFrequency[i];
00376                                         candidates2Error[j] = candidatesError[i];
00377                                 }
00378                         }
00379                         if(!addedNearOne)
00380                                 tmpFreq2.AddElem(candidatesFrequency[i],candidatesError[i]);
00381                 }
00382                 
00383                 // 5.- SEARCH AROUND FOR A RELATIVE MINIMUM
00384                 TData nMinimum = std::min(3,candidates2Frequency.Size());
00385                 for(int i=0; i<nMinimum; i++)
00386                 {
00387                         TData & myFrequency = candidates2Frequency[i];
00388                         TData Low  = myFrequency*TData(.9);
00389                         TData High = myFrequency*TData(1.1);
00390                         TData Incr = std::max(TData(1.0), myFrequency*TData(.008)); 
00391 
00392                         TData FinalPitch = candidates2Frequency[i];
00393                         TData FinalError = candidates2Error[i];
00394                         for(TData lPitch = Low; lPitch <=High; lPitch += Incr)
00395                         {
00396                                 TData lErr = WeightCandidate(lPitch,peaks, magFactor, magFactor34q, magFactor4r, maxNMP, maxNPM);
00397                                 if (lPitch > peakFrequencies[peakIndexes[nMaxMagPeak]]*1.1)
00398                                         lErr +=10;
00399                                 if (lErr < FinalError)
00400                                 {
00401                                         FinalPitch = lPitch;
00402                                         FinalError = lErr;
00403                                 }
00404                         }
00405                         candidates2Frequency[i] = FinalPitch;
00406                         candidates2Error[i] = FinalError;
00407                 }
00408 
00409                 // Ordering the minimum
00410                 tmpFreq2.SortByError();
00411 
00412                 TIndex nCandidates = std::min(outFreq.GetnMaxCandidates(),candidates2Frequency.Size());
00413                 for(int i=0; i<nCandidates; i++)
00414                         if(candidates2Error[i] <= mMaxFundFreqError)
00415                                 outFreq.AddElem(candidates2Frequency[i], candidates2Error[i]);
00416 
00417                 if(outFreq.GetnCandidates() == 0)
00418                 {
00419                         mFundFreqValue.SendControl(0.0f);
00420                         return false;
00421                 }
00422 
00423                 // Added to get into account fundamental frequency for consecutive frames
00424                 // Set Reference fundFreq to last FundFreq
00425                 mReferenceFundFreq = outFreq.GetFreq(0);
00426                 mFundFreqValue.SendControl( mReferenceFundFreq );
00427 
00428                 return true;
00429         }
00430         
00431         TData FundFreqDetect::WeightCandidate(TData freq, const SpectralPeakArray& peaks, const DataArray& magFactor, const DataArray& magFactor34q, 
00432                 const DataArray& magFactor4r, int maxNMP, int maxNPM) const
00433         {
00434                         TData Tmp;
00435                         const int nPeaks = peaks.GetIndexArray().Size();
00436                         const IndexArray & peakIndexes = peaks.GetIndexArray();
00437                         DataArray& peakFrequencies=peaks.GetFreqBuffer();
00438                         //DataArray& peakMagnitudes=peaks.GetMagBuffer();
00439                 
00440                         TData ErrorPM = 0;
00441                         TData ErrorMP = 0;
00442 
00443                         TData HarmonicPm = freq;
00444                         TSize nPM = maxNPM;
00445                         TData lastFreq=peakFrequencies[peakIndexes[nPeaks-1]];
00446                         
00447                         // measured to predicted mismatch error 
00448                         TData HarmonicMp = freq;
00449                         TSize nMP = nPeaks;
00450                         
00451                         int Peak =0;
00452                         int i;
00453                         
00454                         bool finishedPM = false;
00455                         bool finishedMP = false;
00456                         
00457                         TData tenTimesFreq = freq*10.f;
00458                         bool isFreqHigh = (freq>500.);
00459                         TData oneOverFundFreq = 1./freq;
00460                         
00461                         for (i=0; i<nPeaks; i++)
00462                         {
00463                                 if(!finishedPM)
00464                                 {
00465                                         if(i<maxNPM)
00466                                         {
00467                                                 if (HarmonicPm > lastFreq)
00468                                                 {
00469                                                         nPM = i+1;
00470                                                         finishedPM = true;
00471                                                         if (finishedMP) break;
00472                                                 }
00473                                                 else
00474                                                 {
00475                                                         Peak = GetClosestPeak(HarmonicPm,Peak, peakIndexes, peakFrequencies);
00476                                                         //xamat: does not depend on variable data: compute out of the loop!!
00477                                                         TData Freq = peakFrequencies[peakIndexes[Peak]];
00478                                                         //TData Mag  = peakMagnitudes[peakIndexes[Peak]];
00479                                                         
00480                                                         TData FreqDistance = Abs(Freq - HarmonicPm);
00481                                                         //xamat: note that default value for mPMp is 0.5 thus yielding a sqrt
00482 #ifdef CLAM_OPTIMIZE
00483                                                         Tmp = FreqDistance / CLAM_sqrt(HarmonicPm);
00484 #else                                                   
00485                                                         Tmp = FreqDistance * CLAM_pow(HarmonicPm, -mPMp);
00486 #endif
00487                                                         ErrorPM += (Tmp +magFactor[Peak] * (mPMq * Tmp - mPMr));
00488                                                         HarmonicPm += freq;
00489                                                 }
00490                                         }
00491                                 }
00492                         
00493                                 if(!finishedMP)
00494                                 {
00495                                         TData Freq = TData(peakFrequencies[peakIndexes[i]]);
00496                                         // For high frequency candidates, not get into account too-low peaks
00497                                         if ( (isFreqHigh) && (Freq < 100))
00498                                                 continue;
00499                                         
00500                                         HarmonicMp = GetClosestHarmonic(Freq,freq, oneOverFundFreq);
00501                                         TData FreqDistance = Abs(Freq - HarmonicMp);
00502                                         //xamat: note that default value for mMPp is 0.5 thus yielding a sqrt                                                   
00503 #ifdef CLAM_OPTIMIZE
00504                                         Tmp = FreqDistance / CLAM_sqrt(Freq);
00505 #else                                   
00506                                         Tmp = FreqDistance * CLAM_pow(Freq, -mMPp);
00507 #endif
00508                                         ErrorMP += magFactor34q[i] * Tmp - magFactor4r[i];
00509                                         if (Freq > tenTimesFreq){
00510                                                 if (i > maxNMP)
00511                                                 {
00512                                                         nMP =   i+1;
00513                                                         finishedMP = true;
00514                                                         if (finishedPM) break;
00515                                                 }
00516                                         }
00517                                 }
00518                         }
00519         
00520                 
00521                 // total error
00522                 if (ErrorPM > 20)
00523                         ErrorPM = 20 + (ErrorPM-20)*(ErrorPM-20);
00524                 if (ErrorMP > 20)
00525                         ErrorMP = 20 + (ErrorMP-20)*(ErrorMP-20);
00526 
00527                 return (mPMCont * ErrorPM/nPM + mMPCont * ErrorMP/nMP);
00528         }
00529 
00530         /* Get the closest peak to a given frequency 
00531            and returns the number of the closest peak 
00532            there's another parameter, peak, that contains the last peak taken   */
00533         int FundFreqDetect::GetClosestPeak(TData freq, int firstPeak, const IndexArray& peakIndexes, const DataArray & peakFrequencies) const
00534         {
00535                 const int size = peakIndexes.Size();
00536                 int bestpeak = firstPeak;
00537                 TData distance = INFINITE_MAGNITUD;
00538                 for (int peak=firstPeak; peak < size; peak++)
00539                 {
00540                         TData nextdistance = Abs(freq - peakFrequencies[peakIndexes[peak]]);
00541                         if (nextdistance >= distance)
00542                                 return peak-1;
00543                         bestpeak = peak; 
00544                         distance=nextdistance;
00545                 }
00546                 return bestpeak;
00547         }
00548 
00549         /* Get Closest Harmonic */
00550         TData FundFreqDetect::GetClosestHarmonic(TData peak, TData fundfreq, TData oneOverFundfreq) const
00551         {
00552                 if(peak<fundfreq)
00553                         return fundfreq;
00554                 //xamat: this should be optimized!
00555                 return floor(peak*oneOverFundfreq+.5)*fundfreq;
00556         }
00557 
00558         bool FundFreqDetect::IsGoodCandidate(TData freq) const
00559         {
00560                 return (freq >= mLowestFundFreq)  && (freq <= mHighestFundFreq);
00561         }
00562 
00563 } // namespace CLAM
00564 
Generated by  doxygen 1.6.3