1/* 2** Copyright (C) 1999-2014 Erik de Castro Lopo <erikd@mega-nerd.com> 3** 4** This program is free software; you can redistribute it and/or modify 5** it under the terms of the GNU General Public License as published by 6** the Free Software Foundation; either version 2 of the License, or 7** (at your option) any later version. 8** 9** This program is distributed in the hope that it will be useful, 10** but WITHOUT ANY WARRANTY; without even the implied warranty of 11** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12** GNU General Public License for more details. 13** 14** You should have received a copy of the GNU General Public License 15** along with this program; if not, write to the Free Software 16** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17*/ 18 19#include "sfconfig.h" 20 21#include <stdio.h> 22#include <stdlib.h> 23#include <string.h> 24#if HAVE_UNISTD_H 25#include <unistd.h> 26#else 27#include "sf_unistd.h" 28#endif 29#include <math.h> 30#include <inttypes.h> 31 32#include <sndfile.h> 33 34#include "utils.h" 35 36#define BUFFER_SIZE (1 << 14) 37#define SAMPLE_RATE (11025) 38 39#ifndef M_PI 40#define M_PI 3.14159265358979323846264338 41#endif 42 43static void lcomp_test_int (const char *str, const char *filename, int filetype, double margin) ; 44 45static int error_function (double data, double orig, double margin) ; 46static int decay_response (int k) ; 47 48static void gen_signal_double (double *data, double scale, int datalen) ; 49 50/* Force the start of these buffers to be double aligned. Sparc-solaris will 51** choke if they are not. 52*/ 53 54typedef union 55{ double d [BUFFER_SIZE + 1] ; 56 int i [BUFFER_SIZE + 1] ; 57} BUFFER ; 58 59static BUFFER data_buffer ; 60static BUFFER orig_buffer ; 61 62int 63main (void) 64{ const char *filename = "test.au" ; 65 66 lcomp_test_int ("au_g721", filename, SF_ENDIAN_BIG | SF_FORMAT_AU | SF_FORMAT_G721_32, 0.06) ; 67 68 return 0 ; 69} /* main */ 70 71/*============================================================================================ 72** Here are the test functions. 73*/ 74 75static void 76lcomp_test_int (const char *str, const char *filename, int filetype, double margin) 77{ SNDFILE *file ; 78 SF_INFO sfinfo ; 79 int k, m, *orig, *data ; 80 sf_count_t datalen, seekpos ; 81 int64_t sum_abs ; 82 double scale ; 83 84 printf ("\nThis is program is not part of the libsndfile test suite.\n\n") ; 85 86 printf (" lcomp_test_int : %s ... ", str) ; 87 fflush (stdout) ; 88 89 datalen = BUFFER_SIZE ; 90 91 scale = 1.0 * 0x10000 ; 92 93 data = data_buffer.i ; 94 orig = orig_buffer.i ; 95 96 gen_signal_double (orig_buffer.d, 32000.0 * scale, datalen) ; 97 for (k = 0 ; k < datalen ; k++) 98 orig [k] = orig_buffer.d [k] ; 99 100 101 sfinfo.samplerate = SAMPLE_RATE ; 102 sfinfo.frames = 123456789 ; /* Ridiculous value. */ 103 sfinfo.channels = 1 ; 104 sfinfo.format = filetype ; 105 106 if (! (file = sf_open (filename, SFM_WRITE, &sfinfo))) 107 { printf ("sf_open_write failed with error : ") ; 108 puts (sf_strerror (NULL)) ; 109 exit (1) ; 110 } ; 111 112 if ((k = sf_writef_int (file, orig, datalen)) != datalen) 113 { printf ("sf_writef_int failed with short write (%" PRId64 " => %d).\n", datalen, k) ; 114 exit (1) ; 115 } ; 116 sf_close (file) ; 117 118 memset (data, 0, datalen * sizeof (int)) ; 119 120 if ((filetype & SF_FORMAT_TYPEMASK) != SF_FORMAT_RAW) 121 memset (&sfinfo, 0, sizeof (sfinfo)) ; 122 123 if (! (file = sf_open (filename, SFM_READ, &sfinfo))) 124 { printf ("sf_open_read failed with error : ") ; 125 puts (sf_strerror (NULL)) ; 126 exit (1) ; 127 } ; 128 129 if ((sfinfo.format & (SF_FORMAT_TYPEMASK | SF_FORMAT_SUBMASK)) != (filetype & (SF_FORMAT_TYPEMASK | SF_FORMAT_SUBMASK))) 130 { printf ("Line %d: Returned format incorrect (0x%08X => 0x%08X).\n", __LINE__, filetype, sfinfo.format) ; 131 exit (1) ; 132 } ; 133 134 if (sfinfo.frames < datalen) 135 { printf ("Too few.frames in file. (%" PRId64 " should be a little more than %" PRId64 ")\n", datalen, sfinfo.frames) ; 136 exit (1) ; 137 } ; 138 139 if (sfinfo.frames > (datalen + datalen / 2)) 140 { printf ("Too many.frames in file. (%" PRId64 " should be a little more than %" PRId64 ")\n", datalen, sfinfo.frames) ; 141 exit (1) ; 142 } ; 143 144 if (sfinfo.channels != 1) 145 { printf ("Incorrect number of channels in file.\n") ; 146 exit (1) ; 147 } ; 148 149 check_log_buffer_or_die (file, __LINE__) ; 150 151 if ((k = sf_readf_int (file, data, datalen)) != datalen) 152 { printf ("Line %d: short read (%d should be %" PRId64 ").\n", __LINE__, k, datalen) ; 153 exit (1) ; 154 } ; 155 156 sum_abs = 0 ; 157 for (k = 0 ; k < datalen ; k++) 158 { if (error_function (data [k] / scale, orig [k] / scale, margin)) 159 { printf ("Line %d: Incorrect sample (#%d : %f should be %f).\n", __LINE__, k, data [k] / scale, orig [k] / scale) ; 160 oct_save_int (orig, data, datalen) ; 161 exit (1) ; 162 } ; 163 sum_abs += abs (data [k]) ; 164 } ; 165 166 if (sum_abs < 1.0) 167 { printf ("Line %d: Signal is all zeros.\n", __LINE__) ; 168 exit (1) ; 169 } ; 170 171 if ((k = sf_readf_int (file, data, datalen)) != sfinfo.frames - datalen) 172 { printf ("Line %d: Incorrect read length (%" PRId64 " should be %d).\n", __LINE__, sfinfo.frames - datalen, k) ; 173 exit (1) ; 174 } ; 175 176 /* This check is only for block based encoders which must append silence 177 ** to the end of a file so as to fill out a block. 178 */ 179 if ((sfinfo.format & SF_FORMAT_SUBMASK) != SF_FORMAT_MS_ADPCM) 180 for (k = 0 ; k < sfinfo.frames - datalen ; k++) 181 if (ABS (data [k] / scale) > decay_response (k)) 182 { printf ("Line %d : Incorrect sample B (#%d : abs (%d) should be < %d).\n", __LINE__, k, data [k], decay_response (k)) ; 183 exit (1) ; 184 } ; 185 186 if (! sfinfo.seekable) 187 { printf ("ok\n") ; 188 return ; 189 } ; 190 191 /* Now test sf_seek function. */ 192 193 if ((k = sf_seek (file, 0, SEEK_SET)) != 0) 194 { printf ("Line %d: Seek to start of file failed (%d).\n", __LINE__, k) ; 195 exit (1) ; 196 } ; 197 198 for (m = 0 ; m < 3 ; m++) 199 { int n ; 200 201 if ((k = sf_readf_int (file, data, 11)) != 11) 202 { printf ("Line %d: Incorrect read length (11 => %d).\n", __LINE__, k) ; 203 exit (1) ; 204 } ; 205 206 for (k = 0 ; k < 11 ; k++) 207 if (error_function (data [k] / scale, orig [k + m * 11] / scale, margin)) 208 { printf ("Line %d: Incorrect sample (m = %d) (#%d : %d => %d).\n", __LINE__, m, k + m * 11, orig [k + m * 11], data [k]) ; 209 for (n = 0 ; n < 1 ; n++) 210 printf ("%d ", data [n]) ; 211 printf ("\n") ; 212 exit (1) ; 213 } ; 214 } ; 215 216 seekpos = BUFFER_SIZE / 10 ; 217 218 /* Check seek from start of file. */ 219 if ((k = sf_seek (file, seekpos, SEEK_SET)) != seekpos) 220 { printf ("Seek to start of file + %" PRId64 " failed (%d).\n", seekpos, k) ; 221 exit (1) ; 222 } ; 223 224 if ((k = sf_readf_int (file, data, 1)) != 1) 225 { printf ("Line %d: sf_readf_int (file, data, 1) returned %d.\n", __LINE__, k) ; 226 exit (1) ; 227 } ; 228 229 if (error_function ((double) data [0], (double) orig [seekpos], margin)) 230 { printf ("Line %d: sf_seek (SEEK_SET) followed by sf_readf_int failed (%d, %d).\n", __LINE__, orig [1], data [0]) ; 231 exit (1) ; 232 } ; 233 234 if ((k = sf_seek (file, 0, SEEK_CUR)) != seekpos + 1) 235 { printf ("Line %d: sf_seek (SEEK_CUR) with 0 offset failed (%d should be %" PRId64 ")\n", __LINE__, k, seekpos + 1) ; 236 exit (1) ; 237 } ; 238 239 seekpos = sf_seek (file, 0, SEEK_CUR) + BUFFER_SIZE / 5 ; 240 k = sf_seek (file, BUFFER_SIZE / 5, SEEK_CUR) ; 241 sf_readf_int (file, data, 1) ; 242 if (error_function ((double) data [0], (double) orig [seekpos], margin) || k != seekpos) 243 { printf ("Line %d: sf_seek (forwards, SEEK_CUR) followed by sf_readf_int failed (%d, %d) (%d, %" PRId64 ").\n", __LINE__, data [0], orig [seekpos], k, seekpos + 1) ; 244 exit (1) ; 245 } ; 246 247 seekpos = sf_seek (file, 0, SEEK_CUR) - 20 ; 248 /* Check seek backward from current position. */ 249 k = sf_seek (file, -20, SEEK_CUR) ; 250 sf_readf_int (file, data, 1) ; 251 if (error_function ((double) data [0], (double) orig [seekpos], margin) || k != seekpos) 252 { printf ("sf_seek (backwards, SEEK_CUR) followed by sf_readf_int failed (%d, %d) (%d, %" PRId64 ").\n", data [0], orig [seekpos], k, seekpos) ; 253 exit (1) ; 254 } ; 255 256 /* Check that read past end of file returns number of items. */ 257 sf_seek (file, (int) sfinfo.frames, SEEK_SET) ; 258 259 if ((k = sf_readf_int (file, data, datalen)) != 0) 260 { printf ("Line %d: Return value from sf_readf_int past end of file incorrect (%d).\n", __LINE__, k) ; 261 exit (1) ; 262 } ; 263 264 /* Check seek backward from end. */ 265 if ((k = sf_seek (file, 5 - (int) sfinfo.frames, SEEK_END)) != 5) 266 { printf ("sf_seek (SEEK_END) returned %d instead of %d.\n", k, 5) ; 267 exit (1) ; 268 } ; 269 270 sf_readf_int (file, data, 1) ; 271 if (error_function (data [0] / scale, orig [5] / scale, margin)) 272 { printf ("Line %d: sf_seek (SEEK_END) followed by sf_readf_short failed (%d should be %d).\n", __LINE__, data [0], orig [5]) ; 273 exit (1) ; 274 } ; 275 276 sf_close (file) ; 277 278 printf ("ok\n") ; 279} /* lcomp_test_int */ 280 281/*======================================================================================== 282** Auxiliary functions 283*/ 284 285#define SIGNAL_MAXVAL 30000.0 286#define DECAY_COUNT 800 287 288static int 289decay_response (int k) 290{ if (k < 1) 291 return (int) (1.2 * SIGNAL_MAXVAL) ; 292 if (k > DECAY_COUNT) 293 return 0 ; 294 return (int) (1.2 * SIGNAL_MAXVAL * (DECAY_COUNT - k) / (1.0 * DECAY_COUNT)) ; 295} /* decay_response */ 296 297static void 298gen_signal_double (double *data, double scale, int datalen) 299{ int k, ramplen ; 300 double amp = 0.0 ; 301 302 ramplen = datalen / 18 ; 303 304 for (k = 0 ; k < datalen ; k++) 305 { if (k <= ramplen) 306 amp = scale * k / ((double) ramplen) ; 307 else if (k > datalen - ramplen) 308 amp = scale * (datalen - k) / ((double) ramplen) ; 309 310 data [k] = amp * (0.4 * sin (33.3 * 2.0 * M_PI * ((double) (k + 1)) / ((double) SAMPLE_RATE)) 311 + 0.3 * cos (201.1 * 2.0 * M_PI * ((double) (k + 1)) / ((double) SAMPLE_RATE))) ; 312 } ; 313 314 return ; 315} /* gen_signal_double */ 316 317static int 318error_function (double data, double orig, double margin) 319{ double error ; 320 321 if (fabs (orig) <= 500.0) 322 error = fabs (fabs (data) - fabs (orig)) / 2000.0 ; 323 else if (fabs (orig) <= 1000.0) 324 error = fabs (data - orig) / 3000.0 ; 325 else 326 error = fabs (data - orig) / fabs (orig) ; 327 328 if (error > margin) 329 { printf ("\n\n*******************\nError : %f\n", error) ; 330 return 1 ; 331 } ; 332 return 0 ; 333} /* error_function */ 334 335