00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "AimSSI.h"
00020
00021 using std::ostringstream;
00022 using namespace Marsyas;
00023
00024 AimSSI::AimSSI(mrs_string name):MarSystem("AimSSI",name)
00025 {
00026 is_centre_frequencies_calculated = false;
00027 addControls();
00028 }
00029
00030
00031 AimSSI::~AimSSI()
00032 {
00033 }
00034
00035 bool
00036 AimSSI::InitializeInternal() {
00037 return true;
00038 }
00039
00040 void
00041 AimSSI::ResetInternal() {
00042 }
00043
00044
00045 double
00046 AimSSI::Log2(double n) {
00047
00048 return log( n ) / log( 2.0f );
00049 }
00050
00051
00052 MarSystem*
00053 AimSSI::clone() const
00054 {
00055 return new AimSSI(*this);
00056 }
00057
00058 void
00059 AimSSI::addControls()
00060 {
00061 addControl("mrs_bool/do_pitch_cutoff", false , ctrl_do_pitch_cutoff_);
00062 addControl("mrs_bool/weight_by_cutoff", false , ctrl_weight_by_cutoff_);
00063 addControl("mrs_bool/weight_by_scaling", false , ctrl_weight_by_scaling_);
00064 addControl("mrs_bool/log_cycles_axis", true , ctrl_log_cycles_axis_);
00065 addControl("mrs_real/pitch_search_start_ms", 2.0 , ctrl_pitch_search_start_ms_);
00066 addControl("mrs_real/ssi_width_cycles", 10.0 , ctrl_ssi_width_cycles_);
00067 addControl("mrs_real/pivot_cf", 1000.0 , ctrl_pivot_cf_);
00068
00069
00070 addControl("mrs_real/min_frequency", 86.0 , ctrl_min_frequency_);
00071 addControl("mrs_real/max_frequency", 16000.0 , ctrl_max_frequency_);
00072
00073 }
00074
00075 void
00076 AimSSI::myUpdate(MarControlPtr sender)
00077 {
00078
00079 (void) sender;
00080 MRSDIAG("AimSSI.cpp - AimSSI:myUpdate");
00081 ctrl_onSamples_->setValue(ctrl_inSamples_, NOUPDATE);
00082 ctrl_onObservations_->setValue(ctrl_inObservations_, NOUPDATE);
00083 ctrl_osrate_->setValue(ctrl_israte_, NOUPDATE);
00084 ctrl_onObsNames_->setValue("AimSSI_" + ctrl_inObsNames_->to<mrs_string>() , NOUPDATE);
00085
00086
00087
00088
00089
00090
00091 ssi_width_samples_ = 512;
00092
00093
00094 if (ssi_width_samples_ > ctrl_inSamples_->to<mrs_natural>()) {
00095 ssi_width_samples_ = ctrl_inSamples_->to<mrs_natural>();
00096 double cycles = ssi_width_samples_ * ctrl_pivot_cf_->to<mrs_real>() / ctrl_israte_->to<mrs_real>();
00097 MRSWARN("Requested SSI width is too long for the input buffer");
00098
00099
00100
00101
00102 ctrl_ssi_width_cycles_ = cycles;
00103 }
00104
00105 if (!is_centre_frequencies_calculated) {
00106 CalculateCentreFrequencies();
00107 is_centre_frequencies_calculated = true;
00108 }
00109
00110 }
00111
00112
00113
00114 void
00115 AimSSI::CalculateCentreFrequencies() {
00116 int num_channels = ctrl_inObservations_->to<mrs_natural>();
00117 double erb_max = ERBTools::Freq2ERB(ctrl_max_frequency_->to<mrs_real>());
00118 double erb_min = ERBTools::Freq2ERB(ctrl_min_frequency_->to<mrs_real>());
00119 double delta_erb = (erb_max - erb_min) / (num_channels - 1);
00120
00121 centre_frequencies_.resize(num_channels);
00122 double erb_current = erb_min;
00123
00124 for (int i = 0; i < num_channels; ++i) {
00125 centre_frequencies_[i] = ERBTools::ERB2Freq(erb_current);
00126 erb_current += delta_erb;
00127 }
00128 }
00129
00130 int
00131 AimSSI::ExtractPitchIndex(realvec& in) const {
00132
00133 std::vector<double> sai_temporal_profile(ctrl_inSamples_->to<mrs_natural>(), 0.0);
00134 for (int i = 0; i < ctrl_inSamples_->to<mrs_natural>(); ++i) {
00135 double val = 0.0;
00136 for (int ch = 0; ch < ctrl_inObservations_->to<mrs_natural>(); ++ch) {
00137 val += in(ch, i);
00138 }
00139 sai_temporal_profile[i] = val;
00140 }
00141
00142
00143 int start_sample = (int)floor(ctrl_pitch_search_start_ms_->to<mrs_real>() * ctrl_israte_->to<mrs_real>() / 1000.0);
00144 int max_idx = 0;
00145 double max_val = 0.0;
00146 for (int i = start_sample; i < ctrl_inSamples_->to<mrs_natural>(); ++i) {
00147 if (sai_temporal_profile[i] > max_val) {
00148 max_idx = i;
00149 max_val = sai_temporal_profile[i];
00150 }
00151 }
00152 return max_idx;
00153 }
00154
00155
00156 void
00157 AimSSI::myProcess(realvec& in, realvec& out)
00158 {
00159 int pitch_index = ctrl_inSamples_->to<mrs_natural>() - 1;
00160 if (ctrl_do_pitch_cutoff_->to<mrs_bool>()) {
00161 pitch_index = ExtractPitchIndex(in);
00162 }
00163
00164 for (o = 0; o < ctrl_inObservations_->to<mrs_natural>(); o++) {
00165 double centre_frequency = centre_frequencies_[o];
00166
00167 for (t = 0; t < ssi_width_samples_; t++) {
00168 double h;
00169 double cycle_samples = ctrl_israte_->to<mrs_real>() / centre_frequency;
00170 if (ctrl_log_cycles_axis_->to<mrs_bool>()) {
00171 double gamma_min = -1.0;
00172 double gamma_max = Log2(ctrl_ssi_width_cycles_->to<mrs_real>());
00173 double gamma = gamma_min + (gamma_max - gamma_min)
00174 * static_cast<double>(t)
00175 / static_cast<double>(ssi_width_samples_);
00176 h = pow(2.0, gamma);
00177 } else {
00178 h = static_cast<double>(t) * ctrl_ssi_width_cycles_->to<mrs_real>()
00179 / static_cast<double>(ssi_width_samples_);
00180 }
00181
00182
00183
00184
00185
00186 double whole_part;
00187 double frac_part = modf(h * cycle_samples, &whole_part);
00188 int sample = (int)floor(whole_part);
00189
00190 double weight = 1.0;
00191
00192 int cutoff_index = ctrl_inSamples_->to<mrs_natural>() - 1;
00193 if (ctrl_do_pitch_cutoff_->to<mrs_bool>()) {
00194 if (pitch_index < cutoff_index) {
00195 if (ctrl_weight_by_cutoff_->to<mrs_bool>()) {
00196 weight *= static_cast<double>(ctrl_inSamples_->to<mrs_natural>())
00197 / static_cast<double>(pitch_index);
00198 }
00199 cutoff_index = pitch_index;
00200 }
00201 }
00202
00203 if (ctrl_weight_by_scaling_->to<mrs_bool>()) {
00204 if (centre_frequency > ctrl_pivot_cf_->to<mrs_real>()) {
00205 weight *= (centre_frequency / ctrl_pivot_cf_->to<mrs_real>());
00206 }
00207 }
00208
00209 double val;
00210 if (sample < cutoff_index) {
00211 double curr_sample = in(o, sample);
00212 double next_sample = in(o, sample + 1);
00213 val = weight * (curr_sample
00214 + frac_part * (next_sample - curr_sample));
00215 } else {
00216 val = 0.0;
00217 }
00218 out(o, t) = val;
00219 }
00220 }
00221
00222 }