home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
DP Tool Club 12
/
CD_ASCQ_12_0294.iso
/
vrac
/
au2wav.zip
/
ULAW2WAV.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-05-10
|
11KB
|
344 lines
/*-------------------------------------------------------------------------
ulaw2wav.c - Convert an audio/basic stream into a Microsoft .WAV file.
This program can also automatically detect Sun sound file
headers and use the information contained therein.
Usage: ulaw2wav infile outfile
where "infile" is the input file (or "-" for standard input) and "outfile"
is the output file.
The algorithm used in this program is based in part on the SOX sound tools,
which provide much better sound conversion facilities than this simple
program. Acknowledgements and kudos to the authors of SOX.
Copyright (c) 1993 Rhys Weatherley
Permission to use, copy, modify, and distribute this material
for any purpose and without fee is hereby granted, provided
that the above copyright notice and this permission notice
appear in all copies, and that the name of Rhys Weatherley not be
used in advertising or publicity pertaining to this
material without specific, prior written permission.
RHYS WEATHERLEY MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR
SUITABILITY OF THIS MATERIAL FOR ANY PURPOSE. IT IS PROVIDED
"AS IS", WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
Revision History:
================
Version DD/MM/YY By Description
------- -------- -- --------------------------------------
1.0 01/05/93 RW Original Version of ulaw2wav.c
You may contact the author by:
=============================
e-mail: rhys@cs.uq.oz.au
mail: Rhys Weatherley
5 Horizon Drive
Jamboree Heights
Queensland 4074
Australia
-------------------------------------------------------------------------*/
#include <stdio.h>
#ifdef __MSDOS__
#include <io.h>
#include <fcntl.h>
#include <string.h>
#define READ_BINARY "rb"
#define WRITE_BINARY "wb"
#else /* __MSDOS__ */
int strcmp ();
int strncmp ();
char *strncpy ();
#define READ_BINARY "r"
#define WRITE_BINARY "w"
#endif /* __MSDOS__ */
/*** This table was extracted from the SOX sound tools' libst.h file ***/
/*
** This macro converts from ulaw to 16 bit linear, faster.
**
** Jef Poskanzer
** 23 October 1989
**
** Input: 8 bit ulaw sample
** Output: signed 16 bit linear sample
*/
#define st_ulaw_to_linear(ulawbyte) ulaw_table[ulawbyte]
static int ulaw_table[256] = {
-32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956,
-23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764,
-15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412,
-11900, -11388, -10876, -10364, -9852, -9340, -8828, -8316,
-7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
-5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
-3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
-2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
-1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
-1372, -1308, -1244, -1180, -1116, -1052, -988, -924,
-876, -844, -812, -780, -748, -716, -684, -652,
-620, -588, -556, -524, -492, -460, -428, -396,
-372, -356, -340, -324, -308, -292, -276, -260,
-244, -228, -212, -196, -180, -164, -148, -132,
-120, -112, -104, -96, -88, -80, -72, -64,
-56, -48, -40, -32, -24, -16, -8, 0,
32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316,
7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140,
5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092,
3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004,
2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980,
1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436,
1372, 1308, 1244, 1180, 1116, 1052, 988, 924,
876, 844, 812, 780, 748, 716, 684, 652,
620, 588, 556, 524, 492, 460, 428, 396,
372, 356, 340, 324, 308, 292, 276, 260,
244, 228, 212, 196, 180, 164, 148, 132,
120, 112, 104, 96, 88, 80, 72, 64,
56, 48, 40, 32, 24, 16, 8, 0 };
/*** End of extracted code ***/
/*
* Define some types for the various word sizes required
* by this program, together with functions to set the
* values of the given types in little-endian order.
*/
typedef short WORD2;
typedef long WORD4;
#ifdef __MSDOS__
#define SetWord2(w,val) (*(w) = (val))
#define SetWord4(w,val) (*(w) = (val))
#else /* __MSDOS__ */
typedef struct {
char bytes[2];
} WORD2INTERNALS;
typedef struct {
char bytes[4];
} WORD4INTERNALS;
static void SetWord2 (w, val)
WORD2 *w;
short val;
{
((WORD2INTERNALS *)w) -> bytes[0] = val & 255;
((WORD2INTERNALS *)w) -> bytes[1] = (val >> 8) & 255;
} /* SetWord2 */
static void SetWord4 (w, val)
WORD4 *w;
long val;
{
((WORD4INTERNALS *)w) -> bytes[0] = val & 255;
((WORD4INTERNALS *)w) -> bytes[1] = (val >> 8) & 255;
((WORD4INTERNALS *)w) -> bytes[2] = (val >> 16) & 255;
((WORD4INTERNALS *)w) -> bytes[3] = (val >> 24) & 255;
} /* SetWord4 */
#endif /* __MSDOS__ */
/*
* Define the header area to use on a .WAV file when
* converting from audio/basic to .WAV. Note that it
* is assumed that the most efficient packing strategy
* possible is used for the structures. If this isn't
* true of your compiler, you'll have to do something
* else. Since everything is word-aligned, this
* shouldn't be a hassle.
*/
typedef struct {
char riff[4]; /* "RIFF" */
WORD4 size; /* Size of the .WAV file */
char wave[8]; /* "WAVEfmt " */
WORD4 fmtsize; /* 16 */
WORD2 wFormatTag; /* 1 for Microsoft PCM format */
WORD2 wChannels; /* Number of channels */
WORD4 dwSamplesPerSec;/* Samples per second (8000) */
WORD4 dwAvgBytesPerSec;/* Bytes per second (8000) */
WORD2 wBlockAlign; /* Block alignment (1 for bytes) */
WORD2 wBitsPerSample; /* 8 */
char data[4]; /* Audio data */
WORD4 datasize; /* Size of the wave data area */
} AUDIOWAVEHEADER;
/*
* Define some constants important to Sun sound files.
*/
#define SUN_MAGIC ".snd" /* Magic number for Sun sound files */
#define SUN_MAGIC_LEN 4
#define SUN_MIN_HDRSIZE 24 /* Minimum header size */
#define SUN_ULAW 1 /* Encoding for Sun u-law data */
#ifdef __MSDOS__
extern long rsoundlong (FILE *infile);
#else
extern long rsoundlong ();
#endif
int main (argc, argv)
int argc;
char **argv;
{
AUDIOWAVEHEADER header;
FILE *infile, *outfile;
long size;
int ch, len;
char magic[SUN_MAGIC_LEN];
/* Open the input and output files */
if (argc != 3)
{
fprintf (stderr, "Usage: %s infile outfile\n", argv[0]);
return (1);
} /* if */
if (!strcmp (argv[1], "-"))
{
infile = stdin;
#ifdef __MSDOS__
setmode (0, O_BINARY); /* Make stdin a binary stream under MS-DOS */
#endif /* __MSDOS__ */
} /* then */
else if ((infile = fopen (argv[1], READ_BINARY)) == NULL)
{
perror (argv[1]);
return (1);
} /* then */
if ((outfile = fopen (argv[2], WRITE_BINARY)) == NULL)
{
perror (argv[2]);
if (infile != stdin)
fclose (infile);
return (1);
} /* if */
/* Create the header for the output .WAV file */
strncpy (header.riff, "RIFF", 4);
SetWord4 (&header.size, 0);
strncpy (header.wave, "WAVEfmt ", 8);
SetWord4 (&header.fmtsize, 16);
SetWord2 (&header.wFormatTag, 1);
SetWord2 (&header.wChannels, 1);
SetWord4 (&header.dwSamplesPerSec, 8000);
SetWord4 (&header.dwAvgBytesPerSec, 8000);
SetWord2 (&header.wBlockAlign, 1);
SetWord2 (&header.wBitsPerSample, 8);
strncpy (header.data, "data", 4);
SetWord4 (&header.datasize, 0);
/* Check for the presense of a Sun sound file header */
if ((len = fread (magic, 1, SUN_MAGIC_LEN, infile)) == SUN_MAGIC_LEN &&
!strncmp (magic, SUN_MAGIC, SUN_MAGIC_LEN))
{
/* We have a Sun sound file header: process it */
int failed = 0;
long hdrsize = rsoundlong (infile);
if (hdrsize < SUN_MIN_HDRSIZE)
failed = 1;
else
{
rsoundlong (infile); /* Discard the data size */
if (rsoundlong (infile) != SUN_ULAW)
failed = 1; /* We can only handle u-law data */
else
{
/* Read the sampling rate and the number of channels */
/* and set the values in the wave file header. */
long samplerate, channels;
samplerate = rsoundlong (infile);
channels = rsoundlong (infile);
SetWord4 (&header.dwSamplesPerSec, samplerate);
SetWord4 (&header.dwAvgBytesPerSec, samplerate);
SetWord2 (&header.wChannels, (int)channels);
if (samplerate <= 0 || channels < 1)
failed = 1;
} /* else */
} /* else */
len = 0;
hdrsize -= SUN_MIN_HDRSIZE;
while (!failed && hdrsize-- > 0)
{
/* Skip the remaining bytes in the header */
if (getc (infile) == EOF)
failed = 1;
} /* while */
if (failed)
{
fprintf (stderr, "Could not process the Sun sound file header\n");
if (infile != stdin)
fclose (infile);
fclose (outfile);
unlink (argv[2]);
return (1);
} /* if */
} /* if */
/* Write the header to the output file */
fwrite (&header, 1, sizeof (AUDIOWAVEHEADER), outfile);
/* Convert prematurely read u-law data into wave data */
size = len;
for (ch = 0; ch < len; ++ch)
putc ((((st_ulaw_to_linear ((unsigned char)(magic[ch]))) >> 8)
& 255) ^ 128, outfile);
/* Copy the audio/basic data to the output file, converting as we go */
while ((ch = getc (infile)) != EOF)
{
++size;
ch = (((st_ulaw_to_linear (ch)) >> 8) & 255) ^ 128;
putc (ch, outfile);
} /* while */
/* Change the header to reflect the actual data size */
fseek (outfile, 0L, 0);
SetWord4 (&header.datasize, size);
SetWord4 (&header.size, size + sizeof (AUDIOWAVEHEADER) - 8);
fwrite (&header, 1, sizeof (AUDIOWAVEHEADER), outfile);
/* Close the files and exit */
if (infile != stdin)
fclose (infile);
fclose (outfile);
return (0);
} /* main */
/*
* Read a big-endian long value from the input file.
*/
long rsoundlong (file)
FILE *file;
{
int c1, c2, c3, c4;
c1 = getc (file);
c2 = getc (file);
c3 = getc (file);
c4 = getc (file);
if (c1 == EOF || c2 == EOF || c3 == EOF || c4 == EOF)
return (-1);
else
return ((((long)c1) << 24) | (((long)c2) << 16) |
(((long)c3) << 8) | ((long)c4));
} /* rsoundlong */