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