Marsyas  0.5.0-beta1
/Users/jleben/code/marsyas/src/marsyas/marsystems/Windowing.cpp
Go to the documentation of this file.
00001 /*
00002 ** Copyright (C) 1998-2006 George Tzanetakis <gtzan@cs.uvic.ca>
00003 **
00004 ** This program is free software; you can redistribute it and/or modify
00005 ** it under the terms of the GNU General Public License as published by
00006 ** the Free Software Foundation; either version 2 of the License, or
00007 ** (at your option) any later version.
00008 **
00009 ** This program is distributed in the hope that it will be useful,
00010 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 ** GNU General Public License for more details.
00013 **
00014 ** You should have received a copy of the GNU General Public License
00015 ** along with this program; if not, write to the Free Software
00016 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017 */
00018 
00019 #include "Windowing.h"
00020 #include <stdexcept>
00021 
00022 using namespace std;
00023 using namespace Marsyas;
00024 
00025 Windowing::Windowing(mrs_string name):MarSystem("Windowing",name)
00026 {
00027   zeroPadding_ = 0;
00028   size_ = 0;
00029   addcontrols();
00030 }
00031 
00032 Windowing::Windowing(const Windowing& a):MarSystem(a)
00033 {
00034   ctrl_type_ = getctrl("mrs_string/type");
00035   ctrl_zeroPhasing_ = getctrl("mrs_bool/zeroPhasing");
00036   ctrl_zeroPadding_ = getctrl("mrs_natural/zeroPadding");
00037   ctrl_size_ = getctrl("mrs_natural/size");
00038   ctrl_variance_ = getctrl("mrs_real/variance");
00039   ctrl_normalize_ = getctrl("mrs_bool/normalize");
00040   zeroPadding_ = 0;
00041   size_ = 0;
00042 }
00043 
00044 Windowing::~Windowing()
00045 {
00046 }
00047 
00048 MarSystem*
00049 Windowing::clone() const
00050 {
00051   return new Windowing(*this);
00052 }
00053 
00054 void
00055 Windowing::addcontrols()
00056 {
00057   addctrl("mrs_string/type", "Hamming", ctrl_type_);
00058   addctrl("mrs_bool/zeroPhasing", false, ctrl_zeroPhasing_);
00059   addctrl("mrs_natural/zeroPadding", 0, ctrl_zeroPadding_);
00060   addctrl("mrs_natural/size", 0, ctrl_size_);
00061   addctrl("mrs_real/variance", 0.4, ctrl_variance_);// used for the gaussian window
00062   addctrl("mrs_bool/normalize", false, ctrl_normalize_);
00063 
00064   setctrlState("mrs_string/type", true);
00065   setctrlState("mrs_bool/zeroPhasing", true);
00066   setctrlState("mrs_natural/zeroPadding", true);
00067   setctrlState("mrs_natural/size", true);
00068   setctrlState("mrs_real/variance", true);
00069   setctrlState("mrs_bool/normalize", true);
00070 }
00071 
00072 
00073 
00074 void
00075 Windowing::myUpdate(MarControlPtr sender)
00076 {
00077   mrs_natural t;
00078   (void) sender;  //suppress warning of unused parameter(s)
00079   mrs_string type = ctrl_type_->to<mrs_string>();
00080 
00081   ctrl_onObservations_->setValue(ctrl_inObservations_, NOUPDATE);
00082   ctrl_osrate_->setValue(ctrl_israte_, NOUPDATE);
00083 
00084   // Add prefix to the observation names.
00085   mrs_string inObsNames = ctrl_inObsNames_->to<mrs_string>();
00086   mrs_string prefix = mrs_string("Win") + type + mrs_string("_");
00087   ctrl_onObsNames_->setValue(obsNamesAddPrefix(inObsNames, prefix), NOUPDATE);
00088 
00089   //if zeroPadding control changed...
00090   if (ctrl_zeroPadding_->to<mrs_natural>() != onSamples_- inSamples_)
00091   {
00092     //zero padding should always be a positive or zero value
00093     if (ctrl_zeroPadding_->to<mrs_natural>() < 0)
00094     {
00095       ctrl_zeroPadding_->setValue(0, NOUPDATE);
00096     }
00097     ctrl_size_->setValue(ctrl_inSamples_->to<mrs_natural>() +
00098                          ctrl_zeroPadding_->to<mrs_natural>(), NOUPDATE);
00099     onSamples_ = ctrl_size_->to<mrs_natural>();
00100   }
00101   //if size control changed...
00102   if (ctrl_size_->to<mrs_natural>() != onSamples_)
00103   {
00104     //size should never be smaller than inSamples
00105     if (ctrl_size_->to<mrs_natural>() < inSamples_)
00106     {
00107       ctrl_size_->setValue(inSamples_, NOUPDATE);
00108     }
00109     ctrl_zeroPadding_->setValue(ctrl_size_->to<mrs_natural>() -
00110                                 ctrl_inSamples_->to<mrs_natural>(), NOUPDATE);
00111   }
00112 
00113   ctrl_onSamples_->setValue(ctrl_size_, NOUPDATE);
00114 
00115   //check if zero phasing should be performed
00116   if (ctrl_zeroPhasing_->isTrue())
00117   {
00118     delta_ = inSamples_/2+1;
00119   }
00120   else
00121   {
00122     delta_=0;
00123   }
00124 
00125 
00126   tmp_.create(inSamples_);
00127 
00128   // Precalculate the envelope.
00129   // \todo only do this when the type or size is changed.
00130   envelope_.create(inSamples_);
00131 
00132   if (type == "Hamming")
00133   {
00134     windowingFillHamming(envelope_);
00135   }
00136   else if (type == "Hanning" || type == "Hann")
00137   {
00138     windowingFillHanning(envelope_);
00139   }
00140   else if (type == "Triangle")
00141   {
00142     windowingFillTriangle(envelope_);
00143   }
00144   else if (type == "Bartlett")
00145   {
00146     windowingFillBartlett(envelope_);
00147   }
00148   else if (type == "Gaussian")
00149   {
00150     windowingFillGaussian(envelope_, ctrl_variance_->to<mrs_real>());
00151   }
00152   else if (type == "Blackman")
00153   {
00154     windowingFillBlackman(envelope_, 0.16);
00155   }
00156   else if (type == "Blackman-Harris")
00157   {
00158     windowingFillBlackmanHarris(envelope_);
00159   }
00160   else if (type == "Cosine" || type == "Sine")
00161   {
00162     windowingFillCosine(envelope_);
00163   }
00164   else
00165   {
00166     ostringstream oss;
00167     oss << "Invalid windowing type \"" << type << "\"";
00168     throw invalid_argument(oss.str());
00169   }
00170 
00171 
00172 
00173   if (ctrl_normalize_->to<mrs_bool>() == true)
00174   {
00175     mrs_real sum = 0.0;
00176 
00177     for (t =0; t < inSamples_; t++)
00178     {
00179       sum += envelope_(t);
00180     }
00181     mrs_real afac = (mrs_real)(2.0 /sum); // \todo: why is there a factor 2 here?
00182     envelope_ *= afac;
00183     ctrl_normalize_->setValue(false, NOUPDATE);
00184   }
00185 
00186 
00187 }
00188 
00189 void
00190 Windowing::myProcess(realvec& in, realvec& out)
00191 {
00192   out.setval(0.0);
00193   mrs_natural o,t;
00194 
00195   for (o=0; o < inObservations_; o++)
00196   {
00197     //shift windowed data in case zeroPhasing is selected
00198     if (ctrl_zeroPhasing_->isTrue())
00199     {
00200       //apply the window to the input data
00201       for (t = 0; t < inSamples_; t++)
00202       {
00203         tmp_(t) =  in(o,t)*envelope_(t); // /(norm_);
00204       }
00205       for (t = 0; t < inSamples_/2; t++)
00206       {
00207         out(o,t)=tmp_((t+delta_)%inSamples_);
00208       }
00209       for (t = inSamples_/2; t < inSamples_; t++)
00210       {
00211         out(o,t+(onSamples_-inSamples_))=tmp_((t+delta_)%inSamples_);
00212       }
00213     }
00214     else
00215     {
00216       for (t=0; t< inSamples_; ++t)
00217       {
00218         out(o,t) = in(o,t) * envelope_(t);
00219       }
00220     }
00221   }
00222 }
00223 
00224 
00225 
00242 void
00243 Marsyas::windowingFillRaisedCosine(realvec& envelope, mrs_real alpha, mrs_real beta)
00244 {
00245   mrs_natural N = envelope.getSize();
00246   for (mrs_natural t = 0; t < N; t++)
00247   {
00248     envelope(t) = alpha - beta * cos(2.0 * PI * t / (N - 1.0));
00249   }
00250 }
00251 
00252 
00253 
00254 
00255 
00263 void
00264 Marsyas::windowingFillTriangle(realvec& envelope)
00265 {
00266   mrs_natural N = envelope.getSize();
00267   for (mrs_natural t = 0; t < N; t++)
00268   {
00269     envelope(t) = 2.0/N * (N/2.0 - abs(t - (N - 1.0)/2.0));
00270   }
00271 }
00272 
00280 void
00281 Marsyas::windowingFillBartlett(realvec& envelope)
00282 {
00283   mrs_natural N = envelope.getSize();
00284   for (mrs_natural t = 0; t < N; t++)
00285   {
00286     envelope(t) = 2.0/(N-1.0) * ((N-1.0)/2.0 - abs(t - (N - 1.0)/2.0));
00287   }
00288 }
00289 
00297 void Marsyas::windowingFillGaussian(realvec& envelope, mrs_real sigma)
00298 {
00299   mrs_natural N = envelope.getSize();
00300   mrs_real tmp;
00301   for (mrs_natural t = 0; t < N; t++)
00302   {
00303     tmp = (t - (N - 1.0) / 2.0) / (sigma * (N - 1.0) / 2.0);
00304     envelope(t) = exp(-0.5*tmp*tmp);
00305   }
00306 }
00307 
00315 void Marsyas::windowingFillBlackman(realvec& envelope, mrs_real alpha)
00316 {
00317   mrs_natural N = envelope.getSize();
00318   mrs_real a0 = (1.0 - alpha) / 2.0;
00319   mrs_real a2 = alpha / 2.0;
00320   for (mrs_natural t = 0; t < N; t++)
00321   {
00322     envelope(t) = a0  - 0.5 * cos(2.0 * PI * t / (N - 1.0))
00323                   + a2 * cos(4.0 * PI * t / (N - 1.0));
00324   }
00325 }
00326 
00335 void Marsyas::windowingFillBlackmanHarris(realvec& envelope)
00336 {
00337   mrs_natural N = envelope.getSize();
00338   mrs_real a0 = 0.35875, a1 = 0.48829, a2 = 0.14128, a3 = 0.01168;
00339   for (mrs_natural t = 0; t < N; t++)
00340   {
00341     envelope(t) = a0  - a1 * cos(2.0 * PI * t / (N - 1.0))
00342                   + a2 * cos(4.0 * PI * t / (N - 1.0))
00343                   - a3 * cos(6.0 * PI * t / (N - 1.0));
00344   }
00345 }
00346 
00354 void Marsyas::windowingFillCosine(realvec& envelope)
00355 {
00356   mrs_natural N = envelope.getSize();
00357   for (mrs_natural t = 0; t < N; t++)
00358   {
00359     envelope(t) = sin(PI * t / (N - 1.0));
00360   }
00361 }