initial import
[ICEs.git] / bfin-gc-sections / asterisk.c.orig
1 /****************************************************************************
2 *
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.
6 *
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
11 *
12 ****************************************************************************/
13 /****************************************************************************
14 * These are useful functions that all DSP programs might find handy
15 ****************************************************************************/
16
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 /****************************************************************************
26 *
27 * Programs for processing sound files in raw- or WAV-format.
28 * -- Useful functions for parsing command line options and
29 * issuing errors, warnings, and chit chat.
30 *
31 * Name: frame.h
32 * Version: see frame.c
33 * Author: Mark Roberts <mark@manumark.de>
34 *
35 ****************************************************************************/
36 /****************************************************************************
37 * These are useful functions that all DSP programs might find handy
38 ****************************************************************************/
39
40 #ifndef ASDF
41 #define ASDF
42
43 /* fileswitch for parseargs:
44
45 The following are masks for several different ways of opening files.
46 --------------------------------------------------------------------
47 Bit 0: Open infile?
48 Bit 1: Open infile as binary (as opposed to text)
49 Bit 2: Open outfile?
50 Bit 3: Open outfile as binary (as opposed to text)
51 Bit 4: Do not complain about too many file arguments
52 Bit 5: Open one file for input AND output, binary.
53 */
54 #define INTEXT (1+0)
55 #define INBIN (1+2)
56 #define OUTTEXT (4)
57 #define OUTBIN (4+8)
58 #define NOFILES (0)
59 #define NOCOMPLAIN (16)
60 #define IOBIN (32)
61
62 #ifndef FALSE
63 #define FALSE (0==1)
64 #define TRUE (0==0)
65 #endif
66
67 extern int samplefrequency;
68 extern unsigned short samplewidth;
69 extern unsigned short channels;
70 extern int wavout; /* TRUE iff out file is .WAV file */
71 extern int iswav; /* TRUE iff in file was found to be a .WAV file */
72 extern FILE *in, *out;
73 extern char *infilename, *outfilename;
74 extern int verboselevel;
75 extern char *version; /* String to be issued as version string. Should
76 be set by application. */
77 extern char *usage; /* String to be issued as usage string. Should be
78 set by application. */
79
80 #define DEFAULTFREQ 44100
81 #define BUFFSIZE 50000 /* How many samples to read in one go (preferred) */
82 #define MINBUFFSIZE 5000 /* How many samples to read in one go (minimum) */
83
84 /*************************************************
85 * Types of errors handled by argerrornum() *
86 *************************************************/
87 typedef enum
88 {
89 ME_NOINT,
90 ME_NODOUBLE,
91 ME_NOTIME,
92 ME_NOVOL,
93 ME_NOSWITCH,
94 ME_TOOMANYFILES,
95 ME_HEADERONTEXTFILE,
96 ME_NOINFILE,
97 ME_NOOUTFILE,
98 ME_NOIOFILE,
99 ME_NOSTDIN,
100 ME_NOSTDOUT,
101 ME_NOSTDIO,
102 ME_NOTENOUGHFILES,
103 ME_THISCANTHAPPEN
104 } Errornum;
105
106
107 /* -----------------------------------------------------------------------
108 Create memory and copy 'string', returning a pointer to the copy.
109 NULL is returned if malloc fails.
110 -----------------------------------------------------------------------*/
111 extern char *malloccopy( char *string);
112
113 /* -----------------------------------------------------------------------
114 Start the stopwatch and make sure the user is informed at end of program.
115 -----------------------------------------------------------------------*/
116 extern void startstopwatch(void);
117
118 /* -----------------------------------------------------------------------
119 Writes the number of samples to result that are yet to be read from anyin.
120 I.e. the number of remaining bytes is divided by the number of bytes per
121 sample value, but not by the number of channels.
122 Return values are TRUE on success, FALSE on failure.
123 -----------------------------------------------------------------------*/
124 extern int getremainingfilelength( FILE *anyin, long *result);
125
126 /* -----------------------------------------------------------------------
127 Read a .pk-header from 'anyin' and printf the entries.
128 -----------------------------------------------------------------------*/
129 void readpkheader( FILE *anyin);
130
131 /* -----------------------------------------------------------------------
132 Read a .WAV header from 'anyin'.
133 If it is recognised, the data is used.
134 Otherwise, we assume it's PCM-data and ignore the header.
135 The global variable 'iswav' is set on success, otherwise cleared.
136 -----------------------------------------------------------------------*/
137 extern void readwavheader( FILE *anyin);
138
139 /* -----------------------------------------------------------------------
140 Write a .WAV header to 'out'.
141 The filepointer is placed at the end of 'out' before operation.
142 This should be called before any data is
143 written, and again, when ALL the data has been written.
144 First time, this positions the file pointer correctly; second time, the
145 missing data can be inserted that wasn't known the first time round.
146 -----------------------------------------------------------------------*/
147 extern void makewavheader( void);
148
149 /* --------------------------------------------------------------------
150 Tests the character 'coal' for being a command line option character,
151 momentarrily '/' or '-'.
152 -------------------------------------------------------------------- */
153 extern int isoptionchar (char coal);
154
155 /* -----------------------------------------------------------------------
156 Reads through the arguments on the lookout for an option starting
157 with 'string'. The rest of the option is read as a time and passed
158 to *result, where the result is meant to mean 'number of samples' in
159 that time.
160 On failure, *result is unchanged.
161 return value is TRUE on success, FALSE otherwise.
162 -----------------------------------------------------------------------*/
163 extern int parsetimearg( int argcount, char *args[], char *string,
164 int *result);
165
166 /* -----------------------------------------------------------------------
167 The string argument is read as a time and passed to *result, where
168 the result is meant to mean 'number of samples' in that time. On
169 failure, *result is unchanged.
170 return value is TRUE on success, FALSE otherwise.
171 -----------------------------------------------------------------------*/
172 int parsetime(char *string, int *result);
173
174 /* -----------------------------------------------------------------------
175 The string argument is read as a frequency and passed
176 to *result, where the result is meant to mean 'number of samples' in
177 one cycle of that frequency.
178 On failure, *result is unchanged.
179 return value is TRUE on success, FALSE otherwise.
180 -----------------------------------------------------------------------*/
181 int parsefreq(char *string, double *result);
182
183 /* --------------------------------------------------------------------
184 Reads through the arguments on the lookout for a switch -'string'.
185 return value is TRUE if one exists, FALSE otherwise.
186 If characters remain after the switch, a fatal error is issued.
187 -------------------------------------------------------------------- */
188 extern int parseswitcharg( int argcount, char *args[], char *string);
189
190 /* --------------------------------------------------------------------
191 Reads through the arguments on the lookout for an option starting
192 with 'string'. The rest of the option is read as an integer and
193 passed to &result.
194 On failure, &result is unchanged.
195 return value is TRUE on success, FALSE otherwise.
196 -------------------------------------------------------------------- */
197 extern int parseintarg( int argcount, char *args[], char *string,
198 int *result);
199
200 /* --------------------------------------------------------------------
201 Reads through the arguments on the lookout for a filename, i.e. anything
202 that does not start with the optionchar. The filename is copied to
203 newly allocated memory, a pointer to which is returned.
204 The argument is marked as used. Therefore repeated use of this function
205 will yield a complete list of filenames on the commandline.
206 If malloc() fails, the function does not return.
207 -------------------------------------------------------------------- */
208 extern char *parsefilearg( int argcount, char *args[]);
209
210 /* --------------------------------------------------------------------
211 Reads through the arguments on the lookout for an option starting
212 with 'string'. The rest of the option is read as a double and
213 passed to *result.
214 On failure, *result is unchanged.
215 return value is TRUE on success, FALSE otherwise.
216 -------------------------------------------------------------------- */
217 extern int parsedoublearg( int argcount, char *args[], char *string,
218 double *result);
219
220 /* --------------------------------------------------------------------
221 Reads through the arguments on the lookout for an option starting
222 with 'string'. The rest of the option is read as a volume, i.e.
223 absolute, percent or db. The result is passed to *result.
224 On failure, *result is unchanged.
225 -------------------------------------------------------------------- */
226 extern int parsevolarg( int argcount, char *args[], char *string,
227 double *result);
228
229 /* --------------------------------------------------------------------
230 Reads the specified string and interprets it as a volume. The string
231 would be of the form 1.8 or 180% or 5db.
232 On success, the return value is the relative volume, i.e. 1.8
233 On failure, -1 is returned.
234 -------------------------------------------------------------------- */
235 extern int parsevolume(char *s, double *result);
236
237 /* --------------------------------------------------------------------
238 Reads through the arguments on the lookout for a switch -'string'.
239 return value is TRUE if one exists, FALSE otherwise.
240 If characters remain after the switch, a fatal error is issued.
241 -------------------------------------------------------------------- */
242 extern int parseswitch( char *found, char *wanted);
243
244 /* --------------------------------------------------------------------
245 Reports an error due to parsing the string 's' encountered on the
246 command line.
247 -------------------------------------------------------------------- */
248 extern void argerror(char *s);
249
250 /* --------------------------------------------------------------------
251 Reports an error due to parsing the string 's' encountered on the
252 command line. 'code' indicates the type of error.
253 -------------------------------------------------------------------- */
254 extern void argerrornum(char *s, Errornum code);
255
256 /* --------------------------------------------------------------------
257 Reports an error due to parsing the string 's' encountered on the
258 command line. 'message' explains the type of error.
259 -------------------------------------------------------------------- */
260 extern void argerrortxt(char *s, char *message);
261
262 /* --------------------------------------------------------------------
263 Check for any remaining arguments and complain about their existence.
264 If arguments are found, this function does not return.
265 -------------------------------------------------------------------- */
266 extern void checknoargs( int argcount, char *args[]);
267
268 /* --------------------------------------------------------------------
269 Parses the command line arguments as represented by the function
270 arguments. Sets the global variables 'in', 'out', 'samplefrequency'
271 and 'samplewidth' accordingly.
272 According to 'fileswitch', in and out files are opened or not. See
273 above for an explanation of 'fileswitch'.
274 -------------------------------------------------------------------- */
275 extern void parseargs( int argcount, char *args[], int fileswitch);
276
277 /* --------------------------------------------------------------------
278 Returns the index 'i' of the first argument that IS an option, and
279 which begins with the label 's'. If there is none, -1.
280 We also mark that option as done with, i.e. we cross it out.
281 -------------------------------------------------------------------- */
282 extern int findoption( int argcount, char *args[], char *s);
283
284 /* --------------------------------------------------------------------
285 Finishes off the .WAV header (if any) and exits correctly and formerly.
286 -------------------------------------------------------------------- */
287 extern int myexit (int value);
288
289 /* --------------------------------------------------------------------
290 Reads the stated input file bufferwise, calls the function 'work'
291 with the proper values, and writes the result to the stated output file.
292 Return value: TRUE on success, FALSE otherwise.
293 -------------------------------------------------------------------- */
294 extern int workloop( FILE *theinfile, FILE *theoutfile,
295 int (*work)( short *buffer, int length) );
296
297 /* --------------------------------------------------------------------
298 Five functions for printing to stderr. Depending on the level of verbose,
299 output may be supressed. fatalerror() is like error() but does not return.
300 fatalperror() is like the standard function perror() but does not return.
301 -------------------------------------------------------------------- */
302 extern int chat( const char *format, ...);
303 extern int inform( const char *format, ...);
304 extern int error( const char *format, ...);
305 extern void fatalerror( const char *format, ...);
306 extern void fatalperror( const char *string);
307
308 /* --------------------------------------------------------------------
309 And one functions for printing to stdout.
310 -------------------------------------------------------------------- */
311 extern int say( const char *format, ...);
312
313 /* --------------------------------------------------------------------
314 Allocate memory for it and return a pointer to a string made up of
315 the two argument strings.
316 -------------------------------------------------------------------- */
317 extern char *mallocconcat( char *one, char *two);
318
319 /* --------------------------------------------------------------------
320 Convert a sample value to decibel.
321 -------------------------------------------------------------------- */
322 extern double double2db( double value);
323
324 /* --------------------------------------------------------------------
325 Read 'size' samples from file 'in' and lose them.
326 -------------------------------------------------------------------- */
327 extern void readawaysamples( FILE *in, size_t size);
328
329 #endif
330
331 time_t stopwatch; /* will hold time at start of calculation */
332 int samplefrequency;
333 unsigned short samplewidth;
334 unsigned short channels;
335 int wavout; /* TRUE iff out file should be a .WAV file */
336 int iswav; /* TRUE iff in file was found to be a .WAV file */
337 FILE *in, *out;
338 char *infilename, *outfilename;
339 int verboselevel;
340 char *version = "";
341 char *usage = "";
342 static int test_usage;
343
344 static char *standardversion = "frame version 1.3, June 13th 2001";
345 static char *standardusage =
346 "\nOptions common to all mark-dsp programs:\n"
347
348 "-h \t\t create a WAV-header on output files.\n"
349 "-c#\t\t set number of channels to # (1 or 2). Default: like input.\n"
350 "-w#\t\t set number of bits per sample (width) to # (only 16)\n"
351 "-f#\t\t set sample frequency to #. Default: like input.\n"
352 "-V \t\t verbose: talk a lot.\n"
353 "-Q \t\t quiet: talk as little as possible.\n\n"
354 "In most cases, a filename of '-' means stdin or stdout.\n\n"
355 "Bug-reports: mark@manumark.de\n"
356 ;
357
358 /* -----------------------------------------------------------------------
359 Writes the number of samples to result that are yet to be read from anyin.
360 Return values are TRUE on success, FALSE on failure.
361 -----------------------------------------------------------------------*/
362 int getremainingfilelength( FILE *anyin, long *result)
363 {
364 long i;
365
366 i = ftell (anyin);
367 if (i == -1) return FALSE;
368 if (fseek (anyin, 0, SEEK_END) == -1) return FALSE;
369 *result = ftell (anyin);
370 if (*result == -1) return FALSE;
371 (*result) -= i;
372 (*result) /= samplewidth;
373 if (fseek (anyin, i, SEEK_SET) == -1) return FALSE;
374 return TRUE;
375 }
376
377 /* -----------------------------------------------------------------------
378 Read a .pk-header from 'anyin'.
379 -----------------------------------------------------------------------*/
380 void readpkheader( FILE *anyin)
381 {
382 unsigned short tempushort;
383 int tempint, i, x;
384 unsigned char blood[8];
385
386 for (i = 0; i < 11; i++)
387 {
388 fread( &tempint, 4, 1, anyin);
389 printf( "%d: %d, ", i, tempint);
390 }
391 printf( "\n");
392 fread( blood, 1, 8, anyin);
393 for (i = 0; i < 8; i++)
394 printf( "%d ", blood[i]);
395 printf( "\n");
396 for (i = 0; i < 8; i++)
397 {
398 for (x = 128; x > 0; x /= 2)
399 printf((blood[i] & x) == 0? "0 ":"1 ");
400 printf(i%4==3? "\n":"| ");
401 }
402 printf( "\n");
403 for (i = 0; i < 2; i++)
404 {
405 fread( &tempint, 4, 1, anyin);
406 printf( "%d: %d, ", i, tempint);
407 }
408 printf( "\n");
409 for (i = 0; i < 2; i++)
410 {
411 fread( &tempushort, 2, 1, anyin);
412 printf( "%d: %d, ", i, tempushort);
413 }
414 printf( "\n");
415 }
416
417
418
419 /* -----------------------------------------------------------------------
420 Read a .WAV header from 'anyin'. See header for details.
421 -----------------------------------------------------------------------*/
422 void readwavheader( FILE *anyin)
423 {
424 unsigned int tempuint, sf;
425 unsigned short tempushort, cn;
426 char str[9];
427 int nowav = FALSE;
428
429 iswav = FALSE;
430
431 if (ftell(anyin) == -1) /* If we cannot seek this file */
432 {
433 nowav = TRUE; /* -> Pretend this is no wav-file */
434 chat("File not seekable: not checking for WAV-header.\n");
435 }
436 else
437 {
438 /* Expect four bytes "RIFF" and four bytes filelength */
439 fread (str, 1, 8, anyin); /* 0 */
440 str[4] = '\0';
441 if (strcmp(str, "RIFF") != 0) nowav = TRUE;
442 /* Expect eight bytes "WAVEfmt " */
443 fread (str, 1, 8, anyin); /* 8 */
444 str[8] = '\0';
445 if (strcmp(str, "WAVEfmt ") != 0) nowav = TRUE;
446 /* Expect length of fmt data, which should be 16 */
447 fread (&tempuint, 4, 1, anyin); /* 16 */
448 if (tempuint != 16) nowav = TRUE;
449 /* Expect format tag, which should be 1 for pcm */
450 fread (&tempushort, 2, 1, anyin); /* 20 */
451 if (tempushort != 1)
452 nowav = TRUE;
453 /* Expect number of channels */
454 fread (&cn, 2, 1, anyin); /* 20 */
455 if (cn != 1 && cn != 2) nowav = TRUE;
456 /* Read samplefrequency */
457 fread (&sf, 4, 1, anyin); /* 24 */
458 /* Read bytes per second: Should be samplefreq * channels * 2 */
459 fread (&tempuint, 4, 1, anyin); /* 28 */
460 if (tempuint != sf * cn * 2) nowav = TRUE;
461 /* read bytes per frame: Should be channels * 2 */
462 fread (&tempushort, 2, 1, anyin); /* 32 */
463 if (tempushort != cn * 2) nowav = TRUE;
464 /* Read bits per sample: Should be 16 */
465 fread (&tempushort, 2, 1, anyin); /* 34 */
466 if (tempushort != 16) nowav = TRUE;
467 fread (str, 4, 1, anyin); /* 36 */
468 str[4] = '\0';
469 if (strcmp(str, "data") != 0) nowav = TRUE;
470 fread (&tempuint, 4, 1, anyin); /* 40 */
471 if (nowav)
472 {
473 fseek (anyin, 0, SEEK_SET); /* Back to beginning of file */
474 chat("File has no WAV header.\n");
475 }
476 else
477 {
478 samplefrequency = sf;
479 channels = cn;
480 chat ("Read WAV header: %d channels, samplefrequency %d.\n",
481 channels, samplefrequency);
482 iswav = TRUE;
483 }
484 }
485 return;
486 }
487
488
489
490 /* -----------------------------------------------------------------------
491 Write a .WAV header to 'out'. See header for details.
492 -----------------------------------------------------------------------*/
493 void makewavheader( void)
494 {
495 unsigned int tempuint, filelength;
496 unsigned short tempushort;
497
498 /* If fseek fails, don't create the header. */
499 if (fseek (out, 0, SEEK_END) != -1)
500 {
501 filelength = ftell (out);
502 chat ("filelength %d, ", filelength);
503 fseek (out, 0, SEEK_SET);
504 fwrite ("RIFF", 1, 4, out); /* 0 */
505 tempuint = filelength - 8; fwrite (&tempuint, 4, 1, out); /* 4 */
506 fwrite ("WAVEfmt ", 1, 8, out); /* 8 */
507 /* length of fmt data 16 bytes */
508 tempuint = 16;
509 fwrite (&tempuint, 4, 1, out); /* 16 */
510 /* Format tag: 1 for pcm */
511 tempushort = 1;
512 fwrite (&tempushort, 2, 1, out); /* 20 */
513 chat ("%d channels\n", channels);
514 fwrite (&channels, 2, 1, out);
515 chat ("samplefrequency %d\n", samplefrequency);
516 fwrite (&samplefrequency, 4, 1, out); /* 24 */
517 /* Bytes per second */
518 tempuint = channels * samplefrequency * 2;
519 fwrite (&tempuint, 4, 1, out); /* 28 */
520 /* Block align */
521 tempushort = 2 * channels;
522 fwrite (&tempushort, 2, 1, out); /* 32 */
523 /* Bits per sample */
524 tempushort = 16;
525 fwrite (&tempushort, 2, 1, out); /* 34 */
526 fwrite ("data", 4, 1, out); /* 36 */
527 tempuint = filelength - 44; fwrite (&tempuint, 4, 1, out); /* 40 */
528 }
529 return;
530 }
531
532 /* -----------------------------------------------------------------------
533 After all is read and done, inform the inclined user of the elapsed time
534 -----------------------------------------------------------------------*/
535 static void statistics( void)
536 {
537 int temp;
538
539 temp = time(NULL) - stopwatch;
540 if (temp != 1)
541 {
542 inform ("\nTime: %d seconds\n", temp);
543 }
544 else
545 {
546 inform ("\nTime: 1 second\n");
547 }
548 return;
549 }
550
551
552 /* -----------------------------------------------------------------------
553 Start the stopwatch and make sure the user is informed at end of program.
554 -----------------------------------------------------------------------*/
555 void startstopwatch(void)
556 {
557 stopwatch = time(NULL); /* Remember time 'now' */
558 atexit(statistics); /* Call function statistics() at exit. */
559
560 return;
561 }
562
563 /* --------------------------------------------------------------------
564 Tests the character 'coal' for being a command line option character,
565 momentarrily '-'.
566 -------------------------------------------------------------------- */
567 int isoptionchar (char coal)
568 {
569 return (coal =='-');
570 }
571
572 /* -----------------------------------------------------------------------
573 Reads through the arguments on the lookout for an option starting
574 with 'string'. The rest of the option is read as a time and passed
575 to *result, where the result is meant to mean 'number of samples' in
576 that time.
577 On failure, *result is unchanged.
578 return value is TRUE on success, FALSE otherwise.
579 -----------------------------------------------------------------------*/
580 int parsetimearg( int argcount, char *args[], char *string, int *result)
581 {
582 int i;
583
584 if ((i = findoption( argcount, args, string)) > 0)
585 {
586 if (parsetime(args[i] + 1 + strlen( string), result))
587 return TRUE;
588 argerrornum(args[i]+1, ME_NOTIME);
589 }
590 return FALSE;
591 }
592
593 /* -----------------------------------------------------------------------
594 The string argument is read as a time and passed
595 to *result, where the result is meant to mean 'number of samples' in
596 that time.
597 On failure, *result is unchanged.
598 return value is TRUE on success, FALSE otherwise.
599 -----------------------------------------------------------------------*/
600 int parsetime(char *string, int *result)
601 {
602 int k;
603 double temp;
604 char m, s, end;
605
606 k = sscanf(string, "%lf%c%c%c", &temp, &m, &s, &end);
607 switch (k)
608 {
609 case 0: case EOF: case 4:
610 return FALSE;
611 case 1:
612 *result = temp;
613 break;
614 case 2:
615 if (m == 's')
616 *result = temp * samplefrequency;
617 else
618 return FALSE;
619 break;
620 case 3:
621 if (m == 'm' && s == 's')
622 *result = temp * samplefrequency / 1000;
623 else if (m == 'H' && s == 'z')
624 *result = samplefrequency / temp;
625 else
626 return FALSE;
627 break;
628 default:
629 argerrornum(NULL, ME_THISCANTHAPPEN);
630 }
631 return TRUE;
632 }
633
634 /* -----------------------------------------------------------------------
635 The string argument is read as a frequency and passed
636 to *result, where the result is meant to mean 'number of samples' in
637 one cycle of that frequency.
638 On failure, *result is unchanged.
639 return value is TRUE on success, FALSE otherwise.
640 -----------------------------------------------------------------------*/
641 int parsefreq(char *string, double *result)
642 {
643 int k;
644 double temp;
645 char m, s, end;
646
647 k = sscanf(string, "%lf%c%c%c", &temp, &m, &s, &end);
648 switch (k)
649 {
650 case 0: case EOF: case 2: case 4:
651 return FALSE;
652 case 1:
653 *result = temp;
654 break;
655 case 3:
656 if (m == 'H' && s == 'z')
657 *result = samplefrequency / temp;
658 else
659 return FALSE;
660 break;
661 default:
662 argerrornum(NULL, ME_THISCANTHAPPEN);
663 }
664 return TRUE;
665 }
666
667 char *parsefilearg( int argcount, char *args[])
668 {
669 int i;
670 char *result = NULL;
671
672 for (i = 1; i < argcount; i++)
673 {
674 if (args[i][0] != '\0' &&
675 (!isoptionchar (args[i][0]) || args[i][1] == '\0' ))
676 {
677 /*---------------------------------------------*
678 * The argument is a filename: *
679 * it is either no dash followed by something, *
680 * or it is a dash following by nothing. *
681 *---------------------------------------------*/
682 result = malloc( strlen( args[i]) + 1);
683 if (result == NULL)
684 fatalperror( "Couldn't allocate memory for filename\n");
685 strcpy( result, args[i]);
686 args[i][0] = '\0'; /* Mark as used up */
687 break;
688 }
689 }
690 return result;
691 }
692
693 int parseswitch( char *found, char *wanted)
694 {
695 if (strncmp( found, wanted, strlen( wanted)) == 0)
696 {
697 if (found[strlen( wanted)] == '\0')
698 return TRUE;
699 else
700 argerrornum( found, ME_NOSWITCH);
701 }
702 return FALSE;
703 }
704
705 int parseswitcharg( int argcount, char *args[], char *string)
706 {
707 int i;
708
709 if ((i = findoption( argcount, args, string)) > 0)
710 {
711 if (args[i][strlen( string) + 1] == '\0')
712 return TRUE;
713 else
714 argerrornum( args[i] + 1, ME_NOSWITCH);
715 }
716 return FALSE;
717 }
718
719 int parseintarg( int argcount, char *args[], char *string, int *result)
720 {
721 int i, temp;
722 char c;
723
724 if ((i = findoption( argcount, args, string)) > 0)
725 {
726 switch (sscanf(args[i] + 1 + strlen( string),
727 "%d%c", &temp, &c))
728 {
729 case 0: case EOF: case 2:
730 argerrornum(args[i]+1, ME_NOINT);
731 return FALSE;
732 case 1:
733 *result = temp;
734 break;
735 default:
736 say("frame.c: This can't happen\n");
737 }
738 return TRUE;
739 }
740 else
741 {
742 return FALSE;
743 }
744 }
745
746 /* --------------------------------------------------------------------
747 Reads through the arguments on the lookout for an option starting
748 with 'string'. The rest of the option is read as a double and
749 passed to *result.
750 On failure, *result is unchanged.
751 return value is TRUE on success, FALSE otherwise.
752 -------------------------------------------------------------------- */
753 int parsedoublearg( int argcount, char *args[], char *string, double *result)
754 {
755 int i;
756 double temp;
757 char end;
758
759 if ((i = findoption( argcount, args, string)) > 0)
760 {
761 switch (sscanf(args[i] + 1 + strlen( string), "%lf%c", &temp, &end))
762 {
763 case 0: case EOF: case 2:
764 argerrornum(args[i]+1, ME_NODOUBLE);
765 return FALSE;
766 case 1:
767 *result = temp;
768 break;
769 default:
770 say("frame.c: This can't happen\n");
771 }
772 return TRUE;
773 }
774 else
775 {
776 return FALSE;
777 }
778 }
779
780 /* --------------------------------------------------------------------
781 Reads through the arguments on the lookout for an option starting
782 with 'string'. The rest of the option is read as a volume, i.e.
783 absolute, percent or db. The result is passed to *result.
784 On failure, *result is unchanged.
785 return value is TRUE on success, FALSE otherwise.
786 -------------------------------------------------------------------- */
787 int parsevolarg( int argcount, char *args[], char *string, double *result)
788 {
789 double vol = 1.0;
790 char sbd, sbb, end;
791 int i, weird = FALSE;
792
793 if ((i = findoption( argcount, args, string)) > 0)
794 {
795 switch (sscanf(args[i] + 1 + strlen( string),
796 "%lf%c%c%c", &vol, &sbd, &sbb, &end))
797 {
798 case 0: case EOF: case 4:
799 weird = TRUE;
800 break; /* No number: error */
801 case 1:
802 *result = vol;
803 break;
804 case 2:
805 if (sbd == '%')
806 *result = vol / 100;
807 else
808 weird = TRUE; /* One char but no percent: error */
809 break;
810 case 3:
811 if (sbd =='d' && sbb == 'b')
812 *result = pow(2, vol / 6.02);
813 else
814 weird = TRUE; /* Two chars but not db: error */
815 break;
816 default:
817 say("frame.c: This can't happen.\n");
818 }
819 if (weird)
820 argerrornum( args[i] + 1, ME_NOVOL);
821 /* ("Weird option: couldn't parse volume '%s'\n", args[i]+2); */
822 return !weird;
823 }
824 else
825 {
826 return FALSE;
827 }
828 }
829
830
831 /* --------------------------------------------------------------------
832 Reads the specified string 's' and interprets it as a volume. The string
833 would be of the form 1.8 or 180% or 5db.
834 On success, the return value TRUE and *result is given result
835 (i.e. the relative volume, i.e. 1.8). On failure, FALSE is returned and
836 result is given value 1.0.
837 -------------------------------------------------------------------- */
838 int parsevolume(char *s, double *result)
839 {
840 int k;
841 char sbd, sbb, end;
842
843 *result = 1.0;
844 k = sscanf(s, "%lf%c%c%c", result, &sbd, &sbb, &end);
845 switch (k)
846 {
847 case 0:
848 case EOF:
849 case 4:
850 return FALSE;
851 case 1:
852 break;
853 case 2:
854 if (sbd != '%')
855 return FALSE;
856 (*result) /=100;
857 break;
858 case 3:
859 if (sbd !='d' || sbb != 'b')
860 return FALSE;
861 (*result) = pow(2, (*result) / 6.02);
862 break;
863 default:
864 say("parsevolume: This can't happen (%d).\n", k);
865 }
866 return TRUE;
867 }
868
869 /* --------------------------------------------------------------------
870 Reports an error due to parsing the string 's' encountered on the
871 command line.
872 -------------------------------------------------------------------- */
873 void argerror(char *s)
874 {
875 error ("Error parsing command line. Unrecognized option:\n\t-%s\n", s);
876 fatalerror("\nTry --help for help.\n");
877 }
878
879 /* --------------------------------------------------------------------
880 Reports an error due to parsing the string 's' encountered on the
881 command line. 'code' indicates the type of error.
882 -------------------------------------------------------------------- */
883 void argerrornum(char *s, Errornum code)
884 {
885 char *message;
886
887 if (code == ME_TOOMANYFILES)
888 {
889 error("Too many files on command line: '%s'.\n", s);
890 }
891 else
892 {
893 if (s != NULL)
894 error ("Error parsing option -%s:\n\t", s);
895 switch( code)
896 {
897 case ME_NOINT:
898 message = "Integer expected";
899 break;
900 case ME_NODOUBLE:
901 message = "Floating point number expected";
902 break;
903 case ME_NOTIME:
904 message = "Time argument expected";
905 break;
906 case ME_NOVOL:
907 message = "Volume argument expected";
908 break;
909 case ME_NOSWITCH:
910 message = "Garbage after switch-type option";
911 break;
912 case ME_HEADERONTEXTFILE:
913 message = "Option -h is not useful for text-output";
914 break;
915 case ME_NOINFILE:
916 message = "No input file specified";
917 break;
918 case ME_NOOUTFILE:
919 message = "No output file specified";
920 break;
921 case ME_NOIOFILE:
922 message = "No input/output file specified";
923 break;
924 case ME_NOSTDIN:
925 message = "Standard in not supported here";
926 break;
927 case ME_NOSTDOUT:
928 message = "Standard out not supported here";
929 break;
930 case ME_NOSTDIO:
931 message = "Standard in/out not supported here";
932 break;
933 case ME_NOTENOUGHFILES:
934 message = "Not enough files specified";
935 break;
936 case ME_THISCANTHAPPEN:
937 fatalerror("\nThis can't happen. Report this as a bug\n");
938 /* fatalerror does not return */
939 default:
940 error("Error code %d not implemented. Fix me!\n", code);
941 message = "Error message not implemented. Fix me!";
942 }
943 error("%s\n", message);
944 }
945 fatalerror("\nTry --help for help.\n");
946 }
947
948 /* --------------------------------------------------------------------
949 Reports an error due to parsing the string 's' encountered on the
950 command line. 'message' explains the type of error.
951 -------------------------------------------------------------------- */
952 void argerrortxt(char *s, char *message)
953 {
954 if (s != NULL)
955 error ("Error parsing option -%s:\n\t", s);
956 else
957 error ("Error parsing command line:\n\t");
958 error ("%s\n", message);
959 fatalerror("\nTry --help for help.\n");
960 }
961
962 /* --------------------------------------------------------------------
963 Check for any remaining arguments and complain about their existence
964 -------------------------------------------------------------------- */
965 void checknoargs( int argcount, char *args[])
966 {
967 int i, errorcount = 0;
968
969 for (i = 1; i < argcount; i++)
970 {
971 if (args[i][0] != '\0') /* An unused argument! */
972 {
973 errorcount++;
974 if (errorcount == 1)
975 error("The following arguments were not recognized:\n");
976 error("\t%s\n", args[i]);
977 }
978 }
979 if (errorcount > 0) /* Errors are fatal */
980 fatalerror("\nTry --help for help.\n");
981
982 return; /* No errors? Return. */
983 }
984
985 /* --------------------------------------------------------------------
986 Parses the command line arguments as represented by the function
987 arguments. Sets the global variables 'in', 'out', 'samplefrequency'
988 and 'samplewidth' accordingly. Also verboselevel.
989 The files 'in' and 'out' are even opened according to 'fileswitch'.
990 See headerfile for details
991 -------------------------------------------------------------------- */
992 void parseargs( int argcount, char *args[], int fileswitch)
993 {
994 char *filename;
995 int tempint;
996
997 if ((fileswitch & 1) != 0) /* If getting infile */
998 in = NULL;
999 if ((fileswitch & 4) != 0) /* If getting outfile */
1000 out = NULL;
1001 wavout = FALSE;
1002 verboselevel = 5;
1003 samplefrequency = DEFAULTFREQ;
1004 samplewidth = 2;
1005 channels = 1;
1006
1007 /*-----------------------------------------------*
1008 * First first check testcase, usage and version *
1009 *-----------------------------------------------*/
1010 test_usage = parseswitcharg( argcount, args, "-test-usage");
1011 if (parseswitcharg( argcount, args, "-help"))
1012 {
1013 printf("%s%s", usage, standardusage);
1014 exit(0);
1015 }
1016 if (parseswitcharg( argcount, args, "-version"))
1017 {
1018 printf("%s\n(%s)\n", version, standardversion);
1019 exit(0);
1020 }
1021 /*--------------------------------------*
1022 * Set verboselevel *
1023 *--------------------------------------*/
1024 while (parseswitcharg( argcount, args, "V"))
1025 verboselevel = 10;
1026 while (parseswitcharg( argcount, args, "Q"))
1027 verboselevel = 1;
1028 /*-------------------------------------------------*
1029 * Get filenames and open files *
1030 *-------------------------------------------------*/
1031 if ((fileswitch & 1) != 0) /* Infile wanted */
1032 {
1033 infilename = parsefilearg( argcount, args);
1034 if (infilename == NULL)
1035 argerrornum( NULL, ME_NOINFILE);
1036 if (strcmp( infilename, "-") == 0)
1037 {
1038 infilename = "<stdin>";
1039 in = stdin;
1040 if ((fileswitch & 2) != 0) /* Binfile wanted */
1041 readwavheader( in);
1042 }
1043 else
1044 {
1045 if ((fileswitch & 2) == 0) /* Textfile wanted */
1046 in = fopen(infilename, "rt");
1047 else /* Binfile wanted */
1048 if ((in = fopen(infilename, "rb")) != NULL)
1049 readwavheader( in);
1050 }
1051 if (in == NULL)
1052 fatalerror("Error opening input file '%s': %s\n", infilename,strerror(errno));
1053 else
1054 inform("Using file '%s' as input\n", infilename);
1055 }
1056 if ((fileswitch & 4) != 0) /* Outfile wanted */
1057 {
1058 outfilename = parsefilearg( argcount, args);
1059 if (outfilename == NULL)
1060 argerrornum( NULL, ME_NOOUTFILE);
1061 if (strcmp( outfilename, "-") == 0)
1062 {
1063 outfilename = "<stdout>";
1064 out = stdout;
1065 }
1066 else
1067 {
1068
1069 if ((fileswitch & 8) == 0) /* Textfile wanted */
1070 out = fopen(outfilename, "wt");
1071 else /* Binfile wanted */
1072 out = fopen(outfilename, "wb");
1073 }
1074 if (out == NULL)
1075 fatalerror("Error opening output file '%s': %s\n", outfilename,strerror(errno));
1076 else
1077 inform("Using file '%s' as output\n", outfilename);
1078 }
1079 if ((fileswitch & 32) != 0) /* In-/Outfile wanted */
1080 {
1081 assert (in == NULL && out == NULL);
1082 infilename = outfilename = parsefilearg( argcount, args);
1083 if (outfilename == NULL)
1084 argerrornum( NULL, ME_NOIOFILE);
1085 if (strcmp( infilename, "-") == 0)
1086 argerrornum( infilename, ME_NOSTDIN);
1087 inform("Using file '%s' as input/output\n", outfilename);
1088 in = out = fopen(outfilename, "r+");
1089 if (out == NULL)
1090 fatalerror("Error opening input/output file '%s': %s\n", outfilename,strerror(errno));
1091
1092 readwavheader( in);
1093 }
1094 if ((fileswitch & 16) == 0) /* No additional files wanted */
1095 {
1096 if ((filename = parsefilearg( argcount, args)) != NULL)
1097 argerrornum( filename, ME_TOOMANYFILES);
1098 }
1099
1100 /*-------------------------------------------------*
1101 * Set samplefrequency, width, wavout,
1102 *-------------------------------------------------*/
1103 parseintarg( argcount, args, "f", &samplefrequency);
1104 wavout = parseswitcharg( argcount, args, "h");
1105 if (parseintarg( argcount, args, "w", &tempint))
1106 {
1107 if (tempint != 16)
1108 argerrortxt(NULL, "Option -w is only valid "
1109 "with value 16. Sorry.");
1110 else
1111 samplewidth = tempint;
1112 }
1113 if (parseintarg( argcount, args, "c", &tempint))
1114 {
1115 if (tempint != 1 && tempint != 2)
1116 argerrortxt(NULL, "Option -c is only valid "
1117 "with values 1 or 2. Sorry.");
1118 else
1119 channels = tempint;
1120 }
1121 /*-------------------------------------------------*
1122 * Create WAV-header on output if wanted. *
1123 *-------------------------------------------------*/
1124 if (wavout)
1125 switch (fileswitch & (12))
1126 {
1127 case 4: /* User wants header on textfile */
1128 argerrornum( NULL, ME_HEADERONTEXTFILE);
1129 case 12: /* User wants header on binfile */
1130 makewavheader();
1131 break;
1132 case 0: /* User wants header, but there is no outfile */
1133 /* Problem: what about i/o-file, 32? You might want a header
1134 on that? Better ignore this case. */
1135 break;
1136 case 8: /* An application musn't ask for this */
1137 default: /* This can't happen */
1138 assert( FALSE);
1139 }
1140 return;
1141 }
1142
1143 /* --------------------------------------------------------------------
1144 Returns the index 'i' of the first argument that IS an option, and
1145 which begins with the label 's'. If there is none, -1.
1146 We also mark that option as done with, i.e. we cross it out.
1147 -------------------------------------------------------------------- */
1148 int findoption( int argcount, char *args[], char *s)
1149 {
1150 int i;
1151
1152 if (test_usage)
1153 printf("Checking for option -%s\n", s);
1154
1155 for (i=1; i<argcount; i++)
1156 {
1157 if (isoptionchar (args[i][0]) &&
1158 strncmp( args[i] + 1, s, strlen( s)) == 0)
1159 {
1160 args[i][0] = '\0';
1161 return i;
1162 }
1163 }
1164 return -1;
1165 }
1166
1167 /* --------------------------------------------------------------------
1168 Finishes off the .WAV header (if any) and exits correctly and formerly.
1169 -------------------------------------------------------------------- */
1170 int myexit (int value)
1171 {
1172 switch (value)
1173 {
1174 case 0:
1175 if (wavout)
1176 makewavheader(); /* Writes a fully informed .WAV header */
1177 chat ("Success!\n");
1178 break;
1179 default:
1180 chat ("Failure.\n");
1181 break;
1182 }
1183 exit (value);
1184 }
1185
1186 /* --------------------------------------------------------------------
1187 Reads the stated input file bufferwise, calls the function 'work'
1188 with the proper values, and writes the result to the stated output file.
1189 Return value: TRUE on success, FALSE otherwise.
1190 -------------------------------------------------------------------- */
1191 int workloop( FILE *theinfile, FILE *theoutfile,
1192 int (*work)( short *buffer, int length) )
1193 {
1194 short *buffer;
1195 int length, nowlength;
1196
1197 length = BUFFSIZE;
1198 if ((buffer = malloc( sizeof(short) * length)) == NULL)
1199 fatalperror ("");
1200 while (TRUE)
1201 {
1202 nowlength = fread(buffer, sizeof(short), length, theinfile);
1203 if (ferror( theinfile) != 0)
1204 fatalperror("Error reading input file");
1205 if (nowlength == 0) /* Reached end of input file */
1206 break;
1207 /* Call the routine that does the work */
1208 if (!work (buffer, nowlength)) /* On error, stop. */
1209 return FALSE;
1210 fwrite(buffer, sizeof(short), nowlength, theoutfile);
1211 if (ferror( theoutfile) != 0)
1212 fatalperror("Error writing to output file");
1213 }
1214 return TRUE; /* Input file done with, no errors. */
1215 }
1216
1217 int chat( const char *format, ...)
1218 {
1219 va_list ap;
1220 int result = 0;
1221
1222 if (verboselevel > 5)
1223 {
1224 va_start( ap, format);
1225 result = vfprintf( stderr, format, ap);
1226 va_end( ap);
1227 }
1228 return result;
1229 }
1230
1231
1232 int inform( const char *format, ...)
1233 {
1234 va_list ap;
1235 int result = 0;
1236
1237 if (verboselevel > 1)
1238 {
1239 va_start( ap, format);
1240 result = vfprintf( stderr, format, ap);
1241 va_end( ap);
1242 }
1243 return result;
1244 }
1245
1246 int error( const char *format, ...)
1247 {
1248 va_list ap;
1249 int result;
1250
1251 va_start( ap, format);
1252 result = vfprintf( stderr, format, ap);
1253 va_end( ap);
1254 return result;
1255 }
1256
1257 void fatalerror( const char *format, ...)
1258 {
1259 va_list ap;
1260
1261 va_start( ap, format);
1262 vfprintf( stderr, format, ap);
1263 va_end( ap);
1264 myexit(1);
1265 }
1266
1267 void fatalperror( const char *string)
1268 {
1269 perror( string);
1270 myexit( 1);
1271 }
1272
1273 int say( const char *format, ...)
1274 {
1275 va_list ap;
1276 int result;
1277
1278 va_start( ap, format);
1279 result = vfprintf( stdout, format, ap);
1280 va_end( ap);
1281 return result;
1282 }
1283
1284
1285 char *malloccopy( char *string)
1286 {
1287 char *result;
1288
1289 result = malloc( strlen( string) + 1);
1290 if (result != NULL)
1291 strcpy( result, string);
1292 return result;
1293 }
1294
1295
1296 char *mallocconcat( char *one, char *two)
1297 {
1298 char *result;
1299
1300 result = malloc( strlen( one) + strlen( two) + 1);
1301 if (result != NULL)
1302 {
1303 strcpy( result, one);
1304 strcat( result, two);
1305 }
1306 return result;
1307 }
1308
1309 double double2db( double value)
1310 {
1311 if (value < 0)
1312 value = -value;
1313 return 6.0 * log( value / 32767) / log( 2);
1314 }
1315
1316 void readawaysamples( FILE *in, size_t size)
1317 {
1318 short *buffer;
1319 int samplesread, count;
1320
1321 buffer = malloc( sizeof( *buffer) * BUFFSIZE);
1322 if (buffer == NULL) fatalperror("Couldn't allocate buffer");
1323
1324 while (size > 0)
1325 {
1326 if (size > BUFFSIZE)
1327 count = BUFFSIZE;
1328 else
1329 count = size;
1330
1331 samplesread = fread( buffer, sizeof(*buffer), count, in);
1332 if (ferror( in) != 0)
1333 fatalperror("Error reading input file");
1334 size -= samplesread;
1335 }
1336 free( buffer);
1337 }
1338
1339 /****************************************************************************
1340 *
1341 * Programs for processing sound files in raw- or WAV-format.
1342 * -- Merge two mono WAV-files to one stereo WAV-file.
1343 *
1344 * Name: stereorize.c
1345 * Version: 1.1
1346 * Author: Mark Roberts <mark@manumark.de>
1347 * Michael Labuschke <michael@labuschke.de>
1348 *
1349 ****************************************************************************/
1350
1351 #include <stdio.h>
1352 #include <stdlib.h>
1353 #include <string.h>
1354 #include <errno.h>
1355 #include <time.h>
1356 #include <assert.h>
1357
1358 static char *Version = "stereorize 1.1, November 5th 2000";
1359 static char *Usage =
1360 "Usage: stereorize [options] infile-left infile-right outfile\n\n"
1361
1362 "Example:\n"
1363 " stereorize left.wav right.wav stereo.wav -h\n\n"
1364
1365 "Creates stereo.wav (with WAV-header, option -h) from data in mono files\n"
1366 "left.wav and right.wav.\n"
1367 ;
1368
1369 int main( int argcount, char *args[])
1370 {
1371 int i, k[2], maxk, stdin_in_use=FALSE;
1372 short *leftsample, *rightsample, *stereosample;
1373 FILE *channel[2];
1374 char *filename[2], *tempname;
1375
1376 version = Version;
1377 usage = Usage;
1378
1379 channel[0] = NULL;
1380 channel[1] = NULL;
1381
1382 parseargs( argcount, args, NOFILES | NOCOMPLAIN);
1383
1384 for (i = 0; i < 2; i++)
1385 {
1386 filename[i] = parsefilearg( argcount, args);
1387 if (filename[i] == NULL)
1388 argerrornum( NULL, ME_NOTENOUGHFILES);
1389 if (strcmp (filename[i], "-") == 0)
1390 {
1391 if (stdin_in_use)
1392 argerrortxt( filename[i] + 1,
1393 "Cannot use <stdin> for both input files");
1394 filename[i] = "<stdin>";
1395 channel[i] = stdin;
1396 stdin_in_use = TRUE;
1397 }
1398 else
1399 {
1400 channel[i] = fopen(filename[i], "rb");
1401 }
1402 if (channel[i] == NULL)
1403 fatalerror( "Error opening input file '%s': %s\n", filename[i],strerror(errno));
1404 else
1405 inform("Using file '%s' as input\n", filename[i]);
1406 }
1407 for (i = 0; i < 2; i++)
1408 {
1409 assert ( channel[i] != NULL);
1410 readwavheader( channel[i]);
1411 if (iswav && channels != 1)
1412 inform("Warning: '%s' is no mono file\n", filename[i]);
1413 }
1414
1415 outfilename = parsefilearg( argcount, args);
1416 if (outfilename == NULL) argerrornum( NULL, ME_NOOUTFILE);
1417 if (strcmp (outfilename, "-") == 0)
1418 {
1419 outfilename = "<stdout>";
1420 out = stdout;
1421 }
1422 else
1423 {
1424 out = fopen(outfilename, "wb");
1425 }
1426 if (out == NULL)
1427 fatalerror( "Error opening output file '%s': %s\n", outfilename,strerror(errno));
1428 else
1429 inform("Using file '%s' as output\n", outfilename);
1430
1431 if ((tempname = parsefilearg( argcount, args)) != NULL)
1432 argerrornum( tempname, ME_TOOMANYFILES);
1433
1434 checknoargs(argcount, args); /* Check that no arguments are left */
1435
1436 leftsample = malloc( sizeof(*leftsample) * BUFFSIZE);
1437 rightsample = malloc( sizeof(*leftsample) * BUFFSIZE);
1438 stereosample = malloc( sizeof(*leftsample) * 2 * BUFFSIZE);
1439 if (leftsample == NULL || rightsample == NULL || stereosample == NULL)
1440 fatalperror ("");
1441
1442 channels = 2; /* Output files are stereo */
1443 if (wavout)
1444 {
1445 if ((strcmp(outfilename,"<stdout>")!=0) && (fseek( out, 0, SEEK_SET) != 0))
1446 fatalerror("Couldn't navigate output file '%s': %s\n",outfilename, strerror(errno));
1447 makewavheader();
1448 }
1449
1450 startstopwatch();
1451 while (TRUE)
1452 {
1453 maxk = 0;
1454 for (i = 0; i < 2; i++)
1455 {
1456 k[i] = fread(i==0? leftsample : rightsample,
1457 sizeof(*leftsample),
1458 BUFFSIZE,
1459 channel[i]);
1460 if (k[i] == -1)
1461 fatalerror("Error reading file '%s': %s\n", filename[i],strerror(errno));
1462 if (k[i] > maxk)
1463 maxk = k[i];
1464 }
1465 if (maxk == 0)
1466 myexit (0);
1467
1468 /*-------------------------------------------------*
1469 * First the left channel as far as it goes ... *
1470 *-------------------------------------------------*/
1471 for (i = 0; i < k[0]; i++)
1472 stereosample[2 * i] = leftsample[i];
1473 /*-------------------------------------------------*
1474 * ... and fill up till the end of this buffer. *
1475 *-------------------------------------------------*/
1476 for (; i < maxk; i++)
1477 stereosample[2 * i] = 0;
1478
1479 /*-------------------------------------------------*
1480 * Next the right channel as far as it goes ... *
1481 *-------------------------------------------------*/
1482 for (i = 0; i < k[1]; i++)
1483 stereosample[2 * i + 1] = rightsample[i];
1484 /*-------------------------------------------------*
1485 * ... and fill up till the end of this buffer. *
1486 *-------------------------------------------------*/
1487 for (; i < maxk; i++)
1488 stereosample[2 * i + 1] = 0;
1489
1490 fwrite(stereosample, sizeof(*leftsample), 2 * maxk, out);
1491 if (ferror( out) != 0)
1492 fatalerror("Error writing to file '%s': %s\n",
1493 outfilename, strerror(errno));
1494 }
1495 /* That was an endless loop. This point is never reached. */
1496 }