| 
									
										
										
										
											2005-01-21 03:56:22 +00:00
										 |  |  | /****************************************************************************
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Programs for processing sound files in raw- or WAV-format. | 
					
						
							|  |  |  |  * -- Useful functions for parsing command line options and | 
					
						
							|  |  |  |  *    issuing errors, warnings, and chit chat. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Name:    frame.c | 
					
						
							|  |  |  |  * Version: see static char *standardversion, below. | 
					
						
							|  |  |  |  * Author:  Mark Roberts <mark@manumark.de> | 
					
						
							|  |  |  |  *	    Michael Labuschke <michael@labuschke.de> sys_errlist fixes  | 
					
						
							|  |  |  |  *		 | 
					
						
							|  |  |  |  ****************************************************************************/ | 
					
						
							|  |  |  | /****************************************************************************
 | 
					
						
							|  |  |  |  *  These are useful functions that all DSP programs might find handy | 
					
						
							|  |  |  |  ****************************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <stdio.h>
 | 
					
						
							|  |  |  | #include <math.h>
 | 
					
						
							|  |  |  | #include <stdlib.h> /* for exit and malloc */
 | 
					
						
							|  |  |  | #include <string.h>
 | 
					
						
							|  |  |  | #include <time.h>
 | 
					
						
							|  |  |  | #include <stdarg.h>
 | 
					
						
							|  |  |  | #include <errno.h>
 | 
					
						
							|  |  |  | #include <assert.h>
 | 
					
						
							|  |  |  | #include "frame.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | time_t stopwatch;       /* will hold time at start of calculation */ | 
					
						
							| 
									
										
										
										
											2005-10-28 16:19:04 +00:00
										 |  |  | int samplefrequency; | 
					
						
							| 
									
										
										
										
											2005-01-21 03:56:22 +00:00
										 |  |  | unsigned short samplewidth; | 
					
						
							|  |  |  | unsigned short channels; | 
					
						
							|  |  |  | int wavout;            /* TRUE iff out file should be a .WAV file */ | 
					
						
							|  |  |  | int iswav;             /* TRUE iff in file was found to be a .WAV file */ | 
					
						
							|  |  |  | FILE *in, *out; | 
					
						
							|  |  |  | char *infilename, *outfilename; | 
					
						
							|  |  |  | int verboselevel; | 
					
						
							|  |  |  | char *version = ""; | 
					
						
							|  |  |  | char *usage = ""; | 
					
						
							|  |  |  | static int test_usage; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static char *standardversion = "frame version 1.3, June 13th 2001"; | 
					
						
							|  |  |  | static char *standardusage = | 
					
						
							|  |  |  | "\nOptions common to all mark-dsp programs:\n" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | "-h \t\t create a WAV-header on output files.\n" | 
					
						
							|  |  |  | "-c#\t\t set number of channels to # (1 or 2). Default: like input.\n" | 
					
						
							|  |  |  | "-w#\t\t set number of bits per sample (width) to # (only 16)\n" | 
					
						
							|  |  |  | "-f#\t\t set sample frequency to #. Default: like input.\n" | 
					
						
							|  |  |  | "-V \t\t verbose: talk a lot.\n" | 
					
						
							|  |  |  | "-Q \t\t quiet: talk as little as possible.\n\n" | 
					
						
							|  |  |  | "In most cases, a filename of '-' means stdin or stdout.\n\n" | 
					
						
							|  |  |  | "Bug-reports: mark@manumark.de\n" | 
					
						
							|  |  |  | ; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* -----------------------------------------------------------------------
 | 
					
						
							|  |  |  |    Writes the number of samples to result that are yet to be read from anyin. | 
					
						
							|  |  |  |    Return values are TRUE on success, FALSE on failure. | 
					
						
							|  |  |  |    -----------------------------------------------------------------------*/ | 
					
						
							|  |  |  | int getremainingfilelength( FILE *anyin, long *result) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     long i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     i = ftell (anyin); | 
					
						
							|  |  |  |     if (i == -1) return FALSE; | 
					
						
							|  |  |  |     if (fseek (anyin, 0, SEEK_END) == -1) return FALSE; | 
					
						
							|  |  |  |     *result = ftell (anyin); | 
					
						
							|  |  |  |     if (*result == -1) return FALSE; | 
					
						
							|  |  |  |     (*result) -= i; | 
					
						
							|  |  |  |     (*result) /= samplewidth; | 
					
						
							|  |  |  |     if (fseek (anyin, i, SEEK_SET) == -1) return FALSE; | 
					
						
							|  |  |  |     return TRUE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* -----------------------------------------------------------------------
 | 
					
						
							|  |  |  |    Read a .pk-header from 'anyin'. | 
					
						
							|  |  |  |    -----------------------------------------------------------------------*/ | 
					
						
							|  |  |  | void readpkheader( FILE *anyin) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |    unsigned short tempushort; | 
					
						
							|  |  |  |    int tempint, i, x; | 
					
						
							|  |  |  |    unsigned char blood[8]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    for (i = 0; i < 11; i++) | 
					
						
							|  |  |  |    { | 
					
						
							|  |  |  |       fread( &tempint, 4, 1, anyin); | 
					
						
							|  |  |  |       printf( "%d: %d, ", i, tempint); | 
					
						
							|  |  |  |    } | 
					
						
							|  |  |  |    printf( "\n"); | 
					
						
							|  |  |  |    fread( blood, 1, 8, anyin); | 
					
						
							|  |  |  |    for (i = 0; i < 8; i++) | 
					
						
							|  |  |  |       printf( "%d ", blood[i]); | 
					
						
							|  |  |  |    printf( "\n"); | 
					
						
							|  |  |  |    for (i = 0; i < 8; i++) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |       for (x = 128; x > 0; x /= 2) | 
					
						
							|  |  |  |          printf((blood[i] & x) == 0? "0 ":"1 "); | 
					
						
							|  |  |  |       printf(i%4==3? "\n":"| "); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |    printf( "\n"); | 
					
						
							|  |  |  |    for (i = 0; i < 2; i++) | 
					
						
							|  |  |  |    { | 
					
						
							|  |  |  |       fread( &tempint, 4, 1, anyin); | 
					
						
							|  |  |  |       printf( "%d: %d, ", i, tempint); | 
					
						
							|  |  |  |    } | 
					
						
							|  |  |  |    printf( "\n"); | 
					
						
							|  |  |  |    for (i = 0; i < 2; i++) | 
					
						
							|  |  |  |    { | 
					
						
							|  |  |  |       fread( &tempushort, 2, 1, anyin); | 
					
						
							|  |  |  |       printf( "%d: %d, ", i, tempushort); | 
					
						
							|  |  |  |    } | 
					
						
							|  |  |  |    printf( "\n"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* -----------------------------------------------------------------------
 | 
					
						
							|  |  |  |    Read a .WAV header from 'anyin'. See header for details. | 
					
						
							|  |  |  |    -----------------------------------------------------------------------*/ | 
					
						
							|  |  |  | void readwavheader( FILE *anyin) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |    unsigned int tempuint, sf; | 
					
						
							|  |  |  |    unsigned short tempushort, cn; | 
					
						
							|  |  |  |    char str[9]; | 
					
						
							|  |  |  |    int nowav = FALSE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    iswav = FALSE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    if (ftell(anyin) == -1) /* If we cannot seek this file */ | 
					
						
							|  |  |  |      { | 
					
						
							|  |  |  |        nowav = TRUE;   /* -> Pretend this is no wav-file */ | 
					
						
							|  |  |  |        chat("File not seekable: not checking for WAV-header.\n"); | 
					
						
							|  |  |  |      } | 
					
						
							|  |  |  |    else | 
					
						
							|  |  |  |      { | 
					
						
							|  |  |  |        /* Expect four bytes "RIFF" and four bytes filelength */ | 
					
						
							|  |  |  |        fread (str, 1, 8, anyin);           /* 0 */ | 
					
						
							|  |  |  |        str[4] = '\0'; | 
					
						
							|  |  |  |        if (strcmp(str, "RIFF") != 0) nowav = TRUE; | 
					
						
							|  |  |  |        /* Expect eight bytes "WAVEfmt " */ | 
					
						
							|  |  |  |        fread (str, 1, 8, anyin);           /* 8 */ | 
					
						
							|  |  |  |        str[8] = '\0'; | 
					
						
							|  |  |  |        if (strcmp(str, "WAVEfmt ") != 0) nowav = TRUE; | 
					
						
							|  |  |  |        /* Expect length of fmt data, which should be 16 */ | 
					
						
							|  |  |  |        fread (&tempuint, 4, 1, anyin);   /* 16 */ | 
					
						
							|  |  |  |        if (tempuint != 16) nowav = TRUE; | 
					
						
							|  |  |  |        /* Expect format tag, which should be 1 for pcm */ | 
					
						
							|  |  |  |        fread (&tempushort, 2, 1, anyin); /* 20 */ | 
					
						
							|  |  |  |        if (tempushort != 1) | 
					
						
							|  |  |  | 	 nowav = TRUE; | 
					
						
							|  |  |  |        /* Expect number of channels */ | 
					
						
							|  |  |  |        fread (&cn, 2, 1, anyin); /* 20 */ | 
					
						
							|  |  |  |        if (cn != 1 && cn != 2) nowav = TRUE; | 
					
						
							|  |  |  |        /* Read samplefrequency */ | 
					
						
							|  |  |  |        fread (&sf, 4, 1, anyin);  /* 24 */ | 
					
						
							|  |  |  |        /* Read bytes per second: Should be samplefreq * channels * 2 */ | 
					
						
							|  |  |  |        fread (&tempuint, 4, 1, anyin);         /* 28 */ | 
					
						
							|  |  |  |        if (tempuint != sf * cn * 2) nowav = TRUE; | 
					
						
							|  |  |  |        /* read bytes per frame: Should be channels * 2 */ | 
					
						
							|  |  |  |        fread (&tempushort, 2, 1, anyin);       /* 32 */ | 
					
						
							|  |  |  |        if (tempushort != cn * 2) nowav = TRUE; | 
					
						
							|  |  |  |        /* Read bits per sample: Should be 16 */ | 
					
						
							|  |  |  |        fread (&tempushort, 2, 1, anyin);       /* 34 */ | 
					
						
							|  |  |  |        if (tempushort != 16) nowav = TRUE; | 
					
						
							|  |  |  |        fread (str, 4, 1, anyin);            /* 36 */ | 
					
						
							|  |  |  |        str[4] = '\0'; | 
					
						
							|  |  |  |        if (strcmp(str, "data") != 0) nowav = TRUE; | 
					
						
							|  |  |  |        fread (&tempuint, 4, 1, anyin);   /* 40 */ | 
					
						
							|  |  |  |        if (nowav) | 
					
						
							|  |  |  | 	 { | 
					
						
							|  |  |  | 	   fseek (anyin, 0, SEEK_SET);   /* Back to beginning of file */ | 
					
						
							|  |  |  | 	   chat("File has no WAV header.\n"); | 
					
						
							|  |  |  | 	 } | 
					
						
							|  |  |  |        else | 
					
						
							|  |  |  | 	 { | 
					
						
							|  |  |  | 	   samplefrequency = sf; | 
					
						
							|  |  |  | 	   channels = cn; | 
					
						
							|  |  |  | 	   chat ("Read WAV header: %d channels, samplefrequency %d.\n", | 
					
						
							|  |  |  | 		 channels, samplefrequency); | 
					
						
							|  |  |  | 	   iswav = TRUE; | 
					
						
							|  |  |  | 	 } | 
					
						
							|  |  |  |      } | 
					
						
							|  |  |  |    return; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* -----------------------------------------------------------------------
 | 
					
						
							|  |  |  |    Write a .WAV header to 'out'. See header for details. | 
					
						
							|  |  |  |    -----------------------------------------------------------------------*/ | 
					
						
							|  |  |  | void makewavheader( void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |    unsigned int tempuint, filelength; | 
					
						
							|  |  |  |    unsigned short tempushort; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    /* If fseek fails, don't create the header. */ | 
					
						
							|  |  |  |    if (fseek (out, 0, SEEK_END) != -1) | 
					
						
							|  |  |  |      { | 
					
						
							|  |  |  |        filelength = ftell (out); | 
					
						
							|  |  |  |        chat ("filelength %d, ", filelength); | 
					
						
							|  |  |  |        fseek (out, 0, SEEK_SET); | 
					
						
							|  |  |  |        fwrite ("RIFF", 1, 4, out);   /* 0 */ | 
					
						
							|  |  |  |        tempuint = filelength - 8; fwrite (&tempuint, 4, 1, out);   /* 4 */ | 
					
						
							|  |  |  |        fwrite ("WAVEfmt ", 1, 8, out);   /* 8 */ | 
					
						
							|  |  |  |        /* length of fmt data 16 bytes */ | 
					
						
							|  |  |  |        tempuint = 16; | 
					
						
							|  |  |  |        fwrite (&tempuint, 4, 1, out);   /* 16 */ | 
					
						
							|  |  |  |        /* Format tag: 1 for pcm */ | 
					
						
							|  |  |  |        tempushort = 1; | 
					
						
							|  |  |  |        fwrite (&tempushort, 2, 1, out); /* 20 */ | 
					
						
							|  |  |  |        chat ("%d channels\n", channels); | 
					
						
							|  |  |  |        fwrite (&channels, 2, 1, out); | 
					
						
							|  |  |  |        chat ("samplefrequency %d\n", samplefrequency); | 
					
						
							|  |  |  |        fwrite (&samplefrequency, 4, 1, out);  /* 24 */ | 
					
						
							|  |  |  |        /* Bytes per second */ | 
					
						
							|  |  |  |        tempuint = channels * samplefrequency * 2; | 
					
						
							|  |  |  |        fwrite (&tempuint, 4, 1, out);         /* 28 */ | 
					
						
							|  |  |  |        /* Block align */ | 
					
						
							|  |  |  |        tempushort = 2 * channels; | 
					
						
							|  |  |  |        fwrite (&tempushort, 2, 1, out);       /* 32 */ | 
					
						
							|  |  |  |        /* Bits per sample */ | 
					
						
							|  |  |  |        tempushort = 16; | 
					
						
							|  |  |  |        fwrite (&tempushort, 2, 1, out);       /* 34 */ | 
					
						
							|  |  |  |        fwrite ("data", 4, 1, out);            /* 36 */ | 
					
						
							|  |  |  |        tempuint = filelength - 44; fwrite (&tempuint, 4, 1, out);   /* 40 */ | 
					
						
							|  |  |  |      } | 
					
						
							|  |  |  |    return; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* -----------------------------------------------------------------------
 | 
					
						
							|  |  |  |    After all is read and done, inform the inclined user of the elapsed time | 
					
						
							|  |  |  |    -----------------------------------------------------------------------*/ | 
					
						
							|  |  |  | static void statistics( void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |    int temp; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    temp = time(NULL) - stopwatch; | 
					
						
							|  |  |  |    if (temp != 1) | 
					
						
							|  |  |  |    { | 
					
						
							|  |  |  |       inform ("\nTime: %d seconds\n", temp); | 
					
						
							|  |  |  |    } | 
					
						
							|  |  |  |    else | 
					
						
							|  |  |  |    { | 
					
						
							|  |  |  |       inform ("\nTime: 1 second\n"); | 
					
						
							|  |  |  |    } | 
					
						
							|  |  |  |    return; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* -----------------------------------------------------------------------
 | 
					
						
							|  |  |  |    Start the stopwatch and make sure the user is informed at end of program. | 
					
						
							|  |  |  |    -----------------------------------------------------------------------*/ | 
					
						
							|  |  |  | void startstopwatch(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |    stopwatch = time(NULL);       /* Remember time 'now' */ | 
					
						
							|  |  |  |    atexit(statistics);           /* Call function statistics() at exit. */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    return; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* --------------------------------------------------------------------
 | 
					
						
							|  |  |  |    Tests the character 'coal' for being a command line option character, | 
					
						
							|  |  |  |    momentarrily '-'. | 
					
						
							|  |  |  |    -------------------------------------------------------------------- */ | 
					
						
							|  |  |  | int isoptionchar (char coal) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |    return (coal =='-'); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* -----------------------------------------------------------------------
 | 
					
						
							|  |  |  |    Reads through the arguments on the lookout for an option starting | 
					
						
							|  |  |  |    with 'string'. The rest of the option is read as a time and passed | 
					
						
							|  |  |  |    to *result, where the result is meant to mean 'number of samples' in | 
					
						
							|  |  |  |    that time. | 
					
						
							|  |  |  |    On failure, *result is unchanged. | 
					
						
							|  |  |  |    return value is TRUE on success, FALSE otherwise. | 
					
						
							|  |  |  |    -----------------------------------------------------------------------*/ | 
					
						
							|  |  |  | int parsetimearg( int argcount, char *args[], char *string, int *result) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if ((i = findoption( argcount, args, string)) > 0) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  | 	if (parsetime(args[i] + 1 + strlen( string), result)) | 
					
						
							|  |  |  | 	    return TRUE; | 
					
						
							|  |  |  | 	argerrornum(args[i]+1, ME_NOTIME); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return FALSE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* -----------------------------------------------------------------------
 | 
					
						
							|  |  |  |    The string argument is read as a time and passed | 
					
						
							|  |  |  |    to *result, where the result is meant to mean 'number of samples' in | 
					
						
							|  |  |  |    that time. | 
					
						
							|  |  |  |    On failure, *result is unchanged. | 
					
						
							|  |  |  |    return value is TRUE on success, FALSE otherwise. | 
					
						
							|  |  |  |    -----------------------------------------------------------------------*/ | 
					
						
							|  |  |  | int parsetime(char *string, int *result) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int k; | 
					
						
							|  |  |  |     double temp; | 
					
						
							|  |  |  |     char m, s, end; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     k = sscanf(string, "%lf%c%c%c", &temp, &m, &s, &end); | 
					
						
							|  |  |  |     switch (k) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |       case 0: case EOF: case 4: | 
					
						
							|  |  |  | 	return FALSE; | 
					
						
							|  |  |  |       case 1: | 
					
						
							|  |  |  | 	*result = temp; | 
					
						
							|  |  |  | 	break; | 
					
						
							|  |  |  |       case 2: | 
					
						
							|  |  |  | 	if (m == 's') | 
					
						
							|  |  |  | 	  *result = temp * samplefrequency; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 	  return FALSE; | 
					
						
							|  |  |  | 	break; | 
					
						
							|  |  |  |       case 3: | 
					
						
							|  |  |  | 	if (m == 'm' && s == 's') | 
					
						
							|  |  |  | 	  *result = temp * samplefrequency / 1000; | 
					
						
							|  |  |  | 	else if (m == 'H' && s == 'z') | 
					
						
							|  |  |  | 	  *result = samplefrequency / temp; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 	  return FALSE; | 
					
						
							|  |  |  | 	break; | 
					
						
							|  |  |  |       default: | 
					
						
							|  |  |  | 	argerrornum(NULL, ME_THISCANTHAPPEN); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     return TRUE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* -----------------------------------------------------------------------
 | 
					
						
							|  |  |  |    The string argument is read as a frequency and passed | 
					
						
							|  |  |  |    to *result, where the result is meant to mean 'number of samples' in | 
					
						
							|  |  |  |    one cycle of that frequency. | 
					
						
							|  |  |  |    On failure, *result is unchanged. | 
					
						
							|  |  |  |    return value is TRUE on success, FALSE otherwise. | 
					
						
							|  |  |  |    -----------------------------------------------------------------------*/ | 
					
						
							|  |  |  | int parsefreq(char *string, double *result) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int k; | 
					
						
							|  |  |  |     double temp; | 
					
						
							|  |  |  |     char m, s, end; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     k = sscanf(string, "%lf%c%c%c", &temp, &m, &s, &end); | 
					
						
							|  |  |  |     switch (k) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |       case 0: case EOF: case 2: case 4: | 
					
						
							|  |  |  | 	return FALSE; | 
					
						
							|  |  |  |       case 1: | 
					
						
							|  |  |  | 	*result = temp; | 
					
						
							|  |  |  | 	break; | 
					
						
							|  |  |  |       case 3: | 
					
						
							|  |  |  | 	if (m == 'H' && s == 'z') | 
					
						
							|  |  |  | 	  *result = samplefrequency / temp; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 	  return FALSE; | 
					
						
							|  |  |  | 	break; | 
					
						
							|  |  |  |       default: | 
					
						
							|  |  |  | 	argerrornum(NULL, ME_THISCANTHAPPEN); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     return TRUE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | char *parsefilearg( int argcount, char *args[]) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   int i; | 
					
						
							|  |  |  |   char *result = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    for (i = 1; i < argcount; i++) | 
					
						
							|  |  |  |    { | 
					
						
							|  |  |  |       if (args[i][0] != '\0' && | 
					
						
							|  |  |  | 	  (!isoptionchar (args[i][0]) || args[i][1] == '\0' )) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  | 	/*---------------------------------------------*
 | 
					
						
							|  |  |  | 	 * The argument is a filename:                 * | 
					
						
							|  |  |  | 	 * it is either no dash followed by something, * | 
					
						
							|  |  |  | 	 * or it is a dash following by nothing.       * | 
					
						
							|  |  |  | 	 *---------------------------------------------*/ | 
					
						
							|  |  |  | 	result = malloc( strlen( args[i]) + 1); | 
					
						
							|  |  |  | 	if (result == NULL) | 
					
						
							|  |  |  | 	    fatalperror( "Couldn't allocate memory for filename\n"); | 
					
						
							|  |  |  | 	strcpy( result, args[i]); | 
					
						
							|  |  |  | 	args[i][0] = '\0';                    /* Mark as used up */ | 
					
						
							|  |  |  | 	break; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |    } | 
					
						
							|  |  |  |    return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int parseswitch( char *found, char *wanted) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if (strncmp( found, wanted, strlen( wanted)) == 0) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       if (found[strlen( wanted)] == '\0') | 
					
						
							|  |  |  | 	return TRUE; | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  | 	argerrornum( found, ME_NOSWITCH); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   return FALSE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int parseswitcharg( int argcount, char *args[], char *string) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   int i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if ((i = findoption( argcount, args, string)) > 0) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       if (args[i][strlen( string) + 1] == '\0') | 
					
						
							|  |  |  | 	return TRUE; | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  | 	argerrornum( args[i] + 1, ME_NOSWITCH); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   return FALSE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int parseintarg( int argcount, char *args[], char *string, int *result) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   int i, temp; | 
					
						
							|  |  |  |   char c; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if ((i = findoption( argcount, args, string)) > 0) | 
					
						
							|  |  |  |    { | 
					
						
							|  |  |  |       switch (sscanf(args[i] + 1 + strlen( string), | 
					
						
							|  |  |  | 		     "%d%c", &temp, &c)) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  | 	case 0: case EOF: case 2: | 
					
						
							|  |  |  |             argerrornum(args[i]+1, ME_NOINT); | 
					
						
							|  |  |  |             return FALSE; | 
					
						
							|  |  |  |          case 1: | 
					
						
							|  |  |  | 	   *result = temp; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |          default: | 
					
						
							|  |  |  |             say("frame.c: This can't happen\n"); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       return TRUE; | 
					
						
							|  |  |  |    } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       return FALSE; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* --------------------------------------------------------------------
 | 
					
						
							|  |  |  |    Reads through the arguments on the lookout for an option starting | 
					
						
							|  |  |  |    with 'string'. The rest of the option is read as a double and | 
					
						
							|  |  |  |    passed to *result. | 
					
						
							|  |  |  |    On failure, *result is unchanged. | 
					
						
							|  |  |  |    return value is TRUE on success, FALSE otherwise. | 
					
						
							|  |  |  |    -------------------------------------------------------------------- */ | 
					
						
							|  |  |  | int parsedoublearg( int argcount, char *args[], char *string, double *result) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   int i; | 
					
						
							|  |  |  |   double temp; | 
					
						
							|  |  |  |   char end; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if ((i = findoption( argcount, args, string)) > 0) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       switch (sscanf(args[i] + 1 + strlen( string), "%lf%c", &temp, &end)) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	case 0: case EOF: case 2: | 
					
						
							|  |  |  | 	  argerrornum(args[i]+1, ME_NODOUBLE); | 
					
						
							|  |  |  | 	  return FALSE; | 
					
						
							|  |  |  | 	case 1: | 
					
						
							|  |  |  | 	  *result = temp; | 
					
						
							|  |  |  | 	  break; | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 	  say("frame.c: This can't happen\n"); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  |       return TRUE; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       return FALSE; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* --------------------------------------------------------------------
 | 
					
						
							|  |  |  |    Reads through the arguments on the lookout for an option starting | 
					
						
							|  |  |  |    with 'string'. The rest of the option is read as a volume, i.e. | 
					
						
							|  |  |  |    absolute, percent or db. The result is passed to *result. | 
					
						
							|  |  |  |    On failure, *result is unchanged. | 
					
						
							|  |  |  |    return value is TRUE on success, FALSE otherwise. | 
					
						
							|  |  |  |    -------------------------------------------------------------------- */ | 
					
						
							|  |  |  | int parsevolarg( int argcount, char *args[], char *string, double *result) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   double vol = 1.0; | 
					
						
							|  |  |  |   char sbd, sbb, end; | 
					
						
							|  |  |  |   int i, weird = FALSE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if ((i = findoption( argcount, args, string)) > 0) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       switch (sscanf(args[i] + 1 + strlen( string), | 
					
						
							|  |  |  | 		     "%lf%c%c%c", &vol, &sbd, &sbb, &end)) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	  case 0: case EOF: case 4: | 
					
						
							|  |  |  | 	  weird = TRUE; | 
					
						
							|  |  |  | 	  break;    /* No number: error */ | 
					
						
							|  |  |  | 	case 1: | 
					
						
							|  |  |  | 	  *result = vol; | 
					
						
							|  |  |  | 	  break; | 
					
						
							|  |  |  | 	case 2: | 
					
						
							|  |  |  | 	  if (sbd == '%') | 
					
						
							|  |  |  | 	    *result = vol / 100; | 
					
						
							|  |  |  | 	  else | 
					
						
							|  |  |  | 	    weird = TRUE;    /* One char but no percent: error */ | 
					
						
							|  |  |  | 	  break; | 
					
						
							|  |  |  | 	case 3: | 
					
						
							|  |  |  | 	  if (sbd =='d' && sbb == 'b') | 
					
						
							|  |  |  | 	    *result = pow(2, vol / 6.02); | 
					
						
							|  |  |  | 	  else | 
					
						
							|  |  |  | 	    weird = TRUE;    /* Two chars but not db: error */ | 
					
						
							|  |  |  | 	  break; | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 	  say("frame.c: This can't happen.\n"); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  |       if (weird) | 
					
						
							|  |  |  | 	argerrornum( args[i] + 1, ME_NOVOL); | 
					
						
							|  |  |  | 	  /* ("Weird option: couldn't parse volume '%s'\n", args[i]+2); */ | 
					
						
							|  |  |  |       return !weird; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       return FALSE; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* --------------------------------------------------------------------
 | 
					
						
							|  |  |  |    Reads the specified string 's' and interprets it as a volume. The string | 
					
						
							|  |  |  |    would be of the form 1.8 or 180% or 5db. | 
					
						
							|  |  |  |    On success, the return value TRUE and *result is given result | 
					
						
							|  |  |  |    (i.e. the relative volume, i.e. 1.8). On failure, FALSE is returned and | 
					
						
							|  |  |  |    result is given value 1.0. | 
					
						
							|  |  |  |    -------------------------------------------------------------------- */ | 
					
						
							|  |  |  | int parsevolume(char *s, double *result) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int k; | 
					
						
							|  |  |  |     char sbd, sbb, end; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     *result = 1.0; | 
					
						
							|  |  |  |     k = sscanf(s, "%lf%c%c%c", result, &sbd, &sbb, &end); | 
					
						
							|  |  |  |     switch (k) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       case 0: | 
					
						
							|  |  |  |       case EOF: | 
					
						
							|  |  |  |       case 4: | 
					
						
							|  |  |  |        return FALSE; | 
					
						
							|  |  |  |       case 1: | 
					
						
							|  |  |  |        break; | 
					
						
							|  |  |  |       case 2: | 
					
						
							|  |  |  |        if (sbd != '%') | 
					
						
							|  |  |  | 	   return FALSE; | 
					
						
							|  |  |  |        (*result) /=100; | 
					
						
							|  |  |  |        break; | 
					
						
							|  |  |  |       case 3: | 
					
						
							|  |  |  |        if (sbd !='d' || sbb != 'b') | 
					
						
							|  |  |  | 	   return FALSE; | 
					
						
							|  |  |  |        (*result) = pow(2, (*result) / 6.02); | 
					
						
							|  |  |  |        break; | 
					
						
							|  |  |  |       default: | 
					
						
							|  |  |  |        say("parsevolume: This can't happen (%d).\n", k); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return TRUE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* --------------------------------------------------------------------
 | 
					
						
							|  |  |  |    Reports an error due to parsing the string 's' encountered on the | 
					
						
							|  |  |  |    command line. | 
					
						
							|  |  |  |    -------------------------------------------------------------------- */ | 
					
						
							|  |  |  | void argerror(char *s) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   error ("Error parsing command line. Unrecognized option:\n\t-%s\n", s); | 
					
						
							|  |  |  |   fatalerror("\nTry --help for help.\n"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* --------------------------------------------------------------------
 | 
					
						
							|  |  |  |    Reports an error due to parsing the string 's' encountered on the | 
					
						
							|  |  |  |    command line. 'code' indicates the type of error. | 
					
						
							|  |  |  |    -------------------------------------------------------------------- */ | 
					
						
							|  |  |  | void argerrornum(char *s, Errornum code) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   char *message; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (code == ME_TOOMANYFILES) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       error("Too many files on command line: '%s'.\n", s); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       if (s != NULL) | 
					
						
							|  |  |  | 	error ("Error parsing option -%s:\n\t", s); | 
					
						
							|  |  |  |       switch( code) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	case ME_NOINT: | 
					
						
							|  |  |  | 	  message = "Integer expected"; | 
					
						
							|  |  |  | 	  break; | 
					
						
							|  |  |  | 	case ME_NODOUBLE: | 
					
						
							|  |  |  | 	  message = "Floating point number expected"; | 
					
						
							|  |  |  | 	  break; | 
					
						
							|  |  |  | 	case ME_NOTIME: | 
					
						
							|  |  |  | 	  message = "Time argument expected"; | 
					
						
							|  |  |  | 	  break; | 
					
						
							|  |  |  | 	case ME_NOVOL: | 
					
						
							|  |  |  | 	  message = "Volume argument expected"; | 
					
						
							|  |  |  | 	  break; | 
					
						
							|  |  |  | 	case ME_NOSWITCH: | 
					
						
							|  |  |  | 	  message = "Garbage after switch-type option"; | 
					
						
							|  |  |  | 	  break; | 
					
						
							|  |  |  | 	case ME_HEADERONTEXTFILE: | 
					
						
							|  |  |  | 	  message = "Option -h is not useful for text-output"; | 
					
						
							|  |  |  | 	  break; | 
					
						
							|  |  |  | 	case ME_NOINFILE: | 
					
						
							|  |  |  | 	  message = "No input file specified"; | 
					
						
							|  |  |  | 	  break; | 
					
						
							|  |  |  | 	case ME_NOOUTFILE: | 
					
						
							|  |  |  | 	  message = "No output file specified"; | 
					
						
							|  |  |  | 	  break; | 
					
						
							|  |  |  | 	case ME_NOIOFILE: | 
					
						
							|  |  |  | 	  message = "No input/output file specified"; | 
					
						
							|  |  |  | 	  break; | 
					
						
							|  |  |  | 	case ME_NOSTDIN: | 
					
						
							|  |  |  | 	  message = "Standard in not supported here"; | 
					
						
							|  |  |  | 	  break; | 
					
						
							|  |  |  | 	case ME_NOSTDOUT: | 
					
						
							|  |  |  | 	  message = "Standard out not supported here"; | 
					
						
							|  |  |  | 	  break; | 
					
						
							|  |  |  | 	case ME_NOSTDIO: | 
					
						
							|  |  |  | 	  message = "Standard in/out not supported here"; | 
					
						
							|  |  |  | 	  break; | 
					
						
							|  |  |  | 	case ME_NOTENOUGHFILES: | 
					
						
							|  |  |  | 	  message = "Not enough files specified"; | 
					
						
							|  |  |  | 	  break; | 
					
						
							|  |  |  | 	case ME_THISCANTHAPPEN: | 
					
						
							|  |  |  | 	  fatalerror("\nThis can't happen. Report this as a bug\n"); | 
					
						
							|  |  |  | 	  /* fatalerror does not return */ | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 	  error("Error code %d not implemented. Fix me!\n", code); | 
					
						
							|  |  |  | 	  message = "Error message not implemented. Fix me!"; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  |       error("%s\n", message); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   fatalerror("\nTry --help for help.\n"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* --------------------------------------------------------------------
 | 
					
						
							|  |  |  |    Reports an error due to parsing the string 's' encountered on the | 
					
						
							|  |  |  |    command line. 'message' explains the type of error. | 
					
						
							|  |  |  |    -------------------------------------------------------------------- */ | 
					
						
							|  |  |  | void argerrortxt(char *s, char *message) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if (s != NULL) | 
					
						
							|  |  |  |     error ("Error parsing option -%s:\n\t", s); | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     error ("Error parsing command line:\n\t"); | 
					
						
							|  |  |  |   error ("%s\n", message); | 
					
						
							|  |  |  |   fatalerror("\nTry --help for help.\n"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* --------------------------------------------------------------------
 | 
					
						
							|  |  |  |    Check for any remaining arguments and complain about their existence | 
					
						
							|  |  |  |    -------------------------------------------------------------------- */ | 
					
						
							|  |  |  | void checknoargs( int argcount, char *args[]) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   int i, errorcount = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (i = 1; i < argcount; i++) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       if (args[i][0] != '\0')   /* An unused argument! */ | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	  errorcount++; | 
					
						
							|  |  |  | 	  if (errorcount == 1) | 
					
						
							|  |  |  | 	    error("The following arguments were not recognized:\n"); | 
					
						
							|  |  |  | 	  error("\t%s\n", args[i]); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   if (errorcount > 0)           /* Errors are fatal */ | 
					
						
							|  |  |  |     fatalerror("\nTry --help for help.\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return;                       /* No errors? Return. */ | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* --------------------------------------------------------------------
 | 
					
						
							|  |  |  |    Parses the command line arguments as represented by the function | 
					
						
							|  |  |  |    arguments. Sets the global variables 'in', 'out', 'samplefrequency' | 
					
						
							|  |  |  |    and 'samplewidth' accordingly. Also verboselevel. | 
					
						
							|  |  |  |    The files 'in' and 'out' are even opened according to 'fileswitch'. | 
					
						
							|  |  |  |    See headerfile for details | 
					
						
							|  |  |  |    -------------------------------------------------------------------- */ | 
					
						
							|  |  |  | void parseargs( int argcount, char *args[], int fileswitch) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |    char *filename; | 
					
						
							|  |  |  |    int tempint; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    if ((fileswitch & 1) != 0)     /* If getting infile  */ | 
					
						
							|  |  |  |      in = NULL; | 
					
						
							|  |  |  |    if ((fileswitch & 4) != 0)     /* If getting outfile */ | 
					
						
							|  |  |  |      out = NULL; | 
					
						
							|  |  |  |    wavout = FALSE; | 
					
						
							|  |  |  |    verboselevel = 5; | 
					
						
							|  |  |  |    samplefrequency = DEFAULTFREQ; | 
					
						
							|  |  |  |    samplewidth = 2; | 
					
						
							|  |  |  |    channels = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    /*-----------------------------------------------*
 | 
					
						
							|  |  |  |     * First first check testcase, usage and version * | 
					
						
							|  |  |  |     *-----------------------------------------------*/ | 
					
						
							|  |  |  |    test_usage = parseswitcharg( argcount, args, "-test-usage"); | 
					
						
							|  |  |  |    if (parseswitcharg( argcount, args, "-help")) | 
					
						
							|  |  |  |        { | 
					
						
							|  |  |  | 	 printf("%s%s", usage, standardusage); | 
					
						
							|  |  |  | 	 exit(0); | 
					
						
							|  |  |  |        } | 
					
						
							|  |  |  |    if (parseswitcharg( argcount, args, "-version")) | 
					
						
							|  |  |  |        { | 
					
						
							|  |  |  | 	 printf("%s\n(%s)\n", version, standardversion); | 
					
						
							|  |  |  | 	 exit(0); | 
					
						
							|  |  |  |        } | 
					
						
							|  |  |  |    /*--------------------------------------*
 | 
					
						
							|  |  |  |     * Set verboselevel                     * | 
					
						
							|  |  |  |     *--------------------------------------*/ | 
					
						
							|  |  |  |    while (parseswitcharg( argcount, args, "V")) | 
					
						
							|  |  |  |                verboselevel = 10; | 
					
						
							|  |  |  |    while (parseswitcharg( argcount, args, "Q")) | 
					
						
							|  |  |  |                verboselevel = 1; | 
					
						
							|  |  |  |    /*-------------------------------------------------*
 | 
					
						
							|  |  |  |     * Get filenames and open files * | 
					
						
							|  |  |  |     *-------------------------------------------------*/ | 
					
						
							|  |  |  |    if ((fileswitch & 1) != 0)        /* Infile wanted */ | 
					
						
							|  |  |  |      { | 
					
						
							|  |  |  |        infilename = parsefilearg( argcount, args); | 
					
						
							|  |  |  |        if (infilename == NULL) | 
					
						
							|  |  |  | 	 argerrornum( NULL, ME_NOINFILE); | 
					
						
							|  |  |  |        if (strcmp( infilename, "-") == 0) | 
					
						
							|  |  |  | 	 { | 
					
						
							|  |  |  | 	   infilename = "<stdin>"; | 
					
						
							|  |  |  | 	   in = stdin; | 
					
						
							|  |  |  | 	   if ((fileswitch & 2) != 0)   /* Binfile wanted */ | 
					
						
							|  |  |  | 	     readwavheader( in); | 
					
						
							|  |  |  | 	 } | 
					
						
							|  |  |  |        else | 
					
						
							|  |  |  | 	 { | 
					
						
							|  |  |  | 	   if ((fileswitch & 2) == 0)   /* Textfile wanted */ | 
					
						
							|  |  |  | 	     in = fopen(infilename, "rt"); | 
					
						
							|  |  |  | 	   else                         /* Binfile wanted */ | 
					
						
							|  |  |  | 	     if ((in = fopen(infilename, "rb")) != NULL) | 
					
						
							|  |  |  | 	       readwavheader( in); | 
					
						
							|  |  |  | 	 } | 
					
						
							|  |  |  |        if (in == NULL) | 
					
						
							|  |  |  | 	 fatalerror("Error opening input file '%s': %s\n", infilename,strerror(errno)); | 
					
						
							|  |  |  |        else | 
					
						
							|  |  |  | 	 inform("Using file '%s' as input\n", infilename); | 
					
						
							|  |  |  |      } | 
					
						
							|  |  |  |    if ((fileswitch & 4) != 0)        /* Outfile wanted */ | 
					
						
							|  |  |  |      { | 
					
						
							|  |  |  |        outfilename = parsefilearg( argcount, args); | 
					
						
							|  |  |  |        if (outfilename == NULL) | 
					
						
							|  |  |  | 	 argerrornum( NULL, ME_NOOUTFILE); | 
					
						
							|  |  |  |        if (strcmp( outfilename, "-") == 0) | 
					
						
							|  |  |  | 	 { | 
					
						
							|  |  |  | 	   outfilename = "<stdout>"; | 
					
						
							|  |  |  | 	   out = stdout; | 
					
						
							|  |  |  | 	 } | 
					
						
							|  |  |  |        else | 
					
						
							|  |  |  | 	 { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	   if ((fileswitch & 8) == 0)   /* Textfile wanted */ | 
					
						
							|  |  |  | 	     out = fopen(outfilename, "wt"); | 
					
						
							|  |  |  | 	   else                         /* Binfile wanted */ | 
					
						
							|  |  |  | 	     out = fopen(outfilename, "wb"); | 
					
						
							|  |  |  | 	 } | 
					
						
							|  |  |  |        if (out == NULL) | 
					
						
							|  |  |  | 	 fatalerror("Error opening output file '%s': %s\n", outfilename,strerror(errno)); | 
					
						
							|  |  |  |        else | 
					
						
							|  |  |  | 	 inform("Using file '%s' as output\n", outfilename); | 
					
						
							|  |  |  |      } | 
					
						
							|  |  |  |    if ((fileswitch & 32) != 0)      /* In-/Outfile wanted */ | 
					
						
							|  |  |  |      { | 
					
						
							|  |  |  |        assert (in == NULL && out == NULL); | 
					
						
							|  |  |  |        infilename = outfilename = parsefilearg( argcount, args); | 
					
						
							|  |  |  |        if (outfilename == NULL) | 
					
						
							|  |  |  | 	 argerrornum( NULL, ME_NOIOFILE); | 
					
						
							|  |  |  |        if (strcmp( infilename, "-") == 0) | 
					
						
							|  |  |  | 	 argerrornum( infilename, ME_NOSTDIN); | 
					
						
							|  |  |  |        inform("Using file '%s' as input/output\n", outfilename); | 
					
						
							|  |  |  |        in = out = fopen(outfilename, "r+"); | 
					
						
							|  |  |  |        if (out == NULL) | 
					
						
							|  |  |  | 	 fatalerror("Error opening input/output file '%s': %s\n", outfilename,strerror(errno)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |        readwavheader( in); | 
					
						
							|  |  |  |      } | 
					
						
							|  |  |  |    if ((fileswitch & 16) == 0)  /* No additional files wanted */ | 
					
						
							|  |  |  |      { | 
					
						
							|  |  |  |        if ((filename = parsefilearg( argcount, args)) != NULL) | 
					
						
							|  |  |  | 	 argerrornum( filename, ME_TOOMANYFILES); | 
					
						
							|  |  |  |      } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    /*-------------------------------------------------*
 | 
					
						
							|  |  |  |     * Set samplefrequency, width, wavout,  | 
					
						
							|  |  |  |     *-------------------------------------------------*/ | 
					
						
							|  |  |  |    parseintarg( argcount, args, "f", &samplefrequency); | 
					
						
							|  |  |  |    wavout = parseswitcharg( argcount, args, "h"); | 
					
						
							|  |  |  |    if (parseintarg( argcount, args, "w", &tempint)) | 
					
						
							|  |  |  |      { | 
					
						
							|  |  |  |        if (tempint != 16) | 
					
						
							|  |  |  | 	 argerrortxt(NULL, "Option -w is only valid " | 
					
						
							|  |  |  | 		     "with value 16. Sorry."); | 
					
						
							|  |  |  |        else | 
					
						
							|  |  |  | 	 samplewidth = tempint; | 
					
						
							|  |  |  |      } | 
					
						
							|  |  |  |    if (parseintarg( argcount, args, "c", &tempint)) | 
					
						
							|  |  |  |      { | 
					
						
							|  |  |  |        if (tempint != 1 && tempint != 2) | 
					
						
							|  |  |  | 	 argerrortxt(NULL, "Option -c is only valid " | 
					
						
							|  |  |  | 		     "with values 1 or 2. Sorry."); | 
					
						
							|  |  |  |        else | 
					
						
							|  |  |  | 	 channels = tempint; | 
					
						
							|  |  |  |      } | 
					
						
							|  |  |  |    /*-------------------------------------------------*
 | 
					
						
							|  |  |  |     * Create WAV-header on output if wanted.          * | 
					
						
							|  |  |  |     *-------------------------------------------------*/ | 
					
						
							|  |  |  |    if (wavout) | 
					
						
							|  |  |  |      switch (fileswitch & (12)) | 
					
						
							|  |  |  |        { | 
					
						
							|  |  |  |        case 4:   /* User wants header on textfile */ | 
					
						
							|  |  |  | 	 argerrornum( NULL, ME_HEADERONTEXTFILE); | 
					
						
							|  |  |  |        case 12:  /* User wants header on binfile  */ | 
					
						
							|  |  |  | 	 makewavheader(); | 
					
						
							|  |  |  | 	 break; | 
					
						
							|  |  |  |        case 0:   /* User wants header, but there is no outfile */ | 
					
						
							|  |  |  | 	 /* Problem: what about i/o-file, 32? You might want a header
 | 
					
						
							|  |  |  | 	    on that? Better ignore this case. */ | 
					
						
							|  |  |  | 	 break; | 
					
						
							|  |  |  |        case 8:    /* An application musn't ask for this */ | 
					
						
							|  |  |  |        default:   /* This can't happen */ | 
					
						
							|  |  |  | 	 assert( FALSE); | 
					
						
							|  |  |  |        } | 
					
						
							|  |  |  |    return; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* --------------------------------------------------------------------
 | 
					
						
							|  |  |  |    Returns the index 'i' of the first argument that IS an option, and | 
					
						
							|  |  |  |    which begins with the label 's'. If there is none, -1. | 
					
						
							|  |  |  |    We also mark that option as done with, i.e. we cross it out. | 
					
						
							|  |  |  |    -------------------------------------------------------------------- */ | 
					
						
							|  |  |  | int findoption( int argcount, char *args[], char *s) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |    int i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    if (test_usage) | 
					
						
							|  |  |  |      printf("Checking for option -%s\n", s); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    for (i=1; i<argcount; i++) | 
					
						
							|  |  |  |    { | 
					
						
							|  |  |  |      if (isoptionchar (args[i][0]) && | 
					
						
							|  |  |  | 	 strncmp( args[i] + 1, s, strlen( s)) == 0) | 
					
						
							|  |  |  |        { | 
					
						
							|  |  |  | 	 args[i][0] = '\0'; | 
					
						
							|  |  |  | 	 return i; | 
					
						
							|  |  |  |        } | 
					
						
							|  |  |  |    } | 
					
						
							|  |  |  |    return -1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* --------------------------------------------------------------------
 | 
					
						
							|  |  |  |    Finishes off the .WAV header (if any) and exits correctly and formerly. | 
					
						
							|  |  |  |    -------------------------------------------------------------------- */ | 
					
						
							|  |  |  | int myexit (int value) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   switch (value) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case 0: | 
					
						
							|  |  |  |       if (wavout) | 
					
						
							|  |  |  | 	makewavheader();  /* Writes a fully informed .WAV header */ | 
					
						
							|  |  |  |       chat ("Success!\n"); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |       chat ("Failure.\n"); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   exit (value); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* --------------------------------------------------------------------
 | 
					
						
							|  |  |  |    Reads the stated input file bufferwise, calls the function 'work' | 
					
						
							|  |  |  |    with the proper values, and writes the result to the stated output file. | 
					
						
							|  |  |  |    Return value: TRUE on success, FALSE otherwise. | 
					
						
							|  |  |  |    -------------------------------------------------------------------- */ | 
					
						
							|  |  |  | int workloop( FILE *theinfile, FILE *theoutfile, | 
					
						
							|  |  |  | 	      int (*work)( short *buffer, int length) ) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   short *buffer; | 
					
						
							|  |  |  |   int length, nowlength; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   length = BUFFSIZE; | 
					
						
							|  |  |  |   if ((buffer = malloc( sizeof(short) * length)) == NULL) | 
					
						
							|  |  |  |     fatalperror (""); | 
					
						
							|  |  |  |   while (TRUE) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       nowlength = fread(buffer, sizeof(short), length, theinfile); | 
					
						
							|  |  |  |       if (ferror( theinfile) != 0) | 
					
						
							|  |  |  | 	fatalperror("Error reading input file"); | 
					
						
							|  |  |  |       if (nowlength == 0)   /* Reached end of input file */ | 
					
						
							|  |  |  | 	break; | 
					
						
							|  |  |  |       /* Call the routine that does the work */ | 
					
						
							|  |  |  |       if (!work (buffer, nowlength))         /* On error, stop. */ | 
					
						
							|  |  |  | 	return FALSE; | 
					
						
							|  |  |  |       fwrite(buffer, sizeof(short), nowlength, theoutfile); | 
					
						
							|  |  |  |       if (ferror( theoutfile) != 0) | 
					
						
							|  |  |  | 	fatalperror("Error writing to output file"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   return TRUE;      /* Input file done with, no errors. */ | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int chat( const char *format, ...) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     va_list ap; | 
					
						
							|  |  |  |     int result = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (verboselevel > 5) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  | 	va_start( ap, format); | 
					
						
							|  |  |  | 	result = vfprintf( stderr, format, ap); | 
					
						
							|  |  |  | 	va_end( ap); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int inform( const char *format, ...) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     va_list ap; | 
					
						
							|  |  |  |     int result = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (verboselevel > 1) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  | 	va_start( ap, format); | 
					
						
							|  |  |  | 	result = vfprintf( stderr, format, ap); | 
					
						
							|  |  |  | 	va_end( ap); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int error( const char *format, ...) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     va_list ap; | 
					
						
							|  |  |  |     int result; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     va_start( ap, format); | 
					
						
							|  |  |  |     result = vfprintf( stderr, format, ap); | 
					
						
							|  |  |  |     va_end( ap); | 
					
						
							|  |  |  |     return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void fatalerror( const char *format, ...) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     va_list ap; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     va_start( ap, format); | 
					
						
							|  |  |  |     vfprintf( stderr, format, ap); | 
					
						
							|  |  |  |     va_end( ap); | 
					
						
							|  |  |  |     myexit(1); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void fatalperror( const char *string) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   perror( string); | 
					
						
							|  |  |  |   myexit( 1); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int say( const char *format, ...) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     va_list ap; | 
					
						
							|  |  |  |     int result; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     va_start( ap, format); | 
					
						
							|  |  |  |     result = vfprintf( stdout, format, ap); | 
					
						
							|  |  |  |     va_end( ap); | 
					
						
							|  |  |  |     return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | char *malloccopy( char *string) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     char *result; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     result = malloc( strlen( string) + 1); | 
					
						
							|  |  |  |     if (result != NULL) | 
					
						
							|  |  |  | 	strcpy( result, string); | 
					
						
							|  |  |  |     return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | char *mallocconcat( char *one, char *two) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     char *result; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     result = malloc( strlen( one) + strlen( two) + 1); | 
					
						
							|  |  |  |     if (result != NULL) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  | 	strcpy( result, one); | 
					
						
							|  |  |  | 	strcat( result, two); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | double double2db( double value) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if (value < 0) | 
					
						
							|  |  |  |     value = -value; | 
					
						
							|  |  |  |   return 6.0 * log( value / 32767) / log( 2); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void readawaysamples( FILE *in, size_t size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   short *buffer; | 
					
						
							|  |  |  |   int samplesread, count; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   buffer = malloc( sizeof( *buffer) * BUFFSIZE); | 
					
						
							|  |  |  |   if (buffer == NULL) fatalperror("Couldn't allocate buffer"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   while (size > 0) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       if (size > BUFFSIZE) | 
					
						
							|  |  |  | 	count = BUFFSIZE; | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  | 	count = size; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       samplesread = fread( buffer, sizeof(*buffer), count, in); | 
					
						
							|  |  |  |       if (ferror( in) != 0) | 
					
						
							|  |  |  | 	fatalperror("Error reading input file"); | 
					
						
							|  |  |  |       size -= samplesread; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   free( buffer); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 |