CLAM-Development  1.4.0
CleanTracks.cxx
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2001-2004 MUSIC TECHNOLOGY GROUP (MTG)
3  * UNIVERSITAT POMPEU FABRA
4  *
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  *
20  */
21 #include "CleanTracks.hxx"
22 #include <iostream>
23 
24 
25 namespace CLAM {
26 
27 
29  {
30 
31  AddAll();
32  UpdateData();
33 
34  //Default values
35  SetMaxDropOut(3);
36  SetMinLength(3);
37  SetFreqDev(20);
38  SetSamplingRate(44100);
39  SetSpecSize(22050);
40  }
41 
42  CleanTracks::CleanTracks():mTrajectoryArray(100,100),mSearchTrajectories(mTrajectoryArray)
43  {
45  }
46 
47  CleanTracks::CleanTracks(const CleanTracksConfig &c ):mTrajectoryArray(100,100),mSearchTrajectories(mTrajectoryArray)
48  {
49  Configure(c);
50  }
51 
53  {}
54 
55 
56 
57 
58 /* Configure the Processing Object according to the Config object */
59 
60  bool CleanTracks::ConcreteConfigure(const ProcessingConfig& c)
61  {
62 
63  CopyAsConcreteConfig(mConfig, c);
64 
65  mMaxDropOut = mConfig.GetMaxDropOut();
66  mMinLength= mConfig.GetMinLength();
67  mFreqDev= 1.0/mConfig.GetFreqDev();
68  mSamplingRate= mConfig.GetSamplingRate();
69  mSpecSize= mConfig.GetSpecSize();
70  return true;
71  }
72 
73 
74 
75 
76 //Process
77 
78 
79  //Supervised mode
80  bool CleanTracks::Do(void)
81  {
82  CLAM_ASSERT(false,"CleanTracks::Do(): Supervised mode not implemented");
83  return false;
84  }
85 
87  {
88 
89  LoadTracks(peakArrayArray);
90  FindContinuations();
91  JoinContinuations(peakArrayArray);
92  Clean(peakArrayArray);
93  UpdateTrackIds(peakArrayArray);
94  return true;
95  }
96 
97  bool CleanTracks::Do(Segment& segment)
98  {
99  const int nFrames=segment.GetnFrames();
100  Array<SpectralPeakArray*> spectralPeakArrayArray;
101  spectralPeakArrayArray.Resize(nFrames);
102  for(int i=0;i<nFrames;i++)
103  {
104  spectralPeakArrayArray.AddElem(&segment.GetFrame(i).GetSpectralPeakArray());
105  }
106  return Do(spectralPeakArrayArray);
107 
108  }
109 
110  void CleanTracks::LoadTracks(Array<SpectralPeakArray*>& peakArrayArray)
111  {
112  for(int i=0;i<peakArrayArray.Size();i++)
113  {
114  for(int z=0;z<peakArrayArray[i]->GetnIndexedPeaks();z++)
115  {
116  TTrajectory tmpTrajectory;
117  tmpTrajectory.id=peakArrayArray[i]->GetIndex(z);
118  tmpTrajectory.beginPos=i;
119  tmpTrajectory.initialFreq=tmpTrajectory.finalFreq=peakArrayArray[i]->GetFreq(z);//At the beginning, initial=final
120  tmpTrajectory.initialMag=tmpTrajectory.finalMag=peakArrayArray[i]->GetMag(z);
121  tmpTrajectory.length=1;
122  tmpTrajectory.continuedAtId=-1;
123  AddTrajectory(tmpTrajectory);
124  }
125  }
126  }
127 
128  void CleanTracks::FindContinuations()
129  {
130  int firstCandidatable = 0;
131 
132  for(int i=0; i<mTrajectoryArray.Size(); i++)
133  {
134  const TTrajectory & toBeAppended = mTrajectoryArray[i];
135 /*
136  // Non-candidatables now won't be candidatables never
137  while (firstCandidatable<i && toBeAppended.beginPos <
138  mTrajectoryArray[firstCandidatable].beginPos+
139  mTrajectoryArray[firstCandidatable].length+mMaxDropOut)
140  firstCandidatable++;
141 */
142  bool thereIsCandidate=false;
143  // MRJ: Transition of Frequency deviation from absolute hertz to
144  // a %. We multiply this factor by the currently considered trajectory
145  // final frequency
146  TData bestFreqDif=mFreqDev * mTrajectoryArray[i].finalFreq ;
147  int bestCandidate=0;
148 
149  // Get the best 'candidate' to be followed by the track 'toBeAppended'
150  for(int k=firstCandidatable; k<i; k++)
151  {
152  const TTrajectory & candidate = mTrajectoryArray[k];
153 
154  // Suposing that they are ordered by start frame,
155  // there is a point from which all the candidates are invalid
156  if (candidate.beginPos>=toBeAppended.beginPos) break;
157 
158  const TSize dropOut=
159  toBeAppended.beginPos-
160  (candidate.beginPos+candidate.length);
161 
162  // 'candidate' should end before 'toBeAppended' starts
163  if (dropOut<=0) continue;
164  // ...but not too much
165  if (dropOut>mMaxDropOut) continue;
166 
167  // ...and the frequency distance should be the better one
168  const TData frequencyDistance =
169  Abs(toBeAppended.initialFreq-candidate.finalFreq);
170  if (frequencyDistance >= bestFreqDif) continue;
171 
172  bestFreqDif=frequencyDistance;
173  bestCandidate=k;
174  thereIsCandidate=true;
175  }
176 
177  // If there is no candidate, toBeAppended is not appended, next...
178  if (!thereIsCandidate) continue;
179 
180  TTrajectory & candidateTrajectory = mTrajectoryArray[bestCandidate];
181 
182  // Check that the best candidate for 'toBeAppended'
183  // is not the best one to another
184 
185  // Unused variable: const TSize candidateEnd = candidateTrajectory.beginPos+candidateTrajectory.length;
186 
187  TSize previousFollowerPosition = candidateTrajectory.continuedAtId;
188  // Candidate has already has been attached?
189  if (previousFollowerPosition != -1)
190  {
191  TTrajectory & previousFollower = mTrajectoryArray[previousFollowerPosition];
192  const TData frequencyDistance =
193  Abs(previousFollower.initialFreq-candidateTrajectory.finalFreq);
194  if (frequencyDistance <= bestFreqDif) continue;
195  }
196 
197  candidateTrajectory.continuedAtId=toBeAppended.id;
198 
199  }
200  }
201 
202  void CleanTracks::JoinContinuations(Array<SpectralPeakArray*>& peakArrayArray)
203  {
204  for(int i=0;i<mTrajectoryArray.Size();i++)
205  {
206  // Unused variable: const int id = mTrajectoryArray[i].id;
207  int contAt = mTrajectoryArray[i].continuedAtId;
208  // Unused variable: const int begPos = mTrajectoryArray[i].beginPos;
209  // Unused variable: const int lastfreq=int(mTrajectoryArray[i].finalFreq);
210  while(mTrajectoryArray[i].continuedAtId!=-1)
211  {
212  contAt=mTrajectoryArray[i].continuedAtId;
213  InterpolatePeaks(mTrajectoryArray[i], peakArrayArray);
214  }
215  }
216  }
217 
218 
219  void CleanTracks::Clean(Array<SpectralPeakArray*>& peakArrayArray)
220  {
221  for(int i=0;i<peakArrayArray.Size();i++)
222  {
223  int nDeleted=0;
224  for(int z=0;z<peakArrayArray[i]->GetnIndexedPeaks();z++)
225  {
226  const int id=peakArrayArray[i]->GetIndex(z-nDeleted);
227  const int trajectoryPosition=FindTrajectoryPosition(id);
228 
229  if (trajectoryPosition==-1) continue;
230  if (mTrajectoryArray[trajectoryPosition].length>=mMinLength) continue;
231 
232  //modified
233  peakArrayArray[i]->DeleteSpectralPeak(z-nDeleted);
234  peakArrayArray[i]->SetIsIndexUpToDate(true);
235  peakArrayArray[i]->DeleteIndex(id);
236  mTrajectoryArray[trajectoryPosition].length--;//update length
237  if(mTrajectoryArray[trajectoryPosition].length==0)
238  mTrajectoryArray.DeleteElem(trajectoryPosition);
239  nDeleted++;
240  }
241  }
242  }
243 
244 
245  void CleanTracks::UpdateTrackIds(Array<SpectralPeakArray*>& peakArrayArray)
246  {
247  for(int i=0;i<peakArrayArray.Size();i++)
248  {
249  for(int z=0;z<peakArrayArray[i]->GetnIndexedPeaks();z++)
250  {
251  const int currentTrackid=peakArrayArray[i]->GetIndex(z);
252  const int newTrackid=FindTrajectoryPosition(currentTrackid);
253  if(newTrackid!=currentTrackid)
254  {
255  peakArrayArray[i]->SetIndex(z,newTrackid);
256  peakArrayArray[i]->SetIsIndexUpToDate(true);//needed?
257  }
258  }
259  }
260  }
261 
262 
263  void CleanTracks::AddTrajectory(TTrajectory& trajectory)
264  {
265  // would be faster using searcharray.find?
266  const int pos = FindTrajectoryPosition(trajectory.id);
267  if(pos==-1)
268  {
269  // not found, new id, add it
270  mTrajectoryArray.AddElem(trajectory);
271  }
272  else
273  {
274  // if found, length and last data are updated
275  mTrajectoryArray[pos].length++;
276  mTrajectoryArray[pos].finalFreq=trajectory.finalFreq;
277  mTrajectoryArray[pos].finalMag=trajectory.finalMag;
278  }
279  }
280 
281  void CleanTracks::InterpolatePeaks(TTrajectory& fromTrajectory, Array<SpectralPeakArray*>& peakArrayArray)
282  {
283  const int newTrajPos=FindTrajectoryPosition(fromTrajectory.continuedAtId);
284  CLAM_ASSERT(newTrajPos>-1,"CleanTracks::InterpolatePeaks:Negative Index for track");
285  const TTrajectory & toTrajectory = mTrajectoryArray[newTrajPos];
286  int gap=toTrajectory.beginPos-(fromTrajectory.beginPos+fromTrajectory.length);
287  TData freqSlope=(toTrajectory.initialFreq-fromTrajectory.finalFreq)/(gap+1);
288  TData magSlope=(toTrajectory.initialMag-fromTrajectory.finalMag)/(gap+1);
289  TData currentFreq=fromTrajectory.finalFreq;
290  TData currentMag=fromTrajectory.finalMag;
291  TData currentBinPos;
292  int currentBinWidth;
293  TData lastBinPos=0;
294  int z;
295  for(z=fromTrajectory.beginPos+fromTrajectory.length;z<toTrajectory.beginPos;z++)
296  {
297  currentFreq+=freqSlope;
298  currentMag+=magSlope;
299  currentBinPos=2*currentFreq*mSpecSize/mSamplingRate;
300  currentBinWidth=int(currentBinPos-lastBinPos);
301  lastBinPos=currentBinPos;
302  SpectralPeak tmpPeak;
303  tmpPeak.AddPhase();
304  tmpPeak.AddBinWidth();
305  tmpPeak.AddBinPos();
306  tmpPeak.UpdateData();
307  tmpPeak.SetFreq(currentFreq);
308  tmpPeak.SetMag(currentMag);
309  tmpPeak.SetScale(EScale(EScale::eLog));
310  tmpPeak.SetBinPos(currentBinPos);
311  tmpPeak.SetBinWidth(currentBinWidth);
312  peakArrayArray[z]->AddSpectralPeak(tmpPeak, true, fromTrajectory.id);
313  //Peaks should be sorted in the frames where added !!!!!
314  }
315  //Need to only update index in the next frames
316  for(z=toTrajectory.beginPos;z<toTrajectory.beginPos+toTrajectory.length;z++)
317  {
318  peakArrayArray[z]->SetIndex(peakArrayArray[z]->GetPositionFromIndex(toTrajectory.id),fromTrajectory.id);
319  }
320  fromTrajectory.length+=(gap+toTrajectory.length);
321  fromTrajectory.continuedAtId=mTrajectoryArray[newTrajPos].continuedAtId;
322  fromTrajectory.finalFreq=mTrajectoryArray[newTrajPos].finalFreq;
323  mTrajectoryArray.DeleteElem(newTrajPos);
324 
325  }
326 
327  TIndex CleanTracks::FindTrajectoryPosition(TIndex id)
328  {
329  // For Empty arrays return not found
330  if (mTrajectoryArray.Size()==0)
331  return -1;
332  //we have to check whether it is first or last track
333  if (id == mTrajectoryArray[0].id)
334  return 0;
335  if (id == mTrajectoryArray[mTrajectoryArray.Size()-1].id)
336  return mTrajectoryArray.Size()-1;
337 
338  TTrajectory tmpTrajectory;
339  tmpTrajectory.id=id;
340  TIndex trajectoryPosition = mSearchTrajectories.Find(tmpTrajectory);
341 
342  //note that Find returns the closest index and that does not guarantee that is the exact one
343  if (trajectoryPosition!=-1)
344  if (mTrajectoryArray[trajectoryPosition].id!=id)
345  return -1;
346  return trajectoryPosition;
347  }
348 
349 };//namespace
350