Marsyas  0.6.0-alpha
/usr/src/RPM/BUILD/marsyas-0.6.0/src/marsyas/marsystems/Spectrum.cpp
Go to the documentation of this file.
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 }