OSDN Git Service

sbc: Update Nokia copyrights
[android-x86/external-bluetooth-sbc.git] / sbc / sbctester.c
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
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
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
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
248 static void usage()
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
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 }