29 unsigned short samplewidth;
30 unsigned short channels;
34 char *infilename, *outfilename;
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"
58 int getremainingfilelength( FILE *anyin,
long *result)
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;
68 (*result) /= samplewidth;
69 if (fseek(anyin, i, SEEK_SET) == -1)
return FALSE;
76 void readpkheader( FILE *anyin)
78 unsigned short tempushort;
80 unsigned char blood[8];
82 for (i = 0; i < 11; i++)
84 if (!fread( &tempint, 4, 1, anyin)) {
87 printf(
"%d: %d, ", i, tempint);
90 if (!fread( blood, 1, 8, anyin)) {
93 for (i = 0; i < 8; i++)
94 printf(
"%d ", blood[i]);
96 for (i = 0; i < 8; i++)
98 for (x = 128; x > 0; x /= 2)
99 printf((blood[i] & x) == 0?
"0 ":
"1 ");
100 printf(i%4==3?
"\n":
"| ");
103 for (i = 0; i < 2; i++)
105 if (!fread( &tempint, 4, 1, anyin)) {
108 printf(
"%d: %d, ", i, tempint);
111 for (i = 0; i < 2; i++)
113 if (!fread( &tempushort, 2, 1, anyin)) {
116 printf(
"%d: %d, ", i, tempushort);
126 void readwavheader( FILE *anyin)
128 unsigned int tempuint, sf;
129 unsigned short tempushort, cn;
135 if (ftell(anyin) == -1)
138 chat(
"File not seekable: not checking for WAV-header.\n");
143 if (!fread(str, 1, 8, anyin)) {
147 if (strcmp(str,
"RIFF") != 0) nowav = TRUE;
149 if (!fread(str, 1, 8, anyin)) {
153 if (strcmp(str,
"WAVEfmt ") != 0) nowav = TRUE;
155 if (!fread(&tempuint, 4, 1, anyin)) {
158 if (tempuint != 16) nowav = TRUE;
160 if (!fread(&tempushort, 2, 1, anyin)) {
166 if (!fread(&cn, 2, 1, anyin)) {
169 if (cn != 1 && cn != 2) nowav = TRUE;
171 if (!fread(&sf, 4, 1, anyin)) {
175 if (!fread(&tempuint, 4, 1, anyin)) {
178 if (tempuint != sf * cn * 2) nowav = TRUE;
180 if (!fread(&tempushort, 2, 1, anyin)) {
183 if (tempushort != cn * 2) nowav = TRUE;
185 if (!fread(&tempushort, 2, 1, anyin)) {
188 if (tempushort != 16) nowav = TRUE;
189 if (!fread(str, 4, 1, anyin)) {
193 if (strcmp(str,
"data") != 0) nowav = TRUE;
194 if (!fread(&tempuint, 4, 1, anyin)) {
199 fseek(anyin, 0, SEEK_SET);
200 chat(
"File has no WAV header.\n");
204 samplefrequency = sf;
206 chat(
"Read WAV header: %d channels, samplefrequency %d.\n",
207 channels, samplefrequency);
219 void makewavheader(
void)
221 unsigned int tempuint, filelength;
222 unsigned short tempushort;
225 if (fseek(out, 0, SEEK_END) != -1)
227 filelength = ftell(out);
228 chat(
"filelength %d, ", filelength);
229 fseek(out, 0, SEEK_SET);
230 if (!fwrite(
"RIFF", 1, 4, out)) {
233 tempuint = filelength - 8;
234 if (!fwrite(&tempuint, 4, 1, out)) {
237 if (!fwrite(
"WAVEfmt ", 1, 8, out)) {
242 if (!fwrite(&tempuint, 4, 1, out)) {
247 if (!fwrite(&tempushort, 2, 1, out)) {
250 chat(
"%d channels\n", channels);
251 if (!fwrite(&channels, 2, 1, out)) {
254 chat(
"samplefrequency %d\n", samplefrequency);
255 if (!fwrite(&samplefrequency, 4, 1, out)) {
259 tempuint = channels * samplefrequency * 2;
260 if (!fwrite(&tempuint, 4, 1, out)) {
264 tempushort = 2 * channels;
265 if (!fwrite(&tempushort, 2, 1, out)) {
270 if (!fwrite(&tempushort, 2, 1, out)) {
273 if (!fwrite(
"data", 4, 1, out)) {
276 tempuint = filelength - 44;
277 if (!fwrite(&tempuint, 4, 1, out)) {
287 static void statistics(
void)
291 temp = time(NULL) - stopwatch;
294 inform (
"\nTime: %d seconds\n", temp);
298 inform (
"\nTime: 1 second\n");
307 void startstopwatch(
void)
309 stopwatch = time(NULL);
319 int isoptionchar (
char coal)
332 int parsetimearg(
int argcount,
char *args[],
char *
string,
int *result)
336 if ((i = findoption( argcount, args,
string)) > 0)
338 if (parsetime(args[i] + 1 + strlen(
string), result))
340 argerrornum(args[i]+1, ME_NOTIME);
352 int parsetime(
char *
string,
int *result)
358 k = sscanf(
string,
"%30lf%1c%1c%1c", &temp, &m, &s, &end);
361 case 0:
case EOF:
case 4:
368 *result = temp * samplefrequency;
373 if (m ==
'm' && s ==
's')
374 *result = temp * samplefrequency / 1000;
375 else if (m ==
'H' && s ==
'z')
376 *result = samplefrequency / temp;
381 argerrornum(NULL, ME_THISCANTHAPPEN);
393 int parsefreq(
char *
string,
double *result)
399 k = sscanf(
string,
"%30lf%1c%1c%1c", &temp, &m, &s, &end);
402 case 0:
case EOF:
case 2:
case 4:
408 if (m ==
'H' && s ==
'z')
409 *result = samplefrequency / temp;
414 argerrornum(NULL, ME_THISCANTHAPPEN);
419 char *parsefilearg(
int argcount,
char *args[])
424 for (i = 1; i < argcount; i++)
426 if (args[i][0] !=
'\0' &&
427 (!isoptionchar (args[i][0]) || args[i][1] ==
'\0' ))
434 result = malloc( strlen( args[i]) + 1);
436 fatalperror(
"Couldn't allocate memory for filename\n");
437 strcpy( result, args[i]);
445 int parseswitch(
char *found,
char *wanted)
447 if (strncmp( found, wanted, strlen( wanted)) == 0)
449 if (found[strlen( wanted)] ==
'\0')
452 argerrornum( found, ME_NOSWITCH);
457 int parseswitcharg(
int argcount,
char *args[],
char *
string)
461 if ((i = findoption( argcount, args,
string)) > 0)
463 if (args[i][strlen(
string) + 1] ==
'\0')
466 argerrornum( args[i] + 1, ME_NOSWITCH);
471 int parseintarg(
int argcount,
char *args[],
char *
string,
int *result)
476 if ((i = findoption( argcount, args,
string)) > 0)
478 switch (sscanf(args[i] + 1 + strlen(
string),
479 "%30d%1c", &temp, &c))
481 case 0:
case EOF:
case 2:
482 argerrornum(args[i]+1, ME_NOINT);
488 say(
"frame.c: This can't happen\n");
505 int parsedoublearg(
int argcount,
char *args[],
char *
string,
double *result)
511 if ((i = findoption( argcount, args,
string)) > 0)
513 switch (sscanf(args[i] + 1 + strlen(
string),
"%30lf%1c", &temp, &end))
515 case 0:
case EOF:
case 2:
516 argerrornum(args[i]+1, ME_NODOUBLE);
522 say(
"frame.c: This can't happen\n");
539 int parsevolarg(
int argcount,
char *args[],
char *
string,
double *result)
543 int i, weird = FALSE;
545 if ((i = findoption( argcount, args,
string)) > 0)
547 switch (sscanf(args[i] + 1 + strlen(
string),
548 "%30lf%1c%1c%1c", &vol, &sbd, &sbb, &end))
550 case 0:
case EOF:
case 4:
563 if (sbd ==
'd' && sbb ==
'b')
564 *result = pow(2, vol / 6.02);
569 say(
"frame.c: This can't happen.\n");
572 argerrornum( args[i] + 1, ME_NOVOL);
590 int parsevolume(
char *s,
double *result)
596 k = sscanf(s,
"%30lf%1c%1c%1c", result, &sbd, &sbb, &end);
611 if (sbd !=
'd' || sbb !=
'b')
613 (*result) = pow(2, (*result) / 6.02);
616 say(
"parsevolume: This can't happen (%d).\n", k);
625 void argerror(
char *s)
627 error (
"Error parsing command line. Unrecognized option:\n\t-%s\n", s);
628 fatalerror(
"\nTry --help for help.\n");
635 void argerrornum(
char *s, Errornum code)
639 if (code == ME_TOOMANYFILES)
641 error(
"Too many files on command line: '%s'.\n", s);
646 error (
"Error parsing option -%s:\n\t", s);
650 message =
"Integer expected";
653 message =
"Floating point number expected";
656 message =
"Time argument expected";
659 message =
"Volume argument expected";
662 message =
"Garbage after switch-type option";
664 case ME_HEADERONTEXTFILE:
665 message =
"Option -h is not useful for text-output";
668 message =
"No input file specified";
671 message =
"No output file specified";
674 message =
"No input/output file specified";
677 message =
"Standard in not supported here";
680 message =
"Standard out not supported here";
683 message =
"Standard in/out not supported here";
685 case ME_NOTENOUGHFILES:
686 message =
"Not enough files specified";
688 case ME_THISCANTHAPPEN:
689 fatalerror(
"\nThis can't happen. Report this as a bug\n");
692 error(
"Error code %d not implemented. Fix me!\n", code);
693 message =
"Error message not implemented. Fix me!";
695 error(
"%s\n", message);
697 fatalerror(
"\nTry --help for help.\n");
704 void argerrortxt(
char *s,
char *message)
707 error (
"Error parsing option -%s:\n\t", s);
709 error (
"Error parsing command line:\n\t");
710 error (
"%s\n", message);
711 fatalerror(
"\nTry --help for help.\n");
717 void checknoargs(
int argcount,
char *args[])
719 int i, errorcount = 0;
721 for (i = 1; i < argcount; i++)
723 if (args[i][0] !=
'\0')
727 error(
"The following arguments were not recognized:\n");
728 error(
"\t%s\n", args[i]);
732 fatalerror(
"\nTry --help for help.\n");
744 void parseargs(
int argcount,
char *args[],
int fileswitch)
749 if ((fileswitch & 1) != 0)
751 if ((fileswitch & 4) != 0)
755 samplefrequency = DEFAULTFREQ;
762 test_usage = parseswitcharg( argcount, args,
"-test-usage");
763 if (parseswitcharg( argcount, args,
"-help"))
765 printf(
"%s%s", usage, standardusage);
768 if (parseswitcharg( argcount, args,
"-version"))
770 printf(
"%s\n(%s)\n", version, standardversion);
776 while (parseswitcharg( argcount, args,
"V"))
778 while (parseswitcharg( argcount, args,
"Q"))
783 if ((fileswitch & 1) != 0)
785 infilename = parsefilearg( argcount, args);
786 if (infilename == NULL)
787 argerrornum( NULL, ME_NOINFILE);
788 if (strcmp( infilename,
"-") == 0)
790 infilename =
"<stdin>";
792 if ((fileswitch & 2) != 0)
797 if ((fileswitch & 2) == 0)
798 in = fopen(infilename,
"rt");
800 if ((in = fopen(infilename,
"rb")) != NULL)
804 fatalerror(
"Error opening input file '%s': %s\n", infilename,strerror(errno));
806 inform(
"Using file '%s' as input\n", infilename);
808 if ((fileswitch & 4) != 0)
810 outfilename = parsefilearg( argcount, args);
811 if (outfilename == NULL)
812 argerrornum( NULL, ME_NOOUTFILE);
813 if (strcmp( outfilename,
"-") == 0)
815 outfilename =
"<stdout>";
821 if ((fileswitch & 8) == 0)
822 out = fopen(outfilename,
"wt");
824 out = fopen(outfilename,
"wb");
827 fatalerror(
"Error opening output file '%s': %s\n", outfilename,strerror(errno));
829 inform(
"Using file '%s' as output\n", outfilename);
831 if ((fileswitch & 32) != 0)
833 assert (in == NULL && out == NULL);
834 infilename = outfilename = parsefilearg( argcount, args);
835 if (outfilename == NULL)
836 argerrornum( NULL, ME_NOIOFILE);
837 if (strcmp( infilename,
"-") == 0)
838 argerrornum( infilename, ME_NOSTDIN);
839 inform(
"Using file '%s' as input/output\n", outfilename);
840 in = out = fopen(outfilename,
"r+");
842 fatalerror(
"Error opening input/output file '%s': %s\n", outfilename,strerror(errno));
846 if ((fileswitch & 16) == 0)
848 if ((filename = parsefilearg( argcount, args)) != NULL)
849 argerrornum( filename, ME_TOOMANYFILES);
855 parseintarg( argcount, args,
"f", &samplefrequency);
856 wavout = parseswitcharg( argcount, args,
"h");
857 if (parseintarg( argcount, args,
"w", &tempint))
860 argerrortxt(NULL,
"Option -w is only valid "
861 "with value 16. Sorry.");
863 samplewidth = tempint;
865 if (parseintarg( argcount, args,
"c", &tempint))
867 if (tempint != 1 && tempint != 2)
868 argerrortxt(NULL,
"Option -c is only valid "
869 "with values 1 or 2. Sorry.");
877 switch (fileswitch & (12))
880 argerrornum( NULL, ME_HEADERONTEXTFILE);
900 int findoption(
int argcount,
char *args[],
char *s)
905 printf(
"Checking for option -%s\n", s);
907 for (i=1; i<argcount; i++)
909 if (isoptionchar (args[i][0]) &&
910 strncmp( args[i] + 1, s, strlen( s)) == 0)
922 int myexit (
int value)
943 int workloop( FILE *theinfile, FILE *theoutfile,
944 int (*work)(
short *buffer,
int length) )
947 int length, nowlength;
950 if ((buffer = malloc(
sizeof(
short) * length)) == NULL)
954 nowlength = fread(buffer,
sizeof(
short), length, theinfile);
955 if (ferror( theinfile) != 0)
956 fatalperror(
"Error reading input file");
960 if (!work (buffer, nowlength))
962 if (!fwrite(buffer,
sizeof(
short), nowlength, theoutfile)) {
965 if (ferror( theoutfile) != 0)
966 fatalperror(
"Error writing to output file");
971 int __attribute__((format(printf,1,2))) chat( const
char *format, ...)
976 if (verboselevel > 5)
978 va_start( ap, format);
979 result = vfprintf( stderr, format, ap);
985 int __attribute__((format(printf,1,2))) inform( const
char *format, ...)
990 if (verboselevel > 1)
992 va_start( ap, format);
993 result = vfprintf( stderr, format, ap);
999 int __attribute__((format(printf,1,2))) error( const
char *format, ...)
1004 va_start( ap, format);
1005 result = vfprintf( stderr, format, ap);
1010 void __attribute__((format(printf,1,2))) fatalerror( const
char *format, ...)
1014 va_start( ap, format);
1015 vfprintf( stderr, format, ap);
1020 void fatalperror(
const char *
string)
1026 int __attribute__((format(printf,1,2))) say( const
char *format, ...)
1031 va_start( ap, format);
1032 result = vfprintf( stdout, format, ap);
1038 char *malloccopy(
char *
string)
1042 result = malloc( strlen(
string) + 1);
1044 strcpy( result,
string);
1049 char *mallocconcat(
char *one,
char *two)
1053 result = malloc( strlen( one) + strlen( two) + 1);
1056 strcpy( result, one);
1057 strcat( result, two);
1062 double double2db(
double value)
1066 return 6.0 * log( value / 32767) / log( 2);
1069 void readawaysamples( FILE *input,
size_t size)
1072 int samplesread, count;
1074 buffer = malloc(
sizeof( *buffer) * BUFFSIZE);
1075 if (buffer == NULL) fatalperror(
"Couldn't allocate buffer");
1079 if (size > BUFFSIZE)
1084 samplesread = fread( buffer,
sizeof(*buffer), count, input);
1085 if (ferror( input) != 0)
1086 fatalperror(
"Error reading input file");
1087 size -= samplesread;
Time-related functions and macros.