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

  1. /*
  2.  * Sound Tools Macintosh HCOM format.
  3.  * These are really FSSD type files with Huffman compression,
  4.  * in MacBinary format.
  5.  * To do: make the MacBinary format optional (so that .data files
  6.  * are also acceptable).  (How to do this on output?)
  7.  *
  8.  * September 25, 1991
  9.  * Copyright 1991 Guido van Rossum And Sundry Contributors
  10.  * This source code is freely redistributable and may be used for
  11.  * any purpose.  This copyright notice must be maintained. 
  12.  * Guido van Rossum And Sundry Contributors are not responsible for 
  13.  * the consequences of using this software.
  14.  *
  15.  * April 28, 1998 - Chris Bagwell (cbagwell@sprynet.com)
  16.  *
  17.  *  Rearranged some functions so that they are declared before they are
  18.  *  used.  Clears up some compiler warnings.  Because this functions passed
  19.  *  foats, it helped out some dump compilers pass stuff on the stack
  20.  *  correctly.
  21.  *
  22.  */
  23.  
  24. #include "st.h"
  25. #include <string.h>
  26. #include <stdlib.h>
  27. #ifdef HAVE_MALLOC_H
  28. #include <malloc.h>
  29. #endif
  30.  
  31. /* Dictionary entry for Huffman (de)compression */
  32. typedef struct {
  33.     LONG frequ;
  34.     short dict_leftson;
  35.     short dict_rightson;
  36. } dictent;
  37.  
  38. /* Private data used by reader */
  39. struct readpriv {
  40.     /* Static data from the header */
  41.     dictent *dictionary;
  42.     LONG checksum;
  43.     int deltacompression;
  44.     /* Engine state */
  45.     LONG huffcount;
  46.     LONG cksum;
  47.     int dictentry;
  48.     int nrbits;
  49.     ULONG current;
  50.     short sample;
  51. };
  52.  
  53. void skipbytes(P2(ft_t, int));
  54.  
  55. void hcomstartread(ft)
  56. ft_t ft;
  57. {
  58.     struct readpriv *p = (struct readpriv *) ft->priv;
  59.     int i;
  60.     char buf[4];
  61.     ULONG datasize, rsrcsize;
  62.     ULONG huffcount, checksum, compresstype, divisor;
  63.     unsigned short dictsize;
  64.  
  65.     int littlendian = 1;
  66.     char *endptr;
  67.  
  68.  
  69.     endptr = (char *) &littlendian;
  70.     /* hcom is in big endian format.  Swap whats
  71.      * read in on little machine
  72.      */
  73.     if (*endptr)
  74.     {
  75.         ft->swap = ft->swap ? 0 : 1;
  76.     }
  77.  
  78.     /* Skip first 65 bytes of header */
  79.     skipbytes(ft, 65);
  80.  
  81.     /* Check the file type (bytes 65-68) */
  82.     if (fread(buf, 1, 4, ft->fp) != 4 || strncmp(buf, "FSSD", 4) != 0)
  83.         fail("Mac header type is not FSSD");
  84.  
  85.     /* Skip to byte 83 */
  86.     skipbytes(ft, 83-69);
  87.  
  88.     /* Get essential numbers from the header */
  89.     datasize = rlong(ft); /* bytes 83-86 */
  90.     rsrcsize = rlong(ft); /* bytes 87-90 */
  91.  
  92.     /* Skip the rest of the header (total 128 bytes) */
  93.     skipbytes(ft, 128-91);
  94.  
  95.     /* The data fork must contain a "HCOM" header */
  96.     if (fread(buf, 1, 4, ft->fp) != 4 || strncmp(buf, "HCOM", 4) != 0)
  97.         fail("Mac data fork is not HCOM");
  98.  
  99.     /* Then follow various parameters */
  100.     huffcount = rlong(ft);
  101.     checksum = rlong(ft);
  102.     compresstype = rlong(ft);
  103.     if (compresstype > 1)
  104.         fail("Bad compression type in HCOM header");
  105.     divisor = rlong(ft);
  106.     if (divisor == 0 || divisor > 4)
  107.         fail("Bad sampling rate divisor in HCOM header");
  108.     dictsize = rshort(ft);
  109.  
  110.     /* Translate to sox parameters */
  111.     ft->info.style = UNSIGNED;
  112.     ft->info.size = BYTE;
  113.     ft->info.rate = 22050 / divisor;
  114.     ft->info.channels = 1;
  115.  
  116.     /* Allocate memory for the dictionary */
  117.     p->dictionary = (dictent *) malloc(511 * sizeof(dictent));
  118.     if (p->dictionary == NULL)
  119.         fail("can't malloc memory for Huffman dictionary");
  120.  
  121.     /* Read dictionary */
  122.     for(i = 0; i < dictsize; i++) {
  123.         p->dictionary[i].dict_leftson = rshort(ft);
  124.         p->dictionary[i].dict_rightson = rshort(ft);
  125.         /*
  126.         report("%d %d",
  127.                p->dictionary[i].dict_leftson,
  128.                p->dictionary[i].dict_rightson);
  129.                */
  130.     }
  131.     skipbytes(ft, 1); /* skip pad byte */
  132.  
  133.     /* Initialized the decompression engine */
  134.     p->checksum = checksum;
  135.     p->deltacompression = compresstype;
  136.     if (!p->deltacompression)
  137.         report("HCOM data using value compression");
  138.     p->huffcount = huffcount;
  139.     p->cksum = 0;
  140.     p->dictentry = 0;
  141.     p->nrbits = -1; /* Special case to get first byte */
  142. }
  143.  
  144. void skipbytes(ft, n)
  145. ft_t ft;
  146. int n;
  147. {
  148.     while (--n >= 0) {
  149.         if (getc(ft->fp) == EOF)
  150.             fail("unexpected EOF in Mac header");
  151.     }
  152. }
  153.  
  154. int hcomread(ft, buf, len)
  155. ft_t ft;
  156. LONG *buf, len;
  157. {
  158.     register struct readpriv *p = (struct readpriv *) ft->priv;
  159.     int done = 0;
  160.  
  161.     if (p->nrbits < 0) {
  162.         /* The first byte is special */
  163.         if (p->huffcount == 0)
  164.             return 0; /* Don't know if this can happen... */
  165.         p->sample = getc(ft->fp);
  166.         if (p->sample == EOF)
  167.             fail("unexpected EOF at start of HCOM data");
  168.         *buf++ = (p->sample - 128) * 0x1000000L;
  169.         p->huffcount--;
  170.         p->nrbits = 0;
  171.         done++;
  172.         len--;
  173.         if (len == 0)
  174.             return done;
  175.     }
  176.  
  177.     while (p->huffcount > 0) {
  178.         if(p->nrbits == 0) {
  179.             p->current = rlong(ft);
  180.             if (feof(ft->fp))
  181.                 fail("unexpected EOF in HCOM data");
  182.             p->cksum += p->current;
  183.             p->nrbits = 32;
  184.         }
  185.         if(p->current & 0x80000000L) {
  186.             p->dictentry =
  187.                 p->dictionary[p->dictentry].dict_rightson;
  188.         } else {
  189.             p->dictentry =
  190.                 p->dictionary[p->dictentry].dict_leftson;
  191.         }
  192.         p->current = p->current << 1;
  193.         p->nrbits--;
  194.         if(p->dictionary[p->dictentry].dict_leftson < 0) {
  195.             short datum;
  196.             datum = p->dictionary[p->dictentry].dict_rightson;
  197.             if (!p->deltacompression)
  198.                 p->sample = 0;
  199.             p->sample = (p->sample + datum) & 0xff;
  200.             p->huffcount--;
  201.             if (p->sample == 0)
  202.                 *buf++ = -127 * 0x1000000L;
  203.             else
  204.                 *buf++ = (p->sample - 128) * 0x1000000L;
  205.             p->dictentry = 0;
  206.             done++;
  207.             len--;
  208.             if (len == 0)
  209.                 break;
  210.         }
  211.     }
  212.  
  213.     return done;
  214. }
  215.  
  216. void hcomstopread(ft) 
  217. ft_t ft;
  218. {
  219.     register struct readpriv *p = (struct readpriv *) ft->priv;
  220.  
  221.     if (p->huffcount != 0)
  222.         fail("not all HCOM data read");
  223.     if(p->cksum != p->checksum)
  224.         fail("checksum error in HCOM data");
  225.     free((char *)p->dictionary);
  226.     p->dictionary = NULL;
  227. }
  228.  
  229. struct writepriv {
  230.     unsigned char *data;    /* Buffer allocated with malloc */
  231.     unsigned int size;    /* Size of allocated buffer */
  232.     unsigned int pos;    /* Where next byte goes */
  233. };
  234.  
  235. #define BUFINCR (10*BUFSIZ)
  236.  
  237. void hcomstartwrite(ft) 
  238. ft_t ft;
  239. {
  240.     register struct writepriv *p = (struct writepriv *) ft->priv;
  241.  
  242.     int littlendian = 1;
  243.     char *endptr;
  244.  
  245.     endptr = (char *) &littlendian;
  246.     /* hcom is inbigendian format.  Swap whats
  247.      * read in on little endian machines.
  248.      */
  249.     if (*endptr)
  250.     {
  251.         ft->swap = ft->swap ? 0 : 1;
  252.     }
  253.  
  254.     switch (ft->info.rate) {
  255.     case 22050:
  256.     case 22050/2:
  257.     case 22050/3:
  258.     case 22050/4:
  259.         break;
  260.     default:
  261.         fail("unacceptable output rate for HCOM: try 5512, 7350, 11025 or 22050 hertz");
  262.     }
  263.     ft->info.size = BYTE;
  264.     ft->info.style = UNSIGNED;
  265.     ft->info.channels = 1;
  266.  
  267.     p->size = BUFINCR;
  268.     p->pos = 0;
  269.     p->data = (unsigned char *) malloc(p->size);
  270.     if (p->data == NULL)
  271.         fail("can't malloc buffer for uncompressed HCOM data");
  272. }
  273.  
  274. void hcomwrite(ft, buf, len)
  275. ft_t ft;
  276. LONG *buf, len;
  277. {
  278.     register struct writepriv *p = (struct writepriv *) ft->priv;
  279.     LONG datum;
  280.  
  281.     if (p->pos + len > p->size) {
  282.         p->size = ((p->pos + len) / BUFINCR + 1) * BUFINCR;
  283.         p->data = (unsigned char *) realloc(p->data, p->size);
  284.         if (p->data == NULL)
  285.             fail("can't realloc buffer for uncompressed HCOM data");
  286.     }
  287.  
  288.     while (--len >= 0) {
  289.         datum = *buf++;
  290.         datum >>= 24;
  291.         datum ^= 128;
  292.         p->data[p->pos++] = datum;
  293.     }
  294. }
  295.  
  296. /* Some global compression stuff hcom uses.  hcom currently has problems */
  297. /* compiling here.  It could really use some cleaning up by someone that */
  298. /* understands this format. */
  299.  
  300. /* XXX This uses global variables -- one day these should all be
  301.    passed around in a structure instead. */
  302.  
  303. dictent dictionary[511];
  304. dictent *de;
  305. LONG codes[256];
  306. LONG codesize[256];
  307. LONG checksum;
  308.  
  309. void makecodes(e, c, s, b)
  310. int e, c, s, b;
  311. {
  312.   if(dictionary[e].dict_leftson < 0) {
  313.     codes[dictionary[e].dict_rightson] = c;
  314.     codesize[dictionary[e].dict_rightson] = s;
  315.   } else {
  316.     makecodes(dictionary[e].dict_leftson, c, s + 1, b << 1);
  317.     makecodes(dictionary[e].dict_rightson, c + b, s + 1, b << 1);
  318.   }
  319. }
  320.  
  321. LONG curword;
  322. int nbits;
  323.  
  324. void putlong(c, v)
  325. unsigned char *c;
  326. LONG v;
  327. {
  328.   *c++ = (v >> 24) & 0xff;
  329.   *c++ = (v >> 16) & 0xff;
  330.   *c++ = (v >> 8) & 0xff;
  331.   *c++ = v & 0xff;
  332. }
  333.  
  334. void putshort(c, v)
  335. unsigned char *c;
  336. short v;
  337. {
  338.   *c++ = (v >> 8) & 0xff;
  339.   *c++ = v & 0xff;
  340. }
  341.  
  342.  
  343. void putcode(c, df)
  344. unsigned char c;
  345. unsigned char ** df;
  346. {
  347. LONG code, size;
  348. int i;
  349.   code = codes[c];
  350.   size = codesize[c];
  351.   for(i = 0; i < size; i++) {
  352.     curword = (curword << 1);
  353.     if(code & 1) curword += 1;
  354.     nbits++;
  355.     if(nbits == 32) {
  356.       putlong(*df, curword);
  357.       checksum += curword;
  358.       (*df) += 4;
  359.       nbits = 0;
  360.       curword = 0;
  361.     }
  362.     code = code >> 1;
  363.   }
  364. }
  365.  
  366. void compress(df, dl, fr)
  367. unsigned char **df;
  368. LONG *dl;
  369. float fr;
  370. {
  371.   LONG samplerate;
  372.   unsigned char *datafork = *df;
  373.   unsigned char *ddf;
  374.   short dictsize;
  375.   int frequtable[256];
  376.   int i, sample, j, k, d, l, frequcount;
  377.  
  378.   sample = *datafork;
  379.   for(i = 0; i < 256; i++) frequtable[i] = 0;
  380.   for(i = 1; i < *dl; i++) {
  381.     d = (datafork[i] - (sample & 0xff)) & 0xff; /* creates absolute entries LMS */
  382.     sample = datafork[i];
  383.     datafork[i] = d;
  384. #if 0                /* checking our table is accessed correctly */
  385.     if(d < 0 || d > 255)
  386.       printf("d is outside array bounds %d\n", d);
  387. #endif
  388.     frequtable[d]++;
  389.   }
  390.   de = dictionary;
  391.   for(i = 0; i < 256; i++) if(frequtable[i] != 0) {
  392.     de->frequ = -frequtable[i];
  393.     de->dict_leftson = -1;
  394.     de->dict_rightson = i;
  395.     de++;
  396.   }
  397.   frequcount = de - dictionary;
  398.   for(i = 0; i < frequcount; i++) {
  399.     for(j = i + 1; j < frequcount; j++) {
  400.       if(dictionary[i].frequ > dictionary[j].frequ) {
  401.         k = dictionary[i].frequ;
  402.         dictionary[i].frequ = dictionary[j].frequ;
  403.         dictionary[j].frequ = k;
  404.         k = dictionary[i].dict_leftson;
  405.         dictionary[i].dict_leftson = dictionary[j].dict_leftson;
  406.         dictionary[j].dict_leftson = k;
  407.         k = dictionary[i].dict_rightson;
  408.         dictionary[i].dict_rightson = dictionary[j].dict_rightson;
  409.         dictionary[j].dict_rightson = k;
  410.       }
  411.     }
  412.   }
  413.   while(frequcount > 1) {
  414.     j = frequcount - 1;
  415.     de->frequ = dictionary[j - 1].frequ;
  416.     de->dict_leftson = dictionary[j - 1].dict_leftson;
  417.     de->dict_rightson = dictionary[j - 1].dict_rightson;
  418.     l = dictionary[j - 1].frequ + dictionary[j].frequ;
  419.     for(i = j - 2; i >= 0; i--) {
  420.       if(l >= dictionary[i].frequ) break;
  421.       dictionary[i + 1] = dictionary[i];
  422.     }
  423.     i = i + 1;
  424.     dictionary[i].frequ = l;
  425.     dictionary[i].dict_leftson = j;
  426.     dictionary[i].dict_rightson = de - dictionary;
  427.     de++;
  428.     frequcount--;
  429.   }
  430.   dictsize = de - dictionary;
  431.   for(i = 0; i < 256; i++) {
  432.     codes[i] = 0;
  433.     codesize[i] = 0;
  434.   }
  435.   makecodes(0, 0, 0, 1);
  436.   l = 0;
  437.   for(i = 0; i < 256; i++) {
  438.       l += frequtable[i] * codesize[i];
  439.   }
  440.   l = (((l + 31) >> 5) << 2) + 24 + dictsize * 4;
  441.   report("  Original size: %6d bytes", *dl);
  442.   report("Compressed size: %6d bytes", l);
  443.   if((datafork = (unsigned char *)malloc((unsigned)l)) == NULL)
  444.     fail("can't malloc buffer for compressed HCOM data");
  445.   ddf = datafork + 22;
  446.   for(i = 0; i < dictsize; i++) {
  447.     putshort(ddf, dictionary[i].dict_leftson);
  448.     ddf += 2;
  449.     putshort(ddf, dictionary[i].dict_rightson);
  450.     ddf += 2;
  451.   }
  452.   *ddf++ = 0;
  453.   *ddf++ = *(*df)++;
  454.   checksum = 0;
  455.   nbits = 0;
  456.   curword = 0;
  457.   for(i = 1; i < *dl; i++) putcode(*(*df)++, &ddf);
  458.   if(nbits != 0) {
  459.     codes[0] = 0;
  460.     codesize[0] = 32 - nbits;
  461.     putcode(0, &ddf);
  462.   }
  463.   strncpy((char *) datafork, "HCOM", 4);
  464.   putlong(datafork + 4, *dl);
  465.   putlong(datafork + 8, checksum);
  466.   putlong(datafork + 12, 1L);
  467.   samplerate = 22050 / (LONG)fr;
  468.   putlong(datafork + 16, samplerate);
  469.   putshort(datafork + 20, dictsize);
  470.   *df = datafork;        /* reassign passed pointer to new datafork */
  471.   *dl = l;            /* and its compressed length */
  472. }
  473.  
  474. void padbytes(ft, n)
  475. ft_t ft;
  476. int n;
  477. {
  478.     while (--n >= 0)
  479.         putc('\0', ft->fp);
  480. }
  481.  
  482.  
  483. /* End of hcom utility routines */
  484.  
  485. void hcomstopwrite(ft) 
  486. ft_t ft;
  487. {
  488.     register struct writepriv *p = (struct writepriv *) ft->priv;
  489.     unsigned char *compressed_data = p->data;
  490.     LONG compressed_len = p->pos;
  491.  
  492.     /* Compress it all at once */
  493.     compress(&compressed_data, &compressed_len, (double) ft->info.rate);
  494.     free((char *) p->data);
  495.  
  496.     /* Write the header */
  497.     (void) fwrite("\000\001A", 1, 3, ft->fp); /* Dummy file name "A" */
  498.     padbytes(ft, 65-3);
  499.     (void) fwrite("FSSD", 1, 4, ft->fp);
  500.     padbytes(ft, 83-69);
  501.     wlong(ft, (ULONG) compressed_len); /* compressed_data size */
  502.     wlong(ft, (ULONG) 0); /* rsrc size */
  503.     padbytes(ft, 128 - 91);
  504.     if (ferror(ft->fp))
  505.         fail("write error in HCOM header");
  506.  
  507.     /* Write the compressed_data fork */
  508.     if (fwrite((char *) compressed_data, 1, (int)compressed_len, ft->fp) != compressed_len)
  509.         fail("can't write compressed HCOM data");
  510.     free((char *) compressed_data);
  511.  
  512.     /* Pad the compressed_data fork to a multiple of 128 bytes */
  513.     padbytes(ft, 128 - (int) (compressed_len%128));
  514. }
  515.  
  516.