00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "ProcessingData.hxx"
00023 #include "DataTypes.hxx"
00024 #include "Spectrum.hxx"
00025 #include "Audio.hxx"
00026 #include "WindowGenerator.hxx"
00027 #include "ProcessingFactory.hxx"
00028
00029 namespace CLAM
00030 {
00031
00032 namespace Hidden
00033 {
00034 static const char * metadata[] = {
00035 "key", "WindowGenerator",
00036 "category", "Generators",
00037 "description", "WindowGenerator",
00038 0
00039 };
00040 static FactoryRegistrator<ProcessingFactory, WindowGenerator> reg = metadata;
00041 }
00042
00043
00044
00045 WindowGenerator::WindowGenerator(const WindowGeneratorConfig &c)
00046 : mOutput( "Generated window function samples", this )
00047 , mSize("Size",this)
00048 {
00049 Configure(c);
00050 }
00051
00052 WindowGenerator::~WindowGenerator()
00053 {}
00054
00055
00056
00057
00058 bool WindowGenerator::ConcreteConfigure(const ProcessingConfig& c)
00059 {
00060 CopyAsConcreteConfig(mConfig, c);
00061 mSize.DoControl(TControlData(mConfig.GetSize()));
00062
00063 if (!mConfig.HasUseTable()) return true;
00064 if (!mConfig.GetUseTable()) return true;
00065
00066
00067
00068
00069 mTable.Resize(mConfig.GetSize());
00070 mTable.SetSize(mConfig.GetSize());
00071 mSize.DoControl(TControlData(mConfig.GetSize()));
00072
00073 EWindowType type = mConfig.HasType()?
00074 mConfig.GetType() :
00075 EWindowType::eHamming;
00076
00077 CreateTable(mTable,type,mConfig.GetSize());
00078
00079 return true;
00080
00081 }
00082
00083
00084
00085 bool WindowGenerator::Do()
00086 {
00087 CLAM_ASSERT( AbleToExecute(), "This processing is not ready to do anything" );
00088
00089 bool result = Do( mOutput.GetAudio() );
00090 mOutput.Produce();
00091 return result;
00092 }
00093
00094
00095
00096 bool WindowGenerator::Do(DataArray& out)
00097 {
00098 const int winsize = (int) mSize.GetLastValue();
00099 const int audiosize = out.Size();
00100
00101 bool useTable = mConfig.HasUseTable() && mConfig.GetUseTable();
00102
00103 if (useTable)
00104 CreateWindowFromTable(out);
00105 else {
00106 EWindowType type = mConfig.HasType()?
00107 mConfig.GetType() :
00108 EWindowType::eHamming;
00109 CreateTable(out,type,winsize);
00110 }
00111
00112
00113 if (winsize < audiosize) {
00114 TData* audio = out.GetPtr();
00115 memset(audio+winsize,0,(audiosize-winsize)*sizeof(TData));
00116 }
00117
00118 NormalizeWindow(out);
00119 if (mConfig.GetInvert())
00120 InvertWindow(out);
00121
00122 return true;
00123 }
00124
00125 bool WindowGenerator::Do(Audio& out)
00126 {
00127 Do(out.GetBuffer());
00128
00129 return true;
00130 }
00131
00132
00133 bool WindowGenerator::Do(Spectrum& out)
00134 {
00135
00136 CLAM_ASSERT(out.HasMagBuffer(),
00137 "WindowGenerator::Do(): Spectral Window exists only for type MagPhase");
00138
00139 Do(out.GetMagBuffer());
00140 return true;
00141 }
00142
00143
00144
00145
00146 void WindowGenerator::CreateTable(DataArray& table,EWindowType windowType,
00147 long windowsize) const
00148 {
00149 switch(windowType)
00150 {
00151 case EWindowType::eKaiserBessel17:
00152 {
00153 KaiserBessel(windowsize,table,1.7);
00154 break;
00155 }
00156 case EWindowType::eKaiserBessel18:
00157 {
00158 KaiserBessel(windowsize,table,1.8);
00159 break;
00160 }
00161 case EWindowType::eKaiserBessel19:
00162 {
00163 KaiserBessel(windowsize,table,1.9);
00164 break;
00165 }
00166 case EWindowType::eKaiserBessel20:
00167 {
00168 KaiserBessel(windowsize,table,2.0);
00169 break;
00170 }
00171 case EWindowType::eKaiserBessel25:
00172 {
00173 KaiserBessel(windowsize,table,2.5);
00174 break;
00175 }
00176 case EWindowType::eKaiserBessel30:
00177 {
00178 KaiserBessel(windowsize,table,3.0);
00179 break;
00180 }
00181 case EWindowType::eKaiserBessel35:
00182 {
00183 KaiserBessel(windowsize,table,3.5);
00184 break;
00185 }
00186 case EWindowType::eBlackmanHarris62:
00187 {
00188 BlackmanHarris62(windowsize,table);
00189 break;
00190 }
00191 case EWindowType::eBlackmanHarris70:
00192 {
00193 BlackmanHarris70(windowsize,table);
00194 break;
00195 }
00196 case EWindowType::eBlackmanHarris74:
00197 {
00198 BlackmanHarris74(windowsize,table);
00199 break;
00200 }
00201 case EWindowType::eBlackmanHarris92:
00202 {
00203 BlackmanHarris92(windowsize,table);
00204 break;
00205 }
00206 case EWindowType::eHamming:
00207 {
00208 Hamming(windowsize,table);
00209 break;
00210 }
00211 case EWindowType::eTriangular:
00212 {
00213 Triangular(windowsize,table);
00214 break;
00215 }
00216 case EWindowType::eBlackmanHarris92TransMainLobe:
00217 {
00218 BlackmanHarris92TransMainLobe(windowsize,table);
00219 break;
00220 }
00221 case EWindowType::eGaussian:
00222 {
00223 Gaussian(windowsize,table);
00224 break;
00225 }
00226 case EWindowType::eBlackmanHarrisLike:
00227 {
00228 BlackmanHarrisLike(windowsize,table);
00229 break;
00230 }
00231 case EWindowType::eSine:
00232 {
00233 Sine(windowsize, table);
00234 break;
00235 }
00236 case EWindowType::eSquare:
00237 case EWindowType::eNone:
00238 {
00239 Square(windowsize, table);
00240 break;
00241 }
00242 }
00243 }
00244
00245
00246 void WindowGenerator::CreateWindowFromTable(DataArray &array) const
00247 {
00248 unsigned int index = 0x00000000;
00249 unsigned int increment = (unsigned int)((double) (0x00010000) * mConfig.GetSize()/
00250 (mSize.GetLastValue()));
00251
00252
00253
00254 int size = int(mSize.GetLastValue());
00255 CLAM_ASSERT(size<=array.Size(),"WindowGenerator::CreateWindowFromTable:output array does not have a valid size");
00256 for (int i=0;i<size;i++)
00257 {
00258 const TData & val = mTable[index>>16];
00259 array[i] = val;
00260 index += increment;
00261 }
00262 }
00263
00264
00265
00266
00267
00268 double WindowGenerator::BesselFunction(double x) const
00269 {
00270 double Sum = 0;
00271 double Factorial = 1.0;
00272 double HalfX = x/2.0;
00273 Sum += 1.0;
00274 Sum += HalfX * HalfX;
00275 for(int i=2; i<50; i++)
00276 {
00277 Factorial *= i;
00278 Sum += CLAM_pow( CLAM_pow(HalfX, (double)i) / Factorial, 2.0);
00279 }
00280 return Sum;
00281 }
00282
00283
00284
00285 void WindowGenerator::KaiserBessel(long size,DataArray& window,
00286 double alpha) const
00287 {
00288 TData PiAlpha = TData(PI) * TData(alpha);
00289 long windowsize = size;
00290
00291 TData dHalfsize = windowsize/2.0f;
00292 int iHalfsize = (int)windowsize/2;
00293
00294
00295 if (windowsize % 2 != 0)
00296 window[iHalfsize]= TData(BesselFunction(PiAlpha) / BesselFunction(PiAlpha));
00297 for(int i=0; i<iHalfsize; i++)
00298 {
00299 window[i] = window[windowsize-i-1] =TData(
00300 BesselFunction(PiAlpha * CLAM_sqrt(1.0 - CLAM_pow((double)(i-iHalfsize) /
00301 dHalfsize, 2.0))) / BesselFunction(PiAlpha) );
00302 }
00303
00304 }
00305
00306
00307 void WindowGenerator::BlackmanHarrisX(long size,DataArray& window,
00308 double a0,double a1,double a2,double a3) const
00309 {
00310 double fConst = TWO_PI / (size-1);
00311
00312
00313 if(size%2 !=0)
00314 {
00315 window[(int)(size/2)] = a0 - a1 * CLAM_cos(fConst * ((int)(size/2))) + a2 *
00316 CLAM_cos(fConst * 2 * ((int)(size/2))) - a3 * CLAM_cos(fConst * 3 * ((int)(size/2)));
00317 }
00318 for(int i = 0; i < (int)(size/2); i++)
00319 {
00320 window[i] = window[size-i-1] = a0 - a1 * CLAM_cos(fConst * i) +
00321 a2 * CLAM_cos(fConst * 2 * i) - a3 * CLAM_cos(fConst * 3 * i);
00322 }
00323
00324
00325
00326 }
00327
00328
00329
00330 void WindowGenerator::BlackmanHarris62(long size,DataArray& window) const
00331 {
00332
00333 double a0 = .44959, a1 = .49364, a2 = .05677;
00334 BlackmanHarrisX(size,window,a0,a1,a2);
00335 }
00336
00337
00338
00339
00340 void WindowGenerator::BlackmanHarris70(long size,DataArray& window) const
00341 {
00342
00343 double a0 = .42323, a1 = .49755, a2 = .07922;
00344 BlackmanHarrisX(size,window,a0,a1,a2);
00345 }
00346
00347
00348 void WindowGenerator::BlackmanHarris74(long size,DataArray& window) const
00349 {
00350
00351
00352 double a0 = .40217, a1 = .49703, a2 = .09892, a3 = .00188;
00353
00354 BlackmanHarrisX(size,window,a0,a1,a2,a3);
00355 }
00356
00357
00358 void WindowGenerator::BlackmanHarris92(long size,DataArray& window) const
00359 {
00360
00361
00362 double a0 = .35875, a1 = .48829, a2 = .14128, a3 = .01168;
00363
00364 BlackmanHarrisX(size,window,a0,a1,a2,a3);
00365 }
00366
00367 void WindowGenerator::BlackmanHarrisLike(long size, DataArray& window) const
00368 {
00369 TData fSum=0;
00370
00371 for(int i=0; i<size; i++)
00372 fSum += window[i] =
00373 + 0.47
00374 - 0.45 * CLAM_cos(TData(TWO_PI/(size-1.0)*i))
00375 - 0.01 * CLAM_cos(TData(TWO_PI/(size-1.0)*i*2.0))
00376 - 0.01 * CLAM_cos(TData(TWO_PI/(size-1.0)*i*3.0));
00377 fSum = fSum/2;
00378 for (int i = 0; i < size; i++)
00379 window[i] = window[i] / fSum;
00380 return;
00381 }
00382
00383
00384
00385 void WindowGenerator::Hamming(long size,DataArray& window) const
00386 {
00387 if(size%2 !=0)
00388 window[(int)(size/2)]=
00389 + TData(0.54)
00390 - TData(0.46)*CLAM_cos(TData(2.0)*TData(PI)*((int)(size/2))/(size-1));
00391 for(int i = 0; i < (int)(size/2); i++)
00392 window[i] = window[size-i-1] =
00393 + TData(0.54)
00394 - TData(0.46) * CLAM_cos(TData(2.0)*TData(PI)*i/(size-1));
00395 }
00396
00397
00398 void WindowGenerator::Triangular(long size,DataArray& window) const
00399 {
00400 if(size%2 !=0)
00401 window[(int)(size/2)] = (TData)2*((int)(size/2))/(size-1);
00402 for(int i = 0; i < (int)(size/2); i++)
00403 {
00404 window[i] = window[size-i-1]= (TData)2*i/(size-1);
00405 }
00406 }
00407
00408
00409 void WindowGenerator::BlackmanHarris92TransMainLobe(long size,DataArray& window) const
00410 {
00411 const short N = 512;
00412 TData fA[4] = {TData(.35875), TData(.48829), TData(.14128), TData(.01168)},
00413 fMax = 0;
00414 TData fTheta = -TData(4.0) * TData(TWO_PI) / N,
00415 fThetaIncr = (TData(8.0) * TData(TWO_PI) / N) / (size);
00416
00417
00418 for(int i = 0; i < size; i++)
00419 {
00420 window[i] = 0;
00421 for (int m = 0; m < 4; m++)
00422 window[i] += -1 * (fA[m]/2) *
00423 (Sinc (fTheta - m * TData(TWO_PI)/N, N) +
00424 Sinc (fTheta + m * TData(TWO_PI)/N, N));
00425 fTheta += fThetaIncr;
00426 }
00427
00428
00429 fMax = window[(int) size / 2];
00430 for (int i = 0; i < size; i++)
00431 window[i] = window[i] / fMax;
00432
00433 }
00434
00435 void WindowGenerator::Gaussian(long size,DataArray& window) const
00436 {
00437 double s = 0.15;
00438 double scale = 1.0 / ( 2.0 * M_PI * 0.15 * 0.15 );
00439
00440 if(size%2 !=0)
00441 window[size/2] = scale;
00442 for(int i = 0; i < size/2; i++)
00443 {
00444 TData x = (TData)(i-(TData)size/2.)/(TData)(size-1);
00445 window[i] = window[size-i-1]= scale * exp(-(x*x)/(2*s*s));
00446 }
00447 }
00448
00449
00450 void WindowGenerator::Sine(long size,DataArray& window) const
00451 {
00452 double tmp1 = PI/(2.0*float(size));
00453 double tmp2 = 0.5*(2.0*float(size));
00454
00455 for (int i=0;i<size;i++)
00456 window[i] = (float)(1+tmp2*CLAM_sin(tmp1*(i+1)));
00457 }
00458 void WindowGenerator::Square(long size,DataArray& window) const
00459 {
00460 for (int i=0;i<size;i++)
00461 window[i] = 1;
00462 }
00463
00464
00465 void WindowGenerator::InvertWindow(const DataArray& originalWindow,
00466 DataArray& invertedWindow) const
00467 {
00468 if(invertedWindow.AllocatedSize()!=originalWindow.AllocatedSize())
00469 invertedWindow.Resize(originalWindow.AllocatedSize());
00470 if(invertedWindow.Size()!=originalWindow.Size())
00471 invertedWindow.SetSize(originalWindow.Size());
00472
00473 if (originalWindow.Size()%2!=0)
00474 if(originalWindow[(int)(originalWindow.Size()/2)]!=0)
00475 invertedWindow[(int)(originalWindow.Size()/2)]=
00476 1/originalWindow[(int)(originalWindow.Size()/2)];
00477 for(int i=0;i<(int)(originalWindow.Size()/2);i++)
00478 {
00479 if(originalWindow[i]!=0)
00480 invertedWindow[i]=invertedWindow[originalWindow.Size()-1-i]=1.0/originalWindow[i];
00481 }
00482 invertedWindow[originalWindow.Size()-1]=0;
00483 }
00484
00485 void WindowGenerator::InvertWindow(DataArray& window) const
00486 {
00487 InvertWindow(window,window);
00488 }
00489
00490 void WindowGenerator::NormalizeWindow(DataArray& window) const
00491 {
00492 if (mConfig.GetNormalize() == EWindowNormalize::eNone) return;
00493 double normalizationFactor=1.0;
00494
00495 const int size = window.Size();
00496
00497 switch (mConfig.GetNormalize()) {
00498 case EWindowNormalize::eAnalysis:
00499 {
00500 double sum=0.0;
00501 for(int i=0;i<size;i++) sum+=window[i];
00502 normalizationFactor=1/(sum/2);
00503 break;
00504 }
00505 case EWindowNormalize::eEnergy:
00506 {
00507 double sum=0.0;
00508 for(int i=0;i<size;i++) sum+=window[i];
00509 normalizationFactor=size/(sum/2);
00510 break;
00511 }
00512 case EWindowNormalize::eMax:
00513 {
00514 double max=0.0;
00515 for(int i=0;i<size;i++)
00516 if (max<window[i]) max=window[i];
00517 normalizationFactor = 1.0/max;
00518 break;
00519 }
00520 default:
00521 CLAM_ASSERT(false, "Unexpected normalization type");
00522 }
00523
00524 for(int i=0;i<size;i++)
00525 {
00526 window[i]*=normalizationFactor;
00527 }
00528 }
00529
00530
00531 double WindowGenerator::Sinc(double x, short N) const
00532 {
00533 return (sin ((N/2) * x) / sin (x/2));
00534 }
00535
00536 }
00537