Index: webrtc/modules/audio_processing/test/py_quality_assessment/quality_assessment/echo_path_simulation.py |
diff --git a/webrtc/modules/audio_processing/test/py_quality_assessment/quality_assessment/echo_path_simulation.py b/webrtc/modules/audio_processing/test/py_quality_assessment/quality_assessment/echo_path_simulation.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..a1621966fe78b7c38472ebed25cc052a5be29978 |
--- /dev/null |
+++ b/webrtc/modules/audio_processing/test/py_quality_assessment/quality_assessment/echo_path_simulation.py |
@@ -0,0 +1,136 @@ |
+# Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. |
+# |
+# Use of this source code is governed by a BSD-style license |
+# that can be found in the LICENSE file in the root of the source |
+# tree. An additional intellectual property rights grant can be found |
+# in the file PATENTS. All contributing project authors may |
+# be found in the AUTHORS file in the root of the source tree. |
+ |
+"""Echo path simulation module. |
+""" |
+ |
+import hashlib |
+import os |
+ |
+from . import signal_processing |
+ |
+ |
+class EchoPathSimulator(object): |
+ """Abstract class for the echo path simulators. |
+ |
+ In general, an echo path simulator is a function of the render signal and |
+ simulates the propagation of the latter into the microphone (e.g., due to |
+ mechanical or electrical paths). |
+ """ |
+ |
+ NAME = None |
+ REGISTERED_CLASSES = {} |
+ |
+ def __init__(self): |
+ pass |
+ |
+ def Simulate(self, output_path): |
+ """Creates the echo signal and stores it in an audio file (abstract method). |
+ |
+ Args: |
+ output_path: Path in which any output can be saved. |
+ |
+ Returns: |
+ Path to the generated audio track file or None if no echo is present. |
+ """ |
+ raise NotImplementedError() |
+ |
+ @classmethod |
+ def RegisterClass(cls, class_to_register): |
+ """Registers an EchoPathSimulator implementation. |
+ |
+ Decorator to automatically register the classes that extend |
+ EchoPathSimulator. |
+ Example usage: |
+ |
+ @EchoPathSimulator.RegisterClass |
+ class NoEchoPathSimulator(EchoPathSimulator): |
+ pass |
+ """ |
+ cls.REGISTERED_CLASSES[class_to_register.NAME] = class_to_register |
+ return class_to_register |
+ |
+ |
+@EchoPathSimulator.RegisterClass |
+class NoEchoPathSimulator(EchoPathSimulator): |
+ """Simulates absence of echo.""" |
+ |
+ NAME = 'noecho' |
+ |
+ def __init__(self): |
+ EchoPathSimulator.__init__(self) |
+ |
+ def Simulate(self, output_path): |
+ return None |
+ |
+ |
+@EchoPathSimulator.RegisterClass |
+class LinearEchoPathSimulator(EchoPathSimulator): |
+ """Simulates linear echo path. |
+ |
+ This class applies a given impulse response to the render input and then it |
+ sums the signal to the capture input signal. |
+ """ |
+ |
+ NAME = 'linear' |
+ |
+ def __init__(self, render_input_filepath, impulse_response): |
+ """ |
+ Args: |
+ render_input_filepath: Render audio track file. |
+ impulse_response: list or numpy vector of float values. |
+ """ |
+ EchoPathSimulator.__init__(self) |
+ self._render_input_filepath = render_input_filepath |
+ self._impulse_response = impulse_response |
+ |
+ def Simulate(self, output_path): |
+ """Simulates linear echo path.""" |
+ # Form the file name with a hash of the impulse response. |
+ impulse_response_hash = hashlib.sha256( |
+ str(self._impulse_response).encode('utf-8', 'ignore')).hexdigest() |
+ echo_filepath = os.path.join(output_path, 'linear_echo_{}.wav'.format( |
+ impulse_response_hash)) |
+ |
+ # If the simulated echo audio track file does not exists, create it. |
+ if not os.path.exists(echo_filepath): |
+ render = signal_processing.SignalProcessingUtils.LoadWav( |
+ self._render_input_filepath) |
+ echo = signal_processing.SignalProcessingUtils.ApplyImpulseResponse( |
+ render, self._impulse_response) |
+ signal_processing.SignalProcessingUtils.SaveWav(echo_filepath, echo) |
+ |
+ return echo_filepath |
+ |
+ |
+@EchoPathSimulator.RegisterClass |
+class RecordedEchoPathSimulator(EchoPathSimulator): |
+ """Uses recorded echo. |
+ |
+ This class uses the clean capture input file name to build the file name of |
+ the corresponding recording containing echo (a predefined suffix is used). |
+ Such a file is expected to be already existing. |
+ """ |
+ |
+ NAME = 'recorded' |
+ |
+ _FILE_NAME_SUFFIX = '_echo' |
+ |
+ def __init__(self, render_input_filepath): |
+ EchoPathSimulator.__init__(self) |
+ self._render_input_filepath = render_input_filepath |
+ |
+ def Simulate(self, output_path): |
+ """Uses recorded echo path.""" |
+ path, file_name_ext = os.path.split(self._render_input_filepath) |
+ file_name, file_ext = os.path.splitext(file_name_ext) |
+ echo_filepath = os.path.join(path, '{}{}{}'.format( |
+ file_name, self._FILE_NAME_SUFFIX, file_ext)) |
+ assert os.path.exists(echo_filepath), ( |
+ 'cannot find the echo audio track file {}'.format(echo_filepath)) |
+ return echo_filepath |