00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "common.h"
00020 #include "HarmonicStrength.h"
00021
00022 using std::ostringstream;
00023 using namespace Marsyas;
00024
00025 using namespace std;
00026
00027 HarmonicStrength::HarmonicStrength(mrs_string name) : MarSystem("HarmonicStrength", name)
00028 {
00029 addControls();
00030 }
00031
00032 HarmonicStrength::HarmonicStrength(const HarmonicStrength& a) : MarSystem(a)
00033 {
00034 ctrl_base_frequency_ = getctrl("mrs_real/base_frequency");
00035 ctrl_harmonics_ = getctrl("mrs_realvec/harmonics");
00036 ctrl_harmonicsSize_ = getctrl("mrs_natural/harmonicsSize");
00037 ctrl_harmonicsWidth_ = getctrl("mrs_real/harmonicsWidth");
00038 ctrl_inharmonicity_B_ = getctrl("mrs_real/inharmonicity_B");
00039 }
00040
00041
00042 HarmonicStrength::~HarmonicStrength()
00043 {
00044 }
00045
00046 MarSystem*
00047 HarmonicStrength::clone() const
00048 {
00049 return new HarmonicStrength(*this);
00050 }
00051
00052 void
00053 HarmonicStrength::addControls()
00054 {
00055 addctrl("mrs_real/base_frequency", 440.0, ctrl_base_frequency_);
00056 addctrl("mrs_realvec/harmonics", realvec(0), ctrl_harmonics_);
00057 addctrl("mrs_natural/harmonicsSize", 0, ctrl_harmonicsSize_);
00058 setctrlState("mrs_natural/harmonicsSize", true);
00059 addctrl("mrs_real/harmonicsWidth", 0.05, ctrl_harmonicsWidth_);
00060 addctrl("mrs_natural/type", 0);
00061 addctrl("mrs_real/inharmonicity_B", 0.0, ctrl_inharmonicity_B_);
00062 }
00063
00064 void
00065 HarmonicStrength::myUpdate(MarControlPtr sender)
00066 {
00067 MRSDIAG("HarmonicStrength.cpp - HarmonicStrength:myUpdate");
00068
00070 MarSystem::myUpdate(sender);
00071
00072 mrs_natural num_harmonics = ctrl_harmonicsSize_->to<mrs_natural>();
00073
00074 {
00075
00076 MarControlAccessor acc(ctrl_harmonics_);
00077 mrs_realvec& harmonics = acc.to<mrs_realvec>();
00078 if ((num_harmonics > 0) && (harmonics.getSize() == 0))
00079 {
00080 harmonics.stretch(num_harmonics);
00081 for (mrs_natural i=0; i < num_harmonics; ++i)
00082 {
00083 harmonics(i) = i+1;
00084 }
00085 }
00086 }
00087 ctrl_onObservations_->setValue(ctrl_harmonicsSize_->to<mrs_natural>(), NOUPDATE);
00088
00089
00090 ostringstream oss;
00091 for (mrs_natural i = 0; i < num_harmonics; ++i)
00092 {
00093 oss << "HarmonicStrength_" << i+1 << ",";
00094 }
00095 setctrl("mrs_string/onObsNames", oss.str());
00096 }
00097
00098
00099
00100 mrs_real
00101 HarmonicStrength::quadratic_interpolation(mrs_real best_bin,
00102 mrs_realvec& in, mrs_natural t)
00103 {
00104 if ((best_bin == 0) || (best_bin == in.getRows()-1))
00105 {
00106
00107
00108
00109 return in(best_bin, t);
00110 }
00111
00112
00113 mrs_real a = in(best_bin-1, t);
00114 mrs_real b = in(best_bin+0, t);
00115 mrs_real g = in(best_bin+1, t);
00116
00117 mrs_real p = 0.5 * (a-g)/(a-2*b+g);
00118
00119 if ((p < -0.5) || (p > 0.5))
00120 {
00121 return b;
00122 }
00123 mrs_real yp = b - 0.25*(a-g)*p;
00124
00125 if (yp < b)
00126 {
00127
00128
00129
00130
00131
00132 return b;
00133 }
00134 return yp;
00135 }
00136
00137 mrs_real
00138 HarmonicStrength::find_peak_magnitude(mrs_real central_bin, mrs_realvec& in,
00139 mrs_natural t, mrs_real low,
00140 mrs_real high)
00141 {
00142
00143
00144
00145
00146 mrs_natural best_bin = -1;
00147 mrs_real best_magnitude = 0;
00148 if (low < 0)
00149 {
00150 low = 0;
00151 }
00152 if (high < inSamples_)
00153 {
00154 high = inSamples_ -1;
00155 }
00156 for (mrs_natural i=low; i<high; i++)
00157 {
00158 if (in(i,t) > best_magnitude)
00159 {
00160 best_bin = i;
00161 best_magnitude = in(i,t);
00162 }
00163 }
00164 if (best_bin >= 0)
00165 {
00166 best_magnitude = quadratic_interpolation(best_bin, in, t);
00167 }
00168 else
00169 {
00170 best_magnitude = in(central_bin, t);
00171 }
00172
00173 return best_magnitude;
00174 }
00175
00176 void
00177 HarmonicStrength::myProcess(realvec& in, realvec& out)
00178 {
00179 mrs_natural h,t;
00180
00181 mrs_natural num_harmonics = ctrl_harmonicsSize_->to<mrs_natural>();
00182 mrs_real base_freq = ctrl_base_frequency_->to<mrs_real>();
00183 MarControlAccessor acc(ctrl_harmonics_);
00184 mrs_realvec& harmonics = acc.to<mrs_realvec>();
00185 mrs_real width = ctrl_harmonicsWidth_->to<mrs_real>();
00186
00187 mrs_real freq2bin = 1.0 / ctrl_israte_->to<mrs_real>();
00188
00189
00190 for (t = 0; t < inSamples_; t++)
00191 {
00192 mrs_real energy_rms = 0.0;
00193 for (o = 0; o < inObservations_; o++)
00194 {
00195 energy_rms += in(o, t) * in(o,t);
00196 }
00197 energy_rms = sqrt(energy_rms);
00198
00199 for (h = 0; h < num_harmonics; h++)
00200 {
00201 mrs_real n = harmonics(h);
00202 mrs_real B = ctrl_inharmonicity_B_->to<mrs_real>();
00203
00204 mrs_real freq = n * base_freq * sqrt(1.0 + B*n*n);
00205 mrs_real bin = freq * freq2bin;
00206
00207
00208
00209 mrs_real low = bin - width * inObservations_;
00210 mrs_real high = bin + width * inObservations_;
00211 mrs_real magnitude = find_peak_magnitude(bin, in, t, low, high);
00212 if (magnitude == 0)
00213 {
00214 out(h, t) = 0.0;
00215 }
00216 else
00217 {
00218 switch (getctrl("mrs_natural/type")->to<mrs_natural>())
00219 {
00220 case 0:
00221 out(h, t) = log(magnitude / energy_rms);
00222 break;
00223 case 2:
00224 out(h, t) = log(magnitude);
00225 break;
00226 default:
00227 out(h, t) = magnitude;
00228 break;
00229 }
00230 }
00231
00232
00233
00234
00235
00236
00237 }
00238 }
00239 }
00240