Marsyas  0.6.0-alpha
/usr/src/RPM/BUILD/marsyas-0.6.0/src/marsyas/marsystems/SFM.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 "SFM.h"
00020 #include "../common_source.h"
00021 
00022 using namespace std;
00023 using namespace Marsyas;
00024 
00025 SFM::SFM(mrs_string name):MarSystem("SFM",name)
00026 {
00027 }
00028 
00029 SFM::~SFM()
00030 {
00031 }
00032 
00033 MarSystem*
00034 SFM::clone() const
00035 {
00036   return new SFM(*this);
00037 }
00038 
00039 void
00040 SFM::myUpdate(MarControlPtr sender)
00041 {
00042   (void) sender;  //suppress warning of unused parameter(s)
00043   MRSDIAG("SFM.cpp - SFM: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 dinamically modified, depending on the
00057   //sampling frequency?!?
00058   nrValidBands_ = nrBands_;
00059 
00060   setctrl("mrs_natural/onSamples", (mrs_natural)1);
00061   setctrl("mrs_natural/onObservations", (mrs_natural)nrBands_);
00062   setctrl("mrs_real/osrate", getctrl("mrs_real/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 << "SFM_" + orig << i+1 << ",";
00071   setctrl("mrs_string/onObsNames", oss.str());
00072 
00073   edge_.create(nrBands_ + 1);
00074   bandLoEdge_.create(nrBands_);
00075   bandHiEdge_.create(nrBands_);
00076 
00077   //nominal band edges (Hz)
00078   for(i = 0 ; i < nrBands_ + 1 ; ++i)
00079   {
00080     edge_(i) = 1000.0 * std::pow(2.0, (0.25 * (i - 8))); // 1/4 octave resolution (MPEG7)
00081   }
00082   // overlapped low and high band edges (Hz)
00083   for (i = 0; i < nrBands_; ++i)
00084   {
00085     bandLoEdge_(i) = edge_(i) * 0.95f; //band overlapping (MPEG7)
00086     bandHiEdge_(i) = edge_(i+1) * 1.05f; //band overlapping (MPEG7)
00087   }
00088 
00089   spectrumSize_ = ctrl_inObservations_->to<mrs_natural>();//PowerSpectrum returns N/2+1 spectral points
00090   //spectrumBinFreqs_.create(spectrumSize_);
00091 
00092   // spectrum sampling rate - not audio
00093   df_ = ctrl_israte_->to<mrs_real>();
00094 
00095   //calculate the frequency (Hz) of each FFT bin
00096   //for (mrs_natural k=0; k < spectrumSize_ ; k++)
00097   //  spectrumBinFreqs_(k) = (float) k * df_;
00098 
00099   //calculate FFT bin indexes for each band's edges
00100   il_.resize(nrBands_);
00101   ih_.resize(nrBands_);
00102   for(i = 0; i < nrBands_; ++i)
00103   {
00104 
00105     il_[i] = (mrs_natural)(bandLoEdge_(i)/df_ + 0.5f); //round to nearest int (MPEG7)
00106     ih_[i] = (mrs_natural)(bandHiEdge_(i)/df_ + 0.5f); //round to nearest int (MPEG7)
00107 
00108     //must verify if sampling rate is enough
00109     //for the specified nr of bands. If not,
00110     //reduce nr of valid freq. bands
00111     if(ih_[i] >= spectrumSize_) //if ih_[i] >= N/2+1 = spectrumSize_ = inObservations ...
00112     {
00113       nrValidBands_ = i;
00114       il_.resize(nrValidBands_);
00115       ih_.resize(nrValidBands_);
00116       break;
00117     }
00118   }
00119 }
00120 
00121 void
00122 SFM::myProcess(realvec& in, realvec& out)
00123 {
00124   mrs_natural i, k, bandwidth;
00125   mrs_real c;
00126   mrs_real aritMean;
00127   mrs_real geoMean;
00128 
00129   //default SFM value = 1.0; (MPEG7 defines SFM=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     geoMean = 1.0;
00138     aritMean = 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       geoMean *= pow((mrs_real)c, (mrs_real)1.0/bandwidth);
00145     }
00146     if (aritMean != 0.0)
00147     {
00148       out(i) = geoMean/aritMean;
00149     }
00150     //else //mean power = 0 => silence...
00151     //  out(i) = 1.0; //MPEG-7
00152   }
00153 
00154   //for freq bands above the nyquist freq
00155   //return SFM value defined in MPEG7 for silence
00156   //for(i = nrValidBands_; i < nrBands_; ++i)
00157   //    out(i) = 1.0;
00158 }