1 /* libSoX MAUD file format handler, by Lutz Vieweg 1993
3 * supports: mono and stereo, linear, a-law and u-law reading and writing
5 * Copyright 1998-2006 Chris Bagwell and SoX Contributors
6 * This source code is freely redistributable and may be used for
7 * any purpose. This copyright notice must be maintained.
8 * Lance Norskog And Sundry Contributors are not responsible for
9 * the consequences of using this software.
18 /* Private data for MAUD file */
23 static void maudwriteheader(sox_format_t
*);
26 * Do anything required before you start reading samples.
28 * Find out sampling rate,
29 * size and encoding of samples,
32 static int startread(sox_format_t
* ft
)
34 priv_t
* p
= (priv_t
*) ft
->priv
;
39 unsigned short bitpersam
;
42 unsigned short chaninf
;
49 /* Needed for rawread() */
50 rc
= lsx_rawstartread(ft
);
55 if (lsx_reads(ft
, buf
, (size_t)4) == SOX_EOF
|| strncmp(buf
, "FORM", (size_t)4) != 0)
57 lsx_fail_errno(ft
,SOX_EHDR
,"MAUD: header does not begin with magic word `FORM'");
61 lsx_readdw(ft
, &trash32
); /* totalsize */
63 if (lsx_reads(ft
, buf
, (size_t)4) == SOX_EOF
|| strncmp(buf
, "MAUD", (size_t)4) != 0)
65 lsx_fail_errno(ft
,SOX_EHDR
,"MAUD: `FORM' chunk does not specify `MAUD' as type");
69 /* read chunks until 'BODY' (or end) */
71 while (lsx_reads(ft
, buf
, (size_t)4) == SOX_SUCCESS
&& strncmp(buf
,"MDAT",(size_t)4) != 0) {
75 lsx_debug("chunk %s",buf);
78 if (strncmp(buf
,"MHDR",(size_t)4) == 0) {
80 lsx_readdw(ft
, &chunksize
);
83 lsx_fail_errno(ft
,SOX_EHDR
,"MAUD: MHDR chunk has bad size");
87 /* fseeko(ft->fp,12,SEEK_CUR); */
89 /* number of samples stored in MDAT */
90 lsx_readdw(ft
, &(p
->nsamples
));
92 /* number of bits per sample as stored in MDAT */
93 lsx_readw(ft
, &bitpersam
);
95 /* number of bits per sample after decompression */
96 lsx_readw(ft
, &trash16
);
98 lsx_readdw(ft
, &nom
); /* clock source frequency */
99 lsx_readw(ft
, &denom
); /* clock devide */
102 lsx_fail_errno(ft
,SOX_EHDR
,"MAUD: frequency denominator == 0, failed");
106 ft
->signal
.rate
= nom
/ denom
;
108 lsx_readw(ft
, &chaninf
); /* channel information */
111 ft
->signal
.channels
= 1;
114 ft
->signal
.channels
= 2;
117 lsx_fail_errno(ft
,SOX_EFMT
,"MAUD: unsupported number of channels in file");
121 lsx_readw(ft
, &chaninf
); /* number of channels (mono: 1, stereo: 2, ...) */
122 if (chaninf
!= ft
->signal
.channels
)
124 lsx_fail_errno(ft
,SOX_EFMT
,"MAUD: unsupported number of channels in file");
128 lsx_readw(ft
, &chaninf
); /* compression type */
130 lsx_readdw(ft
, &trash32
); /* rest of chunk, unused yet */
131 lsx_readdw(ft
, &trash32
);
132 lsx_readdw(ft
, &trash32
);
134 if (bitpersam
== 8 && chaninf
== 0) {
135 ft
->encoding
.bits_per_sample
= 8;
136 ft
->encoding
.encoding
= SOX_ENCODING_UNSIGNED
;
138 else if (bitpersam
== 8 && chaninf
== 2) {
139 ft
->encoding
.bits_per_sample
= 8;
140 ft
->encoding
.encoding
= SOX_ENCODING_ALAW
;
142 else if (bitpersam
== 8 && chaninf
== 3) {
143 ft
->encoding
.bits_per_sample
= 8;
144 ft
->encoding
.encoding
= SOX_ENCODING_ULAW
;
146 else if (bitpersam
== 16 && chaninf
== 0) {
147 ft
->encoding
.bits_per_sample
= 16;
148 ft
->encoding
.encoding
= SOX_ENCODING_SIGN2
;
152 lsx_fail_errno(ft
,SOX_EFMT
,"MAUD: unsupported compression type detected");
159 if (strncmp(buf
,"ANNO",(size_t)4) == 0) {
160 lsx_readdw(ft
, &chunksize
);
163 chunk_buf
= lsx_malloc(chunksize
+ (size_t)1);
164 if (lsx_readbuf(ft
, chunk_buf
, (size_t)chunksize
)
167 lsx_fail_errno(ft
,SOX_EOF
,"MAUD: Unexpected EOF in ANNO header");
170 chunk_buf
[chunksize
] = '\0';
171 lsx_debug("%s",chunk_buf
);
177 /* some other kind of chunk */
178 lsx_readdw(ft
, &chunksize
);
181 lsx_seeki(ft
, (off_t
)chunksize
, SEEK_CUR
);
186 if (strncmp(buf
,"MDAT",(size_t)4) != 0)
188 lsx_fail_errno(ft
,SOX_EFMT
,"MAUD: MDAT chunk not found");
191 lsx_readdw(ft
, &(p
->nsamples
));
195 static int startwrite(sox_format_t
* ft
)
197 priv_t
* p
= (priv_t
*) ft
->priv
;
200 /* Needed for rawwrite() */
201 rc
= lsx_rawstartwrite(ft
);
205 /* If you have to seek around the output file */
208 lsx_fail_errno(ft
,SOX_EOF
,"Output .maud file must be a file, not a pipe");
211 p
->nsamples
= 0x7f000000;
214 return (SOX_SUCCESS
);
217 static size_t write_samples(sox_format_t
* ft
, const sox_sample_t
*buf
, size_t len
)
219 priv_t
* p
= (priv_t
*) ft
->priv
;
223 return lsx_rawwrite(ft
, buf
, len
);
226 static int stopwrite(sox_format_t
* ft
)
228 /* All samples are already written out. */
230 if (lsx_seeki(ft
, (off_t
)0, 0) != 0)
232 lsx_fail_errno(ft
,errno
,"can't rewind output file to rewrite MAUD header");
240 #define MAUDHEADERSIZE (4+(4+4+32)+(4+4+32)+(4+4))
241 static void maudwriteheader(sox_format_t
* ft
)
243 priv_t
* p
= (priv_t
*) ft
->priv
;
245 lsx_writes(ft
, "FORM");
246 lsx_writedw(ft
, (p
->nsamples
* (ft
->encoding
.bits_per_sample
>> 3)) + MAUDHEADERSIZE
); /* size of file */
247 lsx_writes(ft
, "MAUD"); /* File type */
249 lsx_writes(ft
, "MHDR");
250 lsx_writedw(ft
, 8*4); /* number of bytes to follow */
251 lsx_writedw(ft
, p
->nsamples
); /* number of samples stored in MDAT */
253 switch (ft
->encoding
.encoding
) {
255 case SOX_ENCODING_UNSIGNED
:
256 lsx_writew(ft
, 8); /* number of bits per sample as stored in MDAT */
257 lsx_writew(ft
, 8); /* number of bits per sample after decompression */
260 case SOX_ENCODING_SIGN2
:
261 lsx_writew(ft
, 16); /* number of bits per sample as stored in MDAT */
262 lsx_writew(ft
, 16); /* number of bits per sample after decompression */
265 case SOX_ENCODING_ALAW
:
266 case SOX_ENCODING_ULAW
:
267 lsx_writew(ft
, 8); /* number of bits per sample as stored in MDAT */
268 lsx_writew(ft
, 16); /* number of bits per sample after decompression */
275 lsx_writedw(ft
, (unsigned)(ft
->signal
.rate
+ .5)); /* sample rate, Hz */
276 lsx_writew(ft
, (int) 1); /* clock devide */
278 if (ft
->signal
.channels
== 1) {
279 lsx_writew(ft
, 0); /* channel information */
280 lsx_writew(ft
, 1); /* number of channels (mono: 1, stereo: 2, ...) */
287 switch (ft
->encoding
.encoding
) {
289 case SOX_ENCODING_UNSIGNED
:
290 case SOX_ENCODING_SIGN2
:
291 lsx_writew(ft
, 0); /* no compression */
294 case SOX_ENCODING_ULAW
:
298 case SOX_ENCODING_ALAW
:
306 lsx_writedw(ft
, 0); /* reserved */
307 lsx_writedw(ft
, 0); /* reserved */
308 lsx_writedw(ft
, 0); /* reserved */
310 lsx_writes(ft
, "ANNO");
311 lsx_writedw(ft
, 30); /* length of block */
312 lsx_writes(ft
, "file create by Sound eXchange ");
314 lsx_writes(ft
, "MDAT");
315 lsx_writedw(ft
, p
->nsamples
* (ft
->encoding
.bits_per_sample
>> 3)); /* samples in file */
318 LSX_FORMAT_HANDLER(maud
)
320 static char const * const names
[] = {"maud", NULL
};
321 static unsigned const write_encodings
[] = {
322 SOX_ENCODING_SIGN2
, 16, 0,
323 SOX_ENCODING_UNSIGNED
, 8, 0,
324 SOX_ENCODING_ULAW
, 8, 0,
325 SOX_ENCODING_ALAW
, 8, 0,
327 static sox_format_handler_t
const handler
= {SOX_LIB_VERSION_CODE
,
328 "Used with the ‘Toccata’ sound-card on the Amiga",
329 names
, SOX_FILE_BIG_END
| SOX_FILE_MONO
| SOX_FILE_STEREO
,
330 startread
, lsx_rawread
, lsx_rawstopread
,
331 startwrite
, write_samples
, stopwrite
,
332 NULL
, write_encodings
, NULL
, sizeof(priv_t
)