Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(114)

Side by Side Diff: modules/audio_processing/test/py_quality_assessment/quality_assessment/signal_processing.py

Issue 3010413002: Total Harmonic Distorsion plus noise (THD+n) score in APM-QA. (Closed)
Patch Set: merge Created 3 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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)))
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698