• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  *  Bluetooth low-complexity, subband codec (SBC) library
4  *
5  *  Copyright (C) 2008-2010  Nokia Corporation
6  *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
7  *  Copyright (C) 2007-2008  Frederic Dalleau <fdalleau@free.fr>
8  *
9  *
10  *  This program is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU General Public License as published by
12  *  the Free Software Foundation; either version 2 of the License, or
13  *  (at your option) any later version.
14  *
15  *  This program is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *  GNU General Public License for more details.
19  *
20  *  You should have received a copy of the GNU General Public License
21  *  along with this program; if not, write to the Free Software
22  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
23  *
24  */
25 
26 #ifdef HAVE_CONFIG_H
27 #include <config.h>
28 #endif
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <sndfile.h>
33 #include <math.h>
34 #include <string.h>
35 
36 #define MAXCHANNELS 2
37 #define DEFACCURACY 7
38 
sampletobits(short sample16,int verbose)39 static double sampletobits(short sample16, int verbose)
40 {
41 	double bits = 0;
42 	unsigned short bit;
43 	int i;
44 
45 	if (verbose)
46 		printf("===> sampletobits(%hd, %04hX)\n", sample16, sample16);
47 
48 	/* Bit 0 is MSB */
49 	if (sample16 < 0)
50 		bits = -1;
51 
52 	if (verbose)
53 		printf("%d", (sample16 < 0) ? 1 : 0);
54 
55 	/* Bit 15 is LSB */
56 	for (i = 1; i < 16; i++) {
57 		bit = (unsigned short) sample16;
58 		bit >>= 15 - i;
59 		bit %= 2;
60 
61 		if (verbose)
62 			printf("%d", bit);
63 
64 		if (bit)
65 			bits += (1.0 / pow(2.0, i));
66 	}
67 
68 	if (verbose)
69 		printf("\n");
70 
71 	return bits;
72 }
73 
calculate_rms_level(SNDFILE * sndref,SF_INFO * infosref,SNDFILE * sndtst,SF_INFO * infostst,int accuracy,char * csvname)74 static int calculate_rms_level(SNDFILE * sndref, SF_INFO * infosref,
75 				SNDFILE * sndtst, SF_INFO * infostst,
76 						int accuracy, char *csvname)
77 {
78 	short refsample[MAXCHANNELS], tstsample[MAXCHANNELS];
79 	double refbits, tstbits;
80 	double rms_accu[MAXCHANNELS];
81 	double rms_level[MAXCHANNELS];
82 	double rms_limit = 1.0 / (pow(2.0, accuracy - 1) * pow(12.0, 0.5));
83 	FILE *csv = NULL;
84 	int i, j, r1, r2, verdict;
85 
86 	if (csvname)
87 		csv = fopen(csvname, "wt");
88 
89 	if (csv) {
90 		fprintf(csv, "num;");
91 		for (j = 0; j < infostst->channels; j++)
92 			fprintf(csv, "ref channel %d;tst channel %d;", j, j);
93 		fprintf(csv, "\r\n");
94 	}
95 
96 	sf_seek(sndref, 0, SEEK_SET);
97 	sf_seek(sndtst, 0, SEEK_SET);
98 
99 	memset(rms_accu, 0, sizeof(rms_accu));
100 	memset(rms_level, 0, sizeof(rms_level));
101 
102 	for (i = 0; i < infostst->frames; i++) {
103 		if (csv)
104 			fprintf(csv, "%d;", i);
105 
106 		r1 = sf_read_short(sndref, refsample, infostst->channels);
107 		if (r1 != infostst->channels) {
108 			printf("Failed to read reference data: %s "
109 					"(r1=%d, channels=%d)",
110 					sf_strerror(sndref), r1,
111 					infostst->channels);
112 			if (csv)
113 				fclose(csv);
114 			return -1;
115 		}
116 
117 		r2 = sf_read_short(sndtst, tstsample, infostst->channels);
118 		if (r2 != infostst->channels) {
119 			printf("Failed to read test data: %s "
120 					"(r2=%d, channels=%d)\n",
121 					sf_strerror(sndtst), r2,
122 					infostst->channels);
123 			if (csv)
124 				fclose(csv);
125 			return -1;
126 		}
127 
128 		for (j = 0; j < infostst->channels; j++) {
129 			if (csv)
130 				fprintf(csv, "%d;%d;", refsample[j],
131 						tstsample[j]);
132 
133 			refbits = sampletobits(refsample[j], 0);
134 			tstbits = sampletobits(tstsample[j], 0);
135 
136 			rms_accu[j] += pow(tstbits - refbits, 2.0);
137 		}
138 
139 		if (csv)
140 			fprintf(csv, "\r\n");
141 	}
142 
143 	printf("Limit: %f\n", rms_limit);
144 
145 	for (j = 0; j < infostst->channels; j++) {
146 		printf("Channel %d\n", j);
147 		printf("Accumulated %f\n", rms_accu[j]);
148 		rms_accu[j] /= (double) infostst->frames;
149 		printf("Accumulated / %f = %f\n", (double) infostst->frames,
150 				rms_accu[j]);
151 		rms_level[j] = sqrt(rms_accu[j]);
152 		printf("Level = %f (%f x %f = %f)\n",
153 				rms_level[j], rms_level[j], rms_level[j],
154 						rms_level[j] * rms_level[j]);
155 	}
156 
157 	verdict = 1;
158 
159 	for (j = 0; j < infostst->channels; j++) {
160 		printf("Channel %d: %f\n", j, rms_level[j]);
161 
162 		if (rms_level[j] > rms_limit)
163 			verdict = 0;
164 	}
165 
166 	printf("%s return %d\n", __FUNCTION__, verdict);
167 
168 	return verdict;
169 }
170 
check_absolute_diff(SNDFILE * sndref,SF_INFO * infosref,SNDFILE * sndtst,SF_INFO * infostst,int accuracy)171 static int check_absolute_diff(SNDFILE * sndref, SF_INFO * infosref,
172 				SNDFILE * sndtst, SF_INFO * infostst,
173 				int accuracy)
174 {
175 	short refsample[MAXCHANNELS], tstsample[MAXCHANNELS];
176 	short refmax[MAXCHANNELS], tstmax[MAXCHANNELS];
177 	double refbits, tstbits;
178 	double rms_absolute = 1.0 / (pow(2, accuracy - 2));
179 	double calc_max[MAXCHANNELS];
180 	int calc_count = 0;
181 	short r1, r2;
182 	double cur_diff;
183 	int i, j, verdict;
184 
185 	memset(&refmax, 0, sizeof(refmax));
186 	memset(&tstmax, 0, sizeof(tstmax));
187 	memset(&calc_max, 0, sizeof(calc_max));
188 	memset(&refsample, 0, sizeof(refsample));
189 	memset(&tstsample, 0, sizeof(tstsample));
190 
191 	sf_seek(sndref, 0, SEEK_SET);
192 	sf_seek(sndtst, 0, SEEK_SET);
193 
194 	verdict = 1;
195 
196 	printf("Absolute max: %f\n", rms_absolute);
197 	for (i = 0; i < infostst->frames; i++) {
198 		r1 = sf_read_short(sndref, refsample, infostst->channels);
199 
200 		if (r1 != infostst->channels) {
201 			printf("Failed to read reference data: %s "
202 					"(r1=%d, channels=%d)",
203 					sf_strerror(sndref), r1,
204 					infostst->channels);
205 			return -1;
206 		}
207 
208 		r2 = sf_read_short(sndtst, tstsample, infostst->channels);
209 		if (r2 != infostst->channels) {
210 			printf("Failed to read test data: %s "
211 					"(r2=%d, channels=%d)\n",
212 					sf_strerror(sndtst), r2,
213 					infostst->channels);
214 			return -1;
215 		}
216 
217 		for (j = 0; j < infostst->channels; j++) {
218 			refbits = sampletobits(refsample[j], 0);
219 			tstbits = sampletobits(tstsample[j], 0);
220 
221 			cur_diff = fabs(tstbits - refbits);
222 
223 			if (cur_diff > rms_absolute) {
224 				calc_count++;
225 				/* printf("Channel %d exceeded : fabs(%f - %f) = %f > %f\n", j, tstbits, refbits, cur_diff, rms_absolute); */
226 				verdict = 0;
227 			}
228 
229 			if (cur_diff > calc_max[j]) {
230 				calc_max[j] = cur_diff;
231 				refmax[j] = refsample[j];
232 				tstmax[j] = tstsample[j];
233 			}
234 		}
235 	}
236 
237 	for (j = 0; j < infostst->channels; j++) {
238 		printf("Calculated max: %f (%hd-%hd=%hd)\n",
239 			calc_max[j], tstmax[j], refmax[j],
240 			tstmax[j] - refmax[j]);
241 	}
242 
243 	printf("%s return %d\n", __FUNCTION__, verdict);
244 
245 	return verdict;
246 }
247 
usage(void)248 static void usage(void)
249 {
250 	printf("SBC conformance test ver %s\n", VERSION);
251 	printf("Copyright (c) 2007-2010  Marcel Holtmann\n");
252 	printf("Copyright (c) 2007-2008  Frederic Dalleau\n\n");
253 
254 	printf("Usage:\n"
255 		"\tsbctester reference.wav checkfile.wav\n"
256 		"\tsbctester integer\n"
257 		"\n");
258 
259 	printf("To test the encoder:\n");
260 	printf("\tUse a reference codec to encode original.wav to reference.sbc\n");
261 	printf("\tUse sbcenc to encode original.wav to checkfile.sbc\n");
262 	printf("\tDecode both file using the reference decoder\n");
263 	printf("\tRun sbctester with these two wav files to get the result\n\n");
264 
265 	printf("\tA file called out.csv is generated to use the data in a\n");
266 	printf("\tspreadsheet application or database.\n\n");
267 }
268 
main(int argc,char * argv[])269 int main(int argc, char *argv[])
270 {
271 	SNDFILE *sndref = NULL;
272 	SNDFILE *sndtst = NULL;
273 	SF_INFO infosref;
274 	SF_INFO infostst;
275 	char *ref;
276 	char *tst;
277 	int pass_rms, pass_absolute, pass, accuracy;
278 
279 	if (argc == 2) {
280 		double db;
281 
282 		printf("Test sampletobits\n");
283 		db = sampletobits((short) atoi(argv[1]), 1);
284 		printf("db = %f\n", db);
285 		exit(0);
286 	}
287 
288 	if (argc < 3) {
289 		usage();
290 		exit(1);
291 	}
292 
293 	ref = argv[1];
294 	tst = argv[2];
295 
296 	printf("opening reference %s\n", ref);
297 
298 	sndref = sf_open(ref, SFM_READ, &infosref);
299 	if (!sndref) {
300 		printf("Failed to open reference file\n");
301 		exit(1);
302 	}
303 
304 	printf("opening testfile %s\n", tst);
305 	sndtst = sf_open(tst, SFM_READ, &infostst);
306 	if (!sndtst) {
307 		printf("Failed to open test file\n");
308 		sf_close(sndref);
309 		exit(1);
310 	}
311 
312 	printf("reference:\n\t%d frames,\n\t%d hz,\n\t%d channels\n",
313 		(int) infosref.frames, (int) infosref.samplerate,
314 		(int) infosref.channels);
315 	printf("testfile:\n\t%d frames,\n\t%d hz,\n\t%d channels\n",
316 		(int) infostst.frames, (int) infostst.samplerate,
317 		(int) infostst.channels);
318 
319 	/* check number of channels */
320 	if (infosref.channels > 2 || infostst.channels > 2) {
321 		printf("Too many channels\n");
322 		goto error;
323 	}
324 
325 	/* compare number of samples */
326 	if (infosref.samplerate != infostst.samplerate ||
327 				infosref.channels != infostst.channels) {
328 		printf("Cannot compare files with different charasteristics\n");
329 		goto error;
330 	}
331 
332 	accuracy = DEFACCURACY;
333 	printf("Accuracy: %d\n", accuracy);
334 
335 	/* Condition 1 rms level */
336 	pass_rms = calculate_rms_level(sndref, &infosref, sndtst, &infostst,
337 					accuracy, "out.csv");
338 	if (pass_rms < 0)
339 		goto error;
340 
341 	/* Condition 2 absolute difference */
342 	pass_absolute = check_absolute_diff(sndref, &infosref, sndtst,
343 						&infostst, accuracy);
344 	if (pass_absolute < 0)
345 		goto error;
346 
347 	/* Verdict */
348 	pass = pass_rms && pass_absolute;
349 	printf("Verdict: %s\n", pass ? "pass" : "fail");
350 
351 	return 0;
352 
353 error:
354 	sf_close(sndref);
355 	sf_close(sndtst);
356 
357 	exit(1);
358 }
359