Mercurial > hg > aimc
diff trunk/src/Modules/SAI/ModuleSAI.cc @ 277:6b4921704eb1
- Ported over HTK file output
- Added some more meat to the Slaney IIR gammatone implementation
- Ported over the AIM-MAT sf2003 parabola strobe algorithm
- Finished making the SAI implementation compile
- Ported over the strobe list class (now uses STL deques internally)
author | tomwalters |
---|---|
date | Thu, 18 Feb 2010 16:55:40 +0000 |
parents | ce2bab04f155 |
children | 5b8b9ea1218a |
line wrap: on
line diff
--- a/trunk/src/Modules/SAI/ModuleSAI.cc Tue Feb 16 18:40:55 2010 +0000 +++ b/trunk/src/Modules/SAI/ModuleSAI.cc Thu Feb 18 16:55:40 2010 +0000 @@ -29,11 +29,12 @@ #include "Modules/SAI/ModuleSAI.h" +namespace aimc { ModuleSAI::ModuleSAI(Parameters *parameters) : Module(parameters) { + module_identifier_ = "weighted_sai"; + module_type_ = "sai"; module_description_ = "Stabilised auditory image"; - module_name_ = "sai2007"; - module_type_ = "sai"; - module_id_ = "$Id: ModuleSAI.cc 4 2010-02-03 18:44:58Z tcw $"; + module_version_ = "$Id: ModuleSAI.cc 4 2010-02-03 18:44:58Z tcw $"; min_delay_ms_ = parameters_->DefaultFloat("sai.min_delay_ms", 0.0f); max_delay_ms_ = parameters_->DefaultFloat("sai.max_delay_ms", 35.0f); @@ -43,30 +44,32 @@ 0.03f); frame_period_ms_ = parameters_->DefaultFloat("sai.frame_period_ms", 20.0f); - min_strobe_delay_index_ = 0; - max_strobe_delay_index_ = 0; + max_concurrent_strobes_ + = parameters_->DefaultInt("sai.max_concurrent_strobes", 50); + + min_strobe_delay_idx_ = 0; + max_strobe_delay_idx_ = 0; sai_decay_factor_ = 0.0f; - max_concurrent_strobes_ = 0; - output_frame_period_ms_ = 0.0f; - last_output_frame_time_ms_ = 0.0f; + fire_counter_ = 0; } bool ModuleSAI::InitializeInternal(const SignalBank &input) { // The SAI output bank must be as long as the SAI's Maximum delay. // One sample is added to the SAI buffer length to account for the // zero-lag point - int sai_buffer_length = 1 + Round(input.sample_rate() * max_delay_ms_); + int sai_buffer_length = 1 + floor(input.sample_rate() * max_delay_ms_); + channel_count_ = input.channel_count(); // Make an output SignalBank with the same number of channels and centre // frequencies as the input, but with a different buffer length if (!output_.Initialize(input.channel_count(), sai_buffer_length, - input.sample_rate());) { + input.sample_rate())) { LOG_ERROR("Failed to create output buffer in SAI module"); return false; } for (int i = 0; i < input.channel_count(); ++i ) { - output_.set_centre_frequency(i, input.get_centre_frequency(i)); + output_.set_centre_frequency(i, input.centre_frequency(i)); } // sai_temp_ will be initialized to zero @@ -75,169 +78,154 @@ return false; } - last_output_time_ms_ = 0.0f; - - frame_period_samples_ = Round(input.sample_rate() - * frame_period_ms_ / 1000.0f); - - min_strobe_delay_idx_ = Round(input.sample_rate() * min_delay_ms_ / 1000.0f); - max_strobe_delay_idx_ = Round(input.sample_rate() * max_delay_ms_ / 1000.0f); + frame_period_samples_ = floor(input.sample_rate() * frame_period_ms_ + / 1000.0f); + min_strobe_delay_idx_ = floor(input.sample_rate() * min_delay_ms_ + / 1000.0f); + max_strobe_delay_idx_ = floor(input.sample_rate() * max_delay_ms_ + / 1000.0f); // Make sure we don't go past the output buffer's upper bound - if (max_strobe_delay_idx_ > output_.buffer_length())) + if (max_strobe_delay_idx_ > output_.buffer_length()) { max_strobe_delay_idx_ = output_.buffer_length(); + } // Define decay factor from time since last sample (see ti2003) sai_decay_factor_ = pow(0.5f, 1.0f / (buffer_memory_decay_ * input.sample_rate())); - // Maximum strobes that can be active at the same time within maxdelay. - //! \todo Choose this value in a more principled way - max_concurrent_strobes_ = Round(1000.0f * max_delay_ * 5); - // Precompute strobe weights strobe_weights_.resize(max_concurrent_strobes_); for (int n = 0; n < max_concurrent_strobes_; ++n) { - strobe_weights_[n] = pow(1.0f / (n + 1)), strobe_weight_alpha_); + strobe_weights_[n] = pow(1.0f / (n + 1), strobe_weight_alpha_); } - // Active Strobes - active_strobes_.Resize(input.channel_count()); - for (int i = 0; i < input.channel_count(); ++i) { - active_strobes_[i].Create(max_concurrent_strobes_); - } - next_strobes_.resize(input.channel_count(), 0); + ResetInternal(); return true; } void ModuleSAI::ResetInternal() { + // Active Strobes + active_strobes_.clear(); + active_strobes_.resize(channel_count_); + fire_counter_ = frame_period_samples_ - 1; } void ModuleSAI::Process(const SignalBank &input) { - int s; - int c; - int output_buffer_length = output_.buffer_length(); // Reset the next strobe times next_strobes_.clear(); next_strobes_.resize(output_.channel_count(), 0); // Offset the times on the strobes from the previous buffer - for (c = 0; c < input.channel_count(), ++c) { - active_strobes_[c].shiftStrobes(input.buffer_length()); + for (int ch = 0; ch < input.channel_count(); ++ch) { + active_strobes_[ch].ShiftStrobes(input.buffer_length()); } - // Make sure only start time is transferred to the output - output_.set_start_time(input.start_time()); - // Loop over samples to make the SAI - for (s = 0; s < input_buffer_length; ++s) { + for (int i = 0; i < input.buffer_length(); ++i) { float decay_factor = pow(sai_decay_factor_, fire_counter_); // Loop over channels - for (c = 0; c < input.channel_count(); ++c) { + for (int ch = 0; ch < input.channel_count(); ++ch) { // Local convenience variables - StrobeList &active_strobes = active_strobes_[c]; - float centre_frequency = input.get_centre_frequency(c); - int next_strobe = next_strobes_[c]; + StrobeList &active_strobes = active_strobes_[ch]; + int next_strobe_index = next_strobes_[ch]; - // 1. Update strobes + // Update strobes // If we are up to or beyond the next strobe... - if (next_strobe < input.strobe_count(c)) { - if (s == pSigIn->getStrobe(iNextStrobe)) { - //A new strobe has arrived - // if there aren't already too many strobes active... - if ((active_strobes.getStrobeCount() + 1) < max_concurrent_strobes_) { - // ...add the active strobe to the list of current strobes - // calculate the strobe weight - float weight = 1.0f; - if (active_strobes.getStrobeCount() > 0) { - int last_strobe = active_strobes.getTime( - active_strobes.getStrobeCount()); - - // If the strobe occured within 10 impulse-response - // cycles of the previous strobe, then lower its weight - weight = (s - iLastStrobe) / input.sample_rate() - * centre_frequency / 10.0f; - if (weight > 1.0f) - weight = 1.0f; - } - pActiveStrobes->addStrobe(iCurrentSample, weight); - iNextStrobe++; - } else { - // We have a problem - aimASSERT(0); + if (next_strobe_index < input.strobe_count(ch)) { + if (i == input.strobe(ch, next_strobe_index)) { + // A new strobe has arrived. + // If there are too many strobes active, then get rid of the + // earliest one + if (active_strobes.strobe_count() >= max_concurrent_strobes_) { + active_strobes.DeleteFirstStrobe(); } - // 2. Having updated the strobes, we now need to update the - // strobe weights + // Add the active strobe to the list of current strobes and + // calculate the strobe weight + float weight = 1.0f; + if (active_strobes.strobe_count() > 0) { + int last_strobe_time = active_strobes.Strobe( + active_strobes.strobe_count() - 1).time; + + // If the strobe occured within 10 impulse-response + // cycles of the previous strobe, then lower its weight + weight = (i - last_strobe_time) / input.sample_rate() + * input.centre_frequency(ch) / 10.0f; + if (weight > 1.0f) + weight = 1.0f; + } + active_strobes.AddStrobe(i, weight); + next_strobe_index++; + + + // Update the strobe weights float total_strobe_weight = 0.0f; - for (int si = 1; si <= pActiveStrobes->getStrobeCount(); ++si) { - total_strobe_weight += (pActiveStrobes->getWeight(si) - * m_pStrobeWeights[pActiveStrobes->getStrobeCount() - si]); + for (int si = 0; si < active_strobes.strobe_count(); ++si) { + total_strobe_weight += (active_strobes.Strobe(si).weight + * strobe_weights_[active_strobes.strobe_count() - si - 1]); } - for (int si = 1; si <= pActiveStrobes->getStrobeCount(); ++si) { - active_strobes.setWorkingWeight(si,(active_strobes.getWeight(si) - * strobe_weights_[active_strobes.getStrobeCount() - si]) - / total_strobe_weight); + for (int si = 0; si < active_strobes.strobe_count(); ++si) { + active_strobes.SetWorkingWeight(si, + (active_strobes.Strobe(si).weight + * strobe_weights_[active_strobes.strobe_count() - si - 1]) + / total_strobe_weight); } } } - // remove inactive strobes... - while (pActiveStrobes->getStrobeCount() > 0) { - // Get the time of the first strobe (ordering of strobes is - // from one, not zero) - int iStrobeTime = pActiveStrobes->getTime(1); - int iDelay = iCurrentSample - iStrobeTime; - // ... do we now need to remove this strobe? - if (iDelay > m_maxStrobeDelayIdx) - pActiveStrobes->deleteFirstStrobe(); + // Remove inactive strobes + while (active_strobes.strobe_count() > 0) { + // Get the relative time of the first strobe, and see if it exceeds + // the maximum allowed time. + if ((i - active_strobes.Strobe(0).time) > max_strobe_delay_idx_) + active_strobes.DeleteFirstStrobe(); else break; - // Since the strobes are ordered, we don't need to go - // beyond the first still-active strobe } - // 3. Loop over active strobes - for (int si = 1; si <= pActiveStrobes->getStrobeCount(); si++) { - // 3.1 Add effect of active strobe at correct place in the SAI buffer - // Calculate the time from the strobe event to 'now': iDelay - int iStrobeTime = pActiveStrobes->getTime(si); - int iDelay = iCurrentSample - iStrobeTime; + // Update the SAI buffer with the weighted effect of all the active + // strobes at the current sample + for (int si = 0; si < active_strobes.strobe_count(); ++si) { + // Add the effect of active strobe at correct place in the SAI buffer + // Calculate 'delay', the time from the strobe event to now + int delay = i - active_strobes.Strobe(si).time; // If the delay is greater than the (user-set) // minimum strobe delay, the strobe can be used - if (iDelay >= m_minStrobeDelayIdx && iDelay < m_maxStrobeDelayIdx) { + if (delay >= min_strobe_delay_idx_ && delay < max_strobe_delay_idx_) { // The value at be added to the SAI - float sig = pSigIn->getSample(iCurrentSample, audCh); + float sig = input.sample(ch, i); // Weight the sample correctly - sig *= pActiveStrobes->getWorkingWeight(si); + sig *= active_strobes.Strobe(si).working_weight; // Adjust the weight acording to the number of samples until the // next output frame - sig *= fDecayFactor; + sig *= decay_factor; // Update the temporary SAI buffer - pSigOut->setSample(iDelay, audCh, - pSigOut->getSample(iDelay, audCh)+sig); + output_.set_sample(ch, delay, output_.sample(ch, delay) + sig); } } - m_pNextStrobes[bankCh]=iNextStrobe; + next_strobes_[ch] = next_strobe_index; } // End loop over channels + fire_counter_--; - //Check to see if we need to output an SAI frame this sample - if (m_iFireCounter-- == 0) { + // Check to see if we need to output an SAI frame on this sample + if (fire_counter_ <= 0) { // Decay the SAI by the correct amount and add the current output frame - float decay = pow(sai_decay_factor_, fire_period_samples_); + float decay = pow(sai_decay_factor_, frame_period_samples_); - for (c = 0; c < input.channel_count(); ++c) { + for (int ch = 0; ch < input.channel_count(); ++ch) { for (int i = 0; i < output_.buffer_length(); ++i) { - output_.set_sample(c, i, sai_temp_[c][i] + output_[c][i] * decay); + output_.set_sample(ch, i, + sai_temp_[ch][i] + output_[ch][i] * decay); } } @@ -248,10 +236,10 @@ } } - m_iFireCounter=m_iFirePeriodSamples-1; + fire_counter_ = frame_period_samples_ - 1; - // Make sure the start time is transferred to the output - m_pOutputData->setStartTime(m_pInputData->getSignal(0)->getStartTime()+(SIGNAL_SAMPLE)((float)iCurrentSample*1000.0f/(float)m_pInputData->getSamplerate())); + // Transfer the current time to the output buffer + output_.set_start_time(input.start_time() + i); PushOutput(); } } // End loop over samples @@ -259,3 +247,4 @@ ModuleSAI::~ModuleSAI() { } +} // namespace aimc