cdda2wav.c
上传用户:xiejiait
上传日期:2007-01-06
资源大小:881k
文件大小:62k
源码类别:

SCSI/ASPI

开发平台:

MultiPlatform

  1. /* @(#)cdda2wav.c 1.6 00/01/11 Copyright 1998,1999,2000 Heiko Eissfeldt */
  2. #ifndef lint
  3. static char     sccsid[] =
  4. "@(#)cdda2wav.c 1.6 00/01/11 Copyright 1998,1999,2000 Heiko Eissfeldt";
  5. #endif
  6. #undef DEBUG_BUFFER_ADDRESSES
  7. #undef GPROF
  8. #undef DEBUG_FORKED
  9. #undef DEBUG_CLEANUP
  10. #undef DEBUG_DYN_OVERLAP
  11. #undef DEBUG_READS
  12. /*
  13.  * Copyright: GNU Public License 2 applies
  14.  *
  15.  *   This program is free software; you can redistribute it and/or modify
  16.  *   it under the terms of the GNU General Public License as published by
  17.  *   the Free Software Foundation; either version 2, or (at your option)
  18.  *   any later version.
  19.  *
  20.  *   This program is distributed in the hope that it will be useful,
  21.  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  22.  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  23.  *   GNU General Public License for more details.
  24.  *
  25.  *   You should have received a copy of the GNU General Public License
  26.  *   along with this program; if not, write to the Free Software
  27.  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  28.  *
  29.  * CDDA2WAV (C) 1995-1998 Heiko Eissfeldt heiko@colossus.escape.de
  30.  * parts    (C) Peter Widow
  31.  * parts    (C) Thomas Niederreiter
  32.  * parts    (C) RSA Data Security, Inc.
  33.  *
  34.  * last changes:
  35.  *   18.12.93 - first version, OK
  36.  *   01.01.94 - generalized & clean up HE
  37.  *   10.06.94 - first linux version HE
  38.  *   12.06.94 - wav header alignment problem fixed HE
  39.  *   12.08.94 - open the cdrom device O_RDONLY makes more sense :-)
  40.  * no more floating point math
  41.  * change to sector size 2352 which is more common
  42.  * sub-q-channel information per kernel ioctl requested
  43.  * doesn't work as well as before
  44.  * some new options (-max -i)
  45.  *   01.02.95 - async i/o via semaphores and shared memory
  46.  *   03.02.95 - overlapped reading on sectors
  47.  *   03.02.95 - generalized sample rates. all integral divisors are legal
  48.  *   04.02.95 - sun format added
  49.  *              more divisors: all integral halves >= 1 allowed
  50.  * floating point math needed again
  51.  *   06.02.95 - bugfix for last track and not d0
  52.  *              tested with photo-cd with audio tracks
  53.  * tested with xa disk 
  54.  *   29.01.96 - new options for bulk transfer
  55.  *   01.06.96 - tested with enhanced cd
  56.  *   01.06.96 - tested with cd-plus
  57.  *   02.06.96 - support pipes
  58.  *   02.06.96 - support raw format
  59.  *   04.02.96 - security hole fixed
  60.  *   22.04.97 - large parts rewritten
  61.  *   28.04.97 - make file names DOS compatible
  62.  *   01.09.97 - add speed control
  63.  *   20.10.97 - add find mono option
  64.  *   Jan/Feb 98 - conversion to use Joerg Schillings SCSI library
  65.  *
  66.  */
  67. #include "config.h"
  68. #if defined (HAVE_UNISTD_H) && (HAVE_UNISTD_H == 1)
  69. #include <sys/types.h>
  70. #include <unistd.h>
  71. #endif
  72. #include <stdio.h>
  73. #include <standard.h>
  74. #include <stdlib.h>
  75. #include <strdefs.h>
  76. #if defined HAVE_STRINGS_H
  77. #include <strings.h>
  78. #endif
  79. #include <signal.h>
  80. #include <math.h>
  81. #include <fctldefs.h>
  82. #include <time.h>
  83. #if (defined (HAVE_SYS_TIME_H) || (HAVE_SYS_TIME_H != 1)) && defined (TIME_WITH_SYS_TIME)
  84. #include <sys/time.h>
  85. #endif
  86. #if defined (HAVE_LIMITS_H) && (HAVE_LIMITS_H == 1)
  87. #include <limits.h>
  88. #endif
  89. #if defined (HAVE_SYS_IOCTL_H) && (HAVE_SYS_IOCTL_H == 1)
  90. #include <sys/ioctl.h>
  91. #endif
  92. #if defined (HAVE_SYS_WAIT_H) && (HAVE_SYS_WAIT_H == 1)
  93. #include <sys/wait.h>
  94. #endif
  95. #include <vadefs.h>
  96. #include <standard.h>
  97. #include <scg/scsitransp.h>
  98. #include "mytype.h"
  99. #include "sndconfig.h"
  100. #include "semshm.h" /* semaphore functions */
  101. #include "sndfile.h"
  102. #include "wav.h" /* wav file header structures */
  103. #include "sun.h" /* sun audio file header structures */
  104. #include "raw.h" /* raw file handling */
  105. #include "aiff.h" /* aiff file handling */
  106. #include "aifc.h" /* aifc file handling */
  107. #include "interface.h"  /* low level cdrom interfacing */
  108. #include "cdda2wav.h"
  109. #include "resample.h"
  110. #include "toc.h"
  111. #include "setuid.h"
  112. #include "ringbuff.h"
  113. #include "global.h"
  114. static const char * optstring = "D:A:I:O:c:b:r:a:t:i:d:o:n:v:l:E:C:S:p:M:P:K:smweNqxRBVhFGHTJgQ";
  115. extern char *optarg;
  116. extern int optind, opterr, optopt;
  117. int main __PR((int argc, char **argv));
  118. static void RestrictPlaybackRate __PR((long newrate));
  119. static void output_indices __PR((FILE *fp, index_list *p, unsigned trackstart));
  120. static int write_info_file __PR((char *fname_baseval, unsigned int track, unsigned long SamplesDone, int numbered));
  121. static void CloseAudio __PR((char *fname_baseval, unsigned int track, int bulkflag, int channels_val, unsigned long nSamples, struct soundfile *audio_out));
  122. static void CloseAll __PR((void));
  123. static void OpenAudio __PR((char *fname, double rate, long nBitsPerSample, long channels_val, unsigned long expected_bytes, struct soundfile*audio_out));
  124. static void set_offset __PR((myringbuff *p, int offset));
  125. static int get_offset __PR((myringbuff *p));
  126. static void usage __PR((void));
  127. static void init_globals __PR((void));
  128. #if defined (__GLIBC__) || defined(_GNU_C_SOURCE) || defined(__USE_GNU) || defined(__CYGWIN32__)
  129. #define USE_GETOPT_LONG
  130. #endif
  131. #ifdef USE_GETOPT_LONG
  132. #include <getopt.h> /* for get_long_opt () */
  133. static struct option options [] = {
  134. {"device",required_argument,NULL,'D'},
  135. {"auxdevice",required_argument,NULL,'A'},
  136. {"interface",required_argument,NULL,'I'},
  137. {"output-format",required_argument,NULL,'O'},
  138. {"channels",required_argument,NULL,'c'},
  139. {"bits-per-sample",required_argument,NULL,'b'},
  140. {"rate",required_argument,NULL,'r'},
  141. {"divider",required_argument,NULL,'a'},
  142. {"track",required_argument,NULL,'t'},
  143. {"index",required_argument,NULL,'i'},
  144. {"duration",required_argument,NULL,'d'},
  145. {"offset",required_argument,NULL,'o'},
  146. {"sectors-per-request",required_argument,NULL,'n'},
  147. {"buffers-in-ring",required_argument,NULL,'l'},
  148. {"output-endianess",required_argument,NULL,'E'},
  149. {"cdrom-endianess",required_argument,NULL,'C'},
  150. {"verbose-level",required_argument,NULL,'v'},
  151. {"sound-device",required_argument,NULL,'K'},
  152. #ifdef MD5_SIGNATURES
  153. {"md5",required_argument,NULL,'M'},
  154. #endif
  155. {"stereo",no_argument,NULL,'s'},
  156. {"mono",no_argument,NULL,'m'},
  157. {"wait",no_argument,NULL,'w'},
  158. {"find-extremes",no_argument,NULL,'F'},
  159. {"find-mono",no_argument,NULL,'G'},
  160. #ifdef ECHO_TO_SOUNDCARD
  161. {"echo",no_argument,NULL,'e'},
  162. #endif
  163. {"info-only",no_argument,NULL,'J'},
  164. {"no-write",no_argument,NULL,'N'},
  165. {"no-infofile",no_argument,NULL,'H'},
  166. {"quiet",no_argument,NULL,'q'},
  167. {"max",no_argument,NULL,'x'},
  168. {"set-overlap",required_argument,NULL,'P'},
  169. {"speed-select",required_argument,NULL,'S'},
  170. {"dump-rates",no_argument,NULL,'R'},
  171. {"bulk",no_argument,NULL,'B'},
  172. {"deemphasize",no_argument,NULL,'T'},
  173. {"playback-realtime",required_argument,NULL,'p'},
  174. {"verbose-SCSI",no_argument,NULL,'V'},
  175. {"help",no_argument,NULL,'h'},
  176. {"gui",no_argument,NULL,'g'},
  177. {"silent-SCSI",no_argument,NULL,'Q'},
  178. {NULL,0,NULL,0}
  179. };
  180. #endif /* USE_GETOPT_LONG */
  181. #if defined(__CYGWIN32__) ||defined(__EMX__)
  182. #include <io.h> /* for setmode() prototype */
  183. #endif
  184. /* global variables */
  185. global_t global;
  186. /* static variables */
  187. static unsigned long nSamplesDone = 0;
  188. static int child_pid = -2;
  189. static unsigned long nSamplesToDo;
  190. static unsigned int current_track;
  191. static int bulk = 0;
  192. static void RestrictPlaybackRate( newrate )
  193. long newrate;
  194. {
  195.        global.playback_rate = newrate;
  196.        if ( global.playback_rate < 25 ) global.playback_rate = 25;   /* filter out insane values */
  197.        if ( global.playback_rate > 250 ) global.playback_rate = 250;
  198.        if ( global.playback_rate < 100 )
  199.                global.nsectors = (global.nsectors*global.playback_rate)/100;
  200. }
  201. long SamplesNeeded( amount, undersampling_val)
  202. long amount;
  203. long undersampling_val;
  204. {
  205.   long retval = ((undersampling_val * 2 + Halved)*amount)/2;
  206.   if (Halved && (nSamplesToDo & 1))
  207.     retval += 2;
  208.   return retval;
  209. }
  210. static int argc2;
  211. static int argc3;
  212. static char **argv2;
  213. static void reset_name_iterator __PR((void));
  214. static void reset_name_iterator ()
  215. {
  216. argv2 -= argc3 - argc2;
  217. argc2 = argc3;
  218. }
  219. static char *get_next_name __PR((void));
  220. static char *get_next_name ()
  221. {
  222. if (argc2 > 0) {
  223. argc2--;
  224. return (*argv2++);
  225. } else {
  226. return NULL;
  227. }
  228. }
  229. static char *cut_extension __PR(( char * fname ));
  230. static char
  231. *cut_extension (fname)
  232. char *fname;
  233. {
  234. char *pp;
  235. pp = strrchr(fname, '.');
  236. if (pp == NULL) {
  237. pp = fname + strlen(fname);
  238. }
  239. *pp = '';
  240. return pp;
  241. }
  242. #ifdef INFOFILES
  243. static void output_indices(fp, p, trackstart)
  244. FILE *fp;
  245. index_list *p;
  246. unsigned trackstart;
  247. {
  248.   int ci;
  249.   fprintf(fp, "Index=tt");
  250.   if (p == NULL) {
  251.     fprintf(fp, "0n");
  252.     return;
  253.   }
  254.   for (ci = 1; p != NULL; ci++, p = p->next) {
  255.     int frameoff = p->frameoffset;
  256.     if (p->next == NULL)
  257.  fputs("nIndex0=tt", fp);
  258. #if 0
  259.     else if ( ci > 8 && (ci % 8) == 1)
  260.  fputs("nIndex =tt", fp);
  261. #endif
  262.     if (frameoff != -1)
  263.          fprintf(fp, "%d ", frameoff - trackstart);
  264.     else
  265.          fprintf(fp, "-1 ");
  266.   }
  267.   fputs("n", fp);
  268. }
  269. /*
  270.  * write information at the end of the sampling process
  271.  *
  272.  *
  273.  * uglyfied for Joerg Schillings ultra dumb line parser
  274.  */
  275. static int write_info_file(fname_baseval, track, SamplesDone, numbered)
  276. char *fname_baseval;
  277. unsigned int track;
  278. unsigned long int SamplesDone;
  279. int numbered;
  280. {
  281.   FILE *info_fp;
  282.   char fname[200];
  283.   char datetime[30];
  284.   time_t utc_time;
  285.   struct tm *tmptr;
  286.   /* write info file */
  287.   if (!strcmp(fname_baseval,"standard output")) return 0;
  288.   strncpy(fname, fname_baseval, sizeof(fname) -1);
  289.   fname[sizeof(fname) -1] = 0;
  290.   if (numbered)
  291.     sprintf(cut_extension(fname), "_%02u.inf", track);
  292.   else
  293.     strcpy(cut_extension(fname), ".inf");
  294.   info_fp = fopen (fname, "w");
  295.   if (!info_fp)
  296.     return -1;
  297. #ifdef MD5_SIGNATURES
  298.   if (global.md5blocksize)
  299.     MD5Final (global.MD5_result, &global.context);
  300. #endif
  301.   utc_time = time(NULL);
  302.   tmptr = localtime(&utc_time);
  303.   if (tmptr) {
  304.     strftime(datetime, sizeof(datetime), "%x %X", tmptr);
  305.   } else {
  306.     strncpy(datetime, "unknown", sizeof(datetime));
  307.   }
  308.   fprintf(info_fp, "#created by cdda2wav %s %sn#n", VERSION
  309.   , datetime
  310.   );
  311.   fprintf(info_fp,
  312. "CDINDEX_DISCID=t'%s'n" , global.cdindex_id);
  313.   fprintf(info_fp,
  314. "CDDB_DISCID=t0x%08lxnMCN=tt%snISRC=tt%15.15sn#nAlbumtitle=t'%s'n"
  315.   , (unsigned long) global.cddb_id
  316.   , MCN
  317.   , g_toc[track-1].ISRC
  318.   , global.disctitle != NULL ? global.disctitle : (const unsigned char *)""
  319.   );
  320.   fprintf(info_fp,
  321.   "Tracktitle=t'%s'n"
  322.   , global.tracktitle[track-1] ? global.tracktitle[track-1] : (const unsigned char *)""
  323.   );
  324.   fprintf(info_fp, "Tracknumber=t%un"
  325.   , track
  326.   );
  327.   fprintf(info_fp, 
  328.   "Trackstart=t%dn"
  329.   , g_toc[track-1].dwStartSector
  330.   );
  331.   fprintf(info_fp, 
  332.   "# track length in sectors (1/75 seconds each), rest samplesnTracklength=t%ld, %dn"
  333.   , SamplesDone/588L,(int)(SamplesDone%588));
  334.   fprintf(info_fp, 
  335.   "Pre-emphasis=t%sn"
  336.   , g_toc[track-1].bFlags & 1 ? "yes" : "no");
  337.   fprintf(info_fp, 
  338.   "Channels=t%dn"
  339.   , g_toc[track-1].bFlags & 8 ? 4 : 2);
  340.   fprintf(info_fp, 
  341.   "Copy_permitted=t%sn"
  342.   , g_toc[track-1].bFlags & 2 ? "yes" : "no");
  343.   fprintf(info_fp, 
  344.   "Endianess=t%sn"
  345.   , global.need_big_endian ? "big" : "little"
  346.   );
  347.   fprintf(info_fp, "# index listn");
  348.   output_indices(info_fp, global.trackindexlist[track-1], GetStartSector(track));
  349. #ifdef MD5_SIGNATURES
  350.   fprintf(info_fp, 
  351.   "#(blocksize) checksumnMD-5=tt(%d) %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02xn"
  352.   , global.md5blocksize
  353.   , global.MD5_result[0]
  354.   , global.MD5_result[1]
  355.   , global.MD5_result[2]
  356.   , global.MD5_result[3]
  357.   , global.MD5_result[4]
  358.   , global.MD5_result[5]
  359.   , global.MD5_result[6]
  360.   , global.MD5_result[7]
  361.   , global.MD5_result[8]
  362.   , global.MD5_result[9]
  363.   , global.MD5_result[10]
  364.   , global.MD5_result[11]
  365.   , global.MD5_result[12]
  366.   , global.MD5_result[13]
  367.   , global.MD5_result[14]
  368.   , global.MD5_result[15]);
  369. #endif
  370.   fclose(info_fp);
  371.   return 0;
  372. }
  373. #endif
  374. static void CloseAudio(fname_baseval, track, bulkflag, channels_val, nSamples,
  375. audio_out)
  376. char *fname_baseval;
  377. unsigned int track;
  378. int bulkflag;
  379. int channels_val;
  380. unsigned long nSamples;
  381. struct soundfile *audio_out;
  382. {
  383.       /* define length */
  384.       audio_out->ExitSound( global.audio, nSamples*global.OutSampleSize*channels_val );
  385.       close (global.audio);
  386.       global.audio = -1;
  387. }
  388. static unsigned int track = 1;
  389. /* On terminating:
  390.  * define size-related entries in audio file header, update and close file */
  391. static void CloseAll ()
  392. {
  393.   int chld_return_status = 0;
  394.   int amichild;
  395.   /* terminate child process first */
  396.   amichild = child_pid == 0;
  397. #if defined HAVE_FORK_AND_SHAREDMEM
  398.   if (amichild == 0) {
  399. # ifdef DEBUG_CLEANUP
  400. fprintf(stderr, "Parent (READER) terminating, n");
  401. # endif
  402.     if (global.iloop > 0) {
  403.       /* set to zero */
  404.       global.iloop = 0;
  405.       kill(child_pid, SIGINT);
  406.     }
  407. #else
  408.   if (1) {
  409. #endif
  410.     /* switch to original mode and close device */
  411.     EnableCdda (get_scsi_p(), 0);
  412. #if defined HAVE_FORK_AND_SHAREDMEM
  413.   } else {
  414. #ifdef DEBUG_CLEANUP
  415. fprintf(stderr, "Child (WRITER) terminating, n");
  416. #endif
  417. #else
  418. # ifdef DEBUG_CLEANUP
  419. fprintf(stderr, "Cdda2wav single process terminating, n");
  420. # endif
  421. #endif
  422.     /* do general clean up */
  423.     if (global.audio>=0) {
  424.       if (bulk) {
  425.         /* finish sample file for this track */
  426.         CloseAudio(global.fname_base, current_track, bulk, global.channels,
  427.      global.nSamplesDoneInTrack, global.audio_out);
  428.       } else {
  429.         /* finish sample file for this track */
  430.         CloseAudio(global.fname_base, track, bulk, global.channels,
  431.      (unsigned int) nSamplesToDo, global.audio_out);
  432.       }
  433.     }
  434.     /* tell minimum and maximum amplitudes, if required */
  435.     if (global.findminmax) {
  436.       fprintf(stderr,
  437.  "right channel: minimum amplitude :%d/-32768, maximum amplitude :%d/32767n", 
  438. global.minamp[0], global.maxamp[0]);
  439.       fprintf(stderr,
  440.  "left  channel: minimum amplitude :%d/-32768, maximum amplitude :%d/32767n", 
  441. global.minamp[1], global.maxamp[1]);
  442.     }
  443.     /* tell mono or stereo recording, if required */
  444.     if (global.findmono) {
  445.       fprintf(stderr, "Audio samples are originally %s.n", global.ismono ? "mono" : "stereo");
  446.     }
  447. #ifdef DEBUG_CLEANUP
  448. fprintf(stderr, "Child (WRITER) terminating, n");
  449. #endif
  450.     return;
  451.   }
  452.   if (global.have_forked == 1) {
  453. #ifdef DEBUG_CLEANUP
  454. fprintf(stderr, "Parent wait for child death, n");
  455. #endif
  456. #if defined(HAVE_SYS_WAIT_H) && (HAVE_SYS_WAIT_H == 1)
  457.     /* wait for child to terminate */
  458.     if (0 > wait(&chld_return_status)) {
  459.       perror("");
  460.     } else {
  461.       if (WIFEXITED(chld_return_status)) {
  462.         if (WEXITSTATUS(chld_return_status)) {
  463.           fprintf(stderr, "Child exited with %dn", WEXITSTATUS(chld_return_status));
  464.         }
  465.       }
  466.       if (WIFSIGNALED(chld_return_status)) {
  467.         fprintf(stderr, "Child exited due to signal %dn", WTERMSIG(chld_return_status));
  468.       }
  469.       if (WIFSTOPPED(chld_return_status)) {
  470.         fprintf(stderr, "Child is stopped due to signal %dn", WSTOPSIG(chld_return_status));
  471.       }
  472.     }
  473. #endif
  474. #ifdef DEBUG_CLEANUP
  475. fprintf(stderr, "Parent child death, state:%dn", chld_return_status);
  476. #endif
  477.   }
  478. #ifdef GPROF
  479.   rename("gmon.out", "gmon.child");
  480. #endif
  481. }
  482. /* report a usage error and exit */
  483. #ifdef  PROTOTYPES
  484. static void usage2 (const char *szMessage, ...)
  485. #else
  486. static void usage2 (szMessage, va_alist)
  487. const char *szMessage;
  488. va_dcl
  489. #endif
  490. {
  491.   va_list marker;
  492. #ifdef  PROTOTYPES
  493.   va_start(marker, szMessage);
  494. #else
  495.   va_start(marker);
  496. #endif
  497.   error("%r", szMessage, marker);
  498.   va_end(marker);
  499.   fprintf(stderr, "nPlease use -h or consult the man page for help.n");
  500.   exit (1);
  501. }
  502. /* report a fatal error, clean up and exit */
  503. #ifdef  PROTOTYPES
  504. void FatalError (const char *szMessage, ...)
  505. #else
  506. void FatalError (szMessage, va_alist)
  507. const char *szMessage;
  508. va_dcl
  509. #endif
  510. {
  511.   va_list marker;
  512. #ifdef  PROTOTYPES
  513.   va_start(marker, szMessage);
  514. #else
  515.   va_start(marker);
  516. #endif
  517.   error("%r", szMessage, marker);
  518.   va_end(marker);
  519.   if (child_pid == -2)
  520.     exit (1);
  521.   if (child_pid == 0) {
  522.     /* kill the parent too */
  523.     kill(getppid(), SIGINT);
  524.   } else {
  525. kill(child_pid, SIGINT);
  526.   }
  527.   exit (1);
  528. }
  529. /* open the audio output file and prepare the header. 
  530.  * the header will be defined on terminating (when the size
  531.  * is known). So hitting the interrupt key leaves an intact
  532.  * file.
  533.  */
  534. static void OpenAudio (fname, rate, nBitsPerSample, channels_val, expected_bytes, audio_out)
  535. char *fname;
  536. double rate;
  537. long nBitsPerSample;
  538. long channels_val;
  539. unsigned long expected_bytes;
  540. struct soundfile * audio_out;
  541. {
  542.   if (global.audio == -1) {
  543.     global.audio = open (fname, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY
  544. #ifdef O_NONBLOCK
  545.  | O_NONBLOCK
  546. #endif
  547. #ifdef SYNCHRONOUS_WRITE
  548.  | O_SYNC
  549. #endif
  550.   , 0666);
  551.     if (global.audio == -1) {
  552.       perror("open audio sample file");
  553.       FatalError ("Could not open file %sn", fname);
  554.     }
  555.   }
  556.   audio_out->InitSound( global.audio, channels_val, (unsigned long)rate, nBitsPerSample, expected_bytes );
  557. #ifdef MD5_SIGNATURES
  558.   if (global.md5blocksize)
  559.     MD5Init (&global.context);
  560.   global.md5count = global.md5blocksize;
  561. #endif
  562. }
  563. static void set_offset(p, offset)
  564. myringbuff *p;
  565. int offset;
  566. {
  567. #ifdef DEBUG_SHM
  568.   fprintf(stderr, "Write offset %d at %pn", offset, &p->offset);
  569. #endif
  570.   p->offset = offset;
  571. }
  572. static int get_offset(p)
  573. myringbuff *p;
  574. {
  575. #ifdef DEBUG_SHM
  576.   fprintf(stderr, "Read offset %d from %pn", p->offset, &p->offset);
  577. #endif
  578.   return p->offset;
  579. }
  580. static void usage( )
  581. {
  582.   fprintf( stderr,
  583. "cdda2wav [-c chans] [-s] [-m] [-b bits] [-r rate] [-a divider] [-S speed] [-x]n");
  584.   fprintf( stderr,
  585. "         [-t track[+endtrack]] [-i index] [-o offset] [-d duration] [-F] [-G]n");
  586.   fprintf( stderr,
  587. "         [-q] [-w] [-v] [-R] [-P overlap] [-B] [-T] [-C input-endianess]n");
  588.   fprintf( stderr,
  589. "   [-e] [-n sectors] [-N] [-J] [-H] [-g] [-l buffers] [-D cd-device]n");
  590.   fprintf( stderr,
  591. "   [-I interface] [-K sound-device] [-O audiotype] [-E output-endianess]n");
  592.   fprintf( stderr,
  593. "         [-A auxdevice] [audiofiles ...]n");
  594.   fprintf( stderr,
  595. "Version %sn", VERSION);
  596.   fprintf( stderr,
  597. "cdda2wav copies parts from audio cd's directly to wav or au files.n");
  598.   fprintf( stderr,
  599. "It requires a supported cdrom drive to work.n");
  600.   fprintf( stderr,
  601. "options: -D cd-device: set the cdrom or scsi device (as Bus,Id,Lun).n");
  602.   fprintf( stderr,
  603. "         -A auxdevice: set the aux device (typically /dev/cdrom).n");
  604.   fprintf( stderr,
  605. "         -K sound-device: set the sound device to use for -e (typically /dev/dsp).n");
  606.   fprintf( stderr,
  607. "         -I interface: specify the interface for cdrom access.n");
  608.   fprintf( stderr,
  609. "                     : (generic_scsi or cooked_ioctl).n");
  610.   fprintf( stderr,
  611. "         -c channels : set 1 for mono, 2 or s for stereo (s: channels swapped).n");
  612.   fprintf( stderr,
  613. "         -s          : set to stereo recording.n");
  614.   fprintf( stderr,
  615. "         -m          : set to mono recording.n");
  616.   fprintf( stderr,
  617. "         -x          : set to maximum quality (stereo/16-bit/44.1 KHz).n");
  618.   fprintf( stderr,
  619. "         -b bits     : set bits per sample per channel (8, 12 or 16 bits).n");
  620.   fprintf( stderr,
  621. "         -r rate     : set rate in samples per second. -R gives all ratesn");
  622.   fprintf( stderr,
  623. "         -a divider  : set rate to 44100Hz / divider. -R gives all ratesn");
  624.   fprintf( stderr,
  625. "         -R          : dump a table with all available sample ratesn");
  626.   fprintf( stderr,
  627. "         -S speed    : set the cdrom drive to a given speed during readingn");
  628.   fprintf( stderr,
  629. "         -P sectors  : set amount of overlap sampling (default is 0)n");
  630. #ifdef NOTYET
  631.   fprintf( stderr,
  632. "         -X          : switch off extra alignment paranoia; implies -Y -Zn");
  633.   fprintf( stderr,
  634. "         -Y          : switch off scratch detection; implies -Zn");
  635.   fprintf( stderr,
  636. "         -Z          : switch off scratch reconstructionn");
  637.   fprintf( stderr,
  638. "         -y threshold: tune scratch detection filter; low values catchn");
  639.   fprintf( stderr,
  640. "                     : more scratches but may also catch legitimate valuesn");
  641.   fprintf( stderr,
  642. "         -z          : disable 'smart' scratch auto-detect and force n");
  643.   fprintf( stderr,
  644. "                     : paranoia to treat all data as possibly scratchednn");
  645. #endif
  646.   fprintf( stderr,
  647. "         -n sectors  : read 'sectors' sectors per request.n");
  648.   fprintf( stderr,
  649. "         -l buffers  : use a ring buffer with 'buffers' elements.n");
  650.   fprintf( stderr,
  651. "         -t track[+end track]n");
  652.   fprintf( stderr,
  653. "                     : select start track (and optionally end track).n");
  654.   fprintf( stderr,
  655. "         -i index    : select start index.n");
  656.   fprintf( stderr,
  657. "         -o offset   : start at 'offset' sectors behind start track/index.n");
  658.   fprintf( stderr,
  659. "                       one sector equivalents 1/75 second.n");
  660.   fprintf( stderr,
  661. "         -O audiotype: set wav or au (aka sun) or cdr (aka raw) or aiff or aifc audio format. Default is %s.n", AUDIOTYPE);
  662.   fprintf( stderr,
  663. "         -C endianess: set little or big input sample endianess.n");
  664.   fprintf( stderr,
  665. "         -E endianess: set little or big output sample endianess.n");
  666.   fprintf( stderr,
  667. "         -d duration : set recording time in seconds or 0 for whole track.n");
  668.   fprintf( stderr,
  669. "         -w          : wait for audio signal, then start recording.n");
  670.   fprintf( stderr,
  671. "         -F          : find extrem amplitudes in samples.n");
  672.   fprintf( stderr,
  673. "         -G          : find if input samples are mono.n");
  674.   fprintf( stderr,
  675. "         -T          : undo pre-emphasis in input samples.n");
  676. #ifdef ECHO_TO_SOUNDCARD
  677.   fprintf( stderr,
  678. "         -e          : echo audio data to sound device SOUND_DEV.n");
  679. #endif
  680.   fprintf( stderr,
  681. "         -v level    : print informations on current cd (level: 0-63).n");
  682.   fprintf( stderr,
  683. "         -N          : no file operation.n");
  684.   fprintf( stderr,
  685. "         -J          : give disc information only.n");
  686.   fprintf( stderr,
  687. "         -H          : no info file generation.n");
  688.   fprintf( stderr,
  689. "         -g          : generate special output suitable for gui frontends.n");
  690.   fprintf( stderr,
  691. "         -Q          : do not print status of erreneous scsi-commands.n");
  692. #ifdef MD5_SIGNATURES
  693.   fprintf( stderr,
  694. "         -M count    : calculate MD-5 checksum for 'count' bytes.n");
  695. #endif
  696.   fprintf( stderr,
  697. "         -q          : quiet operation, no screen output.n");
  698.   fprintf( stderr,
  699. "         -p percent  : play (echo) audio at a new pitch rate.n");
  700.   fprintf( stderr,
  701. "         -V          : increase verbosity for SCSI commands.n");
  702.   fprintf( stderr,
  703. "         -h          : this help screen.n"  );
  704.   fprintf( stderr,
  705. "         -B          : record each track into a seperate file.n");
  706.   fprintf( stderr,
  707. "defaults: %s, %d bit, %d.%02d Hz, track 1, no offset, one track,n",
  708.   CHANNELS-1?"stereo":"mono", BITS_P_S,
  709.  44100 / UNDERSAMPLING,
  710.  (4410000 / UNDERSAMPLING) % 100);
  711.   fprintf( stderr,
  712. "          type %s '%s', don't wait for signal, not quiet, not verbose,n",
  713.           AUDIOTYPE, FILENAME);
  714.   fprintf( stderr,
  715. "          use %s, device %s, aux %s",
  716.   DEF_INTERFACE, CD_DEVICE, AUX_DEVICE);
  717. #ifdef ECHO_TO_SOUNDCARD
  718.   fprintf( stderr,
  719. ", sound device %sn",
  720.   SOUND_DEV);
  721. #else
  722.   fprintf( stderr, "n");
  723. #endif
  724.   fprintf( stderr,
  725. "parameters: (optional) a file name or - for standard output.n");
  726.   exit( 1 );
  727. }
  728. static void init_globals()
  729. {
  730.   strncpy(global.dev_name, CD_DEVICE, sizeof(global.dev_name)); /* device name */
  731.   strncpy(global.aux_name, AUX_DEVICE, sizeof(global.aux_name));/* auxiliary cdrom device */
  732.   strncpy(global.fname_base, FILENAME, sizeof(global.fname_base));/* auxiliary cdrom device */
  733.   global.have_forked = 0; /* state variable for clean up */
  734.   global.parent_died = 0; /* state variable for clean up */
  735.   global.audio    = -1; /* audio file desc */
  736.   global.cooked_fd  = -1; /* cdrom file desc */
  737.   global.no_file  =  0; /* flag no_file */
  738.   global.no_infofile  =  0; /* flag no_infofile */
  739.   global.no_cddbfile  =  0; /* flag no_cddbfile */
  740.   global.quiet   =  0; /* flag quiet */
  741.   global.verbose  =  3 + 32 + 64; /* verbose level */
  742.   global.scsi_silent = 0;
  743.   global.scsi_verbose = 0; /* SCSI verbose level */
  744.   global.multiname = 0; /* multiple file names given */
  745.   global.sh_bits  =  0; /* sh_bits: sample bit shift */
  746.   global.Remainder=  0; /* remainder */
  747.   global.iloop    =  0; /* todo counter */
  748.   global.SkippedSamples =  0; /* skipped samples */
  749.   global.OutSampleSize  =  0; /* output sample size */
  750.   global.channels = CHANNELS; /* output sound channels */
  751.   global.nSamplesDoneInTrack = 0; /* written samples in current track */
  752.   global.buffers = 4;           /* buffers to use */
  753.   global.nsectors = NSECTORS;   /* sectors to read in one request */
  754.   global.overlap = 1;           /* amount of overlapping sectors */
  755.   global.useroverlap = -1;      /* amount of overlapping sectors user override */
  756.   global.need_hostorder = 0; /* processing needs samples in host endianess */
  757.   global.outputendianess = NONE; /* user specified output endianess */
  758.   global.findminmax  =  0; /* flag find extrem amplitudes */
  759. #ifdef HAVE_LIMITS_H
  760.   global.maxamp[0] = INT_MIN; /* maximum amplitude */
  761.   global.maxamp[1] = INT_MIN; /* maximum amplitude */
  762.   global.minamp[0] = INT_MAX; /* minimum amplitude */
  763.   global.minamp[1] = INT_MAX; /* minimum amplitude */
  764. #else
  765.   global.maxamp[0] = -32768; /* maximum amplitude */
  766.   global.maxamp[1] = -32768; /* maximum amplitude */
  767.   global.minamp[0] = 32767; /* minimum amplitude */
  768.   global.minamp[1] = 32767; /* minimum amplitude */
  769. #endif
  770.   global.speed = DEFAULT_SPEED; /* use default */ 
  771.   global.userspeed = -1;        /* speed user override */
  772.   global.findmono  =  0; /* flag find if samples are mono */
  773.   global.ismono  =  1; /* flag if samples are mono */
  774.   global.swapchannels  =  0; /* flag if channels shall be swapped */
  775.   global.deemphasize  =  0; /* flag undo pre-emphasis in samples */
  776.   global.playback_rate = 100;   /* new fancy selectable sound output rate */
  777.   global.gui  =  0; /* flag plain formatting for guis */
  778.   global.cddb_id = 0;           /* disc identifying id for CDDB database */
  779.   global.disctitle = NULL;
  780.   global.creator = NULL;
  781.   global.copyright_message = NULL;
  782.   memset(global.tracktitle, 0, sizeof(global.tracktitle));
  783.   memset(global.trackindexlist, 0, sizeof(global.trackindexlist));
  784. }
  785. #if !defined (HAVE_STRCASECMP) || (HAVE_STRCASECMP != 1)
  786. #include <ctype.h>
  787. static int strcasecmp __PR(( const char *s1, const char *s2 ));
  788. static int strcasecmp(s1, s2)
  789. const char *s1;
  790. const char *s2;
  791. {
  792.   if (s1 && s2) {
  793.     while (*s1 && *s2 && (tolower(*s1) - tolower(*s2) == 0)) {
  794.       s1++;
  795.       s2++;
  796.     }
  797.     if (*s1 == '' && *s2 == '') return 0;
  798.     if (*s1 == '') return -1;
  799.     if (*s2 == '') return +1;
  800.     return tolower(*s1) - tolower(*s2);
  801.   }
  802.   return -1;
  803. }
  804. #endif
  805. #if !defined (HAVE_STRTOUL) || (HAVE_STRTOUL != 1)
  806. static unsigned int strtoul __PR(( const char *s1, char **s2, int base ));
  807. static unsigned int strtoul(s1, s2, base)
  808.         const char *s1;
  809.         char **s2;
  810. int base;
  811. {
  812. long retval;
  813. if (base == 10) {
  814. /* strip zeros in front */
  815. while (*s1 == '0')
  816. s1++;
  817. }
  818. if (s2 != NULL) {
  819. *s2 = astol(s1, &retval);
  820. } else {
  821. (void) astol(s1, &retval);
  822. }
  823. return (unsigned long) retval; 
  824. }
  825. #endif
  826. static unsigned long SectorBurst;
  827. #if (SENTINEL > CD_FRAMESIZE_RAW)
  828. error block size for overlap check has to be < sector size
  829. #endif
  830. static void
  831. switch_to_realtime_priority __PR((void));
  832. #ifdef  HAVE_SYS_PRIOCNTL_H
  833. #include <sys/priocntl.h>
  834. #include <sys/rtpriocntl.h>
  835. static void
  836. switch_to_realtime_priority()
  837. {
  838.         pcinfo_t        info;
  839.         pcparms_t       param;
  840.         rtinfo_t        rtinfo;
  841.         rtparms_t       rtparam;
  842. int pid;
  843. pid = getpid();
  844.         /* get info */
  845.         strcpy(info.pc_clname, "RT");
  846.         if (-1 == priocntl(P_PID, pid, PC_GETCID, (void *)&info))
  847.                 comerr("Cannot get priority class id priocntl(PC_GETCID)n");
  848.         movebytes(info.pc_clinfo, &rtinfo, sizeof(rtinfo_t));
  849.         /* set priority not to the max */
  850.         rtparam.rt_pri = rtinfo.rt_maxpri - 2;
  851.         rtparam.rt_tqsecs = 0;
  852.         rtparam.rt_tqnsecs = RT_TQDEF;
  853.         param.pc_cid = info.pc_cid;
  854.         movebytes(&rtparam, param.pc_clparms, sizeof(rtparms_t));
  855. needroot(0);
  856.         if (-1 == priocntl(P_PID, pid, PC_SETPARMS, (void *)&param))
  857.                 comerr("Cannot set priority class parameters priocntl(PC_SETPARMS)n");
  858. dontneedroot();
  859. }
  860. #else
  861. #if      defined _POSIX_PRIORITY_SCHEDULING
  862. #include <sched.h>
  863. static void
  864. switch_to_realtime_priority()
  865. {
  866. #ifdef  _SC_PRIORITY_SCHEDULING
  867. if (sysconf(_SC_PRIORITY_SCHEDULING) == -1) {
  868. errmsg("WARNING: RR-scheduler not available, disabling.n");
  869. } else
  870. #endif
  871. {
  872. int sched_fifo_min, sched_fifo_max;
  873. struct sched_param sched_parms;
  874. sched_fifo_min = sched_get_priority_min(SCHED_FIFO);
  875. sched_fifo_max = sched_get_priority_max(SCHED_FIFO);
  876. sched_parms.sched_priority = sched_fifo_max - 1;
  877. needroot(0);
  878. if (-1 == sched_setscheduler(getpid(), SCHED_FIFO, &sched_parms)
  879. && global.quiet != 1)
  880. perror("cannot set posix realtime scheduling policy");
  881. dontneedroot();
  882. }
  883. }
  884. #else
  885. #if defined(__CYGWIN32__)
  886. /*
  887.  * NOTE: Base.h has a second typedef for BOOL.
  888.  *  We define BOOL to make all local code use BOOL
  889.  *  from Windows.h and use the hidden __SBOOL for
  890.  *  our global interfaces.
  891.  */
  892. #define BOOL WBOOL /* This is the Win BOOL */
  893. #define format __format
  894. #include <Windows32/Base.h>
  895. #include <Windows32/Defines.h>
  896. #include <Windows32/Structures.h>
  897. #include <Windows32/Functions.h>
  898. #undef format
  899. static void
  900. switch_to_realtime_priority()
  901. {
  902.    /* set priority class */
  903.    if (FALSE == SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS)) {
  904.      fprintf(stderr, "No realtime priority possible.n");
  905.      return;
  906.    }
  907.    /* set thread priority */
  908.    if (FALSE == SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST)) {
  909.      fprintf(stderr, "Could not set realtime priority.n");
  910.    }
  911. }
  912. #else
  913. static void
  914. switch_to_realtime_priority()
  915. {
  916. }
  917. #endif
  918. #endif
  919. #endif
  920. /* signal handler for process communication */
  921. static void set_nonforked __PR((int status));
  922. static void set_nonforked(status)
  923. int status;
  924. {
  925. PRETEND_TO_USE(status);
  926. global.parent_died = 1;
  927. #if defined DEBUG_CLEANUP
  928. fprintf( stderr, "SIGPIPE received from %sn.", child_pid == 0 ? "Child" : "Parent");
  929. #endif
  930. if (child_pid == 0)
  931. kill(getppid(), SIGINT);
  932. else
  933. kill(child_pid, SIGINT);
  934. exit(9);
  935. }
  936. static long lSector;
  937. static long lSector_p2;
  938. static double rate = 44100 / UNDERSAMPLING;
  939. static int bits = BITS_P_S;
  940. static char fname[200];
  941. static char audio_type[10];
  942. static long BeginAtSample;
  943. static unsigned long SamplesToWrite; 
  944. static unsigned minover;
  945. static unsigned maxover;
  946. static unsigned long calc_SectorBurst __PR((void));
  947. static unsigned long calc_SectorBurst()
  948. {
  949. unsigned long SectorBurstVal;
  950. SectorBurstVal = min(global.nsectors,
  951.   (global.iloop + CD_FRAMESAMPLES-1) / CD_FRAMESAMPLES);
  952. if ( lSector+(int)SectorBurst-1 >= lSector_p2 )
  953. SectorBurstVal = lSector_p2 - lSector;
  954. return SectorBurstVal;
  955. }
  956. /* if PERCENTAGE_PER_TRACK is defined, the percentage message will reach
  957.  * 100% every time a track end is reached or the time limit is reached.
  958.  *
  959.  * Otherwise if PERCENTAGE_PER_TRACK is not defined, the percentage message
  960.  * will reach 100% once at the very end of the last track.
  961.  */
  962. #define PERCENTAGE_PER_TRACK
  963. static int do_read __PR((myringbuff *p, unsigned *total_unsuccessful_retries));
  964. static int do_read (p, total_unsuccessful_retries)
  965. myringbuff *p;
  966. unsigned *total_unsuccessful_retries;
  967. {
  968.       unsigned char *newbuf;
  969.       int offset;
  970.       unsigned int retry_count;
  971.       unsigned int added_size;
  972.       static unsigned oper = 200;
  973.       /* how many sectors should be read */
  974.       SectorBurst =  calc_SectorBurst();
  975. #define MAX_READRETRY 12
  976.       retry_count = 0;
  977.       do {
  978. #ifdef DEBUG_READS
  979. fprintf(stderr, "reading from %lu to %lu, overlap %un", lSector, lSector + SectorBurst -1, global.overlap);
  980. #endif
  981. #ifdef DEBUG_BUFFER_ADDRESSES
  982.   fprintf(stderr, "%p %ln", p->data, global.pagesize);
  983.   if (((unsigned)p->data) & (global.pagesize -1) != 0) {
  984.     fprintf(stderr, "Address %p is NOT page aligned!!n", p->data);
  985.   }
  986. #endif
  987.           ReadCdRom( get_scsi_p(), p->data, lSector, SectorBurst );
  988.           if (NULL ==
  989.                  (newbuf = synchronize( p->data, SectorBurst*CD_FRAMESAMPLES,
  990.                  nSamplesToDo-global.iloop ))) {
  991.     /* could not synchronize!
  992.      * Try to invalidate the cdrom cache.
  993.      * Increase overlap setting, if possible.
  994.      */
  995.            /*trash_cache(p->data, lSector, SectorBurst);*/
  996.     if (global.overlap < global.nsectors - 1) {
  997.         global.overlap++;
  998. lSector--;
  999.   SectorBurst =  calc_SectorBurst();
  1000. #ifdef DEBUG_DYN_OVERLAP
  1001. fprintf(stderr, "using increased overlap of %un", global.overlap);
  1002. #endif
  1003.     } else {
  1004. lSector += global.overlap - 1;
  1005. global.overlap = 1;
  1006. SectorBurst =  calc_SectorBurst();
  1007.     }
  1008.   } else
  1009. break;
  1010.       } while (++retry_count < MAX_READRETRY);
  1011.       if (retry_count == MAX_READRETRY && newbuf == NULL && global.verbose != 0) {
  1012.         (*total_unsuccessful_retries)++;
  1013.       }
  1014.       if (newbuf) {
  1015.         offset = newbuf - ((unsigned char *)p->data);
  1016.       } else {
  1017.         offset = global.overlap * CD_FRAMESIZE_RAW;
  1018.       }
  1019.       set_offset(p,offset);
  1020.       /* how much has been added? */
  1021.       added_size = SectorBurst * CD_FRAMESAMPLES - offset/4;
  1022.       if (newbuf && nSamplesToDo != global.iloop) {
  1023. minover = min(global.overlap, minover);
  1024. maxover = max(global.overlap, maxover);
  1025. /* should we reduce the overlap setting ? */
  1026. if (offset > CD_FRAMESIZE_RAW && global.overlap > 1) {
  1027. #ifdef DEBUG_DYN_OVERLAP
  1028.           fprintf(stderr, "decreasing overlap from %u to %u (jitter %d)n", global.overlap, global.overlap-1, offset - (global.overlap)*CD_FRAMESIZE_RAW);
  1029. #endif
  1030.   global.overlap--;
  1031.   SectorBurst =  calc_SectorBurst();
  1032. }
  1033.       }
  1034.       if (global.iloop >= added_size)
  1035.         global.iloop -= added_size;
  1036.       else
  1037.         global.iloop = 0;
  1038.       if (global.verbose) {
  1039. unsigned per;
  1040. #ifdef PERCENTAGE_PER_TRACK
  1041.         /* Thomas Niederreiter wants percentage per track */
  1042. unsigned start_in_track = max(BeginAtSample,
  1043.                   g_toc[current_track-1].dwStartSector*CD_FRAMESAMPLES);
  1044. per = min(BeginAtSample+nSamplesToDo,
  1045.   g_toc[current_track].dwStartSector*CD_FRAMESAMPLES)
  1046. - start_in_track;
  1047. per = (BeginAtSample+nSamplesToDo-global.iloop
  1048. - start_in_track
  1049.       )/(per/100);
  1050. #else
  1051. per = global.iloop ? (nSamplesToDo-global.iloop)/(nSamplesToDo/100) : 100;
  1052. #endif
  1053. if (global.overlap > 0) {
  1054.           fprintf(stderr, "r%2d/%2d/%2d/%7d %3d%%",
  1055.            minover, maxover, global.overlap,
  1056.            newbuf ? offset - global.overlap*CD_FRAMESIZE_RAW : 9999999,
  1057. per);
  1058.   fflush(stderr);
  1059. } else if (oper != per) {
  1060.           fprintf(stderr, "r%3d%%", per);
  1061.   fflush(stderr);
  1062.   oper = per;
  1063. }
  1064.       }
  1065.       lSector += SectorBurst - global.overlap;
  1066. #if defined PERCENTAGE_PER_TRACK && defined HAVE_FORK_AND_SHAREDMEM
  1067.       while (lSector >= (int)g_toc[current_track].dwStartSector) {
  1068. current_track++;
  1069.       }
  1070. #endif
  1071.       return offset;
  1072. }
  1073. static unsigned long do_write __PR((myringbuff *p));
  1074. static unsigned long do_write (p)
  1075. myringbuff *p;
  1076. {
  1077.       int current_offset;
  1078.       unsigned int InSamples;
  1079.       current_offset = get_offset(p);
  1080.       /* how many bytes are available? */
  1081.       InSamples = global.nsectors*CD_FRAMESAMPLES - current_offset/4;
  1082.       /* how many samples are wanted? */
  1083.       InSamples = min((nSamplesToDo-nSamplesDone),InSamples);
  1084.       /* when track end is reached, close current file and start a new one */
  1085.       while ((nSamplesDone < nSamplesToDo) && (InSamples != 0)) {
  1086. long unsigned int how_much = InSamples;
  1087. long int left_in_track;
  1088. left_in_track  = (int)g_toc[current_track].dwStartSector*CD_FRAMESAMPLES
  1089.  - (int)(BeginAtSample+nSamplesDone);
  1090. if (left_in_track < 0) {
  1091. fprintf(stderr, "internal error: negative left_in_track:%ldn",left_in_track);
  1092. }
  1093. if (bulk)
  1094.   how_much = min(how_much, (unsigned long) left_in_track);
  1095. #ifdef MD5_SIGNATURES
  1096. if (global.md5count) {
  1097.   MD5Update (&global.context, ((unsigned char *)p->data) +current_offset, min(global.md5count,how_much));
  1098.   global.md5count -= min(global.md5count,how_much);
  1099. }
  1100. #endif
  1101. if ( SaveBuffer ( p->data + current_offset/4,
  1102.  how_much,
  1103.  &nSamplesDone) ) {
  1104.   if (global.have_forked == 1) {
  1105.     /* kill parent */
  1106.     kill(getppid(), SIGINT);
  1107.   }
  1108.   exit(20);
  1109. }
  1110.         global.nSamplesDoneInTrack += how_much;
  1111. SamplesToWrite -= how_much;
  1112. /* move residual samples upto buffer start */
  1113. if (how_much < InSamples) 
  1114. movebytes(
  1115.   (char *)(p->data) + current_offset + how_much*4,
  1116.   (char *)(p->data) + current_offset,
  1117.   (InSamples - how_much) * 4);
  1118. if ((unsigned long) left_in_track < InSamples) {
  1119.   if (bulk) {
  1120.     /* finish sample file for this track */
  1121.     CloseAudio(global.fname_base, current_track, bulk, global.channels,
  1122.      global.nSamplesDoneInTrack, global.audio_out);
  1123.     any_signal = 0;
  1124.           } else if (SamplesToWrite == 0) {
  1125.     /* finish sample file for this track */
  1126.     CloseAudio(global.fname_base, track, bulk, global.channels,
  1127.      (unsigned int) nSamplesToDo, global.audio_out);
  1128.   }
  1129.   if (global.verbose) {
  1130.     if (global.tracktitle[current_track -1] != NULL) {
  1131.       fprintf( stderr, "  track %2u '%s' successfully recordedn", 
  1132. current_track, global.tracktitle[current_track-1]);
  1133.             } else {
  1134.       fprintf( stderr, "  track %2u successfully recordedn", current_track);
  1135.             }
  1136.           }
  1137.           global.nSamplesDoneInTrack = 0;
  1138.   if ( bulk && SamplesToWrite > 0 ) {
  1139.     if ( !global.no_file ) {
  1140.       char *tmp_fname;
  1141.       /* build next filename */
  1142.       tmp_fname = get_next_name();
  1143.       if (tmp_fname != NULL) {
  1144.       strncpy(global.fname_base , tmp_fname, sizeof global.fname_base);
  1145.       global.fname_base[sizeof(global.fname_base)-1]=0;
  1146.       }
  1147.       tmp_fname = cut_extension(global.fname_base);
  1148.       tmp_fname[0] = '';
  1149.       if (global.multiname == 0) {
  1150. sprintf(fname, "%s_%02u.%s",global.fname_base,current_track+1,
  1151. audio_type);
  1152.       } else {
  1153. sprintf(fname, "%s.%s",global.fname_base, audio_type);
  1154.       }
  1155.       OpenAudio( fname, rate, bits, global.channels,
  1156. (g_toc[current_track].dwStartSector -
  1157.  g_toc[current_track-1].dwStartSector)*CD_FRAMESIZE_RAW,
  1158. global.audio_out);
  1159.     }
  1160.   }
  1161.   current_track++;
  1162. }
  1163. InSamples -= how_much;
  1164.       }  /* end while */
  1165.       return nSamplesDone;
  1166. }
  1167. #define PRINT_OVERLAP_INIT 
  1168.    if (global.verbose) { 
  1169. if (global.overlap > 0) 
  1170. fprintf(stderr, "overlap:min/max/cur, jitter, percent_done:n??/??/??/???????   0%%"); 
  1171. else 
  1172. fputs("percent_done:n  0%", stderr); 
  1173.    }
  1174. #if defined HAVE_FORK_AND_SHAREDMEM
  1175. static void forked_read __PR((void));
  1176. /* This function does all audio cdrom reads
  1177.  * until there is nothing more to do
  1178.  */
  1179. static void
  1180. forked_read()
  1181. {
  1182.    unsigned total_unsuccessful_retries = 0;
  1183. #if !defined(HAVE_SEMGET) || !defined(USE_SEMAPHORES)
  1184.    init_child();
  1185. #endif
  1186.    minover = global.nsectors;
  1187.    PRINT_OVERLAP_INIT
  1188.    while (global.iloop) { 
  1189.       do_read(get_next_buffer(), &total_unsuccessful_retries);
  1190.       define_buffer();
  1191.    } /* while (global.iloop) */
  1192.    flush_buffers();
  1193.    if (total_unsuccessful_retries) {
  1194.       fprintf(stderr,"%u unsuccessful matches while readingn",total_unsuccessful_retries);
  1195.    }
  1196. }
  1197. static void forked_write __PR((void));
  1198. static void
  1199. forked_write()
  1200. {
  1201.     /* don't need these anymore.  Good security policy says we get rid
  1202.        of them ASAP */
  1203.     neverneedroot();
  1204.     neverneedgroup();
  1205. #if defined(HAVE_SEMGET) && defined(USE_SEMAPHORES)
  1206. #else
  1207.     init_parent();
  1208. #endif
  1209.     while (nSamplesDone < nSamplesToDo) {
  1210.       /* get oldest buffers */
  1211.       
  1212.       nSamplesDone = do_write(get_oldest_buffer());
  1213.       if (global.parent_died == 0) {
  1214.         drop_buffer();
  1215.       }
  1216.     } /* end while */
  1217.     if (global.verbose) {
  1218.       if (global.tracktitle[current_track -1] != NULL) {
  1219.         fprintf( stderr, "  track %2u '%s' successfully recordedn",
  1220. current_track, global.tracktitle[current_track-1]);
  1221.       } else {
  1222.         fprintf( stderr, "  track %2u successfully recordedn", current_track);
  1223.       }
  1224.     }
  1225. }
  1226. #else
  1227. /* This function implements the read and write calls in one loop (in case
  1228.  * there is no fork/thread_create system call).
  1229.  * This means reads and writes have to wait for each other to complete.
  1230.  */
  1231. static void nonforked_loop __PR((void));
  1232. static void
  1233. nonforked_loop()
  1234. {
  1235.     unsigned total_unsuccessful_retries = 0;
  1236.     minover = global.nsectors;
  1237.     PRINT_OVERLAP_INIT
  1238.     while (global.iloop) { 
  1239.       do_read(get_next_buffer(), &total_unsuccessful_retries);
  1240.       do_write(get_oldest_buffer());
  1241.     }
  1242.     if (total_unsuccessful_retries) {
  1243.       fprintf(stderr,"%u unsuccessful matches while readingn",total_unsuccessful_retries);
  1244.     }
  1245.     if (global.verbose) {
  1246.       if (global.tracktitle[current_track -1] != NULL) {
  1247.         fprintf( stderr, "  track %2u '%s' successfully recordedn",
  1248. current_track, global.tracktitle[current_track-1]);
  1249.       } else {
  1250.         fprintf( stderr, "  track %2u successfully recordedn", current_track);
  1251.       }
  1252.     }
  1253. }
  1254. #endif
  1255. /* and finally: the MAIN program */
  1256. int main( argc, argv )
  1257. int argc;
  1258. char *argv [];
  1259. {
  1260.   long lSector_p1;
  1261.   long sector_offset = 0;
  1262.   unsigned long endtrack = 1;
  1263.   double rectime = DURATION;
  1264.   int cd_index = -1;
  1265.   double int_part;
  1266.   int littleendian = -1;
  1267.   int just_the_toc = 0;
  1268.   char int_name[100];
  1269. #ifdef  ECHO_TO_SOUNDCARD
  1270.   static char user_sound_device[200] = "";
  1271. #endif /* ECHO_TO_SOUNDCARD */
  1272.   int c;
  1273. #ifdef USE_GETOPT_LONG
  1274.   int long_option_index=0;
  1275. #endif /* USE_GETOPT_LONG */
  1276.   int am_i_cdda2wav;
  1277.   char * env_p;
  1278.   int tracks_included;
  1279.   strcpy(int_name, DEF_INTERFACE);
  1280.   strcpy(audio_type, AUDIOTYPE);
  1281.   save_args(argc, argv);
  1282.   /* init global variables */
  1283.   init_globals();
  1284.   /* When being invoked as list_audio_tracks, just dump a list of
  1285.      audio tracks. */
  1286.   am_i_cdda2wav = strcmp(argv[0],"list_audio_tracks");
  1287.   if (!am_i_cdda2wav) global.verbose = SHOW_JUSTAUDIOTRACKS;
  1288.   /* Control those set-id privileges... */
  1289.   initsecurity();
  1290.   env_p = getenv("CDDA_DEVICE");
  1291.   if (env_p != NULL) {
  1292.     strncpy( global.dev_name, env_p, sizeof(global.dev_name) );
  1293.     global.dev_name[sizeof(global.dev_name)-1]=0;
  1294.   }
  1295.   /* command options parsing */
  1296. #ifdef USE_GETOPT_LONG
  1297.   while ( (c = getopt_long (argc,argv,optstring,options,&long_option_index)) 
  1298. != EOF)
  1299. #else
  1300.   while ( (c = getopt(argc, argv, optstring)) != EOF )
  1301. #endif /* USE_GETOPT_LONG */
  1302. {
  1303.     switch (c) {
  1304.       case 'D':    /* override device */
  1305.         strncpy( global.dev_name, optarg, sizeof(global.dev_name) );
  1306.         global.dev_name[sizeof(global.dev_name)-1]=0;
  1307. break;
  1308.       case 'A':    /* override device */
  1309.         strncpy( global.aux_name, optarg, sizeof(global.aux_name) );
  1310.         global.aux_name[sizeof(global.aux_name)-1]=0;
  1311. break;
  1312.       case 'I':    /* override interface */
  1313. strncpy( int_name, optarg, sizeof(int_name) );
  1314.         int_name[sizeof(int_name)-1]=0;
  1315. break;
  1316. #ifdef  ECHO_TO_SOUNDCARD
  1317.       case 'K':    /* override sound device */
  1318. strncpy( user_sound_device, optarg, sizeof(user_sound_device) );
  1319.         user_sound_device[sizeof(user_sound_device)-1]=0;
  1320. break;
  1321. #endif /* ECHO_TO_SOUNDCARD */
  1322.       /* the following options are relevant to 'cdda2wav' only */
  1323. #ifdef MD5_SIGNATURES
  1324.       case 'M':
  1325.         if (!am_i_cdda2wav) break;
  1326. global.md5blocksize = strtoul( optarg, NULL, 10 );
  1327.         break;
  1328. #endif
  1329.       case 'O':    /* override audio type */
  1330.         if (!am_i_cdda2wav) break;
  1331. strncpy( audio_type, optarg, 4);
  1332.         audio_type[sizeof(audio_type)-1]=0;
  1333. break;
  1334.       case 'C':    /* override input endianess */
  1335.         if (!am_i_cdda2wav) break;
  1336. if (strcasecmp(optarg, "little") == 0) {
  1337.    littleendian = 1;
  1338. } else 
  1339. if (strcasecmp(optarg, "big") == 0) {
  1340.    littleendian = 0;
  1341. } else 
  1342. if (strcasecmp(optarg, "guess") == 0) {
  1343.    littleendian = -2;
  1344. } else {
  1345.    usage2("wrong parameter '%s' for option -C", optarg);
  1346. }
  1347. break;
  1348.       case 'E':    /* override output endianess */
  1349.         if (!am_i_cdda2wav) break;
  1350. if (strcasecmp(optarg, "little") == 0) {
  1351.    global.outputendianess = LITTLE;
  1352. } else 
  1353. if (strcasecmp(optarg, "big") == 0) {
  1354.    global.outputendianess = BIG;
  1355. } else {
  1356.    usage2("wrong parameter '%s' for option -E", optarg);
  1357. }
  1358. break;
  1359.       case 'c':    /* override channels */
  1360.         if (!am_i_cdda2wav) break;
  1361. if (optarg[0] == 's') {
  1362. global.channels = 2;
  1363. global.swapchannels = 1;
  1364. } else {
  1365. global.channels = strtol( optarg, NULL, 10);
  1366. }
  1367. break;
  1368.       case 'S':    /* override drive speed */
  1369.         if (!am_i_cdda2wav) break;
  1370. global.userspeed = strtoul( optarg, NULL, 10);
  1371. break;
  1372.       case 'l':    /* install a ring buffer with 'buffers' elements */
  1373.         if (!am_i_cdda2wav) break;
  1374.         global.buffers = strtoul( optarg, NULL, 10);
  1375.         break;
  1376.       case 'b':    /* override bits */
  1377.         if (!am_i_cdda2wav) break;
  1378. bits = strtol( optarg, NULL, 10);
  1379. break;
  1380.       case 'r':    /* override rate */
  1381.         if (!am_i_cdda2wav) break;
  1382. rate = strtol( optarg, NULL, 10);
  1383. break;
  1384.       case 'a':    /* override rate */
  1385.         if (!am_i_cdda2wav) break;
  1386. if (strtod( optarg, NULL ) != 0.0)
  1387.     rate = 44100.0 / strtod( optarg, NULL );
  1388. else {
  1389.     fprintf(stderr, "-a requires a nonzero, positive divider.n");
  1390.     exit ( 1 );
  1391. }
  1392. break;
  1393.       case 't':    /* override start track */
  1394.         if (!am_i_cdda2wav) break;
  1395. {
  1396. char * endptr;
  1397. char * endptr2;
  1398. track = strtoul( optarg, &endptr, 10 );
  1399. endtrack = strtoul( endptr, &endptr2, 10 );
  1400. if (endptr2 == endptr)
  1401. endtrack = track;
  1402. break;
  1403. }
  1404.       case 'i':    /* override start index */
  1405.         if (!am_i_cdda2wav) break;
  1406. cd_index = strtoul( optarg, NULL, 10);
  1407. break;
  1408.       case 'd':    /* override recording time */
  1409.         if (!am_i_cdda2wav) break;
  1410. /* we accept multiple formats now */
  1411. { char *end_ptr = NULL;
  1412.   rectime = strtod( optarg, &end_ptr );
  1413.   if (*end_ptr == '') {
  1414.   } else if (*end_ptr == 'f') {
  1415.     rectime = rectime / 75.0;
  1416. /* TODO: add an absolute end of recording. */
  1417. #if 0
  1418.   } else if (*end_ptr == 'F') {
  1419.     rectime = rectime / 75.0;
  1420. #endif
  1421.   } else
  1422.     rectime = -1.0;
  1423. }
  1424. break;
  1425.       case 'o':    /* override offset */
  1426.         if (!am_i_cdda2wav) break;
  1427. sector_offset = strtol( optarg, NULL, 10);
  1428. break;
  1429.       case 'n':    /* read sectors per request */
  1430.         if (!am_i_cdda2wav) break;
  1431. global.nsectors = strtoul( optarg, NULL, 10);
  1432. break;
  1433.        /*-------------- RS 98 -------------*/
  1434.       case 'p':    /* specify playback pitch rate */
  1435.         global.playback_rate = strtol( optarg, NULL, 10);
  1436.         RestrictPlaybackRate( global.playback_rate );
  1437.         global.need_hostorder = 1;
  1438.         break;
  1439.       case 'P':    /* set initial overlap sectors */
  1440.         if (!am_i_cdda2wav) break;
  1441. global.useroverlap = strtol( optarg, NULL, 10);
  1442. break;
  1443.       case 's':    /* stereo */
  1444.         if (!am_i_cdda2wav) break;
  1445. global.channels = 2;
  1446. break;
  1447.       case 'm':    /* mono */
  1448.         if (!am_i_cdda2wav) break;
  1449. global.channels = 1;
  1450.         global.need_hostorder = 1;
  1451. break;
  1452.       case 'x':    /* max */
  1453.         if (!am_i_cdda2wav) break;
  1454. global.channels = 2; bits = 16; rate = 44100;
  1455. break;
  1456.       case 'w':    /* wait for some audio intensity */
  1457.         if (!am_i_cdda2wav) break;
  1458. waitforsignal = 1;
  1459. break;
  1460.       case 'F':    /* find extreme amplitudes */
  1461.         if (!am_i_cdda2wav) break;
  1462. global.findminmax = 1;
  1463.         global.need_hostorder = 1;
  1464. break;
  1465.       case 'G':    /* find if mono */
  1466.         if (!am_i_cdda2wav) break;
  1467. global.findmono = 1;
  1468. break;
  1469.       case 'e':    /* echo to soundcard */
  1470.         if (!am_i_cdda2wav) break;
  1471. #ifdef ECHO_TO_SOUNDCARD
  1472. global.echo = 1;
  1473.         global.need_hostorder = 1;
  1474. #else
  1475. fprintf(stderr, "There is no sound support compiled into %s.n",argv[0]);
  1476. #endif
  1477. break;
  1478.       case 'v':    /* tell us more */
  1479.         if (!am_i_cdda2wav) break;
  1480. global.verbose = strtol( optarg, NULL, 10);
  1481. break;
  1482.       case 'q':    /* be quiet */
  1483.         if (!am_i_cdda2wav) break;
  1484. global.quiet = 1;
  1485. global.verbose = 0;
  1486. break;
  1487.       case 'N':    /* don't write to file */
  1488.         if (!am_i_cdda2wav) break;
  1489. global.no_file = 1;
  1490. global.no_infofile = 1;
  1491. global.no_cddbfile = 1;
  1492. break;
  1493.       case 'J':    /* information only */
  1494.         if (!am_i_cdda2wav) break;
  1495. global.verbose = SHOW_MAX;
  1496. just_the_toc = 1;
  1497. bulk = 1;
  1498. break;
  1499.       case 'g':    /* screen output formatted for guis */
  1500.         if (!am_i_cdda2wav) break;
  1501. #ifdef Thomas_will_es
  1502. global.no_file = 1;
  1503. global.no_infofile = 1;
  1504. global.no_cddbfile = 1;
  1505. global.verbose = SHOW_MAX;
  1506. #endif
  1507. global.gui = 1;
  1508. break;
  1509.       case 'Q':   /* silent scsi mode */
  1510. global.scsi_silent = 1;
  1511. break;
  1512.       case 'H':    /* don't write extra files */
  1513.         if (!am_i_cdda2wav) break;
  1514. global.no_infofile = 1;
  1515. global.no_cddbfile = 1;
  1516. break;
  1517.       case 'B':    /* bulk transfer */
  1518.         if (!am_i_cdda2wav) break;
  1519. bulk = 1;
  1520. break;
  1521.       case 'T':    /* do deemphasis on the samples */
  1522.         if (!am_i_cdda2wav) break;
  1523. global.deemphasize = 1;
  1524.         global.need_hostorder = 1;
  1525. break;
  1526.       case 'R':    /* list available rates */
  1527.         if (!am_i_cdda2wav) break;
  1528. { int ii;
  1529.   fprintf(stderr, "Cdda2wav version %s: available rates are:nRate   Divider      Rate   Divider      Rate   Divider      Rate   Dividern", VERSION );
  1530.   for (ii = 1; ii <= 44100 / 880 / 2; ii++) {
  1531.     long i2 = ii;
  1532.     fprintf(stderr, "%-7g  %2ld         %-7g  %2ld.5       ",
  1533.                     44100.0/i2,i2,44100/(i2+0.5),i2);
  1534.     i2 += 25;
  1535.     fprintf(stderr, "%-7g  %2ld         %-7g  %2ld.5n",
  1536.                     44100.0/i2,i2,44100/(i2+0.5),i2);
  1537.     i2 -= 25;
  1538.   }
  1539. }
  1540. exit(0);
  1541. break;
  1542.       case 'V':
  1543.         if (!am_i_cdda2wav) break;
  1544. global.scsi_verbose++; /* XXX nach open_scsi() scgp->verbose = .. !!!! */
  1545. break;
  1546.       case 'h':
  1547. usage();
  1548. break;
  1549.       default:
  1550. #ifdef USE_GETOPT_LONG
  1551. fputs ("use cdda2wav --help to get more information.n", stderr);
  1552. #else
  1553. fputs ("use cdda2wav -h to get more information.n", stderr);
  1554. #endif
  1555. exit (1);
  1556.     }
  1557.   }
  1558.   /* check all parameters */
  1559.   if (global.verbose < 0 || global.verbose > SHOW_MAX) {
  1560.     usage2("Incorrect verbose level setting: %d",global.verbose);
  1561.   }
  1562.   if (global.verbose == 0) global.quiet = 1;
  1563.   if ( rectime < 0.0 ) {
  1564.     usage2("Incorrect recording time setting: %d.%02d",
  1565. (int)rectime, (int)(rectime*100+0.5) % 100);
  1566.   }
  1567.   if ( global.channels != 1 && global.channels != 2 ) {
  1568.     usage2("Incorrect channel setting: %d",global.channels);
  1569.   }
  1570.   if ( bits != 8 && bits != 12 && bits != 16 ) {
  1571.     usage2("Incorrect bits_per_sample setting: %d",bits);
  1572.   }
  1573.   if ( rate < 827.0 || rate > 44100.0 ) {
  1574.     usage2("Incorrect sample rate setting: %d.%02d",
  1575. (int)rate, ((int)rate*100) % 100);
  1576.   }
  1577.   int_part = (double)(long) (2*44100.0 / rate);
  1578.   
  1579.   if (2*44100.0 / rate - int_part >= 0.5 ) {
  1580.       int_part += 1.0;
  1581.       fprintf( stderr, "Nearest available sample rate is %d.%02d Hertzn",
  1582.       2*44100 / (int)int_part,
  1583.       (2*4410000 / (int)int_part) % 100);
  1584.   }
  1585.   Halved = ((int) int_part) & 1;
  1586.   rate = 2*44100.0 / int_part;
  1587.   undersampling = (int) int_part / 2.0;
  1588.   samples_to_do = undersampling;
  1589.   if (!strcmp((char *)int_name,"generic_scsi"))
  1590.       interface = GENERIC_SCSI;
  1591.   else if (!strcmp((char *)int_name,"cooked_ioctl"))
  1592.       interface = COOKED_IOCTL;
  1593.   else  {
  1594.     usage2("Incorrect interface setting: %s",int_name);
  1595.   }
  1596.   /* If we need to calculate with samples or write them to a soundcard,
  1597.    * we need a conversion to host byte order.
  1598.    */ 
  1599.   if (global.channels != 2 
  1600.       || bits != 16
  1601.       || rate != 44100)
  1602. global.need_hostorder = 1;
  1603.   /* check * init audio file */
  1604.   if (!strncmp(audio_type,"wav",3)) {
  1605.     global.audio_out = &wavsound;
  1606.   } else if (!strncmp(audio_type, "sun", 3) || !strncmp(audio_type, "au", 2)) {
  1607.     /* Enhanced compatibility */
  1608.     strcpy(audio_type, "au");
  1609.     global.audio_out = &sunsound;
  1610.   } else if (!strncmp(audio_type, "cdr", 3) || 
  1611.              !strncmp(audio_type, "raw", 3)) {
  1612.     global.audio_out = &rawsound;
  1613.   } else if (!strncmp(audio_type, "aiff", 4)) {
  1614.     global.audio_out = &aiffsound;
  1615.   } else if (!strncmp(audio_type, "aifc", 4)) {
  1616.     global.audio_out = &aifcsound;
  1617.   } else {
  1618.     usage2("Incorrect audio type setting: %3s", audio_type);
  1619.   }
  1620.   global.need_big_endian = global.audio_out->need_big_endian;
  1621.   if (global.outputendianess != NONE)
  1622.     global.need_big_endian = global.outputendianess == BIG;
  1623.   if (global.no_file) global.fname_base[0] = '';
  1624.   if (!bulk) {
  1625.     strcat(global.fname_base, ".");
  1626.     strcat(global.fname_base, audio_type);
  1627.   }
  1628.   /*
  1629.    * all options processed.
  1630.    * Now a file name per track may follow 
  1631.    */
  1632.   argc2 = argc3 = argc - optind;
  1633.   argv2 = argv + optind;
  1634.   if ( optind < argc ) {
  1635.     if (!strcmp(argv[optind],"-")) {
  1636.       /*
  1637.        * pipe mode
  1638.        */
  1639.       if (bulk == 1) {
  1640.         fprintf(stderr, "bulk mode disabled while outputting to a pipen");
  1641.         bulk = 0;
  1642.       }
  1643. #if     defined(__CYGWIN32__) || defined(__EMX__)
  1644.       setmode(fileno(stdout), O_BINARY);
  1645. #endif
  1646.       global.audio = dup (fileno(stdout));
  1647.       strncpy( global.fname_base, "standard output", sizeof(global.fname_base) );
  1648.       global.fname_base[sizeof(global.fname_base)-1]=0;
  1649.       global.no_infofile = 1;
  1650.       global.no_cddbfile = 1;
  1651.     } else if (optind + 1 < argc) {
  1652. /* do we have more than one argument? */
  1653. global.multiname = 1;
  1654.     }
  1655.   }
  1656. #define SETSIGHAND(PROC, SIG, SIGNAME) if (signal(SIG, PROC) == SIG_ERR) 
  1657. { fprintf(stderr, "cannot set signal %s handlern", SIGNAME); exit(1); }
  1658.     SETSIGHAND(exit, SIGINT, "SIGINT")
  1659.     SETSIGHAND(exit, SIGQUIT, "SIGQUIT")
  1660.     SETSIGHAND(exit, SIGTERM, "SIGTERM")
  1661.     SETSIGHAND(exit, SIGHUP, "SIGHUP")
  1662.     SETSIGHAND(set_nonforked, SIGPIPE, "SIGPIPE")
  1663.   /* setup interface and open cdrom device */
  1664.   /* request sychronization facilities and shared memory */
  1665.   SetupInterface( );
  1666. #if defined(HAVE_SEMGET) && defined(USE_SEMAPHORES)
  1667.   atexit ( free_sem );
  1668. #endif
  1669.   /*
  1670.    * set input endian default
  1671.    */
  1672.   if (littleendian != -1)
  1673.     *in_lendian = littleendian;
  1674.   /* get table of contents */
  1675.   cdtracks = ReadToc( get_scsi_p(), g_toc );
  1676.   if (cdtracks == 0) {
  1677.     fprintf(stderr, "No track in table of contents! Aborting...n");
  1678.     exit(10);
  1679.   }
  1680.   if (ReadTocText != NULL) ReadTocText(get_scsi_p());
  1681.   handle_cdtext();
  1682.   calc_cddb_id();
  1683.   calc_cdindex_id();
  1684.   if ( global.verbose == SHOW_JUSTAUDIOTRACKS ) {
  1685.     unsigned int z;
  1686.     for (z = 0; z < cdtracks; z++)
  1687. if ((g_toc[z].bFlags & CDROM_DATA_TRACK) == 0)
  1688.   printf("%02dt%06un", g_toc[z].bTrack, g_toc[z].dwStartSector);
  1689.     exit(0);
  1690.   }
  1691.   if ( global.verbose != 0 ) {
  1692.     fputs( "#Cdda2wav version ", stderr );
  1693.     fputs( VERSION, stderr );
  1694. #if defined _POSIX_PRIORITY_SCHEDULING || defined HAVE_SYS_PRIOCNTL_H
  1695.     fputs( " real time sched.", stderr );
  1696. #endif
  1697. #if defined ECHO_TO_SOUNDCARD
  1698.     fputs( " soundcard support", stderr );
  1699. #endif
  1700.     fputs( "n", stderr );
  1701.   }
  1702.   have_CD_extra = FixupTOC(cdtracks + 1);
  1703.   if ( global.verbose & (SHOW_TOC | SHOW_STARTPOSITIONS) )
  1704.     DisplayToc ();
  1705.   /* use global.useroverlap to set our overlap */
  1706.   if (global.useroverlap != -1)
  1707. global.overlap = global.useroverlap;
  1708.   if (global.nsectors < 1+global.overlap) {
  1709.       usage2("Overlap (%d) is greater or equal than nsectors (%d)nUse -P to set the overlap sectors and -n to set the nsectors",global.overlap, global.nsectors);
  1710.   }
  1711.   /* try to get some extra kicks */
  1712.   needroot(0);
  1713. #if defined(HAVE_NICE) && (HAVE_NICE == 1)
  1714.   nice(-20);
  1715. #endif
  1716.   dontneedroot();
  1717.   /* switch cdrom to audio mode */
  1718.   EnableCdda (get_scsi_p(), 1);
  1719.   atexit ( CloseAll );
  1720.   if ( !FirstAudioTrack () )
  1721.     FatalError ( "This disk has no audio tracksn" );
  1722.   if ( global.verbose & (SHOW_MCN | SHOW_ISRC) )
  1723.     Read_MCN_ISRC();
  1724.   /* check if start track is in range */
  1725.   if ( track < 1 || track > cdtracks ) {
  1726.     usage2("Incorrect start track setting: %d",track);
  1727.   }
  1728.   /* check if end track is in range */
  1729.   if ( endtrack < track || endtrack > cdtracks ) {
  1730.     usage2("Incorrect end track setting: %ld",endtrack);
  1731.   }
  1732.   do {
  1733.     lSector = GetStartSector ( track );
  1734.     lSector_p1 = GetEndSector ( track ) + 1;
  1735.     if ( lSector < 0 ) {
  1736.       if ( bulk == 0 ) {
  1737.         FatalError ( "track %d not foundn", track );
  1738.       } else {
  1739.         fprintf(stderr, "Skipping data track %d...n", track);
  1740. if (endtrack == track) endtrack++;
  1741.         track++;
  1742.       }
  1743.     }
  1744.   } while (bulk != 0 && track <= cdtracks && lSector < 0);
  1745.   if (cd_index != -1) {
  1746.     if (global.verbose && !global.quiet) {
  1747.       global.verbose |= SHOW_INDICES;
  1748.     }
  1749.     sector_offset += ScanIndices( track, cd_index, bulk );
  1750.   } else {
  1751.     cd_index = 1;
  1752.     if (global.verbose & SHOW_INDICES) {
  1753.       ScanIndices( track, cd_index, bulk );
  1754.     }
  1755.   }
  1756.   lSector += sector_offset;
  1757.   /* check against end sector of track */
  1758.   if ( lSector >= lSector_p1 ) {
  1759.     fputs( "sector offset exceeds track size (ignored)n", stderr );
  1760.     lSector -= sector_offset;
  1761.   }
  1762.   if ( lSector < 0L ) {
  1763.     fputs( "negative start sector! Set to zero.n", stderr );
  1764.     lSector = 0L;
  1765.   }
  1766.   lSector_p2 = GetLastSectorOnCd( track );
  1767.   if (bulk == 1 && track == endtrack && rectime == 0.0)
  1768.      rectime = 99999.0;
  1769.   if ( rectime == 0.0 ) {
  1770.     /* set time to track time */
  1771.     nSamplesToDo = (lSector_p1 - lSector) * CD_FRAMESAMPLES;
  1772.     rectime = (lSector_p1 - lSector) / 75.0;
  1773.     if (CheckTrackrange( track, endtrack) == 1) {
  1774.       lSector_p2 = GetEndSector ( endtrack ) + 1;
  1775.       if (lSector_p2 >= 0) {
  1776.         rectime = (lSector_p2 - lSector) / 75.0;
  1777.         nSamplesToDo = (long)(rectime*44100.0 + 0.5);
  1778.       } else {
  1779.         fputs( "end track is no valid audio track (ignored)n", stderr );
  1780.       }
  1781.     } else {
  1782.       fputs( "track range does not consist of audio tracks only (ignored)n", stderr );
  1783.     }
  1784.   } else {
  1785.     /* Prepare the maximum recording duration.
  1786.      * It is defined as the biggest amount of
  1787.      * adjacent audio sectors beginning with the
  1788.      * specified track/index/offset. */
  1789.     if ( rectime > (lSector_p2 - lSector) / 75.0 ) {
  1790.       rectime = (lSector_p2 - lSector) / 75.0;
  1791.       lSector_p1 = lSector_p2;
  1792.     }
  1793.     /* calculate # of samples to read */
  1794.     nSamplesToDo = (long)(rectime*44100.0 + 0.5);
  1795.   }
  1796.   global.OutSampleSize = (1+bits/12);
  1797.   if (nSamplesToDo/undersampling == 0L) {
  1798.       usage2("Time interval is too short. Choose a duration greater than %d.%02d secs!", 
  1799.        undersampling/44100, (int)(undersampling/44100) % 100);
  1800.   }
  1801.   SamplesToWrite = nSamplesToDo*2/(int)int_part;
  1802.   tracks_included = GetTrack(
  1803.       (unsigned) (lSector + nSamplesToDo/CD_FRAMESAMPLES -1))
  1804.      - track + 1;
  1805.   if ( !waitforsignal ) {
  1806.       if (global.multiname != 0 && optind + tracks_included > argc) {
  1807. global.multiname = 0;
  1808.       }
  1809. #ifdef INFOFILES
  1810.       if (!global.no_infofile) {
  1811. int i;
  1812. for (i = track; i < track + tracks_included; i++) {
  1813. unsigned minsec, maxsec;
  1814.         char *tmp_fname;
  1815.         /* build next filename */
  1816.         tmp_fname = get_next_name();
  1817.         if (tmp_fname != NULL)
  1818.   strncpy( global.fname_base, tmp_fname, sizeof(global.fname_base)-8 );
  1819.   global.fname_base[sizeof(global.fname_base)-1]=0;
  1820. minsec = max(lSector, GetStartSector(i));
  1821. maxsec = min(lSector_p2, 1+GetEndSector(i));
  1822. write_info_file(global.fname_base,i,(maxsec-minsec)*CD_FRAMESAMPLES, bulk && global.multiname == 0);
  1823. if (!bulk) break;
  1824. }
  1825. reset_name_iterator();
  1826.       }
  1827. #endif
  1828.   }
  1829.   if (just_the_toc) exit(0);
  1830. #ifdef  ECHO_TO_SOUNDCARD
  1831.   if (user_sound_device[0] != '') {
  1832.       set_snd_device(user_sound_device);
  1833.   }
  1834.   init_soundcard(rate, bits);
  1835. #endif /* ECHO_TO_SOUNDCARD */
  1836.   if (global.userspeed > -1)
  1837.      global.speed = global.userspeed;
  1838.   if (global.speed != 0 && SelectSpeed != NULL) {
  1839.      SelectSpeed(get_scsi_p(), global.speed);
  1840.   }
  1841.   current_track = track;
  1842.   if ( !global.no_file ) {
  1843.     {
  1844.       char *myfname;
  1845.       myfname = get_next_name();
  1846.       if (myfname != NULL) {
  1847.         strncpy( global.fname_base, myfname, sizeof(global.fname_base)-8 );
  1848.         global.fname_base[sizeof(global.fname_base)-1]=0;
  1849.       }
  1850.     }
  1851.     /* strip audio_type extension */
  1852.     {
  1853.       char *cp = global.fname_base;
  1854.       cp = strrchr(cp, '.');
  1855.       if (cp == NULL) {
  1856. cp = global.fname_base + strlen(global.fname_base);
  1857.       }
  1858.       *cp = '';
  1859.     }
  1860.     if (bulk && global.multiname == 0) {
  1861.       sprintf(fname, "%s_%02u.%s",global.fname_base,current_track,audio_type);
  1862.     } else {
  1863.       sprintf(fname, "%s.%s",global.fname_base,audio_type);
  1864.     }
  1865.     OpenAudio( fname, rate, bits, global.channels, 
  1866.       (unsigned)(SamplesToWrite*global.OutSampleSize*global.channels),
  1867. global.audio_out);
  1868.   }
  1869.   global.Remainder = (75 % global.nsectors)+1;
  1870.   global.sh_bits = 16 - bits; /* shift counter */
  1871.   global.iloop = nSamplesToDo;
  1872.   if (Halved && (global.iloop&1))
  1873.       global.iloop += 2;
  1874.   BeginAtSample = lSector * CD_FRAMESAMPLES;
  1875.   if ( 1 ) {
  1876.       if ( (global.verbose & SHOW_SUMMARY) && !just_the_toc ) {
  1877. fprintf(stderr, "samplefile size will be %lu bytes.n",
  1878.            global.audio_out->GetHdrSize() + SamplesToWrite*global.OutSampleSize*global.channels  ); 
  1879.         fprintf (stderr, "recording %d.%05d seconds %s with %d bits @ %5d.%01d Hz"
  1880.       ,(int)rectime , (int)(rectime * 10000) % 10000,
  1881.       global.channels == 1 ? "mono":"stereo", bits, (int)rate, (int)(rate*10)%10);
  1882.         if (!global.no_file && *global.fname_base)
  1883. fprintf(stderr, " ->'%s'...", global.fname_base );
  1884.         fputs("n", stderr);
  1885.       }
  1886.   }
  1887. #if defined(HAVE_SEMGET) && defined(USE_SEMAPHORES)
  1888. #else
  1889.   init_pipes();
  1890. #endif
  1891. #if defined(HAVE_FORK_AND_SHAREDMEM)
  1892.   /* Everything is set up. Now fork and let one process read cdda sectors
  1893.      and let the other one store them in a wav file */
  1894.   /* forking */
  1895.   child_pid = fork();
  1896.   if (child_pid > 0 && global.gui > 0 && global.verbose > 0) fprintf( stderr, "child pid is %dn", child_pid);
  1897.   /*********************** fork **************************************/
  1898.   if (child_pid == 0) {
  1899.     /* child WRITER section */
  1900. #ifdef __EMX__
  1901.     if (DosGetSharedMem(fill_buffer, 3)) {
  1902.       comerr("DosGetSharedMem() failed.n");
  1903.     }
  1904. #endif
  1905.     global.have_forked = 1;
  1906.     forked_write();
  1907. #ifdef __EMX__
  1908.     DosFreeMem(fill_buffer);
  1909.     _exit(0);
  1910. #endif
  1911.     exit(0);
  1912.   } else if (child_pid > 0) {
  1913.     /* parent READER section */
  1914.     
  1915.     global.have_forked = 1;
  1916.     switch_to_realtime_priority();
  1917.     forked_read();
  1918. #ifdef __EMX__
  1919.     DosFreeMem(fill_buffer);
  1920. #endif
  1921.     exit(0);
  1922.   } else
  1923. #else
  1924.   /* version without fork */
  1925.   {
  1926.     global.have_forked = 0;
  1927.     switch_to_realtime_priority();
  1928.     fprintf(stderr, "a nonforking version is running...n");
  1929.     nonforked_loop();
  1930.     exit(0);
  1931.   }
  1932. #endif
  1933.   return 0;
  1934. }