1 /* libSoX Sun format with header (SunOS 4.1; see /usr/demo/SOUND).
2 * Copyright 1991, 1992, 1993 Guido van Rossum And Sundry Contributors.
4 * This source code is freely redistributable and may be used for
5 * any purpose. This copyright notice must be maintained.
6 * Guido van Rossum And Sundry Contributors are not responsible for
7 * the consequences of using this software.
9 * October 7, 1998 - cbagwell@sprynet.com
10 * G.723 was using incorrect # of bits. Corrected to 3 and 5 bits.
12 * NeXT uses this format also, but has more format codes defined.
13 * DEC uses a slight variation and swaps bytes.
14 * We support only the common formats, plus
15 * CCITT G.721 (32 kbit/s) and G.723 (24/40 kbit/s),
16 * courtesy of Sun's public domain implementation.
23 /* Magic numbers used in Sun and NeXT audio files */
24 static struct {char str
[4]; sox_bool reverse_bytes
; char const * desc
;} id
[] = {
25 {"\x2e\x73\x6e\x64", MACHINE_IS_LITTLEENDIAN
, "big-endian `.snd'"},
26 {"\x64\x6e\x73\x2e", MACHINE_IS_BIGENDIAN
, "little-endian `.snd'"},
27 {"\x00\x64\x73\x2e", MACHINE_IS_BIGENDIAN
, "little-endian `\\0ds.' (for DEC)"},
28 {"\x2e\x73\x64\x00", MACHINE_IS_LITTLEENDIAN
, "big-endian `\\0ds.'"},
32 #define SUN_UNSPEC ~0u /* Unspecified data size (this is legal) */
35 Unspecified
, Mulaw_8
, Linear_8
, Linear_16
, Linear_24
, Linear_32
, Float
,
36 Double
, Indirect
, Nested
, Dsp_core
, Dsp_data_8
, Dsp_data_16
, Dsp_data_24
,
37 Dsp_data_32
, Unknown
, Display
, Mulaw_squelch
, Emphasized
, Compressed
,
38 Compressed_emphasized
, Dsp_commands
, Dsp_commands_samples
, Adpcm_g721
,
39 Adpcm_g722
, Adpcm_g723_3
, Adpcm_g723_5
, Alaw_8
, Unknown_other
} ft_encoding_t
;
40 static char const * const str
[] = {
41 "Unspecified", "8-bit mu-law", "8-bit signed linear", "16-bit signed linear",
42 "24-bit signed linear", "32-bit signed linear", "Floating-point",
43 "Double precision float", "Fragmented sampled data", "Unknown", "DSP program",
44 "8-bit fixed-point", "16-bit fixed-point", "24-bit fixed-point",
45 "32-bit fixed-point", "Unknown", "Non-audio data", "Mu-law squelch",
46 "16-bit linear with emphasis", "16-bit linear with compression",
47 "16-bit linear with emphasis and compression", "Music Kit DSP commands",
48 "Music Kit DSP samples", "4-bit G.721 ADPCM", "G.722 ADPCM",
49 "3-bit G.723 ADPCM", "5-bit G.723 ADPCM", "8-bit a-law", "Unknown"};
51 static ft_encoding_t
ft_enc(unsigned size
, sox_encoding_t encoding
)
53 if (encoding
== SOX_ENCODING_ULAW
&& size
== 8) return Mulaw_8
;
54 if (encoding
== SOX_ENCODING_ALAW
&& size
== 8) return Alaw_8
;
55 if (encoding
== SOX_ENCODING_SIGN2
&& size
== 8) return Linear_8
;
56 if (encoding
== SOX_ENCODING_SIGN2
&& size
== 16) return Linear_16
;
57 if (encoding
== SOX_ENCODING_SIGN2
&& size
== 24) return Linear_24
;
58 if (encoding
== SOX_ENCODING_SIGN2
&& size
== 32) return Linear_32
;
59 if (encoding
== SOX_ENCODING_FLOAT
&& size
== 32) return Float
;
60 if (encoding
== SOX_ENCODING_FLOAT
&& size
== 64) return Double
;
64 static sox_encoding_t
sox_enc(uint32_t ft_encoding
, unsigned * size
)
66 switch (ft_encoding
) {
67 case Mulaw_8
: *size
= 8; return SOX_ENCODING_ULAW
;
68 case Alaw_8
: *size
= 8; return SOX_ENCODING_ALAW
;
69 case Linear_8
: *size
= 8; return SOX_ENCODING_SIGN2
;
70 case Linear_16
: *size
= 16; return SOX_ENCODING_SIGN2
;
71 case Linear_24
: *size
= 24; return SOX_ENCODING_SIGN2
;
72 case Linear_32
: *size
= 32; return SOX_ENCODING_SIGN2
;
73 case Float
: *size
= 32; return SOX_ENCODING_FLOAT
;
74 case Double
: *size
= 64; return SOX_ENCODING_FLOAT
;
75 case Adpcm_g721
: *size
= 4; return SOX_ENCODING_G721
; /* read-only */
76 case Adpcm_g723_3
: *size
= 3; return SOX_ENCODING_G723
; /* read-only */
77 case Adpcm_g723_5
: *size
= 5; return SOX_ENCODING_G723
; /* read-only */
78 default: return SOX_ENCODING_UNKNOWN
;
82 typedef struct { /* For G72x decoding: */
83 struct g72x_state state
;
84 int (*dec_routine
)(int i
, int out_coding
, struct g72x_state
*state_ptr
);
85 unsigned int in_buffer
;
90 * Unpack input codes and pass them back as bytes.
91 * Returns 1 if there is residual input, returns -1 if eof, else returns 0.
92 * (Adapted from Sun's decode.c.)
94 static int unpack_input(sox_format_t
* ft
, unsigned char *code
)
96 priv_t
* p
= (priv_t
*) ft
->priv
;
97 unsigned char in_byte
;
99 if (p
->in_bits
< (int)ft
->encoding
.bits_per_sample
) {
100 if (lsx_read_b_buf(ft
, &in_byte
, (size_t) 1) != 1) {
104 p
->in_buffer
|= (in_byte
<< p
->in_bits
);
107 *code
= p
->in_buffer
& ((1 << ft
->encoding
.bits_per_sample
) - 1);
108 p
->in_buffer
>>= ft
->encoding
.bits_per_sample
;
109 p
->in_bits
-= ft
->encoding
.bits_per_sample
;
110 return p
->in_bits
> 0;
113 static size_t dec_read(sox_format_t
*ft
, sox_sample_t
*buf
, size_t samp
)
115 priv_t
* p
= (priv_t
*)ft
->priv
;
119 for (done
= 0; samp
> 0 && unpack_input(ft
, &code
) >= 0; ++done
, --samp
)
120 *buf
++ = SOX_SIGNED_16BIT_TO_SAMPLE(
121 (*p
->dec_routine
)(code
, AUDIO_ENCODING_LINEAR
, &p
->state
),);
125 static int startread(sox_format_t
* ft
)
127 priv_t
* p
= (priv_t
*) ft
->priv
;
128 char magic
[4]; /* These 6 variables represent a Sun sound */
129 uint32_t hdr_size
; /* header on disk. The uint32_t are written as */
130 uint32_t data_size
; /* big-endians. At least extra bytes (totalling */
131 uint32_t ft_encoding
; /* hdr_size - FIXED_HDR) are an "info" field of */
132 uint32_t rate
; /* unspecified nature, usually a string. By */
133 uint32_t channels
; /* convention the header size is a multiple of 4. */
134 unsigned i
, bits_per_sample
;
135 sox_encoding_t encoding
;
137 if (lsx_readchars(ft
, magic
, sizeof(magic
)))
140 for (i
= 0; id
[i
].desc
&& memcmp(magic
, id
[i
].str
, sizeof(magic
)); ++i
);
142 lsx_fail_errno(ft
, SOX_EHDR
, "au: can't find Sun/NeXT/DEC identifier");
145 lsx_report("found %s identifier", id
[i
].desc
);
146 ft
->encoding
.reverse_bytes
= id
[i
].reverse_bytes
;
148 if (lsx_readdw(ft
, &hdr_size
) ||
149 lsx_readdw(ft
, &data_size
) || /* Can be SUN_UNSPEC */
150 lsx_readdw(ft
, &ft_encoding
) ||
151 lsx_readdw(ft
, &rate
) ||
152 lsx_readdw(ft
, &channels
))
155 if (hdr_size
< FIXED_HDR
) {
156 lsx_fail_errno(ft
, SOX_EHDR
, "header size %u is too small", hdr_size
);
159 if (hdr_size
< FIXED_HDR
+ 4)
160 lsx_warn("header size %u is too small", hdr_size
);
162 if (!(encoding
= sox_enc(ft_encoding
, &bits_per_sample
))) {
163 int n
= min(ft_encoding
, Unknown_other
);
164 lsx_fail_errno(ft
, SOX_EFMT
, "unsupported encoding `%s' (%#x)", str
[n
], ft_encoding
);
168 switch (ft_encoding
) {
169 case Adpcm_g721
: p
->dec_routine
= g721_decoder
; break;
170 case Adpcm_g723_3
: p
->dec_routine
= g723_24_decoder
; break;
171 case Adpcm_g723_5
: p
->dec_routine
= g723_40_decoder
; break;
173 if (p
->dec_routine
) {
174 g72x_init_state(&p
->state
);
175 ft
->handler
.seek
= NULL
;
176 ft
->handler
.read
= dec_read
;
179 if (hdr_size
> FIXED_HDR
) {
180 size_t info_size
= hdr_size
- FIXED_HDR
;
181 char * buf
= lsx_calloc(1, info_size
+ 1); /* +1 ensures null-terminated */
182 if (lsx_readchars(ft
, buf
, info_size
) != SOX_SUCCESS
) {
186 sox_append_comments(&ft
->oob
.comments
, buf
);
189 if (data_size
== SUN_UNSPEC
)
190 data_size
= SOX_UNSPEC
;
191 return lsx_check_read_params(ft
, channels
, (sox_rate_t
)rate
, encoding
,
192 bits_per_sample
, div_bits(data_size
, bits_per_sample
), sox_true
);
195 static int write_header(sox_format_t
* ft
)
197 char * comment
= lsx_cat_comments(ft
->oob
.comments
);
198 size_t len
= strlen(comment
) + 1; /* Write out null-terminated */
199 size_t info_len
= max(4, (len
+ 3) & ~3u); /* Minimum & multiple of 4 bytes */
200 int i
= ft
->encoding
.reverse_bytes
== MACHINE_IS_BIGENDIAN
? 2 : 0;
201 uint64_t size64
= ft
->olength
? ft
->olength
: ft
->signal
.length
;
202 unsigned size
= size64
== SOX_UNSPEC
204 : size64
*(ft
->encoding
.bits_per_sample
>> 3) > UINT_MAX
206 : (unsigned)(size64
*(ft
->encoding
.bits_per_sample
>> 3));
207 sox_bool error
= sox_false
208 ||lsx_writechars(ft
, id
[i
].str
, sizeof(id
[i
].str
))
209 ||lsx_writedw(ft
, FIXED_HDR
+ (unsigned)info_len
)
210 ||lsx_writedw(ft
, size
)
211 ||lsx_writedw(ft
, ft_enc(ft
->encoding
.bits_per_sample
, ft
->encoding
.encoding
))
212 ||lsx_writedw(ft
, (unsigned)(ft
->signal
.rate
+ .5))
213 ||lsx_writedw(ft
, ft
->signal
.channels
)
214 ||lsx_writechars(ft
, comment
, len
)
215 ||lsx_padbytes(ft
, info_len
- len
);
217 return error
? SOX_EOF
: SOX_SUCCESS
;
220 LSX_FORMAT_HANDLER(au
)
222 static char const * const names
[] = {"au", "snd", NULL
};
223 static unsigned const write_encodings
[] = {
224 SOX_ENCODING_ULAW
, 8, 0,
225 SOX_ENCODING_ALAW
, 8, 0,
226 SOX_ENCODING_SIGN2
, 8, 16, 24, 32, 0,
227 SOX_ENCODING_FLOAT
, 32, 64, 0,
229 static sox_format_handler_t
const handler
= {SOX_LIB_VERSION_CODE
,
230 "PCM file format used widely on Sun systems",
231 names
, SOX_FILE_BIG_END
| SOX_FILE_REWIND
,
232 startread
, lsx_rawread
, NULL
,
233 write_header
, lsx_rawwrite
, NULL
,
234 lsx_rawseek
, write_encodings
, NULL
, sizeof(priv_t
)