Marsyas  0.6.0-alpha
/usr/src/RPM/BUILD/marsyas-0.6.0/src/marsyas/marsystems/SCF.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 "SCF.h"
00020 #include "../common_source.h"
00021 
00022 using namespace std;
00023 using namespace Marsyas;
00024 
00025 SCF::SCF(mrs_string name):MarSystem("SCF",name)
00026 {
00027 }
00028 
00029 SCF::~SCF()
00030 {
00031 }
00032 
00033 MarSystem*
00034 SCF::clone() const
00035 {
00036   return new SCF(*this);
00037 }
00038 
00039 void
00040 SCF::myUpdate(MarControlPtr sender)
00041 {
00042   (void) sender;  //suppress warning of unused parameter(s)
00043   MRSDIAG("SCF.cpp - SCF:myUpdate");
00044 
00045   //MPEG-7 audio standard:
00046   //assumes an 1/4 octave frequency resolution,
00047   //resulting in 24 frequency bands between 250Hz and 16kHz.
00048   //If the signal under analysis does not contain frequencies
00049   //above a determined value (e.g. due to signal sampling rate or
00050   //bandwidth limitations), the nr of bands should be reduced.
00051 
00052   mrs_natural i;
00053 
00054   //nrBands_ = getctrl("mrs_natural/nrbands");// can this be received as a control value?
00055   nrBands_ = 24;
00056   //can this parameter be dynamically modified, depending on the
00057   //sampling frequency?!?
00058   nrValidBands_ = nrBands_;
00059 
00060   setctrl(ctrl_onSamples_, 1);
00061   setctrl(ctrl_onObservations_, nrBands_);
00062   setctrl(ctrl_osrate_, ctrl_israte_);
00063 
00064   //features names
00065   mrs_string orig = ctrl_inObsNames_->to<mrs_string>();
00066   // remove final comma in name
00067   orig = orig.substr(0, orig.size()-1);
00068   ostringstream oss;
00069   for (i = 0; i < nrBands_; ++i)
00070     oss << "SCF_" + orig << i+1 << ",";
00071   setctrl(ctrl_onObsNames_, oss.str());
00072 
00073   edge_.create(nrBands_ + 1);
00074   bandLoEdge_.create(nrBands_);
00075   bandHiEdge_.create(nrBands_);
00076 
00077   //nominal band edges (Hz) -> reference = 1kHz (MPEG7)
00078   for(i = 0 ; i < nrBands_ + 1 ; ++i)
00079   {
00080     // 1/4 octave resolution (MPEG7)
00081     edge_(i) = 1000.0 * std::pow(2.0, (0.25 * (i - 8)));
00082   }
00083   // overlapped low and high band edges (Hz)
00084   for (i = 0; i < nrBands_; ++i)
00085   {
00086     bandLoEdge_(i) = edge_(i) * 0.95f; //band overlapping (MPEG7)
00087     bandHiEdge_(i) = edge_(i+1) * 1.05f; //band overlapping (MPEG7)
00088   }
00089 
00090   spectrumSize_ = ctrl_inObservations_->to<mrs_natural>();//PowerSpectrum returns N/2+1 spectral points
00091   //spectrumBinFreqs_.create(spectrumSize_);
00092 
00093   // spectrum sampling rate - not audio
00094   df_ = ctrl_israte_->to<mrs_real>();
00095 
00096   //calculate the frequency (Hz) of each FFT bin
00097   //for (mrs_natural k=0; k < spectrumSize_ ; k++)
00098   //    spectrumBinFreqs_(k) = (float) k * df_;
00099 
00100   //calculate FFT bin indexes for each band's edges
00101   il_.resize(nrBands_);
00102   ih_.resize(nrBands_);
00103   for(i = 0; i < nrBands_; ++i)
00104   {
00105     //round to nearest int (MPEG7)
00106     il_[i] = (mrs_natural)(bandLoEdge_(i)/df_ + 0.5f);
00107     ih_[i] = (mrs_natural)(bandHiEdge_(i)/df_ + 0.5f);
00108 
00109     //must verify if sampling rate is enough
00110     //for the specified nr of bands. If not,
00111     //reduce nr of valid freq. bands
00112     if(ih_[i] >= spectrumSize_) //if ih_[i] >= N/2+1 = spectrumSize_ = inObservations ...
00113     {
00114       nrValidBands_ = i;
00115       il_.resize(nrValidBands_);
00116       ih_.resize(nrValidBands_);
00117       break;
00118     }
00119   }
00120 }
00121 
00122 void
00123 SCF::myProcess(realvec& in, realvec& out)
00124 {
00125   mrs_natural i, k, bandwidth;
00126   double c, maxc;
00127   double aritMean ;
00128 
00129   //default SCF value = 1.0; (defines SCF=1.0 for silence)
00130   out.setval(1.0);
00131 
00132   //MPEG7 defines a grouping mechanism for the frequency bands above 1KHz
00133   //in order to reduce computational effort of the following calculation.
00134   //For now such grouping mechanism is not implemented...
00135   for(i = 0; i < nrValidBands_; ++i)
00136   {
00137     aritMean = 0.0;
00138     maxc = 0.0;
00139     bandwidth = ih_[i] - il_[i] + 1;
00140     for(k = il_[i]; k <= ih_[i]; k++)
00141     {
00142       c = in(k); //power spectrum coeff
00143       aritMean += c / bandwidth;
00144       if(c > maxc)
00145         maxc = c;
00146     }
00147     if (aritMean != 0.0)
00148     {
00149       out(i) = (float)(maxc/aritMean);
00150     }
00151     //else //mean power = 0 => silence...
00152     //  out(i) = 1.0; //as used for the SFM (MPEG-7)...
00153   }
00154 
00155   //for freq bands above the nyquist freq
00156   //return SFM value defined in MPEG7 for silence
00157   //for(i = nrValidBands_; i < nrBands_; ++i)
00158   //    out(i) = 1.0;
00159 }