ref: 40ad2f19bc2ec47e7b3b1e08a9903e82e8624954
parent: 280fbd36331c6e0b6607fc72ced19b16f8a1b1f2
author: robs <robs>
date: Sun Mar 16 03:52:57 EDT 2008
Can now write Sounder files Can now write DEC-variant au files (with -x) Comments support for SoundTool files Fix IRCAM SF header processing; support all (modern) variants Fix 24-bit read/write on big-endian systems For some file-types, warn if file size seems too short Added auto-detect for caf, sndr, txw & sf files Fix endian selection (-B, -L, -x) in some circumstances Reimplement (separately) SoundTool & Sounder format handlers
--- a/ChangeLog
+++ b/ChangeLog
@@ -26,12 +26,6 @@
o New option --help-format shows info about supported format(s). (robs)
o New htk format. (robs)
- o Fix [1864216] comments mangled when writing ogg-vorbis. (robs)
- o Fix short noise at end of alsa playback. (Morita Sho/Tim Munro/robs)
- o Fix wve seek accuracy. (robs)
- o Fix lpc10 not working. (robs)
- o Fix [1187257] wav MS-ADPCM block-align size incorrect. (robs)
- o For wav & au, fix [548256] size in header wrong when piping out. (robs)
o Writing aiff, aifc & dvms now repeatable with -R. (robs)
o Writing hcom no longer fails with unsupported rate--chooses
best match. (robs)
@@ -40,6 +34,17 @@
o Can now write .amb (.wav variant) files [FR 1902232]. (robs)
o Can now read 2,3(2.6),4 bit ADPCM .voc files [FR 1714991]. (robs)
o Can now read some MP3 ID3 tags. (robs)
+ o Can now write Sounder files. (robs)
+ o Can now write DEC-variant au files (with -x). (robs)
+ o Comments support for SoundTool files. (robs)
+ o Fix [1864216] comments mangled when writing ogg-vorbis. (robs)
+ o Fix short noise at end of alsa playback. (Morita Sho/Tim Munro/robs)
+ o Fix wve seek accuracy. (robs)
+ o Fix lpc10 not working. (robs)
+ o Fix [1187257] wav MS-ADPCM block-align size incorrect. (robs)
+ o For wav & au, fix [548256] size in header wrong when piping out. (robs)
+ o Fix IRCAM SF header processing; support all (modern) variants. (robs)
+ o Fix 24-bit read/write on big-endian systems. (robs)
Effects:
@@ -69,6 +74,8 @@
and default audio device (all). (robs)
o Simpler file info display for `play'. (robs)
o New `multiply' method for the input file combiner. (robs)
+ o For some file-types, warn if file size seems too short. (robs)
+ o Added auto-detect for caf, sndr, txw & sf files. (robs)
Other bug fixes:
@@ -75,14 +82,15 @@
o Fix [1890983] rec shortcut should apply bit depth (8-bit,
16-bit, etc.) to input handler. (robs)
o Fix auto-detect of hcom files. (robs)
- o Added auto-detect for caf, txw & sf files. (robs)
o Fix ungraceful handling of out of disc space and other write
errors (bug was introduced in 14.0.0). (robs)
+ o Fix endian selection (-B, -L, -x) in some circumstances. (robs)
Internal improvements:
o Use FORTIFY_SOURCE with gcc. (robs)
o Fixed all compiler warnings (AFAICT). (robs)
+ o Reimplement (separately) SoundTool & Sounder format handlers. (robs)
Deprecated features to be removed in future:
--- a/src/8svx.c
+++ b/src/8svx.c
@@ -341,7 +341,7 @@
sox_writedw(ft, nsamples/ft->signal.channels); /* samples, 1-shot */
sox_writedw(ft, 0); /* samples, repeat */
sox_writedw(ft, 0); /* samples per repeat cycle */
- sox_writew(ft, (uint16_t)ft->signal.rate); /* samples per second */
+ sox_writew(ft, min(65535, (unsigned)(ft->signal.rate + .5)));
sox_writeb(ft,1); /* number of octabes */
sox_writeb(ft,0); /* data compression (none) */
sox_writew(ft,1); sox_writew(ft,0); /* volume */
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -30,17 +30,17 @@
dither key pitch speed vol
)
set(formats_srcs
- 8svx cvsd-fmt htk s1-fmt u2-fmt
- adpcm dat ima-fmt s2-fmt u3-fmt
- adpcms dvms-fmt ima_rw s3-fmt u4-fmt
- aifc-fmt formats la-fmt s4-fmt ul-fmt
- aiff g711 lpc10.c sf voc
- aiff-fmt g721 lu-fmt skelform vox
- al-fmt g723_24 maud smp vox-fmt
- au g723_40 nulfile sndrtool wav
- avr g72x prc sphere wve
- cdr gsm.c raw tx16w xa
- cvsd hcom raw-fmt u1-fmt
+ 8svx cvsd-fmt htk s1-fmt u1-fmt
+ adpcm dat ima-fmt s2-fmt u2-fmt
+ adpcms dvms-fmt ima_rw s3-fmt u3-fmt
+ aifc-fmt formats la-fmt s4-fmt u4-fmt
+ aiff g711 lpc10.c sf ul-fmt
+ aiff-fmt g721 lu-fmt skelform voc
+ al-fmt g723_24 maud smp vox
+ au g723_40 nulfile sounder vox-fmt
+ avr g72x prc soundtool wav
+ cdr gsm.c raw sphere wve
+ cvsd hcom raw-fmt tx16w xa
)
add_library(lib${PROJECT_NAME}
${effects_srcs} misc util
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -40,11 +40,11 @@
libsox_fmt_cdr.la libsox_fmt_cvsd.la libsox_fmt_dvms.la \
libsox_fmt_dat.la libsox_fmt_gsm.la libsox_fmt_hcom.la \
libsox_fmt_lpc10.la libsox_fmt_maud.la libsox_fmt_prc.la \
- libsox_fmt_sf.la libsox_fmt_smp.la libsox_fmt_sndrtool.la \
+ libsox_fmt_sf.la libsox_fmt_smp.la \
libsox_fmt_sphere.la libsox_fmt_txw.la libsox_fmt_voc.la \
libsox_fmt_vox.la libsox_fmt_ima.la libsox_fmt_wav.la \
libsox_fmt_wve.la libsox_fmt_xa.la libsox_fmt_nul.la \
- libsox_fmt_htk.la
+ libsox_fmt_htk.la libsox_fmt_sounder.la libsox_fmt_soundtool.la
# File formats
libsox_fmt_raw_la_SOURCES = raw-fmt.c
@@ -103,12 +103,14 @@
libsox_fmt_maud_la_LIBADD = libsox.la
libsox_fmt_prc_la_SOURCES = prc.c
libsox_fmt_prc_la_LIBADD = libsox.la
-libsox_fmt_sf_la_SOURCES = sf.c sfircam.h
+libsox_fmt_sf_la_SOURCES = sf.c
libsox_fmt_sf_la_LIBADD = libsox.la
libsox_fmt_smp_la_SOURCES = smp.c
libsox_fmt_smp_la_LIBADD = libsox.la
-libsox_fmt_sndrtool_la_SOURCES = sndrtool.c
-libsox_fmt_sndrtool_la_LIBADD = libsox.la
+libsox_fmt_sounder_la_SOURCES = sounder.c
+libsox_fmt_sounder_la_LIBADD = libsox.la
+libsox_fmt_soundtool_la_SOURCES = soundtool.c
+libsox_fmt_soundtool_la_LIBADD = libsox.la
libsox_fmt_sphere_la_SOURCES = sphere.c
libsox_fmt_sphere_la_LIBADD = libsox.la
libsox_fmt_txw_la_SOURCES = tx16w.c
@@ -218,8 +220,8 @@
libsox_la_SOURCES += raw-fmt.c s1-fmt.c s2-fmt.c s3-fmt.c \
s4-fmt.c u1-fmt.c u2-fmt.c u3-fmt.c u4-fmt.c al-fmt.c la-fmt.c ul-fmt.c \
lu-fmt.c 8svx.c aiff-fmt.c aifc-fmt.c au.c avr.c cdr.c cvsd-fmt.c \
- dvms-fmt.c dat.c gsm.c hcom.c htk.c lpc10.c maud.c prc.c sf.c sfircam.h smp.c \
- sndrtool.c sphere.c tx16w.c voc.c vox-fmt.c ima-fmt.c adpcm.c adpcm.h \
+ dvms-fmt.c dat.c gsm.c hcom.c htk.c lpc10.c maud.c prc.c sf.c smp.c \
+ sounder.c soundtool.c sphere.c tx16w.c voc.c vox-fmt.c ima-fmt.c adpcm.c adpcm.h \
ima_rw.c ima_rw.h wav.c wav.h wve.c xa.c nulfile.c
libsox_la_LIBADD = @GSM_LIBS@ @LIBGSM_LIBADD@
libsox_la_LIBADD += ../lpc10/liblpc10.la
--- a/src/au.c
+++ b/src/au.c
@@ -14,7 +14,6 @@
* We support only the common formats, plus
* CCITT G.721 (32 kbit/s) and G.723 (24/40 kbit/s),
* courtesy of Sun's public domain implementation.
- * Output is always in big-endian (Sun/NeXT) order.
*/
#include "sox_i.h"
@@ -22,11 +21,14 @@
#include <string.h>
/* Magic numbers used in Sun and NeXT audio files */
-#define SUN_MAGIC 0x2e736e64 /* Really '.snd' */
-#define SUN_INV_MAGIC 0x646e732e /* '.snd' reversed bytes */
-#define DEC_MAGIC 0x2e736400 /* Really '\0ds.' (for DEC) */
-#define DEC_INV_MAGIC 0x0064732e /* '\0ds.' reversed bytes */
-#define SUN_HDRSIZE 24 /* Size of minimal header */
+static struct {char str[4]; sox_bool reverse_bytes; char const * desc;} id[] = {
+ {"\x2e\x73\x6e\x64", SOX_IS_LITTLEENDIAN, "Big-endian .snd"},
+ {"\x64\x6e\x73\x2e", SOX_IS_BIGENDIAN , "Little-endian .snd"},
+ {"\x00\x64\x73\x2e", SOX_IS_BIGENDIAN , "Little-endian '\0ds.' (for DEC)"},
+ {"\x2e\x73\x64\x00", SOX_IS_LITTLEENDIAN, "Big-endian '\0ds.'"},
+ {" ", 0, NULL}
+};
+#define FIXED_HDR 24
#define SUN_UNSPEC ~0u /* Unspecified data size (this is legal) */
typedef enum {
@@ -34,7 +36,7 @@
Double, Indirect, Nested, Dsp_core, Dsp_data_8, Dsp_data_16, Dsp_data_24,
Dsp_data_32, Unknown, Display, Mulaw_squelch, Emphasized, Compressed,
Compressed_emphasized, Dsp_commands, Dsp_commands_samples, Adpcm_g721,
- Adpcm_g722, Adpcm_g723_3, Adpcm_g723_5, Alaw_8, Unknown_other} sun_encoding_t;
+ Adpcm_g722, Adpcm_g723_3, Adpcm_g723_5, Alaw_8, Unknown_other} ft_encoding_t;
static char const * const str[] = {
"Unspecified", "8-bit mu-law", "8-bit signed linear", "16-bit signed linear",
"24-bit signed linear", "32-bit signed linear", "Floating-point",
@@ -46,40 +48,35 @@
"Music Kit DSP samples", "4-bit G.721 ADPCM", "G.722 ADPCM",
"3-bit G.723 ADPCM", "5-bit G.723 ADPCM", "8-bit a-law", "Unknown"};
-static sun_encoding_t sun_enc(unsigned size, sox_encoding_t sox_enc)
+static ft_encoding_t ft_enc(unsigned size, sox_encoding_t encoding)
{
- sun_encoding_t result = Unspecified;
- if (sox_enc == SOX_ENCODING_ULAW && size == 8) result = Mulaw_8;
- else if (sox_enc == SOX_ENCODING_ALAW && size == 8) result = Alaw_8;
- else if (sox_enc == SOX_ENCODING_SIGN2 && size == 8) result = Linear_8;
- else if (sox_enc == SOX_ENCODING_SIGN2 && size == 16) result = Linear_16;
- else if (sox_enc == SOX_ENCODING_SIGN2 && size == 24) result = Linear_24;
- else if (sox_enc == SOX_ENCODING_SIGN2 && size == 32) result = Linear_32;
- else if (sox_enc == SOX_ENCODING_FLOAT && size == 32) result = Float;
- else if (sox_enc == SOX_ENCODING_FLOAT && size == 64) result = Double;
- return result;
+ if (encoding == SOX_ENCODING_ULAW && size == 8) return Mulaw_8;
+ if (encoding == SOX_ENCODING_ALAW && size == 8) return Alaw_8;
+ if (encoding == SOX_ENCODING_SIGN2 && size == 8) return Linear_8;
+ if (encoding == SOX_ENCODING_SIGN2 && size == 16) return Linear_16;
+ if (encoding == SOX_ENCODING_SIGN2 && size == 24) return Linear_24;
+ if (encoding == SOX_ENCODING_SIGN2 && size == 32) return Linear_32;
+ if (encoding == SOX_ENCODING_FLOAT && size == 32) return Float;
+ if (encoding == SOX_ENCODING_FLOAT && size == 64) return Double;
+ return Unspecified;
}
-static int sox_enc(
- uint32_t sun_encoding, sox_encoding_t * encoding, unsigned * size)
+static sox_encoding_t sox_enc(uint32_t ft_encoding, unsigned * size)
{
- switch (sun_encoding) {
- case Mulaw_8 : *encoding = SOX_ENCODING_ULAW ; *size = 8; break;
- case Alaw_8 : *encoding = SOX_ENCODING_ALAW ; *size = 8; break;
- case Linear_8 : *encoding = SOX_ENCODING_SIGN2; *size = 8; break;
- case Linear_16 : *encoding = SOX_ENCODING_SIGN2; *size = 16; break;
- case Linear_24 : *encoding = SOX_ENCODING_SIGN2; *size = 24; break;
- case Linear_32 : *encoding = SOX_ENCODING_SIGN2; *size = 32; break;
- case Float : *encoding = SOX_ENCODING_FLOAT; *size = 32; break;
- case Double : *encoding = SOX_ENCODING_FLOAT; *size = 64; break;
- /* Sun encodings that SoX can read, but not write: */
- case Adpcm_g721 : *encoding = SOX_ENCODING_G721 ; *size = 4; break;
- case Adpcm_g723_3: *encoding = SOX_ENCODING_G723 ; *size = 3; break;
- case Adpcm_g723_5: *encoding = SOX_ENCODING_G723 ; *size = 5; break;
-
- default: sox_debug("encoding: 0x%x", sun_encoding); return SOX_EOF;
+ switch (ft_encoding) {
+ case Mulaw_8 : *size = 8; return SOX_ENCODING_ULAW;
+ case Alaw_8 : *size = 8; return SOX_ENCODING_ALAW;
+ case Linear_8 : *size = 8; return SOX_ENCODING_SIGN2;
+ case Linear_16 : *size = 16; return SOX_ENCODING_SIGN2;
+ case Linear_24 : *size = 24; return SOX_ENCODING_SIGN2;
+ case Linear_32 : *size = 32; return SOX_ENCODING_SIGN2;
+ case Float : *size = 32; return SOX_ENCODING_FLOAT;
+ case Double : *size = 64; return SOX_ENCODING_FLOAT;
+ case Adpcm_g721 : *size = 4; return SOX_ENCODING_G721; /* read-only */
+ case Adpcm_g723_3: *size = 3; return SOX_ENCODING_G723; /* read-only */
+ case Adpcm_g723_5: *size = 5; return SOX_ENCODING_G723; /* read-only */
+ default: return SOX_ENCODING_UNKNOWN;
}
- return SOX_SUCCESS;
}
typedef struct { /* For G72x decoding: */
@@ -128,57 +125,47 @@
static int startread(sox_format_t * ft)
{
priv_t * p = (priv_t * ) ft->priv;
- uint32_t magic; /* These 6 uint32_t variables represent a Sun sound */
- uint32_t hdr_size; /* header on disk. The numbers are written as */
- uint32_t data_size; /* big-endians. Any extra bytes (totalling */
- uint32_t sun_encoding; /* hdr_size - 24) are an "info" field of */
- uint32_t sample_rate; /* unspecified nature, usually a string. By */
+ char magic[4]; /* These 6 variables represent a Sun sound */
+ uint32_t hdr_size; /* header on disk. The uint32_t are written as */
+ uint32_t data_size; /* big-endians. At least extra bytes (totalling */
+ uint32_t ft_encoding; /* hdr_size - FIXED_HDR) are an "info" field of */
+ uint32_t rate; /* unspecified nature, usually a string. By */
uint32_t channels; /* convention the header size is a multiple of 4. */
- unsigned bits_per_sample;
- sox_encoding_t sox_encoding;
+ unsigned i, bits_per_sample;
+ sox_encoding_t encoding;
- sox_readdw(ft, &magic);
- if (magic == DEC_INV_MAGIC) {
- sox_debug("Found inverted DEC magic word.");
- /* Inverted headers are not standard. Code was probably
- * left over from pre-standardize period of testing for
- * endianess. Its not hurting though.
- */
- ft->encoding.reverse_bytes = SOX_IS_BIGENDIAN;
- }
- else if (magic == SUN_INV_MAGIC) {
- sox_debug("Found inverted Sun/NeXT magic word.");
- ft->encoding.reverse_bytes = SOX_IS_BIGENDIAN;
- }
- else if (magic == SUN_MAGIC) {
- sox_debug("Found Sun/NeXT magic word");
- ft->encoding.reverse_bytes = SOX_IS_LITTLEENDIAN;
- }
- else if (magic == DEC_MAGIC) {
- sox_debug("Found DEC magic word");
- ft->encoding.reverse_bytes = SOX_IS_LITTLEENDIAN;
- }
- else {
- sox_fail_errno(ft,SOX_EHDR,"Did not detect valid Sun/NeXT/DEC magic number in header.");
+ if (sox_readchars(ft, magic, sizeof(magic)))
return SOX_EOF;
+
+ for (i = 0; id[i].desc && memcmp(magic, id[i].str, sizeof(magic)); ++i);
+ if (!id[i].desc) {
+ sox_fail_errno(ft, SOX_EHDR, "au: can't find Sun/NeXT/DEC identifier");
+ return SOX_EOF;
}
+ sox_report("found %s identifier", id[i].desc);
+ ft->encoding.reverse_bytes = id[i].reverse_bytes;
- sox_readdw(ft, &hdr_size);
- if (hdr_size < SUN_HDRSIZE) {
- sox_fail_errno(ft, SOX_EHDR, "Sun/NeXT header size too small.");
+ if (sox_readdw(ft, &hdr_size) ||
+ sox_readdw(ft, &data_size) || /* Can be SUN_UNSPEC */
+ sox_readdw(ft, &ft_encoding) ||
+ sox_readdw(ft, &rate) ||
+ sox_readdw(ft, &channels))
return SOX_EOF;
+
+ if (hdr_size < FIXED_HDR) {
+ sox_fail_errno(ft, SOX_EHDR, "header size %u is too small", hdr_size);
+ return SOX_EOF;
}
- sox_readdw(ft, &data_size); /* Can be SUN_UNSPEC */
- sox_readdw(ft, &sun_encoding);
- sox_readdw(ft, &sample_rate);
- sox_readdw(ft, &channels);
+ if (hdr_size < FIXED_HDR + 4)
+ sox_warn("header size %u is too small", hdr_size);
- if (sox_enc(sun_encoding, &sox_encoding, &bits_per_sample) == SOX_EOF) {
- int n = min(sun_encoding, Unknown_other);
- sox_fail_errno(ft, SOX_EFMT, "unsupported encoding `%s' (%u)", str[n], sun_encoding);
+ if (!(encoding = sox_enc(ft_encoding, &bits_per_sample))) {
+ int n = min(ft_encoding, Unknown_other);
+ sox_fail_errno(ft, SOX_EFMT, "unsupported encoding `%s' (%#x)", str[n], ft_encoding);
return SOX_EOF;
}
- switch (sun_encoding) {
+
+ switch (ft_encoding) {
case Adpcm_g721 : p->dec_routine = g721_decoder ; break;
case Adpcm_g723_3: p->dec_routine = g723_24_decoder; break;
case Adpcm_g723_5: p->dec_routine = g723_40_decoder; break;
@@ -189,11 +176,10 @@
ft->handler.read = dec_read;
}
- hdr_size -= SUN_HDRSIZE; /* # bytes already read */
- if (hdr_size > 0) {
- char * buf = xcalloc(1, hdr_size + 1); /* +1 ensures null-terminated */
- if (sox_readbuf(ft, buf, hdr_size) != hdr_size) {
- sox_fail_errno(ft, SOX_EOF, "Unexpected EOF in Sun/NeXT header info.");
+ if (hdr_size > FIXED_HDR) {
+ size_t info_size = hdr_size - FIXED_HDR;
+ char * buf = xcalloc(1, info_size + 1); /* +1 ensures null-terminated */
+ if (sox_readchars(ft, buf, info_size) != SOX_SUCCESS) {
free(buf);
return SOX_EOF;
}
@@ -201,25 +187,26 @@
free(buf);
}
if (data_size == SUN_UNSPEC)
- data_size = 0; /* SoX uses 0 for unspecified */
- return sox_check_read_params( ft, channels, (sox_rate_t)sample_rate,
- sox_encoding, bits_per_sample, div_bits(data_size, bits_per_sample));
+ data_size = 0; /* libSoX uses 0 for unspecified */
+ return sox_check_read_params(ft, channels, (sox_rate_t)rate,
+ encoding, bits_per_sample, div_bits(data_size, bits_per_sample));
}
static int write_header(sox_format_t * ft)
{
- char *comment = cat_comments(ft->comments);
+ char * comment = cat_comments(ft->comments);
size_t len = strlen(comment) + 1; /* Write out null-terminated */
size_t info_len = max(4, (len + 3) & ~3u); /* Minimum & multiple of 4 bytes */
size_t size = ft->olength? ft->olength : ft->length;
+ int i = ft->encoding.reverse_bytes == SOX_IS_BIGENDIAN? 2 : 0;
sox_bool error = sox_false
- ||sox_writedw(ft, SUN_MAGIC)
- ||sox_writedw(ft, SUN_HDRSIZE + info_len)
+ ||sox_writechars(ft, id[i].str, sizeof(id[i].str))
+ ||sox_writedw(ft, FIXED_HDR + info_len)
||sox_writedw(ft, size? size*(ft->encoding.bits_per_sample >> 3) : SUN_UNSPEC)
- ||sox_writedw(ft, sun_enc(ft->encoding.bits_per_sample,ft->encoding.encoding))
+ ||sox_writedw(ft, ft_enc(ft->encoding.bits_per_sample, ft->encoding.encoding))
||sox_writedw(ft, (unsigned)(ft->signal.rate + .5))
||sox_writedw(ft, ft->signal.channels)
- ||sox_writebuf(ft, comment, len) != len
+ ||sox_writechars(ft, comment, len)
||sox_padbytes(ft, info_len - len);
free(comment);
return error? SOX_EOF: SOX_SUCCESS;
@@ -234,8 +221,7 @@
SOX_ENCODING_SIGN2, 8, 16, 24, 32, 0,
SOX_ENCODING_FLOAT, 32, 64, 0,
0};
- static sox_format_handler_t const handler = {
- SOX_LIB_VERSION_CODE,
+ static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE,
"PCM file format used widely on Sun systems",
names, SOX_FILE_BIG_END | SOX_FILE_REWIND,
startread, sox_rawread, NULL,
--- a/src/formats.h
+++ b/src/formats.h
@@ -26,7 +26,8 @@
FORMAT(s4)
FORMAT(sf)
FORMAT(smp)
- FORMAT(sndrtool)
+ FORMAT(sounder)
+ FORMAT(soundtool)
FORMAT(sphere)
FORMAT(svx)
FORMAT(txw)
--- a/src/misc.c
+++ b/src/misc.c
@@ -156,8 +156,13 @@
sox_warn("'%s': overriding encoding size", ft->filename);
ft->encoding.bits_per_sample = bits_per_sample;
- if (!ft->length && ft->encoding.bits_per_sample && sox_filelength(ft))
- ft->length = div_bits(sox_filelength(ft) - ft->data_start, ft->encoding.bits_per_sample);
+ if (ft->encoding.bits_per_sample && sox_filelength(ft)) {
+ off_t calculated_length = div_bits(sox_filelength(ft) - ft->data_start, ft->encoding.bits_per_sample);
+ if (!ft->length)
+ ft->length = calculated_length;
+ else if (length != calculated_length)
+ sox_warn("file header gives the total number of samples as %u but file length indicates the number is in fact %u", (unsigned)length, (unsigned)calculated_length); /* FIXME: casts */
+ }
if ( sox_precision(ft->encoding.encoding, ft->encoding.bits_per_sample))
return SOX_SUCCESS;
@@ -173,8 +178,6 @@
return (SOX_SAMPLE_MAX >> shift) << shift;
}
-const char sox_readerr[] = "Premature EOF while reading sample file";
-
/* Lookup table to reverse the bit order of a byte. ie MSB become LSB */
uint8_t const cswap[256] = {
0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0,
@@ -209,7 +212,9 @@
size_t sox_readbuf(sox_format_t * ft, void *buf, sox_size_t len)
{
size_t ret = fread(buf, 1, len, ft->fp);
- return (ferror(ft->fp) || (feof(ft->fp) && ret == 0)) ? 0 : ret;
+ if (ret != len && ferror(ft->fp))
+ sox_fail_errno(ft, errno, "sox_readbuf");
+ return ret;
}
/* Skip input without seeking. */
@@ -238,7 +243,7 @@
* Returns number of bytes written.
*/
-size_t sox_writebuf(sox_format_t * ft, void const *buf, sox_size_t len)
+size_t sox_writebuf(sox_format_t * ft, void const * buf, sox_size_t len)
{
size_t ret = fwrite(buf, 1, len, ft->fp);
if (ret != len) {
@@ -303,8 +308,6 @@
if (sox_readbuf(ft, &in, 1) != 1)
{
*sc = 0;
- if (sox_error(ft))
- sox_fail_errno(ft, errno, sox_readerr);
return (SOX_EOF);
}
if (in == 0 || in == '\n')
--- a/src/mp3.c
+++ b/src/mp3.c
@@ -196,9 +196,7 @@
*/
ReadSize = sox_readbuf(ft, p->InputBuffer, INPUT_BUFFER_SIZE);
if (ReadSize < INPUT_BUFFER_SIZE) {
- if (sox_error(ft))
- sox_fail_errno(ft, SOX_EOF, "error reading input file");
- else if (sox_eof(ft))
+ if (sox_eof(ft))
sox_fail_errno(ft, SOX_EOF, "input file too short");
return SOX_EOF;
}
--- a/src/raw.c
+++ b/src/raw.c
@@ -65,8 +65,7 @@
{ \
sox_size_t n, nread; \
ctype *data = xmalloc(sizeof(ctype) * len); \
- if ((nread = sox_read_ ## type ## _buf(ft, (uctype *)data, len)) != len && sox_error(ft)) \
- sox_fail_errno(ft, errno, sox_readerr); \
+ nread = sox_read_ ## type ## _buf(ft, (uctype *)data, len); \
for (n = 0; n < nread; n++) \
*buf++ = cast(data[n], ft->clips); \
free(data); \
--- a/src/sf.c
+++ b/src/sf.c
@@ -1,232 +1,155 @@
/*
- * July 5, 1991
- * Copyright 1991 Lance Norskog And Sundry Contributors
- * This source code is freely redistributable and may be used for
- * any purpose. This copyright notice must be maintained.
- * Lance Norskog And Sundry Contributors are not responsible for
- * the consequences of using this software.
- */
-
-/*
- * libSoX IRCAM SoundFile format handler.
+ * File format: IRCAM SoundFile (c) 2008 robs@users.sourceforge.net
*
- * Derived from: libSoX skeleton handler file.
+ * See http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/IRCAM/IRCAM.html
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, write to the Free Software Foundation,
+ * Fifth Floor, 51 Franklin Street, Boston, MA 02111-1301, USA.
*/
#include "sox_i.h"
-#include "sfircam.h"
-
#include <string.h>
-#include <stdlib.h>
-/* Private data for SF file */
-typedef struct sfstuff {
- struct sfinfo info;
- /* needed for seek */
- sox_size_t dataStart;
-} *sf_t;
+/* Magic numbers used in IRCAM audio files */
+static struct {char str[4]; sox_bool reverse_bytes; char const * desc;} id[] = {
+ {"\144\243\001\0", SOX_IS_BIGENDIAN , "Little-endian VAX (native)"},
+ {"\0\001\243\144", SOX_IS_LITTLEENDIAN, "Big-endian VAX"},
+ {"\144\243\002\0", SOX_IS_LITTLEENDIAN, "Big-endian Sun (native)"},
+ {"\0\002\243\144", SOX_IS_BIGENDIAN , "Little-endian Sun"},
+ {"\144\243\003\0", SOX_IS_BIGENDIAN , "Little-endian MIPS (DEC)"},
+ {"\0\003\243\144", SOX_IS_LITTLEENDIAN, "Big-endian MIPS (SGI)"},
+ {"\144\243\004\0", SOX_IS_LITTLEENDIAN, "Big-endian NeXT"},
+ {" ", 0, NULL}
+};
+#define FIXED_HDR 1024
+#define SF_COMMENT 2 /* code for "comment line" */
-/*
- * Read the codes from the sound file, allocate space for the comment and
- * assign its pointer to the comment field in ft.
- */
-static void readcodes(sox_format_t * ft, SFHEADER *sfhead)
-{
- char *commentbuf = NULL, *sfcharp;
- sox_size_t bsize;
- sox_bool finished = sox_false;
- SFCODE *sfcodep;
+typedef enum {Unspecified,
+ Linear_8 = 0x00001, Alaw_8 = 0x10001, Mulaw_8 = 0x20001, Linear_16 = 0x00002,
+ Linear_24 = 0x00003, Linear_32 = 0x40004, Float = 0x00004, Double = 0x00008
+} ft_encoding_t;
- sfcodep = (SFCODE *) (&sfhead->sfinfo + 1);
- do {
- sfcharp = (char *) sfcodep + sizeof(SFCODE);
- if (ft->encoding.reverse_bytes) {
- sfcodep->bsize = sox_swapdw(sfcodep->bsize);
- sfcodep->code = sox_swapdw(sfcodep->code);
- }
- bsize = sfcodep->bsize - sizeof(SFCODE);
- switch(sfcodep->code) {
- case SF_END:
- finished = sox_true;
- break;
- case SF_COMMENT:
- commentbuf = (char *) xmalloc(bsize + 1);
- memcpy(commentbuf, sfcharp, bsize);
- commentbuf[bsize] = '\0';
- break;
- }
- sfcodep = (SFCODE *) (sfcharp + bsize);
- } while(!finished);
- append_comments(&ft->comments, commentbuf);
- free(commentbuf);
-}
+static ft_encoding_t ft_enc(unsigned size, sox_encoding_t encoding)
+{
+ if (encoding == SOX_ENCODING_ULAW && size == 8) return Mulaw_8;
+ if (encoding == SOX_ENCODING_ALAW && size == 8) return Alaw_8;
+ if (encoding == SOX_ENCODING_SIGN2 && size == 8) return Linear_8;
+ if (encoding == SOX_ENCODING_SIGN2 && size == 16) return Linear_16;
+ if (encoding == SOX_ENCODING_SIGN2 && size == 24) return Linear_24;
+ if (encoding == SOX_ENCODING_SIGN2 && size == 32) return Linear_32;
+ if (encoding == SOX_ENCODING_FLOAT && size == 32) return Float;
+ if (encoding == SOX_ENCODING_FLOAT && size == 64) return Double;
+ return Unspecified;
+}
-static int seek(sox_format_t * ft, sox_size_t offset)
+static sox_encoding_t sox_enc(uint32_t ft_encoding, unsigned * size)
{
- sox_size_t new_offset, channel_block, alignment;
-
- sf_t sf = (sf_t ) ft->priv;
- new_offset = offset * (ft->encoding.bits_per_sample >> 3);
- /* Make sure request aligns to a channel block (ie left+right) */
- channel_block = ft->signal.channels * (ft->encoding.bits_per_sample >> 3);
- alignment = new_offset % channel_block;
- /* Most common mistaken is to compute something like
- * "skip everthing upto and including this sample" so
- * advance to next sample block in this case.
- */
- if (alignment != 0)
- new_offset += (channel_block - alignment);
- new_offset += sf->dataStart;
-
- return sox_seeki(ft, (sox_ssize_t)new_offset, SEEK_SET);
+ switch (ft_encoding) {
+ case Mulaw_8 : *size = 8; return SOX_ENCODING_ULAW;
+ case Alaw_8 : *size = 8; return SOX_ENCODING_ALAW;
+ case Linear_8 : *size = 8; return SOX_ENCODING_SIGN2;
+ case Linear_16 : *size = 16; return SOX_ENCODING_SIGN2;
+ case Linear_24 : *size = 24; return SOX_ENCODING_SIGN2;
+ case Linear_32 : *size = 32; return SOX_ENCODING_SIGN2;
+ case Float : *size = 32; return SOX_ENCODING_FLOAT;
+ case Double : *size = 64; return SOX_ENCODING_FLOAT;
+ default: return SOX_ENCODING_UNKNOWN;
+ }
}
-/*
- * Do anything required before you start reading samples.
- * Read file header.
- * Find out sampling rate,
- * size and encoding of samples,
- * mono/stereo/quad.
- */
static int startread(sox_format_t * ft)
{
- sf_t sf = (sf_t) ft->priv;
- SFHEADER sfhead;
- int rc;
- int samplesize = 0;
+ char magic[4];
+ float rate;
+ uint32_t channels, ft_encoding;
+ unsigned i, bits_per_sample;
+ sox_encoding_t encoding;
+ uint16_t code, size;
- if (sox_readbuf(ft, &sfhead, sizeof(sfhead)) != sizeof(sfhead))
- {
- sox_fail("unexpected EOF in SF header");
- return(SOX_EOF);
- }
- memcpy(&sf->info, &sfhead.sfinfo, sizeof(struct sfinfo));
- if (ft->encoding.reverse_bytes) {
- sox_swapf(&sf->info.sf_srate);
- sf->info.sf_packmode = sox_swapdw(sf->info.sf_packmode);
- sf->info.sf_chans = sox_swapdw(sf->info.sf_chans);
- }
- if ((sfmagic1(&sfhead) != SF_MAGIC1) ||
- (sfmagic2(&sfhead) != SF_MAGIC2)) {
- sox_fail_errno(ft, SOX_EHDR, "sf: can't find IRCAM identifier");
- return SOX_EOF;
- }
+ if (sox_readchars(ft, magic, sizeof(magic)))
+ return SOX_EOF;
+
+ for (i = 0; id[i].desc && memcmp(magic, id[i].str, sizeof(magic)); ++i);
+ if (!id[i].desc) {
+ sox_fail_errno(ft, SOX_EHDR, "sf: can't find IRCAM identifier");
+ return SOX_EOF;
+ }
+ sox_report("found %s identifier", id[i].desc);
+ ft->encoding.reverse_bytes = id[i].reverse_bytes;
- /*
- * If your format specifies or your file header contains
- * any of the following information.
- */
- ft->signal.rate = sf->info.sf_srate;
- switch(sf->info.sf_packmode) {
- case SF_SHORT:
- ft->encoding.bits_per_sample = 16;
- ft->encoding.encoding = SOX_ENCODING_SIGN2;
- samplesize = 2;
- break;
- case SF_FLOAT:
- ft->encoding.bits_per_sample = 16;
- ft->encoding.encoding = SOX_ENCODING_FLOAT;
- samplesize = sizeof(float);
- break;
- default:
- sox_fail("Soundfile input: unknown format 0x%x",
- sf->info.sf_packmode);
- return(SOX_EOF);
- }
- ft->signal.channels = (int) sf->info.sf_chans;
-
- if (ft->signal.channels == 0)
- ft->signal.channels = 1;
-
- /* Read codes and print as comments. */
- readcodes(ft, &sfhead);
-
- /* Needed for rawread() */
- rc = sox_rawstartread(ft);
-
-/* Need length for seeking */
- if(ft->seekable){
- ft->length = sox_filelength(ft)/samplesize;
- sf->dataStart = sox_tell(ft);
- } else {
- ft->length = 0;
- }
-
- return(rc);
+ if (sox_readf(ft, &rate) || sox_readdw(ft, &channels) || sox_readdw(ft, &ft_encoding))
+ return SOX_EOF;
+
+ if (!(encoding = sox_enc(ft_encoding, &bits_per_sample))) {
+ sox_fail_errno(ft, SOX_EFMT, "sf: unsupported encoding %#x)", ft_encoding);
+ return SOX_EOF;
+ }
+ do {
+ if (sox_readw(ft, &code) || sox_readw(ft, &size))
+ return SOX_EOF;
+ if (code == SF_COMMENT) {
+ char * buf = xcalloc(1, (size_t)size + 1); /* +1 ensures null-terminated */
+ if (sox_readchars(ft, buf, size) != SOX_SUCCESS) {
+ free(buf);
+ return SOX_EOF;
+ }
+ append_comments(&ft->comments, buf);
+ free(buf);
+ }
+ else if (sox_skipbytes(ft, size))
+ return SOX_EOF;
+ } while (code);
+ if (sox_skipbytes(ft, FIXED_HDR - (sox_size_t)sox_tell(ft)))
+ return SOX_EOF;
+
+ return sox_check_read_params(ft, channels, rate, encoding, bits_per_sample, (off_t)0);
}
-static int startwrite(sox_format_t * ft)
+static int write_header(sox_format_t * ft)
{
- sf_t sf = (sf_t) ft->priv;
- SFHEADER sfhead;
- SFCODE *sfcodep;
- char *sfcharp;
- int rc;
- char * comment = cat_comments(ft->comments);
-
- /* Needed for rawwrite() */
- rc = sox_rawstartwrite(ft);
- if (rc)
- return rc;
-
- sf->info.magic_union._magic_bytes.sf_magic1 = SF_MAGIC1;
- sf->info.magic_union._magic_bytes.sf_magic2 = SF_MAGIC2;
- sf->info.magic_union._magic_bytes.sf_param = 0;
-
- /* This file handler can handle both big and little endian data */
- if (SOX_IS_LITTLEENDIAN)
- sf->info.magic_union._magic_bytes.sf_machine = SF_VAX;
- else
- sf->info.magic_union._magic_bytes.sf_machine = SF_SUN;
-
- sf->info.sf_srate = ft->signal.rate;
- if (ft->encoding.bits_per_sample == 32 &&
- ft->encoding.encoding == SOX_ENCODING_FLOAT) {
- sf->info.sf_packmode = SF_FLOAT;
- } else {
- sf->info.sf_packmode = SF_SHORT;
- /* Default to signed words */
- ft->encoding.bits_per_sample = 16;
- ft->encoding.encoding = SOX_ENCODING_SIGN2;
- }
-
- sf->info.sf_chans = ft->signal.channels;
-
- /* Clean out structure so unused areas will remain constain */
- /* between different coverts and not rely on memory contents */
- memset (&sfhead, 0, sizeof(SFHEADER));
- memcpy(&sfhead.sfinfo, &sf->info, sizeof(struct sfinfo));
- sfcodep = (SFCODE *) (&sfhead.filler[SF_INFO_LEN+1]);
- sfcodep->code = SF_COMMENT;
- sfcodep->bsize = strlen(comment) + sizeof(SFCODE);
- while (sfcodep->bsize % 4)
- sfcodep->bsize++;
- sfcharp = (char *) sfcodep;
- strcpy(sfcharp + sizeof(SFCODE), comment);
- free(comment);
- sfcodep = (SFCODE *) (sfcharp + sfcodep->bsize);
- sfcodep->code = SF_END;
- sfcodep->bsize = sizeof(SFCODE);
- sfcharp = (char *) sfcodep + sizeof(SFCODE);
- sox_writebuf(ft, &sfhead, sizeof(SFHEADER));
-
- return(SOX_SUCCESS);
+ char * comment = cat_comments(ft->comments);
+ size_t len = min(FIXED_HDR - 26, strlen(comment)) + 1; /* null-terminated */
+ size_t info_len = max(4, (len + 3) & ~3u); /* Minimum & multiple of 4 bytes */
+ int i = ft->encoding.reverse_bytes == SOX_IS_BIGENDIAN? 0 : 2;
+ sox_bool error = sox_false
+ ||sox_writechars(ft, id[i].str, sizeof(id[i].str))
+ ||sox_writef(ft, ft->signal.rate)
+ ||sox_writedw(ft, ft->signal.channels)
+ ||sox_writedw(ft, ft_enc(ft->encoding.bits_per_sample, ft->encoding.encoding))
+ ||sox_writew(ft, SF_COMMENT)
+ ||sox_writew(ft, info_len)
+ ||sox_writechars(ft, comment, len)
+ ||sox_padbytes(ft, FIXED_HDR - 20 - len);
+ free(comment);
+ return error? SOX_EOF: SOX_SUCCESS;
}
SOX_FORMAT_HANDLER(sf)
{
static char const * const names[] = {"sf", "ircam", NULL};
- static unsigned const encodings[] = {
- SOX_ENCODING_SIGN2, 16, 0,
- SOX_ENCODING_FLOAT, 32, 0,
+ static unsigned const write_encodings[] = {
+ SOX_ENCODING_ULAW, 8, 0,
+ SOX_ENCODING_ALAW, 8, 0,
+ SOX_ENCODING_SIGN2, 8, 16, 24, 32, 0,
+ SOX_ENCODING_FLOAT, 32, 64, 0,
0};
- static sox_format_handler_t const handler = {
- SOX_LIB_VERSION_CODE,
- "Institut de Recherche et Coordination Acoustique/Musique Sound Description Interchange Format",
- names, 0,
- startread, sox_rawread, sox_rawstopread,
- startwrite, sox_rawwrite, sox_rawstopwrite,
- seek, encodings, NULL
+ static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE,
+ "Institut de Recherche et Coordination Acoustique/Musique",
+ names, SOX_FILE_LIT_END,
+ startread, sox_rawread, NULL,
+ write_header, sox_rawwrite, NULL,
+ sox_rawseek, write_encodings, NULL
};
return &handler;
}
--- a/src/sfircam.h
+++ /dev/null
@@ -1,222 +1,0 @@
-/* SFHEADER.H */
-
-/* definitions and structures needed for manipulating soundfiles.
- */
-
-#define SIZEOF_HEADER 1024
-#define SF_BUFSIZE (16*1024) /* used only in play */
-#define SF_MAXCHAN 4
-#define MAXCOMM 512
-#define MINCOMM 256
-
-#define SF_MAGIC1 0144
-#define SF_MAGIC2 0243
-
-/* Definition of SF_MACHINE and SF_MAGIC
- *
- * Note that SF_MAGIC always has SF_MAGIC1 as its first byte, SF_MAGIC2 as its
- * second, SF_MACHINE as its third, and zero as its fourth. Separate defines
- * are needed because byte order is different on different machines.
- */
-#define SF_VAX 1
-#define SF_SUN 2
-#define SF_MIPS 3
-#define SF_NEXT 4
-#ifdef vax
-#define SF_MACHINE SF_VAX
-#define SF_MAGIC ((uint32_t)(SF_MAGIC1 | SF_MAGIC2 << 8 | SF_MACHINE << 16))
-#endif
-#ifdef sun
-#define SF_MACHINE SF_SUN
-#define SF_MAGIC ((uint32_t)(SF_MAGIC1 << 24 | SF_MAGIC2 << 16 | SF_MACHINE << 8))
-#endif
-#ifdef mips
-#define SF_MACHINE SF_MIPS
-#define SF_MAGIC ((uint32_t)(SF_MAGIC1 | SF_MAGIC2 << 8 | SF_MACHINE << 16))
-#endif
-#ifdef NeXT
-#define SF_MACHINE SF_NEXT
-#define SF_MAGIC ((uint32_t)(SF_MAGIC1 << 24 | SF_MAGIC2 << 16 | SF_MACHINE << 8))
-#endif
-
-
-/* Packing modes, as stored in the SFHEADER.sf_packmode field
- *
- * For each packing mode, the lower-order short is the number of bytes per
- * sample, and for backward compatibility, SF_SHORT and SF_FLOAT have
- * high-order short = 0 so overall they're the bytes per sample, but that's not
- * true for all SF_'s. Thus while the "sfclass" macro still returns a unique
- * ID for each packing mode, the new "sfsamplesize" macro should be used to get
- * the bytes per sample.
- *
- * Note that SF_X == SFMT_X in most, but not all, cases, because MIT changed
- * SFMT_FLOAT and we kept SF_FLOAT for compatibility with existing sound files.
- *
- * Possible values of sf_packmode:
- */
-#define SF_CHAR ((uint32_t) sizeof(char))
-#define SF_ALAW ((uint32_t) sizeof(char) | 0x10000)
-#define SF_ULAW ((uint32_t) sizeof(char) | 0x20000)
-#define SF_SHORT ((uint32_t) sizeof(short))
-#define SF_LONG ((uint32_t) sizeof(long) | 0x40000)
-#define SF_FLOAT ((uint32_t) sizeof(float))
-
-/* For marking data after fixed section of soundfile header -- see man (3carl)
- * sfcodes and defintions of SFCODE and related structures, below.
- */
-#define SF_END 0 /* Meaning no more information */
-#define SF_MAXAMP 1 /* Meaning maxamp follows */
-#define SF_COMMENT 2 /* code for "comment line" */
-#define SF_PVDATA 3
-#define SF_AUDIOENCOD 4
-#define SF_CODMAX 4
-
-/*
- * DEFINITION OF SFHEADER FORMAT
- *
- * The first four bytes are the magic information for the sound file. They
- * can be accessed, via a union, either as a structure of four unsigned bytes
- * sf_magic1, sf_magic2, sf_machine, sf_param, or as the single long sf_magic.
- * sf_magic is for backward compatibility; it should be SF_MAGIC as defined
- * above.
- */
-
-/* Define this value to get around by padding issues. */
-#define SF_INFO_LEN 16
-
-struct sfinfo {
- union magic_union {
- struct {
- unsigned char sf_magic1; /* byte 1 of magic */
- unsigned char sf_magic2; /* 2 */
- unsigned char sf_machine; /* 3 */
- unsigned char sf_param; /* 4 */
- } _magic_bytes;
- uint32_t sf_magic; /* magic as a 4-byte long */
- } magic_union;
- float sf_srate;
- uint32_t sf_chans;
- uint32_t sf_packmode;
-};
-
-typedef union sfheader {
- struct sfinfo sfinfo;
- char filler[SIZEOF_HEADER];
-} SFHEADER;
-
-/*
- * Definition of SFCODE and related data structs
- *
- * Two routines in libbicsf/sfcodes.c, getsfcode() and putsfcode()
- * are used to insert additionnal information into a header
- * or to retreive such information. See man sfcodes.
- *
- * 10/90 pw
- * These routines are now part of libcarl/sfcodes.c
- */
-
-typedef struct sfcode {
- short code;
- short bsize;
-} SFCODE;
-
-typedef struct Sfmaxamp {
- float value[SF_MAXCHAN];
- uint32_t samploc[SF_MAXCHAN];
- uint32_t timetag;
-} SFMAXAMP;
-
-typedef struct sfcomment {
- char comment[MAXCOMM];
-} SFCOMMENT;
-
-typedef struct { /* this code written by pvanal */
- short frameSize;
- short frameIncr;
-} SFPVDATA;
-
-typedef struct { /* ditto */
- short encoding;
- short grouping;
-} SFAUDIOENCOD;
-
-/*
- * DEFINITION OF MACROS TO GET HEADER INFO
- * x is a pointer to SFHEADER
- *
- * For backward compatibility in MIT Csound code, sfmagic(x) still provides
- * access to the first long of SFHEADER x. It can be compared to SF_MAGIC,
- * which is defined machine-dependently (above) to always be the right four
- * bytes in the right order.
- *
- * sfclass(x) returns one of SF_SHORT, SF_FLOAT etc. defined above, while
- * sfsamplesize(x) returns just the bytes per object, the lower-order short of
- * sf_packmode.
- */
-#define sfmagic(x) ((x)->sfinfo.magic_union.sf_magic)
-#define sfmagic1(x) ((x)->sfinfo.magic_union._magic_bytes.sf_magic1)
-#define sfmagic2(x) ((x)->sfinfo.magic_union._magic_bytes.sf_magic2)
-#define sfmachine(x) ((x)->sfinfo.magic_union._magic_bytes.sf_machine)
-#define sfparam(x) ((x)->sfinfo.magic_union._magic_bytes.sf_param)
-#define sfsrate(x) ((x)->sfinfo.sf_srate)
-#define sfchans(x) ((x)->sfinfo.sf_chans)
-#define sfclass(x) ((x)->sfinfo.sf_packmode)
-#define sfsamplesize(x) ((size_t) ((x)->sfinfo.sf_packmode & 0xFFFF))
-#define sfbsize(x) ((x)->sox_size - sizeof(SFHEADER))
-
-/*
- * Macros for testing soundfiles
- */
-/* True if soundfile and good arch */
-#define ismagic(x) ((sfmagic1(x) == SF_MAGIC1) && \
- (sfmagic2(x) == SF_MAGIC2) && \
- (sfmachine(x) == SF_MACHINE))
-
-/* True if soundfile */
-#define isforeignmagic(x) ((sfmagic1(x) == SF_MAGIC1) && \
- (sfmagic2(x) == SF_MAGIC2))
-
-/* True if soundfile */
-#define issoundfile(x) ((sfmagic1(x) == SF_MAGIC1) && \
- (sfmagic2(x) == SF_MAGIC2))
-
-/* True if soundfile and foreign arch */
-#define isforeignsoundfile(x) ((sfmagic1(x) == SF_MAGIC1) && \
- (sfmagic2(x) == SF_MAGIC2) && \
- (sfmachine(x) != SF_MACHINE))
-
-/* True if foreign arch */
-#define isforeign(x) (sfmachine(x) != SF_MACHINE)
-
-
-/*
- * The macros for opening soundfiles have been rewritten as C routines.
- * In order to preserve compatibility, we supply the following new macros
- */
-
-#define readopensf(name,fd,sfh,sfst,prog,result) \
- result = (fd = openrosf(name, &sfh, &sfst, prog)) < 0 ? fd : 0;
-
-#define freadopensf(name,fp,sfh,sfst,prog,result) \
- result = fopenrosf(name, &fp, &sfh, &sfst, prog);
-
-#define wropensf(name,fd,sfh,prog,result) \
- result = (fd = openwosf(name, &sfh, prog)) < 0 ? fd : 0;
-
-#define rdwropensf(name,fd,sfh,sfst,prog,result) \
- result = (fd = openrwsf(name, &sfh, &sfst, prog)) < 0 ? fd : 0;
-
-
-/*
- * Definition of macro to get MAXAMP and COMMENT info
- *
- * sfm is ptr to SFMAXAMP
- * sfst is the address of a stat struct
- */
-
-#define sfmaxamp(mptr,chan) (mptr)->value[chan]
-#define sfmaxamploc(mptr,chan) (mptr)->samploc[chan]
-#define sfmaxamptime(x) (x)->timetag
-#define ismaxampgood(x,s) (sfmaxamptime(x) >= (s)->sox_mtime)
-#define sfcomm(x,n) (x)->comment[n]
-
--- a/src/sndrtool.c
+++ /dev/null
@@ -1,178 +1,0 @@
-/*
- * Sounder/Sndtool format handler: W V Neisius, February 1992
- *
- * June 28, 93: force output to mono.
- *
- * March 3, 1999 - cbagwell@sprynet.com
- * Forced extra comment fields to zero.
- */
-
-#include "sox_i.h"
-
-#include <math.h>
-#include <string.h>
-#include <stdio.h>
-#include <errno.h>
-
-/* Private data used by writer */
-typedef struct sndpriv {
- sox_size_t nsamples;
- sox_size_t dataStart;
-} *snd_t;
-
-static void sndtwriteheader(sox_format_t * ft, sox_size_t nsamples)
-{
- char name_buf[97];
-
- /* sndtool header */
- sox_writes(ft, "SOUND"); /* magic */
- sox_writeb(ft, 0x1a);
- sox_writew(ft, 0); /* hGSound */
- sox_writedw(ft, nsamples);
- sox_writedw(ft, 0);
- sox_writedw(ft, nsamples);
- sox_writew(ft, (unsigned)(ft->signal.rate + .5));
- sox_writew(ft, 0);
- sox_writew(ft, 10);
- sox_writew(ft, 4);
- memset(name_buf, 0, 96);
- sprintf(name_buf, "%.62s - File created by SoX", ft->filename);
- sox_writebuf(ft, name_buf, 96);
-}
-
-static int seek(sox_format_t * ft, sox_size_t offset)
-{
- sox_size_t new_offset, channel_block, alignment;
- snd_t snd = (snd_t) ft->priv;
-
- new_offset = offset * (ft->encoding.bits_per_sample >> 3);
- /* Make sure request aligns to a channel block (ie left+right) */
- channel_block = ft->signal.channels * (ft->encoding.bits_per_sample >> 3);
- alignment = new_offset % channel_block;
- /* Most common mistaken is to compute something like
- * "skip everthing upto and including this sample" so
- * advance to next sample block in this case.
- */
- if (alignment != 0)
- new_offset += (channel_block - alignment);
- new_offset += snd->dataStart;
-
- return sox_seeki(ft, (sox_ssize_t) new_offset, SEEK_SET);
-}
-
-static int startread(sox_format_t * ft)
-{
- snd_t snd = (snd_t) ft->priv;
-
- char buf[96];
-
- unsigned short rate;
- int rc;
-
- /* Needed for rawread() */
- rc = sox_rawstartread(ft);
- if (rc)
- return rc;
-
- rate = 0;
-
- /* determine file type */
- /* if first 5 bytes == SOUND then this is probably a sndtool sound */
- /* if first word (16 bits) == 0
- * and second word is between 4000 & 25000 then this is sounder sound */
- /* otherwise, its probably raw, not handled here */
-
- if (sox_readbuf(ft, buf, 2) != 2) {
- sox_fail_errno(ft, errno, "SND: unexpected EOF");
- return (SOX_EOF);
- }
- if (strncmp(buf, "\0\0", 2) == 0) {
- /* sounder */
- sox_readw(ft, &rate);
- if (rate < 4000 || rate > 25000) {
- sox_fail_errno(ft, SOX_EFMT, "SND: sample rate out of range");
- return (SOX_EOF);
- }
- sox_seeki(ft, 4, SEEK_CUR);
- } else {
- /* sndtool ? */
- sox_readbuf(ft, &buf[2], 6);
- if (strncmp(buf, "SOUND", 5)) {
- sox_fail_errno(ft, SOX_EFMT, "SND: unrecognized SND format");
- return (SOX_EOF);
- }
- sox_seeki(ft, 12, SEEK_CUR);
- sox_readw(ft, &rate);
- sox_seeki(ft, 6, SEEK_CUR);
- if (sox_readbuf(ft, buf, 96) != 96) {
- sox_fail_errno(ft, SOX_EHDR, "SND: unexpected EOF in SND header");
- return (SOX_EOF);
- }
- sox_debug("comments: %.96s", buf);
- }
-
- ft->signal.channels = 1;
- ft->signal.rate = rate;
- ft->encoding.encoding = SOX_ENCODING_UNSIGNED;
- ft->encoding.bits_per_sample = 8;
-
- snd->dataStart = sox_tell(ft);
- ft->length = sox_filelength(ft) - snd->dataStart;
-
- return (SOX_SUCCESS);
-}
-
-static int startwrite(sox_format_t * ft)
-{
- snd_t p = (snd_t) ft->priv;
- int rc;
-
- /* Needed for rawwrite() */
- rc = sox_rawstartwrite(ft);
- if (rc)
- return rc;
-
- /* write header */
- p->nsamples = 0;
- sndtwriteheader(ft, 0);
-
- return (SOX_SUCCESS);
-}
-
-static sox_size_t write_samples(sox_format_t * ft, const sox_sample_t * buf,
- sox_size_t len)
-{
- snd_t p = (snd_t) ft->priv;
-
- p->nsamples += len;
- return sox_rawwrite(ft, buf, len);
-}
-
-static int stopwrite(sox_format_t * ft)
-{
- snd_t p = (snd_t) ft->priv;
-
- /* fixup file sizes in header */
- if (sox_seeki(ft, 0, 0) != 0) {
- sox_fail_errno(ft, errno,
- "can't rewind output file to rewrite SND header");
- return SOX_EOF;
- }
- sndtwriteheader(ft, p->nsamples);
- return (SOX_SUCCESS);
-}
-
-SOX_FORMAT_HANDLER(sndrtool)
-{
- static char const * const names[] = {"sndt", NULL};
- static unsigned const write_encodings[] = {SOX_ENCODING_UNSIGNED, 8, 0, 0};
- static sox_format_handler_t const handler = {
- SOX_LIB_VERSION_CODE,
- "Handles Sndtool and Sounder files",
- names, SOX_FILE_LIT_END | SOX_FILE_MONO,
- startread, sox_rawread, sox_rawstopread,
- startwrite, write_samples, stopwrite,
- seek, write_encodings, NULL
- };
- return &handler;
-}
--- /dev/null
+++ b/src/sounder.c
@@ -1,0 +1,56 @@
+/*
+ * Sounder format handler (c) 2008 robs@users.sourceforge.net
+ * Based on description in soundr3b.zip.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, write to the Free Software Foundation,
+ * Fifth Floor, 51 Franklin Street, Boston, MA 02111-1301, USA.
+ */
+
+#include "sox_i.h"
+
+static int start_read(sox_format_t * ft)
+{
+ uint16_t type, rate;
+
+ if (sox_readw(ft, &type) || sox_readw(ft, &rate) || sox_skipbytes(ft, 4))
+ return SOX_EOF;
+ if (type) {
+ sox_fail_errno(ft, SOX_EHDR, "invalid Sounder header");
+ return SOX_EOF;
+ }
+ return sox_check_read_params(ft, 1, (sox_rate_t)rate, SOX_ENCODING_UNSIGNED, 8, (off_t)0);
+}
+
+static int write_header(sox_format_t * ft)
+{
+ return sox_writew(ft, 0) /* sample type */
+ || sox_writew(ft, min(65535, (unsigned)(ft->signal.rate + .5)))
+ || sox_writew(ft, 10) /* speaker driver volume */
+ || sox_writew(ft, 4)? /* speaker driver DC shift */
+ SOX_EOF : SOX_SUCCESS;
+}
+
+SOX_FORMAT_HANDLER(sounder)
+{
+ static char const * const names[] = {"sndr", NULL};
+ static unsigned const write_encodings[] = {SOX_ENCODING_UNSIGNED, 8, 0, 0};
+ static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE,
+ "8-bit linear audio as used by Aaron Wallace's `Sounder' of 1991",
+ names, SOX_FILE_LIT_END | SOX_FILE_MONO,
+ start_read, sox_rawread, NULL,
+ write_header, sox_rawwrite, NULL,
+ sox_rawseek, write_encodings, NULL
+ };
+ return &handler;
+}
--- /dev/null
+++ b/src/soundtool.c
@@ -1,0 +1,79 @@
+/*
+ * Sounder format handler (c) 2008 robs@users.sourceforge.net
+ * Based on description in sndtl26.zip.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, write to the Free Software Foundation,
+ * Fifth Floor, 51 Franklin Street, Boston, MA 02111-1301, USA.
+ */
+
+#include "sox_i.h"
+#include <string.h>
+
+static char const ID1[6] = "SOUND\x1a";
+#define text_field_len 96 /* Includes null-terminator */
+
+static int start_read(sox_format_t * ft)
+{
+ char id1[sizeof(ID1)], comments[text_field_len + 1];
+ uint32_t nsamples;
+ uint16_t rate;
+
+ if (sox_readchars(ft, id1, sizeof(ID1)) ||
+ sox_skipbytes(ft, 10) || sox_readdw(ft, &nsamples) ||
+ sox_readw(ft, &rate) || sox_skipbytes(ft, 6) ||
+ sox_readchars(ft, comments, text_field_len))
+ return SOX_EOF;
+ if (memcmp(ID1, id1, sizeof(id1))) {
+ sox_fail_errno(ft, SOX_EHDR, "soundtool: can't find SoundTool identifier");
+ return SOX_EOF;
+ }
+ comments[text_field_len] = '\0'; /* Be defensive against incorrect files */
+ append_comments(&ft->comments, comments);
+ return sox_check_read_params(ft, 1, (sox_rate_t)rate, SOX_ENCODING_UNSIGNED, 8, (off_t)0);
+}
+
+static int write_header(sox_format_t * ft)
+{
+ char * comment = cat_comments(ft->comments);
+ char text_buf[text_field_len];
+ sox_size_t length = ft->olength? ft->olength:ft->length;
+
+ memset(text_buf, 0, sizeof(text_buf));
+ strncpy(text_buf, comment, text_field_len - 1);
+ free(comment);
+ return sox_writechars(ft, ID1, sizeof(ID1))
+ || sox_writew (ft, 0) /* GSound: not used */
+ || sox_writedw (ft, length) /* length of complete sample */
+ || sox_writedw (ft, 0) /* first byte to play from sample */
+ || sox_writedw (ft, length) /* first byte NOT to play from sample */
+ || sox_writew (ft, min(65535, (unsigned)(ft->signal.rate + .5)))
+ || sox_writew (ft, 0) /* sample size/type */
+ || sox_writew (ft, 10) /* speaker driver volume */
+ || sox_writew (ft, 4) /* speaker driver DC shift */
+ || sox_writechars(ft, text_buf, sizeof(text_buf))? SOX_EOF:SOX_SUCCESS;
+}
+
+SOX_FORMAT_HANDLER(soundtool)
+{
+ static char const * const names[] = {"sndt", NULL};
+ static unsigned const write_encodings[] = {SOX_ENCODING_UNSIGNED, 8, 0, 0};
+ static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE,
+ "8-bit linear audio as used by Martin Hepperle's `SoundTool' of 1991/2",
+ names, SOX_FILE_LIT_END | SOX_FILE_MONO | SOX_FILE_REWIND,
+ start_read, sox_rawread, NULL,
+ write_header, sox_rawwrite, NULL,
+ sox_rawseek, write_encodings, NULL
+ };
+ return &handler;
+}
--- a/src/sox.c
+++ b/src/sox.c
@@ -288,7 +288,7 @@
}
if (full) {
- if (ft->encoding.bits_per_sample > 8)
+ if (ft->encoding.bits_per_sample > 8 || (ft->handler.flags & SOX_FILE_ENDIAN))
fprintf(output, "Endian Type : %s\n",
ft->encoding.reverse_bytes != SOX_IS_BIGENDIAN ? "big" : "little");
if (ft->encoding.bits_per_sample)
@@ -1266,11 +1266,11 @@
static sox_bool parse_gopts_and_fopts(file_t f, int argc, char **argv)
{
while (sox_true) {
- int option_index;
+ int c, option_index;
int i; /* sscanf silently accepts negative numbers for %u :( */
char dummy; /* To check for extraneous chars in optarg. */
- switch (getopt_long(argc, argv, getoptstr, long_options, &option_index)) {
+ switch (c=getopt_long(argc, argv, getoptstr, long_options, &option_index)) {
case -1: /* @ one of: file-name, effect name, end of arg-list. */
return sox_false; /* i.e. not null file. */
@@ -1306,10 +1306,12 @@
break;
case 5:
+ if (f->encoding.reverse_bytes != SOX_OPTION_DEFAULT || f->encoding.opposite_endian)
+ usage("only one endian option per file is allowed");
switch (enum_option(option_index, endian_options)) {
case ENDIAN_little: f->encoding.reverse_bytes = SOX_IS_BIGENDIAN; break;
case ENDIAN_big: f->encoding.reverse_bytes = SOX_IS_LITTLEENDIAN; break;
- case ENDIAN_swap: f->encoding.reverse_bytes = sox_true; break;
+ case ENDIAN_swap: f->encoding.opposite_endian = sox_true; break;
}
break;
@@ -1419,9 +1421,15 @@
f->encoding.bits_per_sample = 8;
break;
- case 'L': f->encoding.reverse_bytes = SOX_IS_BIGENDIAN; break;
- case 'B': f->encoding.reverse_bytes = SOX_IS_LITTLEENDIAN; break;
- case 'x': f->encoding.reverse_bytes = SOX_OPTION_YES; break;
+ case 'L': case 'B': case 'x':
+ if (f->encoding.reverse_bytes != SOX_OPTION_DEFAULT || f->encoding.opposite_endian)
+ usage("only one endian option per file is allowed");
+ switch (c) {
+ case 'L': f->encoding.reverse_bytes = SOX_IS_BIGENDIAN; break;
+ case 'B': f->encoding.reverse_bytes = SOX_IS_LITTLEENDIAN; break;
+ case 'x': f->encoding.opposite_endian = sox_true; break;
+ }
+ break;
case 'X': f->encoding.reverse_bits = SOX_OPTION_YES; break;
case 'N': f->encoding.reverse_nibbles = SOX_OPTION_YES; break;
--- a/src/sox.h
+++ b/src/sox.h
@@ -232,6 +232,7 @@
* indicate to the libSoX core if they have a preference using
* SOX_FILE_xxx flags.
*/
+ sox_bool opposite_endian;
sox_option_t reverse_bytes; /* endiannesses... */
sox_option_t reverse_nibbles;
sox_option_t reverse_bits;
--- a/src/sox_i.h
+++ b/src/sox_i.h
@@ -149,6 +149,7 @@
int sox_reads(sox_format_t * ft, char *c, sox_size_t len);
int sox_writes(sox_format_t * ft, char const * c);
void set_signal_defaults(sox_signalinfo_t * signal);
+#define sox_writechars(ft, chars, len) (sox_writebuf(ft, chars, len) == len? SOX_SUCCESS : SOX_EOF)
sox_size_t sox_read_b_buf(sox_format_t * ft, uint8_t *buf, sox_size_t len);
sox_size_t sox_read_w_buf(sox_format_t * ft, uint16_t *buf, sox_size_t len);
@@ -164,20 +165,23 @@
sox_size_t sox_write_f_buf(sox_format_t * ft, float *buf, sox_size_t len);
sox_size_t sox_write_df_buf(sox_format_t * ft, double *buf, sox_size_t len);
-#define sox_readb(ft, ub) (sox_read_b_buf(ft, ub, 1) == 1 ? SOX_SUCCESS : SOX_EOF)
+int sox_read3(sox_format_t * ft, uint24_t * u3);
+int sox_readb(sox_format_t * ft, uint8_t * ub);
+int sox_readdf(sox_format_t * ft, double * d);
+int sox_readdw(sox_format_t * ft, uint32_t * udw);
+int sox_readf(sox_format_t * ft, float * f);
+int sox_readw(sox_format_t * ft, uint16_t * uw);
+int sox_readchars(sox_format_t * ft, char * chars, sox_size_t len);
+
+int sox_write3(sox_format_t * ft, unsigned u3);
int sox_writeb(sox_format_t * ft, unsigned ub);
-#define sox_readw(ft, uw) (sox_read_w_buf(ft, uw, 1) == 1 ? SOX_SUCCESS : SOX_EOF)
-int sox_writew(sox_format_t * ft, unsigned uw);
+int sox_writedw(sox_format_t * ft, unsigned udw);
+int sox_writef(sox_format_t * ft, double f);
int sox_writesb(sox_format_t * ft, signed);
int sox_writesw(sox_format_t * ft, signed);
-#define sox_read3(ft, u3) (sox_read_3_buf(ft, u3, 1) == 1 ? SOX_SUCCESS : SOX_EOF)
-int sox_write3(sox_format_t * ft, unsigned u3);
-#define sox_readdw(ft, udw) (sox_read_dw_buf(ft, udw, 1) == 1 ? SOX_SUCCESS : SOX_EOF)
-int sox_writedw(sox_format_t * ft, unsigned udw);
-#define sox_readf(ft, f) (sox_read_f_buf(ft, f, 1) == 1 ? SOX_SUCCESS : SOX_EOF)
-int sox_writef(sox_format_t * ft, float f);
-#define sox_readdf(ft, d) (sox_read_df_buf(ft, d, 1) == 1 ? SOX_SUCCESS : SOX_EOF)
+int sox_writew(sox_format_t * ft, unsigned uw);
int sox_writedf(sox_format_t * ft, double d);
+
int sox_seeki(sox_format_t * ft, sox_ssize_t to_sample, int whence);
int sox_offset_seek(sox_format_t * ft, off_t byte_offset, sox_size_t to_sample);
sox_size_t sox_filelength(sox_format_t * ft);
@@ -296,8 +300,6 @@
extern sox_globals_t sox_globals;
extern sox_effects_globals_t sox_effects_globals;
-
-extern const char sox_readerr[];
extern uint8_t const cswap[256];
--- a/src/test-comments
+++ b/src/test-comments
@@ -27,17 +27,10 @@
cp $tmp.au $tmp.comment.au
cat > $tmp.i << .
-TITLE=The First Track
-ARTIST=A Band Of Musicians
+TITLE=First Track
+ARTIST=A Band
ALBUM=A Collection Of Songs
-DATE=2008
TRACKNUMBER=01
-TRACKTOTAL=14
-GENRE=Music
-REPLAYGAIN_TRACK_PEAK=1.00515676
-REPLAYGAIN_TRACK_GAIN=-3.97 dB
-REPLAYGAIN_ALBUM_PEAK=1.00515676
-REPLAYGAIN_ALBUM_GAIN=-2.88 dB
.
./sox monkey.au --comment-file $tmp.i $tmp.comments.au
@@ -77,7 +70,8 @@
./sox $tmp.comments.au $tmp.flac
./sox $tmp.flac $tmp.sf
./sox $tmp.sf $tmp.ogg
-./sox $tmp.ogg $tmp.au
+./sox $tmp.ogg $tmp.sndt
+./sox $tmp.sndt $tmp.au
check_file $tmp.au $tmp.i
rm -f $tmp.*
--- a/src/tests.sh
+++ b/src/tests.sh
@@ -158,7 +158,7 @@
convertToAndFrom ima s2 u2 s3 u3 s4 u4 raw Raw dat au aiff aifc flac caf # FIXME: vox wav
format1=wav1u
- convertToAndFrom smp s1 s1X s1N s1XN sndt
+ convertToAndFrom smp s1 s1X s1N s1XN sndt sndr
#(rate=50000; convertToAndFrom txw) || exit 1 # FIXME
(rate=11025; convertToAndFrom hcom) || exit 1 # Fixed rates
--- a/src/wav.c
+++ b/src/wav.c
@@ -1324,7 +1324,7 @@
/* If user specified opposite swap than we think, assume they are
* asking to write a RIFX file.
*/
- if (ft->encoding.reverse_bytes && SOX_IS_LITTLEENDIAN)
+ if (ft->encoding.reverse_bytes == SOX_IS_LITTLEENDIAN)
{
if (!second_header)
sox_report("Requested to swap bytes so writing RIFX header");
--- a/src/wve.c
+++ b/src/wve.c
@@ -29,8 +29,8 @@
char buf[sizeof(ID1)];
uint32_t num_samples;
- if (sox_readbuf(ft, buf, sizeof(buf)) != sizeof(buf) ||
- sox_readdw(ft, &num_samples) || sox_skipbytes(ft, sizeof(ID2)))
+ if (sox_readchars(ft, buf, sizeof(buf)) || sox_readdw(ft, &num_samples) ||
+ sox_skipbytes(ft, sizeof(ID2)))
return SOX_EOF;
if (memcmp(ID1, buf, sizeof(buf))) {
sox_fail_errno(ft, SOX_EHDR, "wve: can't find Psion identifier");
@@ -41,9 +41,9 @@
static int write_header(sox_format_t * ft)
{
- return sox_writebuf(ft, ID1, sizeof(ID1)) != sizeof(ID1)
+ return sox_writechars(ft, ID1, sizeof(ID1))
|| sox_writedw(ft, ft->olength? ft->olength:ft->length)
- || sox_writebuf(ft, ID2, sizeof(ID2)) != sizeof(ID2)? SOX_EOF:SOX_SUCCESS;
+ || sox_writechars(ft, ID2, sizeof(ID2))? SOX_EOF:SOX_SUCCESS;
}
SOX_FORMAT_HANDLER(wve)