aboutsummaryrefslogtreecommitdiffstats
path: root/trunk/utils/frame.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/utils/frame.c')
-rw-r--r--trunk/utils/frame.c1034
1 files changed, 1034 insertions, 0 deletions
diff --git a/trunk/utils/frame.c b/trunk/utils/frame.c
new file mode 100644
index 000000000..7fdb1637d
--- /dev/null
+++ b/trunk/utils/frame.c
@@ -0,0 +1,1034 @@
+/****************************************************************************
+ *
+ * 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 */
+int samplefrequency;
+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);
+}
+