Please consider a donation to the Higher Intellect project. See https://preterhuman.net/donate.php or the Donate to Higher Intellect page for more info.

CDDA.C

From Higher Intellect Vintage Wiki
Jump to navigation Jump to search
/*

From [email protected] (Yeng-Chee Su)

  I've written a program which can read CDDA data from audio CD and make
them as Microsoft Windows WAV format on disk.  This works on Panasonic
CR-562B/563B.  Any commect/suggest/flame welcomed.  It should be compiled
on Turbo C/Borland C on any memory model.


  GOAL:
    This program is intended to read CD raw data into disk file.

  Author:
    Yeng-Chee Su
    Department of Computer Science and Information Engineering
    National Chiao Tung University

  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.  Since the
    current driver doesn't have callback facility, the speed of
    file system is very important for timing constrain.  If your
    system doesn't be fast enough, you will hear a glitch
    periodically.  To increase the cache size of smartdrv delayed
    write buffer will release the timing a little but not totally
    solved.  I'm still looking for a callback driver.

*/

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <dos.h>
#include <dir.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <io.h>

#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

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, &reg, &reg, &seg);
}

int check_mscdex(void)
{
  union REGS reg;

  reg.x.ax=0x1500;
  reg.x.bx=0;
  int86(0x2f, &reg, &reg);
  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;
}

void main()
{
  WORD status;
  char *buf;
  DWORD *track_loc, loc, size;
  DWORD i, j;
  BYTE info;
  int fd, key, n;
  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.0\n");
  printf("         written by Yeng-Chee Su, CSIE, NCTU\n");
  printf("\n");
  buf = (char*)malloc((long)FRAME_SIZE * NBLOCK);
  if (buf == NULL) {
    printf("Out of memory!\n");
    exit(1);
  }

  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);

  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("Start location (High Sierra format) :");
  scanf("%ld", &loc);
  printf("Frame length :");
  scanf("%ld", &size);
  printf("Stop location (High Sierra format): %ld\n", loc+size);
*/
again:
  printf("Which track :");
  scanf("%d", &n);
  if (n < lowest || n > highest) {
    printf("illega track!\n");
    goto again;
  }
  loc = Red2Sierra(track_loc[n]);
  size = Red2Sierra(track_loc[n+1]) - Red2Sierra(track_loc[n]);
  printf("Start location (High Sierra format) : %ld\n", loc);
  printf("Stop location (High Sierra format) : %ld\n", loc+size);

  _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);
    }
  }

  if (size > NBLOCK) i = NBLOCK; else i = size;
  printf("Reading frame %ld to %ld\r", loc, loc+i-1);
  status = ReadLong(loc, i, buf);
  if (status != 0x0100) {
    printf("CDROM read with status %x\n", status);
    exit(1);
  }
  loc += i;
  size -= i;
  while (size > 0) {
    if (size > NBLOCK) j = NBLOCK; else j = size;
    if (write(fd, buf, FRAME_SIZE * i) == -1) {
      perror("write");
      exit(1);
    }
    i = j;
    printf("Reading frame %ld to %ld\r", loc, loc+i-1);
    status = ReadLong(loc, i, buf);
    if (status != 0x0100) {
      printf("CDROM read failed with status %x\n", status);
      exit(1);
    }
    loc += i;
    size -= i;
  }
  if (write(fd, buf, FRAME_SIZE * i) == -1) {
    perror("write");
    exit(1);
  }
  close(fd);
  free(&track_loc[lowest]);
  free(buf);
}

--
   ________________________________________________________________________
  /             National Chiao Tung University in Taiwan                 / \
 |  Name: Yeng-Chee Su              Dept:  Computer Engineering         |__/
 |  Phone: +886-35-783513           E-mail: [email protected]    |
 |  Address: 22, Alley 2, Lane 173, Gao Tsui Road, HsinChu, Taiwan 300  |___ 
  \______________________________________________________________________\__/


+++ Dep. Computer Sci. & Information Eng., Chiao Tung Univ., Taiwan, R.O.C
-!- uugate 0.31 (OS/2 2.10)
 ! Origin: Internet gateway (cindy) (2:200/427.3)