OLD | NEW |
---|---|
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._input_filepaths = None |
51 self._reverse_input_filepaths = None | |
50 | 52 |
51 def Run(self, config_filepaths, input_filepaths, test_data_generator_names, | 53 def Run(self, config_filepaths, input_filepaths, test_data_generator_names, |
52 eval_score_names, output_dir): | 54 eval_score_names, output_dir, reverse_input_filepaths=None, |
55 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 Reverse input can be optionally added. If added, the number of input audio | |
60 tracks and reverse input audio tracks has to equal. The two lists are used | |
peah-webrtc
2017/04/21 05:28:45
have?
AleBzk
2017/04/24 14:30:42
Done.
| |
61 to form pairs of input and reverse input. | |
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 input_filepaths: set of 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 reverse_input_filepaths: set of revert input audio track files to test. | |
70 echo_path_simulator_name: name of the echo path simulator to use when | |
71 reverse input is provided. | |
63 """ | 72 """ |
73 assert reverse_input_filepaths is None or len(input_filepaths) == len( | |
74 reverse_input_filepaths), ('reverse input set size not matching input ' | |
75 'set size') | |
76 assert reverse_input_filepaths is None or echo_path_simulator_name in ( | |
77 echo_path_simulation.EchoPathSimulator.REGISTERED_CLASSES), ( | |
78 'reverse input ') | |
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 reverse_input_filepaths is None: |
98 # Forward input only. | |
99 self._input_filepaths = self._CreatePathsCollection(input_filepaths) | |
100 self._reverse_input_filepaths = None | |
101 else: | |
102 # Set both forward and reverse input signals. | |
103 self._SetProbingSignalFilePaths(input_filepaths, reverse_input_filepaths) | |
104 | |
105 # TODO(alessiob): Instance EchoPathSimulator through factory. | |
peah-webrtc
2017/04/21 05:28:45
Instantiate ?
AleBzk
2017/04/24 14:30:41
Done.
| |
83 | 106 |
84 self._SimulateAll() | 107 self._SimulateAll() |
85 | 108 |
86 def _SimulateAll(self): | 109 def _SimulateAll(self): |
87 """Runs all the simulations. | 110 """Runs all the simulations. |
88 | 111 |
89 Iterates over the combinations of APM configurations, probing signals, and | 112 Iterates over the combinations of APM configurations, probing signals, and |
90 test data generators. | 113 test data generators. |
91 """ | 114 """ |
115 without_reverse_input = self._reverse_input_filepaths is None | |
116 | |
92 # Try different APM config files. | 117 # Try different APM config files. |
93 for config_name in self._config_filepaths: | 118 for config_name in self._config_filepaths: |
94 config_filepath = self._config_filepaths[config_name] | 119 config_filepath = self._config_filepaths[config_name] |
95 | 120 |
96 # Try different probing signal files. | 121 # Try different probing signal files. |
97 for input_name in self._input_filepaths: | 122 for input_name in self._input_filepaths: |
98 input_filepath = self._input_filepaths[input_name] | 123 input_filepath = self._input_filepaths[input_name] |
124 reverse_input_filepath = None if without_reverse_input else ( | |
125 self._reverse_input_filepaths[input_name]) | |
99 | 126 |
100 # Try different test data generators. | 127 # Try different test data generators. |
101 for test_data_generators in self._test_data_generators: | 128 for test_data_generators in self._test_data_generators: |
102 logging.info('config: <%s>, input: <%s>, noise: <%s>', | 129 logging.info('config: <%s>, input: <%s>, noise: <%s>', |
103 config_name, input_name, test_data_generators.NAME) | 130 config_name, input_name, test_data_generators.NAME) |
104 | 131 |
105 # Output path for the input-noise pairs. It is used to cache the noisy | 132 # Output path for the input-noise pairs. It is used to cache the noisy |
106 # copies of the probing signals (shared across some simulations). | 133 # copies of the probing signals (shared across some simulations). |
107 input_noise_cache_path = os.path.join( | 134 input_noise_cache_path = os.path.join( |
108 self._base_output_path, | 135 self._base_output_path, |
109 '_cache', | 136 '_cache', |
110 'input_{}-noise_{}'.format(input_name, test_data_generators.NAME)) | 137 'input_{}-noise_{}'.format(input_name, test_data_generators.NAME)) |
111 data_access.MakeDirectory(input_noise_cache_path) | 138 data_access.MakeDirectory(input_noise_cache_path) |
112 logging.debug('input-noise cache path: <%s>', input_noise_cache_path) | 139 logging.debug('input-noise cache path: <%s>', input_noise_cache_path) |
113 | 140 |
114 # Full output path. | 141 # Full output path. |
142 input_dir_suffix = input_name if without_reverse_input else ( | |
143 '{}-{}'.format(input_name, self._ExtractFileName( | |
144 reverse_input_filepath))) | |
115 output_path = os.path.join( | 145 output_path = os.path.join( |
116 self._base_output_path, | 146 self._base_output_path, |
117 'cfg-{}'.format(config_name), | 147 'cfg-{}'.format(config_name), |
118 'input-{}'.format(input_name), | 148 'input-{}'.format(input_dir_suffix), |
119 'gen-{}'.format(test_data_generators.NAME)) | 149 'gen-{}'.format(test_data_generators.NAME)) |
120 data_access.MakeDirectory(output_path) | 150 data_access.MakeDirectory(output_path) |
121 logging.debug('output path: <%s>', output_path) | 151 logging.debug('output path: <%s>', output_path) |
122 | 152 |
123 self._Simulate(test_data_generators, input_filepath, | 153 self._Simulate(test_data_generators, input_filepath, |
124 input_noise_cache_path, output_path, config_filepath) | 154 reverse_input_filepath, input_noise_cache_path, |
155 output_path, config_filepath,) | |
125 | 156 |
126 def _Simulate(self, test_data_generators, input_filepath, | 157 def _Simulate(self, test_data_generators, input_filepath, |
127 input_noise_cache_path, output_path, config_filepath): | 158 reverse_input_filepath, input_noise_cache_path, output_path, |
159 config_filepath): | |
128 """Runs a single set of simulation. | 160 """Runs a single set of simulation. |
129 | 161 |
130 Simulates a given combination of APM configuration, probing signal, and | 162 Simulates a given combination of APM configuration, probing signal, and |
131 test data generator. It iterates over the test data generator | 163 test data generator. It iterates over the test data generator |
132 internal configurations. | 164 internal configurations. |
133 | 165 |
134 Args: | 166 Args: |
135 test_data_generators: TestDataGenerator instance. | 167 test_data_generators: TestDataGenerator instance. |
136 input_filepath: input audio track file to test. | 168 input_filepath: input audio track file to test. |
169 reverse_input_filepath: reverse input audio track file to test. | |
137 input_noise_cache_path: path for the noisy audio track files. | 170 input_noise_cache_path: path for the noisy audio track files. |
138 output_path: base output path for the test data generator. | 171 output_path: base output path for the test data generator. |
139 config_filepath: APM configuration file to test. | 172 config_filepath: APM configuration file to test. |
140 """ | 173 """ |
141 # Generate pairs of noisy input and reference signal files. | 174 # Generate pairs of noisy input and reference signal files. |
142 test_data_generators.Generate( | 175 test_data_generators.Generate( |
143 input_signal_filepath=input_filepath, | 176 input_signal_filepath=input_filepath, |
144 input_noise_cache_path=input_noise_cache_path, | 177 input_noise_cache_path=input_noise_cache_path, |
145 base_output_path=output_path) | 178 base_output_path=output_path) |
146 | 179 |
147 # For each test data pair, simulate a call and evaluate. | 180 # For each test data pair, simulate a call and evaluate. |
148 for test_data_generators_config_name in test_data_generators.config_names: | 181 for test_data_generators_config_name in test_data_generators.config_names: |
149 logging.info(' - test data generator config: <%s>', | 182 logging.info(' - test data generator config: <%s>', |
150 test_data_generators_config_name) | 183 test_data_generators_config_name) |
151 | 184 |
152 # APM input and output signal paths. | 185 # Paths to the test data generator output. |
186 # Note that the reference signal does not depend on the reverse input | |
187 # which is optional. | |
153 noisy_signal_filepath = test_data_generators.noisy_signal_filepaths[ | 188 noisy_signal_filepath = test_data_generators.noisy_signal_filepaths[ |
154 test_data_generators_config_name] | 189 test_data_generators_config_name] |
155 evaluation_output_path = test_data_generators.apm_output_paths[ | |
156 test_data_generators_config_name] | |
157 | |
158 # Simulate a call using the audio processing module. | |
159 self._audioproc_wrapper.Run( | |
160 config_filepath=config_filepath, | |
161 input_filepath=noisy_signal_filepath, | |
162 output_path=evaluation_output_path) | |
163 | |
164 # Reference signal path for the evaluation step. | |
165 reference_signal_filepath = ( | 190 reference_signal_filepath = ( |
166 test_data_generators.reference_signal_filepaths[ | 191 test_data_generators.reference_signal_filepaths[ |
167 test_data_generators_config_name]) | 192 test_data_generators_config_name]) |
168 | 193 |
194 # Path to the APM input signal. | |
195 apm_input_filepath = noisy_signal_filepath | |
196 if reverse_input_filepath is not None: | |
197 logging.info(' - reverse input filepath: <%s>', reverse_input_filepath) | |
198 # TODO(alessiob): Simulate echo path using the EchoPathSimulator | |
199 # instance with which |apm_input_filepath| is updated. | |
200 | |
201 # Path for the APM output file. | |
202 evaluation_output_path = test_data_generators.apm_output_paths[ | |
203 test_data_generators_config_name] | |
204 | |
205 # Simulate a call using APM. | |
206 self._audioproc_wrapper.Run( | |
207 config_filepath=config_filepath, | |
208 input_filepath=apm_input_filepath, | |
209 reverse_input_filepath=reverse_input_filepath, | |
210 output_path=evaluation_output_path) | |
211 | |
169 # Evaluate. | 212 # Evaluate. |
170 self._evaluator.Run( | 213 self._evaluator.Run( |
171 evaluation_score_workers=self._evaluation_score_workers, | 214 evaluation_score_workers=self._evaluation_score_workers, |
172 apm_output_filepath=self._audioproc_wrapper.output_filepath, | 215 apm_output_filepath=self._audioproc_wrapper.output_filepath, |
173 reference_input_filepath=reference_signal_filepath, | 216 reference_input_filepath=reference_signal_filepath, |
174 output_path=evaluation_output_path) | 217 output_path=evaluation_output_path) |
175 | 218 |
219 def _SetProbingSignalFilePaths(self, input_filepaths, | |
peah-webrtc
2017/04/21 05:28:45
The naming of this method does not seem intuitive
AleBzk
2017/04/24 14:30:42
Renamed to _SetTestInputSignalFilePaths().
| |
220 reverse_input_filepaths): | |
221 """Sets input and revers input file paths collections. | |
222 | |
223 Pairs the input and rever input files by storing the file paths into two | |
peah-webrtc
2017/04/21 05:28:45
reverse ?
AleBzk
2017/04/24 14:30:42
Done.
| |
224 collections. The key is the file name of the input file. | |
225 | |
226 Args: | |
227 input_filepaths: list of file paths. | |
228 reverse_input_filepaths: list of file paths. | |
229 """ | |
230 self._input_filepaths = {} | |
231 self._reverse_input_filepaths = {} | |
232 assert len(input_filepaths) == len(reverse_input_filepaths) | |
233 for input_filepath, reverse_input_filepath in zip( | |
234 input_filepaths, reverse_input_filepaths): | |
235 name = self._ExtractFileName(input_filepath) | |
236 self._input_filepaths[name] = os.path.abspath(input_filepath) | |
237 self._reverse_input_filepaths[name] = os.path.abspath( | |
238 reverse_input_filepath) | |
239 | |
176 @classmethod | 240 @classmethod |
177 def _CreatePathsCollection(cls, filepaths): | 241 def _CreatePathsCollection(cls, filepaths): |
178 """Creates a collection of file paths. | 242 """Creates a collection of file paths. |
179 | 243 |
180 Given a list of file paths, makes a collection with one item for each file | 244 Given a list of file paths, makes a collection with one item for each file |
181 path. The value is absolute path, the key is the file name without | 245 path. The value is absolute path, the key is the file name without |
182 extenstion. | 246 extenstion. |
183 | 247 |
184 Args: | 248 Args: |
185 filepaths: list of file paths. | 249 filepaths: list of file paths. |
186 | 250 |
187 Returns: | 251 Returns: |
188 A dict. | 252 A dict. |
189 """ | 253 """ |
190 filepaths_collection = {} | 254 filepaths_collection = {} |
191 for filepath in filepaths: | 255 for filepath in filepaths: |
192 name = os.path.splitext(os.path.split(filepath)[1])[0] | 256 name = cls._ExtractFileName(filepath) |
193 filepaths_collection[name] = os.path.abspath(filepath) | 257 filepaths_collection[name] = os.path.abspath(filepath) |
194 return filepaths_collection | 258 return filepaths_collection |
259 | |
260 @classmethod | |
261 def _ExtractFileName(cls, filepath): | |
262 return os.path.splitext(os.path.split(filepath)[1])[0] | |
OLD | NEW |