OSDN Git Service

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