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 "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 }