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