home *** CD-ROM | disk | FTP | other *** search
/ Computer Installation Guide - Dragon Clan Series / CD2.iso / Audio / READCDA2 / READCDA2.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-09-12  |  27.0 KB  |  1,025 lines

  1. /*
  2.  
  3.   GOAL:
  4.     This program is intended to read CD audio data into a disk file.
  5.  
  6.   Author:
  7.     First version:
  8.       Yeng-Chee Su (yenchee@csie.nctu.edu.tw)
  9.       Department of Computer Science and Information Engineering
  10.       National Chiao Tung University
  11.     Later adapted and extended by:
  12.       Klaas Hemstra (hst@mh.nl)         Gouda, the Netherlands
  13.       Stewart Addison (tardis.ed.ac.uk) Edinburgh, Scotland
  14.  
  15.   Notice:
  16.     Most CD-ROM drive doesn't have the capability to read raw
  17.     data on compact disk, but some drives can work.  These includes
  18.     Panasonic CR-562B/563B and Toshiba XM-3401B.  This program
  19.     is designed on CR-562B and should work well on it.  If it
  20.     can't work for you, find a better driver around.
  21.     Yeng-Chee Su wrote the first attempt, but the program depended on
  22.     the speed of the file-system for clean 'recordings'.
  23.  
  24.     The buffered read + synchronisation is added later by me.
  25.  
  26.     Klaas Hemstra
  27.  
  28. */
  29.  
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <stdarg.h>
  33. #include <conio.h>
  34. #include <dos.h>
  35. #include <string.h>
  36. #include <ctype.h>
  37. #include <fcntl.h>
  38. #include <sys/stat.h>
  39. #include <io.h>
  40.  
  41. #include <sys/timeb.h>        /* Allows accurate timing - psyche */
  42.  
  43. #define MAXPATH 80        /* Compensates for the lack of dir.h <g> */
  44.  
  45. #define RAW_MODE 1
  46. #define COOKED_MODE 0
  47. #define READ_MODE RAW_MODE
  48. #if READ_MODE == COOKED_MODE
  49.   #define FRAME_SIZE 2048
  50. #else
  51.   #define FRAME_SIZE 2352
  52. #endif
  53.  
  54. /********** Some constants for the allocation of buffers etc. *********/
  55.  
  56. #define NBLOCK 8       /* Each buffer is 8x2352 = about 18K of data */
  57. #define BUFSIZE        (NBLOCK*FRAME_SIZE)  /* One buffer = 18K */
  58. #define SYNCH_SIZE 128  /* Bytes synch pattern (to start with) */
  59.  
  60. typedef unsigned char BYTE;
  61. typedef unsigned int WORD;
  62. typedef unsigned long int DWORD;
  63.  
  64. /************* Structures for calling the CD-ROM device driver *******/
  65.  
  66. struct ReqHdr {
  67.   BYTE len;
  68.   BYTE unit;
  69.   BYTE command;
  70.   WORD status;
  71.   BYTE reserved[8];
  72. };
  73.  
  74. struct IOCTLI {
  75.   struct ReqHdr req;
  76.   BYTE descriptor;
  77.   void far *address;
  78.   WORD len;
  79.   WORD secnum;
  80.   void far *ptr;
  81. };
  82.  
  83. struct DeviceStatus {
  84.   BYTE control;
  85.   DWORD param;
  86. };
  87.  
  88. struct DiskInfo {
  89.   BYTE control;
  90.   BYTE lowest;
  91.   BYTE highest;
  92.   DWORD total;
  93. };
  94.  
  95. struct TrackInfo {
  96.   BYTE control;
  97.   BYTE track;
  98.   DWORD loc;
  99.   BYTE info;
  100. };
  101.  
  102. struct SEEK {
  103.   struct ReqHdr req;
  104.   BYTE mode;
  105.   DWORD address;
  106.   WORD secnum;
  107.   DWORD loc;
  108. };
  109.  
  110. struct PlayReq {
  111.   struct ReqHdr req;
  112.   BYTE mode;
  113.   DWORD loc;
  114.   DWORD secnum;
  115. };
  116.  
  117. int CDROM;
  118. int lowest, highest;
  119. DWORD total_time;
  120. char image[MAXPATH];
  121.  
  122. void CallDevice(void *ptr)
  123. {
  124.   static union REGS reg;
  125.   static struct SREGS seg;
  126.  
  127.   segread(&seg);
  128.   seg.es=FP_SEG(ptr);
  129.   reg.x.ax=0x1510;
  130.   reg.x.bx=FP_OFF(ptr);
  131.   reg.x.cx=CDROM;
  132.   int86x(0x2f, ®, ®, &seg);
  133. }
  134.  
  135. int check_mscdex(void)
  136. {
  137.   union REGS reg;
  138.  
  139.   reg.x.ax=0x1500;
  140.   reg.x.bx=0;
  141.   int86(0x2f, ®, ®);
  142.   if (!reg.x.bx)
  143.     return 0;
  144.   else {
  145.     CDROM=reg.x.cx;
  146.     return 1;
  147.   }
  148. }
  149.  
  150. int GetDeviceStatus(void)
  151. {
  152.   struct IOCTLI cmd;
  153.   struct DeviceStatus buf;
  154.  
  155.   cmd.req.len=26;
  156.   cmd.req.unit=0;
  157.   cmd.req.command=3;
  158.   cmd.descriptor=0;
  159.   cmd.address=&buf;
  160.   cmd.len=5;
  161.   cmd.secnum=0;
  162.   cmd.ptr=NULL;
  163.   buf.control=6;
  164.   CallDevice(&cmd);
  165.   return cmd.req.status;
  166. }
  167.  
  168. int GetDiskInfo(void)
  169. {
  170.   struct IOCTLI cmd;
  171.   struct DiskInfo buf;
  172.  
  173.   cmd.req.len=26;
  174.   cmd.req.unit=0;
  175.   cmd.req.command=3;
  176.   cmd.descriptor=0;
  177.   cmd.address=&buf;
  178.   cmd.len=7;
  179.   cmd.secnum=0;
  180.   cmd.ptr=NULL;
  181.   buf.control=10;
  182.   CallDevice(&cmd);
  183.   lowest=buf.lowest;
  184.   highest=buf.highest;
  185.   total_time=buf.total;
  186.   return cmd.req.status;
  187. }
  188.  
  189. int GetTrackInfo(int track, DWORD *loc, BYTE *info)
  190. {
  191.   struct IOCTLI cmd;
  192.   struct TrackInfo buf;
  193.  
  194.   cmd.req.len=26;
  195.   cmd.req.unit=0;
  196.   cmd.req.command=3;
  197.   cmd.descriptor=0;
  198.   cmd.address=&buf;
  199.   cmd.len=7;
  200.   cmd.secnum=0;
  201.   cmd.ptr=NULL;
  202.   buf.control=11;
  203.   buf.track=track;
  204.   CallDevice(&cmd);
  205.   *loc=buf.loc;
  206.   *info=buf.info;
  207.   return cmd.req.status;
  208. }
  209.  
  210. int SeekTrack(DWORD loc)
  211. {
  212.   struct SEEK cmd;
  213.  
  214.   cmd.req.len=24;
  215.   cmd.req.unit=0;
  216.   cmd.req.command=131;
  217.   cmd.mode=1;
  218.   cmd.address=NULL;
  219.   cmd.secnum=0;
  220.   cmd.loc=loc;
  221.   CallDevice(&cmd);
  222.   return cmd.req.status;
  223. }
  224.  
  225. int PlayAudio(DWORD loc, DWORD num)
  226. {
  227.   struct PlayReq cmd;
  228.  
  229.   cmd.req.len=22;
  230.   cmd.req.unit=0;
  231.   cmd.req.command=132;
  232.   cmd.mode=1;
  233.   cmd.loc=loc;
  234.   cmd.secnum=num;
  235.   CallDevice(&cmd);
  236.   return cmd.req.status;
  237. }
  238.  
  239. int StopAudio(void)
  240. {
  241.   struct ReqHdr cmd;
  242.  
  243.   cmd.len=13;
  244.   cmd.unit=0;
  245.   cmd.command=133;
  246.   CallDevice(&cmd);
  247.   return cmd.status;
  248. }
  249.  
  250. DWORD Red2Sierra(DWORD loc)
  251. {
  252.   BYTE min, sec, frame;
  253.  
  254.   min = (loc >> 16) & 0xff;
  255.   sec = (loc >> 8) & 0xff;
  256.   frame = loc & 0xff;
  257.   return (DWORD)min * 75 * 60 + (DWORD)sec * 75 + (DWORD)frame - 150;
  258. }
  259.  
  260. int ReadLong(DWORD loc, WORD secnum, char far *buf)
  261. {
  262.   struct ReadL {
  263.     struct ReqHdr req;
  264.     BYTE mode;
  265.     void far *address;
  266.     WORD secnum;
  267.     DWORD loc;
  268.     BYTE readmode;
  269.     BYTE skip[2];
  270.   } cmd;
  271.  
  272.   cmd.req.len=sizeof(cmd);
  273.   cmd.req.unit=0;
  274.   cmd.req.command=128;
  275.   cmd.mode=0;
  276.   cmd.address=buf;
  277.   cmd.secnum=secnum;
  278.   cmd.loc=loc;
  279.   cmd.readmode=READ_MODE;
  280.   cmd.skip[0]=cmd.skip[1]=0;
  281.   CallDevice(&cmd);
  282.   return cmd.req.status;
  283. }
  284.  
  285. int GetVolSize(DWORD *size)
  286. {
  287.   struct IOCTLI cmd;
  288.   struct {
  289.     BYTE control;
  290.     DWORD size;
  291.   } buf;
  292.  
  293.   cmd.req.len=sizeof(cmd);
  294.   cmd.req.unit=0;
  295.   cmd.req.command=3;
  296.   cmd.descriptor=0;
  297.   cmd.address=&buf;
  298.   cmd.len=sizeof(buf);
  299.   cmd.secnum=0;
  300.   cmd.ptr=NULL;
  301.   buf.control=8;
  302.   CallDevice(&cmd);
  303.   *size=buf.size;
  304.   return cmd.req.status;
  305. }
  306.  
  307. char *
  308. location_str(DWORD loc)
  309. {
  310.     static char ret_buf[256];
  311.     long min,sec,frames;
  312.  
  313.     frames = loc % 75;
  314.     sec = (loc+150) / 75;
  315.     min = sec / 60;
  316.     sec = sec % 60;
  317.  
  318.     sprintf(ret_buf,"High sierra %ld ; %02ld:%02ld.%02ld",loc,min,sec,frames);
  319.     return ret_buf;
  320. }
  321.  
  322. void
  323. translate_location(char *strbuf,DWORD *loc)
  324. {
  325.     char *p;
  326.  
  327.     for (p=strbuf;*p && (*p != ':'); p++)
  328.       ;
  329.     if (*p == ':') {
  330.       *loc = atol(strbuf)*75L*60L+atol(p+1)*75L;
  331.     } else {
  332.       *loc = atol(strbuf);
  333.     }
  334. }
  335.  
  336. void
  337. read_location(char *question,DWORD *loc)
  338. {
  339. #define MAX_LOC 256
  340.     char buf[MAX_LOC];
  341.     buf[0] = '\0';
  342.  
  343.     while (buf[0] == '\0') {
  344.       printf("%s",question);
  345.       fgets(buf,MAX_LOC,stdin);
  346.     }
  347.     translate_location(buf,loc);
  348. }
  349.  
  350.  
  351. void
  352. usage()
  353. {
  354.   fprintf(stderr,"Usage: readcda [options]\n");
  355.   fprintf(stderr,"  If no options are specified the user is asked for the required data\n");
  356.   fprintf(stderr,"Options: -file <output-filename>   [needed]\n");
  357.   fprintf(stderr,"         -track <tracknumber>      which track to read\n");
  358.   fprintf(stderr,"         -from <location>          from where to read\n");
  359.   fprintf(stderr,"         -length <length>          how long to read\n");
  360.   fprintf(stderr,"Note: -track or -from are needed, and -from must be combined with -length\n");
  361.   fprintf(stderr,"      where -track CAN be combined with -length\n");
  362.   fprintf(stderr,"      both -length and -from can be 'min:sec' or sector number\n");
  363.   fprintf(stderr,"Extra options:\n");
  364.   fprintf(stderr,"   -debug <level> Display more output with higher level\n");
  365.   fprintf(stderr,"   -wav           Write an WAV file (=default)\n");
  366.   fprintf(stderr,"   -cdda          Write the RAW CDDA output\n");
  367.   fprintf(stderr,"   -nbuf <#buf>   Use #buf buffers (>8,when automatic failes\n");
  368.   fprintf(stderr,"   -swapbytes     Swap all bytes (MSB/LSB) in output\n");
  369.   fprintf(stderr,"   -swapwords     Swap all words (channels) in output\n");
  370.   fprintf(stderr,"   -nosynch       Skip the synchronization algorithm\n");
  371.   fprintf(stderr,"   -synch         Keep using the synchronization algorithm\n");
  372.   exit(1);
  373. }
  374.  
  375.  
  376. /**** Commandline parameter fields ***************************/
  377.  
  378. int  p_track=-1;        /* track-no 1...   */
  379. char p_filename[255];   /* file name       */
  380. char p_from[255];       /* From location   */
  381. char p_length[255];     /* Length of recording */
  382. int  p_nbuf = -1;       /* Default number of audio buffers */
  383. int  p_debug=0;         /* debug-info-lebel (0=no,1,2,..) */
  384. int  p_waveform=1;      /* Default = WAV file */
  385. int  p_swapbytes;       /* Default = No swapping of bytes (MSB/LSB) */
  386. int  p_swapwords;       /* Default = No swapping of words (audio channels) */
  387. int  ask_param=1;       /* Flag for asking of parameters */
  388. int  p_nosynch=0;       /* Default= use synchronization algorithm,if 1 don't */
  389. #ifdef TIMING
  390. struct timeb ts, te;    /* For overall timing */
  391. struct timeb tms, tme;  /* For exact-ish timing */
  392. #endif
  393.  
  394. void
  395. writelog(char *format, ... )
  396. {
  397.   FILE *f_log;
  398.   va_list(arglist);
  399.  
  400.   if ( p_debug ) {
  401.     va_start(arglist,format);
  402.     f_log=fopen("readcda2.log","a");
  403.     vfprintf(f_log,format,arglist);
  404.     fclose(f_log);
  405.     va_end(arglist);
  406.   }
  407. }
  408.  
  409. void
  410. get_command_line_param(int argc, char *argv[])
  411. {
  412.   int i;
  413.   i = 1;
  414.  
  415.   while (i < argc) {
  416.     if (strcmp(argv[i],"-track") == 0) {
  417.       i++;
  418.       p_track = atoi(argv[i]);
  419.     } else if(strcmp(argv[i],"-file")== 0) {
  420.       i++;
  421.       strcpy(p_filename,argv[i]);
  422.     } else if(strcmp(argv[i],"-from")== 0) {
  423.       i++;
  424.       strcpy(p_from,argv[i]);
  425.     } else if(strcmp(argv[i],"-length")== 0) {
  426.       i++;
  427.       strcpy(p_length,argv[i]);
  428.     } else if(strcmp(argv[i],"-debug")== 0) {
  429.       i++;
  430.       p_debug = atoi(argv[i]);
  431.     } else if(strcmp(argv[i],"-nbuf")== 0) {
  432.       i++;
  433.       p_nbuf = atoi(argv[i]);
  434.     } else if(strcmp(argv[i],"-wav")== 0) {
  435.       p_waveform = 1;
  436.     } else if(strcmp(argv[i],"-cdda")== 0) {
  437.       p_waveform = 0;
  438.     } else if(strcmp(argv[i],"-swapbytes")== 0) {
  439.       p_swapbytes = 1;
  440.     } else if(strcmp(argv[i],"-swapwords")== 0) {
  441.       p_swapwords = 1;
  442.     } else if(strcmp(argv[i],"-synch")== 0) {
  443.       p_nosynch = 0;
  444.     } else if(strcmp(argv[i],"-nosynch")== 0) {
  445.       p_nosynch = 1;
  446.     } else {
  447.       usage();
  448.     }
  449.     i++;
  450.   }
  451.  
  452.   if (argc > 1) {
  453.     ask_param = 0;  /* Ok, there are command line parameters */
  454.  
  455.     if (((p_track == -1) && (*p_from == '\0')) || (*p_filename == '\0')) {
  456.       printf("Not all parameters supplied !!\n\n");
  457.       usage();    /* Not all necessary param specified */
  458.     }
  459.  
  460.     writelog("-----------------------------------------------\n");
  461.     writelog("Reading file %s\n",p_filename);
  462.     if (p_track != -1) {
  463.       if (! *p_length)
  464.         writelog("Reading track %d\n",p_track);
  465.       else
  466.     writelog("Reading track %d, length %s\n",p_track,p_length);
  467.     }
  468.     else
  469.       writelog("Reading from pos %s, length %s\n",p_from,p_length);
  470.   }
  471.  
  472.   return;
  473. }
  474.  
  475. /*
  476.  * Ok, here is the main program.
  477.  * Most of the programming is below :-)
  478.  *
  479. */
  480.  
  481. void main(int argc, char *argv[])
  482. {
  483.   WORD status,w;
  484.   char *buf[50],*previous_end;
  485.   DWORD *track_loc, loc, start_pos, end_pos, buf_start,size;
  486.   DWORD i, j, offset=0, synch_size;
  487.   long work_offset, min_offset=32768, max_offset=0, avg_offset=0;
  488.   int no_offset=0, num_reads;
  489.   long readtime_min=0, readtime_max=0;    /* Max & min. timings - psyche */
  490.   long maxtime,mintime;
  491.   BYTE info,b;
  492.   int fd, key, n,first_time;
  493.   int retry, waveform;
  494.  
  495.   struct RIFF {
  496.     char rID[4];
  497.     DWORD rLen;
  498.   } riff;
  499.   struct FORMAT {
  500.     char fID[4];
  501.     DWORD fLen;
  502.     WORD wTag;
  503.     WORD wChannel;
  504.     DWORD nSample;
  505.     DWORD nByte;
  506.     WORD align;
  507.     WORD sample;
  508.   };
  509.   struct DATA {
  510.     char dID[4];
  511.     DWORD dLen;
  512.   };
  513.   struct WAVE {
  514.     char wID[4];
  515.     struct FORMAT fmt;
  516.     struct DATA data;
  517.   } wave;
  518.  
  519.   struct timeb ts, te;        /* For overall timing (maximum) */
  520.   struct timeb tms, tme;    /* For exact-ish timing (minimum) */
  521.  
  522.   printf("READ CD digital Audio 2.0\n");
  523.   printf("Written by Klaas Hemstra (hst@mh.nl).\n");
  524.   printf("Based on code by Yeng-Chee Su (yenchee@csie.nctu.edu.tw)\n");
  525.   printf("Timing by Stewart Addison (psyche@tardis.ed.ac.uk)\n\n");
  526.  
  527.     /*
  528.      * See if user added commandline param
  529.     */
  530.   get_command_line_param(argc,argv);
  531.  
  532.     /*
  533.      * Allocate memory buffers
  534.      *
  535.      * First the one for the block to synchronize against.
  536.     */
  537.   previous_end = (char*)malloc(BUFSIZE/2);
  538.   if (previous_end == (char *) NULL) {
  539.     fprintf(stderr,"Out of memory allocating synch buffer, real low on memory !!\n");
  540.     writelog("Out of memory while allocating synch buffer\n");
  541.     exit(1);
  542.   }
  543.     /*
  544.      * Then the for the real thing, the buffers that are filled each sweep
  545.     */
  546.   i=0;
  547.   do
  548.   {
  549.     buf[i] = (char*)malloc(BUFSIZE);
  550.     if (buf[i] == (char *) NULL)
  551.         break;
  552.     else
  553.         i++;
  554.   }
  555.   while (((p_nbuf > 0) && (i < p_nbuf))     /* nbuf parameter given ? */
  556.          ||                              /* Or all memory allocated ? */
  557.          ((p_nbuf <= 0) && (buf[i-1] != (char *) NULL)));
  558.  
  559.   if ((p_nbuf > 0) && (i < p_nbuf)) {
  560.       fprintf(stderr,"Only %d buffers allocated (lower the nbuf parameter)\n",i);
  561.       writelog("Out of memory while allocating buffers\n");
  562.       exit(1);
  563.   }
  564.   if (i < 8) {
  565.     printf("Warning: only %d memory buffers, try freeing up DOS memory !\n",i);
  566.   }
  567.   p_nbuf = i;
  568.  
  569.   printf("Memory used for %d buffers = %dK\n",p_nbuf,
  570.          (int)(((long)BUFSIZE * p_nbuf) / 1024L));
  571.  
  572.     /*
  573.      * Get Disc info
  574.     */
  575.   if (!check_mscdex()) {
  576.     fprintf(stderr,"No CD-ROM extension available!\n");
  577.     writelog("No CD-ROM extension available !\n");
  578.     exit(1);
  579.   }
  580.   retry=0;
  581.   status=GetDiskInfo();
  582.   while (status != 0x0100) {
  583.     printf("Can't get CD-ROM information, status=%x\n", status);
  584.     delay(1000);
  585.     retry++;
  586.     if (retry == 3) {
  587.       fprintf(stderr,"Get CD-ROM information failed\n");
  588.       writelog("Get CD-ROM information failed !\n");
  589.       exit(1);
  590.     }
  591.     status=GetDiskInfo();
  592.   }
  593.     /*
  594.      * Ok, there is a CD-ROM, Get Track information
  595.     */
  596.   track_loc=(DWORD*)malloc(sizeof(DWORD)*(highest-lowest+2));
  597.   if (track_loc==NULL) {
  598.     fprintf(stderr,"Out of memory!\n");
  599.     writelog("Out of memory, while allocating track info buffers\n");
  600.     exit(1);
  601.   }
  602.   track_loc = &track_loc[-lowest];
  603.   track_loc[highest+1]=total_time;
  604.   for (i=lowest; i<=highest; i++) {
  605.     status=GetTrackInfo(i, &loc, &info);
  606.     track_loc[i]=loc;
  607.   }
  608.     /*
  609.      * If it is an interactive session or lots of debug wanted Then
  610.      *  Display track info
  611.     */
  612.   for (i=lowest; i<=highest; i++) {
  613.     if (p_debug >= 3 || argc==1) {
  614.       printf("Track %2ld : %02ld:%02ld.%02ld %6ld Len = %ld\n",
  615.          i, (track_loc[i] >> 16) & 0xff,
  616.          (track_loc[i] >> 8) & 0xff,
  617.          track_loc[i] & 0xff, Red2Sierra(track_loc[i]),
  618.          Red2Sierra(track_loc[i+1]) - Red2Sierra(track_loc[i]));
  619.       writelog("Track %2ld : %02ld:%02ld.%02ld %6ld Len = %ld\n",
  620.            i, (track_loc[i] >> 16) & 0xff,
  621.            (track_loc[i] >> 8) & 0xff,
  622.            track_loc[i] & 0xff, Red2Sierra(track_loc[i]),
  623.            Red2Sierra(track_loc[i+1]) - Red2Sierra(track_loc[i]));
  624.     }
  625.   }
  626.   if (p_debug >= 3) {
  627.     printf("Total time : %02ld:%02ld.%02ld\n", (total_time >> 16) & 0xff,
  628.            (total_time >> 8) & 0xff, total_time & 0xff);
  629.     writelog("Total time : %02ld:%02ld.%02ld\n", (total_time >> 16) & 0xff,
  630.          (total_time >> 8) & 0xff, total_time & 0xff);
  631.   }
  632.  
  633.    /*
  634.     * Interactive User interface (it's real simple...)
  635.    */
  636.   if (ask_param) {
  637.     printf("Image filename: ");
  638.     gets(image);
  639.   } else {
  640.     strcpy(image,p_filename);
  641.   }
  642.  
  643.   if (ask_param) {
  644.     printf("(0) CDDA format, (1) WAV format : ");
  645.     key = getch();
  646.     while (key != '0' && key != '1')
  647.       key = getch();
  648.     printf("%c\n", key);
  649.     if (key == '1')
  650.       waveform = 1;
  651.     else
  652.       waveform = 0;
  653.   } else {
  654.     waveform = p_waveform;
  655.   }
  656.  
  657.   if (ask_param) {
  658.     printf("(0) Read Track, (1) Read A to B : ");
  659.     key = getch();
  660.     while (key != '0' && key != '1')
  661.       key = getch();
  662.     printf("%c\n", key);
  663.  
  664.     if (key == '1') {
  665.       read_location("Start location (High sierra or min:sec) : ",&loc);
  666.       read_location("Frame length (Sectors or min:sec) : ",&size);
  667.     } else {
  668.       n = -1;
  669.       while (n == -1) {
  670.     printf("Which track :");
  671.         scanf("%d", &n);
  672.  
  673.         if (n < lowest || n > highest) {
  674.           printf("Illegal track! ->%i<-\n",n);
  675.           n = -1;
  676.     } else {
  677.           loc = Red2Sierra(track_loc[n]);
  678.           size = Red2Sierra(track_loc[n+1]) - Red2Sierra(track_loc[n]);
  679.     }
  680.       }
  681.     }
  682.   } else {
  683.     if (p_track != -1) {
  684.       n = p_track;
  685.       if (n < lowest || n > highest) {
  686.     fprintf(stderr,"Illegal track! ->%i<-\n",n);
  687.     writelog("Illegal track, should be between %d and %d\n",highest,lowest);
  688.     exit(1);
  689.       }
  690.       loc = Red2Sierra(track_loc[n]);
  691.       size = Red2Sierra(track_loc[n+1]) - Red2Sierra(track_loc[n]);
  692.       if (*p_length)
  693.         translate_location(p_length,&size);
  694.     } else {
  695.       translate_location(p_from,&loc);
  696.       translate_location(p_length,&size);
  697.     }
  698.   }
  699.  
  700.   if (size < NBLOCK * p_nbuf)
  701.      size = NBLOCK * 4;
  702.  
  703.   printf("Start location %s\n", location_str(loc));
  704.   printf("Stop location %s\n", location_str(loc+size));
  705.  
  706.  
  707.     /*
  708.      * Create the file
  709.     */
  710.   _fmode = O_BINARY;
  711.   fd = creat(image, S_IREAD|S_IWRITE);
  712.   if (fd == -1) {
  713.     perror("open");
  714.     writelog("Can not open output file %s\n",p_filename);
  715.     exit(1);
  716.   }
  717.  
  718.     /*
  719.      * If a WAV file should be created, write the WAV header
  720.     */
  721.   if (waveform) {
  722.     strcpy(riff.rID, "RIFF");
  723.     riff.rLen = FRAME_SIZE * (DWORD)size + sizeof(struct WAVE);
  724.     strcpy(wave.wID, "WAVE");
  725.     strcpy(wave.fmt.fID, "fmt ");
  726.     wave.fmt.fLen = sizeof(struct FORMAT) - 8;
  727.     wave.fmt.wTag = 1;
  728.     wave.fmt.wChannel = 2;
  729.     wave.fmt.nSample = 44100L;
  730.     wave.fmt.nByte = 44100L * 4;
  731.     wave.fmt.align = 4;
  732.     wave.fmt.sample = 16;
  733.     strcpy(wave.data.dID, "data");
  734.     wave.data.dLen = FRAME_SIZE * (DWORD)size;
  735.     if (write(fd, &riff, sizeof(struct RIFF)) != sizeof(struct RIFF)) {
  736.       perror("write");
  737.       writelog("Can not write wav-header (RIFF) to file %s\n",p_filename);
  738.       exit(1);
  739.     }
  740.     if (write(fd, &wave, sizeof(struct WAVE)) != sizeof(struct WAVE)) {
  741.       perror("write");
  742.       writelog("Can not write wav-header (WAVE) to file %s\n",p_filename);
  743.       exit(1);
  744.     }
  745.   }
  746.  
  747.     /*
  748.      * Here the Reading of the data is done.
  749.      * Read the date in blocks, as much as possible in memory
  750.      * After p_nbuf (default 8) blocks of FRAME_SIZE*NBLOCK are read
  751.      * the data is written to the output file, after synchronizing the
  752.      * position to write it to.
  753.     */
  754.  
  755.   wave.data.dLen = 0L;
  756.   first_time = 1;
  757.   start_pos = loc;
  758.   end_pos = loc+size;
  759.  
  760.   ftime(&ts);        /* Starts micro-timer - psyche */
  761.   num_reads=0;
  762.  
  763.   while (loc < end_pos) {
  764.  
  765.       /*
  766.        * Read thos p_nbuf blocks of data in memory first
  767.       */
  768.     for (i=0; (i < p_nbuf); i++) {
  769.  
  770.       printf("\rReading frame %ld to %ld in mem (%ld)  buf[%2i]            \r",
  771.          loc, loc+NBLOCK-1, end_pos, i);
  772.       if (p_debug >= 3) {
  773.     writelog("Reading frame %ld to %ld in mem (%ld)  buf[%2i]\n",
  774.          loc, loc+NBLOCK-1,end_pos,i);
  775.       }
  776.  
  777.       ftime(&tms);
  778.       status = ReadLong(loc, NBLOCK, buf[i]);
  779.       ftime(&tme);
  780.       readtime_min += (1000L*tme.time+tme.millitm)-(1000L*tms.time+tms.millitm);
  781.  
  782.       if (status != 0x0100) {
  783.     fprintf(stderr,"CDROM read status %x\n", status);
  784.     fprintf(stderr,"Your CD-ROM does not support the READ LONG call properly !!\n");
  785.     writelog("CDROM read status %x)\n",status);
  786.     writelog("Your CD-ROM does not support the READ LONG call properly !!\n");
  787.     exit(1);
  788.       }
  789.  
  790.       if (p_swapbytes) {    /* Swap bytes option, swap each word's MSB/LSB */
  791.     for (j=0; j < BUFSIZE; j += 2) {
  792.       b = buf[i][j];
  793.       buf[i][j] = buf[i][j+1];
  794.       buf[i][j+1] = b;
  795.     }
  796.       }
  797.  
  798.       if (p_swapwords) {    /* Swap words option, swap each two words */
  799.     for (j=0; j < BUFSIZE; j += 4) {
  800.       w = *((WORD *) (&(buf[i][j])));
  801.       *((WORD *) (&(buf[i][j]))) = *((WORD *) (&(buf[i][j+2])));
  802.       *((WORD *) (&(buf[i][j+2]))) = w;
  803.     }
  804.       }
  805.  
  806.       loc += NBLOCK;
  807.     }
  808.  
  809.     offset = 0;
  810.     if (!first_time && !p_nosynch) {
  811.       /*
  812.        * Synchronize data to previous block
  813.        * This is really important !!
  814.        * Some CD-ROM drive do it themselves, but others don't
  815.        * The problem is that if you tell it to read at sector 2034,
  816.        * and after writing the data to the file tell it to read
  817.        * sector 2035, the data is not exactly 'positioned' right.
  818.        * Most of the time there is an offset of something like a 1000
  819.        * bytes. This offset is determined by searching for the matching
  820.        * block of data in the datablock that is read twice.
  821.        */
  822.       synch_size = SYNCH_SIZE;   /* Start with the default synch size */
  823.  
  824.       i=BUFSIZE/4;
  825.       while (i < (BUFSIZE-synch_size)) {
  826.         if (memcmp(previous_end,buf[0]+i,synch_size) == 0) {
  827.       if (offset == 0) {
  828.         offset = i;      /* Ok, found a matching block */
  829.         /* Continue searching, */
  830.         /* if you find another match it is not right */
  831.       } else {
  832.           /*
  833.            * Shit, found another match
  834.            * Maybe the data coincedently matches another piece of data
  835.            * So, Try a bigger block to compare
  836.           */
  837.         synch_size *= 2;
  838.         if (synch_size > 4096) {
  839.           /*
  840.            * Well, two matches were found,
  841.            * there is however a possibility that this matches are
  842.            * located in dead silence on the CD (like in a gap between tracks)
  843.            * In that case, it is OK, synchronization has NOT failed
  844.           */
  845.           j = offset;
  846.           for (j=offset; j < synch_size; j++) {
  847.         if (*(buf[0]+j) != '\000') {
  848.           fprintf(stderr,"Synchronisation failed,TWO matches found !\n");
  849.           writelog("Sync failed,sync size to big !!\n");
  850.           exit(1);
  851.         }
  852.           }
  853.           offset = BUFSIZE/2;  /* Synch=middle of block */
  854.           break;
  855.         }
  856.         i = 0;
  857.         continue;
  858.       }
  859.     }
  860.     i+=4;
  861.       }
  862.  
  863.       if (offset == 0) {
  864.     fprintf(stderr,"Synchronisation failed, no matching block found !!\n");
  865.     writelog("Sync failed,no matching block found !!\n");
  866.     exit(1);
  867.       }
  868.       work_offset = abs(offset - BUFSIZE/2);
  869.  
  870.       if ( work_offset!=0 )
  871.     no_offset++;
  872.  
  873.       if (work_offset < min_offset)
  874.     min_offset = work_offset;
  875.       else
  876.     if (work_offset > max_offset)
  877.       max_offset = work_offset;
  878.  
  879.       avg_offset+=work_offset;
  880.  
  881.     }
  882.  
  883.     first_time = 0;
  884.  
  885.       /*
  886.        * Copy last block, for next read
  887.       */
  888.     memcpy(previous_end,buf[p_nbuf-1]+BUFSIZE/2,BUFSIZE/2);
  889.  
  890.       /*
  891.        * Now write that read blocks to the output file.
  892.        * The first one is written from possition 'offset' in the block
  893.        * The rest of them is written as read from the CD
  894.        * Except the last buffer, of which only half of it is written
  895.        * Stop when the required number of frames are written to the file
  896.        * The way it is programmed now, this could be NBLOCK-1 frames
  897.        * too much, but that is only milliseconds of audio...
  898.       */
  899.     printf("\rSynchronized write frame %ld to %ld to disk, offset = %ld      ",
  900.        loc-(p_nbuf*NBLOCK),loc-(NBLOCK/2),
  901.        p_nosynch ? 0 : offset-(BUFSIZE/2));
  902.     fflush(stdout);
  903.     if ( p_debug >=2 )
  904.       writelog("Synchronized write frame %ld to %ld to disk, offset = %ld\n",
  905.            loc-(p_nbuf*NBLOCK),loc-(NBLOCK/2),
  906.            p_nosynch ? 0 : offset-(BUFSIZE/2));
  907.  
  908.  
  909.     for (i=0;(i < ((p_nbuf-1)+ (p_nosynch ? 1 : 0)));i++) {
  910.       if ( write(fd, buf[i]+offset, BUFSIZE-offset) != (BUFSIZE-offset)) {
  911.     perror("write");
  912.     writelog("Error writing data to file %s!!\n",p_filename);
  913.     exit(1);
  914.       }
  915.       wave.data.dLen += (BUFSIZE-offset);
  916.       if (wave.data.dLen > (size * FRAME_SIZE))
  917.     i = p_nbuf;   /* Skip the rest */
  918.       offset = 0;
  919.     }
  920.  
  921.     if (wave.data.dLen <= (size * FRAME_SIZE)) {
  922.       /*
  923.        * Write only half of last buffer,
  924.        * The next loop, after synchronisation the rest will be written
  925.        */
  926.  
  927.       if (write(fd, buf[p_nbuf-1], BUFSIZE/2) != (BUFSIZE/2)) {
  928.     perror("write");
  929.     writelog("Error writing data to file %s\n",p_filename);
  930.     exit(1);
  931.       }
  932.       wave.data.dLen += (BUFSIZE/2);
  933.     }
  934.  
  935.     if (!p_nosynch)
  936.       loc -= NBLOCK;
  937.     /* sleep(1); */
  938.     num_reads++;
  939.   }
  940.  
  941.     /*
  942.      * Display timing data
  943.     */
  944.   if ( !p_nosynch )
  945.     loc+=NBLOCK;    /* Adjusts for final block count - psyche */
  946.  
  947.   ftime(&te); /**** save end-time ***/
  948.  
  949.   readtime_max=(1000L*te.time+te.millitm)-(1000L*ts.time+ts.millitm);
  950.  
  951.    /*
  952.     * Do all calculations without floats, that saves executable size
  953.     */
  954.   maxtime = ((1000L*(loc-start_pos))/75L+5L)/(readtime_max/100L);
  955.   mintime = ((1000L*(loc-start_pos))/75L+5L)/(readtime_min/100L);
  956.  
  957.   printf("\n\nReading speed was somewhere between %d.%02dx and %d.%02dx.\n",
  958.      (int)(maxtime / 100L),(int)(maxtime % 100L),
  959.      (int)(mintime / 100L),(int)(mintime % 100L));
  960.   writelog("\n\nReading speed was somewhere between %d.%02dx and %d.%02dx.\n",
  961.      (int)(maxtime / 100L),(int)(maxtime % 100L),
  962.      (int)(mintime / 100L),(int)(mintime % 100L));
  963.  
  964.   if (p_nosynch == 2)
  965.     printf("Synchronization not needed.\n");
  966.   else if (!p_nosynch ) {
  967.     if ( min_offset==0 && max_offset==0 ) {
  968.       printf("No synchronization was needed !!!\n");
  969.       printf("Consider using -nosynch for extra performance\n");
  970.       writelog("No synchronization was needed\n");
  971.     } else {
  972.       printf("Synchronization offsets : minimum = %ld%%, maximum = %ld%%, average=%ld%%.\n",
  973.          (100L*min_offset)/FRAME_SIZE,
  974.          (100L*max_offset)/FRAME_SIZE,
  975.          ((100L*avg_offset)/FRAME_SIZE)/num_reads);
  976.       printf("Correction was required on %d%% of all reads (%d of %d)\n",
  977.          100*(no_offset+1)/num_reads, (no_offset+1), num_reads);
  978.  
  979.       writelog("Synchronization offsets : minimum = %d%%, maximum = %d%%, average=%d%%.\n\
  980.               Correction was required on %d%% of all reads (%d of %d)\n",
  981.            (100L*min_offset)/FRAME_SIZE,
  982.            (100L*max_offset)/FRAME_SIZE,
  983.            ((100L*avg_offset)/FRAME_SIZE)/((end_pos-start_pos)/NBLOCK),
  984.            100*no_offset/num_reads,
  985.            no_offset, num_reads);
  986.     }
  987.   }
  988.  
  989.     /*
  990.      * Complete the WAV file header in the file
  991.     */
  992.   if (waveform) {
  993.     lseek(fd,0L,SEEK_SET);
  994.     printf("\nCompleting header information of WAV file");
  995.     writelog("Completing header information of WAV file\n");
  996.     riff.rLen = wave.data.dLen + sizeof(struct WAVE);
  997.  
  998.     if (write(fd, &riff, sizeof(struct RIFF)) != sizeof(struct RIFF)) {
  999.       perror("write");
  1000.       writelog("Error completing wav-header in file %s\n",p_filename);
  1001.       exit(1);
  1002.     }
  1003.  
  1004.     if (write(fd, &wave, sizeof(struct WAVE)) != sizeof(struct WAVE)) {
  1005.       perror("write");
  1006.       writelog("Error completing wav-header in file %s\n",p_filename);
  1007.       exit(1);
  1008.     }
  1009.     printf(" ... Done.\n");
  1010.   }
  1011.  
  1012.   close(fd);
  1013.   writelog("Output file %s complete !\n",p_filename);
  1014.  
  1015.     /*
  1016.      * Not really necessary of course, but it's a good style of programming !
  1017.      * Free all those malloc-ed memory blocks
  1018.     */
  1019.   free(&track_loc[lowest]);
  1020.   free(previous_end);
  1021.   for (i=0; i< p_nbuf ;i++)
  1022.     free(buf[i]);
  1023. }
  1024.  
  1025.