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   distance=-1;
00220   int nPeaks=iPeakArray.GetnPeaks();
00221   DataArray& peakFreqBuffer=iPeakArray.GetFreqBuffer();
00222   TData factor=100./currentPeakFreq;
00223   
00224   //xamat: test!
00225   SearchArray<TData> mySearch(peakFreqBuffer);
00226   TIndex found=mySearch.Find(currentPeakFreq);
00227   if (found==-1) found = 0; //Pau: to avoid assert. Is this the correct behaviour?
00228   TIndex originalFound = found;
00229   distance = Abs(peakFreqBuffer[found]-currentPeakFreq);
00230   //make sure that the two surrounding peaks are not in fact closer
00231   TIndex newFound;
00232   TData nextDistance;
00233   if(originalFound<nPeaks-1)
00234   {
00235         for(newFound=found+1; newFound<nPeaks; newFound++)
00236         {
00237                 nextDistance = Abs(peakFreqBuffer[newFound]-currentPeakFreq);
00238                 if(nextDistance>distance) break;
00239                 distance = nextDistance;
00240         }
00241         found = newFound-1;
00242   }
00243   if(originalFound>0)
00244   {
00245         for(newFound=found-1; newFound>-1; newFound--)
00246         {
00247                 nextDistance = Abs(peakFreqBuffer[newFound]-currentPeakFreq);
00248                 if(nextDistance>distance) break;
00249                 distance = nextDistance;
00250                 }
00251         found = newFound + 1;
00252   }
00253   distance *= factor;
00254   return found;
00255 }
00256 
00257 
00258 
00259 //true if there is no peak in previousPeakArray closer to candidate
00260 
00261 bool SinTracking::IsBestCandidate(TData candidateFreq, TData currentFreq) const
00262 {
00263         double nextDistance=Abs(currentFreq-candidateFreq);
00264 
00265         int nPeaks=mPreviousPeakArray.GetnPeaks();
00266         DataArray& peakFreqBuffer=mPreviousPeakArray.GetFreqBuffer();
00267         for(int i=0;i<nPeaks;i++)
00268         {
00269                 if(Abs(peakFreqBuffer[i]-candidateFreq)<nextDistance) return false;
00270         }
00271         return true;
00272 
00273 }
00274 
00275 
00276 
00277 //Set the best candidate in oPeakArray at the same position as in iPeakArray
00278 //with the same index as the peak it continues
00279 void SinTracking::Match(TIndex trackId, TIndex peakIndex,
00280                                                  const SpectralPeak& currentPeak, 
00281                                                  SpectralPeakArray& oPeakArray) const
00282 {
00283   CLAM_ASSERT(peakIndex<oPeakArray.GetnPeaks(),"SinTracking::Match: Not a valid peak Index");
00284   oPeakArray.SetSpectralPeak(peakIndex,currentPeak,trackId);
00285   
00286 }
00287 
00288 
00289 
00290 /*Function to check peaks in next frame that have not been matched to peaks in current
00291 frame. These are then assigned to newborn tracks.*/
00292 void SinTracking::CheckForNewBornTracks(const SpectralPeakArray& iPeakArray,SpectralPeakArray& oPeakArray) const
00293 {
00294   TIndex nonAssignedPeakIndex=0;
00295   bool notFinished=true;
00296   nonAssignedPeakIndex=GetFirstNonAssignedPeakPos(oPeakArray,nonAssignedPeakIndex);
00297   while(notFinished)
00298   {
00299    if(nonAssignedPeakIndex == -1)
00300    {
00301          notFinished=false;
00302          break;
00303    }
00304    else
00305    {
00306          /*Note that when a new track is born the Id assigned is next index. This gives
00307          us and idea of the number of total tracks that have been born and died up to
00308          now, unique ID*/
00309          AddNewTrack(nonAssignedPeakIndex,iPeakArray.GetSpectralPeak(nonAssignedPeakIndex),oPeakArray);
00310          nonAssignedPeakIndex++;
00311          nonAssignedPeakIndex=GetFirstNonAssignedPeakPos(oPeakArray,nonAssignedPeakIndex);
00312    }
00313   }
00314 
00315 }
00316 
00317 
00318 /*Returns index of first peak that has not been assigned to a track (-1 if all have
00319 already been assigned)*/
00320 //beginAt=0? why not starting from the previous new track index?
00321 TIndex SinTracking::GetFirstNonAssignedPeakPos(const SpectralPeakArray& oPeakArray, TIndex beginAt=0) const
00322 {
00323         const TIndex nPeaks = oPeakArray.GetnPeaks();
00324         if (beginAt>=nPeaks) return -1;
00325         if (beginAt<0) return -1;
00326 
00327         int i=oPeakArray.GetFirstNonValidIndexPosition(beginAt);
00328 
00329         if(i==nPeaks) return -1;//All peaks have been matched
00330 
00331         return i;
00332 }
00333 
00334 
00335 //Initialization of the first output peak array: all peaks must be assigned a track
00336 void SinTracking::Initialization(const SpectralPeakArray& iPeakArray, SpectralPeakArray& oPeakArray)
00337 {
00338         TSize nPeaks=oPeakArray.GetnPeaks();
00339         for(int i=0; i<nPeaks; i++)
00340         {
00341                 AddNewTrack(i, iPeakArray.GetSpectralPeak(i), oPeakArray);
00342         }
00343         mPreviousPeakArray=oPeakArray;
00344 }
00345 
00346 void SinTracking::KillAll()
00347 {
00348         for (int i=0;i<mnMaxSines;i++)
00349         {
00350                 mGuideArray[i].isDead=true;
00351         }
00352         mnActiveGuides=0;
00353 }
00354 
00355 bool SinTracking::DoInharmonic(const SpectralPeakArray& iPeakArray,SpectralPeakArray& oPeakArray)
00356 {
00357         if(iPeakArray.GetnPeaks()<mnMaxSines)
00358                 oPeakArray.SetnPeaks(iPeakArray.GetnPeaks());
00359         else
00360                 oPeakArray.SetnPeaks(mnMaxSines);
00361 
00362         oPeakArray.ResetIndices();
00363         oPeakArray.InitIndices();
00364         oPeakArray.SetScale(EScale(EScale::eLog));
00365         
00366         if(!mInitialized)
00367         {
00368                 Initialization(iPeakArray, oPeakArray);
00369                 mInitialized=true;
00370                 return true;
00371         }
00372         
00373         oPeakArray.SetIsIndexUpToDate(true);
00374         for(int i=0;i<mPreviousPeakArray.GetnPeaks();i++)
00375         {
00376                 Tracking(iPeakArray,oPeakArray,i);
00377         }
00378         CheckForNewBornTracks(iPeakArray,oPeakArray);
00379         mPreviousPeakArray=oPeakArray;
00380         
00381         //xamat: testing not to keep inharmonic peaks
00382         //oPeakArray.SetnPeaks(0);
00383         //mPreviousPeakArray=oPeakArray;
00384         return true;
00385 }
00386 
00387 
00388 /* Harmonic Peak Continuation */
00389 bool SinTracking::DoHarmonic(const SpectralPeakArray& in, SpectralPeakArray& out,TData funFreq)
00390 {
00391         out.SetnPeaks(mnMaxSines);
00392 
00393         out.ResetIndices();
00394         out.SetScale(EScale(EScale::eLog));
00395         
00396         InitHarmonicTracks(out,funFreq);
00397         out.SetIsIndexUpToDate(true);
00398         HarmonicTracking(in, out, funFreq);
00399         mPreviousPeakArray=out;
00400         return true;
00401 
00402 }
00403 
00404 void SinTracking::HarmonicTracking(const SpectralPeakArray& in,SpectralPeakArray& out,TData funFreq)
00405 {
00406         TData d;
00407         TIndex pos;
00408         
00409         out.SetnPeaks(mnMaxSines);
00410         
00411         //DataArray& iFreqBuffer=in.GetFreqBuffer();
00412         DataArray& oFreqBuffer=out.GetFreqBuffer();
00413         DataArray& iMagBuffer=in.GetMagBuffer();
00414         DataArray& oMagBuffer=out.GetMagBuffer();
00415         DataArray& iPhaseBuffer=in.GetPhaseBuffer();
00416         DataArray& oPhaseBuffer=out.GetPhaseBuffer();
00417 
00418         
00419         int i;
00420 
00421         TSize nPeaks=mnMaxSines;
00422         i=0;
00423         int n;
00424         for(n=0; n<mnMaxSines;n++)
00425         {
00426                 pos=GetCandidate(oFreqBuffer[i],in,d);
00427                 if(d<funFreq/2 && pos>-1)
00428                 {
00429                         if(i==0 || iMagBuffer[pos]!=oMagBuffer[i-1])
00430                         {
00431                                 oMagBuffer[i]=iMagBuffer[pos];
00432                                 oFreqBuffer[i]=oFreqBuffer[n];
00433                                 oPhaseBuffer[i]=iPhaseBuffer[pos];
00434                                 i++;
00435                         }
00436                 }
00437         }
00438         out.SetnPeaks(i);
00439 }
00440 
00441 void SinTracking::InitHarmonicTracks(SpectralPeakArray& peaks, TData funFreq)
00442 {
00443         DataArray& freqBuffer=peaks.GetFreqBuffer();
00444         DataArray& magBuffer=peaks.GetMagBuffer();
00445         
00446         int i;
00447         
00448         TData currentFreq=funFreq;
00449 
00450         for(i=0;i<mnMaxSines;i++)
00451         {
00452                 freqBuffer[i]=currentFreq;
00453                 magBuffer[i]=-99;
00454                 currentFreq+=funFreq;
00455         }
00456 }
00457 
00458 } // namespace CLAM
00459 
Generated by  doxygen 1.6.3