parent
eeef1e1e0c
commit
3510350c01
@ -1,344 +0,0 @@ |
||||
/* libSoX MAUD file format handler, by Lutz Vieweg 1993
|
||||
* |
||||
* supports: mono and stereo, linear, a-law and u-law reading and writing |
||||
* |
||||
* an IFF format; description at http://lclevy.free.fr/amiga/MAUDINFO.TXT
|
||||
* |
||||
* Copyright 1998-2006 Chris Bagwell and SoX 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. |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
#include <string.h> |
||||
#include <stdlib.h> |
||||
#include <stdio.h> |
||||
#include <errno.h> |
||||
|
||||
/* Private data for MAUD file */ |
||||
typedef struct { |
||||
uint32_t nsamples; |
||||
} priv_t; |
||||
|
||||
static void maudwriteheader(sox_format_t *); |
||||
|
||||
/*
|
||||
* 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) |
||||
{ |
||||
priv_t * p = (priv_t *) ft->priv; |
||||
|
||||
char buf[12]; |
||||
char *chunk_buf; |
||||
|
||||
unsigned short bitpersam; |
||||
uint32_t nom; |
||||
unsigned short denom; |
||||
unsigned short chaninf; |
||||
|
||||
uint32_t chunksize; |
||||
uint32_t trash32; |
||||
uint16_t trash16; |
||||
int rc; |
||||
|
||||
/* Needed for rawread() */ |
||||
rc = lsx_rawstartread(ft); |
||||
if (rc) |
||||
return rc; |
||||
|
||||
/* read FORM chunk */ |
||||
if (lsx_reads(ft, buf, (size_t)4) == SOX_EOF || strncmp(buf, "FORM", (size_t)4) != 0) |
||||
{ |
||||
lsx_fail_errno(ft,SOX_EHDR,"MAUD: header does not begin with magic word `FORM'"); |
||||
return (SOX_EOF); |
||||
} |
||||
|
||||
lsx_readdw(ft, &trash32); /* totalsize */ |
||||
|
||||
if (lsx_reads(ft, buf, (size_t)4) == SOX_EOF || strncmp(buf, "MAUD", (size_t)4) != 0) |
||||
{ |
||||
lsx_fail_errno(ft,SOX_EHDR,"MAUD: `FORM' chunk does not specify `MAUD' as type"); |
||||
return(SOX_EOF); |
||||
} |
||||
|
||||
/* read chunks until 'BODY' (or end) */ |
||||
|
||||
while (lsx_reads(ft, buf, (size_t)4) == SOX_SUCCESS && strncmp(buf,"MDAT",(size_t)4) != 0) { |
||||
|
||||
/*
|
||||
buf[4] = 0; |
||||
lsx_debug("chunk %s",buf); |
||||
*/ |
||||
|
||||
if (strncmp(buf,"MHDR",(size_t)4) == 0) { |
||||
|
||||
lsx_readdw(ft, &chunksize); |
||||
if (chunksize != 8*4) |
||||
{ |
||||
lsx_fail_errno(ft,SOX_EHDR,"MAUD: MHDR chunk has bad size"); |
||||
return(SOX_EOF); |
||||
} |
||||
|
||||
/* number of samples stored in MDAT */ |
||||
lsx_readdw(ft, &(p->nsamples)); |
||||
|
||||
/* number of bits per sample as stored in MDAT */ |
||||
lsx_readw(ft, &bitpersam); |
||||
|
||||
/* number of bits per sample after decompression */ |
||||
lsx_readw(ft, &trash16); |
||||
|
||||
lsx_readdw(ft, &nom); /* clock source frequency */ |
||||
lsx_readw(ft, &denom); /* clock devide */ |
||||
if (denom == 0) |
||||
{ |
||||
lsx_fail_errno(ft,SOX_EHDR,"MAUD: frequency denominator == 0, failed"); |
||||
return (SOX_EOF); |
||||
} |
||||
|
||||
ft->signal.rate = nom / denom; |
||||
|
||||
lsx_readw(ft, &chaninf); /* channel information */ |
||||
switch (chaninf) { |
||||
case 0: |
||||
ft->signal.channels = 1; |
||||
break; |
||||
case 1: |
||||
ft->signal.channels = 2; |
||||
break; |
||||
default: |
||||
lsx_fail_errno(ft,SOX_EFMT,"MAUD: unsupported number of channels in file"); |
||||
return (SOX_EOF); |
||||
} |
||||
|
||||
lsx_readw(ft, &chaninf); /* number of channels (mono: 1, stereo: 2, ...) */ |
||||
if (chaninf != ft->signal.channels) |
||||
{ |
||||
lsx_fail_errno(ft,SOX_EFMT,"MAUD: unsupported number of channels in file"); |
||||
return(SOX_EOF); |
||||
} |
||||
|
||||
lsx_readw(ft, &chaninf); /* compression type */ |
||||
|
||||
lsx_readdw(ft, &trash32); /* rest of chunk, unused yet */ |
||||
lsx_readdw(ft, &trash32); |
||||
lsx_readdw(ft, &trash32); |
||||
|
||||
if (bitpersam == 8 && chaninf == 0) { |
||||
ft->encoding.bits_per_sample = 8; |
||||
ft->encoding.encoding = SOX_ENCODING_UNSIGNED; |
||||
} |
||||
else if (bitpersam == 8 && chaninf == 2) { |
||||
ft->encoding.bits_per_sample = 8; |
||||
ft->encoding.encoding = SOX_ENCODING_ALAW; |
||||
} |
||||
else if (bitpersam == 8 && chaninf == 3) { |
||||
ft->encoding.bits_per_sample = 8; |
||||
ft->encoding.encoding = SOX_ENCODING_ULAW; |
||||
} |
||||
else if (bitpersam == 16 && chaninf == 0) { |
||||
ft->encoding.bits_per_sample = 16; |
||||
ft->encoding.encoding = SOX_ENCODING_SIGN2; |
||||
} |
||||
else |
||||
{ |
||||
lsx_fail_errno(ft,SOX_EFMT,"MAUD: unsupported compression type detected"); |
||||
return(SOX_EOF); |
||||
} |
||||
|
||||
continue; |
||||
} |
||||
|
||||
if (strncmp(buf,"ANNO",(size_t)4) == 0) { |
||||
lsx_readdw(ft, &chunksize); |
||||
if (chunksize & 1) |
||||
chunksize++; |
||||
chunk_buf = lsx_malloc(chunksize + (size_t)1); |
||||
if (lsx_readbuf(ft, chunk_buf, (size_t)chunksize) |
||||
!= chunksize) |
||||
{ |
||||
lsx_fail_errno(ft,SOX_EOF,"MAUD: Unexpected EOF in ANNO header"); |
||||
return(SOX_EOF); |
||||
} |
||||
chunk_buf[chunksize] = '\0'; |
||||
lsx_debug("%s",chunk_buf); |
||||
free(chunk_buf); |
||||
|
||||
continue; |
||||
} |
||||
|
||||
/* some other kind of chunk */ |
||||
lsx_readdw(ft, &chunksize); |
||||
if (chunksize & 1) |
||||
chunksize++; |
||||
lsx_seeki(ft, (off_t)chunksize, SEEK_CUR); |
||||
continue; |
||||
|
||||
} |
||||
|
||||
if (strncmp(buf,"MDAT",(size_t)4) != 0) |
||||
{ |
||||
lsx_fail_errno(ft,SOX_EFMT,"MAUD: MDAT chunk not found"); |
||||
return(SOX_EOF); |
||||
} |
||||
lsx_readdw(ft, &(p->nsamples)); |
||||
return(SOX_SUCCESS); |
||||
} |
||||
|
||||
static int startwrite(sox_format_t * ft) |
||||
{ |
||||
priv_t * p = (priv_t *) ft->priv; |
||||
int rc; |
||||
|
||||
/* Needed for rawwrite() */ |
||||
rc = lsx_rawstartwrite(ft); |
||||
if (rc) |
||||
return rc; |
||||
|
||||
/* If you have to seek around the output file */ |
||||
if (! ft->seekable) |
||||
{ |
||||
lsx_fail_errno(ft,SOX_EOF,"Output .maud file must be a file, not a pipe"); |
||||
return (SOX_EOF); |
||||
} |
||||
p->nsamples = 0x7f000000; |
||||
maudwriteheader(ft); |
||||
p->nsamples = 0; |
||||
return (SOX_SUCCESS); |
||||
} |
||||
|
||||
static size_t write_samples(sox_format_t * ft, const sox_sample_t *buf, size_t len) |
||||
{ |
||||
priv_t * p = (priv_t *) ft->priv; |
||||
|
||||
p->nsamples += len; |
||||
|
||||
return lsx_rawwrite(ft, buf, len); |
||||
} |
||||
|
||||
static int stopwrite(sox_format_t * ft) |
||||
{ |
||||
/* All samples are already written out. */ |
||||
|
||||
priv_t *p = (priv_t*)ft->priv; |
||||
uint32_t mdat_size; /* MDAT chunk size */ |
||||
mdat_size = p->nsamples * (ft->encoding.bits_per_sample >> 3); |
||||
lsx_padbytes(ft, (size_t) (mdat_size%2)); |
||||
|
||||
if (lsx_seeki(ft, (off_t)0, 0) != 0) |
||||
{ |
||||
lsx_fail_errno(ft,errno,"can't rewind output file to rewrite MAUD header"); |
||||
return(SOX_EOF); |
||||
} |
||||
|
||||
maudwriteheader(ft); |
||||
return(SOX_SUCCESS); |
||||
} |
||||
|
||||
#define MAUDHEADERSIZE (4+(4+4+32)+(4+4+19+1)+(4+4)) |
||||
static void maudwriteheader(sox_format_t * ft) |
||||
{ |
||||
priv_t * p = (priv_t *) ft->priv; |
||||
uint32_t mdat_size; /* MDAT chunk size */ |
||||
|
||||
mdat_size = p->nsamples * (ft->encoding.bits_per_sample >> 3); |
||||
|
||||
lsx_writes(ft, "FORM"); |
||||
lsx_writedw(ft, MAUDHEADERSIZE + mdat_size + mdat_size%2); /* size of file */ |
||||
lsx_writes(ft, "MAUD"); /* File type */ |
||||
|
||||
lsx_writes(ft, "MHDR"); |
||||
lsx_writedw(ft, 8*4); /* number of bytes to follow */ |
||||
lsx_writedw(ft, p->nsamples); /* number of samples stored in MDAT */ |
||||
|
||||
switch (ft->encoding.encoding) { |
||||
|
||||
case SOX_ENCODING_UNSIGNED: |
||||
lsx_writew(ft, 8); /* number of bits per sample as stored in MDAT */ |
||||
lsx_writew(ft, 8); /* number of bits per sample after decompression */ |
||||
break; |
||||
|
||||
case SOX_ENCODING_SIGN2: |
||||
lsx_writew(ft, 16); /* number of bits per sample as stored in MDAT */ |
||||
lsx_writew(ft, 16); /* number of bits per sample after decompression */ |
||||
break; |
||||
|
||||
case SOX_ENCODING_ALAW: |
||||
case SOX_ENCODING_ULAW: |
||||
lsx_writew(ft, 8); /* number of bits per sample as stored in MDAT */ |
||||
lsx_writew(ft, 16); /* number of bits per sample after decompression */ |
||||
break; |
||||
|
||||
default: |
||||
break; |
||||
} |
||||
|
||||
lsx_writedw(ft, (unsigned)(ft->signal.rate + .5)); /* sample rate, Hz */ |
||||
lsx_writew(ft, (int) 1); /* clock devide */ |
||||
|
||||
if (ft->signal.channels == 1) { |
||||
lsx_writew(ft, 0); /* channel information */ |
||||
lsx_writew(ft, 1); /* number of channels (mono: 1, stereo: 2, ...) */ |
||||
} |
||||
else { |
||||
lsx_writew(ft, 1); |
||||
lsx_writew(ft, 2); |
||||
} |
||||
|
||||
switch (ft->encoding.encoding) { |
||||
|
||||
case SOX_ENCODING_UNSIGNED: |
||||
case SOX_ENCODING_SIGN2: |
||||
lsx_writew(ft, 0); /* no compression */ |
||||
break; |
||||
|
||||
case SOX_ENCODING_ULAW: |
||||
lsx_writew(ft, 3); |
||||
break; |
||||
|
||||
case SOX_ENCODING_ALAW: |
||||
lsx_writew(ft, 2); |
||||
break; |
||||
|
||||
default: |
||||
break; |
||||
} |
||||
|
||||
lsx_writedw(ft, 0); /* reserved */ |
||||
lsx_writedw(ft, 0); /* reserved */ |
||||
lsx_writedw(ft, 0); /* reserved */ |
||||
|
||||
lsx_writes(ft, "ANNO"); |
||||
lsx_writedw(ft, 19); /* length of block */ |
||||
lsx_writes(ft, "file created by SoX"); |
||||
lsx_padbytes(ft, (size_t)1); |
||||
|
||||
lsx_writes(ft, "MDAT"); |
||||
lsx_writedw(ft, p->nsamples * (ft->encoding.bits_per_sample >> 3)); /* samples in file */ |
||||
} |
||||
|
||||
LSX_FORMAT_HANDLER(maud) |
||||
{ |
||||
static char const * const names[] = {"maud", NULL}; |
||||
static unsigned const write_encodings[] = { |
||||
SOX_ENCODING_SIGN2, 16, 0, |
||||
SOX_ENCODING_UNSIGNED, 8, 0, |
||||
SOX_ENCODING_ULAW, 8, 0, |
||||
SOX_ENCODING_ALAW, 8, 0, |
||||
0}; |
||||
static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE, |
||||
"Used with the ‘Toccata’ sound-card on the Amiga", |
||||
names, SOX_FILE_BIG_END | SOX_FILE_MONO | SOX_FILE_STEREO, |
||||
startread, lsx_rawread, lsx_rawstopread, |
||||
startwrite, write_samples, stopwrite, |
||||
NULL, write_encodings, NULL, sizeof(priv_t) |
||||
}; |
||||
return &handler; |
||||
} |
Loading…
Reference in new issue