Marsyas
0.6.0-alpha
|
00001 /* 00002 ** Copyright (C) 1998-2010 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 00020 #include "Spectrum.h" 00021 #include <cmath> 00022 00023 using namespace std; 00024 using namespace Marsyas; 00025 00026 template<typename NUM> 00027 static bool is_power_of_two(NUM n) 00028 { 00029 double real_power_of_two = std::log( (double) n ) / std::log(2.0); 00030 int int_power_of_two = (int) real_power_of_two; 00031 return real_power_of_two == int_power_of_two; 00032 } 00033 00034 Spectrum::Spectrum(mrs_string name): 00035 MarSystem("Spectrum",name), 00036 cutoff_(1.0), 00037 lowcutoff_(0.0), 00038 re_(0.0), 00039 im_ (0.0), 00040 ponObservations_(0), 00041 correct_input_format_(false) 00042 { 00043 addControls(); 00044 checkInputFormat(); 00045 } 00046 00047 Spectrum::~Spectrum() 00048 { 00049 } 00050 00051 Spectrum::Spectrum(const Spectrum& a): 00052 MarSystem(a), 00053 cutoff_(1.0), 00054 lowcutoff_(0.0), 00055 re_(0.0), 00056 im_ (0.0), 00057 ponObservations_(0), 00058 correct_input_format_(false) 00059 { 00060 ctrl_cutoff_ = getctrl("mrs_real/cutoff"); 00061 ctrl_lowcutoff_ = getctrl("mrs_real/lowcutoff"); 00062 checkInputFormat(); 00063 } 00064 00065 void 00066 Spectrum::addControls() 00067 { 00068 addctrl("mrs_real/cutoff", 1.0, ctrl_cutoff_); 00069 setctrlState("mrs_real/cutoff", true); 00070 addctrl("mrs_real/lowcutoff", 0.0, ctrl_lowcutoff_); 00071 setctrlState("mrs_real/lowcutoff", true); 00072 } 00073 00074 MarSystem* 00075 Spectrum::clone() const 00076 { 00077 return new Spectrum(*this); 00078 } 00079 00080 void Spectrum::checkInputFormat() 00081 { 00082 if (inSamples_ == 0) 00083 return; 00084 00085 correct_input_format_ = is_power_of_two(inSamples_); 00086 if (!correct_input_format_) 00087 { 00088 MRSERR("Spectrum: input amount of samples not power of two: " << inSamples_); 00089 } 00090 } 00091 00092 void 00093 Spectrum::myUpdate(MarControlPtr sender) 00094 { 00095 (void) sender; //suppress warning of unused parameter(s) 00096 ctrl_onSamples_->setValue((mrs_natural)1, NOUPDATE); 00097 ctrl_onObservations_->setValue(ctrl_inSamples_, NOUPDATE); 00098 ctrl_osrate_->setValue(ctrl_israte_->to<mrs_real>() / ctrl_inSamples_->to<mrs_natural>()); 00099 00100 cutoff_ = ctrl_cutoff_->to<mrs_real>(); 00101 lowcutoff_ = ctrl_lowcutoff_->to<mrs_real>(); 00102 00103 onObservations_ = ctrl_onObservations_->to<mrs_natural>(); 00104 00105 if (ponObservations_ != onObservations_) 00106 { 00107 checkInputFormat(); 00108 00109 /* ostringstream oss; 00110 oss << "rbin_0" << ","; //DC bin (only has real part) 00111 oss << "rbin_" << onObservations_/2 << ","; //Nyquist bin (only has real part) 00112 for (mrs_natural n=2; n < onObservations_/2; n++) 00113 { 00114 oss << "rbin_" << n-1 << ","; 00115 oss << "ibin_" << n-1 << ","; 00116 } 00117 ctrl_onObsNames_->setValue(oss.str(), NOUPDATE); 00118 */ 00119 } 00120 00121 00122 // gtzan: output gets to cluttered if we annotate every bin of the 00123 // spectrum - commented out detailed output 00124 00125 // Set the observation names by prefixing it with FFTxxx, 00126 // based on the first item of inObsNames_, because we ignore the 00127 // other observation channels. 00128 // mrs_string inObsName = stringSplit(ctrl_inObsNames_->to<mrs_string>(), ",")[0]; 00129 ostringstream oss; 00130 00131 // for (mrs_natural i = 0; i < inSamples_; ++i) 00132 // { 00133 // oss << "FFT" << inSamples_ 00134 // \todo: shouldn't there be some sort of index included in the obsName? like 00135 // << "i" << i 00136 // << "_" << inObsName << ","; 00137 // } 00138 00139 // ctrl_onObsNames_->setValue(oss.str(), NOUPDATE); 00140 00141 ctrl_onObsNames_->setValue("FFT" + oss.str() + "_" + ctrl_inObsNames_->to<mrs_string>(), NOUPDATE); 00142 00143 00144 00145 00146 ponObservations_ = onObservations_; 00147 } 00148 00149 void 00150 Spectrum::myProcess(realvec& in, realvec& out) 00151 { 00152 if (!correct_input_format_) 00153 return; 00154 00155 mrs_natural t; 00156 // copy to output to perform inplace fft 00157 // notice transposition of matrix 00158 // from row to column 00159 for (t=0; t < inSamples_; t++) 00160 { 00161 out(t,0) = in(0,t); 00162 } 00163 00164 mrs_real *tmp = out.getData(); 00165 myfft_.rfft(tmp, inSamples_/2, FFT_FORWARD); 00166 00167 if (cutoff_ != 1.0) 00168 { 00169 for (t= (mrs_natural)((cutoff_ * inSamples_) / 2); t < inSamples_/2; t++) 00170 { 00171 out(2*t,0) = 0; 00172 out(2*t+1,0) = 0; 00173 } 00174 } 00175 00176 if (lowcutoff_ != 0.0) 00177 { 00178 for (t=0; t < (mrs_natural)((lowcutoff_ * inSamples_) /2); t++) 00179 { 00180 out(2*t,0) = 0; 00181 out(2*t+1,0) = 0; 00182 } 00183 } 00184 00185 //compare with matlab fft 00186 // MATLAB_PUT(in, "vec"); 00187 // MATLAB_EVAL("out=fft(vec);"); 00188 // MATLAB_GET("vec", out); 00189 00190 return; 00191 }