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

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

Issue 2813883002: APM QA refactoring: render stream support, echo path simulation, new export engine (Closed)
Patch Set: Merge + comments from Per addressed Created 3 years, 8 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 """APM module simulator. 9 """APM module simulator.
10 """ 10 """
11 11
12 import logging 12 import logging
13 import os 13 import os
14 14
15 from . import data_access 15 from . import data_access
16 from . import echo_path_simulation
16 from . import eval_scores 17 from . import eval_scores
17 from . import eval_scores_factory 18 from . import eval_scores_factory
18 from . import test_data_generation 19 from . import test_data_generation
19 from . import test_data_generation_factory 20 from . import test_data_generation_factory
20 21
21 22
22 class ApmModuleSimulator(object): 23 class ApmModuleSimulator(object):
23 """APM module simulator class. 24 """Audio processing module (APM) simulator class.
24 """ 25 """
25 26
26 _TEST_DATA_GENERATOR_CLASSES = ( 27 _TEST_DATA_GENERATOR_CLASSES = (
27 test_data_generation.TestDataGenerator.REGISTERED_CLASSES) 28 test_data_generation.TestDataGenerator.REGISTERED_CLASSES)
28 _EVAL_SCORE_WORKER_CLASSES = eval_scores.EvaluationScore.REGISTERED_CLASSES 29 _EVAL_SCORE_WORKER_CLASSES = eval_scores.EvaluationScore.REGISTERED_CLASSES
29 30
30 def __init__(self, aechen_ir_database_path, polqa_tool_bin_path, 31 def __init__(self, aechen_ir_database_path, polqa_tool_bin_path,
31 ap_wrapper, evaluator): 32 ap_wrapper, evaluator):
32 # Init. 33 # Init.
33 self._audioproc_wrapper = ap_wrapper 34 self._audioproc_wrapper = ap_wrapper
34 self._evaluator = evaluator 35 self._evaluator = evaluator
35 36
36 # Instance factory objects. 37 # Instance factory objects.
37 self._test_data_generator_factory = ( 38 self._test_data_generator_factory = (
38 test_data_generation_factory.TestDataGeneratorFactory( 39 test_data_generation_factory.TestDataGeneratorFactory(
39 aechen_ir_database_path=aechen_ir_database_path)) 40 aechen_ir_database_path=aechen_ir_database_path))
40 self._evaluation_score_factory = ( 41 self._evaluation_score_factory = (
41 eval_scores_factory.EvaluationScoreWorkerFactory( 42 eval_scores_factory.EvaluationScoreWorkerFactory(
42 polqa_tool_bin_path=polqa_tool_bin_path)) 43 polqa_tool_bin_path=polqa_tool_bin_path))
43 44
44 # Properties for each run. 45 # Properties for each run.
45 self._base_output_path = None 46 self._base_output_path = None
46 self._test_data_generators = None 47 self._test_data_generators = None
47 self._evaluation_score_workers = None 48 self._evaluation_score_workers = None
48 self._config_filepaths = None 49 self._config_filepaths = None
49 self._input_filepaths = None 50 self._capture_input_filepaths = None
51 self._render_input_filepaths = None
50 52
51 def Run(self, config_filepaths, input_filepaths, test_data_generator_names, 53 def Run(self, config_filepaths, capture_input_filepaths,
52 eval_score_names, output_dir): 54 test_data_generator_names, eval_score_names, output_dir,
55 render_input_filepaths=None, echo_path_simulator_name=None):
53 """Runs the APM simulation. 56 """Runs the APM simulation.
54 57
55 Initializes paths and required instances, then runs all the simulations. 58 Initializes paths and required instances, then runs all the simulations.
59 The render input can be optionally added. If added, the number of capture
60 input audio tracks and the number of render input audio tracks have to
61 equal. The two lists are used to form pairs of capture and render input.
peah-webrtc 2017/05/03 08:10:08 input->inputs
peah-webrtc 2017/05/03 08:10:08 be equal
56 62
57 Args: 63 Args:
58 config_filepaths: set of APM configuration files to test. 64 config_filepaths: set of APM configuration files to test.
59 input_filepaths: set of input audio track files to test. 65 capture_input_filepaths: set of capture input audio track files to test.
60 test_data_generator_names: set of test data generator names to test. 66 test_data_generator_names: set of test data generator names to test.
61 eval_score_names: set of evaluation score names to test. 67 eval_score_names: set of evaluation score names to test.
62 output_dir: base path to the output directory for wav files and outcomes. 68 output_dir: base path to the output directory for wav files and outcomes.
69 render_input_filepaths: set of render input audio track files to test.
70 echo_path_simulator_name: name of the echo path simulator to use when
71 render input is provided.
63 """ 72 """
73 assert render_input_filepaths is None or (
74 len(capture_input_filepaths) == len(render_input_filepaths)), (
75 'render input set size not matching input set size')
76 assert render_input_filepaths is None or echo_path_simulator_name in (
77 echo_path_simulation.EchoPathSimulator.REGISTERED_CLASSES), (
78 'invalid echo path simulator')
64 self._base_output_path = os.path.abspath(output_dir) 79 self._base_output_path = os.path.abspath(output_dir)
65 80
66 # Instance test data generators. 81 # Instance test data generators.
67 self._test_data_generators = [self._test_data_generator_factory.GetInstance( 82 self._test_data_generators = [self._test_data_generator_factory.GetInstance(
68 test_data_generators_class=( 83 test_data_generators_class=(
69 self._TEST_DATA_GENERATOR_CLASSES[name])) for name in ( 84 self._TEST_DATA_GENERATOR_CLASSES[name])) for name in (
70 test_data_generator_names)] 85 test_data_generator_names)]
71 86
72 # Instance evaluation score workers. 87 # Instance evaluation score workers.
73 self._evaluation_score_workers = [ 88 self._evaluation_score_workers = [
74 self._evaluation_score_factory.GetInstance( 89 self._evaluation_score_factory.GetInstance(
75 evaluation_score_class=self._EVAL_SCORE_WORKER_CLASSES[name]) for ( 90 evaluation_score_class=self._EVAL_SCORE_WORKER_CLASSES[name]) for (
76 name) in eval_score_names] 91 name) in eval_score_names]
77 92
78 # Set APM configuration file paths. 93 # Set APM configuration file paths.
79 self._config_filepaths = self._CreatePathsCollection(config_filepaths) 94 self._config_filepaths = self._CreatePathsCollection(config_filepaths)
80 95
81 # Set probing signal file paths. 96 # Set probing signal file paths.
82 self._input_filepaths = self._CreatePathsCollection(input_filepaths) 97 if render_input_filepaths is None:
98 # Capture input only.
99 self._capture_input_filepaths = self._CreatePathsCollection(
100 capture_input_filepaths)
101 self._render_input_filepaths = None
102 else:
103 # Set both capture and render input signals.
104 self._SetTestInputSignalFilePaths(
105 capture_input_filepaths, render_input_filepaths)
106 # TODO(alessiob): Instanciate EchoPathSimulator through factory.
peah-webrtc 2017/05/03 08:10:08 Instanciate -> Instantiate
83 107
84 self._SimulateAll() 108 self._SimulateAll()
85 109
86 def _SimulateAll(self): 110 def _SimulateAll(self):
87 """Runs all the simulations. 111 """Runs all the simulations.
88 112
89 Iterates over the combinations of APM configurations, probing signals, and 113 Iterates over the combinations of APM configurations, probing signals, and
90 test data generators. 114 test data generators.
91 """ 115 """
116 without_render_input = self._render_input_filepaths is None
peah-webrtc 2017/05/03 08:10:08 suggestion: without_render_input -> no_render_inpu
117
92 # Try different APM config files. 118 # Try different APM config files.
93 for config_name in self._config_filepaths: 119 for config_name in self._config_filepaths:
94 config_filepath = self._config_filepaths[config_name] 120 config_filepath = self._config_filepaths[config_name]
95 121
96 # Try different probing signal files. 122 # Try different probing signal files.
97 for input_name in self._input_filepaths: 123 for capture_input_name in self._capture_input_filepaths:
98 input_filepath = self._input_filepaths[input_name] 124 capture_input_filepath = self._capture_input_filepaths[
125 capture_input_name]
126 render_input_filepath = None if without_render_input else (
127 self._render_input_filepaths[capture_input_name])
99 128
100 # Try different test data generators. 129 # Try different test data generators.
101 for test_data_generators in self._test_data_generators: 130 for test_data_generators in self._test_data_generators:
102 logging.info('config: <%s>, input: <%s>, noise: <%s>', 131 logging.info('config: <%s>, input: <%s>, noise: <%s>',
103 config_name, input_name, test_data_generators.NAME) 132 config_name, capture_input_name,
133 test_data_generators.NAME)
104 134
105 # Output path for the input-noise pairs. It is used to cache the noisy 135 # Output path for the input-noise pairs. It is used to cache the noisy
106 # copies of the probing signals (shared across some simulations). 136 # copies of the probing signals (shared across some simulations).
107 input_noise_cache_path = os.path.join( 137 input_noise_cache_path = os.path.join(
108 self._base_output_path, 138 self._base_output_path,
109 '_cache', 139 '_cache',
110 'input_{}-noise_{}'.format(input_name, test_data_generators.NAME)) 140 'input_{}-noise_{}'.format(capture_input_name,
141 test_data_generators.NAME))
111 data_access.MakeDirectory(input_noise_cache_path) 142 data_access.MakeDirectory(input_noise_cache_path)
112 logging.debug('input-noise cache path: <%s>', input_noise_cache_path) 143 logging.debug('input-noise cache path: <%s>', input_noise_cache_path)
113 144
114 # Full output path. 145 # Full output path.
146 input_dir_suffix = capture_input_name if without_render_input else (
147 '{}-{}'.format(capture_input_name, self._ExtractFileName(
148 render_input_filepath)))
115 output_path = os.path.join( 149 output_path = os.path.join(
116 self._base_output_path, 150 self._base_output_path,
117 'cfg-{}'.format(config_name), 151 'cfg-{}'.format(config_name),
118 'input-{}'.format(input_name), 152 'input-{}'.format(input_dir_suffix),
119 'gen-{}'.format(test_data_generators.NAME)) 153 'gen-{}'.format(test_data_generators.NAME))
120 data_access.MakeDirectory(output_path) 154 data_access.MakeDirectory(output_path)
121 logging.debug('output path: <%s>', output_path) 155 logging.debug('output path: <%s>', output_path)
122 156
123 self._Simulate(test_data_generators, input_filepath, 157 self._Simulate(test_data_generators, capture_input_filepath,
124 input_noise_cache_path, output_path, config_filepath) 158 render_input_filepath, input_noise_cache_path,
159 output_path, config_filepath,)
125 160
126 def _Simulate(self, test_data_generators, input_filepath, 161 def _Simulate(self, test_data_generators, capture_input_filepath,
127 input_noise_cache_path, output_path, config_filepath): 162 render_input_filepath, input_noise_cache_path, output_path,
163 config_filepath):
128 """Runs a single set of simulation. 164 """Runs a single set of simulation.
129 165
130 Simulates a given combination of APM configuration, probing signal, and 166 Simulates a given combination of APM configuration, probing signal, and
131 test data generator. It iterates over the test data generator 167 test data generator. It iterates over the test data generator
132 internal configurations. 168 internal configurations.
133 169
134 Args: 170 Args:
135 test_data_generators: TestDataGenerator instance. 171 test_data_generators: TestDataGenerator instance.
136 input_filepath: input audio track file to test. 172 capture_input_filepath: clean capture input audio track file to test.
173 render_input_filepath: render input audio track file to test.
137 input_noise_cache_path: path for the noisy audio track files. 174 input_noise_cache_path: path for the noisy audio track files.
138 output_path: base output path for the test data generator. 175 output_path: base output path for the test data generator.
139 config_filepath: APM configuration file to test. 176 config_filepath: APM configuration file to test.
140 """ 177 """
141 # Generate pairs of noisy input and reference signal files. 178 # Generate pairs of noisy input and reference signal files.
142 test_data_generators.Generate( 179 test_data_generators.Generate(
143 input_signal_filepath=input_filepath, 180 input_signal_filepath=capture_input_filepath,
144 input_noise_cache_path=input_noise_cache_path, 181 input_noise_cache_path=input_noise_cache_path,
145 base_output_path=output_path) 182 base_output_path=output_path)
146 183
147 # For each test data pair, simulate a call and evaluate. 184 # For each test data pair, simulate a call and evaluate.
148 for config_name in test_data_generators.config_names: 185 for config_name in test_data_generators.config_names:
149 logging.info(' - test data generator config: <%s>', config_name) 186 logging.info(' - test data generator config: <%s>', config_name)
150 187
151 # APM input and output signal paths. 188 # Paths to the test data generator output.
152 noisy_signal_filepath = test_data_generators.noisy_signal_filepaths[ 189 # Note that the reference signal does not depend on the render input
153 config_name] 190 # which is optional.
191 noisy_capture_input_filepath = (
192 test_data_generators.noisy_signal_filepaths[config_name])
193 reference_signal_filepath = (
194 test_data_generators.reference_signal_filepaths[config_name])
195
196 # Paths to the APM input signals.
197 if render_input_filepath is not None:
198 logging.info(' - render input filepath: <%s>', render_input_filepath)
199 # TODO(alessiob): Simulate echo path using the EchoPathSimulator
200 # instance with which |noisy_capture_input_filepath| is updated.
201
202 # Path for the APM output file.
154 evaluation_output_path = test_data_generators.apm_output_paths[ 203 evaluation_output_path = test_data_generators.apm_output_paths[
155 config_name] 204 config_name]
156 205
157 # Simulate a call using the audio processing module. 206 # Simulate a call using APM.
158 self._audioproc_wrapper.Run( 207 self._audioproc_wrapper.Run(
159 config_filepath=config_filepath, 208 config_filepath=config_filepath,
160 input_filepath=noisy_signal_filepath, 209 capture_input_filepath=noisy_capture_input_filepath,
210 render_input_filepath=render_input_filepath,
161 output_path=evaluation_output_path) 211 output_path=evaluation_output_path)
162 212
163 # Reference signal path for the evaluation step.
164 reference_signal_filepath = (
165 test_data_generators.reference_signal_filepaths[
166 config_name])
167
168 # Evaluate. 213 # Evaluate.
169 self._evaluator.Run( 214 self._evaluator.Run(
170 evaluation_score_workers=self._evaluation_score_workers, 215 evaluation_score_workers=self._evaluation_score_workers,
171 apm_output_filepath=self._audioproc_wrapper.output_filepath, 216 apm_output_filepath=self._audioproc_wrapper.output_filepath,
172 reference_input_filepath=reference_signal_filepath, 217 reference_input_filepath=reference_signal_filepath,
173 output_path=evaluation_output_path) 218 output_path=evaluation_output_path)
174 219
220 def _SetTestInputSignalFilePaths(self, capture_input_filepaths,
221 render_input_filepaths):
222 """Sets input and render input file paths collections.
223
224 Pairs the input and render input files by storing the file paths into two
225 collections. The key is the file name of the input file.
226
227 Args:
228 capture_input_filepaths: list of file paths.
229 render_input_filepaths: list of file paths.
230 """
231 self._capture_input_filepaths = {}
232 self._render_input_filepaths = {}
233 assert len(capture_input_filepaths) == len(render_input_filepaths)
234 for capture_input_filepath, render_input_filepath in zip(
235 capture_input_filepaths, render_input_filepaths):
236 name = self._ExtractFileName(capture_input_filepath)
237 self._capture_input_filepaths[name] = os.path.abspath(
238 capture_input_filepath)
239 self._render_input_filepaths[name] = os.path.abspath(
240 render_input_filepath)
241
175 @classmethod 242 @classmethod
176 def _CreatePathsCollection(cls, filepaths): 243 def _CreatePathsCollection(cls, filepaths):
177 """Creates a collection of file paths. 244 """Creates a collection of file paths.
178 245
179 Given a list of file paths, makes a collection with one item for each file 246 Given a list of file paths, makes a collection with one item for each file
180 path. The value is absolute path, the key is the file name without 247 path. The value is absolute path, the key is the file name without
181 extenstion. 248 extenstion.
182 249
183 Args: 250 Args:
184 filepaths: list of file paths. 251 filepaths: list of file paths.
185 252
186 Returns: 253 Returns:
187 A dict. 254 A dict.
188 """ 255 """
189 filepaths_collection = {} 256 filepaths_collection = {}
190 for filepath in filepaths: 257 for filepath in filepaths:
191 name = os.path.splitext(os.path.split(filepath)[1])[0] 258 name = cls._ExtractFileName(filepath)
192 filepaths_collection[name] = os.path.abspath(filepath) 259 filepaths_collection[name] = os.path.abspath(filepath)
193 return filepaths_collection 260 return filepaths_collection
261
262 @classmethod
263 def _ExtractFileName(cls, filepath):
264 return os.path.splitext(os.path.split(filepath)[1])[0]
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698