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

  1. /*
  2.  * Amiga 8SVX format handler: W V Neisius, February 1992
  3.  */
  4.  
  5. #include <math.h>
  6. #include <errno.h>
  7. #include <string.h>
  8. #include <stdlib.h>
  9. #include <stdio.h>
  10.  
  11. #ifdef    VMS
  12. #include <perror.h>
  13. #endif
  14.  
  15. #ifdef HAVE_UNISTD_H
  16. #include <unistd.h>    /* For SEEK_* defines if not found in stdio */
  17. #endif
  18.  
  19. #ifdef HAVE_MALLOC_H
  20. #include <malloc.h>
  21. #endif
  22.  
  23. #include "st.h"
  24.  
  25. /* Private data used by writer */
  26. struct svxpriv {
  27.         ULONG nsamples;
  28.     FILE *ch[4];
  29. };
  30.  
  31. void svxwriteheader(P2(ft_t, LONG));
  32.     
  33. /*======================================================================*/
  34. /*                         8SVXSTARTREAD                                */
  35. /*======================================================================*/
  36.  
  37. void svxstartread(ft)
  38. ft_t ft;
  39. {
  40.     struct svxpriv *p = (struct svxpriv *) ft->priv;
  41.  
  42.     char buf[12];
  43.     char *chunk_buf;
  44.  
  45.     ULONG totalsize;
  46.     ULONG chunksize;
  47.  
  48.     int channels;
  49.     LONG rate;
  50.     int i;
  51.     int littlendian = 1;
  52.     char *endptr;
  53.  
  54.     ULONG chan1_pos;
  55.  
  56.     endptr = (char*) &littlendian;
  57.     /* 8svx is in big endian format. Swap whats
  58.      * read in on little endian machines.
  59.      */
  60.     if (*endptr)
  61.     {
  62.         ft->swap = ft->swap ? 0 : 1;
  63.     }
  64.  
  65.     rate = 0;
  66.     channels = 1;
  67.  
  68.     /* read FORM chunk */
  69.     if (fread(buf, 1, 4, ft->fp) != 4 || strncmp(buf, "FORM", 4) != 0)
  70.         fail("8SVX: header does not begin with magic word 'FORM'");
  71.     totalsize = rlong(ft);
  72.     if (fread(buf, 1, 4, ft->fp) != 4 || strncmp(buf, "8SVX", 4) != 0)
  73.         fail("8SVX: 'FORM' chunk does not specify '8SVX' as type");
  74.  
  75.     /* read chunks until 'BODY' (or end) */
  76.     while (fread(buf,1,4,ft->fp) == 4 && strncmp(buf,"BODY",4) != 0) {
  77.         if (strncmp(buf,"VHDR",4) == 0) {
  78.             chunksize = rlong(ft);
  79.             if (chunksize != 20)
  80.                 fail ("8SVX: VHDR chunk has bad size");
  81.             fseek(ft->fp,12,SEEK_CUR);
  82.             rate = rshort(ft);
  83.             fseek(ft->fp,1,SEEK_CUR);
  84.             fread(buf,1,1,ft->fp);
  85.             if (buf[0] != 0)
  86.                 fail ("8SVX: unsupported data compression");
  87.             fseek(ft->fp,4,SEEK_CUR);
  88.             continue;
  89.         }
  90.  
  91.         if (strncmp(buf,"ANNO",4) == 0) {
  92.             chunksize = rlong(ft);
  93.             if (chunksize & 1)
  94.                 chunksize++;
  95.             chunk_buf = (char *) malloc(chunksize + 1);
  96.             if (fread(chunk_buf,1,(size_t)chunksize,ft->fp) 
  97.                     != chunksize)
  98.                 fail("8SVX: Unexpected EOF in ANNO header");
  99.             chunk_buf[chunksize] = '\0';
  100.             report ("%s",chunk_buf);
  101.             free(chunk_buf);
  102.  
  103.             continue;
  104.         }
  105.  
  106.         if (strncmp(buf,"NAME",4) == 0) {
  107.             chunksize = rlong(ft);
  108.             if (chunksize & 1)
  109.                 chunksize++;
  110.             chunk_buf = (char *) malloc(chunksize + 1);
  111.             if (fread (chunk_buf,1,(size_t)chunksize,ft->fp) 
  112.                     != chunksize)
  113.                 fail("8SVX: Unexpected EOF in NAME header");
  114.             chunk_buf[chunksize] = '\0';
  115.             report ("%s",chunk_buf);
  116.             free(chunk_buf);
  117.  
  118.             continue;
  119.         }
  120.  
  121.         if (strncmp(buf,"CHAN",4) == 0) {
  122.             chunksize = rlong(ft);
  123.             if (chunksize != 4) 
  124.                 fail("8SVX: Short channel chunk");
  125.             channels = rlong(ft);
  126.             channels = (channels & 0x01) + 
  127.                     ((channels & 0x02) >> 1) +
  128.                        ((channels & 0x04) >> 2) + 
  129.                     ((channels & 0x08) >> 3);
  130.  
  131.             continue;
  132.         }
  133.  
  134.         /* some other kind of chunk */
  135.         chunksize = rlong(ft);
  136.         if (chunksize & 1)
  137.             chunksize++;
  138.         fseek(ft->fp,chunksize,SEEK_CUR);
  139.         continue;
  140.  
  141.     }
  142.  
  143.     if (rate == 0)
  144.         fail ("8SVX: invalid rate");
  145.     if (strncmp(buf,"BODY",4) != 0)
  146.         fail ("8SVX: BODY chunk not found");
  147.     p->nsamples = rlong(ft);
  148.  
  149.     ft->info.channels = channels;
  150.     ft->info.rate = rate;
  151.     ft->info.style = SIGN2;
  152.     ft->info.size = BYTE;
  153.  
  154.     /* open files to channels */
  155.     p->ch[0] = ft->fp;
  156.     chan1_pos = ftell(p->ch[0]);
  157.  
  158.     for (i = 1; i < channels; i++) {
  159.         if ((p->ch[i] = fopen(ft->filename, READBINARY)) == NULL)
  160.             fail("Can't open channel file '%s': %s",
  161.                 ft->filename, strerror(errno));
  162.  
  163.         /* position channel files */
  164.         if (fseek(p->ch[i],chan1_pos,SEEK_SET))
  165.             fail ("Can't position channel %d: %s",i,strerror(errno));
  166.         if (fseek(p->ch[i],p->nsamples/channels*i,SEEK_CUR))
  167.             fail ("Can't seek channel %d: %s",i,strerror(errno));
  168.     }
  169. }
  170.  
  171. /*======================================================================*/
  172. /*                         8SVXREAD                                     */
  173. /*======================================================================*/
  174. LONG svxread(ft, buf, nsamp) 
  175. ft_t ft;
  176. LONG *buf, nsamp;
  177. {
  178.     ULONG datum;
  179.     int done = 0;
  180.     int i;
  181.  
  182.     struct svxpriv *p = (struct svxpriv *) ft->priv;
  183.  
  184.     while (done < nsamp) {
  185.         for (i = 0; i < ft->info.channels; i++) {
  186.             datum = getc(p->ch[i]);
  187.             if (feof(p->ch[i]))
  188.                 return done;
  189.             /* scale signed up to long's range */
  190.             *buf++ = LEFT(datum, 24);
  191.         }
  192.         done += ft->info.channels;
  193.     }
  194.     return done;
  195. }
  196.  
  197. /*======================================================================*/
  198. /*                         8SVXSTOPREAD                                 */
  199. /*======================================================================*/
  200. void svxstopread(ft)
  201. ft_t ft;
  202. {
  203.     int i;
  204.  
  205.     struct svxpriv *p = (struct svxpriv *) ft->priv;
  206.  
  207.     /* close channel files */
  208.     for (i = 1; i < ft->info.channels; i++) {
  209.         fclose (p->ch[i]);
  210.     }
  211. }
  212.  
  213. /*======================================================================*/
  214. /*                         8SVXSTARTWRITE                               */
  215. /*======================================================================*/
  216. void svxstartwrite(ft)
  217. ft_t ft;
  218. {
  219.     struct svxpriv *p = (struct svxpriv *) ft->priv;
  220.     int i;
  221.  
  222.     int littlendian = 1;
  223.     char *endptr;
  224.  
  225.     endptr = (char *) &littlendian;
  226.     /* 8svx is in big endian format.  Swaps wahst
  227.      * read in on little endian machines.
  228.      */
  229.     if (*endptr)
  230.     {
  231.         ft->swap = ft->swap ? 0 : 1;
  232.     }
  233.  
  234.     /* open channel output files */
  235.     p->ch[0] = ft->fp;
  236.     for (i = 1; i < ft->info.channels; i++) {
  237.         if ((p->ch[i] = tmpfile()) == NULL)
  238.             fail("Can't open channel output file: %s",
  239.                 strerror(errno));
  240.     }
  241.  
  242.     /* write header (channel 0) */
  243.     ft->info.style = SIGN2;
  244.     ft->info.size = BYTE;
  245.  
  246.     p->nsamples = 0;
  247.     svxwriteheader(ft, p->nsamples);
  248. }
  249.  
  250. /*======================================================================*/
  251. /*                         8SVXWRITE                                    */
  252. /*======================================================================*/
  253.  
  254. void svxwrite(ft, buf, len)
  255. ft_t ft;
  256. LONG *buf, len;
  257. {
  258.     struct svxpriv *p = (struct svxpriv *) ft->priv;
  259.  
  260.     LONG datum;
  261.     int done = 0;
  262.     int i;
  263.  
  264.     p->nsamples += len;
  265.  
  266.     while(done < len) {
  267.         for (i = 0; i < ft->info.channels; i++) {
  268.             datum = RIGHT(*buf++, 24);
  269.             putc((int)datum, p->ch[i]);
  270.         }
  271.         done += ft->info.channels;
  272.     }
  273. }
  274.  
  275. /*======================================================================*/
  276. /*                         8SVXSTOPWRITE                                */
  277. /*======================================================================*/
  278.  
  279. void svxstopwrite(ft)
  280. ft_t ft;
  281. {
  282.     struct svxpriv *p = (struct svxpriv *) ft->priv;
  283.  
  284.     int i;
  285.     int len;
  286.     char svxbuf[512];
  287.  
  288.     /* append all channel pieces to channel 0 */
  289.     /* close temp files */
  290.     for (i = 1; i < ft->info.channels; i++) {
  291.         if (fseek (p->ch[i], 0L, 0))
  292.             fail ("Can't rewind channel output file %d",i);
  293.         while (!feof(p->ch[i])) {
  294.             len = fread (svxbuf, 1, 512, p->ch[i]);
  295.             fwrite (svxbuf, 1, len, p->ch[0]);
  296.         }
  297.         fclose (p->ch[i]);
  298.     }
  299.  
  300.     /* add a pad byte if BODY size is odd */
  301.     if(p->nsamples % 2 != 0)
  302.         fputc('\0', ft->fp);
  303.  
  304.     /* fixup file sizes in header */
  305.     if (fseek(ft->fp, 0L, 0) != 0)
  306.         fail("can't rewind output file to rewrite 8SVX header");
  307.     svxwriteheader(ft, p->nsamples);
  308. }
  309.  
  310. /*======================================================================*/
  311. /*                         8SVXWRITEHEADER                              */
  312. /*======================================================================*/
  313. #define SVXHEADERSIZE 100
  314. void svxwriteheader(ft,nsamples)
  315. ft_t ft;
  316. LONG nsamples;
  317. {
  318.     LONG formsize =  nsamples + SVXHEADERSIZE - 8;
  319.  
  320.     /* FORM size must be even */
  321.     if(formsize % 2 != 0) formsize++;
  322.  
  323.     fputs ("FORM", ft->fp);
  324.     wlong(ft, formsize);  /* size of file */
  325.     fputs("8SVX", ft->fp); /* File type */
  326.  
  327.     fputs ("VHDR", ft->fp);
  328.     wlong(ft, (LONG) 20); /* number of bytes to follow */
  329.     wlong(ft, nsamples);  /* samples, 1-shot */
  330.     wlong(ft, (LONG) 0);  /* samples, repeat */
  331.     wlong(ft, (LONG) 0);  /* samples per repeat cycle */
  332.     wshort(ft, (int) ft->info.rate); /* samples per second */
  333.     fputc(1,ft->fp); /* number of octaves */
  334.     fputc(0,ft->fp); /* data compression (none) */
  335.     wshort(ft,1); wshort(ft,0); /* volume */
  336.  
  337.     fputs ("ANNO", ft->fp);
  338.     wlong(ft, (LONG) 32); /* length of block */
  339.     fputs ("File created by Sound Exchange  ", ft->fp);
  340.  
  341.     fputs ("CHAN", ft->fp);
  342.     wlong(ft, (LONG) 4);
  343.     wlong(ft, (ft->info.channels == 2) ? (LONG) 6 :
  344.            (ft->info.channels == 4) ? (LONG) 15 : (LONG) 2);
  345.  
  346.     fputs ("BODY", ft->fp);
  347.     wlong(ft, nsamples); /* samples in file */
  348. }
  349.