1#!/usr/bin/env python 2# Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. 3# 4# Use of this source code is governed by a BSD-style license 5# that can be found in the LICENSE file in the root of the source 6# tree. An additional intellectual property rights grant can be found 7# in the file PATENTS. All contributing project authors may 8# be found in the AUTHORS file in the root of the source tree. 9"""Perform APM module quality assessment on one or more input files using one or 10 more APM simulator configuration files and one or more test data generators. 11 12Usage: apm_quality_assessment.py -i audio1.wav [audio2.wav ...] 13 -c cfg1.json [cfg2.json ...] 14 -n white [echo ...] 15 -e audio_level [polqa ...] 16 -o /path/to/output 17""" 18 19import argparse 20import logging 21import os 22import sys 23 24import quality_assessment.audioproc_wrapper as audioproc_wrapper 25import quality_assessment.echo_path_simulation as echo_path_simulation 26import quality_assessment.eval_scores as eval_scores 27import quality_assessment.evaluation as evaluation 28import quality_assessment.eval_scores_factory as eval_scores_factory 29import quality_assessment.external_vad as external_vad 30import quality_assessment.test_data_generation as test_data_generation 31import quality_assessment.test_data_generation_factory as \ 32 test_data_generation_factory 33import quality_assessment.simulation as simulation 34 35_ECHO_PATH_SIMULATOR_NAMES = ( 36 echo_path_simulation.EchoPathSimulator.REGISTERED_CLASSES) 37_TEST_DATA_GENERATOR_CLASSES = ( 38 test_data_generation.TestDataGenerator.REGISTERED_CLASSES) 39_TEST_DATA_GENERATORS_NAMES = _TEST_DATA_GENERATOR_CLASSES.keys() 40_EVAL_SCORE_WORKER_CLASSES = eval_scores.EvaluationScore.REGISTERED_CLASSES 41_EVAL_SCORE_WORKER_NAMES = _EVAL_SCORE_WORKER_CLASSES.keys() 42 43_DEFAULT_CONFIG_FILE = 'apm_configs/default.json' 44 45_POLQA_BIN_NAME = 'PolqaOem64' 46 47 48def _InstanceArgumentsParser(): 49 """Arguments parser factory. 50 """ 51 parser = argparse.ArgumentParser(description=( 52 'Perform APM module quality assessment on one or more input files using ' 53 'one or more APM simulator configuration files and one or more ' 54 'test data generators.')) 55 56 parser.add_argument('-c', 57 '--config_files', 58 nargs='+', 59 required=False, 60 help=('path to the configuration files defining the ' 61 'arguments with which the APM simulator tool is ' 62 'called'), 63 default=[_DEFAULT_CONFIG_FILE]) 64 65 parser.add_argument( 66 '-i', 67 '--capture_input_files', 68 nargs='+', 69 required=True, 70 help='path to the capture input wav files (one or more)') 71 72 parser.add_argument('-r', 73 '--render_input_files', 74 nargs='+', 75 required=False, 76 help=('path to the render input wav files; either ' 77 'omitted or one file for each file in ' 78 '--capture_input_files (files will be paired by ' 79 'index)'), 80 default=None) 81 82 parser.add_argument('-p', 83 '--echo_path_simulator', 84 required=False, 85 help=('custom echo path simulator name; required if ' 86 '--render_input_files is specified'), 87 choices=_ECHO_PATH_SIMULATOR_NAMES, 88 default=echo_path_simulation.NoEchoPathSimulator.NAME) 89 90 parser.add_argument('-t', 91 '--test_data_generators', 92 nargs='+', 93 required=False, 94 help='custom list of test data generators to use', 95 choices=_TEST_DATA_GENERATORS_NAMES, 96 default=_TEST_DATA_GENERATORS_NAMES) 97 98 parser.add_argument('--additive_noise_tracks_path', required=False, 99 help='path to the wav files for the additive', 100 default=test_data_generation. \ 101 AdditiveNoiseTestDataGenerator. \ 102 DEFAULT_NOISE_TRACKS_PATH) 103 104 parser.add_argument('-e', 105 '--eval_scores', 106 nargs='+', 107 required=False, 108 help='custom list of evaluation scores to use', 109 choices=_EVAL_SCORE_WORKER_NAMES, 110 default=_EVAL_SCORE_WORKER_NAMES) 111 112 parser.add_argument('-o', 113 '--output_dir', 114 required=False, 115 help=('base path to the output directory in which the ' 116 'output wav files and the evaluation outcomes ' 117 'are saved'), 118 default='output') 119 120 parser.add_argument('--polqa_path', 121 required=True, 122 help='path to the POLQA tool') 123 124 parser.add_argument('--air_db_path', 125 required=True, 126 help='path to the Aechen IR database') 127 128 parser.add_argument('--apm_sim_path', required=False, 129 help='path to the APM simulator tool', 130 default=audioproc_wrapper. \ 131 AudioProcWrapper. \ 132 DEFAULT_APM_SIMULATOR_BIN_PATH) 133 134 parser.add_argument('--echo_metric_tool_bin_path', 135 required=False, 136 help=('path to the echo metric binary ' 137 '(required for the echo eval score)'), 138 default=None) 139 140 parser.add_argument( 141 '--copy_with_identity_generator', 142 required=False, 143 help=('If true, the identity test data generator makes a ' 144 'copy of the clean speech input file.'), 145 default=False) 146 147 parser.add_argument('--external_vad_paths', 148 nargs='+', 149 required=False, 150 help=('Paths to external VAD programs. Each must take' 151 '\'-i <wav file> -o <output>\' inputs'), 152 default=[]) 153 154 parser.add_argument('--external_vad_names', 155 nargs='+', 156 required=False, 157 help=('Keys to the vad paths. Must be different and ' 158 'as many as the paths.'), 159 default=[]) 160 161 return parser 162 163 164def _ValidateArguments(args, parser): 165 if args.capture_input_files and args.render_input_files and (len( 166 args.capture_input_files) != len(args.render_input_files)): 167 parser.error( 168 '--render_input_files and --capture_input_files must be lists ' 169 'having the same length') 170 sys.exit(1) 171 172 if args.render_input_files and not args.echo_path_simulator: 173 parser.error( 174 'when --render_input_files is set, --echo_path_simulator is ' 175 'also required') 176 sys.exit(1) 177 178 if len(args.external_vad_names) != len(args.external_vad_paths): 179 parser.error('If provided, --external_vad_paths and ' 180 '--external_vad_names must ' 181 'have the same number of arguments.') 182 sys.exit(1) 183 184 185def main(): 186 # TODO(alessiob): level = logging.INFO once debugged. 187 logging.basicConfig(level=logging.DEBUG) 188 parser = _InstanceArgumentsParser() 189 args = parser.parse_args() 190 _ValidateArguments(args, parser) 191 192 simulator = simulation.ApmModuleSimulator( 193 test_data_generator_factory=( 194 test_data_generation_factory.TestDataGeneratorFactory( 195 aechen_ir_database_path=args.air_db_path, 196 noise_tracks_path=args.additive_noise_tracks_path, 197 copy_with_identity=args.copy_with_identity_generator)), 198 evaluation_score_factory=eval_scores_factory. 199 EvaluationScoreWorkerFactory( 200 polqa_tool_bin_path=os.path.join(args.polqa_path, _POLQA_BIN_NAME), 201 echo_metric_tool_bin_path=args.echo_metric_tool_bin_path), 202 ap_wrapper=audioproc_wrapper.AudioProcWrapper(args.apm_sim_path), 203 evaluator=evaluation.ApmModuleEvaluator(), 204 external_vads=external_vad.ExternalVad.ConstructVadDict( 205 args.external_vad_paths, args.external_vad_names)) 206 simulator.Run(config_filepaths=args.config_files, 207 capture_input_filepaths=args.capture_input_files, 208 render_input_filepaths=args.render_input_files, 209 echo_path_simulator_name=args.echo_path_simulator, 210 test_data_generator_names=args.test_data_generators, 211 eval_score_names=args.eval_scores, 212 output_dir=args.output_dir) 213 sys.exit(0) 214 215 216if __name__ == '__main__': 217 main() 218