| 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
|
|
|