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