home *** CD-ROM | disk | FTP | other *** search
/ Da Capo / da_capo_vol1.bin / programs / amiga / edit / amisox3.3 / dist / voc.c < prev    next >
C/C++ Source or Header  |  1994-01-23  |  7KB  |  305 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 Sound Blaster VOC handler sources.
  12.  *
  13.  * Outstanding problem: the Sound Blaster DMA clock is 8 bits wide,
  14.  * giving spotty resolution above 10khz.  voctartwrite() should check
  15.  * the given output rate and make sure it's +-1% what the SB can
  16.  * actually do.  Other format drivers should do similar checks.
  17.  *
  18.  * June 28, 93: force output to mono.
  19.  */
  20.  
  21. #include "st.h"
  22.  
  23. /* Private data for VOC file */
  24. typedef struct vocstuff {
  25.     long    rest;            /* bytes remaining in current block */
  26.     long    rate;            /* rate code (byte) of this chunk */
  27.     int    silent;            /* sound or silence? */
  28.     long    srate;            /* rate code (byte) of silence */
  29.     int    blockseek;        /* start of current output block */
  30.     long    samples;        /* number of samples output */
  31. } *vs_t;
  32.  
  33. #define    VOC_TERM    0
  34. #define    VOC_DATA    1
  35. #define    VOC_CONT    2
  36. #define    VOC_SILENCE    3
  37. #define    VOC_MARKER    4
  38. #define    VOC_TEXT    5
  39. #define    VOC_LOOP    6
  40. #define    VOC_LOOPEND    7
  41.  
  42. #define    min(a, b)    (((a) < (b)) ? (a) : (b))
  43.  
  44. IMPORT int summary, verbose;
  45. void getblock();
  46.  
  47. vocstartread(ft) 
  48. ft_t ft;
  49. {
  50.     char header[20];
  51.     vs_t v = (vs_t) ft->priv;
  52.     int sbseek;
  53.  
  54.     if (! ft->seekable)
  55.         fail("VOC input file must be a file, not a pipe");
  56.     if (fread(header, 1, 20, ft->fp) != 20)
  57.         fail("unexpected EOF in VOC header");
  58.     if (strncmp(header, "Creative Voice File\032", 19))
  59.         fail("VOC file header incorrect");
  60.  
  61.     sbseek = rlshort(ft);
  62.     fseek(ft->fp, sbseek, 0);
  63.  
  64.     v->rate = -1;
  65.     v->rest = 0;
  66.     getblock(ft);
  67.     if (v->rate == -1)
  68.         fail("Input .voc file had no sound!");
  69.  
  70.     ft->info.rate = 1000000.0/(256 - v->rate);
  71.     ft->info.size = BYTE;
  72.     ft->info.style = UNSIGNED;
  73.     if (ft->info.channels == -1)
  74.         ft->info.channels = 1;
  75. }
  76.  
  77. vocread(ft, buf, len) 
  78. ft_t ft;
  79. long *buf, len;
  80. {
  81.     vs_t v = (vs_t) ft->priv;
  82.     int done = 0;
  83.     
  84.     if (v->rest == 0)
  85.         getblock(ft);
  86.     if (v->rest == 0)
  87.         return 0;
  88.  
  89.     if (v->silent) {
  90.         /* Fill in silence */
  91.         for(;v->rest && (done < len); v->rest--, done++)
  92.             *buf++ = 0x80000000;
  93.     } else {
  94.         for(;v->rest && (done < len); v->rest--, done++) {
  95.             long l;
  96.             if ((l = getc(ft->fp)) == EOF) {
  97.                 fail("VOC input: short file"); /* */
  98.                 v->rest = 0;
  99.                 return 0;
  100.             }
  101.             l ^= 0x80;    /* convert to signed */
  102.             *buf++ = LEFT(l, 24);
  103.         }
  104.     }
  105.     return done;
  106. }
  107.  
  108. /* nothing to do */
  109. vocstopread(ft) 
  110. ft_t ft;
  111. {
  112. }
  113.  
  114. vocstartwrite(ft) 
  115. ft_t ft;
  116. {
  117.     vs_t v = (vs_t) ft->priv;
  118.  
  119.     if (! ft->seekable)
  120.         fail("Output .voc file must be a file, not a pipe");
  121.  
  122.     v->samples = 0;
  123.  
  124.     /* File format name and a ^Z (aborts printing under DOS) */
  125.     (void) fwrite("Creative Voice File\032\032", 1, 20, ft->fp);
  126.     wlshort(ft, 26);        /* size of header */
  127.     wlshort(ft, 0x10a);             /* major/minor version number */
  128.     wlshort(ft, 0x1129);        /* checksum of version number */
  129.  
  130.     ft->info.size = BYTE;
  131.     ft->info.style = UNSIGNED;
  132.     if (ft->info.channels == -1)
  133.         ft->info.channels = 1;
  134.     else    /* Don't implement stereo yet! */
  135.         ft->info.channels = 1;
  136. }
  137.  
  138. vocwrite(ft, buf, len) 
  139. ft_t ft;
  140. long *buf, len;
  141. {
  142.     vs_t v = (vs_t) ft->priv;
  143.     unsigned char uc;
  144.  
  145.     v->rate = 256 - (1000000.0/(float)ft->info.rate);    /* Rate code */
  146.     if (v->samples == 0) {
  147.         /* No silence packing yet. */
  148.         v->silent = 0;
  149.         blockstart(&outformat);
  150.     }
  151.     v->samples += len;
  152.     while(len--) {
  153.         uc = RIGHT(*buf++, 24);
  154.         uc ^= 0x80;
  155.         putc(uc, ft->fp);
  156.     }
  157. }
  158.  
  159. vocstopwrite(ft) 
  160. ft_t ft;
  161. {
  162.     blockstop(ft);
  163. }
  164.  
  165. /* Voc-file handlers */
  166.  
  167. /* Read next block header, save info, leave position at start of data */
  168. void
  169. getblock(ft)
  170. ft_t ft;
  171. {
  172.     vs_t v = (vs_t) ft->priv;
  173.     unsigned char uc, block;
  174.     unsigned long sblen;
  175.     int i;
  176.  
  177.     v->silent = 0;
  178.     while (v->rest == 0) {
  179.         if (feof(ft->fp))
  180.             return;
  181.         block = getc(ft->fp);
  182.         if (block == VOC_TERM)
  183.             return;
  184.         if (feof(ft->fp))
  185.             return;
  186.         uc = getc(ft->fp);
  187.         sblen = uc;
  188.         uc = getc(ft->fp);
  189.         sblen |= ((long) uc) << 8;
  190.         uc = getc(ft->fp);
  191.         sblen |= ((long) uc) << 16;
  192.         switch(block) {
  193.         case VOC_DATA: 
  194.             uc = getc(ft->fp);
  195.             if (uc == 0)
  196.                fail("File %s: Sample rate is zero?");
  197.             if ((v->rate != -1) && (uc != v->rate))
  198.                fail("File %s: sample rate codes differ: %d != %d",
  199.                     v->rate, uc);
  200.             v->rate = uc;
  201.             uc = getc(ft->fp);
  202.             if (uc != 0)
  203.                 fail("File %s: only interpret 8-bit data!");
  204.             v->rest = sblen - 2;
  205.             return;
  206.         case VOC_CONT: 
  207.             v->rest = sblen;
  208.             return;
  209.         case VOC_SILENCE: 
  210.             {
  211.             unsigned short period;
  212.  
  213.             period = rlshort(ft);
  214.             uc = getc(ft->fp);
  215.             if (uc == 0)
  216.                 fail("File %s: Silence sample rate is zero");
  217.             /* 
  218.              * Some silence-packed files have gratuitously
  219.              * different sample rate codes in silence.
  220.              * Adjust period.
  221.              */
  222.             if ((v->rate != -1) && (uc != v->rate))
  223.                 period = (period * (256 - uc))/(256 - v->rate);
  224.             else
  225.                 v->rate = uc;
  226.             v->rest = period;
  227.             v->silent = 1;
  228.             return;
  229.             }
  230.         case VOC_MARKER:
  231.             uc = getc(ft->fp);
  232.             uc = getc(ft->fp);
  233.             /* Falling! Falling! */
  234.         case VOC_TEXT:
  235.             {
  236.             int i;
  237.             /* Could add to comment in SF? */
  238.             for(i = 0; i < sblen; i++)
  239.                 getc(ft->fp);
  240.             }
  241.             continue;    /* get next block */
  242.         case VOC_LOOP:
  243.         case VOC_LOOPEND:
  244.             report("File %s: skipping repeat loop");
  245.             for(i = 0; i < sblen; i++)
  246.                 getc(ft->fp);
  247.             break;
  248.         default:
  249.             report("File %s: skipping unknown block code %d",
  250.                 ft->filename, block);
  251.             for(i = 0; i < sblen; i++)
  252.                 getc(ft->fp);
  253.         }
  254.     }
  255. }
  256.  
  257. /* Start an output block. */
  258. blockstart(ft)
  259. ft_t ft;
  260. {
  261.     vs_t v = (vs_t) ft->priv;
  262.  
  263.     v->blockseek = ftell(ft->fp);
  264.     if (v->silent) {
  265.         putc(VOC_SILENCE, ft->fp);    /* Silence block code */
  266.         putc(0, ft->fp);        /* Period length */
  267.         putc(0, ft->fp);        /* Period length */
  268.         putc((int) v->rate, ft->fp);        /* Rate code */
  269.     } else {
  270.         putc(VOC_DATA, ft->fp);        /* Voice Data block code */
  271.         putc(0, ft->fp);        /* block length (for now) */
  272.         putc(0, ft->fp);        /* block length (for now) */
  273.         putc(0, ft->fp);        /* block length (for now) */
  274.         putc((int) v->rate, ft->fp);        /* Rate code */
  275.         putc(0, ft->fp);        /* 8-bit raw data */
  276.     }
  277. }
  278.  
  279. /* End the current data or silence block. */
  280. blockstop(ft) 
  281. ft_t ft;
  282. {
  283.     vs_t v = (vs_t) ft->priv;
  284.     long datum;
  285.  
  286.     putc(0, ft->fp);            /* End of file block code */
  287.     fseek(ft->fp, v->blockseek, 0);        /* seek back to block length */
  288.     fseek(ft->fp, 1, 1);            /* seek forward one */
  289.     if (v->silent) {
  290.         datum = (v->samples) & 0xff;
  291.         putc((int)datum, ft->fp);       /* low byte of length */
  292.         datum = (v->samples >> 8) & 0xff;
  293.         putc((int)datum, ft->fp);  /* high byte of length */
  294.     } else {
  295.         v->samples += 2;        /* adjustment: SBDK pp. 3-5 */
  296.         datum = (v->samples) & 0xff;
  297.         putc((int)datum, ft->fp);       /* low byte of length */
  298.         datum = (v->samples >> 8) & 0xff;
  299.         putc((int)datum, ft->fp);  /* middle byte of length */
  300.         datum = (v->samples >> 16) & 0xff;
  301.         putc((int)datum, ft->fp); /* high byte of length */
  302.     }
  303. }
  304.  
  305.