CleanTracks.cxx

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2001-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 #include "CleanTracks.hxx"
00022 #include <iostream>
00023 
00024 
00025 namespace CLAM {
00026 
00027 
00028         void CleanTracksConfig::DefaultInit()
00029         {
00030 
00031                 AddAll();
00032                 UpdateData();
00033 
00034                 //Default values
00035                 SetMaxDropOut(3);
00036                 SetMinLength(3);
00037                 SetFreqDev(20);
00038                 SetSamplingRate(44100);
00039                 SetSpecSize(22050);
00040         }
00041 
00042         CleanTracks::CleanTracks():mTrajectoryArray(100,100),mSearchTrajectories(mTrajectoryArray)
00043         {
00044                 Configure(CleanTracksConfig());
00045         }
00046 
00047         CleanTracks::CleanTracks(const CleanTracksConfig &c ):mTrajectoryArray(100,100),mSearchTrajectories(mTrajectoryArray)
00048         {
00049                 Configure(c);
00050         }
00051 
00052         CleanTracks::~CleanTracks()
00053         {}
00054 
00055 
00056 
00057 
00058 /* Configure the Processing Object according to the Config object */
00059 
00060         bool CleanTracks::ConcreteConfigure(const ProcessingConfig& c)
00061         {
00062 
00063                 CopyAsConcreteConfig(mConfig, c);
00064 
00065                 mMaxDropOut = mConfig.GetMaxDropOut();
00066                 mMinLength= mConfig.GetMinLength();
00067                 mFreqDev= 1.0/mConfig.GetFreqDev();
00068                 mSamplingRate= mConfig.GetSamplingRate();
00069                 mSpecSize= mConfig.GetSpecSize();
00070                 return true;
00071         }
00072 
00073 
00074 
00075 
00076 //Process
00077 
00078 
00079         //Supervised mode
00080         bool  CleanTracks::Do(void)
00081         {
00082                 CLAM_ASSERT(false,"CleanTracks::Do(): Supervised mode not implemented");
00083                 return false;
00084         }
00085 
00086         bool CleanTracks::Do(Array<SpectralPeakArray*>& peakArrayArray)
00087         {
00088 
00089                 LoadTracks(peakArrayArray);
00090                 FindContinuations();
00091                 JoinContinuations(peakArrayArray);
00092                 Clean(peakArrayArray);
00093                 UpdateTrackIds(peakArrayArray);
00094                 return true;
00095         }
00096 
00097         bool CleanTracks::Do(Segment& segment)
00098         {
00099                 const int nFrames=segment.GetnFrames();
00100                 Array<SpectralPeakArray*> spectralPeakArrayArray;
00101                 spectralPeakArrayArray.Resize(nFrames);
00102                 for(int i=0;i<nFrames;i++)
00103                 {
00104                         spectralPeakArrayArray.AddElem(&segment.GetFrame(i).GetSpectralPeakArray());
00105                 }
00106                 return Do(spectralPeakArrayArray);
00107 
00108         }
00109 
00110         void CleanTracks::LoadTracks(Array<SpectralPeakArray*>& peakArrayArray)
00111         {
00112                 for(int i=0;i<peakArrayArray.Size();i++)
00113                 {
00114                         for(int z=0;z<peakArrayArray[i]->GetnIndexedPeaks();z++)
00115                         {
00116                                 TTrajectory tmpTrajectory;
00117                                 tmpTrajectory.id=peakArrayArray[i]->GetIndex(z);
00118                                 tmpTrajectory.beginPos=i;
00119                                 tmpTrajectory.initialFreq=tmpTrajectory.finalFreq=peakArrayArray[i]->GetFreq(z);//At the beginning, initial=final
00120                                 tmpTrajectory.initialMag=tmpTrajectory.finalMag=peakArrayArray[i]->GetMag(z);
00121                                 tmpTrajectory.length=1;
00122                                 tmpTrajectory.continuedAtId=-1;
00123                                 AddTrajectory(tmpTrajectory);
00124                         }
00125                 }
00126         }
00127 
00128         void CleanTracks::FindContinuations()
00129         {
00130                 int firstCandidatable = 0;
00131 
00132                 for(int i=0; i<mTrajectoryArray.Size(); i++)
00133                 {
00134                         const TTrajectory & toBeAppended = mTrajectoryArray[i];
00135 /*
00136                         // Non-candidatables now won't be candidatables never
00137                         while (firstCandidatable<i && toBeAppended.beginPos <
00138                                 mTrajectoryArray[firstCandidatable].beginPos+
00139                                 mTrajectoryArray[firstCandidatable].length+mMaxDropOut)
00140                                 firstCandidatable++;
00141 */
00142                         bool thereIsCandidate=false;
00143                         // MRJ: Transition of Frequency deviation from absolute hertz to
00144                         // a %. We multiply this factor by the currently considered trajectory
00145                         // final frequency
00146                         TData bestFreqDif=mFreqDev * mTrajectoryArray[i].finalFreq ;
00147                         int bestCandidate=0;
00148 
00149                         // Get the best 'candidate' to be followed by the track 'toBeAppended'
00150                         for(int k=firstCandidatable; k<i; k++)
00151                         {
00152                                 const TTrajectory & candidate = mTrajectoryArray[k];
00153 
00154                                 // Suposing that they are ordered by start frame,
00155                                 // there is a point from which all the candidates are invalid
00156                                 if (candidate.beginPos>=toBeAppended.beginPos) break;
00157 
00158                                 const TSize dropOut=
00159                                         toBeAppended.beginPos-
00160                                                 (candidate.beginPos+candidate.length);
00161 
00162                                 // 'candidate' should end before 'toBeAppended' starts
00163                                 if (dropOut<=0) continue;
00164                                 // ...but not too much
00165                                 if (dropOut>mMaxDropOut) continue;
00166 
00167                                 // ...and the frequency distance should be the better one
00168                                 const TData frequencyDistance =
00169                                         Abs(toBeAppended.initialFreq-candidate.finalFreq);
00170                                 if (frequencyDistance >= bestFreqDif) continue;
00171 
00172                                 bestFreqDif=frequencyDistance;
00173                                 bestCandidate=k;
00174                                 thereIsCandidate=true;
00175                         }
00176 
00177                         // If there is no candidate, toBeAppended is not appended, next...
00178                         if (!thereIsCandidate) continue;
00179 
00180                         TTrajectory & candidateTrajectory = mTrajectoryArray[bestCandidate];
00181 
00182                         // Check that the best candidate for 'toBeAppended'
00183                         // is not the best one to another
00184 
00185                         // Unused variable: const TSize candidateEnd = candidateTrajectory.beginPos+candidateTrajectory.length;
00186 
00187                         TSize previousFollowerPosition = candidateTrajectory.continuedAtId;
00188                         // Candidate has already has been attached?
00189                         if (previousFollowerPosition != -1)
00190                         {
00191                                 TTrajectory & previousFollower = mTrajectoryArray[previousFollowerPosition];
00192                                 const TData frequencyDistance =
00193                                         Abs(previousFollower.initialFreq-candidateTrajectory.finalFreq);
00194                                 if (frequencyDistance <= bestFreqDif) continue;
00195                         }
00196 
00197                         candidateTrajectory.continuedAtId=toBeAppended.id;
00198 
00199                 }
00200         }
00201 
00202         void CleanTracks::JoinContinuations(Array<SpectralPeakArray*>& peakArrayArray)
00203         {
00204                 for(int i=0;i<mTrajectoryArray.Size();i++)
00205                 {
00206                         // Unused variable: const int id     = mTrajectoryArray[i].id;
00207                         int contAt = mTrajectoryArray[i].continuedAtId;
00208                         // Unused variable: const int begPos = mTrajectoryArray[i].beginPos;
00209                         // Unused variable: const int lastfreq=int(mTrajectoryArray[i].finalFreq);
00210                         while(mTrajectoryArray[i].continuedAtId!=-1)
00211                         {
00212                                 contAt=mTrajectoryArray[i].continuedAtId;
00213                                 InterpolatePeaks(mTrajectoryArray[i], peakArrayArray);
00214                         }
00215                 }
00216         }
00217 
00218 
00219         void CleanTracks::Clean(Array<SpectralPeakArray*>& peakArrayArray)
00220         {
00221                 for(int i=0;i<peakArrayArray.Size();i++)
00222                 {
00223                         int nDeleted=0;
00224                         for(int z=0;z<peakArrayArray[i]->GetnIndexedPeaks();z++)
00225                         {
00226                                 const int id=peakArrayArray[i]->GetIndex(z-nDeleted);
00227                                 const int trajectoryPosition=FindTrajectoryPosition(id);
00228 
00229                                 if (trajectoryPosition==-1) continue;
00230                                 if (mTrajectoryArray[trajectoryPosition].length>=mMinLength) continue;
00231 
00232                                 //modified
00233                                 peakArrayArray[i]->DeleteSpectralPeak(z-nDeleted);
00234                                 peakArrayArray[i]->SetIsIndexUpToDate(true);
00235                                 peakArrayArray[i]->DeleteIndex(id);
00236                                 mTrajectoryArray[trajectoryPosition].length--;//update length
00237                                 if(mTrajectoryArray[trajectoryPosition].length==0)
00238                                         mTrajectoryArray.DeleteElem(trajectoryPosition);
00239                                 nDeleted++;
00240                         }
00241                 }
00242         }
00243 
00244 
00245         void CleanTracks::UpdateTrackIds(Array<SpectralPeakArray*>& peakArrayArray)
00246         {
00247                 for(int i=0;i<peakArrayArray.Size();i++)
00248                 {
00249                         for(int z=0;z<peakArrayArray[i]->GetnIndexedPeaks();z++)
00250                         {
00251                                 const int currentTrackid=peakArrayArray[i]->GetIndex(z);
00252                                 const int newTrackid=FindTrajectoryPosition(currentTrackid);
00253                                 if(newTrackid!=currentTrackid)
00254                                 {
00255                                         peakArrayArray[i]->SetIndex(z,newTrackid);
00256                                         peakArrayArray[i]->SetIsIndexUpToDate(true);//needed?
00257                                 }
00258                         }
00259                 }
00260         }
00261 
00262 
00263         void CleanTracks::AddTrajectory(TTrajectory& trajectory)
00264         {
00265                 // would be faster using searcharray.find?
00266                 const int pos = FindTrajectoryPosition(trajectory.id);
00267                 if(pos==-1)
00268                 {
00269                         // not found, new id, add it
00270                         mTrajectoryArray.AddElem(trajectory);
00271                 }
00272                 else
00273                 {
00274                         // if found, length and last data are updated
00275                         mTrajectoryArray[pos].length++;
00276                         mTrajectoryArray[pos].finalFreq=trajectory.finalFreq;
00277                         mTrajectoryArray[pos].finalMag=trajectory.finalMag;
00278                 }
00279         }
00280 
00281         void CleanTracks::InterpolatePeaks(TTrajectory& fromTrajectory, Array<SpectralPeakArray*>& peakArrayArray)
00282         {
00283                 const int newTrajPos=FindTrajectoryPosition(fromTrajectory.continuedAtId);
00284                 CLAM_ASSERT(newTrajPos>-1,"CleanTracks::InterpolatePeaks:Negative Index for track");
00285                 const TTrajectory & toTrajectory = mTrajectoryArray[newTrajPos];
00286                 int gap=toTrajectory.beginPos-(fromTrajectory.beginPos+fromTrajectory.length);
00287                 TData freqSlope=(toTrajectory.initialFreq-fromTrajectory.finalFreq)/(gap+1);
00288                 TData magSlope=(toTrajectory.initialMag-fromTrajectory.finalMag)/(gap+1);
00289                 TData currentFreq=fromTrajectory.finalFreq;
00290                 TData currentMag=fromTrajectory.finalMag;
00291                 TData currentBinPos;
00292                 int currentBinWidth;
00293                 TData lastBinPos=0;
00294                 int z;
00295                 for(z=fromTrajectory.beginPos+fromTrajectory.length;z<toTrajectory.beginPos;z++)
00296                 {
00297                         currentFreq+=freqSlope;
00298                         currentMag+=magSlope;
00299                         currentBinPos=2*currentFreq*mSpecSize/mSamplingRate;
00300                         currentBinWidth=int(currentBinPos-lastBinPos);
00301                         lastBinPos=currentBinPos;
00302                         SpectralPeak tmpPeak;
00303                         tmpPeak.AddPhase();
00304                         tmpPeak.AddBinWidth();
00305                         tmpPeak.AddBinPos();
00306                         tmpPeak.UpdateData();
00307                         tmpPeak.SetFreq(currentFreq);
00308                         tmpPeak.SetMag(currentMag);
00309                         tmpPeak.SetScale(EScale(EScale::eLog));
00310                         tmpPeak.SetBinPos(currentBinPos);
00311                         tmpPeak.SetBinWidth(currentBinWidth);
00312                         peakArrayArray[z]->AddSpectralPeak(tmpPeak, true, fromTrajectory.id);
00313                         //Peaks should be sorted in the frames where added !!!!!
00314                 }
00315                 //Need to only update index in the next frames
00316                 for(z=toTrajectory.beginPos;z<toTrajectory.beginPos+toTrajectory.length;z++)
00317                 {
00318                         peakArrayArray[z]->SetIndex(peakArrayArray[z]->GetPositionFromIndex(toTrajectory.id),fromTrajectory.id);
00319                 }
00320                 fromTrajectory.length+=(gap+toTrajectory.length);
00321                 fromTrajectory.continuedAtId=mTrajectoryArray[newTrajPos].continuedAtId;
00322                 fromTrajectory.finalFreq=mTrajectoryArray[newTrajPos].finalFreq;
00323                 mTrajectoryArray.DeleteElem(newTrajPos);
00324 
00325         }
00326 
00327         TIndex CleanTracks::FindTrajectoryPosition(TIndex id)
00328         {
00329                 // For Empty arrays return not found
00330                 if (mTrajectoryArray.Size()==0)
00331                         return -1;
00332                 //we have to check whether it is first or last track
00333                 if (id == mTrajectoryArray[0].id)
00334                         return 0;
00335                 if (id == mTrajectoryArray[mTrajectoryArray.Size()-1].id)
00336                         return mTrajectoryArray.Size()-1;
00337 
00338                 TTrajectory tmpTrajectory;
00339                 tmpTrajectory.id=id;
00340                 TIndex trajectoryPosition = mSearchTrajectories.Find(tmpTrajectory);
00341 
00342                 //note that Find returns the closest index and that does not guarantee that is the exact one
00343                 if (trajectoryPosition!=-1)
00344                         if (mTrajectoryArray[trajectoryPosition].id!=id)
00345                                 return -1;
00346                 return trajectoryPosition;
00347         }
00348 
00349 };//namespace
00350 
Generated by  doxygen 1.6.3