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