www.pudn.com > readcda.zip > READCDA.C


/* 
 
  GOAL: 
    This program is intended to read CD audio data into a disk file. 
 
  Author: 
    Yeng-Chee Su (yenchee@csie.nctu.edu.tw) 
    Department of Computer Science and Information Engineering 
    National Chiao Tung University 
    & 
    Klaas Hemstra (hst@mh.nl) 
    Gouda, the Netherlands 
 
  Notice: 
    Most CD-ROM drive doesn't have the capability to read raw 
    data on compact disk, but some drives can work.  These includes 
    Panasonic CR-562B/563B and Toshiba XM-3401B.  This program 
    is designed on CR-562B and should work well on it.  If it 
    can't work for you, find a better driver around. 
    Yeng-Chee Su wrote the first attempt, but the program depended on 
    the speed of the file-system for clean 'recordings'. 
 
    The buffered read + synchronisation is added later by me. 
 
*/ 
 
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
 
#define RAW_MODE 1 
#define COOKED_MODE 0 
#define READ_MODE RAW_MODE 
#if READ_MODE == COOKED_MODE 
  #define FRAME_SIZE 2048 
#else 
  #define FRAME_SIZE 2352 
#endif 
#define NBLOCK 16 
#define NBUF   10 
#define SYNCH_SIZE 128  /* Bytes synch pattern */ 
 
typedef unsigned char BYTE; 
typedef unsigned int WORD; 
typedef unsigned long int DWORD; 
 
struct ReqHdr { 
  BYTE len; 
  BYTE unit; 
  BYTE command; 
  WORD status; 
  BYTE reserved[8]; 
}; 
 
struct IOCTLI { 
  struct ReqHdr req; 
  BYTE descriptor; 
  void far *address; 
  WORD len; 
  WORD secnum; 
  void far *ptr; 
}; 
 
struct DeviceStatus { 
  BYTE control; 
  DWORD param; 
}; 
 
struct DiskInfo { 
  BYTE control; 
  BYTE lowest; 
  BYTE highest; 
  DWORD total; 
}; 
 
struct TrackInfo { 
  BYTE control; 
  BYTE track; 
  DWORD loc; 
  BYTE info; 
}; 
 
struct SEEK { 
  struct ReqHdr req; 
  BYTE mode; 
  DWORD address; 
  WORD secnum; 
  DWORD loc; 
}; 
 
struct PlayReq { 
  struct ReqHdr req; 
  BYTE mode; 
  DWORD loc; 
  DWORD secnum; 
}; 
 
int CDROM; 
int lowest, highest; 
DWORD total_time; 
char image[MAXPATH]; 
 
void CallDevice(void *ptr) 
{ 
  static union REGS reg; 
  static struct SREGS seg; 
 
  segread(&seg); 
  seg.es=FP_SEG(ptr); 
  reg.x.ax=0x1510; 
  reg.x.bx=FP_OFF(ptr); 
  reg.x.cx=CDROM; 
  int86x(0x2f, ®, ®, &seg); 
} 
 
int check_mscdex(void) 
{ 
  union REGS reg; 
 
  reg.x.ax=0x1500; 
  reg.x.bx=0; 
  int86(0x2f, ®, ®); 
  if (!reg.x.bx) 
	 return 0; 
  else { 
	 CDROM=reg.x.cx; 
	 return 1; 
  } 
} 
 
int GetDeviceStatus(void) 
{ 
  struct IOCTLI cmd; 
  struct DeviceStatus buf; 
 
  cmd.req.len=26; 
  cmd.req.unit=0; 
  cmd.req.command=3; 
  cmd.descriptor=0; 
  cmd.address=&buf; 
  cmd.len=5; 
  cmd.secnum=0; 
  cmd.ptr=NULL; 
  buf.control=6; 
  CallDevice(&cmd); 
  return cmd.req.status; 
} 
 
int GetDiskInfo(void) 
{ 
  struct IOCTLI cmd; 
  struct DiskInfo buf; 
 
  cmd.req.len=26; 
  cmd.req.unit=0; 
  cmd.req.command=3; 
  cmd.descriptor=0; 
  cmd.address=&buf; 
  cmd.len=7; 
  cmd.secnum=0; 
  cmd.ptr=NULL; 
  buf.control=10; 
  CallDevice(&cmd); 
  lowest=buf.lowest; 
  highest=buf.highest; 
  total_time=buf.total; 
  return cmd.req.status; 
} 
 
int GetTrackInfo(int track, DWORD *loc, BYTE *info) 
{ 
  struct IOCTLI cmd; 
  struct TrackInfo buf; 
 
  cmd.req.len=26; 
  cmd.req.unit=0; 
  cmd.req.command=3; 
  cmd.descriptor=0; 
  cmd.address=&buf; 
  cmd.len=7; 
  cmd.secnum=0; 
  cmd.ptr=NULL; 
  buf.control=11; 
  buf.track=track; 
  CallDevice(&cmd); 
  *loc=buf.loc; 
  *info=buf.info; 
  return cmd.req.status; 
} 
 
int SeekTrack(DWORD loc) 
{ 
  struct SEEK cmd; 
 
  cmd.req.len=24; 
  cmd.req.unit=0; 
  cmd.req.command=131; 
  cmd.mode=1; 
  cmd.address=NULL; 
  cmd.secnum=0; 
  cmd.loc=loc; 
  CallDevice(&cmd); 
  return cmd.req.status; 
} 
 
int PlayAudio(DWORD loc, DWORD num) 
{ 
  struct PlayReq cmd; 
 
  cmd.req.len=22; 
  cmd.req.unit=0; 
  cmd.req.command=132; 
  cmd.mode=1; 
  cmd.loc=loc; 
  cmd.secnum=num; 
  CallDevice(&cmd); 
  return cmd.req.status; 
} 
 
int StopAudio(void) 
{ 
  struct ReqHdr cmd; 
 
  cmd.len=13; 
  cmd.unit=0; 
  cmd.command=133; 
  CallDevice(&cmd); 
  return cmd.status; 
} 
 
DWORD Red2Sierra(DWORD loc) 
{ 
  BYTE min, sec, frame; 
 
  min = (loc >> 16) & 0xff; 
  sec = (loc >> 8) & 0xff; 
  frame = loc & 0xff; 
  return (DWORD)min * 75 * 60 + (DWORD)sec * 75 + (DWORD)frame - 150; 
} 
 
int ReadLong(DWORD loc, WORD secnum, char far *buf) 
{ 
  struct ReadL { 
    struct ReqHdr req; 
    BYTE mode; 
    void far *address; 
    WORD secnum; 
    DWORD loc; 
    BYTE readmode; 
    BYTE skip[2]; 
  } cmd; 
 
  cmd.req.len=sizeof(cmd); 
  cmd.req.unit=0; 
  cmd.req.command=128; 
  cmd.mode=0; 
  cmd.address=buf; 
  cmd.secnum=secnum; 
  cmd.loc=loc; 
  cmd.readmode=READ_MODE; 
  cmd.skip[0]=cmd.skip[1]=0; 
  CallDevice(&cmd); 
  return cmd.req.status; 
} 
 
int GetVolSize(DWORD *size) 
{ 
  struct IOCTLI cmd; 
  struct { 
    BYTE control; 
    DWORD size; 
  } buf; 
 
  cmd.req.len=sizeof(cmd); 
  cmd.req.unit=0; 
  cmd.req.command=3; 
  cmd.descriptor=0; 
  cmd.address=&buf; 
  cmd.len=sizeof(buf); 
  cmd.secnum=0; 
  cmd.ptr=NULL; 
  buf.control=8; 
  CallDevice(&cmd); 
  *size=buf.size; 
  return cmd.req.status; 
} 
 
char * 
location_str( DWORD loc) 
{ 
    static char ret_buf[256]; 
    long min,sec,frames; 
 
    frames = loc % 75; 
    sec = (loc+150) / 75; 
    min = sec / 60; 
    sec = sec % 60; 
 
    sprintf(ret_buf,"High sierra %ld ; %02ld:%02ld.%02ld",loc,min,sec,frames); 
    return ret_buf; 
} 
 
void 
read_location(char *question,DWORD *loc) 
{ 
#define MAX_LOC 256 
    char buf[MAX_LOC],*p; 
    buf[0] = '\0'; 
 
    while (buf[0] == '\0') { 
	printf("%s",question); 
	fgets(buf,MAX_LOC,stdin); 
    } 
    for (p=buf;*p && (*p != ':'); p++) 
      ; 
    if (*p == ':') { 
      *loc = atol(buf)*75L*60L+atol(p+1)*75L; 
    } else { 
      *loc = atol(buf); 
    } 
} 
 
 
void main() 
{ 
  WORD status; 
  char *buf[NBUF],*previous_end; 
  DWORD *track_loc, loc, end_pos, size; 
  DWORD i, j, offset,synch_size; 
  BYTE info; 
  int fd, key, n,first_time; 
  int retry, waveform; 
  struct RIFF { 
    char rID[4]; 
    DWORD rLen; 
  } riff; 
  struct FORMAT { 
    char fID[4]; 
    DWORD fLen; 
    WORD wTag; 
    WORD wChannel; 
    DWORD nSample; 
    DWORD nByte; 
    WORD align; 
    WORD sample; 
  }; 
  struct DATA { 
    char dID[4]; 
    DWORD dLen; 
  }; 
  struct WAVE { 
    char wID[4]; 
    struct FORMAT fmt; 
    struct DATA data; 
  } wave; 
 
  printf("CD-ROM digital audio data extractor, Ver 1.1\n"); 
  printf(" written by Yeng-Chee Su, CSIE, NCTU & Klaas Hemstra (hst@mh.nl)\n"); 
  printf("\n"); 
 
   /* 
    * Allocate memory buffers 
   */ 
  for (i=0; i< NBUF; i++) 
    buf[i] = (char*)malloc((long)FRAME_SIZE * NBLOCK); 
    if (buf[i] == NULL) { 
      printf("Out of memory!\n"); 
      exit(1); 
    } 
  previous_end = (char*)malloc((long)FRAME_SIZE * NBLOCK); 
  if (previous_end == (char *) NULL) { 
    printf("Out of memory!\n"); 
    exit(1); 
  } 
 
   /* 
    * Get Disc info 
   */ 
  if (!check_mscdex()) { 
    printf("No CD-ROM extension available!\n"); 
    exit(1); 
  } 
  retry=0; 
  status=GetDiskInfo(); 
  while (status != 0x0100) { 
    printf("Can't get CD-ROM information, status=%x\n", status); 
    delay(1000); 
    retry++; 
    if (retry == 3) { 
      printf("Get CD-ROM information failed\n"); 
      exit(1); 
    } 
    status=GetDiskInfo(); 
  } 
  track_loc=(DWORD*)malloc(sizeof(DWORD)*(highest-lowest+2)); 
  if (track_loc==NULL) { 
    printf("Out of memory!\n"); 
    exit(1); 
  } 
  track_loc = &track_loc[-lowest]; 
  track_loc[highest+1]=total_time; 
  for (i=lowest; i<=highest; i++) { 
    status=GetTrackInfo(i, &loc, &info); 
    track_loc[i]=loc; 
  } 
  for (i=lowest; i<=highest; i++) 
    printf("Track %2ld : %02ld:%02ld.%02ld %6ld Len = %ld\n", i, (track_loc[i] >> 16) & 0xff, 
     (track_loc[i] >> 8) & 0xff, track_loc[i] & 0xff, Red2Sierra(track_loc[i]), 
     Red2Sierra(track_loc[i+1]) - Red2Sierra(track_loc[i])); 
  printf("Total time : %02ld:%02ld.%02ld\n", (total_time >> 16) & 0xff, 
   (total_time >> 8) & 0xff, total_time & 0xff); 
 
   /* 
    * User interface 
   */ 
  printf("Image filename:"); 
  gets(image); 
  printf("(0) CDDA format, (1) WAV format :"); 
  key = getch(); 
  while (key != '0' && key != '1') 
    key = getch(); 
  printf("%c\n", key); 
  if (key == '1') waveform = 1; else waveform = 0; 
 
  printf("(0) Read Track, (1) Read A to B :"); 
  key = getch(); 
  while (key != '0' && key != '1') 
    key = getch(); 
  printf("%c\n", key); 
  if (key == '1') { 
    read_location("Start location (High sierra or min:sec) : ",&loc); 
    read_location("Frame length (Sectors or min:sec) : ",&size); 
  } else { 
track_again: 
    printf("Which track :"); 
    scanf("%d", &n); 
    if (n < lowest || n > highest) { 
      printf("illega track!\n"); 
      goto track_again; 
    } 
    loc = Red2Sierra(track_loc[n]); 
    size = Red2Sierra(track_loc[n+1]) - Red2Sierra(track_loc[n]); 
  } 
  printf("Start location %s\n", location_str(loc)); 
  printf("Stop location %s\n", location_str(loc+size)); 
 
   /* 
    * Create the file 
   */ 
  _fmode = O_BINARY; 
  fd = creat(image, S_IREAD|S_IWRITE); 
  if (fd == -1) { 
    perror("open"); 
    exit(1); 
  } 
 
  if (waveform) { 
    strcpy(riff.rID, "RIFF"); 
    riff.rLen = FRAME_SIZE * (DWORD)size + sizeof(struct WAVE); 
    strcpy(wave.wID, "WAVE"); 
    strcpy(wave.fmt.fID, "fmt "); 
    wave.fmt.fLen = sizeof(struct FORMAT) - 8; 
    wave.fmt.wTag = 1; 
    wave.fmt.wChannel = 2; 
    wave.fmt.nSample = 44100L; 
    wave.fmt.nByte = 44100L * 4; 
    wave.fmt.align = 4; 
    wave.fmt.sample = 16; 
    strcpy(wave.data.dID, "data"); 
    wave.data.dLen = FRAME_SIZE * (DWORD)size; 
    if (write(fd, &riff, sizeof(struct RIFF)) != sizeof(struct RIFF)) { 
      perror("write"); 
      exit(1); 
    } 
    if (write(fd, &wave, sizeof(struct WAVE)) != sizeof(struct WAVE)) { 
      perror("write"); 
      exit(1); 
    } 
  } 
 
   /* 
    * Read the date in blocks, first in memory 
   */ 
  wave.data.dLen = 0L; 
  first_time = 1; 
  end_pos = loc+size; 
  while (loc < end_pos) { 
 
    for (i=0;(i < NBUF);i++) { 
      printf("\rReading frame %ld to %ld in memory                          \r", 
                                                               loc, loc+NBLOCK-1); 
      status = ReadLong(loc, NBLOCK, buf[i]); 
      if (status != 0x0100) { 
        printf("CDROM read with status %x\n", status); 
	exit(1); 
      } 
      loc += NBLOCK; 
    } 
 
    if (first_time == 0) { 
      /* 
       * Synchronize data to previous block 
      */ 
      offset = 0; 
      synch_size = SYNCH_SIZE; 
      while (offset == 0) { 
        for (i=(NBLOCK/4)*FRAME_SIZE; 
             i < (((unsigned int)NBLOCK*FRAME_SIZE)-synch_size); 
	     i+=4) { 
	  if (memcmp(previous_end+(NBLOCK/2)*FRAME_SIZE,buf[0]+i,synch_size) == 0) { 
	    if (offset == 0) 
	      offset = i; 
	    else { 
	      synch_size *= 2; 
	      if (synch_size > 4096) { 
		fprintf(stderr,"Synchronisation failed, synch size to big !!\n"); 
		exit(1); 
	      } 
	      break; 
	    } 
	  } 
	} 
	if (offset == 0) { 
	  fprintf(stderr,"Synchronisation failed, no matching block found !!\n"); 
	  exit(1); 
	} 
      } 
    } 
    else 
      offset = 0; 
 
    first_time = 0; 
 
    memcpy(previous_end,buf[NBUF-1],(long)FRAME_SIZE*NBLOCK); 
 
    printf("\rSynchronized write frame %ld to %ld to disk, offset = %ld    ", 
		loc-(NBUF*NBLOCK),loc-(NBLOCK/2),offset-(NBLOCK/2*FRAME_SIZE)); 
 
    for (i=0;(i < NBUF-1);i++) { 
      if (write(fd, buf[i]+offset, ((long) FRAME_SIZE * NBLOCK)-offset) == -1) { 
	perror("write"); 
	exit(1); 
      } 
      wave.data.dLen += (((long) FRAME_SIZE * NBLOCK)-offset); 
      offset = 0; 
    } 
 
       /* 
        * Write only half of last buffer, 
        * The next loop, after synchronisation the rest will be written 
       */ 
 
    if (write(fd, buf[NBUF-1], ((long) FRAME_SIZE * (NBLOCK/2))) == -1) { 
      perror("write"); 
      exit(1); 
    } 
    wave.data.dLen += ((long) FRAME_SIZE * (NBLOCK/2)); 
 
    loc -= NBLOCK; 
    /* sleep(1); */ 
  } 
 
  if (waveform) { 
    lseek(fd,0L,SEEK_SET); 
    printf("\nCompleting header information of WAV file\n"); 
    riff.rLen = wave.data.dLen + sizeof(struct WAVE); 
    if (write(fd, &riff, sizeof(struct RIFF)) != sizeof(struct RIFF)) { 
      perror("write"); 
      exit(1); 
    } 
    if (write(fd, &wave, sizeof(struct WAVE)) != sizeof(struct WAVE)) { 
      perror("write"); 
      exit(1); 
    } 
  } 
 
  close(fd); 
  free(&track_loc[lowest]); 
  free(buf); 
}