accomodate users who seem to lack a sense of humor :-)
[asterisk-bristuff.git] / utils / frame.c
blob7fdb1637db650325a3fae79d62e8388e1226345c
1 /****************************************************************************
3 * Programs for processing sound files in raw- or WAV-format.
4 * -- Useful functions for parsing command line options and
5 * issuing errors, warnings, and chit chat.
7 * Name: frame.c
8 * Version: see static char *standardversion, below.
9 * Author: Mark Roberts <mark@manumark.de>
10 * Michael Labuschke <michael@labuschke.de> sys_errlist fixes
12 ****************************************************************************/
13 /****************************************************************************
14 * These are useful functions that all DSP programs might find handy
15 ****************************************************************************/
17 #include <stdio.h>
18 #include <math.h>
19 #include <stdlib.h> /* for exit and malloc */
20 #include <string.h>
21 #include <time.h>
22 #include <stdarg.h>
23 #include <errno.h>
24 #include <assert.h>
25 #include "frame.h"
27 time_t stopwatch; /* will hold time at start of calculation */
28 int samplefrequency;
29 unsigned short samplewidth;
30 unsigned short channels;
31 int wavout; /* TRUE iff out file should be a .WAV file */
32 int iswav; /* TRUE iff in file was found to be a .WAV file */
33 FILE *in, *out;
34 char *infilename, *outfilename;
35 int verboselevel;
36 char *version = "";
37 char *usage = "";
38 static int test_usage;
40 static char *standardversion = "frame version 1.3, June 13th 2001";
41 static char *standardusage =
42 "\nOptions common to all mark-dsp programs:\n"
44 "-h \t\t create a WAV-header on output files.\n"
45 "-c#\t\t set number of channels to # (1 or 2). Default: like input.\n"
46 "-w#\t\t set number of bits per sample (width) to # (only 16)\n"
47 "-f#\t\t set sample frequency to #. Default: like input.\n"
48 "-V \t\t verbose: talk a lot.\n"
49 "-Q \t\t quiet: talk as little as possible.\n\n"
50 "In most cases, a filename of '-' means stdin or stdout.\n\n"
51 "Bug-reports: mark@manumark.de\n"
54 /* -----------------------------------------------------------------------
55 Writes the number of samples to result that are yet to be read from anyin.
56 Return values are TRUE on success, FALSE on failure.
57 -----------------------------------------------------------------------*/
58 int getremainingfilelength( FILE *anyin, long *result)
60 long i;
62 i = ftell (anyin);
63 if (i == -1) return FALSE;
64 if (fseek (anyin, 0, SEEK_END) == -1) return FALSE;
65 *result = ftell (anyin);
66 if (*result == -1) return FALSE;
67 (*result) -= i;
68 (*result) /= samplewidth;
69 if (fseek (anyin, i, SEEK_SET) == -1) return FALSE;
70 return TRUE;
73 /* -----------------------------------------------------------------------
74 Read a .pk-header from 'anyin'.
75 -----------------------------------------------------------------------*/
76 void readpkheader( FILE *anyin)
78 unsigned short tempushort;
79 int tempint, i, x;
80 unsigned char blood[8];
82 for (i = 0; i < 11; i++)
84 fread( &tempint, 4, 1, anyin);
85 printf( "%d: %d, ", i, tempint);
87 printf( "\n");
88 fread( blood, 1, 8, anyin);
89 for (i = 0; i < 8; i++)
90 printf( "%d ", blood[i]);
91 printf( "\n");
92 for (i = 0; i < 8; i++)
94 for (x = 128; x > 0; x /= 2)
95 printf((blood[i] & x) == 0? "0 ":"1 ");
96 printf(i%4==3? "\n":"| ");
98 printf( "\n");
99 for (i = 0; i < 2; i++)
101 fread( &tempint, 4, 1, anyin);
102 printf( "%d: %d, ", i, tempint);
104 printf( "\n");
105 for (i = 0; i < 2; i++)
107 fread( &tempushort, 2, 1, anyin);
108 printf( "%d: %d, ", i, tempushort);
110 printf( "\n");
115 /* -----------------------------------------------------------------------
116 Read a .WAV header from 'anyin'. See header for details.
117 -----------------------------------------------------------------------*/
118 void readwavheader( FILE *anyin)
120 unsigned int tempuint, sf;
121 unsigned short tempushort, cn;
122 char str[9];
123 int nowav = FALSE;
125 iswav = FALSE;
127 if (ftell(anyin) == -1) /* If we cannot seek this file */
129 nowav = TRUE; /* -> Pretend this is no wav-file */
130 chat("File not seekable: not checking for WAV-header.\n");
132 else
134 /* Expect four bytes "RIFF" and four bytes filelength */
135 fread (str, 1, 8, anyin); /* 0 */
136 str[4] = '\0';
137 if (strcmp(str, "RIFF") != 0) nowav = TRUE;
138 /* Expect eight bytes "WAVEfmt " */
139 fread (str, 1, 8, anyin); /* 8 */
140 str[8] = '\0';
141 if (strcmp(str, "WAVEfmt ") != 0) nowav = TRUE;
142 /* Expect length of fmt data, which should be 16 */
143 fread (&tempuint, 4, 1, anyin); /* 16 */
144 if (tempuint != 16) nowav = TRUE;
145 /* Expect format tag, which should be 1 for pcm */
146 fread (&tempushort, 2, 1, anyin); /* 20 */
147 if (tempushort != 1)
148 nowav = TRUE;
149 /* Expect number of channels */
150 fread (&cn, 2, 1, anyin); /* 20 */
151 if (cn != 1 && cn != 2) nowav = TRUE;
152 /* Read samplefrequency */
153 fread (&sf, 4, 1, anyin); /* 24 */
154 /* Read bytes per second: Should be samplefreq * channels * 2 */
155 fread (&tempuint, 4, 1, anyin); /* 28 */
156 if (tempuint != sf * cn * 2) nowav = TRUE;
157 /* read bytes per frame: Should be channels * 2 */
158 fread (&tempushort, 2, 1, anyin); /* 32 */
159 if (tempushort != cn * 2) nowav = TRUE;
160 /* Read bits per sample: Should be 16 */
161 fread (&tempushort, 2, 1, anyin); /* 34 */
162 if (tempushort != 16) nowav = TRUE;
163 fread (str, 4, 1, anyin); /* 36 */
164 str[4] = '\0';
165 if (strcmp(str, "data") != 0) nowav = TRUE;
166 fread (&tempuint, 4, 1, anyin); /* 40 */
167 if (nowav)
169 fseek (anyin, 0, SEEK_SET); /* Back to beginning of file */
170 chat("File has no WAV header.\n");
172 else
174 samplefrequency = sf;
175 channels = cn;
176 chat ("Read WAV header: %d channels, samplefrequency %d.\n",
177 channels, samplefrequency);
178 iswav = TRUE;
181 return;
186 /* -----------------------------------------------------------------------
187 Write a .WAV header to 'out'. See header for details.
188 -----------------------------------------------------------------------*/
189 void makewavheader( void)
191 unsigned int tempuint, filelength;
192 unsigned short tempushort;
194 /* If fseek fails, don't create the header. */
195 if (fseek (out, 0, SEEK_END) != -1)
197 filelength = ftell (out);
198 chat ("filelength %d, ", filelength);
199 fseek (out, 0, SEEK_SET);
200 fwrite ("RIFF", 1, 4, out); /* 0 */
201 tempuint = filelength - 8; fwrite (&tempuint, 4, 1, out); /* 4 */
202 fwrite ("WAVEfmt ", 1, 8, out); /* 8 */
203 /* length of fmt data 16 bytes */
204 tempuint = 16;
205 fwrite (&tempuint, 4, 1, out); /* 16 */
206 /* Format tag: 1 for pcm */
207 tempushort = 1;
208 fwrite (&tempushort, 2, 1, out); /* 20 */
209 chat ("%d channels\n", channels);
210 fwrite (&channels, 2, 1, out);
211 chat ("samplefrequency %d\n", samplefrequency);
212 fwrite (&samplefrequency, 4, 1, out); /* 24 */
213 /* Bytes per second */
214 tempuint = channels * samplefrequency * 2;
215 fwrite (&tempuint, 4, 1, out); /* 28 */
216 /* Block align */
217 tempushort = 2 * channels;
218 fwrite (&tempushort, 2, 1, out); /* 32 */
219 /* Bits per sample */
220 tempushort = 16;
221 fwrite (&tempushort, 2, 1, out); /* 34 */
222 fwrite ("data", 4, 1, out); /* 36 */
223 tempuint = filelength - 44; fwrite (&tempuint, 4, 1, out); /* 40 */
225 return;
228 /* -----------------------------------------------------------------------
229 After all is read and done, inform the inclined user of the elapsed time
230 -----------------------------------------------------------------------*/
231 static void statistics( void)
233 int temp;
235 temp = time(NULL) - stopwatch;
236 if (temp != 1)
238 inform ("\nTime: %d seconds\n", temp);
240 else
242 inform ("\nTime: 1 second\n");
244 return;
248 /* -----------------------------------------------------------------------
249 Start the stopwatch and make sure the user is informed at end of program.
250 -----------------------------------------------------------------------*/
251 void startstopwatch(void)
253 stopwatch = time(NULL); /* Remember time 'now' */
254 atexit(statistics); /* Call function statistics() at exit. */
256 return;
259 /* --------------------------------------------------------------------
260 Tests the character 'coal' for being a command line option character,
261 momentarrily '-'.
262 -------------------------------------------------------------------- */
263 int isoptionchar (char coal)
265 return (coal =='-');
268 /* -----------------------------------------------------------------------
269 Reads through the arguments on the lookout for an option starting
270 with 'string'. The rest of the option is read as a time and passed
271 to *result, where the result is meant to mean 'number of samples' in
272 that time.
273 On failure, *result is unchanged.
274 return value is TRUE on success, FALSE otherwise.
275 -----------------------------------------------------------------------*/
276 int parsetimearg( int argcount, char *args[], char *string, int *result)
278 int i;
280 if ((i = findoption( argcount, args, string)) > 0)
282 if (parsetime(args[i] + 1 + strlen( string), result))
283 return TRUE;
284 argerrornum(args[i]+1, ME_NOTIME);
286 return FALSE;
289 /* -----------------------------------------------------------------------
290 The string argument is read as a time and passed
291 to *result, where the result is meant to mean 'number of samples' in
292 that time.
293 On failure, *result is unchanged.
294 return value is TRUE on success, FALSE otherwise.
295 -----------------------------------------------------------------------*/
296 int parsetime(char *string, int *result)
298 int k;
299 double temp;
300 char m, s, end;
302 k = sscanf(string, "%lf%c%c%c", &temp, &m, &s, &end);
303 switch (k)
305 case 0: case EOF: case 4:
306 return FALSE;
307 case 1:
308 *result = temp;
309 break;
310 case 2:
311 if (m == 's')
312 *result = temp * samplefrequency;
313 else
314 return FALSE;
315 break;
316 case 3:
317 if (m == 'm' && s == 's')
318 *result = temp * samplefrequency / 1000;
319 else if (m == 'H' && s == 'z')
320 *result = samplefrequency / temp;
321 else
322 return FALSE;
323 break;
324 default:
325 argerrornum(NULL, ME_THISCANTHAPPEN);
327 return TRUE;
330 /* -----------------------------------------------------------------------
331 The string argument is read as a frequency and passed
332 to *result, where the result is meant to mean 'number of samples' in
333 one cycle of that frequency.
334 On failure, *result is unchanged.
335 return value is TRUE on success, FALSE otherwise.
336 -----------------------------------------------------------------------*/
337 int parsefreq(char *string, double *result)
339 int k;
340 double temp;
341 char m, s, end;
343 k = sscanf(string, "%lf%c%c%c", &temp, &m, &s, &end);
344 switch (k)
346 case 0: case EOF: case 2: case 4:
347 return FALSE;
348 case 1:
349 *result = temp;
350 break;
351 case 3:
352 if (m == 'H' && s == 'z')
353 *result = samplefrequency / temp;
354 else
355 return FALSE;
356 break;
357 default:
358 argerrornum(NULL, ME_THISCANTHAPPEN);
360 return TRUE;
363 char *parsefilearg( int argcount, char *args[])
365 int i;
366 char *result = NULL;
368 for (i = 1; i < argcount; i++)
370 if (args[i][0] != '\0' &&
371 (!isoptionchar (args[i][0]) || args[i][1] == '\0' ))
373 /*---------------------------------------------*
374 * The argument is a filename: *
375 * it is either no dash followed by something, *
376 * or it is a dash following by nothing. *
377 *---------------------------------------------*/
378 result = malloc( strlen( args[i]) + 1);
379 if (result == NULL)
380 fatalperror( "Couldn't allocate memory for filename\n");
381 strcpy( result, args[i]);
382 args[i][0] = '\0'; /* Mark as used up */
383 break;
386 return result;
389 int parseswitch( char *found, char *wanted)
391 if (strncmp( found, wanted, strlen( wanted)) == 0)
393 if (found[strlen( wanted)] == '\0')
394 return TRUE;
395 else
396 argerrornum( found, ME_NOSWITCH);
398 return FALSE;
401 int parseswitcharg( int argcount, char *args[], char *string)
403 int i;
405 if ((i = findoption( argcount, args, string)) > 0)
407 if (args[i][strlen( string) + 1] == '\0')
408 return TRUE;
409 else
410 argerrornum( args[i] + 1, ME_NOSWITCH);
412 return FALSE;
415 int parseintarg( int argcount, char *args[], char *string, int *result)
417 int i, temp;
418 char c;
420 if ((i = findoption( argcount, args, string)) > 0)
422 switch (sscanf(args[i] + 1 + strlen( string),
423 "%d%c", &temp, &c))
425 case 0: case EOF: case 2:
426 argerrornum(args[i]+1, ME_NOINT);
427 return FALSE;
428 case 1:
429 *result = temp;
430 break;
431 default:
432 say("frame.c: This can't happen\n");
434 return TRUE;
436 else
438 return FALSE;
442 /* --------------------------------------------------------------------
443 Reads through the arguments on the lookout for an option starting
444 with 'string'. The rest of the option is read as a double and
445 passed to *result.
446 On failure, *result is unchanged.
447 return value is TRUE on success, FALSE otherwise.
448 -------------------------------------------------------------------- */
449 int parsedoublearg( int argcount, char *args[], char *string, double *result)
451 int i;
452 double temp;
453 char end;
455 if ((i = findoption( argcount, args, string)) > 0)
457 switch (sscanf(args[i] + 1 + strlen( string), "%lf%c", &temp, &end))
459 case 0: case EOF: case 2:
460 argerrornum(args[i]+1, ME_NODOUBLE);
461 return FALSE;
462 case 1:
463 *result = temp;
464 break;
465 default:
466 say("frame.c: This can't happen\n");
468 return TRUE;
470 else
472 return FALSE;
476 /* --------------------------------------------------------------------
477 Reads through the arguments on the lookout for an option starting
478 with 'string'. The rest of the option is read as a volume, i.e.
479 absolute, percent or db. The result is passed to *result.
480 On failure, *result is unchanged.
481 return value is TRUE on success, FALSE otherwise.
482 -------------------------------------------------------------------- */
483 int parsevolarg( int argcount, char *args[], char *string, double *result)
485 double vol = 1.0;
486 char sbd, sbb, end;
487 int i, weird = FALSE;
489 if ((i = findoption( argcount, args, string)) > 0)
491 switch (sscanf(args[i] + 1 + strlen( string),
492 "%lf%c%c%c", &vol, &sbd, &sbb, &end))
494 case 0: case EOF: case 4:
495 weird = TRUE;
496 break; /* No number: error */
497 case 1:
498 *result = vol;
499 break;
500 case 2:
501 if (sbd == '%')
502 *result = vol / 100;
503 else
504 weird = TRUE; /* One char but no percent: error */
505 break;
506 case 3:
507 if (sbd =='d' && sbb == 'b')
508 *result = pow(2, vol / 6.02);
509 else
510 weird = TRUE; /* Two chars but not db: error */
511 break;
512 default:
513 say("frame.c: This can't happen.\n");
515 if (weird)
516 argerrornum( args[i] + 1, ME_NOVOL);
517 /* ("Weird option: couldn't parse volume '%s'\n", args[i]+2); */
518 return !weird;
520 else
522 return FALSE;
527 /* --------------------------------------------------------------------
528 Reads the specified string 's' and interprets it as a volume. The string
529 would be of the form 1.8 or 180% or 5db.
530 On success, the return value TRUE and *result is given result
531 (i.e. the relative volume, i.e. 1.8). On failure, FALSE is returned and
532 result is given value 1.0.
533 -------------------------------------------------------------------- */
534 int parsevolume(char *s, double *result)
536 int k;
537 char sbd, sbb, end;
539 *result = 1.0;
540 k = sscanf(s, "%lf%c%c%c", result, &sbd, &sbb, &end);
541 switch (k)
543 case 0:
544 case EOF:
545 case 4:
546 return FALSE;
547 case 1:
548 break;
549 case 2:
550 if (sbd != '%')
551 return FALSE;
552 (*result) /=100;
553 break;
554 case 3:
555 if (sbd !='d' || sbb != 'b')
556 return FALSE;
557 (*result) = pow(2, (*result) / 6.02);
558 break;
559 default:
560 say("parsevolume: This can't happen (%d).\n", k);
562 return TRUE;
565 /* --------------------------------------------------------------------
566 Reports an error due to parsing the string 's' encountered on the
567 command line.
568 -------------------------------------------------------------------- */
569 void argerror(char *s)
571 error ("Error parsing command line. Unrecognized option:\n\t-%s\n", s);
572 fatalerror("\nTry --help for help.\n");
575 /* --------------------------------------------------------------------
576 Reports an error due to parsing the string 's' encountered on the
577 command line. 'code' indicates the type of error.
578 -------------------------------------------------------------------- */
579 void argerrornum(char *s, Errornum code)
581 char *message;
583 if (code == ME_TOOMANYFILES)
585 error("Too many files on command line: '%s'.\n", s);
587 else
589 if (s != NULL)
590 error ("Error parsing option -%s:\n\t", s);
591 switch( code)
593 case ME_NOINT:
594 message = "Integer expected";
595 break;
596 case ME_NODOUBLE:
597 message = "Floating point number expected";
598 break;
599 case ME_NOTIME:
600 message = "Time argument expected";
601 break;
602 case ME_NOVOL:
603 message = "Volume argument expected";
604 break;
605 case ME_NOSWITCH:
606 message = "Garbage after switch-type option";
607 break;
608 case ME_HEADERONTEXTFILE:
609 message = "Option -h is not useful for text-output";
610 break;
611 case ME_NOINFILE:
612 message = "No input file specified";
613 break;
614 case ME_NOOUTFILE:
615 message = "No output file specified";
616 break;
617 case ME_NOIOFILE:
618 message = "No input/output file specified";
619 break;
620 case ME_NOSTDIN:
621 message = "Standard in not supported here";
622 break;
623 case ME_NOSTDOUT:
624 message = "Standard out not supported here";
625 break;
626 case ME_NOSTDIO:
627 message = "Standard in/out not supported here";
628 break;
629 case ME_NOTENOUGHFILES:
630 message = "Not enough files specified";
631 break;
632 case ME_THISCANTHAPPEN:
633 fatalerror("\nThis can't happen. Report this as a bug\n");
634 /* fatalerror does not return */
635 default:
636 error("Error code %d not implemented. Fix me!\n", code);
637 message = "Error message not implemented. Fix me!";
639 error("%s\n", message);
641 fatalerror("\nTry --help for help.\n");
644 /* --------------------------------------------------------------------
645 Reports an error due to parsing the string 's' encountered on the
646 command line. 'message' explains the type of error.
647 -------------------------------------------------------------------- */
648 void argerrortxt(char *s, char *message)
650 if (s != NULL)
651 error ("Error parsing option -%s:\n\t", s);
652 else
653 error ("Error parsing command line:\n\t");
654 error ("%s\n", message);
655 fatalerror("\nTry --help for help.\n");
658 /* --------------------------------------------------------------------
659 Check for any remaining arguments and complain about their existence
660 -------------------------------------------------------------------- */
661 void checknoargs( int argcount, char *args[])
663 int i, errorcount = 0;
665 for (i = 1; i < argcount; i++)
667 if (args[i][0] != '\0') /* An unused argument! */
669 errorcount++;
670 if (errorcount == 1)
671 error("The following arguments were not recognized:\n");
672 error("\t%s\n", args[i]);
675 if (errorcount > 0) /* Errors are fatal */
676 fatalerror("\nTry --help for help.\n");
678 return; /* No errors? Return. */
681 /* --------------------------------------------------------------------
682 Parses the command line arguments as represented by the function
683 arguments. Sets the global variables 'in', 'out', 'samplefrequency'
684 and 'samplewidth' accordingly. Also verboselevel.
685 The files 'in' and 'out' are even opened according to 'fileswitch'.
686 See headerfile for details
687 -------------------------------------------------------------------- */
688 void parseargs( int argcount, char *args[], int fileswitch)
690 char *filename;
691 int tempint;
693 if ((fileswitch & 1) != 0) /* If getting infile */
694 in = NULL;
695 if ((fileswitch & 4) != 0) /* If getting outfile */
696 out = NULL;
697 wavout = FALSE;
698 verboselevel = 5;
699 samplefrequency = DEFAULTFREQ;
700 samplewidth = 2;
701 channels = 1;
703 /*-----------------------------------------------*
704 * First first check testcase, usage and version *
705 *-----------------------------------------------*/
706 test_usage = parseswitcharg( argcount, args, "-test-usage");
707 if (parseswitcharg( argcount, args, "-help"))
709 printf("%s%s", usage, standardusage);
710 exit(0);
712 if (parseswitcharg( argcount, args, "-version"))
714 printf("%s\n(%s)\n", version, standardversion);
715 exit(0);
717 /*--------------------------------------*
718 * Set verboselevel *
719 *--------------------------------------*/
720 while (parseswitcharg( argcount, args, "V"))
721 verboselevel = 10;
722 while (parseswitcharg( argcount, args, "Q"))
723 verboselevel = 1;
724 /*-------------------------------------------------*
725 * Get filenames and open files *
726 *-------------------------------------------------*/
727 if ((fileswitch & 1) != 0) /* Infile wanted */
729 infilename = parsefilearg( argcount, args);
730 if (infilename == NULL)
731 argerrornum( NULL, ME_NOINFILE);
732 if (strcmp( infilename, "-") == 0)
734 infilename = "<stdin>";
735 in = stdin;
736 if ((fileswitch & 2) != 0) /* Binfile wanted */
737 readwavheader( in);
739 else
741 if ((fileswitch & 2) == 0) /* Textfile wanted */
742 in = fopen(infilename, "rt");
743 else /* Binfile wanted */
744 if ((in = fopen(infilename, "rb")) != NULL)
745 readwavheader( in);
747 if (in == NULL)
748 fatalerror("Error opening input file '%s': %s\n", infilename,strerror(errno));
749 else
750 inform("Using file '%s' as input\n", infilename);
752 if ((fileswitch & 4) != 0) /* Outfile wanted */
754 outfilename = parsefilearg( argcount, args);
755 if (outfilename == NULL)
756 argerrornum( NULL, ME_NOOUTFILE);
757 if (strcmp( outfilename, "-") == 0)
759 outfilename = "<stdout>";
760 out = stdout;
762 else
765 if ((fileswitch & 8) == 0) /* Textfile wanted */
766 out = fopen(outfilename, "wt");
767 else /* Binfile wanted */
768 out = fopen(outfilename, "wb");
770 if (out == NULL)
771 fatalerror("Error opening output file '%s': %s\n", outfilename,strerror(errno));
772 else
773 inform("Using file '%s' as output\n", outfilename);
775 if ((fileswitch & 32) != 0) /* In-/Outfile wanted */
777 assert (in == NULL && out == NULL);
778 infilename = outfilename = parsefilearg( argcount, args);
779 if (outfilename == NULL)
780 argerrornum( NULL, ME_NOIOFILE);
781 if (strcmp( infilename, "-") == 0)
782 argerrornum( infilename, ME_NOSTDIN);
783 inform("Using file '%s' as input/output\n", outfilename);
784 in = out = fopen(outfilename, "r+");
785 if (out == NULL)
786 fatalerror("Error opening input/output file '%s': %s\n", outfilename,strerror(errno));
788 readwavheader( in);
790 if ((fileswitch & 16) == 0) /* No additional files wanted */
792 if ((filename = parsefilearg( argcount, args)) != NULL)
793 argerrornum( filename, ME_TOOMANYFILES);
796 /*-------------------------------------------------*
797 * Set samplefrequency, width, wavout,
798 *-------------------------------------------------*/
799 parseintarg( argcount, args, "f", &samplefrequency);
800 wavout = parseswitcharg( argcount, args, "h");
801 if (parseintarg( argcount, args, "w", &tempint))
803 if (tempint != 16)
804 argerrortxt(NULL, "Option -w is only valid "
805 "with value 16. Sorry.");
806 else
807 samplewidth = tempint;
809 if (parseintarg( argcount, args, "c", &tempint))
811 if (tempint != 1 && tempint != 2)
812 argerrortxt(NULL, "Option -c is only valid "
813 "with values 1 or 2. Sorry.");
814 else
815 channels = tempint;
817 /*-------------------------------------------------*
818 * Create WAV-header on output if wanted. *
819 *-------------------------------------------------*/
820 if (wavout)
821 switch (fileswitch & (12))
823 case 4: /* User wants header on textfile */
824 argerrornum( NULL, ME_HEADERONTEXTFILE);
825 case 12: /* User wants header on binfile */
826 makewavheader();
827 break;
828 case 0: /* User wants header, but there is no outfile */
829 /* Problem: what about i/o-file, 32? You might want a header
830 on that? Better ignore this case. */
831 break;
832 case 8: /* An application musn't ask for this */
833 default: /* This can't happen */
834 assert( FALSE);
836 return;
839 /* --------------------------------------------------------------------
840 Returns the index 'i' of the first argument that IS an option, and
841 which begins with the label 's'. If there is none, -1.
842 We also mark that option as done with, i.e. we cross it out.
843 -------------------------------------------------------------------- */
844 int findoption( int argcount, char *args[], char *s)
846 int i;
848 if (test_usage)
849 printf("Checking for option -%s\n", s);
851 for (i=1; i<argcount; i++)
853 if (isoptionchar (args[i][0]) &&
854 strncmp( args[i] + 1, s, strlen( s)) == 0)
856 args[i][0] = '\0';
857 return i;
860 return -1;
863 /* --------------------------------------------------------------------
864 Finishes off the .WAV header (if any) and exits correctly and formerly.
865 -------------------------------------------------------------------- */
866 int myexit (int value)
868 switch (value)
870 case 0:
871 if (wavout)
872 makewavheader(); /* Writes a fully informed .WAV header */
873 chat ("Success!\n");
874 break;
875 default:
876 chat ("Failure.\n");
877 break;
879 exit (value);
882 /* --------------------------------------------------------------------
883 Reads the stated input file bufferwise, calls the function 'work'
884 with the proper values, and writes the result to the stated output file.
885 Return value: TRUE on success, FALSE otherwise.
886 -------------------------------------------------------------------- */
887 int workloop( FILE *theinfile, FILE *theoutfile,
888 int (*work)( short *buffer, int length) )
890 short *buffer;
891 int length, nowlength;
893 length = BUFFSIZE;
894 if ((buffer = malloc( sizeof(short) * length)) == NULL)
895 fatalperror ("");
896 while (TRUE)
898 nowlength = fread(buffer, sizeof(short), length, theinfile);
899 if (ferror( theinfile) != 0)
900 fatalperror("Error reading input file");
901 if (nowlength == 0) /* Reached end of input file */
902 break;
903 /* Call the routine that does the work */
904 if (!work (buffer, nowlength)) /* On error, stop. */
905 return FALSE;
906 fwrite(buffer, sizeof(short), nowlength, theoutfile);
907 if (ferror( theoutfile) != 0)
908 fatalperror("Error writing to output file");
910 return TRUE; /* Input file done with, no errors. */
913 int chat( const char *format, ...)
915 va_list ap;
916 int result = 0;
918 if (verboselevel > 5)
920 va_start( ap, format);
921 result = vfprintf( stderr, format, ap);
922 va_end( ap);
924 return result;
928 int inform( const char *format, ...)
930 va_list ap;
931 int result = 0;
933 if (verboselevel > 1)
935 va_start( ap, format);
936 result = vfprintf( stderr, format, ap);
937 va_end( ap);
939 return result;
942 int error( const char *format, ...)
944 va_list ap;
945 int result;
947 va_start( ap, format);
948 result = vfprintf( stderr, format, ap);
949 va_end( ap);
950 return result;
953 void fatalerror( const char *format, ...)
955 va_list ap;
957 va_start( ap, format);
958 vfprintf( stderr, format, ap);
959 va_end( ap);
960 myexit(1);
963 void fatalperror( const char *string)
965 perror( string);
966 myexit( 1);
969 int say( const char *format, ...)
971 va_list ap;
972 int result;
974 va_start( ap, format);
975 result = vfprintf( stdout, format, ap);
976 va_end( ap);
977 return result;
981 char *malloccopy( char *string)
983 char *result;
985 result = malloc( strlen( string) + 1);
986 if (result != NULL)
987 strcpy( result, string);
988 return result;
992 char *mallocconcat( char *one, char *two)
994 char *result;
996 result = malloc( strlen( one) + strlen( two) + 1);
997 if (result != NULL)
999 strcpy( result, one);
1000 strcat( result, two);
1002 return result;
1005 double double2db( double value)
1007 if (value < 0)
1008 value = -value;
1009 return 6.0 * log( value / 32767) / log( 2);
1012 void readawaysamples( FILE *in, size_t size)
1014 short *buffer;
1015 int samplesread, count;
1017 buffer = malloc( sizeof( *buffer) * BUFFSIZE);
1018 if (buffer == NULL) fatalperror("Couldn't allocate buffer");
1020 while (size > 0)
1022 if (size > BUFFSIZE)
1023 count = BUFFSIZE;
1024 else
1025 count = size;
1027 samplesread = fread( buffer, sizeof(*buffer), count, in);
1028 if (ferror( in) != 0)
1029 fatalperror("Error reading input file");
1030 size -= samplesread;
1032 free( buffer);