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