OLD | NEW |
---|---|
(Empty) | |
1 /* | |
2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. | |
3 * | |
4 * Use of this source code is governed by a BSD-style license | |
5 * that can be found in the LICENSE file in the root of the source | |
6 * tree. An additional intellectual property rights grant can be found | |
7 * in the file PATENTS. All contributing project authors may | |
8 * be found in the AUTHORS file in the root of the source tree. | |
9 */ | |
10 | |
11 #include "webrtc/modules/audio_processing/repetition_detector.h" | |
12 | |
13 #include "webrtc/base/checks.h" | |
14 #include "webrtc/base/safe_conversions.h" | |
15 | |
16 namespace webrtc { | |
17 | |
18 namespace { | |
19 static const RepetitionDetector::Pattern kRepetitionPatterns[] = { | |
20 // {id_, look_back_, length_} | |
21 {0, 10, 10}, | |
22 {1, 100, 100} | |
23 }; | |
24 } | |
25 | |
26 RepetitionDetector::State::State(int id, int look_back_ms, int min_length_ms) | |
27 : id_(id), | |
28 look_back_ms_(look_back_ms), | |
29 min_length_ms_(min_length_ms) { | |
30 Reset(); | |
31 } | |
32 | |
33 void RepetitionDetector::State::Increment(bool zero) { | |
34 if (0 == count_samples_ && zero) { | |
35 all_zero_ = true; | |
36 } | |
37 ++count_samples_; | |
38 if (!zero) { | |
39 all_zero_ = false; | |
40 } | |
41 } | |
42 | |
43 bool RepetitionDetector::State::HasValidReport(int sample_rate_hz) const { | |
44 return (!all_zero_ && count_samples_ >= | |
45 rtc::checked_cast<size_t>(min_length_ms_ * sample_rate_hz / 1000)); | |
46 } | |
47 | |
48 void RepetitionDetector::State::Reset() { | |
49 count_samples_ = 0; | |
50 all_zero_ = true; | |
51 reported_ = false; | |
52 } | |
53 | |
54 RepetitionDetector::RepetitionDetector() | |
55 : max_look_back_ms_(0), | |
56 sample_rate_hz_(0), | |
57 buffer_size_samples_(0), | |
58 buffer_end_index_(0) { | |
59 RegisterRepetitionPatterns(kRepetitionPatterns, | |
60 sizeof(kRepetitionPatterns) / sizeof (Pattern)); | |
61 } | |
62 | |
63 void RepetitionDetector::RegisterRepetitionPatterns(const Pattern* patterns, | |
64 size_t num_patterns) { | |
65 Pattern pattern; | |
66 for (size_t idx = 0; idx < num_patterns; idx++) { | |
67 pattern = patterns[idx]; | |
68 states_.push_back(new State(pattern.id_, pattern.look_back_ms_, | |
69 pattern.min_length_ms_)); | |
70 if (pattern.look_back_ms_ > max_look_back_ms_) { | |
71 max_look_back_ms_ = pattern.look_back_ms_; | |
72 } | |
73 } | |
74 } | |
75 | |
76 void RepetitionDetector::Reset(size_t num_channels, int sample_rate_hz) { | |
Andrew MacDonald
2015/09/07 06:52:18
Do you need this? Why not have users just create a
minyue-webrtc
2015/09/07 07:33:24
This is needed when the num_channels, or sampling
Andrew MacDonald
2015/09/07 22:52:19
The other solution is to have clients recreate it
minyue-webrtc
2015/09/11 14:01:41
I prefer that RepetitionDetector takes care of tha
| |
77 num_channels_ = num_channels; | |
78 sample_rate_hz_ = sample_rate_hz; | |
79 int sample_1k = max_look_back_ms_ * sample_rate_hz_; | |
80 buffer_size_samples_ = sample_1k / 1000 + (sample_1k % 1000 != 0); | |
81 audio_buffer_.reset(new float[buffer_size_samples_ * num_channels_]()); | |
82 for (auto state : states_) { | |
83 state->Reset(); | |
84 } | |
85 } | |
86 | |
87 void RepetitionDetector::AddSampleToBuffer(const float* sample) { | |
88 float* ref = &audio_buffer_[buffer_end_index_ * num_channels_]; | |
89 for (size_t cdx = 0; cdx < num_channels_; ++cdx, ++ref, ++sample) { | |
Andrew MacDonald
2015/09/07 06:52:18
memcpy? (or even better, std::copy)
Might not be
minyue-webrtc
2015/09/07 07:33:24
I also thought about adding data chunks. It is tri
| |
90 *ref = *sample; | |
91 } | |
92 buffer_end_index_++; | |
93 if (buffer_end_index_ == buffer_size_samples_) { | |
94 buffer_end_index_ = 0; | |
95 } | |
96 } | |
97 | |
98 bool RepetitionDetector::Equal(const float* sample, | |
99 int look_back_samples) const { | |
100 const size_t look_back_index = | |
101 (buffer_end_index_ + buffer_size_samples_ - look_back_samples) % | |
102 buffer_size_samples_ ; | |
103 const float* ref = &audio_buffer_[look_back_index * num_channels_]; | |
104 for (size_t cdx = 0; cdx < num_channels_; ++cdx, ++ref, ++sample) { | |
105 if (*sample != *ref) { | |
Andrew MacDonald
2015/09/07 06:52:18
I thought you were worried about exact floating po
minyue-webrtc
2015/09/07 07:33:24
I want to check bit exact equality, and with curre
| |
106 return false; | |
107 } | |
108 } | |
109 return true; | |
110 } | |
111 | |
112 bool RepetitionDetector::IsZero(const float* sample) const { | |
113 for (size_t cdx = 0; cdx < num_channels_; ++cdx, ++sample) { | |
114 if (*sample != 0) { | |
115 return false; | |
116 } | |
117 } | |
118 return true; | |
119 } | |
120 | |
121 void RepetitionDetector::Detect(const float* data, size_t num_frames, | |
122 size_t num_channels, int sample_rate_hz) { | |
123 DCHECK_GT(states_.size(), 0ul); | |
124 if (num_channels != num_channels_ || sample_rate_hz != sample_rate_hz_) { | |
125 Reset(num_channels, sample_rate_hz); | |
126 } | |
127 | |
128 for (size_t idx = 0; idx < num_frames; ++idx, data += num_channels) { | |
129 for (auto state : states_) { | |
130 const size_t look_back_samples = | |
131 rtc::CheckedDivExact(state->look_back_ms() * sample_rate_hz_, 1000); | |
132 if (Equal(data, look_back_samples)) { | |
133 if (!state->reported()) { | |
134 state->Increment(IsZero(data)); | |
135 if (state->HasValidReport(sample_rate_hz)) { | |
136 ReportRepetition(state->id()); | |
137 state->set_reported(true); | |
138 } | |
139 } | |
140 } else { | |
141 state->Reset(); | |
142 } | |
143 } | |
144 AddSampleToBuffer(data); | |
145 } | |
146 } | |
147 | |
148 } // namespace webrtc | |
OLD | NEW |