OLD | NEW |
1 # Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. | 1 # Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. |
2 # | 2 # |
3 # Use of this source code is governed by a BSD-style license | 3 # Use of this source code is governed by a BSD-style license |
4 # that can be found in the LICENSE file in the root of the source | 4 # that can be found in the LICENSE file in the root of the source |
5 # tree. An additional intellectual property rights grant can be found | 5 # tree. An additional intellectual property rights grant can be found |
6 # in the file PATENTS. All contributing project authors may | 6 # in the file PATENTS. All contributing project authors may |
7 # be found in the AUTHORS file in the root of the source tree. | 7 # be found in the AUTHORS file in the root of the source tree. |
8 | 8 |
9 """Signal processing utility module. | 9 """Signal processing utility module. |
10 """ | 10 """ |
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
142 AudioSegment instance. | 142 AudioSegment instance. |
143 """ | 143 """ |
144 generator = pydub.generators.WhiteNoise( | 144 generator = pydub.generators.WhiteNoise( |
145 sample_rate=template.frame_rate, | 145 sample_rate=template.frame_rate, |
146 bit_depth=template.sample_width * 8) | 146 bit_depth=template.sample_width * 8) |
147 return generator.to_audio_segment( | 147 return generator.to_audio_segment( |
148 duration=len(template), | 148 duration=len(template), |
149 volume=0.0) | 149 volume=0.0) |
150 | 150 |
151 @classmethod | 151 @classmethod |
| 152 def AudioSegmentToRawData(cls, signal): |
| 153 samples = signal.get_array_of_samples() |
| 154 if samples.typecode != 'h': |
| 155 raise exceptions.SignalProcessingException('Unsupported samples type') |
| 156 return np.array(signal.get_array_of_samples(), np.int16) |
| 157 |
| 158 @classmethod |
152 def DetectHardClipping(cls, signal, threshold=2): | 159 def DetectHardClipping(cls, signal, threshold=2): |
153 """Detects hard clipping. | 160 """Detects hard clipping. |
154 | 161 |
155 Hard clipping is simply detected by counting samples that touch either the | 162 Hard clipping is simply detected by counting samples that touch either the |
156 lower or upper bound too many times in a row (according to |threshold|). | 163 lower or upper bound too many times in a row (according to |threshold|). |
157 The presence of a single sequence of samples meeting such property is enough | 164 The presence of a single sequence of samples meeting such property is enough |
158 to label the signal as hard clipped. | 165 to label the signal as hard clipped. |
159 | 166 |
160 Args: | 167 Args: |
161 signal: AudioSegment instance. | 168 signal: AudioSegment instance. |
162 threshold: minimum number of samples at full-scale in a row. | 169 threshold: minimum number of samples at full-scale in a row. |
163 | 170 |
164 Returns: | 171 Returns: |
165 True if hard clipping is detect, False otherwise. | 172 True if hard clipping is detect, False otherwise. |
166 """ | 173 """ |
167 if signal.channels != 1: | 174 if signal.channels != 1: |
168 raise NotImplementedError('mutliple-channel clipping not implemented') | 175 raise NotImplementedError('mutliple-channel clipping not implemented') |
169 if signal.sample_width != 2: # Note that signal.sample_width is in bytes. | 176 if signal.sample_width != 2: # Note that signal.sample_width is in bytes. |
170 raise exceptions.SignalProcessingException( | 177 raise exceptions.SignalProcessingException( |
171 'hard-clipping detection only supported for 16 bit samples') | 178 'hard-clipping detection only supported for 16 bit samples') |
172 | 179 samples = cls.AudioSegmentToRawData(signal) |
173 # Get raw samples, check type, cast. | |
174 samples = signal.get_array_of_samples() | |
175 if samples.typecode != 'h': | |
176 raise exceptions.SignalProcessingException( | |
177 'hard-clipping detection only supported for 16 bit samples') | |
178 samples = np.array(signal.get_array_of_samples(), np.int16) | |
179 | 180 |
180 # Detect adjacent clipped samples. | 181 # Detect adjacent clipped samples. |
181 samples_type_info = np.iinfo(samples.dtype) | 182 samples_type_info = np.iinfo(samples.dtype) |
182 mask_min = samples == samples_type_info.min | 183 mask_min = samples == samples_type_info.min |
183 mask_max = samples == samples_type_info.max | 184 mask_max = samples == samples_type_info.max |
184 | 185 |
185 def HasLongSequence(vector, min_legth=threshold): | 186 def HasLongSequence(vector, min_legth=threshold): |
186 """Returns True if there are one or more long sequences of True flags.""" | 187 """Returns True if there are one or more long sequences of True flags.""" |
187 seq_length = 0 | 188 seq_length = 0 |
188 for b in vector: | 189 for b in vector: |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
327 logging.debug(' signal (pre): %d ms', len(signal)) | 328 logging.debug(' signal (pre): %d ms', len(signal)) |
328 signal = signal + padding | 329 signal = signal + padding |
329 logging.debug(' signal (post): %d ms', len(signal)) | 330 logging.debug(' signal (post): %d ms', len(signal)) |
330 | 331 |
331 # Update power. | 332 # Update power. |
332 signal_power = float(signal.dBFS) | 333 signal_power = float(signal.dBFS) |
333 | 334 |
334 # Mix signals using the target SNR. | 335 # Mix signals using the target SNR. |
335 gain_db = signal_power - noise_power - target_snr | 336 gain_db = signal_power - noise_power - target_snr |
336 return cls.Normalize(signal.overlay(noise.apply_gain(gain_db))) | 337 return cls.Normalize(signal.overlay(noise.apply_gain(gain_db))) |
OLD | NEW |