Marsyas
0.6.0-alpha
|
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 }