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