CLAM-Development
1.1
|
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