frame.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092
  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. #include <stdio.h>
  17. #include <math.h>
  18. #include <stdlib.h> /* for exit and malloc */
  19. #include <string.h>
  20. #include <time.h>
  21. #include <stdarg.h>
  22. #include <errno.h>
  23. #include <assert.h>
  24. #include "frame.h"
  25. time_t stopwatch; /* will hold time at start of calculation */
  26. int samplefrequency;
  27. unsigned short samplewidth;
  28. unsigned short channels;
  29. int wavout; /* TRUE iff out file should be a .WAV file */
  30. int iswav; /* TRUE iff in file was found to be a .WAV file */
  31. FILE *in, *out;
  32. char *infilename, *outfilename;
  33. int verboselevel;
  34. char *version = "";
  35. char *usage = "";
  36. static int test_usage;
  37. static char *standardversion = "frame version 1.3, June 13th 2001";
  38. static char *standardusage =
  39. "\nOptions common to all mark-dsp programs:\n"
  40. "-h \t\t create a WAV-header on output files.\n"
  41. "-c#\t\t set number of channels to # (1 or 2). Default: like input.\n"
  42. "-w#\t\t set number of bits per sample (width) to # (only 16)\n"
  43. "-f#\t\t set sample frequency to #. Default: like input.\n"
  44. "-V \t\t verbose: talk a lot.\n"
  45. "-Q \t\t quiet: talk as little as possible.\n\n"
  46. "In most cases, a filename of '-' means stdin or stdout.\n\n"
  47. "Bug-reports: mark@manumark.de\n"
  48. ;
  49. /* -----------------------------------------------------------------------
  50. Writes the number of samples to result that are yet to be read from anyin.
  51. Return values are TRUE on success, FALSE on failure.
  52. -----------------------------------------------------------------------*/
  53. int getremainingfilelength( FILE *anyin, long *result)
  54. {
  55. long i;
  56. i = ftell(anyin);
  57. if (i == -1) return FALSE;
  58. if (fseek(anyin, 0, SEEK_END) == -1) return FALSE;
  59. *result = ftell(anyin);
  60. if (*result == -1) return FALSE;
  61. (*result) -= i;
  62. (*result) /= samplewidth;
  63. if (fseek(anyin, i, SEEK_SET) == -1) return FALSE;
  64. return TRUE;
  65. }
  66. /* -----------------------------------------------------------------------
  67. Read a .pk-header from 'anyin'.
  68. -----------------------------------------------------------------------*/
  69. void readpkheader( FILE *anyin)
  70. {
  71. unsigned short tempushort;
  72. int tempint, i, x;
  73. unsigned char blood[8];
  74. for (i = 0; i < 11; i++)
  75. {
  76. if (!fread( &tempint, 4, 1, anyin)) {
  77. return;
  78. }
  79. printf( "%d: %d, ", i, tempint);
  80. }
  81. printf( "\n");
  82. if (!fread( blood, 1, 8, anyin)) {
  83. return;
  84. }
  85. for (i = 0; i < 8; i++)
  86. printf( "%d ", blood[i]);
  87. printf( "\n");
  88. for (i = 0; i < 8; i++)
  89. {
  90. for (x = 128; x > 0; x /= 2)
  91. printf((blood[i] & x) == 0? "0 ":"1 ");
  92. printf(i%4==3? "\n":"| ");
  93. }
  94. printf( "\n");
  95. for (i = 0; i < 2; i++)
  96. {
  97. if (!fread( &tempint, 4, 1, anyin)) {
  98. return;
  99. }
  100. printf( "%d: %d, ", i, tempint);
  101. }
  102. printf( "\n");
  103. for (i = 0; i < 2; i++)
  104. {
  105. if (!fread( &tempushort, 2, 1, anyin)) {
  106. return;
  107. }
  108. printf( "%d: %d, ", i, tempushort);
  109. }
  110. printf( "\n");
  111. }
  112. /* -----------------------------------------------------------------------
  113. Read a .WAV header from 'anyin'. See header for details.
  114. -----------------------------------------------------------------------*/
  115. void readwavheader( FILE *anyin)
  116. {
  117. unsigned int tempuint, sf;
  118. unsigned short tempushort, cn;
  119. char str[9];
  120. int nowav = FALSE;
  121. iswav = FALSE;
  122. if (ftell(anyin) == -1) /* If we cannot seek this file */
  123. {
  124. nowav = TRUE; /* -> Pretend this is no wav-file */
  125. chat("File not seekable: not checking for WAV-header.\n");
  126. }
  127. else
  128. {
  129. /* Expect four bytes "RIFF" and four bytes filelength */
  130. if (!fread(str, 1, 8, anyin)) { /* 0 */
  131. return;
  132. }
  133. str[4] = '\0';
  134. if (strcmp(str, "RIFF") != 0) nowav = TRUE;
  135. /* Expect eight bytes "WAVEfmt " */
  136. if (!fread(str, 1, 8, anyin)) { /* 8 */
  137. return;
  138. }
  139. str[8] = '\0';
  140. if (strcmp(str, "WAVEfmt ") != 0) nowav = TRUE;
  141. /* Expect length of fmt data, which should be 16 */
  142. if (!fread(&tempuint, 4, 1, anyin)) { /* 16 */
  143. return;
  144. }
  145. if (tempuint != 16) nowav = TRUE;
  146. /* Expect format tag, which should be 1 for pcm */
  147. if (!fread(&tempushort, 2, 1, anyin)) { /* 20 */
  148. return;
  149. }
  150. if (tempushort != 1)
  151. nowav = TRUE;
  152. /* Expect number of channels */
  153. if (!fread(&cn, 2, 1, anyin)) { /* 20 */
  154. return;
  155. }
  156. if (cn != 1 && cn != 2) nowav = TRUE;
  157. /* Read samplefrequency */
  158. if (!fread(&sf, 4, 1, anyin)) { /* 24 */
  159. return;
  160. }
  161. /* Read bytes per second: Should be samplefreq * channels * 2 */
  162. if (!fread(&tempuint, 4, 1, anyin)) { /* 28 */
  163. return;
  164. }
  165. if (tempuint != sf * cn * 2) nowav = TRUE;
  166. /* read bytes per frame: Should be channels * 2 */
  167. if (!fread(&tempushort, 2, 1, anyin)) { /* 32 */
  168. return;
  169. }
  170. if (tempushort != cn * 2) nowav = TRUE;
  171. /* Read bits per sample: Should be 16 */
  172. if (!fread(&tempushort, 2, 1, anyin)) { /* 34 */
  173. return;
  174. }
  175. if (tempushort != 16) nowav = TRUE;
  176. if (!fread(str, 4, 1, anyin)) { /* 36 */
  177. return;
  178. }
  179. str[4] = '\0';
  180. if (strcmp(str, "data") != 0) nowav = TRUE;
  181. if (!fread(&tempuint, 4, 1, anyin)) { /* 40 */
  182. return;
  183. }
  184. if (nowav)
  185. {
  186. fseek(anyin, 0, SEEK_SET); /* Back to beginning of file */
  187. chat("File has no WAV header.\n");
  188. }
  189. else
  190. {
  191. samplefrequency = sf;
  192. channels = cn;
  193. chat("Read WAV header: %d channels, samplefrequency %d.\n",
  194. channels, samplefrequency);
  195. iswav = TRUE;
  196. }
  197. }
  198. return;
  199. }
  200. /* -----------------------------------------------------------------------
  201. Write a .WAV header to 'out'. See header for details.
  202. -----------------------------------------------------------------------*/
  203. void makewavheader( void)
  204. {
  205. unsigned int tempuint, filelength;
  206. unsigned short tempushort;
  207. /* If fseek fails, don't create the header. */
  208. if (fseek(out, 0, SEEK_END) != -1)
  209. {
  210. filelength = ftell(out);
  211. chat("filelength %d, ", filelength);
  212. fseek(out, 0, SEEK_SET);
  213. if (!fwrite("RIFF", 1, 4, out)) { /* 0 */
  214. return;
  215. }
  216. tempuint = filelength - 8;
  217. if (!fwrite(&tempuint, 4, 1, out)) { /* 4 */
  218. return;
  219. }
  220. if (!fwrite("WAVEfmt ", 1, 8, out)) { /* 8 */
  221. return;
  222. }
  223. /* length of fmt data 16 bytes */
  224. tempuint = 16;
  225. if (!fwrite(&tempuint, 4, 1, out)) { /* 16 */
  226. return;
  227. }
  228. /* Format tag: 1 for pcm */
  229. tempushort = 1;
  230. if (!fwrite(&tempushort, 2, 1, out)) { /* 20 */
  231. return;
  232. }
  233. chat("%d channels\n", channels);
  234. if (!fwrite(&channels, 2, 1, out)) {
  235. return;
  236. }
  237. chat("samplefrequency %d\n", samplefrequency);
  238. if (!fwrite(&samplefrequency, 4, 1, out)) { /* 24 */
  239. return;
  240. }
  241. /* Bytes per second */
  242. tempuint = channels * samplefrequency * 2;
  243. if (!fwrite(&tempuint, 4, 1, out)) { /* 28 */
  244. return;
  245. }
  246. /* Block align */
  247. tempushort = 2 * channels;
  248. if (!fwrite(&tempushort, 2, 1, out)) { /* 32 */
  249. return;
  250. }
  251. /* Bits per sample */
  252. tempushort = 16;
  253. if (!fwrite(&tempushort, 2, 1, out)) { /* 34 */
  254. return;
  255. }
  256. if (!fwrite("data", 4, 1, out)) { /* 36 */
  257. return;
  258. }
  259. tempuint = filelength - 44;
  260. if (!fwrite(&tempuint, 4, 1, out)) { /* 40 */
  261. return;
  262. }
  263. }
  264. return;
  265. }
  266. /* -----------------------------------------------------------------------
  267. After all is read and done, inform the inclined user of the elapsed time
  268. -----------------------------------------------------------------------*/
  269. static void statistics( void)
  270. {
  271. int temp;
  272. temp = time(NULL) - stopwatch;
  273. if (temp != 1)
  274. {
  275. inform ("\nTime: %d seconds\n", temp);
  276. }
  277. else
  278. {
  279. inform ("\nTime: 1 second\n");
  280. }
  281. return;
  282. }
  283. /* -----------------------------------------------------------------------
  284. Start the stopwatch and make sure the user is informed at end of program.
  285. -----------------------------------------------------------------------*/
  286. void startstopwatch(void)
  287. {
  288. stopwatch = time(NULL); /* Remember time 'now' */
  289. atexit(statistics); /* Call function statistics() at exit. */
  290. return;
  291. }
  292. /* --------------------------------------------------------------------
  293. Tests the character 'coal' for being a command line option character,
  294. momentarrily '-'.
  295. -------------------------------------------------------------------- */
  296. int isoptionchar (char coal)
  297. {
  298. return (coal =='-');
  299. }
  300. /* -----------------------------------------------------------------------
  301. Reads through the arguments on the lookout for an option starting
  302. with 'string'. The rest of the option is read as a time and passed
  303. to *result, where the result is meant to mean 'number of samples' in
  304. that time.
  305. On failure, *result is unchanged.
  306. return value is TRUE on success, FALSE otherwise.
  307. -----------------------------------------------------------------------*/
  308. int parsetimearg( int argcount, char *args[], char *string, int *result)
  309. {
  310. int i;
  311. if ((i = findoption( argcount, args, string)) > 0)
  312. {
  313. if (parsetime(args[i] + 1 + strlen( string), result))
  314. return TRUE;
  315. argerrornum(args[i]+1, ME_NOTIME);
  316. }
  317. return FALSE;
  318. }
  319. /* -----------------------------------------------------------------------
  320. The string argument is read as a time and passed
  321. to *result, where the result is meant to mean 'number of samples' in
  322. that time.
  323. On failure, *result is unchanged.
  324. return value is TRUE on success, FALSE otherwise.
  325. -----------------------------------------------------------------------*/
  326. int parsetime(char *string, int *result)
  327. {
  328. int k;
  329. double temp;
  330. char m, s, end;
  331. k = sscanf(string, "%30lf%1c%1c%1c", &temp, &m, &s, &end);
  332. switch (k)
  333. {
  334. case 0: case EOF: case 4:
  335. return FALSE;
  336. case 1:
  337. *result = temp;
  338. break;
  339. case 2:
  340. if (m == 's')
  341. *result = temp * samplefrequency;
  342. else
  343. return FALSE;
  344. break;
  345. case 3:
  346. if (m == 'm' && s == 's')
  347. *result = temp * samplefrequency / 1000;
  348. else if (m == 'H' && s == 'z')
  349. *result = samplefrequency / temp;
  350. else
  351. return FALSE;
  352. break;
  353. default:
  354. argerrornum(NULL, ME_THISCANTHAPPEN);
  355. }
  356. return TRUE;
  357. }
  358. /* -----------------------------------------------------------------------
  359. The string argument is read as a frequency and passed
  360. to *result, where the result is meant to mean 'number of samples' in
  361. one cycle of that frequency.
  362. On failure, *result is unchanged.
  363. return value is TRUE on success, FALSE otherwise.
  364. -----------------------------------------------------------------------*/
  365. int parsefreq(char *string, double *result)
  366. {
  367. int k;
  368. double temp;
  369. char m, s, end;
  370. k = sscanf(string, "%30lf%1c%1c%1c", &temp, &m, &s, &end);
  371. switch (k)
  372. {
  373. case 0: case EOF: case 2: case 4:
  374. return FALSE;
  375. case 1:
  376. *result = temp;
  377. break;
  378. case 3:
  379. if (m == 'H' && s == 'z')
  380. *result = samplefrequency / temp;
  381. else
  382. return FALSE;
  383. break;
  384. default:
  385. argerrornum(NULL, ME_THISCANTHAPPEN);
  386. }
  387. return TRUE;
  388. }
  389. char *parsefilearg( int argcount, char *args[])
  390. {
  391. int i;
  392. char *result = NULL;
  393. for (i = 1; i < argcount; i++)
  394. {
  395. if (args[i][0] != '\0' &&
  396. (!isoptionchar (args[i][0]) || args[i][1] == '\0' ))
  397. {
  398. /*---------------------------------------------*
  399. * The argument is a filename: *
  400. * it is either no dash followed by something, *
  401. * or it is a dash following by nothing. *
  402. *---------------------------------------------*/
  403. result = malloc( strlen( args[i]) + 1);
  404. if (result == NULL)
  405. fatalperror( "Couldn't allocate memory for filename\n");
  406. strcpy( result, args[i]);
  407. args[i][0] = '\0'; /* Mark as used up */
  408. break;
  409. }
  410. }
  411. return result;
  412. }
  413. int parseswitch( char *found, char *wanted)
  414. {
  415. if (strncmp( found, wanted, strlen( wanted)) == 0)
  416. {
  417. if (found[strlen( wanted)] == '\0')
  418. return TRUE;
  419. else
  420. argerrornum( found, ME_NOSWITCH);
  421. }
  422. return FALSE;
  423. }
  424. int parseswitcharg( int argcount, char *args[], char *string)
  425. {
  426. int i;
  427. if ((i = findoption( argcount, args, string)) > 0)
  428. {
  429. if (args[i][strlen( string) + 1] == '\0')
  430. return TRUE;
  431. else
  432. argerrornum( args[i] + 1, ME_NOSWITCH);
  433. }
  434. return FALSE;
  435. }
  436. int parseintarg( int argcount, char *args[], char *string, int *result)
  437. {
  438. int i, temp;
  439. char c;
  440. if ((i = findoption( argcount, args, string)) > 0)
  441. {
  442. switch (sscanf(args[i] + 1 + strlen( string),
  443. "%30d%1c", &temp, &c))
  444. {
  445. case 0: case EOF: case 2:
  446. argerrornum(args[i]+1, ME_NOINT);
  447. return FALSE;
  448. case 1:
  449. *result = temp;
  450. break;
  451. default:
  452. say("frame.c: This can't happen\n");
  453. }
  454. return TRUE;
  455. }
  456. else
  457. {
  458. return FALSE;
  459. }
  460. }
  461. /* --------------------------------------------------------------------
  462. Reads through the arguments on the lookout for an option starting
  463. with 'string'. The rest of the option is read as a double and
  464. passed to *result.
  465. On failure, *result is unchanged.
  466. return value is TRUE on success, FALSE otherwise.
  467. -------------------------------------------------------------------- */
  468. int parsedoublearg( int argcount, char *args[], char *string, double *result)
  469. {
  470. int i;
  471. double temp;
  472. char end;
  473. if ((i = findoption( argcount, args, string)) > 0)
  474. {
  475. switch (sscanf(args[i] + 1 + strlen( string), "%30lf%1c", &temp, &end))
  476. {
  477. case 0: case EOF: case 2:
  478. argerrornum(args[i]+1, ME_NODOUBLE);
  479. return FALSE;
  480. case 1:
  481. *result = temp;
  482. break;
  483. default:
  484. say("frame.c: This can't happen\n");
  485. }
  486. return TRUE;
  487. }
  488. else
  489. {
  490. return FALSE;
  491. }
  492. }
  493. /* --------------------------------------------------------------------
  494. Reads through the arguments on the lookout for an option starting
  495. with 'string'. The rest of the option is read as a volume, i.e.
  496. absolute, percent or db. The result is passed to *result.
  497. On failure, *result is unchanged.
  498. return value is TRUE on success, FALSE otherwise.
  499. -------------------------------------------------------------------- */
  500. int parsevolarg( int argcount, char *args[], char *string, double *result)
  501. {
  502. double vol = 1.0;
  503. char sbd, sbb, end;
  504. int i, weird = FALSE;
  505. if ((i = findoption( argcount, args, string)) > 0)
  506. {
  507. switch (sscanf(args[i] + 1 + strlen( string),
  508. "%30lf%1c%1c%1c", &vol, &sbd, &sbb, &end))
  509. {
  510. case 0: case EOF: case 4:
  511. weird = TRUE;
  512. break; /* No number: error */
  513. case 1:
  514. *result = vol;
  515. break;
  516. case 2:
  517. if (sbd == '%')
  518. *result = vol / 100;
  519. else
  520. weird = TRUE; /* One char but no percent: error */
  521. break;
  522. case 3:
  523. if (sbd =='d' && sbb == 'b')
  524. *result = pow(2, vol / 6.02);
  525. else
  526. weird = TRUE; /* Two chars but not db: error */
  527. break;
  528. default:
  529. say("frame.c: This can't happen.\n");
  530. }
  531. if (weird)
  532. argerrornum( args[i] + 1, ME_NOVOL);
  533. /* ("Weird option: couldn't parse volume '%s'\n", args[i]+2); */
  534. return !weird;
  535. }
  536. else
  537. {
  538. return FALSE;
  539. }
  540. }
  541. /* --------------------------------------------------------------------
  542. Reads the specified string 's' and interprets it as a volume. The string
  543. would be of the form 1.8 or 180% or 5db.
  544. On success, the return value TRUE and *result is given result
  545. (i.e. the relative volume, i.e. 1.8). On failure, FALSE is returned and
  546. result is given value 1.0.
  547. -------------------------------------------------------------------- */
  548. int parsevolume(char *s, double *result)
  549. {
  550. int k;
  551. char sbd, sbb, end;
  552. *result = 1.0;
  553. k = sscanf(s, "%30lf%1c%1c%1c", result, &sbd, &sbb, &end);
  554. switch (k)
  555. {
  556. case 0:
  557. case EOF:
  558. case 4:
  559. return FALSE;
  560. case 1:
  561. break;
  562. case 2:
  563. if (sbd != '%')
  564. return FALSE;
  565. (*result) /=100;
  566. break;
  567. case 3:
  568. if (sbd !='d' || sbb != 'b')
  569. return FALSE;
  570. (*result) = pow(2, (*result) / 6.02);
  571. break;
  572. default:
  573. say("parsevolume: This can't happen (%d).\n", k);
  574. }
  575. return TRUE;
  576. }
  577. /* --------------------------------------------------------------------
  578. Reports an error due to parsing the string 's' encountered on the
  579. command line.
  580. -------------------------------------------------------------------- */
  581. void argerror(char *s)
  582. {
  583. error ("Error parsing command line. Unrecognized option:\n\t-%s\n", s);
  584. fatalerror("\nTry --help for help.\n");
  585. }
  586. /* --------------------------------------------------------------------
  587. Reports an error due to parsing the string 's' encountered on the
  588. command line. 'code' indicates the type of error.
  589. -------------------------------------------------------------------- */
  590. void argerrornum(char *s, Errornum code)
  591. {
  592. char *message;
  593. if (code == ME_TOOMANYFILES)
  594. {
  595. error("Too many files on command line: '%s'.\n", s);
  596. }
  597. else
  598. {
  599. if (s != NULL)
  600. error ("Error parsing option -%s:\n\t", s);
  601. switch( code)
  602. {
  603. case ME_NOINT:
  604. message = "Integer expected";
  605. break;
  606. case ME_NODOUBLE:
  607. message = "Floating point number expected";
  608. break;
  609. case ME_NOTIME:
  610. message = "Time argument expected";
  611. break;
  612. case ME_NOVOL:
  613. message = "Volume argument expected";
  614. break;
  615. case ME_NOSWITCH:
  616. message = "Garbage after switch-type option";
  617. break;
  618. case ME_HEADERONTEXTFILE:
  619. message = "Option -h is not useful for text-output";
  620. break;
  621. case ME_NOINFILE:
  622. message = "No input file specified";
  623. break;
  624. case ME_NOOUTFILE:
  625. message = "No output file specified";
  626. break;
  627. case ME_NOIOFILE:
  628. message = "No input/output file specified";
  629. break;
  630. case ME_NOSTDIN:
  631. message = "Standard in not supported here";
  632. break;
  633. case ME_NOSTDOUT:
  634. message = "Standard out not supported here";
  635. break;
  636. case ME_NOSTDIO:
  637. message = "Standard in/out not supported here";
  638. break;
  639. case ME_NOTENOUGHFILES:
  640. message = "Not enough files specified";
  641. break;
  642. case ME_THISCANTHAPPEN:
  643. fatalerror("\nThis can't happen. Report this as a bug\n");
  644. /* fatalerror does not return */
  645. default:
  646. error("Error code %d not implemented. Fix me!\n", code);
  647. message = "Error message not implemented. Fix me!";
  648. }
  649. error("%s\n", message);
  650. }
  651. fatalerror("\nTry --help for help.\n");
  652. }
  653. /* --------------------------------------------------------------------
  654. Reports an error due to parsing the string 's' encountered on the
  655. command line. 'message' explains the type of error.
  656. -------------------------------------------------------------------- */
  657. void argerrortxt(char *s, char *message)
  658. {
  659. if (s != NULL)
  660. error ("Error parsing option -%s:\n\t", s);
  661. else
  662. error ("Error parsing command line:\n\t");
  663. error ("%s\n", message);
  664. fatalerror("\nTry --help for help.\n");
  665. }
  666. /* --------------------------------------------------------------------
  667. Check for any remaining arguments and complain about their existence
  668. -------------------------------------------------------------------- */
  669. void checknoargs( int argcount, char *args[])
  670. {
  671. int i, errorcount = 0;
  672. for (i = 1; i < argcount; i++)
  673. {
  674. if (args[i][0] != '\0') /* An unused argument! */
  675. {
  676. errorcount++;
  677. if (errorcount == 1)
  678. error("The following arguments were not recognized:\n");
  679. error("\t%s\n", args[i]);
  680. }
  681. }
  682. if (errorcount > 0) /* Errors are fatal */
  683. fatalerror("\nTry --help for help.\n");
  684. return; /* No errors? Return. */
  685. }
  686. /* --------------------------------------------------------------------
  687. Parses the command line arguments as represented by the function
  688. arguments. Sets the global variables 'in', 'out', 'samplefrequency'
  689. and 'samplewidth' accordingly. Also verboselevel.
  690. The files 'in' and 'out' are even opened according to 'fileswitch'.
  691. See headerfile for details
  692. -------------------------------------------------------------------- */
  693. void parseargs( int argcount, char *args[], int fileswitch)
  694. {
  695. char *filename;
  696. int tempint = 0;
  697. if ((fileswitch & 1) != 0) /* If getting infile */
  698. in = NULL;
  699. if ((fileswitch & 4) != 0) /* If getting outfile */
  700. out = NULL;
  701. wavout = FALSE;
  702. verboselevel = 5;
  703. samplefrequency = DEFAULTFREQ;
  704. samplewidth = 2;
  705. channels = 1;
  706. /*-----------------------------------------------*
  707. * First first check testcase, usage and version *
  708. *-----------------------------------------------*/
  709. test_usage = parseswitcharg( argcount, args, "-test-usage");
  710. if (parseswitcharg( argcount, args, "-help"))
  711. {
  712. printf("%s%s", usage, standardusage);
  713. exit(0);
  714. }
  715. if (parseswitcharg( argcount, args, "-version"))
  716. {
  717. printf("%s\n(%s)\n", version, standardversion);
  718. exit(0);
  719. }
  720. /*--------------------------------------*
  721. * Set verboselevel *
  722. *--------------------------------------*/
  723. while (parseswitcharg( argcount, args, "V"))
  724. verboselevel = 10;
  725. while (parseswitcharg( argcount, args, "Q"))
  726. verboselevel = 1;
  727. /*-------------------------------------------------*
  728. * Get filenames and open files *
  729. *-------------------------------------------------*/
  730. if ((fileswitch & 1) != 0) /* Infile wanted */
  731. {
  732. infilename = parsefilearg( argcount, args);
  733. if (infilename == NULL)
  734. argerrornum( NULL, ME_NOINFILE);
  735. if (strcmp( infilename, "-") == 0)
  736. {
  737. infilename = "<stdin>";
  738. in = stdin;
  739. if ((fileswitch & 2) != 0) /* Binfile wanted */
  740. readwavheader( in);
  741. }
  742. else
  743. {
  744. if ((fileswitch & 2) == 0) /* Textfile wanted */
  745. in = fopen(infilename, "rt");
  746. else /* Binfile wanted */
  747. if ((in = fopen(infilename, "rb")) != NULL)
  748. readwavheader( in);
  749. }
  750. if (in == NULL)
  751. fatalerror("Error opening input file '%s': %s\n", infilename,strerror(errno));
  752. else
  753. inform("Using file '%s' as input\n", infilename);
  754. }
  755. if ((fileswitch & 4) != 0) /* Outfile wanted */
  756. {
  757. outfilename = parsefilearg( argcount, args);
  758. if (outfilename == NULL)
  759. argerrornum( NULL, ME_NOOUTFILE);
  760. if (strcmp( outfilename, "-") == 0)
  761. {
  762. outfilename = "<stdout>";
  763. out = stdout;
  764. }
  765. else
  766. {
  767. if ((fileswitch & 8) == 0) /* Textfile wanted */
  768. out = fopen(outfilename, "wt");
  769. else /* Binfile wanted */
  770. out = fopen(outfilename, "wb");
  771. }
  772. if (out == NULL)
  773. fatalerror("Error opening output file '%s': %s\n", outfilename,strerror(errno));
  774. else
  775. inform("Using file '%s' as output\n", outfilename);
  776. }
  777. if ((fileswitch & 32) != 0) /* In-/Outfile wanted */
  778. {
  779. assert (in == NULL && out == NULL);
  780. infilename = outfilename = parsefilearg( argcount, args);
  781. if (outfilename == NULL)
  782. argerrornum( NULL, ME_NOIOFILE);
  783. if (strcmp( infilename, "-") == 0)
  784. argerrornum( infilename, ME_NOSTDIN);
  785. inform("Using file '%s' as input/output\n", outfilename);
  786. in = out = fopen(outfilename, "r+");
  787. if (out == NULL)
  788. fatalerror("Error opening input/output file '%s': %s\n", outfilename,strerror(errno));
  789. readwavheader( in);
  790. }
  791. if ((fileswitch & 16) == 0) /* No additional files wanted */
  792. {
  793. if ((filename = parsefilearg( argcount, args)) != NULL)
  794. argerrornum( filename, ME_TOOMANYFILES);
  795. }
  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))
  802. {
  803. if (tempint != 16)
  804. argerrortxt(NULL, "Option -w is only valid "
  805. "with value 16. Sorry.");
  806. else
  807. samplewidth = tempint;
  808. }
  809. if (parseintarg( argcount, args, "c", &tempint))
  810. {
  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;
  816. }
  817. /*-------------------------------------------------*
  818. * Create WAV-header on output if wanted. *
  819. *-------------------------------------------------*/
  820. if (wavout)
  821. switch (fileswitch & (12))
  822. {
  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);
  835. }
  836. return;
  837. }
  838. /* --------------------------------------------------------------------
  839. Returns the index 'i' of the first argument that IS an option, and
  840. which begins with the label 's'. If there is none, -1.
  841. We also mark that option as done with, i.e. we cross it out.
  842. -------------------------------------------------------------------- */
  843. int findoption( int argcount, char *args[], char *s)
  844. {
  845. int i;
  846. if (test_usage)
  847. printf("Checking for option -%s\n", s);
  848. for (i=1; i<argcount; i++)
  849. {
  850. if (isoptionchar (args[i][0]) &&
  851. strncmp( args[i] + 1, s, strlen( s)) == 0)
  852. {
  853. args[i][0] = '\0';
  854. return i;
  855. }
  856. }
  857. return -1;
  858. }
  859. /* --------------------------------------------------------------------
  860. Finishes off the .WAV header (if any) and exits correctly and formerly.
  861. -------------------------------------------------------------------- */
  862. int myexit (int value)
  863. {
  864. switch (value)
  865. {
  866. case 0:
  867. if (wavout)
  868. makewavheader(); /* Writes a fully informed .WAV header */
  869. chat("Success!\n");
  870. break;
  871. default:
  872. chat("Failure.\n");
  873. break;
  874. }
  875. exit (value);
  876. }
  877. /* --------------------------------------------------------------------
  878. Reads the stated input file bufferwise, calls the function 'work'
  879. with the proper values, and writes the result to the stated output file.
  880. Return value: TRUE on success, FALSE otherwise.
  881. -------------------------------------------------------------------- */
  882. int workloop( FILE *theinfile, FILE *theoutfile,
  883. int (*work)( short *buffer, int length) )
  884. {
  885. short *buffer;
  886. int length, nowlength;
  887. length = BUFFSIZE;
  888. if ((buffer = malloc( sizeof(short) * length)) == NULL)
  889. fatalperror ("");
  890. while (TRUE)
  891. {
  892. nowlength = fread(buffer, sizeof(short), length, theinfile);
  893. if (ferror( theinfile) != 0)
  894. fatalperror("Error reading input file");
  895. if (nowlength == 0) /* Reached end of input file */
  896. break;
  897. /* Call the routine that does the work */
  898. if (!work (buffer, nowlength)) /* On error, stop. */
  899. return FALSE;
  900. if (!fwrite(buffer, sizeof(short), nowlength, theoutfile)) {
  901. return FALSE;
  902. }
  903. if (ferror( theoutfile) != 0)
  904. fatalperror("Error writing to output file");
  905. }
  906. return TRUE; /* Input file done with, no errors. */
  907. }
  908. int __attribute__((format(printf,1,2))) chat( const char *format, ...)
  909. {
  910. va_list ap;
  911. int result = 0;
  912. if (verboselevel > 5)
  913. {
  914. va_start( ap, format);
  915. result = vfprintf( stderr, format, ap);
  916. va_end( ap);
  917. }
  918. return result;
  919. }
  920. int __attribute__((format(printf,1,2))) inform( const char *format, ...)
  921. {
  922. va_list ap;
  923. int result = 0;
  924. if (verboselevel > 1)
  925. {
  926. va_start( ap, format);
  927. result = vfprintf( stderr, format, ap);
  928. va_end( ap);
  929. }
  930. return result;
  931. }
  932. int __attribute__((format(printf,1,2))) error( const char *format, ...)
  933. {
  934. va_list ap;
  935. int result;
  936. va_start( ap, format);
  937. result = vfprintf( stderr, format, ap);
  938. va_end( ap);
  939. return result;
  940. }
  941. void __attribute__((format(printf,1,2))) fatalerror( const char *format, ...)
  942. {
  943. va_list ap;
  944. va_start( ap, format);
  945. vfprintf( stderr, format, ap);
  946. va_end( ap);
  947. myexit(1);
  948. }
  949. void fatalperror( const char *string)
  950. {
  951. perror( string);
  952. myexit( 1);
  953. }
  954. int __attribute__((format(printf,1,2))) say( const char *format, ...)
  955. {
  956. va_list ap;
  957. int result;
  958. va_start( ap, format);
  959. result = vfprintf( stdout, format, ap);
  960. va_end( ap);
  961. return result;
  962. }
  963. char *malloccopy( char *string)
  964. {
  965. char *result;
  966. result = malloc( strlen( string) + 1);
  967. if (result != NULL)
  968. strcpy( result, string);
  969. return result;
  970. }
  971. char *mallocconcat( char *one, char *two)
  972. {
  973. char *result;
  974. result = malloc( strlen( one) + strlen( two) + 1);
  975. if (result != NULL)
  976. {
  977. strcpy( result, one);
  978. strcat( result, two);
  979. }
  980. return result;
  981. }
  982. double double2db( double value)
  983. {
  984. if (value < 0)
  985. value = -value;
  986. return 6.0 * log( value / 32767) / log( 2);
  987. }
  988. void readawaysamples( FILE *input, size_t size)
  989. {
  990. short *buffer;
  991. int samplesread, count;
  992. buffer = malloc( sizeof( *buffer) * BUFFSIZE);
  993. if (buffer == NULL) fatalperror("Couldn't allocate buffer");
  994. while (size > 0)
  995. {
  996. if (size > BUFFSIZE)
  997. count = BUFFSIZE;
  998. else
  999. count = size;
  1000. samplesread = fread( buffer, sizeof(*buffer), count, input);
  1001. if (ferror( input) != 0)
  1002. fatalperror("Error reading input file");
  1003. size -= samplesread;
  1004. }
  1005. free( buffer);
  1006. }