tomwalters@5
|
1 // Copyright 2007-2010, Thomas Walters
|
tomwalters@5
|
2 //
|
tomwalters@5
|
3 // AIM-C: A C++ implementation of the Auditory Image Model
|
tomwalters@5
|
4 // http://www.acousticscale.org/AIMC
|
tomwalters@5
|
5 //
|
tomwalters@5
|
6 // This program is free software: you can redistribute it and/or modify
|
tomwalters@5
|
7 // it under the terms of the GNU General Public License as published by
|
tomwalters@5
|
8 // the Free Software Foundation, either version 3 of the License, or
|
tomwalters@5
|
9 // (at your option) any later version.
|
tomwalters@5
|
10 //
|
tomwalters@5
|
11 // This program is distributed in the hope that it will be useful,
|
tomwalters@5
|
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
|
tomwalters@5
|
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
tomwalters@5
|
14 // GNU General Public License for more details.
|
tomwalters@5
|
15 //
|
tomwalters@5
|
16 // You should have received a copy of the GNU General Public License
|
tomwalters@5
|
17 // along with this program. If not, see <http://www.gnu.org/licenses/>.
|
tomwalters@5
|
18
|
tomwalters@5
|
19 /*!
|
tomwalters@5
|
20 * \file
|
tomwalters@5
|
21 * \brief Parabola strobe detection module - Using the 'parabloa' strobe
|
tomwalters@5
|
22 * criterion from the AIM-MAT sf2003 module
|
tomwalters@5
|
23 *
|
tomwalters@11
|
24 * \author Thomas Walters <tom@acousticscale.org>
|
tomwalters@5
|
25 * \date created 2007/08/01
|
tomwalters@23
|
26 * \version \$Id$
|
tomwalters@5
|
27 */
|
tomwalters@5
|
28
|
tomwalters@21
|
29 #include <limits.h>
|
tomwalters@15
|
30 #include <cmath>
|
tomwalters@5
|
31
|
tomwalters@5
|
32 #include "Modules/Strobes/ModuleParabola.h"
|
tomwalters@5
|
33
|
tomwalters@5
|
34 namespace aimc {
|
tomwalters@5
|
35 ModuleParabola::ModuleParabola(Parameters *params) : Module(params) {
|
tomwalters@5
|
36 module_description_ = "sf2003 parabola algorithm";
|
tomwalters@5
|
37 module_identifier_ = "parabola";
|
tomwalters@5
|
38 module_type_ = "strobes";
|
tomwalters@5
|
39 module_version_ = "$Id$";
|
tomwalters@5
|
40
|
tomwalters@5
|
41 // Get data from parameters
|
tomwalters@5
|
42 height_ = parameters_->DefaultFloat("parabola.height", 1.2f);
|
tomwalters@5
|
43 parabw_ = parameters_->DefaultFloat("parabola.width_cycles", 1.5f);
|
tomwalters@5
|
44 strobe_decay_time_ = parameters_->DefaultFloat("parabla.strobe_decay_time",
|
tomwalters@5
|
45 0.02f);
|
tomwalters@5
|
46 channel_count_ = 0;
|
tomwalters@5
|
47 }
|
tomwalters@5
|
48
|
tomwalters@5
|
49 bool ModuleParabola::InitializeInternal(const SignalBank &input) {
|
tomwalters@5
|
50 output_.Initialize(input);
|
tomwalters@5
|
51 channel_count_ = input.channel_count();
|
tomwalters@5
|
52 sample_rate_ = input.sample_rate();
|
tomwalters@5
|
53
|
tomwalters@5
|
54 // Parameters for the parabola
|
tomwalters@5
|
55 parab_a_.resize(channel_count_);
|
tomwalters@5
|
56 parab_b_.resize(channel_count_);
|
tomwalters@5
|
57 parab_wnull_.resize(channel_count_);
|
tomwalters@5
|
58 parab_var_samples_.resize(channel_count_);
|
tomwalters@5
|
59
|
tomwalters@5
|
60 for (int ch = 0; ch < channel_count_; ++ch) {
|
tomwalters@5
|
61 parab_wnull_[ch] = parabw_ / input.centre_frequency(ch);
|
tomwalters@5
|
62 parab_var_samples_[ch] = floor(parab_wnull_[ch] * sample_rate_);
|
tomwalters@5
|
63 parab_a_[ch] = 4.0f * (1.0f - height_)
|
tomwalters@5
|
64 / (parab_wnull_[ch] * parab_wnull_[ch]);
|
tomwalters@5
|
65 parab_b_[ch] = -parab_wnull_[ch] / 2.0f;
|
tomwalters@5
|
66 }
|
tomwalters@5
|
67
|
tomwalters@5
|
68 // Number of samples over which the threshold should decay
|
tomwalters@5
|
69 strobe_decay_samples_ = floor(sample_rate_ * strobe_decay_time_);
|
tomwalters@5
|
70
|
tomwalters@5
|
71 // Prepare internal buffers
|
tomwalters@5
|
72 ResetInternal();
|
tomwalters@5
|
73
|
tomwalters@5
|
74 return true;
|
tomwalters@5
|
75 }
|
tomwalters@5
|
76
|
tomwalters@5
|
77 void ModuleParabola::ResetInternal() {
|
tomwalters@32
|
78 threshold_.clear();
|
tomwalters@5
|
79 threshold_.resize(channel_count_, 0.0f);
|
tomwalters@32
|
80 last_threshold_.clear();
|
tomwalters@5
|
81 last_threshold_.resize(channel_count_, 0.0f);
|
tomwalters@32
|
82 samples_since_last_strobe_.clear();
|
tomwalters@5
|
83 samples_since_last_strobe_.resize(channel_count_, 0);
|
tomwalters@5
|
84
|
tomwalters@32
|
85 prev_sample_.clear();
|
tomwalters@5
|
86 prev_sample_.resize(channel_count_, 10000.0f);
|
tomwalters@32
|
87 curr_sample_.clear();
|
tomwalters@5
|
88 curr_sample_.resize(channel_count_, 5000.0f);
|
tomwalters@32
|
89 next_sample_.clear();
|
tomwalters@5
|
90 next_sample_.resize(channel_count_, 0.0f);
|
tomwalters@5
|
91 }
|
tomwalters@5
|
92
|
tomwalters@5
|
93 void ModuleParabola::Process(const SignalBank &input) {
|
tomwalters@5
|
94 float decay_constant;
|
tomwalters@5
|
95
|
tomwalters@5
|
96 for (int ch = 0; ch < output_.channel_count(); ch++) {
|
tomwalters@5
|
97 output_.ResetStrobes(ch);
|
tomwalters@5
|
98 }
|
tomwalters@5
|
99 output_.set_start_time(input.start_time());
|
tomwalters@5
|
100
|
tomwalters@5
|
101 // Loop across samples first, then channels
|
tomwalters@5
|
102 for (int i = 0; i < input.buffer_length(); i++) {
|
tomwalters@5
|
103 // Find strobes in each channel first
|
tomwalters@5
|
104 for (int ch = 0; ch < input.channel_count(); ++ch) {
|
tomwalters@5
|
105 // Shift all the samples by one
|
tomwalters@5
|
106 // curr_sample is the sample at time (i - 1)
|
tomwalters@5
|
107 prev_sample_[ch] = curr_sample_[ch];
|
tomwalters@5
|
108 curr_sample_[ch] = next_sample_[ch];
|
tomwalters@5
|
109 next_sample_[ch] = input.sample(ch, i);
|
tomwalters@5
|
110
|
tomwalters@5
|
111 // Copy input signal to output signal
|
tomwalters@5
|
112 output_.set_sample(ch, i, input.sample(ch, i));
|
tomwalters@5
|
113
|
tomwalters@7
|
114 if (curr_sample_[ch] >= threshold_[ch]) {
|
tomwalters@7
|
115 threshold_[ch] = curr_sample_[ch];
|
tomwalters@7
|
116 if (prev_sample_[ch] < curr_sample_[ch]
|
tomwalters@7
|
117 && next_sample_[ch] < curr_sample_[ch]) {
|
tomwalters@7
|
118 // We have a strobe: set threshold and add strobe to the list
|
tomwalters@7
|
119 output_.AddStrobe(ch, i - 1);
|
tomwalters@7
|
120 last_threshold_[ch] = threshold_[ch];
|
tomwalters@7
|
121 parab_var_samples_[ch] =
|
tomwalters@7
|
122 floor(input.sample_rate()
|
tomwalters@7
|
123 * (parab_wnull_[ch] - (threshold_[ch]
|
tomwalters@7
|
124 - 2.0f * parab_a_[ch] *parab_b_[ch])
|
tomwalters@7
|
125 / (2.0f * parab_a_[ch])));
|
tomwalters@7
|
126 }
|
tomwalters@5
|
127 }
|
tomwalters@7
|
128 if (output_.strobe_count(ch) > 0) {
|
tomwalters@5
|
129 samples_since_last_strobe_[ch] = (i - 1)
|
tomwalters@5
|
130 - output_.strobe(ch, output_.strobe_count(ch) - 1);
|
tomwalters@5
|
131 } else {
|
tomwalters@7
|
132 samples_since_last_strobe_[ch] = UINT_MAX;
|
tomwalters@5
|
133 }
|
tomwalters@5
|
134
|
tomwalters@7
|
135 if (samples_since_last_strobe_[ch] > parab_var_samples_[ch]) {
|
tomwalters@7
|
136 decay_constant = last_threshold_[ch] / strobe_decay_samples_;
|
tomwalters@7
|
137 if (threshold_[ch] > decay_constant)
|
tomwalters@7
|
138 threshold_[ch] -= decay_constant;
|
tomwalters@7
|
139 else
|
tomwalters@7
|
140 threshold_[ch] = 0.0f;
|
tomwalters@5
|
141 } else {
|
tomwalters@7
|
142 threshold_[ch] = last_threshold_[ch]
|
tomwalters@7
|
143 * (parab_a_[ch] * pow((samples_since_last_strobe_[ch]
|
tomwalters@7
|
144 / input.sample_rate() + parab_b_[ch]),
|
tomwalters@7
|
145 2.0f) + height_);
|
tomwalters@5
|
146 }
|
tomwalters@5
|
147 }
|
tomwalters@5
|
148 }
|
tomwalters@5
|
149
|
tomwalters@5
|
150 PushOutput();
|
tomwalters@5
|
151 }
|
tomwalters@5
|
152
|
tomwalters@5
|
153
|
tomwalters@5
|
154
|
tomwalters@5
|
155 ModuleParabola::~ModuleParabola() {
|
tomwalters@5
|
156 }
|
tomwalters@5
|
157 } // namespace aimc
|