1c72fcc34Sopenharmony_ci/* 2c72fcc34Sopenharmony_ci * Copyright (C) 2013-2015 Intel Corporation 3c72fcc34Sopenharmony_ci * 4c72fcc34Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 5c72fcc34Sopenharmony_ci * it under the terms of the GNU General Public License as published by 6c72fcc34Sopenharmony_ci * the Free Software Foundation; either version 2 of the License, or 7c72fcc34Sopenharmony_ci * (at your option) any later version. 8c72fcc34Sopenharmony_ci * 9c72fcc34Sopenharmony_ci * This program is distributed in the hope that it will be useful, 10c72fcc34Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 11c72fcc34Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12c72fcc34Sopenharmony_ci * GNU General Public License for more details. 13c72fcc34Sopenharmony_ci * 14c72fcc34Sopenharmony_ci */ 15c72fcc34Sopenharmony_ci 16c72fcc34Sopenharmony_ci#ifndef ATTRIBUTE_UNUSED 17c72fcc34Sopenharmony_ci/** do not print warning (gcc) when function parameter is not used */ 18c72fcc34Sopenharmony_ci#define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) 19c72fcc34Sopenharmony_ci#endif 20c72fcc34Sopenharmony_ci 21c72fcc34Sopenharmony_ci#define TEMP_RECORD_FILE_NAME "/tmp/bat.wav.XXXXXX" 22c72fcc34Sopenharmony_ci#define DEFAULT_DEV_NAME "default" 23c72fcc34Sopenharmony_ci 24c72fcc34Sopenharmony_ci#define OPT_BASE 300 25c72fcc34Sopenharmony_ci#define OPT_LOG (OPT_BASE + 1) 26c72fcc34Sopenharmony_ci#define OPT_READFILE (OPT_BASE + 2) 27c72fcc34Sopenharmony_ci#define OPT_SAVEPLAY (OPT_BASE + 3) 28c72fcc34Sopenharmony_ci#define OPT_LOCAL (OPT_BASE + 4) 29c72fcc34Sopenharmony_ci#define OPT_STANDALONE (OPT_BASE + 5) 30c72fcc34Sopenharmony_ci#define OPT_ROUNDTRIPLATENCY (OPT_BASE + 6) 31c72fcc34Sopenharmony_ci#define OPT_SNRTHD_DB (OPT_BASE + 7) 32c72fcc34Sopenharmony_ci#define OPT_SNRTHD_PC (OPT_BASE + 8) 33c72fcc34Sopenharmony_ci#define OPT_READCAPTURE (OPT_BASE + 9) 34c72fcc34Sopenharmony_ci 35c72fcc34Sopenharmony_ci#define COMPOSE(a, b, c, d) ((a) | ((b)<<8) | ((c)<<16) | ((d)<<24)) 36c72fcc34Sopenharmony_ci#define WAV_RIFF COMPOSE('R', 'I', 'F', 'F') 37c72fcc34Sopenharmony_ci#define WAV_WAVE COMPOSE('W', 'A', 'V', 'E') 38c72fcc34Sopenharmony_ci#define WAV_FMT COMPOSE('f', 'm', 't', ' ') 39c72fcc34Sopenharmony_ci#define WAV_DATA COMPOSE('d', 'a', 't', 'a') 40c72fcc34Sopenharmony_ci#define WAV_FORMAT_PCM 1 /* PCM WAVE file encoding */ 41c72fcc34Sopenharmony_ci 42c72fcc34Sopenharmony_ci#define MAX_CHANNELS 2 43c72fcc34Sopenharmony_ci#define MIN_CHANNELS 1 44c72fcc34Sopenharmony_ci#define MAX_PEAKS 10 45c72fcc34Sopenharmony_ci#define MAX_FRAMES (10 * 1024 * 1024) 46c72fcc34Sopenharmony_ci/* Given in ms */ 47c72fcc34Sopenharmony_ci#define CAPTURE_DELAY 500 48c72fcc34Sopenharmony_ci/* signal frequency should be less than samplerate * RATE_FACTOR */ 49c72fcc34Sopenharmony_ci#define RATE_FACTOR 0.4 50c72fcc34Sopenharmony_ci/* valid range of samplerate: (1 - RATE_RANGE, 1 + RATE_RANGE) * samplerate */ 51c72fcc34Sopenharmony_ci#define RATE_RANGE 0.05 52c72fcc34Sopenharmony_ci/* Given in us */ 53c72fcc34Sopenharmony_ci#define MAX_BUFFERTIME 500000 54c72fcc34Sopenharmony_ci/* devide factor, was 4, changed to 8 to remove reduce capture overrun */ 55c72fcc34Sopenharmony_ci#define DIV_BUFFERTIME 8 56c72fcc34Sopenharmony_ci/* margin to avoid sign inversion when generate sine wav */ 57c72fcc34Sopenharmony_ci#define RANGE_FACTOR 0.95 58c72fcc34Sopenharmony_ci#define MAX_BUFFERSIZE 200000 59c72fcc34Sopenharmony_ci#define MIN_BUFFERSIZE 32 60c72fcc34Sopenharmony_ci#define MAX_PERIODSIZE 200000 61c72fcc34Sopenharmony_ci#define MIN_PERIODSIZE 32 62c72fcc34Sopenharmony_ci/* default period size for tinyalsa */ 63c72fcc34Sopenharmony_ci#define TINYALSA_PERIODSIZE 1024 64c72fcc34Sopenharmony_ci 65c72fcc34Sopenharmony_ci#define LATENCY_TEST_NUMBER 5 66c72fcc34Sopenharmony_ci#define LATENCY_TEST_TIME_LIMIT 25 67c72fcc34Sopenharmony_ci#define DIV_BUFFERSIZE 2 68c72fcc34Sopenharmony_ci 69c72fcc34Sopenharmony_ci#define EBATBASE 1000 70c72fcc34Sopenharmony_ci#define ENOPEAK (EBATBASE + 1) 71c72fcc34Sopenharmony_ci#define EONLYDC (EBATBASE + 2) 72c72fcc34Sopenharmony_ci#define EBADPEAK (EBATBASE + 3) 73c72fcc34Sopenharmony_ci 74c72fcc34Sopenharmony_ci#define DC_THRESHOLD 7.01 75c72fcc34Sopenharmony_ci 76c72fcc34Sopenharmony_ci/* tolerance of detected peak = max (DELTA_HZ, DELTA_RATE * target_freq). 77c72fcc34Sopenharmony_ci * If DELTA_RATE is too high, BAT may not be able to recognize negative result; 78c72fcc34Sopenharmony_ci * if too low, BAT may be too sensitive and results in uncecessary failure. */ 79c72fcc34Sopenharmony_ci#define DELTA_RATE 0.005 80c72fcc34Sopenharmony_ci#define DELTA_HZ 1 81c72fcc34Sopenharmony_ci 82c72fcc34Sopenharmony_ci#define FOUND_DC (1<<1) 83c72fcc34Sopenharmony_ci#define FOUND_WRONG_PEAK (1<<0) 84c72fcc34Sopenharmony_ci 85c72fcc34Sopenharmony_ci/* Truncate sample frames to (1 << N), for faster FFT analysis process. The 86c72fcc34Sopenharmony_ci * valid range of N is (SHIFT_MIN, SHIFT_MAX). When N increases, the analysis 87c72fcc34Sopenharmony_ci * will be more time-consuming, and the result will be more accurate. */ 88c72fcc34Sopenharmony_ci#define SHIFT_MAX (sizeof(int) * 8 - 2) 89c72fcc34Sopenharmony_ci#define SHIFT_MIN 8 90c72fcc34Sopenharmony_ci 91c72fcc34Sopenharmony_ci/* Define SNR range in dB. 92c72fcc34Sopenharmony_ci * if the noise is equal to signal, SNR = 0.0dB; 93c72fcc34Sopenharmony_ci * if the noise is zero, SNR is limited by RIFF wav data width: 94c72fcc34Sopenharmony_ci * 8 bit --> 20.0 * log10f (powf(2.0, 8.0)) = 48.16 dB 95c72fcc34Sopenharmony_ci * 16 bit --> 20.0 * log10f (powf(2.0, 16.0)) = 96.33 dB 96c72fcc34Sopenharmony_ci * 24 bit --> 20.0 * log10f (powf(2.0, 24.0)) = 144.49 dB 97c72fcc34Sopenharmony_ci * 32 bit --> 20.0 * log10f (powf(2.0, 32.0)) = 192.66 dB 98c72fcc34Sopenharmony_ci * so define the SNR range (0.0, 200.0) dB, value out of range is invalid. */ 99c72fcc34Sopenharmony_ci#define SNR_DB_INVALID -1.0 100c72fcc34Sopenharmony_ci#define SNR_DB_MIN 0.0 101c72fcc34Sopenharmony_ci#define SNR_DB_MAX 200.0 102c72fcc34Sopenharmony_ci 103c72fcc34Sopenharmony_cistatic inline bool snr_is_valid(float db) 104c72fcc34Sopenharmony_ci{ 105c72fcc34Sopenharmony_ci return (db > SNR_DB_MIN && db < SNR_DB_MAX); 106c72fcc34Sopenharmony_ci} 107c72fcc34Sopenharmony_ci 108c72fcc34Sopenharmony_cistruct wav_header { 109c72fcc34Sopenharmony_ci unsigned int magic; /* 'RIFF' */ 110c72fcc34Sopenharmony_ci unsigned int length; /* file len */ 111c72fcc34Sopenharmony_ci unsigned int type; /* 'WAVE' */ 112c72fcc34Sopenharmony_ci}; 113c72fcc34Sopenharmony_ci 114c72fcc34Sopenharmony_cistruct wav_chunk_header { 115c72fcc34Sopenharmony_ci unsigned int type; /* 'data' */ 116c72fcc34Sopenharmony_ci unsigned int length; /* sample count */ 117c72fcc34Sopenharmony_ci}; 118c72fcc34Sopenharmony_ci 119c72fcc34Sopenharmony_cistruct wav_fmt { 120c72fcc34Sopenharmony_ci unsigned int magic; /* 'FMT '*/ 121c72fcc34Sopenharmony_ci unsigned int fmt_size; /* 16 or 18 */ 122c72fcc34Sopenharmony_ci unsigned short format; /* see WAV_FMT_* */ 123c72fcc34Sopenharmony_ci unsigned short channels; 124c72fcc34Sopenharmony_ci unsigned int sample_rate; /* Frequency of sample */ 125c72fcc34Sopenharmony_ci unsigned int bytes_p_second; 126c72fcc34Sopenharmony_ci unsigned short blocks_align; /* sample size; 1 or 2 bytes */ 127c72fcc34Sopenharmony_ci unsigned short sample_length; /* 8, 12 or 16 bit */ 128c72fcc34Sopenharmony_ci}; 129c72fcc34Sopenharmony_ci 130c72fcc34Sopenharmony_cistruct chunk_fmt { 131c72fcc34Sopenharmony_ci unsigned short format; /* see WAV_FMT_* */ 132c72fcc34Sopenharmony_ci unsigned short channels; 133c72fcc34Sopenharmony_ci unsigned int sample_rate; /* Frequency of sample */ 134c72fcc34Sopenharmony_ci unsigned int bytes_p_second; 135c72fcc34Sopenharmony_ci unsigned short blocks_align; /* sample size; 1 or 2 bytes */ 136c72fcc34Sopenharmony_ci unsigned short sample_length; /* 8, 12 or 16 bit */ 137c72fcc34Sopenharmony_ci}; 138c72fcc34Sopenharmony_ci 139c72fcc34Sopenharmony_cistruct wav_container { 140c72fcc34Sopenharmony_ci struct wav_header header; 141c72fcc34Sopenharmony_ci struct wav_fmt format; 142c72fcc34Sopenharmony_ci struct wav_chunk_header chunk; 143c72fcc34Sopenharmony_ci}; 144c72fcc34Sopenharmony_ci 145c72fcc34Sopenharmony_cistruct bat; 146c72fcc34Sopenharmony_ci 147c72fcc34Sopenharmony_cienum _bat_pcm_format { 148c72fcc34Sopenharmony_ci BAT_PCM_FORMAT_UNKNOWN = -1, 149c72fcc34Sopenharmony_ci BAT_PCM_FORMAT_S16_LE = 0, 150c72fcc34Sopenharmony_ci BAT_PCM_FORMAT_S32_LE, 151c72fcc34Sopenharmony_ci BAT_PCM_FORMAT_U8, 152c72fcc34Sopenharmony_ci BAT_PCM_FORMAT_S24_3LE, 153c72fcc34Sopenharmony_ci BAT_PCM_FORMAT_MAX 154c72fcc34Sopenharmony_ci}; 155c72fcc34Sopenharmony_ci 156c72fcc34Sopenharmony_cienum _bat_op_mode { 157c72fcc34Sopenharmony_ci MODE_UNKNOWN = -1, 158c72fcc34Sopenharmony_ci MODE_SINGLE = 0, 159c72fcc34Sopenharmony_ci MODE_LOOPBACK, 160c72fcc34Sopenharmony_ci MODE_ANALYZE_ONLY, 161c72fcc34Sopenharmony_ci MODE_LAST 162c72fcc34Sopenharmony_ci}; 163c72fcc34Sopenharmony_ci 164c72fcc34Sopenharmony_cienum latency_state { 165c72fcc34Sopenharmony_ci LATENCY_STATE_COMPLETE_FAILURE = -1, 166c72fcc34Sopenharmony_ci LATENCY_STATE_COMPLETE_SUCCESS = 0, 167c72fcc34Sopenharmony_ci LATENCY_STATE_MEASURE_FOR_1_SECOND, 168c72fcc34Sopenharmony_ci LATENCY_STATE_PLAY_AND_LISTEN, 169c72fcc34Sopenharmony_ci LATENCY_STATE_WAITING, 170c72fcc34Sopenharmony_ci}; 171c72fcc34Sopenharmony_ci 172c72fcc34Sopenharmony_cistruct pcm { 173c72fcc34Sopenharmony_ci unsigned int card_tiny; 174c72fcc34Sopenharmony_ci unsigned int device_tiny; 175c72fcc34Sopenharmony_ci char *device; 176c72fcc34Sopenharmony_ci char *file; 177c72fcc34Sopenharmony_ci enum _bat_op_mode mode; 178c72fcc34Sopenharmony_ci void *(*fct)(struct bat *); 179c72fcc34Sopenharmony_ci}; 180c72fcc34Sopenharmony_ci 181c72fcc34Sopenharmony_cistruct sin_generator; 182c72fcc34Sopenharmony_ci 183c72fcc34Sopenharmony_cistruct sin_generator { 184c72fcc34Sopenharmony_ci double state_real; 185c72fcc34Sopenharmony_ci double state_imag; 186c72fcc34Sopenharmony_ci double phasor_real; 187c72fcc34Sopenharmony_ci double phasor_imag; 188c72fcc34Sopenharmony_ci float frequency; 189c72fcc34Sopenharmony_ci float sample_rate; 190c72fcc34Sopenharmony_ci float magnitude; 191c72fcc34Sopenharmony_ci}; 192c72fcc34Sopenharmony_ci 193c72fcc34Sopenharmony_cistruct roundtrip_latency { 194c72fcc34Sopenharmony_ci int number; 195c72fcc34Sopenharmony_ci enum latency_state state; 196c72fcc34Sopenharmony_ci float result[LATENCY_TEST_NUMBER]; 197c72fcc34Sopenharmony_ci int final_result; 198c72fcc34Sopenharmony_ci int samples; 199c72fcc34Sopenharmony_ci float sum; 200c72fcc34Sopenharmony_ci int threshold; 201c72fcc34Sopenharmony_ci int error; 202c72fcc34Sopenharmony_ci bool is_capturing; 203c72fcc34Sopenharmony_ci bool is_playing; 204c72fcc34Sopenharmony_ci bool xrun_error; 205c72fcc34Sopenharmony_ci}; 206c72fcc34Sopenharmony_ci 207c72fcc34Sopenharmony_cistruct noise_analyzer { 208c72fcc34Sopenharmony_ci int nsamples; /* number of sample */ 209c72fcc34Sopenharmony_ci float *source; /* single-tone to be analyzed */ 210c72fcc34Sopenharmony_ci float *target; /* target single-tone as standard */ 211c72fcc34Sopenharmony_ci float rms_tgt; /* rms of target single-tone */ 212c72fcc34Sopenharmony_ci float snr_db; /* snr in dB */ 213c72fcc34Sopenharmony_ci}; 214c72fcc34Sopenharmony_ci 215c72fcc34Sopenharmony_cistruct bat { 216c72fcc34Sopenharmony_ci unsigned int rate; /* sampling rate */ 217c72fcc34Sopenharmony_ci int channels; /* nb of channels */ 218c72fcc34Sopenharmony_ci int frames; /* nb of frames */ 219c72fcc34Sopenharmony_ci int frame_size; /* size of frame */ 220c72fcc34Sopenharmony_ci int sample_size; /* size of sample */ 221c72fcc34Sopenharmony_ci enum _bat_pcm_format format; /* PCM format */ 222c72fcc34Sopenharmony_ci int buffer_size; /* buffer size in frames */ 223c72fcc34Sopenharmony_ci int period_size; /* period size in frames */ 224c72fcc34Sopenharmony_ci 225c72fcc34Sopenharmony_ci float sigma_k; /* threshold for peak detection */ 226c72fcc34Sopenharmony_ci float snr_thd_db; /* threshold for noise detection (dB) */ 227c72fcc34Sopenharmony_ci float target_freq[MAX_CHANNELS]; 228c72fcc34Sopenharmony_ci 229c72fcc34Sopenharmony_ci int sinus_duration; /* number of frames for playback */ 230c72fcc34Sopenharmony_ci char *narg; /* argument string of duration */ 231c72fcc34Sopenharmony_ci char *logarg; /* path name of log file */ 232c72fcc34Sopenharmony_ci char *debugplay; /* path name to store playback signal */ 233c72fcc34Sopenharmony_ci char *capturefile; /* path name for previously saved recording */ 234c72fcc34Sopenharmony_ci bool standalone; /* enable to bypass analysis */ 235c72fcc34Sopenharmony_ci bool roundtriplatency; /* enable round trip latency */ 236c72fcc34Sopenharmony_ci 237c72fcc34Sopenharmony_ci struct pcm playback; 238c72fcc34Sopenharmony_ci struct pcm capture; 239c72fcc34Sopenharmony_ci struct roundtrip_latency latency; 240c72fcc34Sopenharmony_ci 241c72fcc34Sopenharmony_ci unsigned int periods_played; 242c72fcc34Sopenharmony_ci unsigned int periods_total; 243c72fcc34Sopenharmony_ci bool period_is_limited; 244c72fcc34Sopenharmony_ci 245c72fcc34Sopenharmony_ci FILE *fp; 246c72fcc34Sopenharmony_ci 247c72fcc34Sopenharmony_ci FILE *log; 248c72fcc34Sopenharmony_ci FILE *err; 249c72fcc34Sopenharmony_ci 250c72fcc34Sopenharmony_ci void (*convert_sample_to_float)(void *, float *, int); 251c72fcc34Sopenharmony_ci void (*convert_float_to_sample)(float *, void *, int, int); 252c72fcc34Sopenharmony_ci 253c72fcc34Sopenharmony_ci void *buf; /* PCM Buffer */ 254c72fcc34Sopenharmony_ci 255c72fcc34Sopenharmony_ci bool local; /* true for internal test */ 256c72fcc34Sopenharmony_ci}; 257c72fcc34Sopenharmony_ci 258c72fcc34Sopenharmony_cistruct analyze { 259c72fcc34Sopenharmony_ci void *buf; 260c72fcc34Sopenharmony_ci float *in; 261c72fcc34Sopenharmony_ci float *out; 262c72fcc34Sopenharmony_ci float *mag; 263c72fcc34Sopenharmony_ci}; 264c72fcc34Sopenharmony_ci 265c72fcc34Sopenharmony_civoid prepare_wav_info(struct wav_container *, struct bat *); 266c72fcc34Sopenharmony_ciint read_wav_header(struct bat *, char *, FILE *, bool); 267c72fcc34Sopenharmony_ciint write_wav_header(FILE *, struct wav_container *, struct bat *); 268c72fcc34Sopenharmony_ciint update_wav_header(struct bat *, FILE *, int); 269c72fcc34Sopenharmony_ciint generate_input_data(struct bat *, void *, int, int); 270