/* convert to/from ulaw audio encoding handles only 8000 Hz. 8-bit single channel data R. Perry, March 2005 */ #include #include #include #include #include #include "g711.h" /* global argv[0] for error messages */ char *progname; /* input buffer for encoding */ double *buf = NULL; int size = 0; int n = 0; int push( double s) { if( n == size) { int newsize = 1.5*size + 65536; double *newbuf; if( newsize > 1048576) { fprintf( stderr, "%s: buffer limit reached\n", progname); return 1; } newbuf = realloc( buf, newsize*sizeof(double)); if( newbuf == NULL) { fprintf( stderr, "%s: realloc() failed\n", progname); exit(1); } size = newsize; buf = newbuf; } buf[n++] = s; return 0; } /* au file header */ typedef struct { unsigned int magic; /* file magic ".snd" */ unsigned int offset; /* offset to start of data */ unsigned int nbytes; /* number of bytes of data */ unsigned int format; /* data format code */ unsigned int rate; /* sampling rate */ unsigned int nchan; /* number of channels */ unsigned int info; /* optional text info */ } au_header; /* for little-endian systems only, e.g. Intel, * swap bytes of a 32-bit int * (since the Sun audio file header data format is bigendian) */ int swap( int x) { return ((x << 24) & 0xFF000000) | ((x << 8) & 0x00FF0000) | ((x >> 8) & 0x0000FF00) | ((x >> 24) & 0x000000FF); } // pick one: // #define SWAP(x) swap(x) // #define SWAP(x) (x) /* convert au file to text/PCM samples */ void do_decode( void) { int c, s; double d; au_header auh; errno = 0; if( fread( &auh, sizeof(auh), 1, stdin) != 1) { fprintf( stderr, "%s: can't read au header: %s\n", progname, strerror( errno)); exit(1); } if( SWAP(auh.format) != 1) { fprintf( stderr, "%s: au format %u != 1\n", progname, SWAP(auh.format)); exit(1); } if( SWAP(auh.nchan) != 1) { fprintf( stderr, "%s: au nchan %u != 1\n", progname, SWAP(auh.nchan)); exit(1); } if( fseek( stdin, SWAP(auh.offset) - sizeof(auh), SEEK_CUR)) { fprintf( stderr, "%s: fseek: %s\n", progname, strerror( errno)); exit(1); } while( (c = getchar()) >= 0) { s = ulaw2linear( c); d = s/32767.0; printf( "%18.9e\n", d); } } /* convert text/PCM samples to au file */ void do_encode( void) { int i, c; double s, t, max; au_header auh; while( scanf( "%lf", &s) == 1) if( push(s)) break; memcpy( &auh.magic, ".snd", 4); auh.offset = SWAP(sizeof(auh)); auh.nbytes = SWAP(n); auh.format = SWAP(1); auh.rate = SWAP(8000); auh.nchan = SWAP(1); auh.info = SWAP(0); if( fwrite( &auh, sizeof(auh), 1, stdout) != 1) { fprintf( stderr, "%s: can't write au header: %s\n", progname, strerror( errno)); exit(1); } max = fabs( buf[0]); for( i = 1; i < n; ++i) { t = fabs( buf[i]); if( t > max) max = t; } #if 0 fprintf( stderr, "max = %g\n", max); #endif for( i = 0; i < n; ++i) { t = 32767.0*(buf[i]/max); if( t > 0) t += 0.5; else t -= 0.5; c = linear2ulaw( (int) t); putchar( c); } } int main( int argc, char *argv[]) { int encode = 1; // default is to encode progname = argv[0]; if( argc == 2) { if( strcmp( argv[1], "-e") == 0) encode = 1; else if( strcmp( argv[1], "-d") == 0) encode = 0; else encode = -1; } else if( argc > 2) { encode = -1; } if( encode < 0) { fprintf( stderr, "Usage: %s [-e|-d]\n", progname); return 1; } if( encode) do_encode(); else do_decode(); return 0; }