CLAM-Development  1.4.0
SpectralPeakDescriptors.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 
22 
23 
24 
25 #include "ProcessingData.hxx"
27 #include "SpectralPeakArray.hxx"
28 #include "CLAM_Math.hxx"
29 
30 namespace CLAM{
31 
33  DataArray Multiply(TData &factor, DataArray &a);
34  DataArray Multiply(DataArray &a, DataArray &b); // scalar product
35 
37 {
38  CLAM_ASSERT(pSpectralPeakArray->GetScale()==EScale::eLinear,
39  "Spectral Peak Descriptors require a linear magnitude SpectralPeakArray");
40  MandatoryInit();
41  mpSpectralPeakArray=pSpectralPeakArray;
42 }
43 
45 {
46  MandatoryInit();
47  AddAll();
48  UpdateData();
49 
50  SetMagnitudeMean(initVal);
51  SetHarmonicCentroid(initVal);
52  SetFirstTristimulus(initVal);
53  SetSecondTristimulus(initVal);
54  SetThirdTristimulus(initVal);
55  SetHarmonicDeviation(initVal);
56  SetOddHarmonics(initVal);
57  SetEvenHarmonics(initVal);
58  SetOddToEvenRatio(initVal);
59 }
60 
61 void SpectralPeakDescriptors::DefaultInit() {
62  mpSpectralPeakArray=0;
63  mpStats=0;
64 }
65 
66 void SpectralPeakDescriptors::CopyInit(const SpectralPeakDescriptors & copied) {
67  mpSpectralPeakArray=copied.mpSpectralPeakArray;
68  mpStats=0;
69 }
70 
72  return mpSpectralPeakArray;
73 }
74 
76 {
77  CLAM_ASSERT(pSpectralPeakArray->GetScale()==EScale::eLinear,
78  "Spectral Peak Descriptors require a linear magnitude SpectralPeakArray");
79  mpSpectralPeakArray=pSpectralPeakArray;
80  //TODO: it may give problems because pointer passed
81  InitStats(&mpSpectralPeakArray->GetMagBuffer());
82  mCentroid.Reset();
83 }
84 
85 
87 {
88 
89  if (HasMagnitudeMean())
90  SetMagnitudeMean(mpStats->GetMean());
91  if (HasHarmonicCentroid())
92  SetHarmonicCentroid(ComputeCentroid());
93  if(HasFirstTristimulus())
94  SetFirstTristimulus(ComputeFirstTristimulus());
95  if(HasSecondTristimulus())
96  SetSecondTristimulus(ComputeSecondTristimulus());
97  if(HasThirdTristimulus())
98  SetThirdTristimulus(ComputeThirdTristimulus());
99  if(HasHarmonicDeviation())
100  SetHarmonicDeviation(ComputeHarmonicDeviation());
101  if(HasOddHarmonics())
102  SetOddHarmonics(ComputeOddHarmonics());
103  if(HasEvenHarmonics())
104  SetEvenHarmonics(ComputeEvenHarmonics());
105  if(HasOddToEvenRatio())
106  SetOddToEvenRatio(ComputeOddToEvenRatio());
107 }
108 
109 TData SpectralPeakDescriptors::ComputeCentroid()
110 {
111  unsigned size = mpSpectralPeakArray->GetnPeaks();
112  if (size<=0) return 0;
113  const Array<TData> & magnitudes = mpSpectralPeakArray->GetMagBuffer();
114  const Array<TData> & frequencies = mpSpectralPeakArray->GetFreqBuffer();
115  TData crossProduct=0.0;
116  for (unsigned i = 0; i < size; i++)
117  {
118  crossProduct += magnitudes[i]*frequencies[i];
119  }
120  return crossProduct/(mpStats->GetMean()*size);
121 }
122 
123 TData SpectralPeakDescriptors::ComputeFirstTristimulus()
124 {
125  if (mpSpectralPeakArray->GetnPeaks()<=0) return 0;
126  const TData firstHarmonicMag=mpSpectralPeakArray->GetMagBuffer()[0];
127  return firstHarmonicMag*firstHarmonicMag/mpStats->GetEnergy();
128 }
129 
130 TData SpectralPeakDescriptors::ComputeSecondTristimulus()
131 {
132  if (mpSpectralPeakArray->GetnPeaks()<=3) return 0;
133 
134  const TData secondHarmonicMag=mpSpectralPeakArray->GetMagBuffer()[1];
135  const TData thirdHarmonicMag=mpSpectralPeakArray->GetMagBuffer()[2];
136  const TData fourthHarmonicMag=mpSpectralPeakArray->GetMagBuffer()[3];
137 
138  return (secondHarmonicMag*secondHarmonicMag+thirdHarmonicMag*thirdHarmonicMag+
139  fourthHarmonicMag*fourthHarmonicMag)/mpStats->GetEnergy();
140 }
141 
142 TData SpectralPeakDescriptors::ComputeThirdTristimulus()
143 {
144  if (mpSpectralPeakArray->GetnPeaks()<=4) return 0;
145  const DataArray& a=mpSpectralPeakArray->GetMagBuffer();
146  return accumulate(a.GetPtr()+4,a.GetPtr()+a.Size(),0.,Power<2>())/mpStats->GetEnergy();
147 }
148 
149 TData SpectralPeakDescriptors::ComputeHarmonicDeviation()
150 {
151  const unsigned size=mpSpectralPeakArray->GetnPeaks();
152  if (size<4) return 0.0; //is it really necessary to have 4 or with 2 is enough
153  const DataArray & data=mpSpectralPeakArray->GetMagBuffer();
154 
155  TData denom = 0;
156  TData nom = 0;
157 
158  const TData tmp0 = log10((data[0]+data[1])/2);
159  const TData logdata0=log10(data[0]);
160  denom += logdata0;
161  nom += CLAM::Abs(logdata0 - tmp0);
162 
163  for (unsigned i=1;i<size-1;i++)
164  {
165  const TData tmpi = log10((data[i-1]+data[i]+data[i+1])/3);
166  const TData logdatai=log10(data[i]);
167  denom += logdatai;
168  nom += CLAM::Abs(logdatai - tmpi);
169  }
170 
171  const TData tmpN = log10((data[size-2]+data[size-1])/2);
172  const TData logdataN=log10(data[size-1]);
173  denom += logdataN;
174  nom += CLAM::Abs(logdataN - tmpN);
175 
176  return nom/denom;
177 }
178 
179 TData SpectralPeakDescriptors::ComputeOddHarmonics()
180 {
181  const unsigned size=mpSpectralPeakArray->GetnPeaks();
182  if (size<3) return 0;
183  const DataArray& data=mpSpectralPeakArray->GetMagBuffer();
184  TData oddEnergy = 0.0;
185  for (unsigned i=2;i<size;i+=2)
186  {
187  oddEnergy+=data[i]*data[i];
188  }
189  return oddEnergy/mpStats->GetEnergy();
190 }
191 
192 TData SpectralPeakDescriptors::ComputeEvenHarmonics()
193 {
194  const unsigned size=mpSpectralPeakArray->GetnPeaks();
195  if (size<2) return 0;
196  const DataArray& data=mpSpectralPeakArray->GetMagBuffer();
197  TData evenEnergy = 0.0;
198  for (unsigned i=1;i<size;i+=2)
199  {
200  evenEnergy+=data[i]*data[i];
201  }
202  return evenEnergy/mpStats->GetEnergy();
203 }
204 
205 TData SpectralPeakDescriptors::ComputeOddToEvenRatio()
206 {
207  if (mpSpectralPeakArray->GetnPeaks()<=1) return 0.5;
208  TData odd,even;
209  if (HasOddHarmonics()) odd=GetOddHarmonics();
210  else odd=ComputeOddHarmonics();
211  if (HasEvenHarmonics()) even=GetEvenHarmonics();
212  else even=ComputeEvenHarmonics();
213 
214  return odd/(even+odd);
215 }
216 
218 {
219  SpectralPeakDescriptors tmpD(a);
220 
221  if (a.HasMagnitudeMean())
222  {
223  tmpD.SetMagnitudeMean(a.GetMagnitudeMean()*mult);
224  }
225  if (a.HasHarmonicCentroid())
226  {
227  tmpD.SetHarmonicCentroid(a.GetHarmonicCentroid()*mult);
228  }
229  if (a.HasFirstTristimulus())
230  {
231  tmpD.SetFirstTristimulus(a.GetFirstTristimulus()*mult);
232  }
233  if (a.HasSecondTristimulus())
234  {
235  tmpD.SetSecondTristimulus(a.GetSecondTristimulus()*mult);
236  }
237  if (a.HasThirdTristimulus())
238  {
239  tmpD.SetThirdTristimulus(a.GetThirdTristimulus()*mult);
240  }
241  if (a.HasHarmonicDeviation())
242  {
243  tmpD.SetHarmonicDeviation(a.GetHarmonicDeviation()*mult);
244  }
245  if (a.HasOddHarmonics())
246  {
247  tmpD.SetOddHarmonics(a.GetOddHarmonics()*mult);
248  }
249  if (a.HasEvenHarmonics())
250  {
251  tmpD.SetEvenHarmonics(a.GetEvenHarmonics()*mult);
252  }
253  if (a.HasOddToEvenRatio())
254  {
255  tmpD.SetOddToEvenRatio(a.GetOddToEvenRatio()*mult);
256  }
257  if(a.HasHPCP())
258  tmpD.SetHPCP(Multiply(mult,a.GetHPCP()));
259 
260  return tmpD;
261 }
262 
264 {
266 
267  if (a.HasMagnitudeMean() && b.HasMagnitudeMean())
268  {
269  tmpD.AddMagnitudeMean();
270  tmpD.UpdateData();
271  tmpD.SetMagnitudeMean(a.GetMagnitudeMean()*b.GetMagnitudeMean());
272  }
273  if (a.HasHarmonicCentroid() && b.HasHarmonicCentroid())
274  {
275  tmpD.AddHarmonicCentroid();
276  tmpD.UpdateData();
277  tmpD.SetHarmonicCentroid(a.GetHarmonicCentroid()*b.GetHarmonicCentroid());
278  }
279  if (a.HasFirstTristimulus() && b.HasFirstTristimulus())
280  {
281  tmpD.AddFirstTristimulus();
282  tmpD.UpdateData();
283  tmpD.SetFirstTristimulus(a.GetFirstTristimulus()*b.GetFirstTristimulus());
284  }
285  if (a.HasSecondTristimulus() && b.HasSecondTristimulus())
286  {
287  tmpD.AddSecondTristimulus();
288  tmpD.UpdateData();
289  tmpD.SetSecondTristimulus(a.GetSecondTristimulus()*b.GetSecondTristimulus());
290  }
291  if (a.HasThirdTristimulus() && b.HasThirdTristimulus())
292  {
293  tmpD.AddThirdTristimulus();
294  tmpD.UpdateData();
295  tmpD.SetThirdTristimulus(a.GetThirdTristimulus()*b.GetThirdTristimulus());
296  }
297  if (a.HasHarmonicDeviation() && b.HasHarmonicDeviation())
298  {
299  tmpD.AddHarmonicDeviation();
300  tmpD.UpdateData();
301  tmpD.SetHarmonicDeviation(a.GetHarmonicDeviation()*b.GetHarmonicDeviation());
302  }
303  if (a.HasOddHarmonics() && b.HasOddHarmonics())
304  {
305  tmpD.AddOddHarmonics();
306  tmpD.UpdateData();
307  tmpD.SetOddHarmonics(a.GetOddHarmonics()*b.GetOddHarmonics());
308  }
309  if (a.HasEvenHarmonics() && b.HasEvenHarmonics())
310  {
311  tmpD.AddEvenHarmonics();
312  tmpD.UpdateData();
313  tmpD.SetEvenHarmonics(a.GetEvenHarmonics()*b.GetEvenHarmonics());
314  }
315  if (a.HasOddToEvenRatio() && b.HasOddToEvenRatio())
316  {
317  tmpD.AddOddToEvenRatio();
318  tmpD.UpdateData();
319  tmpD.SetOddToEvenRatio(a.GetOddToEvenRatio()*b.GetOddToEvenRatio());
320  }
321  if (a.HasHPCP() && b.HasHPCP())
322  {
323  tmpD.AddHPCP();
324  tmpD.UpdateData();
325  tmpD.SetHPCP(Multiply(a.GetHPCP(),b.GetHPCP()));
326  }
327 
328  return tmpD;
329 }
330 
332 {
334 
335  if (a.HasMagnitudeMean() && b.HasMagnitudeMean())
336  {
337  tmpD.AddMagnitudeMean();
338  tmpD.UpdateData();
339  tmpD.SetMagnitudeMean(a.GetMagnitudeMean()+b.GetMagnitudeMean());
340  }
341  if (a.HasHarmonicCentroid() && b.HasHarmonicCentroid())
342  {
343  tmpD.AddHarmonicCentroid();
344  tmpD.UpdateData();
345  tmpD.SetHarmonicCentroid(a.GetHarmonicCentroid()+b.GetHarmonicCentroid());
346  }
347  if (a.HasFirstTristimulus() && b.HasFirstTristimulus())
348  {
349  tmpD.AddFirstTristimulus();
350  tmpD.UpdateData();
351  tmpD.SetFirstTristimulus(a.GetFirstTristimulus()+b.GetFirstTristimulus());
352  }
353  if (a.HasSecondTristimulus() && b.HasSecondTristimulus())
354  {
355  tmpD.AddSecondTristimulus();
356  tmpD.UpdateData();
357  tmpD.SetSecondTristimulus(a.GetSecondTristimulus()+b.GetSecondTristimulus());
358  }
359  if (a.HasThirdTristimulus() && b.HasThirdTristimulus())
360  {
361  tmpD.AddThirdTristimulus();
362  tmpD.UpdateData();
363  tmpD.SetThirdTristimulus(a.GetThirdTristimulus()+b.GetThirdTristimulus());
364  }
365  if (a.HasHarmonicDeviation() && b.HasHarmonicDeviation())
366  {
367  tmpD.AddHarmonicDeviation();
368  tmpD.UpdateData();
369  tmpD.SetHarmonicDeviation(a.GetHarmonicDeviation()+b.GetHarmonicDeviation());
370  }
371  if (a.HasOddHarmonics() && b.HasOddHarmonics())
372  {
373  tmpD.AddOddHarmonics();
374  tmpD.UpdateData();
375  tmpD.SetOddHarmonics(a.GetOddHarmonics()+b.GetOddHarmonics());
376  }
377  if (a.HasEvenHarmonics() && b.HasEvenHarmonics())
378  {
379  tmpD.AddEvenHarmonics();
380  tmpD.UpdateData();
381  tmpD.SetEvenHarmonics(a.GetEvenHarmonics()+b.GetEvenHarmonics());
382  }
383  if (a.HasOddToEvenRatio() && b.HasOddToEvenRatio())
384  {
385  tmpD.AddOddToEvenRatio();
386  tmpD.UpdateData();
387  tmpD.SetOddToEvenRatio(a.GetOddToEvenRatio()+b.GetOddToEvenRatio());
388  }
389  if(a.HasHPCP() && b.HasHPCP() )
390  {
391  tmpD.AddHPCP();
392  tmpD.UpdateData();
393  tmpD.SetHPCP(Add(a.GetHPCP(),b.GetHPCP()));
394  }
395 
396 
397  return tmpD;
398 }
399 
401 {
402  return a*(1/div);
403 }
404 
406 {
407  return a*mult;
408 }
409 
410 }//CLAM
411