home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 3 / AACD03.BIN / AACD / Sound / SoX / Source / maud.c < prev    next >
C/C++ Source or Header  |  1999-07-18  |  8KB  |  342 lines

  1. /*
  2.  * July 5, 1991
  3.  * Copyright 1991 Lance Norskog 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.  * Lance Norskog And Sundry Contributors are not responsible for 
  7.  * the consequences of using this software.
  8.  */
  9.  
  10. /*
  11.  * Sound Tools MAUD file format driver, by Lutz Vieweg 1993
  12.  *
  13.  * supports: mono and stereo, linear, a-law and u-law reading and writing
  14.  *
  15.  * March 3, 1999 - cbagwell
  16.  *   Changed to use rawread for reading.
  17.  *
  18.  */
  19.  
  20. #include "st.h"
  21. #include "libst.h"
  22. #include <string.h>
  23. #include <stdlib.h>
  24. #include <stdio.h>
  25.  
  26. #ifdef HAVE_UNISTD_H
  27. #include <unistd.h>    /* For SEEK_* defines if not found in stdio */
  28. #endif
  29.  
  30. /* Private data for MAUD file */
  31. struct maudstuff { /* max. 100 bytes!!!! */
  32.     ULONG nsamples;
  33. };
  34.  
  35. void maudwriteheader(P1(ft_t));
  36. LONG rawread(P3(ft_t, LONG *, LONG));
  37. void rawwrite(P3(ft_t, LONG *, LONG));
  38.  
  39. /*
  40.  * Do anything required before you start reading samples.
  41.  * Read file header. 
  42.  *    Find out sampling rate, 
  43.  *    size and style of samples, 
  44.  *    mono/stereo/quad.
  45.  */
  46. void maudstartread(ft) 
  47. ft_t ft;
  48. {
  49.     struct maudstuff * p = (struct maudstuff *) ft->priv;
  50.     
  51.     char buf[12];
  52.     char *chunk_buf;
  53.     
  54.     unsigned short bitpersam;
  55.     ULONG nom;
  56.     unsigned short denom;
  57.     unsigned short chaninf;
  58.     
  59.     ULONG chunksize;
  60.  
  61.     int littlendian = 1;
  62.     char *endptr;
  63.  
  64.     /* Needed for rawread() */
  65.     rawstartread(ft);
  66.  
  67.     endptr = (char *) &littlendian;
  68.     /* maud is in big endian format.  Swap whats read in
  69.      * on little endian machines.
  70.      */
  71.     if (*endptr)
  72.     {
  73.         ft->swap = ft->swap ? 0 : 1;
  74.     }
  75.     
  76.     /* read FORM chunk */
  77.     if (fread(buf, 1, 4, ft->fp) != 4 || strncmp(buf, "FORM", 4) != 0)
  78.         fail("MAUD: header does not begin with magic word 'FORM'");
  79.     
  80.     rlong(ft); /* totalsize */
  81.     
  82.     if (fread(buf, 1, 4, ft->fp) != 4 || strncmp(buf, "MAUD", 4) != 0)
  83.         fail("MAUD: 'FORM' chunk does not specify 'MAUD' as type");
  84.     
  85.     /* read chunks until 'BODY' (or end) */
  86.     
  87.     while (fread(buf,1,4,ft->fp) == 4 && strncmp(buf,"MDAT",4) != 0) {
  88.         
  89.         /*
  90.         buf[4] = 0;
  91.         report("chunk %s",buf);
  92.         */
  93.         
  94.         if (strncmp(buf,"MHDR",4) == 0) {
  95.             
  96.             chunksize = rlong(ft);
  97.             if (chunksize != 8*4) fail ("MAUD: MHDR chunk has bad size");
  98.             
  99.             /* fseek(ft->fp,12,SEEK_CUR); */
  100.             
  101.             p->nsamples = rlong(ft); /* number of samples stored in MDAT */
  102.             bitpersam = rshort(ft);  /* number of bits per sample as stored in MDAT */
  103.             rshort(ft);              /* number of bits per sample after decompression */
  104.             nom = rlong(ft);         /* clock source frequency */
  105.             denom = rshort(ft);       /* clock devide           */
  106.             if (denom == 0) fail("MAUD: frequency denominator == 0, failed");
  107.             
  108.             ft->info.rate = nom / denom;
  109.             
  110.             chaninf = rshort(ft); /* channel information */
  111.             switch (chaninf) {
  112.             case 0:
  113.                 ft->info.channels = 1;
  114.                 break;
  115.             case 1:
  116.                 ft->info.channels = 2;
  117.                 break;
  118.             default:
  119.                 fail("MAUD: unsupported number of channels in file");
  120.                 break;
  121.             }
  122.             
  123.             chaninf = rshort(ft); /* number of channels (mono: 1, stereo: 2, ...) */
  124.             if (chaninf != ft->info.channels) fail("MAUD: unsupported number of channels in file");
  125.             
  126.             chaninf = rshort(ft); /* compression type */
  127.             
  128.             rlong(ft); /* rest of chunk, unused yet */
  129.             rlong(ft);
  130.             rlong(ft);
  131.             
  132.             if (bitpersam == 8 && chaninf == 0) {
  133.                 ft->info.size = BYTE;
  134.                 ft->info.style = UNSIGNED;
  135.             }
  136.             else if (bitpersam == 8 && chaninf == 2) {
  137.                 ft->info.size = BYTE;
  138.                 ft->info.style = ALAW;
  139.             }
  140.             else if (bitpersam == 8 && chaninf == 3) {
  141.                 ft->info.size = BYTE;
  142.                 ft->info.style = ULAW;
  143.             }
  144.             else if (bitpersam == 16 && chaninf == 0) {
  145.                 ft->info.size = WORD;
  146.                 ft->info.style = SIGN2;
  147.             }
  148.             else fail("MAUD: unsupported compression type detected");
  149.             
  150.             ft->comment = 0;
  151.             
  152.             continue;
  153.         }
  154.         
  155.         if (strncmp(buf,"ANNO",4) == 0) {
  156.             chunksize = rlong(ft);
  157.             if (chunksize & 1)
  158.                 chunksize++;
  159.             chunk_buf = (char *) malloc(chunksize + 1);
  160.             if (fread(chunk_buf,1,(int)chunksize,ft->fp) 
  161.                     != chunksize)
  162.                 fail("MAUD: Unexpected EOF in ANNO header");
  163.             chunk_buf[chunksize] = '\0';
  164.             report ("%s",chunk_buf);
  165.             free(chunk_buf);
  166.             
  167.             continue;
  168.         }
  169.         
  170.         /* some other kind of chunk */
  171.         chunksize = rlong(ft);
  172.         if (chunksize & 1)
  173.             chunksize++;
  174.         fseek(ft->fp,chunksize,SEEK_CUR);
  175.         continue;
  176.         
  177.     }
  178.     
  179.     if (strncmp(buf,"MDAT",4) != 0) fail("MAUD: MDAT chunk not found");
  180.     p->nsamples = rlong(ft);
  181. }
  182.  
  183. /*
  184.  * Read up to len samples from file.
  185.  * Convert to signed longs.
  186.  * Place in buf[].
  187.  * Return number of samples read.
  188.  */
  189.  
  190. LONG maudread(ft, buf, len) 
  191. ft_t ft;
  192. LONG *buf, len;
  193. {
  194.     return (rawread(ft, buf, len));
  195. }
  196.  
  197. /*
  198.  * Do anything required when you stop reading samples.  
  199.  * Don't close input file! 
  200.  */
  201. void maudstopread(ft) 
  202. ft_t ft;
  203. {
  204.     /* Needed because of rawread() */
  205.     rawstopread(ft);
  206. }
  207.  
  208. void maudstartwrite(ft) 
  209. ft_t ft;
  210. {
  211.     struct maudstuff * p = (struct maudstuff *) ft->priv;
  212.  
  213.     int littlendian = 1;
  214.     char *endptr;
  215.  
  216.     /* Needed for rawwrite() */
  217.     rawstartwrite(ft);
  218.  
  219.     endptr = (char *) &littlendian;
  220.     /* maud is in big endian format.  Swap whats read in
  221.      * on little endian machines.
  222.      */
  223.     if (*endptr)
  224.     {
  225.         ft->swap = ft->swap ? 0 : 1;
  226.     }
  227.     
  228.     /* If you have to seek around the output file */
  229.     if (! ft->seekable) fail("Output .maud file must be a file, not a pipe");
  230.     
  231.     if (ft->info.channels != 1 && ft->info.channels != 2) {
  232.         fail("MAUD: unsupported number of channels, unable to store");
  233.     }
  234.     if (ft->info.size == WORD) ft->info.style = SIGN2;
  235.     if (ft->info.style == ULAW || ft->info.style == ALAW) ft->info.size = BYTE;
  236.     if (ft->info.size == BYTE && ft->info.style == SIGN2) ft->info.style = UNSIGNED;
  237.     
  238.     p->nsamples = 0x7f000000L;
  239.     maudwriteheader(ft);
  240.     p->nsamples = 0;
  241. }
  242.  
  243. void maudwrite(ft, buf, len) 
  244. ft_t ft;
  245. LONG *buf, len;
  246. {
  247.     struct maudstuff * p = (struct maudstuff *) ft->priv;
  248.     
  249.     p->nsamples += len;
  250.     
  251.     rawwrite(ft, buf, len);
  252. }
  253.  
  254. void maudstopwrite(ft) 
  255. ft_t ft;
  256. {
  257.     /* Flush out remaining samples*/
  258.     rawstopwrite(ft);
  259.  
  260.     /* All samples are already written out. */
  261.     
  262.     if (fseek(ft->fp, 0L, 0) != 0) fail("can't rewind output file to rewrite MAUD header");
  263.     
  264.     maudwriteheader(ft);
  265. }
  266.  
  267. #define MAUDHEADERSIZE (4+(4+4+32)+(4+4+32)+(4+4))
  268. void maudwriteheader(ft)
  269. ft_t ft;
  270. {
  271.     struct maudstuff * p = (struct maudstuff *) ft->priv;
  272.     
  273.     fputs ("FORM", ft->fp);
  274.     wlong(ft, (p->nsamples*ft->info.size) + MAUDHEADERSIZE);  /* size of file */
  275.     fputs("MAUD", ft->fp); /* File type */
  276.     
  277.     fputs ("MHDR", ft->fp);
  278.     wlong(ft, (LONG) 8*4); /* number of bytes to follow */
  279.     wlong(ft, (LONG) (p->nsamples ));  /* number of samples stored in MDAT */
  280.     
  281.     switch (ft->info.style) {
  282.         
  283.     case UNSIGNED:
  284.         wshort(ft, (int) 8); /* number of bits per sample as stored in MDAT */
  285.         wshort(ft, (int) 8); /* number of bits per sample after decompression */
  286.         break;
  287.         
  288.     case SIGN2:
  289.         wshort(ft, (int) 16); /* number of bits per sample as stored in MDAT */
  290.         wshort(ft, (int) 16); /* number of bits per sample after decompression */
  291.         break;
  292.         
  293.     case ALAW:
  294.     case ULAW:
  295.         wshort(ft, (int) 8); /* number of bits per sample as stored in MDAT */
  296.         wshort(ft, (int) 16); /* number of bits per sample after decompression */
  297.         break;
  298.         
  299.     }
  300.     
  301.     wlong(ft, (LONG) ft->info.rate); /* clock source frequency */
  302.     wshort(ft, (int) 1); /* clock devide */
  303.     
  304.     if (ft->info.channels == 1) {
  305.         wshort(ft, (int) 0); /* channel information */
  306.         wshort(ft, (int) 1); /* number of channels (mono: 1, stereo: 2, ...) */
  307.     }
  308.     else {
  309.         wshort(ft, (int) 1);
  310.         wshort(ft, (int) 2);
  311.     }
  312.     
  313.     switch (ft->info.style) {
  314.         
  315.     case UNSIGNED:
  316.     case SIGN2:
  317.         wshort(ft, (int) 0); /* no compression */
  318.         break;
  319.         
  320.     case ULAW:
  321.         wshort(ft, (int) 3);
  322.         break;
  323.         
  324.     case ALAW:
  325.         wshort(ft, (int) 2);
  326.         break;
  327.         
  328.     }
  329.     
  330.     wlong(ft, (LONG) 0); /* reserved */
  331.     wlong(ft, (LONG) 0); /* reserved */
  332.     wlong(ft, (LONG) 0); /* reserved */
  333.     
  334.     fputs ("ANNO", ft->fp);
  335.     wlong(ft, (LONG) 32); /* length of block */
  336.     fputs ("file written by SOX MAUD-export ", ft->fp);
  337.     
  338.     fputs ("MDAT", ft->fp);
  339.     wlong(ft, p->nsamples * ft->info.size ); /* samples in file */
  340. }
  341.  
  342.