home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 12 / CD_ASCQ_12_0294.iso / vrac / au2wav.zip / ULAW2WAV.C < prev    next >
C/C++ Source or Header  |  1993-05-10  |  11KB  |  344 lines

  1. /*-------------------------------------------------------------------------
  2.  
  3.   ulaw2wav.c - Convert an audio/basic stream into a Microsoft .WAV file.
  4.              This program can also automatically detect Sun sound file
  5.            headers and use the information contained therein.
  6.  
  7.   Usage: ulaw2wav infile outfile
  8.  
  9.   where "infile" is the input file (or "-" for standard input) and "outfile"
  10.   is the output file.
  11.  
  12.   The algorithm used in this program is based in part on the SOX sound tools,
  13.   which provide much better sound conversion facilities than this simple
  14.   program.  Acknowledgements and kudos to the authors of SOX.
  15.  
  16.   Copyright (c) 1993 Rhys Weatherley
  17.  
  18.   Permission to use, copy, modify, and distribute this material
  19.   for any purpose and without fee is hereby granted, provided
  20.   that the above copyright notice and this permission notice
  21.   appear in all copies, and that the name of Rhys Weatherley not be
  22.   used in advertising or publicity pertaining to this
  23.   material without specific, prior written permission.
  24.   RHYS WEATHERLEY MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR
  25.   SUITABILITY OF THIS MATERIAL FOR ANY PURPOSE.  IT IS PROVIDED
  26.   "AS IS", WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
  27.  
  28.   Revision History:
  29.   ================
  30.  
  31.    Version  DD/MM/YY  By  Description
  32.    -------  --------  --  --------------------------------------
  33.      1.0    01/05/93  RW  Original Version of ulaw2wav.c
  34.  
  35.   You may contact the author by:
  36.   =============================
  37.  
  38.    e-mail: rhys@cs.uq.oz.au
  39.      mail: Rhys Weatherley
  40.        5 Horizon Drive
  41.        Jamboree Heights
  42.        Queensland 4074
  43.        Australia
  44.  
  45. -------------------------------------------------------------------------*/
  46.  
  47. #include <stdio.h>
  48.  
  49. #ifdef    __MSDOS__
  50.  
  51. #include <io.h>
  52. #include <fcntl.h>
  53. #include <string.h>
  54.  
  55. #define    READ_BINARY    "rb"
  56. #define    WRITE_BINARY    "wb"
  57.  
  58. #else    /* __MSDOS__ */
  59.  
  60. int    strcmp     ();
  61. int    strncmp     ();
  62. char    *strncpy ();
  63.  
  64. #define    READ_BINARY    "r"
  65. #define    WRITE_BINARY    "w"
  66.  
  67. #endif    /* __MSDOS__ */
  68.  
  69. /*** This table was extracted from the SOX sound tools' libst.h file ***/
  70.  
  71. /*
  72. ** This macro converts from ulaw to 16 bit linear, faster.
  73. **
  74. ** Jef Poskanzer
  75. ** 23 October 1989
  76. **
  77. ** Input: 8 bit ulaw sample
  78. ** Output: signed 16 bit linear sample
  79. */
  80. #define st_ulaw_to_linear(ulawbyte) ulaw_table[ulawbyte]
  81.  
  82. static int ulaw_table[256] = {
  83.     -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956,
  84.     -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764,
  85.     -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412,
  86.     -11900, -11388, -10876, -10364,  -9852,  -9340,  -8828,  -8316,
  87.      -7932,  -7676,  -7420,  -7164,  -6908,  -6652,  -6396,  -6140,
  88.      -5884,  -5628,  -5372,  -5116,  -4860,  -4604,  -4348,  -4092,
  89.      -3900,  -3772,  -3644,  -3516,  -3388,  -3260,  -3132,  -3004,
  90.      -2876,  -2748,  -2620,  -2492,  -2364,  -2236,  -2108,  -1980,
  91.      -1884,  -1820,  -1756,  -1692,  -1628,  -1564,  -1500,  -1436,
  92.      -1372,  -1308,  -1244,  -1180,  -1116,  -1052,   -988,   -924,
  93.       -876,   -844,   -812,   -780,   -748,   -716,   -684,   -652,
  94.       -620,   -588,   -556,   -524,   -492,   -460,   -428,   -396,
  95.       -372,   -356,   -340,   -324,   -308,   -292,   -276,   -260,
  96.       -244,   -228,   -212,   -196,   -180,   -164,   -148,   -132,
  97.       -120,   -112,   -104,    -96,    -88,    -80,    -72,    -64,
  98.        -56,    -48,    -40,    -32,    -24,    -16,     -8,      0,
  99.      32124,  31100,  30076,  29052,  28028,  27004,  25980,  24956,
  100.      23932,  22908,  21884,  20860,  19836,  18812,  17788,  16764,
  101.      15996,  15484,  14972,  14460,  13948,  13436,  12924,  12412,
  102.      11900,  11388,  10876,  10364,   9852,   9340,   8828,   8316,
  103.       7932,   7676,   7420,   7164,   6908,   6652,   6396,   6140,
  104.       5884,   5628,   5372,   5116,   4860,   4604,   4348,   4092,
  105.       3900,   3772,   3644,   3516,   3388,   3260,   3132,   3004,
  106.       2876,   2748,   2620,   2492,   2364,   2236,   2108,   1980,
  107.       1884,   1820,   1756,   1692,   1628,   1564,   1500,   1436,
  108.       1372,   1308,   1244,   1180,   1116,   1052,    988,    924,
  109.        876,    844,    812,    780,    748,    716,    684,    652,
  110.        620,    588,    556,    524,    492,    460,    428,    396,
  111.        372,    356,    340,    324,    308,    292,    276,    260,
  112.        244,    228,    212,    196,    180,    164,    148,    132,
  113.        120,    112,    104,     96,     88,     80,     72,     64,
  114.     56,     48,     40,     32,     24,     16,      8,      0 };
  115.  
  116. /*** End of extracted code ***/
  117.  
  118. /*
  119.  * Define some types for the various word sizes required
  120.  * by this program, together with functions to set the
  121.  * values of the given types in little-endian order.
  122.  */
  123. typedef    short    WORD2;
  124. typedef    long    WORD4;
  125.  
  126. #ifdef    __MSDOS__
  127.  
  128. #define    SetWord2(w,val)        (*(w) = (val))
  129. #define    SetWord4(w,val)        (*(w) = (val))
  130.  
  131. #else    /* __MSDOS__ */
  132.  
  133. typedef    struct    {
  134.           char    bytes[2];
  135.         } WORD2INTERNALS;
  136.  
  137. typedef    struct    {
  138.           char    bytes[4];
  139.         } WORD4INTERNALS;
  140.  
  141. static    void    SetWord2 (w, val)
  142. WORD2    *w;
  143. short    val;
  144. {
  145.   ((WORD2INTERNALS *)w) -> bytes[0] = val & 255;
  146.   ((WORD2INTERNALS *)w) -> bytes[1] = (val >> 8) & 255;
  147. } /* SetWord2 */
  148.  
  149. static    void    SetWord4 (w, val)
  150. WORD4    *w;
  151. long    val;
  152. {
  153.   ((WORD4INTERNALS *)w) -> bytes[0] = val & 255;
  154.   ((WORD4INTERNALS *)w) -> bytes[1] = (val >> 8) & 255;
  155.   ((WORD4INTERNALS *)w) -> bytes[2] = (val >> 16) & 255;
  156.   ((WORD4INTERNALS *)w) -> bytes[3] = (val >> 24) & 255;
  157. } /* SetWord4 */
  158.  
  159. #endif    /* __MSDOS__ */
  160.  
  161. /*
  162.  * Define the header area to use on a .WAV file when
  163.  * converting from audio/basic to .WAV.  Note that it
  164.  * is assumed that the most efficient packing strategy
  165.  * possible is used for the structures.  If this isn't
  166.  * true of your compiler, you'll have to do something
  167.  * else.  Since everything is word-aligned, this
  168.  * shouldn't be a hassle.
  169.  */
  170. typedef    struct    {
  171.           char    riff[4];    /* "RIFF" */
  172.           WORD4    size;        /* Size of the .WAV file */
  173.           char    wave[8];    /* "WAVEfmt " */
  174.           WORD4    fmtsize;    /* 16 */
  175.           WORD2    wFormatTag;    /* 1 for Microsoft PCM format */
  176.           WORD2    wChannels;    /* Number of channels */
  177.           WORD4    dwSamplesPerSec;/* Samples per second (8000) */
  178.           WORD4    dwAvgBytesPerSec;/* Bytes per second (8000) */
  179.           WORD2    wBlockAlign;    /* Block alignment (1 for bytes) */
  180.           WORD2    wBitsPerSample;    /* 8 */
  181.           char    data[4];    /* Audio data */
  182.           WORD4    datasize;    /* Size of the wave data area */
  183.         } AUDIOWAVEHEADER;
  184.  
  185. /*
  186.  * Define some constants important to Sun sound files.
  187.  */
  188. #define    SUN_MAGIC    ".snd"        /* Magic number for Sun sound files */
  189. #define    SUN_MAGIC_LEN    4
  190. #define    SUN_MIN_HDRSIZE    24        /* Minimum header size */
  191. #define    SUN_ULAW    1        /* Encoding for Sun u-law data */
  192.  
  193. #ifdef    __MSDOS__
  194. extern    long    rsoundlong (FILE *infile);
  195. #else
  196. extern    long    rsoundlong ();
  197. #endif
  198.  
  199. int    main (argc, argv)
  200. int    argc;
  201. char    **argv;
  202. {
  203.   AUDIOWAVEHEADER header;
  204.   FILE *infile, *outfile;
  205.   long size;
  206.   int ch, len;
  207.   char magic[SUN_MAGIC_LEN];
  208.  
  209.   /* Open the input and output files */
  210.   if (argc != 3)
  211.     {
  212.       fprintf (stderr, "Usage: %s infile outfile\n", argv[0]);
  213.       return (1);
  214.     } /* if */
  215.   if (!strcmp (argv[1], "-"))
  216.     {
  217.       infile = stdin;
  218. #ifdef    __MSDOS__
  219.       setmode (0, O_BINARY);    /* Make stdin a binary stream under MS-DOS */
  220. #endif    /* __MSDOS__ */
  221.     } /* then */
  222.    else if ((infile = fopen (argv[1], READ_BINARY)) == NULL)
  223.     {
  224.       perror (argv[1]);
  225.       return (1);
  226.     } /* then */
  227.   if ((outfile = fopen (argv[2], WRITE_BINARY)) == NULL)
  228.     {
  229.       perror (argv[2]);
  230.       if (infile != stdin)
  231.         fclose (infile);
  232.       return (1);
  233.     } /* if */
  234.  
  235.   /* Create the header for the output .WAV file */
  236.   strncpy (header.riff, "RIFF", 4);
  237.   SetWord4 (&header.size, 0);
  238.   strncpy (header.wave, "WAVEfmt ", 8);
  239.   SetWord4 (&header.fmtsize, 16);
  240.   SetWord2 (&header.wFormatTag, 1);
  241.   SetWord2 (&header.wChannels, 1);
  242.   SetWord4 (&header.dwSamplesPerSec, 8000);
  243.   SetWord4 (&header.dwAvgBytesPerSec, 8000);
  244.   SetWord2 (&header.wBlockAlign, 1);
  245.   SetWord2 (&header.wBitsPerSample, 8);
  246.   strncpy (header.data, "data", 4);
  247.   SetWord4 (&header.datasize, 0);
  248.  
  249.   /* Check for the presense of a Sun sound file header */
  250.   if ((len = fread (magic, 1, SUN_MAGIC_LEN, infile)) == SUN_MAGIC_LEN &&
  251.       !strncmp (magic, SUN_MAGIC, SUN_MAGIC_LEN))
  252.     {
  253.       /* We have a Sun sound file header: process it */
  254.       int failed = 0;
  255.       long hdrsize = rsoundlong (infile);
  256.       if (hdrsize < SUN_MIN_HDRSIZE)
  257.         failed = 1;
  258.        else
  259.         {
  260.       rsoundlong (infile);    /* Discard the data size */
  261.       if (rsoundlong (infile) != SUN_ULAW)
  262.         failed = 1;        /* We can only handle u-law data */
  263.        else
  264.         {
  265.           /* Read the sampling rate and the number of channels */
  266.           /* and set the values in the wave file header.       */
  267.           long samplerate, channels;
  268.           samplerate = rsoundlong (infile);
  269.           channels = rsoundlong (infile);
  270.           SetWord4 (&header.dwSamplesPerSec, samplerate);
  271.           SetWord4 (&header.dwAvgBytesPerSec, samplerate);
  272.           SetWord2 (&header.wChannels, (int)channels);
  273.           if (samplerate <= 0 || channels < 1)
  274.             failed = 1;
  275.         } /* else */
  276.     } /* else */
  277.       len = 0;
  278.       hdrsize -= SUN_MIN_HDRSIZE;
  279.       while (!failed && hdrsize-- > 0)
  280.         {
  281.       /* Skip the remaining bytes in the header */
  282.       if (getc (infile) == EOF)
  283.         failed = 1;
  284.     } /* while */
  285.       if (failed)
  286.         {
  287.       fprintf (stderr, "Could not process the Sun sound file header\n");
  288.       if (infile != stdin)
  289.         fclose (infile);
  290.       fclose (outfile);
  291.       unlink (argv[2]);
  292.       return (1);
  293.     } /* if */
  294.     } /* if */
  295.  
  296.   /* Write the header to the output file */
  297.   fwrite (&header, 1, sizeof (AUDIOWAVEHEADER), outfile);
  298.  
  299.   /* Convert prematurely read u-law data into wave data */
  300.   size = len;
  301.   for (ch = 0; ch < len; ++ch)
  302.     putc ((((st_ulaw_to_linear ((unsigned char)(magic[ch]))) >> 8)
  303.                 & 255) ^ 128, outfile);
  304.  
  305.   /* Copy the audio/basic data to the output file, converting as we go */
  306.   while ((ch = getc (infile)) != EOF)
  307.     {
  308.       ++size;
  309.       ch = (((st_ulaw_to_linear (ch)) >> 8) & 255) ^ 128;
  310.       putc (ch, outfile);
  311.     } /* while */
  312.  
  313.   /* Change the header to reflect the actual data size */
  314.   fseek (outfile, 0L, 0);
  315.   SetWord4 (&header.datasize, size);
  316.   SetWord4 (&header.size, size + sizeof (AUDIOWAVEHEADER) - 8);
  317.   fwrite (&header, 1, sizeof (AUDIOWAVEHEADER), outfile);
  318.  
  319.   /* Close the files and exit */
  320.   if (infile != stdin)
  321.     fclose (infile);
  322.   fclose (outfile);
  323.   return (0);
  324. } /* main */
  325.  
  326. /*
  327.  * Read a big-endian long value from the input file.
  328.  */
  329. long    rsoundlong (file)
  330. FILE    *file;
  331. {
  332.   int c1, c2, c3, c4;
  333.   c1 = getc (file);
  334.   c2 = getc (file);
  335.   c3 = getc (file);
  336.   c4 = getc (file);
  337.   if (c1 == EOF || c2 == EOF || c3 == EOF || c4 == EOF)
  338.     return (-1);
  339.    else
  340.     return ((((long)c1) << 24) | (((long)c2) << 16) |
  341.             (((long)c3) << 8) | ((long)c4));
  342. } /* rsoundlong */
  343.  
  344.