3 * Bluetooth low-complexity, subband codec (SBC) library
5 * Copyright (C) 2007-2008 Marcel Holtmann <marcel@holtmann.org>
6 * Copyright (C) 2007-2008 Frederic Dalleau <fdalleau@free.fr>
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.
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.
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
38 static double sampletobits(short sample16, int verbose)
45 printf("===> sampletobits(%hd, %04hX)\n", sample16, sample16);
52 printf("%d", (sample16 < 0) ? 1 : 0);
55 for (i = 1; i < 16; i++) {
56 bit = (unsigned short) sample16;
64 bits += (1.0 / pow(2.0, i));
73 static int calculate_rms_level(SNDFILE * sndref, SF_INFO * infosref,
74 SNDFILE * sndtst, SF_INFO * infostst,
75 int accuracy, char *csvname)
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));
83 int i, j, r1, r2, verdict;
86 csv = fopen(csvname, "wt");
90 for (j = 0; j < infostst->channels; j++)
91 fprintf(csv, "ref channel %d;tst channel %d;", j, j);
95 sf_seek(sndref, 0, SEEK_SET);
96 sf_seek(sndtst, 0, SEEK_SET);
98 memset(rms_accu, 0, sizeof(rms_accu));
99 memset(rms_level, 0, sizeof(rms_level));
101 for (i = 0; i < infostst->frames; i++) {
103 fprintf(csv, "%d;", i);
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,
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,
127 for (j = 0; j < infostst->channels; j++) {
129 fprintf(csv, "%d;%d;", refsample[j],
132 refbits = sampletobits(refsample[j], 0);
133 tstbits = sampletobits(tstsample[j], 0);
135 rms_accu[j] += pow(tstbits - refbits, 2.0);
139 fprintf(csv, "\r\n");
142 printf("Limit: %f\n", rms_limit);
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,
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]);
158 for (j = 0; j < infostst->channels; j++) {
159 printf("Channel %d: %f\n", j, rms_level[j]);
161 if (rms_level[j] > rms_limit)
165 printf("%s return %d\n", __FUNCTION__, verdict);
170 static int check_absolute_diff(SNDFILE * sndref, SF_INFO * infosref,
171 SNDFILE * sndtst, SF_INFO * infostst,
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];
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));
190 sf_seek(sndref, 0, SEEK_SET);
191 sf_seek(sndtst, 0, SEEK_SET);
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);
199 if (r1 != infostst->channels) {
200 printf("Failed to read reference data: %s "
201 "(r1=%d, channels=%d)",
202 sf_strerror(sndref), r1,
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,
216 for (j = 0; j < infostst->channels; j++) {
217 refbits = sampletobits(refsample[j], 0);
218 tstbits = sampletobits(tstsample[j], 0);
220 cur_diff = fabs(tstbits - refbits);
222 if (cur_diff > rms_absolute) {
224 /* printf("Channel %d exceeded : fabs(%f - %f) = %f > %f\n", j, tstbits, refbits, cur_diff, rms_absolute); */
228 if (cur_diff > calc_max[j]) {
229 calc_max[j] = cur_diff;
230 refmax[j] = refsample[j];
231 tstmax[j] = tstsample[j];
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]);
242 printf("%s return %d\n", __FUNCTION__, verdict);
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");
254 "\tsbctester reference.wav checkfile.wav\n"
255 "\tsbctester integer\n"
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");
264 printf("\tA file called out.csv is generated to use the data in a\n");
265 printf("\tspreadsheet application or database.\n\n");
268 int main(int argc, char *argv[])
270 SNDFILE *sndref = NULL;
271 SNDFILE *sndtst = NULL;
276 int pass_rms, pass_absolute, pass, accuracy;
281 printf("Test sampletobits\n");
282 db = sampletobits((short) atoi(argv[1]), 1);
283 printf("db = %f\n", db);
295 printf("opening reference %s\n", ref);
297 sndref = sf_open(ref, SFM_READ, &infosref);
299 printf("Failed to open reference file\n");
303 printf("opening testfile %s\n", tst);
304 sndtst = sf_open(tst, SFM_READ, &infostst);
306 printf("Failed to open test file\n");
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);
318 /* check number of channels */
319 if (infosref.channels > 2 || infostst.channels > 2) {
320 printf("Too many channels\n");
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");
331 accuracy = DEFACCURACY;
332 printf("Accuracy: %d\n", accuracy);
334 /* Condition 1 rms level */
335 pass_rms = calculate_rms_level(sndref, &infosref, sndtst, &infostst,
336 accuracy, "out.csv");
340 /* Condition 2 absolute difference */
341 pass_absolute = check_absolute_diff(sndref, &infosref, sndtst,
342 &infostst, accuracy);
343 if (pass_absolute < 0)
347 pass = pass_rms && pass_absolute;
348 printf("Verdict: %s\n", pass ? "pass" : "fail");