1 /* Implements a libSoX internal interface for use in implementing file formats.
2 * All public functions & data are prefixed with lsx_ .
4 * (c) 2005-8 Chris Bagwell and SoX contributors
6 * This library is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or (at
9 * your option) any later version.
11 * This library is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
14 * General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this library; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26 void lsx_fail_errno(sox_format_t
* ft
, int sox_errno
, const char *fmt
, ...)
30 ft
->sox_errno
= sox_errno
;
34 vsnprintf(ft
->sox_errstr
, sizeof(ft
->sox_errstr
), fmt
, args
);
36 vsprintf(ft
->sox_errstr
, fmt
, args
);
39 ft
->sox_errstr
[255] = '\0';
42 void lsx_set_signal_defaults(sox_format_t
* ft
)
44 if (!ft
->signal
.rate
) ft
->signal
.rate
= SOX_DEFAULT_RATE
;
45 if (!ft
->signal
.precision
) ft
->signal
.precision
= SOX_DEFAULT_PRECISION
;
46 if (!ft
->signal
.channels
) ft
->signal
.channels
= SOX_DEFAULT_CHANNELS
;
48 if (!ft
->encoding
.bits_per_sample
)
49 ft
->encoding
.bits_per_sample
= ft
->signal
.precision
;
50 if (ft
->encoding
.encoding
== SOX_ENCODING_UNKNOWN
)
51 ft
->encoding
.encoding
= SOX_ENCODING_SIGN2
;
54 int lsx_check_read_params(sox_format_t
* ft
, unsigned channels
,
55 sox_rate_t rate
, sox_encoding_t encoding
, unsigned bits_per_sample
,
56 off_t num_samples
, sox_bool check_length
)
58 ft
->signal
.length
= ft
->signal
.length
== SOX_IGNORE_LENGTH
? SOX_UNSPEC
: num_samples
;
61 ft
->data_start
= lsx_tell(ft
);
63 if (channels
&& ft
->signal
.channels
&& ft
->signal
.channels
!= channels
)
64 lsx_warn("`%s': overriding number of channels", ft
->filename
);
65 else ft
->signal
.channels
= channels
;
67 if (rate
&& ft
->signal
.rate
&& ft
->signal
.rate
!= rate
)
68 lsx_warn("`%s': overriding sample rate", ft
->filename
);
69 else ft
->signal
.rate
= rate
;
71 if (encoding
&& ft
->encoding
.encoding
&& ft
->encoding
.encoding
!= encoding
)
72 lsx_warn("`%s': overriding encoding type", ft
->filename
);
73 else ft
->encoding
.encoding
= encoding
;
75 if (bits_per_sample
&& ft
->encoding
.bits_per_sample
&& ft
->encoding
.bits_per_sample
!= bits_per_sample
)
76 lsx_warn("`%s': overriding encoding size", ft
->filename
);
77 ft
->encoding
.bits_per_sample
= bits_per_sample
;
79 if (check_length
&& ft
->encoding
.bits_per_sample
&& lsx_filelength(ft
)) {
80 off_t calculated_length
= div_bits(lsx_filelength(ft
) - ft
->data_start
, ft
->encoding
.bits_per_sample
);
81 if (!ft
->signal
.length
)
82 ft
->signal
.length
= calculated_length
;
83 else if (num_samples
!= calculated_length
)
84 lsx_warn("`%s': file header gives the total number of samples as %u but file length indicates the number is in fact %u", ft
->filename
, (unsigned)num_samples
, (unsigned)calculated_length
); /* FIXME: casts */
87 if (sox_precision(ft
->encoding
.encoding
, ft
->encoding
.bits_per_sample
))
89 lsx_fail_errno(ft
, EINVAL
, "invalid format for this file type");
93 /* Read in a buffer of data of length len bytes.
94 * Returns number of bytes read.
96 size_t lsx_readbuf(sox_format_t
* ft
, void *buf
, size_t len
)
98 size_t ret
= fread(buf
, (size_t) 1, len
, ft
->fp
);
99 if (ret
!= len
&& ferror(ft
->fp
))
100 lsx_fail_errno(ft
, errno
, "lsx_readbuf");
105 /* Skip input without seeking. */
106 int lsx_skipbytes(sox_format_t
* ft
, size_t n
)
111 if (lsx_readb(ft
, &trash
) == SOX_EOF
)
114 return (SOX_SUCCESS
);
118 int lsx_padbytes(sox_format_t
* ft
, size_t n
)
121 if (lsx_writeb(ft
, '\0') == SOX_EOF
)
124 return (SOX_SUCCESS
);
127 /* Write a buffer of data of length bytes.
128 * Returns number of bytes written.
130 size_t lsx_writebuf(sox_format_t
* ft
, void const * buf
, size_t len
)
132 size_t ret
= fwrite(buf
, (size_t) 1, len
, ft
->fp
);
134 lsx_fail_errno(ft
, errno
, "error writing output file");
135 clearerr(ft
->fp
); /* Allows us to seek back to write header */
141 size_t lsx_filelength(sox_format_t
* ft
)
144 int ret
= fstat(fileno(ft
->fp
), &st
);
146 return (!ret
&& (st
.st_mode
& S_IFREG
))? (size_t)st
.st_size
: 0;
149 int lsx_flush(sox_format_t
* ft
)
151 return fflush(ft
->fp
);
154 off_t
lsx_tell(sox_format_t
* ft
)
156 return ft
->seekable
? (ptrdiff_t)ftello(ft
->fp
) : ft
->tell_off
;
159 int lsx_eof(sox_format_t
* ft
)
164 int lsx_error(sox_format_t
* ft
)
166 return ferror(ft
->fp
);
169 void lsx_rewind(sox_format_t
* ft
)
175 void lsx_clearerr(sox_format_t
* ft
)
181 int lsx_unreadb(sox_format_t
* ft
, unsigned b
)
183 return ungetc((int)b
, ft
->fp
);
186 /* Implements traditional fseek() behavior. Meant to abstract out
187 * file operations so that they could one day also work on memory
190 * N.B. Can only seek forwards on non-seekable streams!
192 int lsx_seeki(sox_format_t
* ft
, off_t offset
, int whence
)
194 if (ft
->seekable
== 0) {
195 /* If a stream peel off chars else EPERM */
196 if (whence
== SEEK_CUR
) {
197 while (offset
> 0 && !feof(ft
->fp
)) {
203 lsx_fail_errno(ft
,SOX_EOF
, "offset past EOF");
205 ft
->sox_errno
= SOX_SUCCESS
;
207 lsx_fail_errno(ft
,SOX_EPERM
, "file not seekable");
209 if (fseeko(ft
->fp
, offset
, whence
) == -1)
210 lsx_fail_errno(ft
,errno
, "%s", strerror(errno
));
212 ft
->sox_errno
= SOX_SUCCESS
;
214 return ft
->sox_errno
;
217 int lsx_offset_seek(sox_format_t
* ft
, off_t byte_offset
, off_t to_sample
)
219 double wide_sample
= to_sample
- (to_sample
% ft
->signal
.channels
);
220 double to_d
= wide_sample
* ft
->encoding
.bits_per_sample
/ 8;
222 return (to
!= to_d
)? SOX_EOF
: lsx_seeki(ft
, (byte_offset
+ to
), SEEK_SET
);
225 /* Read and write known datatypes in "machine format". Swap if indicated.
226 * They all return SOX_EOF on error and SOX_SUCCESS on success.
228 /* Read n-char string (and possibly null-terminating).
229 * Stop reading and null-terminate string if either a 0 or \n is reached.
231 int lsx_reads(sox_format_t
* ft
, char *c
, size_t len
)
239 if (lsx_readbuf(ft
, &in
, (size_t)1) != 1)
244 if (in
== 0 || in
== '\n')
249 } while (sc
- c
< (ptrdiff_t)len
);
254 /* Write null-terminated string (without \0). */
255 int lsx_writes(sox_format_t
* ft
, char const * c
)
257 if (lsx_writebuf(ft
, c
, strlen(c
)) != strlen(c
))
262 /* return swapped 32-bit float */
263 static void lsx_swapf(float * f
)
271 u
.dw
= (u
.dw
>>24) | ((u
.dw
>>8)&0xff00) | ((u
.dw
<<8)&0xff0000) | (u
.dw
<<24);
275 static void swap(void * data
, size_t len
)
277 uint8_t * bytes
= (uint8_t *)data
;
280 for (i
= 0; i
< len
/ 2; ++i
) {
282 bytes
[i
] = bytes
[len
- 1 - i
];
283 bytes
[len
- 1 - i
] = tmp
;
287 static double lsx_swapdf(double data
)
289 swap(&data
, sizeof(data
));
293 static uint64_t lsx_swapqw(uint64_t data
)
295 swap(&data
, sizeof(data
));
299 /* Lookup table to reverse the bit order of a byte. ie MSB become LSB */
300 static uint8_t const cswap
[256] = {
301 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0,
302 0x30, 0xB0, 0x70, 0xF0, 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
303 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, 0x04, 0x84, 0x44, 0xC4,
304 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
305 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC,
306 0x3C, 0xBC, 0x7C, 0xFC, 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
307 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2, 0x0A, 0x8A, 0x4A, 0xCA,
308 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
309 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6,
310 0x36, 0xB6, 0x76, 0xF6, 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
311 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, 0x01, 0x81, 0x41, 0xC1,
312 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
313 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9,
314 0x39, 0xB9, 0x79, 0xF9, 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
315 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5, 0x0D, 0x8D, 0x4D, 0xCD,
316 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
317 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3,
318 0x33, 0xB3, 0x73, 0xF3, 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
319 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB, 0x07, 0x87, 0x47, 0xC7,
320 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
321 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF,
322 0x3F, 0xBF, 0x7F, 0xFF
325 /* Utilities to byte-swap values, use libc optimized macros if possible */
326 #define TWIDDLE_BYTE(ub, type) \
328 if (ft->encoding.reverse_bits) \
330 if (ft->encoding.reverse_nibbles) \
331 ub = ((ub & 15) << 4) | (ub >> 4); \
334 #define TWIDDLE_WORD(uw, type) \
335 if (ft->encoding.reverse_bytes) \
336 uw = lsx_swap ## type(uw);
338 #define TWIDDLE_FLOAT(f, type) \
339 if (ft->encoding.reverse_bytes) \
342 /* N.B. This macro doesn't work for unaligned types (e.g. 3-byte
344 #define READ_FUNC(type, size, ctype, twiddle) \
345 size_t lsx_read_ ## type ## _buf( \
346 sox_format_t * ft, ctype *buf, size_t len) \
349 nread = lsx_readbuf(ft, buf, len * size) / size; \
350 for (n = 0; n < nread; n++) \
351 twiddle(buf[n], type); \
355 /* Unpack a 3-byte value from a uint8_t * */
356 #define sox_unpack3(p) (ft->encoding.reverse_bytes == MACHINE_IS_BIGENDIAN? \
357 ((p)[0] | ((p)[1] << 8) | ((p)[2] << 16)) : \
358 ((p)[2] | ((p)[1] << 8) | ((p)[0] << 16)))
360 /* This (slower) macro works for unaligned types (e.g. 3-byte types)
361 that need to be unpacked. */
362 #define READ_FUNC_UNPACK(type, size, ctype, twiddle) \
363 size_t lsx_read_ ## type ## _buf( \
364 sox_format_t * ft, ctype *buf, size_t len) \
367 uint8_t *data = lsx_malloc(size * len); \
368 nread = lsx_readbuf(ft, data, len * size) / size; \
369 for (n = 0; n < nread; n++) \
370 buf[n] = sox_unpack ## size(data + n * size); \
375 READ_FUNC(b
, 1, uint8_t, TWIDDLE_BYTE
)
376 READ_FUNC(w
, 2, uint16_t, TWIDDLE_WORD
)
377 READ_FUNC_UNPACK(3, 3, uint24_t
, TWIDDLE_WORD
)
378 READ_FUNC(dw
, 4, uint32_t, TWIDDLE_WORD
)
379 READ_FUNC(qw
, 8, uint64_t, TWIDDLE_WORD
)
380 READ_FUNC(f
, sizeof(float), float, TWIDDLE_FLOAT
)
381 READ_FUNC(df
, sizeof(double), double, TWIDDLE_WORD
)
383 #define READ1_FUNC(type, ctype) \
384 int lsx_read ## type(sox_format_t * ft, ctype * datum) { \
385 if (lsx_read_ ## type ## _buf(ft, datum, (size_t)1) == 1) \
386 return SOX_SUCCESS; \
387 if (!lsx_error(ft)) \
388 lsx_fail_errno(ft, errno, premature_eof); \
392 static char const premature_eof
[] = "premature EOF";
394 READ1_FUNC(b
, uint8_t)
395 READ1_FUNC(w
, uint16_t)
396 READ1_FUNC(3, uint24_t
)
397 READ1_FUNC(dw
, uint32_t)
398 READ1_FUNC(qw
, uint64_t)
400 READ1_FUNC(df
, double)
402 int lsx_readchars(sox_format_t
* ft
, char * chars
, size_t len
)
404 size_t ret
= lsx_readbuf(ft
, chars
, len
);
408 lsx_fail_errno(ft
, errno
, premature_eof
);
412 /* N.B. This macro doesn't work for unaligned types (e.g. 3-byte
414 #define WRITE_FUNC(type, size, ctype, twiddle) \
415 size_t lsx_write_ ## type ## _buf( \
416 sox_format_t * ft, ctype *buf, size_t len) \
418 size_t n, nwritten; \
419 for (n = 0; n < len; n++) \
420 twiddle(buf[n], type); \
421 nwritten = lsx_writebuf(ft, buf, len * size); \
422 return nwritten / size; \
425 /* Pack a 3-byte value to a uint8_t * */
426 #define sox_pack3(p, v) do {if (ft->encoding.reverse_bytes == MACHINE_IS_BIGENDIAN)\
427 {(p)[0] = v & 0xff; (p)[1] = (v >> 8) & 0xff; (p)[2] = (v >> 16) & 0xff;} else \
428 {(p)[2] = v & 0xff; (p)[1] = (v >> 8) & 0xff; (p)[0] = (v >> 16) & 0xff;} \
431 /* This (slower) macro works for unaligned types (e.g. 3-byte types)
432 that need to be packed. */
433 #define WRITE_FUNC_PACK(type, size, ctype, twiddle) \
434 size_t lsx_write_ ## type ## _buf( \
435 sox_format_t * ft, ctype *buf, size_t len) \
437 size_t n, nwritten; \
438 uint8_t *data = lsx_malloc(size * len); \
439 for (n = 0; n < len; n++) \
440 sox_pack ## size(data + n * size, buf[n]); \
441 nwritten = lsx_writebuf(ft, data, len * size); \
443 return nwritten / size; \
446 WRITE_FUNC(b
, 1, uint8_t, TWIDDLE_BYTE
)
447 WRITE_FUNC(w
, 2, uint16_t, TWIDDLE_WORD
)
448 WRITE_FUNC_PACK(3, 3, uint24_t
, TWIDDLE_WORD
)
449 WRITE_FUNC(dw
, 4, uint32_t, TWIDDLE_WORD
)
450 WRITE_FUNC(qw
, 8, uint64_t, TWIDDLE_WORD
)
451 WRITE_FUNC(f
, sizeof(float), float, TWIDDLE_FLOAT
)
452 WRITE_FUNC(df
, sizeof(double), double, TWIDDLE_WORD
)
454 #define WRITE1U_FUNC(type, ctype) \
455 int lsx_write ## type(sox_format_t * ft, unsigned d) \
456 { ctype datum = (ctype)d; \
457 return lsx_write_ ## type ## _buf(ft, &datum, (size_t)1) == 1 ? SOX_SUCCESS : SOX_EOF; \
460 #define WRITE1S_FUNC(type, ctype) \
461 int lsx_writes ## type(sox_format_t * ft, signed d) \
462 { ctype datum = (ctype)d; \
463 return lsx_write_ ## type ## _buf(ft, &datum, (size_t)1) == 1 ? SOX_SUCCESS : SOX_EOF; \
466 #define WRITE1_FUNC(type, ctype) \
467 int lsx_write ## type(sox_format_t * ft, ctype datum) \
469 return lsx_write_ ## type ## _buf(ft, &datum, (size_t)1) == 1 ? SOX_SUCCESS : SOX_EOF; \
472 WRITE1U_FUNC(b
, uint8_t)
473 WRITE1U_FUNC(w
, uint16_t)
474 WRITE1U_FUNC(3, uint24_t
)
475 WRITE1U_FUNC(dw
, uint32_t)
476 WRITE1_FUNC(qw
, uint64_t)
477 WRITE1S_FUNC(b
, uint8_t)
478 WRITE1S_FUNC(w
, uint16_t)
479 WRITE1_FUNC(df
, double)
481 int lsx_writef(sox_format_t
* ft
, double datum
)
484 return lsx_write_f_buf(ft
, &f
, (size_t) 1) == 1 ? SOX_SUCCESS
: SOX_EOF
;