Marsyas
0.6.0-alpha
|
00001 /* 00002 ** Copyright (C) 1998-2010 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 "AimSAI.h" 00020 #include "../common_source.h" 00021 #include "../ERBTools.h" 00022 #include <algorithm> 00023 00024 using std::ostringstream; 00025 using namespace Marsyas; 00026 00027 AimSAI::AimSAI(mrs_string name):MarSystem("AimSAI",name) 00028 { 00029 is_initialized = false; 00030 initialized_israte = 0; 00031 initialized_inobservations = 0; 00032 initialized_insamples = 0; 00033 initialized_frame_period_ms = 0.0; 00034 initialized_min_delay_ms = 0.0; 00035 initialized_max_delay_ms = 0.0; 00036 initialized_buffer_memory_decay = 0.0; 00037 initialized_max_concurrent_strobes = 0; 00038 initialized_strobe_weight_alpha = 0.0; 00039 00040 is_reset = false; 00041 reseted_israte = 0; 00042 reseted_inobservations = 0; 00043 reseted_frame_period_ms = 0; 00044 00045 addControls(); 00046 00047 // Set default values 00048 min_strobe_delay_idx_ = 0; 00049 max_strobe_delay_idx_ = 0; 00050 sai_decay_factor_ = 0.0; 00051 fire_counter_ = 0; 00052 } 00053 00054 AimSAI::~AimSAI() 00055 { 00056 } 00057 00058 MarSystem* 00059 AimSAI::clone() const 00060 { 00061 return new AimSAI(*this); 00062 } 00063 00064 void 00065 AimSAI::addControls() 00066 { 00067 addControl("mrs_real/min_delay_ms_", 0.0 , ctrl_min_delay_ms_); 00068 addControl("mrs_real/max_delay_ms_", 11.63266, ctrl_max_delay_ms_); 00069 addControl("mrs_real/strobe_weight_alpha_", 0.5 , ctrl_strobe_weight_alpha_); 00070 addControl("mrs_real/buffer_memory_decay_;", 0.03 , ctrl_buffer_memory_decay_); 00071 addControl("mrs_real/frame_period_ms_ ", 11.63266 , ctrl_frame_period_ms_); 00072 addControl("mrs_natural/max_concurrent_strobes_;", 50 , ctrl_max_concurrent_strobes_); 00073 } 00074 00075 void 00076 AimSAI::myUpdate(MarControlPtr sender) 00077 { 00078 int temp_frame_period_samples = (int)(1 + floor(ctrl_israte_->to<mrs_real>() * ctrl_frame_period_ms_->to<mrs_real>() 00079 / 1000.0)); 00080 MRSDIAG("AimSAI.cpp - AimSAI:myUpdate"); 00081 00082 (void) sender; //suppress warning of unused parameter(s) 00083 ctrl_onSamples_->setValue(temp_frame_period_samples, NOUPDATE); 00084 ctrl_osrate_->setValue(ctrl_israte_->to<mrs_real>(), NOUPDATE); 00085 ctrl_onObsNames_->setValue("AimSAI_" + ctrl_inObsNames_->to<mrs_string>() , NOUPDATE); 00086 00087 // The actual number of signal channels in the input. The output 00088 // from PZFC + HCL + Localmax is a realvec with the first third of 00089 // observations being the signal, and the second third being the 00090 // channels and the last third being the strobes. 00091 channel_count_ = ctrl_inObservations_->to<mrs_natural>() / 3; 00092 ctrl_onObservations_->setValue(channel_count_, NOUPDATE); 00093 00094 // 00095 // Does the MarSystem need initialization? 00096 // 00097 if (initialized_israte != ctrl_israte_->to<mrs_real>() || 00098 initialized_inobservations != ctrl_inObservations_->to<mrs_natural>() || 00099 initialized_insamples != ctrl_inSamples_->to<mrs_natural>() || 00100 initialized_frame_period_ms != ctrl_frame_period_ms_->to<mrs_real>() || 00101 initialized_min_delay_ms != ctrl_min_delay_ms_->to<mrs_real>() || 00102 initialized_max_delay_ms != ctrl_max_delay_ms_->to<mrs_real>() || 00103 initialized_buffer_memory_decay != ctrl_buffer_memory_decay_->to<mrs_real>() || 00104 initialized_max_concurrent_strobes != ctrl_max_concurrent_strobes_->to<mrs_natural>() || 00105 initialized_strobe_weight_alpha != ctrl_strobe_weight_alpha_->to<mrs_real>()) { 00106 is_initialized = false; 00107 } 00108 00109 if (!is_initialized) { 00110 InitializeInternal(); 00111 is_initialized = true; 00112 initialized_israte = ctrl_israte_->to<mrs_real>(); 00113 initialized_inobservations = ctrl_inObservations_->to<mrs_natural>(); 00114 initialized_insamples = ctrl_inSamples_->to<mrs_natural>(); 00115 initialized_frame_period_ms = ctrl_frame_period_ms_->to<mrs_real>(); 00116 initialized_min_delay_ms = ctrl_min_delay_ms_->to<mrs_real>(); 00117 initialized_max_delay_ms = ctrl_max_delay_ms_->to<mrs_real>(); 00118 initialized_buffer_memory_decay = ctrl_buffer_memory_decay_->to<mrs_real>(); 00119 initialized_max_concurrent_strobes = ctrl_max_concurrent_strobes_->to<mrs_natural>(); 00120 initialized_strobe_weight_alpha = ctrl_strobe_weight_alpha_->to<mrs_real>(); 00121 } 00122 00123 // 00124 // Does the MarSystem need a reset? 00125 // 00126 if (reseted_israte != ctrl_israte_->to<mrs_real>() || 00127 reseted_inobservations != ctrl_inObservations_->to<mrs_natural>() || 00128 reseted_frame_period_ms != ctrl_frame_period_ms_->to<mrs_real>()) { 00129 is_reset = false; 00130 } 00131 00132 if (!is_reset) { 00133 ResetInternal(); 00134 is_reset = true; 00135 reseted_israte = ctrl_israte_->to<mrs_real>(); 00136 reseted_inobservations = ctrl_inObservations_->to<mrs_natural>(); 00137 reseted_frame_period_ms = ctrl_frame_period_ms_->to<mrs_real>(); 00138 } 00139 00140 } 00141 00142 void 00143 AimSAI::InitializeInternal() { 00144 // The SAI output bank must be as long as the SAI's Maximum delay. 00145 // One sample is added to the SAI buffer length to account for the 00146 // zero-lag point 00147 // int sai_buffer_length = 1 + floor(ctrl_israte_->to<mrs_real>() * ctrl_max_delay_ms_->to<mrs_real>() 00148 // / 1000.0); 00149 // channel_count_ = ctrl_inObservations_->to<mrs_natural>() / 2; 00150 // cout << "channel_count=" << channel_count_ << endl; 00151 00152 00153 // // Make an output SignalBank with the same number of channels and centre 00154 // // frequencies as the input, but with a different buffer length 00155 // if (!output_.Initialize(input.channel_count(), 00156 // sai_buffer_length, 00157 // input.sample_rate())) { 00158 // LOG_ERROR("Failed to create output buffer in SAI module"); 00159 // return false; 00160 // } 00161 // for (int i = 0; i < inObservations; ++i) { 00162 // output_.set_centre_frequency(i, input.centre_frequency(i)); 00163 // } 00164 00165 // // sai_temp_ will be initialized to zero 00166 // if (!sai_temp_.Initialize(output_)) { 00167 // LOG_ERROR("Failed to create temporary buffer in SAI module"); 00168 // return false; 00169 // } 00170 00171 centre_frequencies_.resize(channel_count_); 00172 00173 int temp_frame_period_samples = (int)(1 + floor(ctrl_israte_->to<mrs_real>() * ctrl_frame_period_ms_->to<mrs_real>() 00174 / 1000.0)); 00175 sai_temp_.create(channel_count_,temp_frame_period_samples); 00176 00177 frame_period_samples_ = (int)floor(ctrl_israte_->to<mrs_real>() * ctrl_frame_period_ms_->to<mrs_real>() 00178 / 1000.0); 00179 min_strobe_delay_idx_ = (int)floor(ctrl_israte_->to<mrs_real>() * ctrl_min_delay_ms_->to<mrs_real>() 00180 / 1000.0); 00181 max_strobe_delay_idx_ = (int)floor(ctrl_israte_->to<mrs_real>() * ctrl_max_delay_ms_->to<mrs_real>() 00182 / 1000.0); 00183 00184 // Make sure we don't go past the output buffer's upper bound 00185 if (max_strobe_delay_idx_ > ctrl_onSamples_->to<mrs_natural>()) { 00186 max_strobe_delay_idx_ = ctrl_onSamples_->to<mrs_natural>(); 00187 } 00188 00189 // Define decay factor from time since last sample (see ti2003) 00190 sai_decay_factor_ = pow(0.5, 1.0 / (double)(ctrl_buffer_memory_decay_->to<mrs_real>() * (double)ctrl_israte_->to<mrs_real>())); 00191 00192 // Precompute strobe weights 00193 strobe_weights_.resize(ctrl_max_concurrent_strobes_->to<mrs_natural>()); 00194 for (int n = 0; n < ctrl_max_concurrent_strobes_->to<mrs_natural>(); ++n) { 00195 strobe_weights_[n] = pow(1.0 / (n + 1), (double)ctrl_strobe_weight_alpha_->to<mrs_real>()); 00196 } 00197 } 00198 00199 void 00200 AimSAI::ResetInternal() { 00201 // Active Strobes 00202 active_strobes_.clear(); 00203 active_strobes_.resize(channel_count_); 00204 fire_counter_ = frame_period_samples_ - 1; 00205 } 00206 00207 00208 // We are passed a realvec with the signals and then the strobes for 00209 // the signals, so we have twice the number of observations that we 00210 // would usually have. Take the strobes part of the realvec and find 00211 // the strobes for each observation. 00212 void 00213 AimSAI::findStrobes(realvec& in) { 00214 mrs_natural _inSamples = ctrl_inSamples_->to<mrs_natural>(); 00215 00216 strobes_.clear(); 00217 strobes_.resize(channel_count_); 00218 for (int o = 0; o < channel_count_; o++) { 00219 strobes_[o].clear(); 00220 for (int t = 0; t < _inSamples; t++) { 00221 if (in(o + channel_count_ + channel_count_,t) == 1) { 00222 strobes_[o].push_back(t); 00223 } 00224 } 00225 } 00226 00227 // for (int o = 0; o < channel_count_; o++) { 00228 // // cout << "ch=" << o << " strobes="; 00229 // for (unsigned int i=0; i < strobes_[o].size(); ++i) { 00230 // cout << strobes_[o][i] << " "; 00231 // } 00232 // cout << endl; 00233 // } 00234 00235 // exit(0); 00236 00237 } 00238 00239 // // sness - Because we can't pass the centre_frequencies from one 00240 // // MarSystem to the next, we need to recalculate them here. 00241 // void 00242 // AimSAI::CalculateCentreFrequencies() { 00243 // // sness - Need to divide by two because there is one strobe channel 00244 // // for every observation channel 00245 // int num_channels = ctrl_inObservations_->to<mrs_natural>() / 2; 00246 // double erb_min = ERBTools::Freq2ERB(ctrl_min_frequency_->to<mrs_real>()); 00247 // double erb_max = ERBTools::Freq2ERB(ctrl_max_frequency_->to<mrs_real>()); 00248 // double delta_erb = (erb_max - erb_min) / (num_channels - 1); 00249 00250 // centre_frequencies_.resize(num_channels); 00251 // double erb_current = erb_min; 00252 00253 // for (int i = 0; i < num_channels; ++i) { 00254 // centre_frequencies_[i] = ERBTools::ERB2Freq(erb_current); 00255 // erb_current += delta_erb; 00256 // } 00257 // } 00258 00259 void 00260 AimSAI::myProcess(realvec& in, realvec& out) 00261 { 00262 // cout << "AimSAI::myProcess" << endl; 00263 size_t _max_concurrent_strobes = (size_t) std::max((mrs_natural) 0, ctrl_max_concurrent_strobes_->to<mrs_natural>()); 00264 mrs_real _israte = ctrl_israte_->to<mrs_real>(); 00265 // mrs_natural _inSamples = ctrl_inSamples_->to<mrs_natural>(); 00266 00267 // Grab the centre frequencies from the input 00268 for (int o = 0; o < channel_count_; ++o) { 00269 centre_frequencies_[o] = in(o + channel_count_); 00270 // cout << "centre_frequencies_[" << o << "]=" << centre_frequencies_[o] << endl; 00271 } 00272 00273 findStrobes(in); 00274 00275 // Reset the next strobe times 00276 next_strobes_.clear(); 00277 next_strobes_.resize(channel_count_, 0); 00278 00279 // Offset the times on the strobes from the previous buffer 00280 for (int o = 0; o < channel_count_; ++o) { 00281 active_strobes_[o].ShiftStrobes(ctrl_inSamples_->to<mrs_natural>()); 00282 } 00283 00284 // Loop over samples to make the SAI 00285 for (int t = 0; t < ctrl_inSamples_->to<mrs_natural>(); ++t) 00286 { 00287 double decay_factor = pow(sai_decay_factor_, fire_counter_); 00288 00289 // Loop over channels 00290 for (int o = 0; o < channel_count_; ++o) 00291 { 00292 // cout << "o=" << o << endl; 00293 // cout << "\tch=" << o << endl; 00294 // Local convenience variables 00295 StrobeList &active_strobes = active_strobes_[o]; 00296 unsigned int next_strobe_index = next_strobes_[o]; 00297 00298 // Update strobes 00299 // If we are up to or beyond the next strobe... 00300 if (next_strobe_index < strobes_[o].size()) { 00301 // cout << "(next_strobe_index < strobes_[o].size())" << endl; 00302 // cout << "\t\tnext_strobe_index" << next_strobe_index << endl; 00303 // cout << "\t\tinput.strobe(ch, next_strobe_index)=" << strobes_[o][next_strobe_index] << endl; 00304 00305 if (t == strobes_[o][next_strobe_index]) { 00306 // cout << "(t == strobes_[o][next_strobe_index])" << endl; 00307 // A new strobe has arrived. 00308 // If there are too many strobes active, then get rid of the 00309 // earliest one 00310 if (active_strobes.strobe_count() >= _max_concurrent_strobes) { 00311 active_strobes.DeleteFirstStrobe(); 00312 } 00313 00314 // Add the active strobe to the list of current strobes and 00315 // calculate the strobe weight 00316 double weight = 1.0; 00317 if (active_strobes.strobe_count() > 0) { 00318 int last_strobe_time = active_strobes.Strobe( 00319 active_strobes.strobe_count() - 1).time; 00320 00321 // If the strobe occured within 10 impulse-response 00322 // cycles of the previous strobe, then lower its weight 00323 // cout << "t=" << t << "\tlast_strobe_time=" << last_strobe_time << "_israte=" << _israte << " cf=" << centre_frequencies_[o] << endl; 00324 weight = (t - last_strobe_time) / _israte 00325 * centre_frequencies_[o] / 10.0; 00326 if (weight > 1.0) 00327 weight = 1.0; 00328 } 00329 active_strobes.AddStrobe(t, weight); 00330 next_strobe_index++; 00331 00332 // Update the strobe weights 00333 double total_strobe_weight = 0.0; 00334 for (size_t si = 0; si < active_strobes.strobe_count(); ++si) { 00335 // cout << "si=" << si << "\tw=" << active_strobes.Strobe(si).weight << "\tw2=" << strobe_weights_[active_strobes.strobe_count() - si - 1] << endl; 00336 total_strobe_weight += (active_strobes.Strobe(si).weight 00337 * strobe_weights_[active_strobes.strobe_count() - si - 1]); 00338 } 00339 for (size_t si = 0; si < active_strobes.strobe_count(); ++si) { 00340 // cout << "si=" << si << "\tw1=" << active_strobes.Strobe(si).weight << "\tw2=" << strobe_weights_[active_strobes.strobe_count() - si - 1] << " tot=" << total_strobe_weight << endl; 00341 active_strobes.SetWorkingWeight(si, 00342 (active_strobes.Strobe(si).weight 00343 * strobe_weights_[active_strobes.strobe_count() - si - 1]) 00344 / total_strobe_weight); 00345 } 00346 } 00347 } 00348 00349 // Remove inactive strobes 00350 while (active_strobes.strobe_count() > 0) { 00351 // Get the relative time of the first strobe, and see if it exceeds 00352 // the maximum allowed time. 00353 if ((t - active_strobes.Strobe(0).time) > max_strobe_delay_idx_) { 00354 active_strobes.DeleteFirstStrobe(); 00355 } else { 00356 // cout << "break" << endl; 00357 break; 00358 } 00359 } 00360 00361 // Update the SAI buffer with the weighted effect of all the active 00362 // strobes at the current sample 00363 for (size_t si = 0; si < active_strobes.strobe_count(); ++si) { 00364 // cout << "si=" << si << endl; 00365 // Add the effect of active strobe at correct place in the SAI buffer 00366 // Calculate 'delay', the time from the strobe event to now 00367 int delay = t - active_strobes.Strobe(si).time; 00368 00369 // If the delay is greater than the (user-set) 00370 // minimum strobe delay, the strobe can be used 00371 if (delay >= min_strobe_delay_idx_ && delay < max_strobe_delay_idx_) { 00372 // The value at be added to the SAI 00373 double sig = in(o, t); 00374 // cout << "sig=" << sig << "\tww=" << active_strobes.Strobe(si).working_weight << "\tdecay=" << decay_factor << endl; 00375 00376 // Weight the sample correctly 00377 sig *= active_strobes.Strobe(si).working_weight; 00378 00379 // Adjust the weight acording to the number of samples until the 00380 // next output frame 00381 sig *= decay_factor; 00382 00383 // Update the temporary SAI buffer 00384 // cout << "output1(" << o << "," << delay << ")=" << out(o, delay) + sig << endl; 00385 sai_temp_(o, delay) = sai_temp_(o, delay) + sig; 00386 } 00387 } 00388 00389 next_strobes_[o] = next_strobe_index; 00390 } // End loop over channels 00391 00392 fire_counter_--; 00393 00394 // cout << "fire_counter_=" << fire_counter_ << endl; 00395 00396 // Check to see if we need to output an SAI frame on this sample 00397 if (fire_counter_ <= 0) { 00398 // cout << "(fire_counter_ <= 0)" << endl; 00399 // Decay the SAI by the correct amount and add the current output frame 00400 double decay = pow(sai_decay_factor_, frame_period_samples_); 00401 00402 for (int o = 0; o < channel_count_; ++o) { 00403 // for (int t = 0; t < _inSamples; ++t ) { 00404 for (int t = 0; t < frame_period_samples_; ++t ) { 00405 // cout << "output2(" << o << "," << t << ")=" << sai_temp_(o,t) + out(o,t) * decay << endl; 00406 out(o, t) = sai_temp_(o,t) + out(o,t) * decay; 00407 } 00408 } 00409 00410 // Zero the temporary signal 00411 for (int o = 0; o < sai_temp_.getRows(); ++o) { 00412 for (int t = 0; t < sai_temp_.getCols(); ++t) { 00413 sai_temp_(o, t) = 0.0; 00414 } 00415 } 00416 fire_counter_ = frame_period_samples_ - 1; 00417 } 00418 } // End loop over samples 00419 00420 // Copy over the strobes 00421 // for (int t = 0; t < ctrl_inSamples_->to<mrs_natural>(); ++t) { 00422 // for (int o = channel_count_; o < channel_count_ * 2; ++o) { 00423 // out(o,t) = in(o,t); 00424 // } 00425 // } 00426 00427 }