SinTracking.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 "SinTracking.hxx"
00023 #include "SearchArray.hxx"
00024 
00025 
00026 namespace CLAM
00027 {
00028 
00029 
00030 SinTracking::SinTracking()
00031         : mInput("Input", this ),
00032           mOutput("Output", this ),
00033           mFundFreqValue("Fund Freq Value", this )
00034 {
00035         Configure(SinTrackingConfig());
00036 }
00037 
00038 SinTracking::SinTracking(const SinTrackingConfig &c )
00039         : mInput("Input", this ),
00040           mOutput("Output", this ),
00041           mFundFreqValue("Fund Freq Value", this )
00042 
00043 {
00044         Configure(c);
00045 }
00046 
00047 SinTracking::~SinTracking()
00048 {}
00049 
00050 
00051 
00052 
00053 /* Configure the Processing Object according to the Config object */
00054 
00055 bool SinTracking::ConcreteConfigure(const ProcessingConfig& c)
00056 {           
00057 
00058         CopyAsConcreteConfig(mConfig, c);
00059 
00060         mnMaxSines = mConfig.GetnMaxSines();
00061 
00062         mThreshold= mConfig.GetThreshold();
00063 
00064         mHarmonic= mConfig.GetIsHarmonic();
00065 
00066         mnActiveGuides=0;
00067 
00068         mNextTrackId=0;
00069 
00070         mInitialized=false;
00071         mLastHarmonic=false;
00072         
00073         int i;
00074         //initializes guide array
00075         mGuideArray.Resize(mnMaxSines);
00076 
00077         mGuideArray.SetSize(mnMaxSines);
00078         for(i=0;i<mnMaxSines;i++)
00079         {
00080                 mGuideArray[i].isDead=true;
00081         }
00082         
00083         return true;
00084 }
00085 
00086 
00087 
00088 
00089 //Process
00090 
00091 
00092 //Supervised mode
00093 bool  SinTracking::Do(void) 
00094 {
00095         bool result = Do( mInput.GetData(), mOutput.GetData() );
00096         mInput.Consume();
00097         mOutput.Produce();
00098         return result;
00099 }
00100 
00101 bool SinTracking::Do(const SpectralPeakArray& iPeakArray,SpectralPeakArray& oPeakArray)
00102 {
00103         //oPeakArray initialization             
00104         oPeakArray.AddIndexArray();
00105         oPeakArray.AddPhaseBuffer();
00106         oPeakArray.AddBinWidthBuffer();
00107         oPeakArray.AddBinPosBuffer();
00108         oPeakArray.UpdateData();
00109 
00110         TData fn = mFundFreqValue.GetLastValue();
00111         if(mHarmonic && fn>0)
00112         {
00113                 mLastHarmonic=true;
00114                 return DoHarmonic(iPeakArray,oPeakArray,fn);
00115         }
00116         else
00117         {
00118                 if(mLastHarmonic) KillAll();
00119                 mLastHarmonic=false;
00120                 return DoInharmonic(iPeakArray,oPeakArray);
00121         }
00122 }
00123 
00124 
00125 void SinTracking::AddNewTrack(int peakPosition, const SpectralPeak& currentPeak,SpectralPeakArray& oPeakArray) const
00126 {
00127   for(int i=0;i<mnMaxSines;i++)
00128   {
00129         if(mGuideArray[i].isDead==true)
00130         {
00131           mGuideArray[i].isDead=false;
00132           mGuideArray[i].trackId=mNextTrackId;
00133           mGuideArray[i].freq=currentPeak.GetFreq();
00134           mGuideArray[i].mag=currentPeak.GetMag();
00135           oPeakArray.SetSpectralPeak(peakPosition,currentPeak, mNextTrackId);
00136           mNextTrackId++;
00137           mnActiveGuides++;
00138           break;
00139         }
00140   }
00141 
00142 }
00143 
00144 
00145 
00146 void SinTracking::Tracking(const SpectralPeakArray& iPeakArray,SpectralPeakArray& oPeakArray,TIndex processedPeakPos) const
00147 {
00148         const DataArray & previousFreqBuffer = mPreviousPeakArray.GetFreqBuffer();
00149         const IndexArray & previousIndexBuffer = mPreviousPeakArray.GetIndexArray();
00150         TData currentPeakFreq = previousFreqBuffer[processedPeakPos];
00151 
00152         const DataArray& iFreqBuffer=iPeakArray.GetFreqBuffer();
00153 
00154         if(!ThereIsCandidate(currentPeakFreq,iPeakArray,oPeakArray))
00155         {
00156                 KillTrack(previousIndexBuffer[processedPeakPos]);
00157                 return;
00158         }
00159 
00160         TData distance;
00161         int candidatePos=GetCandidate(currentPeakFreq,iPeakArray,distance);
00162         if(candidatePos==-1) return;
00163         TData candidatePeakFreq = iFreqBuffer[candidatePos];
00164 
00165         if( candidatePos>=oPeakArray.GetnPeaks()
00166             || (!IsBestCandidate(candidatePeakFreq,currentPeakFreq))
00167             || (oPeakArray.GetIndex(candidatePos)!=-1) )
00168         {
00169                 KillTrack(previousIndexBuffer[processedPeakPos]);
00170                 return;
00171         }
00172 
00173         // TODO: Optimize this by accessing directly to the buffers
00174         // instead of calling Set/GetSpectralPeak
00175         const SpectralPeak candidatePeak = iPeakArray.GetSpectralPeak(candidatePos);
00176         TIndex trackId = previousIndexBuffer[processedPeakPos];
00177         oPeakArray.SetSpectralPeak(candidatePos,candidatePeak,trackId);
00178 }
00179 
00180 
00181 
00182 //true as soon as the distance between currentPeak and a Peak in iPeakArray is <mThreshold
00183 bool SinTracking::ThereIsCandidate(TData currentPeakFreq, 
00184                                    const SpectralPeakArray& iPeakArray,
00185                                    SpectralPeakArray& oPeakArray) const
00186 {
00187   TSize nInputPeaks=iPeakArray.GetnPeaks();
00188   if(nInputPeaks>mnMaxSines) nInputPeaks=mnMaxSines;
00189   DataArray& peakFreqBuffer=iPeakArray.GetFreqBuffer();   
00190   TData factor=100/currentPeakFreq;
00191   IndexArray& outputIndexArray=oPeakArray.GetIndexArray();
00192   for (int i=0;i<nInputPeaks;i++)
00193   {
00194         int dist=int(Abs(peakFreqBuffer[i]-currentPeakFreq)*factor);
00195         if((dist< mThreshold)&&(outputIndexArray[i]==-1)) return true;
00196   }
00197   return false;
00198 }
00199 
00200 
00201 //Sets mGuideArray.isDead to true and mnActiveGuides--
00202 void SinTracking::KillTrack(int trackId) const
00203 {
00204         for(int i=0;i<mnMaxSines;i++)
00205         {
00206                 if(mGuideArray[i].trackId!=trackId) continue;
00207                 mGuideArray[i].isDead=true;
00208                 mnActiveGuides--;
00209                 return;
00210         }
00211 }
00212 
00213 //Return the position of the peak in iPeakArray which is the closest to currentPeak
00214 TIndex SinTracking::GetCandidate(TData currentPeakFreq, 
00215                                                                            const SpectralPeakArray& iPeakArray,
00216                                                                            TData& distance) const
00217 {
00218   //Can be optimized! XA
00219   TIndex bestCandidate=-1;
00220   TData tmpDistance;
00221   distance=-1;
00222   int nPeaks=iPeakArray.GetnPeaks();
00223   DataArray& peakFreqBuffer=iPeakArray.GetFreqBuffer();
00224   TData factor=100./currentPeakFreq;
00225   
00226   //xamat: test!
00227   SearchArray<TData> mySearch(peakFreqBuffer);
00228   TIndex found=mySearch.Find(currentPeakFreq);
00229   if (found==-1) found = 0; //Pau: to avoid assert. Is this the correct behaviour?
00230   TIndex originalFound = found;
00231   distance = Abs(peakFreqBuffer[found]-currentPeakFreq);
00232   //make sure that the two surrounding peaks are not in fact closer
00233   TIndex newFound;
00234   TData nextDistance;
00235   if(originalFound<nPeaks-1)
00236   {
00237         for(newFound=found+1; newFound<nPeaks; newFound++)
00238         {
00239                 nextDistance = Abs(peakFreqBuffer[newFound]-currentPeakFreq);
00240                 if(nextDistance>distance) break;
00241                 distance = nextDistance;
00242         }
00243         found = newFound-1;
00244   }
00245   if(originalFound>0)
00246   {
00247         for(newFound=found-1; newFound>-1; newFound--)
00248         {
00249                 nextDistance = Abs(peakFreqBuffer[newFound]-currentPeakFreq);
00250                 if(nextDistance>distance) break;
00251                 distance = nextDistance;
00252                 }
00253         found = newFound + 1;
00254   }
00255   distance *= factor;
00256   return found;
00257 }
00258 
00259 
00260 
00261 //true if there is no peak in previousPeakArray closer to candidate
00262 
00263 bool SinTracking::IsBestCandidate(TData candidateFreq, TData currentFreq) const
00264 {
00265         double nextDistance=Abs(currentFreq-candidateFreq);
00266 
00267         int nPeaks=mPreviousPeakArray.GetnPeaks();
00268         DataArray& peakFreqBuffer=mPreviousPeakArray.GetFreqBuffer();
00269         for(int i=0;i<nPeaks;i++)
00270         {
00271                 if(Abs(peakFreqBuffer[i]-candidateFreq)<nextDistance) return false;
00272         }
00273         return true;
00274 
00275 }
00276 
00277 
00278 
00279 //Set the best candidate in oPeakArray at the same position as in iPeakArray
00280 //with the same index as the peak it continues
00281 void SinTracking::Match(TIndex trackId, TIndex peakIndex,
00282                                                  const SpectralPeak& currentPeak, 
00283                                                  SpectralPeakArray& oPeakArray) const
00284 {
00285   CLAM_ASSERT(peakIndex<oPeakArray.GetnPeaks(),"SinTracking::Match: Not a valid peak Index");
00286   oPeakArray.SetSpectralPeak(peakIndex,currentPeak,trackId);
00287   
00288 }
00289 
00290 
00291 
00292 /*Function to check peaks in next frame that have not been matched to peaks in current
00293 frame. These are then assigned to newborn tracks.*/
00294 void SinTracking::CheckForNewBornTracks(const SpectralPeakArray& iPeakArray,SpectralPeakArray& oPeakArray) const
00295 {
00296   TIndex nonAssignedPeakIndex=0;
00297   bool notFinished=true;
00298   nonAssignedPeakIndex=GetFirstNonAssignedPeakPos(oPeakArray,nonAssignedPeakIndex);
00299   while(notFinished)
00300   {
00301    if(nonAssignedPeakIndex == -1)
00302    {
00303          notFinished=false;
00304          break;
00305    }
00306    else
00307    {
00308          /*Note that when a new track is born the Id assigned is next index. This gives
00309          us and idea of the number of total tracks that have been born and died up to
00310          now, unique ID*/
00311          AddNewTrack(nonAssignedPeakIndex,iPeakArray.GetSpectralPeak(nonAssignedPeakIndex),oPeakArray);
00312          nonAssignedPeakIndex++;
00313          nonAssignedPeakIndex=GetFirstNonAssignedPeakPos(oPeakArray,nonAssignedPeakIndex);
00314    }
00315   }
00316 
00317 }
00318 
00319 
00320 /*Returns index of first peak that has not been assigned to a track (-1 if all have
00321 already been assigned)*/
00322 //beginAt=0? why not starting from the previous new track index?
00323 TIndex SinTracking::GetFirstNonAssignedPeakPos(const SpectralPeakArray& oPeakArray, TIndex beginAt=0) const
00324 {
00325         const TIndex nPeaks = oPeakArray.GetnPeaks();
00326         if (beginAt>=nPeaks) return -1;
00327         if (beginAt<0) return -1;
00328 
00329         int i=oPeakArray.GetFirstNonValidIndexPosition(beginAt);
00330 
00331         if(i==nPeaks) return -1;//All peaks have been matched
00332 
00333         return i;
00334 }
00335 
00336 
00337 //Initialization of the first output peak array: all peaks must be assigned a track
00338 void SinTracking::Initialization(const SpectralPeakArray& iPeakArray, SpectralPeakArray& oPeakArray)
00339 {
00340         TSize nPeaks=oPeakArray.GetnPeaks();
00341         for(int i=0; i<nPeaks; i++)
00342         {
00343                 AddNewTrack(i, iPeakArray.GetSpectralPeak(i), oPeakArray);
00344         }
00345         mPreviousPeakArray=oPeakArray;
00346 }
00347 
00348 void SinTracking::KillAll()
00349 {
00350         for (int i=0;i<mnMaxSines;i++)
00351         {
00352                 mGuideArray[i].isDead=true;
00353         }
00354         mnActiveGuides=0;
00355 }
00356 
00357 bool SinTracking::DoInharmonic(const SpectralPeakArray& iPeakArray,SpectralPeakArray& oPeakArray)
00358 {
00359         if(iPeakArray.GetnPeaks()<mnMaxSines)
00360                 oPeakArray.SetnPeaks(iPeakArray.GetnPeaks());
00361         else
00362                 oPeakArray.SetnPeaks(mnMaxSines);
00363 
00364         oPeakArray.ResetIndices();
00365         oPeakArray.InitIndices();
00366         oPeakArray.SetScale(EScale(EScale::eLog));
00367         
00368         if(!mInitialized)
00369         {
00370                 Initialization(iPeakArray, oPeakArray);
00371                 mInitialized=true;
00372                 return true;
00373         }
00374         
00375         oPeakArray.SetIsIndexUpToDate(true);
00376         for(int i=0;i<mPreviousPeakArray.GetnPeaks();i++)
00377         {
00378                 Tracking(iPeakArray,oPeakArray,i);
00379         }
00380         CheckForNewBornTracks(iPeakArray,oPeakArray);
00381         mPreviousPeakArray=oPeakArray;
00382         
00383         //xamat: testing not to keep inharmonic peaks
00384         //oPeakArray.SetnPeaks(0);
00385         //mPreviousPeakArray=oPeakArray;
00386         return true;
00387 }
00388 
00389 
00390 /* Harmonic Peak Continuation */
00391 bool SinTracking::DoHarmonic(const SpectralPeakArray& in, SpectralPeakArray& out,TData funFreq)
00392 {
00393         out.SetnPeaks(mnMaxSines);
00394 
00395         out.ResetIndices();
00396         out.SetScale(EScale(EScale::eLog));
00397         
00398         InitHarmonicTracks(out,funFreq);
00399         out.SetIsIndexUpToDate(true);
00400         HarmonicTracking(in, out, funFreq);
00401         mPreviousPeakArray=out;
00402         return true;
00403 
00404 }
00405 
00406 void SinTracking::HarmonicTracking(const SpectralPeakArray& in,SpectralPeakArray& out,TData funFreq)
00407 {
00408         TData d;
00409         TIndex pos;
00410         
00411         out.SetnPeaks(mnMaxSines);
00412         
00413         //DataArray& iFreqBuffer=in.GetFreqBuffer();
00414         DataArray& oFreqBuffer=out.GetFreqBuffer();
00415         DataArray& iMagBuffer=in.GetMagBuffer();
00416         DataArray& oMagBuffer=out.GetMagBuffer();
00417         DataArray& iPhaseBuffer=in.GetPhaseBuffer();
00418         DataArray& oPhaseBuffer=out.GetPhaseBuffer();
00419 
00420         
00421         int i;
00422 
00423         TSize nPeaks=mnMaxSines;
00424         i=0;
00425         int n;
00426         for(n=0; n<mnMaxSines;n++)
00427         {
00428                 pos=GetCandidate(oFreqBuffer[i],in,d);
00429                 if(d<funFreq/2 && pos>-1)
00430                 {
00431                         if(i==0 || iMagBuffer[pos]!=oMagBuffer[i-1])
00432                         {
00433                                 oMagBuffer[i]=iMagBuffer[pos];
00434                                 oFreqBuffer[i]=oFreqBuffer[n];
00435                                 oPhaseBuffer[i]=iPhaseBuffer[pos];
00436                                 i++;
00437                         }
00438                 }
00439         }
00440         out.SetnPeaks(i);
00441 }
00442 
00443 void SinTracking::InitHarmonicTracks(SpectralPeakArray& peaks, TData funFreq)
00444 {
00445         DataArray& freqBuffer=peaks.GetFreqBuffer();
00446         DataArray& magBuffer=peaks.GetMagBuffer();
00447         
00448         int i;
00449         
00450         TData currentFreq=funFreq;
00451 
00452         for(i=0;i<mnMaxSines;i++)
00453         {
00454                 freqBuffer[i]=currentFreq;
00455                 magBuffer[i]=-99;
00456                 currentFreq+=funFreq;
00457         }
00458 }
00459 
00460 } // namespace CLAM
00461 

Generated on Tue Aug 12 22:33:44 2008 for CLAM by  doxygen 1.5.5