CLAM-Development  1.4.0
SinTracking.cxx
Go to the documentation of this file.
1 /*
2  * Copyright (c) 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 
22 #include "SinTracking.hxx"
23 #include "SearchArray.hxx"
24 
25 
26 namespace CLAM
27 {
28 
29 
31  : mInput("Input", this ),
32  mOutput("Output", this ),
33  mFundFreqValue("Fund Freq Value", this )
34 {
36 }
37 
39  : mInput("Input", this ),
40  mOutput("Output", this ),
41  mFundFreqValue("Fund Freq Value", this )
42 
43 {
44  Configure(c);
45 }
46 
48 {}
49 
50 
51 
52 
53 /* Configure the Processing Object according to the Config object */
54 
55 bool SinTracking::ConcreteConfigure(const ProcessingConfig& c)
56 {
57 
58  CopyAsConcreteConfig(mConfig, c);
59 
60  mnMaxSines = mConfig.GetnMaxSines();
61 
62  mThreshold= mConfig.GetThreshold();
63 
64  mHarmonic= mConfig.GetIsHarmonic();
65 
66  mnActiveGuides=0;
67 
68  mNextTrackId=0;
69 
70  mInitialized=false;
71  mLastHarmonic=false;
72 
73  int i;
74  //initializes guide array
75  mGuideArray.Resize(mnMaxSines);
76 
77  mGuideArray.SetSize(mnMaxSines);
78  for(i=0;i<mnMaxSines;i++)
79  {
80  mGuideArray[i].isDead=true;
81  }
82 
83  return true;
84 }
85 
86 
87 
88 
89 //Process
90 
91 
92 //Supervised mode
93 bool SinTracking::Do(void)
94 {
95  bool result = Do( mInput.GetData(), mOutput.GetData() );
96  mInput.Consume();
97  mOutput.Produce();
98  return result;
99 }
100 
101 bool SinTracking::Do(const SpectralPeakArray& iPeakArray,SpectralPeakArray& oPeakArray)
102 {
103  //oPeakArray initialization
104  oPeakArray.AddIndexArray();
105  oPeakArray.AddPhaseBuffer();
106  oPeakArray.AddBinWidthBuffer();
107  oPeakArray.AddBinPosBuffer();
108  oPeakArray.UpdateData();
109 
110  TData fn = mFundFreqValue.GetLastValue();
111  if(mHarmonic && fn>0)
112  {
113  mLastHarmonic=true;
114  return DoHarmonic(iPeakArray,oPeakArray,fn);
115  }
116  else
117  {
118  if(mLastHarmonic) KillAll();
119  mLastHarmonic=false;
120  return DoInharmonic(iPeakArray,oPeakArray);
121  }
122 }
123 
124 
125 void SinTracking::AddNewTrack(int peakPosition, const SpectralPeak& currentPeak,SpectralPeakArray& oPeakArray) const
126 {
127  for(int i=0;i<mnMaxSines;i++)
128  {
129  if(mGuideArray[i].isDead==true)
130  {
131  mGuideArray[i].isDead=false;
132  mGuideArray[i].trackId=mNextTrackId;
133  mGuideArray[i].freq=currentPeak.GetFreq();
134  mGuideArray[i].mag=currentPeak.GetMag();
135  oPeakArray.SetSpectralPeak(peakPosition,currentPeak, mNextTrackId);
136  mNextTrackId++;
137  mnActiveGuides++;
138  break;
139  }
140  }
141 
142 }
143 
144 
145 
146 void SinTracking::Tracking(const SpectralPeakArray& iPeakArray,SpectralPeakArray& oPeakArray,TIndex processedPeakPos) const
147 {
148  const DataArray & previousFreqBuffer = mPreviousPeakArray.GetFreqBuffer();
149  const IndexArray & previousIndexBuffer = mPreviousPeakArray.GetIndexArray();
150  TData currentPeakFreq = previousFreqBuffer[processedPeakPos];
151 
152  const DataArray& iFreqBuffer=iPeakArray.GetFreqBuffer();
153 
154  if(!ThereIsCandidate(currentPeakFreq,iPeakArray,oPeakArray))
155  {
156  KillTrack(previousIndexBuffer[processedPeakPos]);
157  return;
158  }
159 
160  TData distance;
161  int candidatePos=GetCandidate(currentPeakFreq,iPeakArray,distance);
162  if(candidatePos==-1) return;
163  TData candidatePeakFreq = iFreqBuffer[candidatePos];
164 
165  if( candidatePos>=oPeakArray.GetnPeaks()
166  || (!IsBestCandidate(candidatePeakFreq,currentPeakFreq))
167  || (oPeakArray.GetIndex(candidatePos)!=-1) )
168  {
169  KillTrack(previousIndexBuffer[processedPeakPos]);
170  return;
171  }
172 
173  // TODO: Optimize this by accessing directly to the buffers
174  // instead of calling Set/GetSpectralPeak
175  const SpectralPeak candidatePeak = iPeakArray.GetSpectralPeak(candidatePos);
176  TIndex trackId = previousIndexBuffer[processedPeakPos];
177  oPeakArray.SetSpectralPeak(candidatePos,candidatePeak,trackId);
178 }
179 
180 
181 
182 //true as soon as the distance between currentPeak and a Peak in iPeakArray is <mThreshold
183 bool SinTracking::ThereIsCandidate(TData currentPeakFreq,
184  const SpectralPeakArray& iPeakArray,
185  SpectralPeakArray& oPeakArray) const
186 {
187  TSize nInputPeaks=iPeakArray.GetnPeaks();
188  if(nInputPeaks>mnMaxSines) nInputPeaks=mnMaxSines;
189  DataArray& peakFreqBuffer=iPeakArray.GetFreqBuffer();
190  TData factor=100/currentPeakFreq;
191  IndexArray& outputIndexArray=oPeakArray.GetIndexArray();
192  for (int i=0;i<nInputPeaks;i++)
193  {
194  int dist=int(Abs(peakFreqBuffer[i]-currentPeakFreq)*factor);
195  if((dist< mThreshold)&&(outputIndexArray[i]==-1)) return true;
196  }
197  return false;
198 }
199 
200 
201 //Sets mGuideArray.isDead to true and mnActiveGuides--
202 void SinTracking::KillTrack(int trackId) const
203 {
204  for(int i=0;i<mnMaxSines;i++)
205  {
206  if(mGuideArray[i].trackId!=trackId) continue;
207  mGuideArray[i].isDead=true;
208  mnActiveGuides--;
209  return;
210  }
211 }
212 
213 //Return the position of the peak in iPeakArray which is the closest to currentPeak
214 TIndex SinTracking::GetCandidate(TData currentPeakFreq,
215  const SpectralPeakArray& iPeakArray,
216  TData& distance) const
217 {
218  //Can be optimized! XA
219  distance=-1;
220  int nPeaks=iPeakArray.GetnPeaks();
221  DataArray& peakFreqBuffer=iPeakArray.GetFreqBuffer();
222  TData factor=100./currentPeakFreq;
223 
224  //xamat: test!
225  SearchArray<TData> mySearch(peakFreqBuffer);
226  TIndex found=mySearch.Find(currentPeakFreq);
227  if (found==-1) found = 0; //Pau: to avoid assert. Is this the correct behaviour?
228  TIndex originalFound = found;
229  distance = Abs(peakFreqBuffer[found]-currentPeakFreq);
230  //make sure that the two surrounding peaks are not in fact closer
231  TIndex newFound;
232  TData nextDistance;
233  if(originalFound<nPeaks-1)
234  {
235  for(newFound=found+1; newFound<nPeaks; newFound++)
236  {
237  nextDistance = Abs(peakFreqBuffer[newFound]-currentPeakFreq);
238  if(nextDistance>distance) break;
239  distance = nextDistance;
240  }
241  found = newFound-1;
242  }
243  if(originalFound>0)
244  {
245  for(newFound=found-1; newFound>-1; newFound--)
246  {
247  nextDistance = Abs(peakFreqBuffer[newFound]-currentPeakFreq);
248  if(nextDistance>distance) break;
249  distance = nextDistance;
250  }
251  found = newFound + 1;
252  }
253  distance *= factor;
254  return found;
255 }
256 
257 
258 
259 //true if there is no peak in previousPeakArray closer to candidate
260 
261 bool SinTracking::IsBestCandidate(TData candidateFreq, TData currentFreq) const
262 {
263  double nextDistance=Abs(currentFreq-candidateFreq);
264 
265  int nPeaks=mPreviousPeakArray.GetnPeaks();
266  DataArray& peakFreqBuffer=mPreviousPeakArray.GetFreqBuffer();
267  for(int i=0;i<nPeaks;i++)
268  {
269  if(Abs(peakFreqBuffer[i]-candidateFreq)<nextDistance) return false;
270  }
271  return true;
272 
273 }
274 
275 
276 
277 //Set the best candidate in oPeakArray at the same position as in iPeakArray
278 //with the same index as the peak it continues
279 void SinTracking::Match(TIndex trackId, TIndex peakIndex,
280  const SpectralPeak& currentPeak,
281  SpectralPeakArray& oPeakArray) const
282 {
283  CLAM_ASSERT(peakIndex<oPeakArray.GetnPeaks(),"SinTracking::Match: Not a valid peak Index");
284  oPeakArray.SetSpectralPeak(peakIndex,currentPeak,trackId);
285 
286 }
287 
288 
289 
290 /*Function to check peaks in next frame that have not been matched to peaks in current
291 frame. These are then assigned to newborn tracks.*/
292 void SinTracking::CheckForNewBornTracks(const SpectralPeakArray& iPeakArray,SpectralPeakArray& oPeakArray) const
293 {
294  TIndex nonAssignedPeakIndex=0;
295  bool notFinished=true;
296  nonAssignedPeakIndex=GetFirstNonAssignedPeakPos(oPeakArray,nonAssignedPeakIndex);
297  while(notFinished)
298  {
299  if(nonAssignedPeakIndex == -1)
300  {
301  notFinished=false;
302  break;
303  }
304  else
305  {
306  /*Note that when a new track is born the Id assigned is next index. This gives
307  us and idea of the number of total tracks that have been born and died up to
308  now, unique ID*/
309  AddNewTrack(nonAssignedPeakIndex,iPeakArray.GetSpectralPeak(nonAssignedPeakIndex),oPeakArray);
310  nonAssignedPeakIndex++;
311  nonAssignedPeakIndex=GetFirstNonAssignedPeakPos(oPeakArray,nonAssignedPeakIndex);
312  }
313  }
314 
315 }
316 
317 
318 /*Returns index of first peak that has not been assigned to a track (-1 if all have
319 already been assigned)*/
320 //beginAt=0? why not starting from the previous new track index?
321 TIndex SinTracking::GetFirstNonAssignedPeakPos(const SpectralPeakArray& oPeakArray, TIndex beginAt=0) const
322 {
323  const TIndex nPeaks = oPeakArray.GetnPeaks();
324  if (beginAt>=nPeaks) return -1;
325  if (beginAt<0) return -1;
326 
327  int i=oPeakArray.GetFirstNonValidIndexPosition(beginAt);
328 
329  if(i==nPeaks) return -1;//All peaks have been matched
330 
331  return i;
332 }
333 
334 
335 //Initialization of the first output peak array: all peaks must be assigned a track
336 void SinTracking::Initialization(const SpectralPeakArray& iPeakArray, SpectralPeakArray& oPeakArray)
337 {
338  TSize nPeaks=oPeakArray.GetnPeaks();
339  for(int i=0; i<nPeaks; i++)
340  {
341  AddNewTrack(i, iPeakArray.GetSpectralPeak(i), oPeakArray);
342  }
343  mPreviousPeakArray=oPeakArray;
344 }
345 
346 void SinTracking::KillAll()
347 {
348  for (int i=0;i<mnMaxSines;i++)
349  {
350  mGuideArray[i].isDead=true;
351  }
352  mnActiveGuides=0;
353 }
354 
355 bool SinTracking::DoInharmonic(const SpectralPeakArray& iPeakArray,SpectralPeakArray& oPeakArray)
356 {
357  if(iPeakArray.GetnPeaks()<mnMaxSines)
358  oPeakArray.SetnPeaks(iPeakArray.GetnPeaks());
359  else
360  oPeakArray.SetnPeaks(mnMaxSines);
361 
362  oPeakArray.ResetIndices();
363  oPeakArray.InitIndices();
364  oPeakArray.SetScale(EScale(EScale::eLog));
365 
366  if(!mInitialized)
367  {
368  Initialization(iPeakArray, oPeakArray);
369  mInitialized=true;
370  return true;
371  }
372 
373  oPeakArray.SetIsIndexUpToDate(true);
374  for(int i=0;i<mPreviousPeakArray.GetnPeaks();i++)
375  {
376  Tracking(iPeakArray,oPeakArray,i);
377  }
378  CheckForNewBornTracks(iPeakArray,oPeakArray);
379  mPreviousPeakArray=oPeakArray;
380 
381  //xamat: testing not to keep inharmonic peaks
382  //oPeakArray.SetnPeaks(0);
383  //mPreviousPeakArray=oPeakArray;
384  return true;
385 }
386 
387 
388 /* Harmonic Peak Continuation */
389 bool SinTracking::DoHarmonic(const SpectralPeakArray& in, SpectralPeakArray& out,TData funFreq)
390 {
391  out.SetnPeaks(mnMaxSines);
392 
393  out.ResetIndices();
394  out.SetScale(EScale(EScale::eLog));
395 
396  InitHarmonicTracks(out,funFreq);
397  out.SetIsIndexUpToDate(true);
398  HarmonicTracking(in, out, funFreq);
399  mPreviousPeakArray=out;
400  return true;
401 
402 }
403 
404 void SinTracking::HarmonicTracking(const SpectralPeakArray& in,SpectralPeakArray& out,TData funFreq)
405 {
406  TData d;
407  TIndex pos;
408 
409  out.SetnPeaks(mnMaxSines);
410 
411  //DataArray& iFreqBuffer=in.GetFreqBuffer();
412  DataArray& oFreqBuffer=out.GetFreqBuffer();
413  DataArray& iMagBuffer=in.GetMagBuffer();
414  DataArray& oMagBuffer=out.GetMagBuffer();
415  DataArray& iPhaseBuffer=in.GetPhaseBuffer();
416  DataArray& oPhaseBuffer=out.GetPhaseBuffer();
417 
418 
419  int i;
420 
421  TSize nPeaks=mnMaxSines;
422  i=0;
423  int n;
424  for(n=0; n<mnMaxSines;n++)
425  {
426  pos=GetCandidate(oFreqBuffer[i],in,d);
427  if(d<funFreq/2 && pos>-1)
428  {
429  if(i==0 || iMagBuffer[pos]!=oMagBuffer[i-1])
430  {
431  oMagBuffer[i]=iMagBuffer[pos];
432  oFreqBuffer[i]=oFreqBuffer[n];
433  oPhaseBuffer[i]=iPhaseBuffer[pos];
434  i++;
435  }
436  }
437  }
438  out.SetnPeaks(i);
439 }
440 
441 void SinTracking::InitHarmonicTracks(SpectralPeakArray& peaks, TData funFreq)
442 {
443  DataArray& freqBuffer=peaks.GetFreqBuffer();
444  DataArray& magBuffer=peaks.GetMagBuffer();
445 
446  int i;
447 
448  TData currentFreq=funFreq;
449 
450  for(i=0;i<mnMaxSines;i++)
451  {
452  freqBuffer[i]=currentFreq;
453  magBuffer[i]=-99;
454  currentFreq+=funFreq;
455  }
456 }
457 
458 } // namespace CLAM
459