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 * an IFF format; description at http://lclevy.free.fr/amiga/MAUDINFO.TXT
7 * Copyright 1998-2006 Chris Bagwell and SoX Contributors
8 * This source code is freely redistributable and may be used for
9 * any purpose. This copyright notice must be maintained.
10 * Lance Norskog And Sundry Contributors are not responsible for
11 * the consequences of using this software.
20 /* Private data for MAUD file */
25 static void maudwriteheader(sox_format_t
*);
28 * Do anything required before you start reading samples.
30 * Find out sampling rate,
31 * size and encoding of samples,
34 static int startread(sox_format_t
* ft
)
36 priv_t
* p
= (priv_t
*) ft
->priv
;
41 unsigned short bitpersam
;
44 unsigned short chaninf
;
51 /* Needed for rawread() */
52 rc
= lsx_rawstartread(ft
);
57 if (lsx_reads(ft
, buf
, (size_t)4) == SOX_EOF
|| strncmp(buf
, "FORM", (size_t)4) != 0)
59 lsx_fail_errno(ft
,SOX_EHDR
,"MAUD: header does not begin with magic word `FORM'");
63 lsx_readdw(ft
, &trash32
); /* totalsize */
65 if (lsx_reads(ft
, buf
, (size_t)4) == SOX_EOF
|| strncmp(buf
, "MAUD", (size_t)4) != 0)
67 lsx_fail_errno(ft
,SOX_EHDR
,"MAUD: `FORM' chunk does not specify `MAUD' as type");
71 /* read chunks until 'BODY' (or end) */
73 while (lsx_reads(ft
, buf
, (size_t)4) == SOX_SUCCESS
&& strncmp(buf
,"MDAT",(size_t)4) != 0) {
77 lsx_debug("chunk %s",buf);
80 if (strncmp(buf
,"MHDR",(size_t)4) == 0) {
82 lsx_readdw(ft
, &chunksize
);
85 lsx_fail_errno(ft
,SOX_EHDR
,"MAUD: MHDR chunk has bad size");
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 priv_t
*p
= (priv_t
*)ft
->priv
;
231 uint32_t mdat_size
; /* MDAT chunk size */
232 mdat_size
= p
->nsamples
* (ft
->encoding
.bits_per_sample
>> 3);
233 lsx_padbytes(ft
, (size_t) (mdat_size
%2));
235 if (lsx_seeki(ft
, (off_t
)0, 0) != 0)
237 lsx_fail_errno(ft
,errno
,"can't rewind output file to rewrite MAUD header");
245 #define MAUDHEADERSIZE (4+(4+4+32)+(4+4+19+1)+(4+4))
246 static void maudwriteheader(sox_format_t
* ft
)
248 priv_t
* p
= (priv_t
*) ft
->priv
;
249 uint32_t mdat_size
; /* MDAT chunk size */
251 mdat_size
= p
->nsamples
* (ft
->encoding
.bits_per_sample
>> 3);
253 lsx_writes(ft
, "FORM");
254 lsx_writedw(ft
, MAUDHEADERSIZE
+ mdat_size
+ mdat_size
%2); /* size of file */
255 lsx_writes(ft
, "MAUD"); /* File type */
257 lsx_writes(ft
, "MHDR");
258 lsx_writedw(ft
, 8*4); /* number of bytes to follow */
259 lsx_writedw(ft
, p
->nsamples
); /* number of samples stored in MDAT */
261 switch (ft
->encoding
.encoding
) {
263 case SOX_ENCODING_UNSIGNED
:
264 lsx_writew(ft
, 8); /* number of bits per sample as stored in MDAT */
265 lsx_writew(ft
, 8); /* number of bits per sample after decompression */
268 case SOX_ENCODING_SIGN2
:
269 lsx_writew(ft
, 16); /* number of bits per sample as stored in MDAT */
270 lsx_writew(ft
, 16); /* number of bits per sample after decompression */
273 case SOX_ENCODING_ALAW
:
274 case SOX_ENCODING_ULAW
:
275 lsx_writew(ft
, 8); /* number of bits per sample as stored in MDAT */
276 lsx_writew(ft
, 16); /* number of bits per sample after decompression */
283 lsx_writedw(ft
, (unsigned)(ft
->signal
.rate
+ .5)); /* sample rate, Hz */
284 lsx_writew(ft
, (int) 1); /* clock devide */
286 if (ft
->signal
.channels
== 1) {
287 lsx_writew(ft
, 0); /* channel information */
288 lsx_writew(ft
, 1); /* number of channels (mono: 1, stereo: 2, ...) */
295 switch (ft
->encoding
.encoding
) {
297 case SOX_ENCODING_UNSIGNED
:
298 case SOX_ENCODING_SIGN2
:
299 lsx_writew(ft
, 0); /* no compression */
302 case SOX_ENCODING_ULAW
:
306 case SOX_ENCODING_ALAW
:
314 lsx_writedw(ft
, 0); /* reserved */
315 lsx_writedw(ft
, 0); /* reserved */
316 lsx_writedw(ft
, 0); /* reserved */
318 lsx_writes(ft
, "ANNO");
319 lsx_writedw(ft
, 19); /* length of block */
320 lsx_writes(ft
, "file created by SoX");
321 lsx_padbytes(ft
, (size_t)1);
323 lsx_writes(ft
, "MDAT");
324 lsx_writedw(ft
, p
->nsamples
* (ft
->encoding
.bits_per_sample
>> 3)); /* samples in file */
327 LSX_FORMAT_HANDLER(maud
)
329 static char const * const names
[] = {"maud", NULL
};
330 static unsigned const write_encodings
[] = {
331 SOX_ENCODING_SIGN2
, 16, 0,
332 SOX_ENCODING_UNSIGNED
, 8, 0,
333 SOX_ENCODING_ULAW
, 8, 0,
334 SOX_ENCODING_ALAW
, 8, 0,
336 static sox_format_handler_t
const handler
= {SOX_LIB_VERSION_CODE
,
337 "Used with the ‘Toccata’ sound-card on the Amiga",
338 names
, SOX_FILE_BIG_END
| SOX_FILE_MONO
| SOX_FILE_STEREO
,
339 startread
, lsx_rawread
, lsx_rawstopread
,
340 startwrite
, write_samples
, stopwrite
,
341 NULL
, write_encodings
, NULL
, sizeof(priv_t
)