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

Unified Diff: webrtc/modules/audio_processing/test/py_quality_assessment/quality_assessment/noise_generation.py

Issue 2715233003: APM Quality Generator, noise generator and evaluation score workers factory + echo noise generator (Closed)
Patch Set: Noise generation and evaluation score workers now instantiated through factory objects, class decor… Created 3 years, 9 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 side-by-side diff with in-line comments
Download patch
Index: webrtc/modules/audio_processing/test/py_quality_assessment/quality_assessment/noise_generation.py
diff --git a/webrtc/modules/audio_processing/test/py_quality_assessment/quality_assessment/noise_generation.py b/webrtc/modules/audio_processing/test/py_quality_assessment/quality_assessment/noise_generation.py
index 6d2f6e99e21e135210121a70bb0634451ca17ad0..fa6d6ada1cc048c99023f57e90f22dd2da20f550 100644
--- a/webrtc/modules/audio_processing/test/py_quality_assessment/quality_assessment/noise_generation.py
+++ b/webrtc/modules/audio_processing/test/py_quality_assessment/quality_assessment/noise_generation.py
@@ -9,8 +9,10 @@
import logging
import os
+import scipy.io
kjellander_webrtc 2017/03/09 07:49:31 This is not part of the standard library. Is it po
AleBzk 2017/03/09 11:31:20 True. And in another file I also use another 3rd p
kjellander_webrtc 2017/03/09 14:05:42 This is fine. If this never is going to run on any
+
from . import data_access
-from .signal_processing import SignalProcessingUtils
+from . import signal_processing
class NoiseGenerator(object):
"""Abstract class responsible for the generation of noisy signals.
@@ -45,6 +47,7 @@ class NoiseGenerator(object):
NoiseGenerator.
"""
cls.REGISTERED_CLASSES[class_to_register.NAME] = class_to_register
+ return class_to_register
AleBzk 2017/03/06 11:29:53 Bug fix: the class decorator MUST return the class
@property
def config_names(self):
@@ -175,12 +178,16 @@ class WhiteNoiseGenerator(NoiseGenerator):
def _generate(
self, input_signal_filepath, input_noise_cache_path, base_output_path):
# Load the input signal.
- input_signal = SignalProcessingUtils.load_wav(input_signal_filepath)
- input_signal = SignalProcessingUtils.normalize(input_signal)
+ input_signal = signal_processing.SignalProcessingUtils.load_wav(
+ input_signal_filepath)
+ input_signal = signal_processing.SignalProcessingUtils.normalize(
+ input_signal)
# Create the noise track.
- noise_signal = SignalProcessingUtils.generate_white_noise(input_signal)
- noise_signal = SignalProcessingUtils.normalize(noise_signal)
+ noise_signal = signal_processing.SignalProcessingUtils.generate_white_noise(
+ input_signal)
+ noise_signal = signal_processing.SignalProcessingUtils.normalize(
+ noise_signal)
# Create the noisy mixes (once for each unique SNR value).
noisy_mix_filepaths = {}
@@ -193,11 +200,12 @@ class WhiteNoiseGenerator(NoiseGenerator):
# Create and save if not done.
if not os.path.exists(noisy_signal_filepath):
# Create noisy signal.
- noisy_signal = SignalProcessingUtils.mix_signals(
+ noisy_signal = signal_processing.SignalProcessingUtils.mix_signals(
noise_signal, input_signal, snr)
# Save.
- SignalProcessingUtils.save_wav(noisy_signal_filepath, noisy_signal)
+ signal_processing.SignalProcessingUtils.save_wav(
+ noisy_signal_filepath, noisy_signal)
# Add file to the collection of mixes.
noisy_mix_filepaths[snr] = noisy_signal_filepath
@@ -245,6 +253,7 @@ class EnvironmentalNoiseGenerator(NoiseGenerator):
os.path.dirname(os.path.realpath(__file__)), 'noise_tracks')
# TODO(alessiob): allow the user to have custom noise tracks.
+ # TODO(alessiob): exploit NoiseGeneratorFactory.GetInstance().
_NOISE_TRACKS = [
'city.wav'
]
@@ -271,8 +280,10 @@ class EnvironmentalNoiseGenerator(NoiseGenerator):
snr_values = set([snr for pair in self._SNR_VALUE_PAIRS for snr in pair])
# Load the input signal.
- input_signal = SignalProcessingUtils.load_wav(input_signal_filepath)
- input_signal = SignalProcessingUtils.normalize(input_signal)
+ input_signal = signal_processing.SignalProcessingUtils.load_wav(
+ input_signal_filepath)
+ input_signal = signal_processing.SignalProcessingUtils.normalize(
+ input_signal)
noisy_mix_filepaths = {}
for noise_track_filename in self._NOISE_TRACKS:
@@ -283,8 +294,10 @@ class EnvironmentalNoiseGenerator(NoiseGenerator):
if not os.path.exists(noise_track_filepath):
logging.error('cannot find the <%s> noise track', noise_track_filename)
- noise_signal = SignalProcessingUtils.load_wav(noise_track_filepath)
- noise_signal = SignalProcessingUtils.normalize(noise_signal)
+ noise_signal = signal_processing.SignalProcessingUtils.load_wav(
+ noise_track_filepath)
+ noise_signal = signal_processing.SignalProcessingUtils.normalize(
+ noise_signal)
# Create the noisy mixes (once for each unique SNR value).
noisy_mix_filepaths[noise_track_name] = {}
@@ -296,11 +309,12 @@ class EnvironmentalNoiseGenerator(NoiseGenerator):
# Create and save if not done.
if not os.path.exists(noisy_signal_filepath):
# Create noisy signal.
- noisy_signal = SignalProcessingUtils.mix_signals(
+ noisy_signal = signal_processing.SignalProcessingUtils.mix_signals(
noise_signal, input_signal, snr)
# Save.
- SignalProcessingUtils.save_wav(noisy_signal_filepath, noisy_signal)
+ signal_processing.SignalProcessingUtils.save_wav(
+ noisy_signal_filepath, noisy_signal)
# Add file to the collection of mixes.
noisy_mix_filepaths[noise_track_name][snr] = noisy_signal_filepath
@@ -310,8 +324,7 @@ class EnvironmentalNoiseGenerator(NoiseGenerator):
base_output_path, noisy_mix_filepaths, self._SNR_VALUE_PAIRS)
-# TODO(alessiob): remove comment when class implemented.
-# @NoiseGenerator.register_class
+@NoiseGenerator.register_class
class EchoNoiseGenerator(NoiseGenerator):
"""
Echo noise generator.
@@ -319,10 +332,105 @@ class EchoNoiseGenerator(NoiseGenerator):
NAME = 'echo'
- def __init__(self):
+ _IMPULSE_RESPONSES = {
kjellander_webrtc 2017/03/09 07:49:31 I know nothing about the signal processing involve
AleBzk 2017/03/09 11:31:20 Yup
+ 'lecture': 'air_binaural_lecture_0_0_1.mat', # Long echo.
+ 'booth': 'air_binaural_booth_0_0_1.mat', # Short echo.
+ }
+ _MAX_IMPULSE_RESPONSE_LENGTH = None
+
+ # Each pair indicates the clean vs. noisy and reference vs. noisy SNRs.
+ # Since the implementation below only changes the gain of the noise, the
+ # values indicate the noise-to-signal ratio. Therefore a higher value means
+ # larger amount of noise.
+ # The reference (second value of each pair) always has a lower amount of noise
+ # - i.e., the SNR is 5 dB higher.
+ _SNR_VALUE_PAIRS = [
+ [3, -2], # Largest noise.
+ [-3, -8],
+ ]
+
+ _NOISE_TRACK_FILENAME_TEMPLATE = '{0}.wav'
+ _NOISY_SIGNAL_FILENAME_TEMPLATE = '{0}_{1:d}_SNR.wav'
+
+ def __init__(self, aechen_ir_database_path):
NoiseGenerator.__init__(self)
+ self._aechen_ir_database_path = aechen_ir_database_path
AleBzk 2017/03/06 11:29:53 @kjellander: the same comment I got from you about
def _generate(
kjellander_webrtc 2017/03/09 07:49:31 Add docstring
AleBzk 2017/03/09 11:31:19 Done.
self, input_signal_filepath, input_noise_cache_path, base_output_path):
- # TODO(alessiob): implement.
- pass
+ # Init.
+ snr_values = set([snr for pair in self._SNR_VALUE_PAIRS for snr in pair])
+
+ # Load the input signal.
+ input_signal = signal_processing.SignalProcessingUtils.load_wav(
+ input_signal_filepath)
+
+ noisy_mix_filepaths = {}
+ for impulse_response_name in self._IMPULSE_RESPONSES:
+ noise_track_filename = self._NOISE_TRACK_FILENAME_TEMPLATE.format(
+ impulse_response_name)
+ noise_track_filepath = os.path.join(
+ input_noise_cache_path, noise_track_filename)
+ noise_signal = None
+ try:
+ # Load noise track.
+ noise_signal = signal_processing.SignalProcessingUtils.load_wav(
+ noise_track_filepath)
+ except IOError: # File not found.
+ # Generate noise track by applying the impulse response.
+ impulse_response_filepath = os.path.join(
+ self._aechen_ir_database_path,
+ self._IMPULSE_RESPONSES[impulse_response_name])
+ noise_signal = self._generate_noise_track(
+ noise_track_filepath, input_signal, impulse_response_filepath)
+ assert noise_signal is not None
+
+ # Create the noisy mixes (once for each unique SNR value).
+ noisy_mix_filepaths[impulse_response_name] = {}
+ for snr in snr_values:
+ noisy_signal_filepath = os.path.join(
+ input_noise_cache_path,
+ self._NOISY_SIGNAL_FILENAME_TEMPLATE.format(
+ impulse_response_name, snr))
+
+ # Create and save if not done.
+ if not os.path.exists(noisy_signal_filepath):
+ # Create noisy signal.
+ noisy_signal = signal_processing.SignalProcessingUtils.mix_signals(
+ noise_signal, input_signal, snr, bln_pad_shortest=True)
+
+ # Save.
+ signal_processing.SignalProcessingUtils.save_wav(
+ noisy_signal_filepath, noisy_signal)
+
+ # Add file to the collection of mixes.
+ noisy_mix_filepaths[impulse_response_name][snr] = noisy_signal_filepath
+
+ # Add all the noise-SNR pairs.
+ self._add_noise_snr_pairs(base_output_path, noisy_mix_filepaths,
+ self._SNR_VALUE_PAIRS)
+
+ def _generate_noise_track(self, noise_track_filepath, input_signal,
+ impulse_response_filepath):
+ """
+ Generate a signal by convolving input_signal with the impulse response in
+ impulse_response_filepath; then save to noise_track_filepath.
kjellander_webrtc 2017/03/09 07:49:31 Add docstring for arguments
AleBzk 2017/03/09 11:31:20 Done.
+ """
+ # Load impulse response.
+ data = scipy.io.loadmat(impulse_response_filepath)
+ impulse_response = data['h_air'].flatten()
+ if self._MAX_IMPULSE_RESPONSE_LENGTH is not None:
+ logging.info('truncating impulse response from %d to %d samples',
+ len(impulse_response), self._MAX_IMPULSE_RESPONSE_LENGTH)
+ impulse_response = impulse_response[:self._MAX_IMPULSE_RESPONSE_LENGTH]
+
+ # Apply impulse response.
+ processed_signal = (
+ signal_processing.SignalProcessingUtils.apply_impulse_response(
+ input_signal, impulse_response))
+
+ # Save.
+ signal_processing.SignalProcessingUtils.save_wav(
+ noise_track_filepath, processed_signal)
+
+ return processed_signal

Powered by Google App Engine
This is Rietveld 408576698