Amy Lin | 8c768a7 | 2016-08-01 15:44:16 +0800 | [diff] [blame] | 1 | // Copyright 2016 The Chromium OS Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
Earl Ou | 06c1ad6 | 2016-12-01 17:21:50 +0800 | [diff] [blame] | 5 | #include <assert.h> |
Earl Ou | 7ae955b | 2016-11-30 16:41:22 +0800 | [diff] [blame] | 6 | #include <getopt.h> |
Amy Lin | 8c768a7 | 2016-08-01 15:44:16 +0800 | [diff] [blame] | 7 | #include <stdlib.h> |
Earl Ou | 7ae955b | 2016-11-30 16:41:22 +0800 | [diff] [blame] | 8 | #include <string.h> |
| 9 | #include <sys/types.h> |
| 10 | #include <unistd.h> |
Amy Lin | 8c768a7 | 2016-08-01 15:44:16 +0800 | [diff] [blame] | 11 | |
Earl Ou | 5afc8d3 | 2016-12-01 11:30:52 +0800 | [diff] [blame] | 12 | #include "include/binary_client.h" |
Earl Ou | 7ae955b | 2016-11-30 16:41:22 +0800 | [diff] [blame] | 13 | #include "include/common.h" |
Amy Lin | 8c768a7 | 2016-08-01 15:44:16 +0800 | [diff] [blame] | 14 | #include "include/evaluator.h" |
Earl Ou | 06c1ad6 | 2016-12-01 17:21:50 +0800 | [diff] [blame] | 15 | #include "include/generator_player.h" |
| 16 | #include "include/sample_format.h" |
| 17 | #include "include/tone_generators.h" |
Amy Lin | 8c768a7 | 2016-08-01 15:44:16 +0800 | [diff] [blame] | 18 | |
Earl Ou | 06c1ad6 | 2016-12-01 17:21:50 +0800 | [diff] [blame] | 19 | constexpr static const char *short_options = |
cyueh | f6167eb | 2019-08-12 14:25:23 +0800 | [diff] [blame] | 20 | "a:m:d:n:o:w:P:f:R:F:r:t:c:C:T:l:g:i:x:hv"; |
Earl Ou | 7ae955b | 2016-11-30 16:41:22 +0800 | [diff] [blame] | 21 | |
| 22 | constexpr static const struct option long_options[] = { |
| 23 | {"active-speaker-channels", 1, NULL, 'a'}, |
Ting Shen | a2834cb | 2017-03-07 14:49:05 +0800 | [diff] [blame] | 24 | {"active-mic-channels", 1, NULL, 'm'}, |
Earl Ou | 7ae955b | 2016-11-30 16:41:22 +0800 | [diff] [blame] | 25 | {"allowed-delay", 1, NULL, 'd'}, |
| 26 | {"fft-size", 1, NULL, 'n'}, |
| 27 | {"confidence-threshold", 1, NULL, 'o'}, |
Earl Ou | 06c1ad6 | 2016-12-01 17:21:50 +0800 | [diff] [blame] | 28 | {"match-window-size", 1, NULL, 'w'}, |
Earl Ou | 7ae955b | 2016-11-30 16:41:22 +0800 | [diff] [blame] | 29 | {"player-command", 1, NULL, 'P'}, |
| 30 | {"player-fifo", 1, NULL, 'f'}, |
| 31 | {"recorder-command", 1, NULL, 'R'}, |
| 32 | {"recorder-fifo", 1, NULL, 'F'}, |
| 33 | {"sample-rate", 1, NULL, 'r'}, |
| 34 | {"sample-format", 1, NULL, 't'}, |
| 35 | {"num-mic-channels", 1, NULL, 'c'}, |
| 36 | {"num-speaker-channels", 1, NULL, 'C'}, |
| 37 | {"test-rounds", 1, NULL, 'T'}, |
| 38 | {"tone-length", 1, NULL, 'l'}, |
Marco Chen | 6b3e331 | 2017-09-29 17:02:22 +0800 | [diff] [blame] | 39 | {"volume-gain", 1, NULL, 'g'}, |
cyueh | f6167eb | 2019-08-12 14:25:23 +0800 | [diff] [blame] | 40 | {"min-frequency", 1, NULL, 'i'}, |
| 41 | {"max-frequency", 1, NULL, 'x'}, |
Earl Ou | 7ae955b | 2016-11-30 16:41:22 +0800 | [diff] [blame] | 42 | |
| 43 | // Other helper args. |
| 44 | {"help", 0, NULL, 'h'}, |
| 45 | {"verbose", 0, NULL, 'v'}, |
| 46 | }; |
| 47 | |
| 48 | // Parse the sample format. The input should be one of the string in |
| 49 | // SampleFormat:Type. |
| 50 | SampleFormat ParseSampleFormat(const char *arg) { |
| 51 | SampleFormat sample_format; |
| 52 | for (int format = SampleFormat::kPcmU8; |
| 53 | format != SampleFormat::kPcmInvalid; |
| 54 | format++) { |
| 55 | sample_format = SampleFormat(SampleFormat::Type(format)); |
| 56 | if (strcmp(sample_format.to_string(), optarg) == 0) { |
| 57 | return sample_format; |
| 58 | } |
| 59 | } |
| 60 | fprintf(stderr, "Unknown sample format %s, using S16 instead.", arg); |
| 61 | return SampleFormat(SampleFormat::kPcmS16); |
| 62 | } |
| 63 | |
| 64 | bool ParseOptions(int argc, char *const argv[], AudioFunTestConfig *config) { |
| 65 | int opt = 0; |
| 66 | int optindex = -1; |
| 67 | |
| 68 | while ((opt = getopt_long(argc, argv, short_options, |
| 69 | long_options, |
| 70 | &optindex)) != -1) { |
| 71 | switch (opt) { |
| 72 | case 'a': |
| 73 | ParseActiveChannels(optarg, &(config->active_speaker_channels)); |
| 74 | break; |
Ting Shen | a2834cb | 2017-03-07 14:49:05 +0800 | [diff] [blame] | 75 | case 'm': |
| 76 | ParseActiveChannels(optarg, &(config->active_mic_channels)); |
| 77 | break; |
Earl Ou | 7ae955b | 2016-11-30 16:41:22 +0800 | [diff] [blame] | 78 | case 'd': |
| 79 | config->allowed_delay_sec = atof(optarg); |
| 80 | break; |
| 81 | case 'n': |
| 82 | config->fft_size = atoi(optarg); |
| 83 | if ((config->fft_size == 0) || |
| 84 | (config->fft_size & (config->fft_size - 1))) { |
| 85 | fprintf(stderr, "FFT size needs to be positive & power of 2\n"); |
| 86 | return false; |
| 87 | } |
| 88 | break; |
| 89 | case 'o': |
| 90 | config->confidence_threshold = atof(optarg); |
| 91 | break; |
Earl Ou | 06c1ad6 | 2016-12-01 17:21:50 +0800 | [diff] [blame] | 92 | case 'w': |
| 93 | config->match_window_size = atoi(optarg); |
| 94 | if (config->match_window_size % 2 == 0) { |
| 95 | fprintf(stderr, "Match window size must be an odd value.\n"); |
| 96 | return false; |
| 97 | } |
| 98 | break; |
Earl Ou | 7ae955b | 2016-11-30 16:41:22 +0800 | [diff] [blame] | 99 | case 'P': |
| 100 | config->player_command = std::string(optarg); |
| 101 | break; |
| 102 | case 'f': |
| 103 | config->player_fifo = std::string(optarg); |
| 104 | break; |
| 105 | case 'R': |
| 106 | config->recorder_command = std::string(optarg); |
| 107 | break; |
| 108 | case 'F': |
| 109 | config->recorder_fifo = std::string(optarg); |
| 110 | break; |
| 111 | case 'r': |
| 112 | config->sample_rate = atoi(optarg); |
| 113 | break; |
| 114 | case 't': |
| 115 | config->sample_format = ParseSampleFormat(optarg); |
| 116 | break; |
| 117 | case 'c': |
| 118 | config->num_mic_channels = atoi(optarg); |
| 119 | break; |
| 120 | case 'C': |
| 121 | config->num_speaker_channels = atoi(optarg); |
| 122 | break; |
| 123 | case 'T': |
| 124 | config->test_rounds = atoi(optarg); |
| 125 | break; |
| 126 | case 'l': |
| 127 | config->tone_length_sec = atof(optarg); |
| 128 | // Avoid overly short tones. |
| 129 | if (config->tone_length_sec < 0.01) { |
| 130 | fprintf(stderr, |
| 131 | "Tone length too short. Must be 0.01s or greater.\n"); |
| 132 | return false; |
| 133 | } |
| 134 | break; |
Marco Chen | 6b3e331 | 2017-09-29 17:02:22 +0800 | [diff] [blame] | 135 | case 'g': |
| 136 | config->volume_gain = atoi(optarg); |
| 137 | if (config->volume_gain < 0 || config->volume_gain > 100) { |
| 138 | fprintf(stderr, "Value of volume_gain is out of range.\n"); |
| 139 | return false; |
| 140 | } |
cyueh | f6167eb | 2019-08-12 14:25:23 +0800 | [diff] [blame] | 141 | break; |
| 142 | case 'i': |
| 143 | config->min_frequency = atoi(optarg); |
| 144 | break; |
| 145 | case 'x': |
| 146 | config->max_frequency = atoi(optarg); |
| 147 | break; |
Earl Ou | 7ae955b | 2016-11-30 16:41:22 +0800 | [diff] [blame] | 148 | case 'v': |
| 149 | config->verbose = true; |
| 150 | break; |
| 151 | case 'h': |
| 152 | return false; |
| 153 | default: |
| 154 | fprintf(stderr, "Unknown arguments %c\n", opt); |
| 155 | assert(false); |
| 156 | } |
| 157 | } |
| 158 | |
| 159 | if (config->player_command.empty()) { |
| 160 | fprintf(stderr, "player-command is not set.\n"); |
| 161 | return false; |
| 162 | } |
| 163 | |
| 164 | if (config->recorder_command.empty()) { |
| 165 | fprintf(stderr, "recorder-command is not set.\n"); |
| 166 | return false; |
| 167 | } |
| 168 | |
| 169 | if (config->active_speaker_channels.empty()) { |
| 170 | for (int i = 0; i < config->num_speaker_channels; ++i) { |
| 171 | config->active_speaker_channels.insert(i); |
| 172 | } |
| 173 | } |
Ting Shen | a2834cb | 2017-03-07 14:49:05 +0800 | [diff] [blame] | 174 | |
| 175 | if (config->active_mic_channels.empty()) { |
| 176 | for (int i = 0; i < config->num_mic_channels; ++i) { |
| 177 | config->active_mic_channels.insert(i); |
| 178 | } |
| 179 | } |
cyueh | f6167eb | 2019-08-12 14:25:23 +0800 | [diff] [blame] | 180 | |
| 181 | if (config->min_frequency > config->max_frequency) { |
| 182 | fprintf(stderr, "Range error: min_frequency > max_frequency\n"); |
| 183 | return false; |
| 184 | } |
| 185 | |
| 186 | if (config->min_frequency < 0) { |
| 187 | fprintf(stderr, "Range error: min_frequency < 0\n"); |
| 188 | return false; |
| 189 | } |
Earl Ou | 7ae955b | 2016-11-30 16:41:22 +0800 | [diff] [blame] | 190 | return true; |
| 191 | } |
| 192 | |
| 193 | void PrintUsage(const char *name, FILE *fd = stderr) { |
| 194 | AudioFunTestConfig default_config; |
| 195 | |
| 196 | fprintf(fd, |
| 197 | "Usage %s -P <player_command> -R <recorder_command> [options]\n", |
| 198 | name); |
| 199 | fprintf(fd, |
| 200 | "\t-a, --active-speaker-channels:\n" |
| 201 | "\t\tComma-separated list of speaker channels to play on. " |
| 202 | "(def all channels)\n"); |
| 203 | fprintf(fd, |
Ting Shen | a2834cb | 2017-03-07 14:49:05 +0800 | [diff] [blame] | 204 | "\t-m, --active-mic-channels:\n" |
| 205 | "\t\tComma-separated list of mic channels to test. " |
| 206 | "(def all channels)\n"); |
| 207 | fprintf(fd, |
Earl Ou | 7ae955b | 2016-11-30 16:41:22 +0800 | [diff] [blame] | 208 | "\t-d, --allowed-delay:\n" |
| 209 | "\t\tAllowed latency between player & recorder " |
| 210 | "(def %.4f).\n", default_config.allowed_delay_sec); |
| 211 | fprintf(fd, |
| 212 | "\t-n, --fftsize:\n" |
| 213 | "\t\tLonger fftsize has more carriers but longer latency." |
| 214 | " Also, fftsize needs to be power of 2" |
| 215 | "(def %d)\n", default_config.fft_size); |
| 216 | fprintf(fd, |
| 217 | "\t-o, --confidence-threshold:\n" |
| 218 | "\t\tThreshold of accumulated confidence to pass evaluation " |
| 219 | "(def %.4f)\n", default_config.confidence_threshold); |
| 220 | fprintf(fd, |
Earl Ou | 06c1ad6 | 2016-12-01 17:21:50 +0800 | [diff] [blame] | 221 | "\t-w, --match-window-size:\n" |
| 222 | "\t\tNumber of bin to be used for calculating matching confidence. " |
| 223 | "Should be an odd number." |
| 224 | "(def %d)\n", default_config.match_window_size); |
| 225 | fprintf(fd, |
Earl Ou | 7ae955b | 2016-11-30 16:41:22 +0800 | [diff] [blame] | 226 | "\t-P, --player-command:\n" |
| 227 | "\t\tThe command used to play sound.\n"); |
| 228 | fprintf(fd, |
| 229 | "\t-f, --player-fifo:\n" |
| 230 | "\t\tThe named pipe used to send wave to the player. If not set, " |
| 231 | "wave is send to player program via its stdin.\n"); |
| 232 | fprintf(fd, |
| 233 | "\t-R, --recorder-command:\n" |
| 234 | "\t\tThe command used to record sound.\n"); |
| 235 | fprintf(fd, |
| 236 | "\t-F, --recorder-fifo:\n" |
| 237 | "\t\tThe named pipe used to read recorded wave from the recorder " |
| 238 | "program. If not set, wave is read from recorder program via " |
| 239 | "its stdout.\n"); |
| 240 | fprintf(fd, |
| 241 | "\t-r, --sample-rate:\n" |
| 242 | "\t\tSample rate of generated wave in HZ " |
| 243 | "(def %d)\n", default_config.sample_rate); |
| 244 | fprintf(fd, |
| 245 | "\t-t, --sample-format:\n" |
| 246 | "\t\tFormat of recording & playing samples, should be one of u8, " |
| 247 | "s16, s24, s32." |
Ting Shen | 95141ed | 2017-01-05 18:41:43 +0800 | [diff] [blame] | 248 | "(def %s).\n", default_config.sample_format.to_string()); |
Earl Ou | 7ae955b | 2016-11-30 16:41:22 +0800 | [diff] [blame] | 249 | fprintf(fd, |
| 250 | "\t-c, --num-mic-channels:\n" |
| 251 | "\t\tThe number of microphone channels " |
| 252 | "(def %d)\n", default_config.num_mic_channels); |
| 253 | fprintf(fd, |
| 254 | "\t-C, --num-speaker-channels:\n" |
| 255 | "\t\tThe number of speaker channels " |
| 256 | "(def %d)\n", default_config.num_speaker_channels); |
| 257 | fprintf(fd, |
| 258 | "\t-T, --test-rounds:\n" |
| 259 | "\t\tNumber of test rounds " |
| 260 | "(def %d)\n", default_config.test_rounds); |
| 261 | fprintf(fd, |
| 262 | "\t-l, --tone-length:\n" |
| 263 | "\t\tDecimal value of tone length in secs " |
| 264 | "(def %.4f)\n", default_config.tone_length_sec); |
| 265 | fprintf(fd, |
Marco Chen | 6b3e331 | 2017-09-29 17:02:22 +0800 | [diff] [blame] | 266 | "\t-g, --volume-gain\n" |
| 267 | "\t\tControl the volume of generated audio frames. The range is from" |
cyueh | f6167eb | 2019-08-12 14:25:23 +0800 | [diff] [blame] | 268 | " 0 to 100.\n"); |
| 269 | fprintf(fd, |
| 270 | "\t-i, --min-frequency:\n" |
| 271 | "\t\tThe minimum frequency of generated audio frames." |
| 272 | "(def %d)\n", default_config.min_frequency); |
| 273 | fprintf(fd, |
| 274 | "\t-x, --max-frequency\n" |
| 275 | "\t\tThe maximum frequency of generated audio frames." |
| 276 | "(def %d)\n", default_config.max_frequency); |
Marco Chen | 6b3e331 | 2017-09-29 17:02:22 +0800 | [diff] [blame] | 277 | |
| 278 | fprintf(fd, |
Earl Ou | 7ae955b | 2016-11-30 16:41:22 +0800 | [diff] [blame] | 279 | "\t-v, --verbose: Show debugging information.\n"); |
| 280 | fprintf(fd, |
| 281 | "\t-h, --help: Show this page.\n"); |
| 282 | } |
| 283 | |
Ting Shen | a2834cb | 2017-03-07 14:49:05 +0800 | [diff] [blame] | 284 | void PrintSet(const std::set<int> &numbers, FILE *fd = stdout) { |
Earl Ou | 7ae955b | 2016-11-30 16:41:22 +0800 | [diff] [blame] | 285 | bool first = true; |
Ting Shen | a2834cb | 2017-03-07 14:49:05 +0800 | [diff] [blame] | 286 | for (auto it : numbers) { |
Earl Ou | 7ae955b | 2016-11-30 16:41:22 +0800 | [diff] [blame] | 287 | if (!first) |
| 288 | fprintf(fd, ", "); |
| 289 | fprintf(fd, "%d", it); |
| 290 | first = false; |
| 291 | } |
Ting Shen | a2834cb | 2017-03-07 14:49:05 +0800 | [diff] [blame] | 292 | } |
| 293 | |
| 294 | void PrintConfig(const AudioFunTestConfig &config, FILE *fd = stdout) { |
| 295 | fprintf(fd, "Config values.\n"); |
| 296 | |
| 297 | fprintf(fd, "\tSpeaker active channels: "); |
| 298 | PrintSet(config.active_speaker_channels, fd); |
| 299 | fprintf(fd, "\n"); |
| 300 | fprintf(fd, "\tMic active channels: "); |
| 301 | PrintSet(config.active_mic_channels, fd); |
Earl Ou | 7ae955b | 2016-11-30 16:41:22 +0800 | [diff] [blame] | 302 | fprintf(fd, "\n"); |
| 303 | fprintf(fd, "\tAllowed delay: %.4f(s)\n", config.allowed_delay_sec); |
| 304 | fprintf(fd, "\tFFT size: %d\n", config.fft_size); |
| 305 | fprintf(fd, "\tConfidence threshold: %.4f\n", config.confidence_threshold); |
Earl Ou | 06c1ad6 | 2016-12-01 17:21:50 +0800 | [diff] [blame] | 306 | fprintf(fd, "\tMatch window size: %d\n", config.match_window_size); |
Earl Ou | 7ae955b | 2016-11-30 16:41:22 +0800 | [diff] [blame] | 307 | fprintf(fd, "\tPlayer parameter: %s\n", config.player_command.c_str()); |
| 308 | fprintf(fd, "\tPlayer FIFO name: %s\n", config.player_fifo.c_str()); |
| 309 | fprintf(fd, "\tRecorder parameter: %s\n", config.recorder_command.c_str()); |
| 310 | fprintf(fd, "\tRecorder FIFO name: %s\n", config.recorder_fifo.c_str()); |
| 311 | fprintf(fd, "\tSample format: %s\n", config.sample_format.to_string()); |
| 312 | fprintf(fd, "\tSample rate: %d\n", config.sample_rate); |
| 313 | fprintf(fd, |
| 314 | "\tNumber of Microphone channels: %d\n", config.num_mic_channels); |
| 315 | fprintf(fd, "\tNumber of Speaker channels: %d\n", |
| 316 | config.num_speaker_channels); |
| 317 | fprintf(fd, "\tNumber of test rounds: %d\n", config.test_rounds); |
| 318 | fprintf(fd, "\tTone length: %.4f(s)\n", config.tone_length_sec); |
Marco Chen | 6b3e331 | 2017-09-29 17:02:22 +0800 | [diff] [blame] | 319 | fprintf(fd, "\tVolume gain: %d\n", config.volume_gain); |
cyueh | f6167eb | 2019-08-12 14:25:23 +0800 | [diff] [blame] | 320 | fprintf(fd, "\tMinimum frequency: %d\n", config.min_frequency); |
| 321 | fprintf(fd, "\tMaximum frequency: %d\n", config.max_frequency); |
Earl Ou | 7ae955b | 2016-11-30 16:41:22 +0800 | [diff] [blame] | 322 | |
| 323 | if (config.verbose) |
| 324 | fprintf(fd, "\t** Verbose **.\n"); |
| 325 | } |
Amy Lin | 8c768a7 | 2016-08-01 15:44:16 +0800 | [diff] [blame] | 326 | |
| 327 | // Randomly picks an integer from the given range [min, max], |
| 328 | // including both end points. |
| 329 | inline int RandomPick(int min, int max) { |
| 330 | if (min > max) { |
Earl Ou | 7ae955b | 2016-11-30 16:41:22 +0800 | [diff] [blame] | 331 | fprintf(stderr, "Range error: min > max\n"); |
Amy Lin | 8c768a7 | 2016-08-01 15:44:16 +0800 | [diff] [blame] | 332 | assert(false); |
| 333 | } |
| 334 | |
| 335 | static unsigned int seed = time(NULL) + getpid(); |
| 336 | return (rand_r(&seed) % (max - min + 1)) + min; |
| 337 | } |
| 338 | |
| 339 | // Controls the main process of audiofuntest. |
Earl Ou | 7ae955b | 2016-11-30 16:41:22 +0800 | [diff] [blame] | 340 | void ControlLoop(const AudioFunTestConfig &config, |
Amy Lin | 8c768a7 | 2016-08-01 15:44:16 +0800 | [diff] [blame] | 341 | Evaluator *evaluator, |
Earl Ou | 06c1ad6 | 2016-12-01 17:21:50 +0800 | [diff] [blame] | 342 | PlayClient *player, |
cyueh | f6167eb | 2019-08-12 14:25:23 +0800 | [diff] [blame] | 343 | RecordClient *recorder) { |
Amy Lin | 8c768a7 | 2016-08-01 15:44:16 +0800 | [diff] [blame] | 344 | const double frequency_resolution = |
| 345 | static_cast<double>(config.sample_rate) / config.fft_size; |
cyueh | f6167eb | 2019-08-12 14:25:23 +0800 | [diff] [blame] | 346 | const int min_bin = config.min_frequency / frequency_resolution; |
| 347 | const int max_bin = config.max_frequency / frequency_resolution; |
Amy Lin | 8c768a7 | 2016-08-01 15:44:16 +0800 | [diff] [blame] | 348 | |
Earl Ou | 7ae955b | 2016-11-30 16:41:22 +0800 | [diff] [blame] | 349 | std::vector<int> passes(config.num_mic_channels); |
| 350 | std::vector<bool> single_round_pass(config.num_mic_channels); |
Amy Lin | 8c768a7 | 2016-08-01 15:44:16 +0800 | [diff] [blame] | 351 | |
Earl Ou | 06c1ad6 | 2016-12-01 17:21:50 +0800 | [diff] [blame] | 352 | size_t buf_size = config.fft_size * config.num_speaker_channels * |
| 353 | config.sample_format.bytes(); |
Marco Chen | 6b3e331 | 2017-09-29 17:02:22 +0800 | [diff] [blame] | 354 | SineWaveGenerator generator( |
| 355 | config.sample_rate, |
| 356 | config.tone_length_sec, |
| 357 | config.volume_gain); |
Earl Ou | 06c1ad6 | 2016-12-01 17:21:50 +0800 | [diff] [blame] | 358 | GeneratorPlayer generatorPlayer( |
| 359 | buf_size, |
| 360 | config.num_speaker_channels, |
| 361 | config.active_speaker_channels, |
| 362 | config.sample_format, |
| 363 | player); |
| 364 | |
Amy Lin | 8c768a7 | 2016-08-01 15:44:16 +0800 | [diff] [blame] | 365 | for (int round = 1; round <= config.test_rounds; ++round) { |
| 366 | std::fill(single_round_pass.begin(), single_round_pass.end(), false); |
| 367 | int bin = RandomPick(min_bin, max_bin); |
| 368 | double frequency = bin * frequency_resolution; |
| 369 | |
Earl Ou | 06c1ad6 | 2016-12-01 17:21:50 +0800 | [diff] [blame] | 370 | generator.Reset(frequency); |
| 371 | generatorPlayer.Play(&generator); |
Amy Lin | 8c768a7 | 2016-08-01 15:44:16 +0800 | [diff] [blame] | 372 | |
Earl Ou | 06c1ad6 | 2016-12-01 17:21:50 +0800 | [diff] [blame] | 373 | evaluator->Evaluate(bin, recorder, &single_round_pass); |
Amy Lin | 8c768a7 | 2016-08-01 15:44:16 +0800 | [diff] [blame] | 374 | for (int chn = 0; chn < config.num_mic_channels; ++chn) { |
| 375 | if (single_round_pass[chn]) { |
| 376 | ++passes[chn]; |
| 377 | } |
| 378 | } |
Earl Ou | 06c1ad6 | 2016-12-01 17:21:50 +0800 | [diff] [blame] | 379 | generatorPlayer.Stop(); |
Amy Lin | 8c768a7 | 2016-08-01 15:44:16 +0800 | [diff] [blame] | 380 | |
Earl Ou | 7ae955b | 2016-11-30 16:41:22 +0800 | [diff] [blame] | 381 | printf("carrier = %d\n", bin); |
Ting Shen | a2834cb | 2017-03-07 14:49:05 +0800 | [diff] [blame] | 382 | for (auto c : config.active_mic_channels) { |
Earl Ou | 733306b | 2016-11-14 14:26:04 +0800 | [diff] [blame] | 383 | const char *res = single_round_pass[c] ? "O" : "X"; |
Earl Ou | 7ae955b | 2016-11-30 16:41:22 +0800 | [diff] [blame] | 384 | printf("%s: channel = %d, success = %d, fail = %d, rate = %.4f\n", |
| 385 | res, c, passes[c], round - passes[c], 100.0 * passes[c] / round); |
Amy Lin | 8c768a7 | 2016-08-01 15:44:16 +0800 | [diff] [blame] | 386 | } |
Amy Lin | 8c768a7 | 2016-08-01 15:44:16 +0800 | [diff] [blame] | 387 | } |
| 388 | } |
| 389 | |
| 390 | int main(int argc, char *argv[]) { |
Earl Ou | 7ae955b | 2016-11-30 16:41:22 +0800 | [diff] [blame] | 391 | // Parses configuration.ParamConfig |
| 392 | AudioFunTestConfig config; |
| 393 | if (!ParseOptions(argc, argv, &config)) { |
| 394 | PrintUsage(argv[0]); |
| 395 | return 1; |
Amy Lin | 8c768a7 | 2016-08-01 15:44:16 +0800 | [diff] [blame] | 396 | } |
Earl Ou | 7ae955b | 2016-11-30 16:41:22 +0800 | [diff] [blame] | 397 | |
| 398 | PrintConfig(config); |
Amy Lin | 8c768a7 | 2016-08-01 15:44:16 +0800 | [diff] [blame] | 399 | |
Amy Lin | 8c768a7 | 2016-08-01 15:44:16 +0800 | [diff] [blame] | 400 | PlayClient player(config); |
Earl Ou | 5afc8d3 | 2016-12-01 11:30:52 +0800 | [diff] [blame] | 401 | player.Start(); |
Amy Lin | 8c768a7 | 2016-08-01 15:44:16 +0800 | [diff] [blame] | 402 | |
| 403 | RecordClient recorder(config); |
Earl Ou | 5afc8d3 | 2016-12-01 11:30:52 +0800 | [diff] [blame] | 404 | recorder.Start(); |
Amy Lin | 8c768a7 | 2016-08-01 15:44:16 +0800 | [diff] [blame] | 405 | |
| 406 | Evaluator evaluator(config); |
| 407 | |
Amy Lin | 8c768a7 | 2016-08-01 15:44:16 +0800 | [diff] [blame] | 408 | // Starts evaluation. |
Earl Ou | 06c1ad6 | 2016-12-01 17:21:50 +0800 | [diff] [blame] | 409 | ControlLoop(config, &evaluator, &player, &recorder); |
Amy Lin | 8c768a7 | 2016-08-01 15:44:16 +0800 | [diff] [blame] | 410 | |
| 411 | // Terminates and cleans up. |
| 412 | recorder.Terminate(); |
Amy Lin | 8c768a7 | 2016-08-01 15:44:16 +0800 | [diff] [blame] | 413 | player.Terminate(); |
| 414 | |
| 415 | return 0; |
| 416 | } |