CLAM-Development  1.4.0
MelFilterBank.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 "MelFilterBank.hxx"
23 #include "ProcessingFactory.hxx"
24 
25 namespace CLAM
26 {
27 
28 namespace Hidden
29 {
30  static const char * metadata[] = {
31  "key", "MelFilterBank",
32  "category", "Analysis",
33  "description", "MelFilterBank",
34  0
35  };
36  static FactoryRegistrator<ProcessingFactory, MelFilterBank> reg = metadata;
37 }
38 
40  {
41  AddAll();
42  UpdateData();
43  SetUsePower(false);
44  SetSpectrumSize(513);
45  SetNumBands(20);
46  SetSpectralRange(22050);
47  SetLowCutoff(0);
48  SetHighCutoff(11025);
49  }
50 
52  : mIn("Spectrum", this)
53  , mOut("Mel Spectrum", this)
54  {
56  }
57 
59  : mIn("Spectrum", this)
60  , mOut("Mel Spectrum", this)
61  {
62  Configure( cfg );
63  }
64 
66  {
67  }
68 
70  {
71  const Spectrum & spectrum = mIn.GetData();
72  MelSpectrum & melSpectrum = mOut.GetData();
73  bool ok = Do(spectrum,melSpectrum);
74  mIn.Consume();
75  mOut.Produce();
76  return ok;
77  }
78 
79  bool MelFilterBank::Do( const Spectrum& spec, MelSpectrum& melSpec )
80  {
81  if ( !AbleToExecute() ) return false; // Object is disabled
82 
83  const DataArray& specMag = spec.GetMagBuffer();
84 
85  CLAM_ASSERT( specMag.Size() == mConfig.GetSpectrumSize(),
86  "Spectrum doesn't have the expected size!" );
87  CLAM_ASSERT( spec.GetSpectralRange() == mConfig.GetSpectralRange(),
88  "Spectrum doesn't have the expected frequency range!" );
89  CLAM_ASSERT( spec.GetScale() == EScale::eLinear,
90  "Spectrum is not in linear scale!" );
91 
92  const TSize numBands = mConfig.GetNumBands();
93 
94  melSpec.SetNumBands(numBands);
95  melSpec.SetLowCutoff(mConfig.GetLowCutoff());
96  melSpec.SetHighCutoff(mConfig.GetHighCutoff());
97  melSpec.SetSpectralRange(spec.GetSpectralRange());
98 
99  DataArray& melCoeffs = melSpec.GetCoefficients();
100 
101  if ( melCoeffs.Size() != numBands ) {
102  melCoeffs.Resize( numBands );
103  melCoeffs.SetSize( numBands );
104  }
105  for( int i = 0; i < numBands; i++)
106  melCoeffs[i] = 0;
107 
108  const bool usePower = mConfig.GetUsePower();
109 
110  for (TIndex i=mLowIdx; i<=mHighIdx; i++) {
111 
112  // NOTE: What is the significance of using square?
113  TData mag = specMag[i];
114  if (usePower) mag *=mag;
115 
116  // Get the Mel band number.
117  TIndex bandIdx = mMelBand[i];
118 
119  // Weight spectrum sample with triangular window.
120  TData weightedMag = mFilterWeights[i] * mag;
121 
122  // Add spectrum sample contribution to apropriate bands.
123  if (bandIdx >= 0) {
124  melCoeffs[bandIdx] += weightedMag;
125  }
126 
127  if ((bandIdx+1) < numBands) {
128  melCoeffs[bandIdx+1] += mag - weightedMag;
129  }
130  }
131  return true;
132  }
133 
135  {
136  CopyAsConcreteConfig( mConfig, cfg );
138  return true;
139  }
140 
142  {
143  /* When using log instead of log10, the scaling factor is 1127
144  instead of 2595. */
145 
146  /* NOTE: The discrepancy between HTK and CLAM originates here, or
147  more specificaly from multiplying the argument passed to this
148  method with deltaFreq. (Ref. fb.fres in HTK source code.) */
149 
150  return 1127.0*log(1.0 + linFreq/700.0);
151  }
152 
154  {
155 
156  /* Filterbank cutoff frequencies in Hz. */
157  const TData lowCutoff = mConfig.GetLowCutoff();
158  const TData highCutoff = mConfig.GetHighCutoff();
159 
160  /* Filterbank cutoff frequencies in Mel scale. */
161  const TData melLowCutoff = Mel(lowCutoff);
162  const TData melHighCutoff = Mel(highCutoff);
163  const TData melFreqRange = melHighCutoff - melLowCutoff;
164 
165  /* Index frequency resolution. */
166  const TSize specSize = mConfig.GetSpectrumSize();
167  const TData specRange = mConfig.GetSpectralRange();
168 
169  const TData deltaFreq = specRange/specSize;
170 
171 
172  /* Spectrum index of lowest filterbank frequency (must be 1 or
173  more). */
174  mLowIdx = (TIndex)(lowCutoff/deltaFreq + 1.5);
175 
176 
177  if (mLowIdx < 1) mLowIdx = 1;
178 
179  /* Spectrum index of highest filterbank frequency (must not exceed
180  spectrum size). */
181  mHighIdx = (TIndex)(highCutoff/deltaFreq - 0.5);
182 
183  if (mHighIdx >= specSize) mHighIdx = specSize-1;
184 
185 
186  /* Table of filterbank centre frequencies. */
187  const TSize maxBands = mConfig.GetNumBands() + 1;
188 
189  TData* centreFreq = new TData[maxBands];
190 
191  for (TIndex i=0; i<maxBands; i++) {
192  centreFreq[i] = ((i+1)/(TData)maxBands)*melFreqRange + melLowCutoff;
193  }
194 
195 
196  /* Table for converting linear indexes to Mel band numbers. */
197  mMelBand.Resize( specSize );
198  mMelBand.SetSize( specSize );
199 
200  TData melFreq = 0;
201  TIndex bandIdx = 0;
202  for (TIndex i=0; i<specSize; i++) {
203 
204  if (i<mLowIdx || i>mHighIdx) {
205 
206  // Index is outside the desired range.
207  mMelBand[i] = -1;
208  } else {
209 
210  melFreq = Mel((TData)i*deltaFreq);
211 
212  // Select the band of the closest centre frequency beneath.
213 
214  // NOTE: The condition bandIdx<maxBands may cause an index out
215  // of range error in Do(...)!!!
216 
217  while (centreFreq[bandIdx]<melFreq && bandIdx<maxBands) bandIdx++;
218  mMelBand[i] = bandIdx-1;
219  }
220 
221  }
222 
223 
224  /* Table of triangular filterbank window weights. */
225  mFilterWeights.Resize( specSize );
226  mFilterWeights.SetSize( specSize );
227 
228  for (TIndex i=0; i<specSize; i++) {
229  bandIdx = mMelBand[i];
230 
231  if (i<mLowIdx || i>mHighIdx) {
232  mFilterWeights[i] = 0.0;
233  } else {
234 
235  if (bandIdx >= 0) {
236  mFilterWeights[i] = (centreFreq[bandIdx+1] - Mel((TData)i*deltaFreq))
237  / (centreFreq[bandIdx+1] - centreFreq[bandIdx]);
238 
239  } else {
240  mFilterWeights[i] = (centreFreq[0] - Mel((TData)i*deltaFreq))
241  / (centreFreq[0] - melLowCutoff);
242 
243  }
244  }
245 
246  } // End for
247 
248  delete [] centreFreq;
249  }
250 
251 }
252