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