/*  DIGIGRAB grabs CD Audio data digitally to a file */

#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include <string.h>
#include <alloc.h>

#define MULTIPLEX_INT   0x2f
#define INIT_MP_INT     0x1500
#define CDREQ_MP_INT    0x1510

#define STAT_HAS_AN_ERROR 0x8000
#define STAT_BUSY         0x0200
#define STAT_DONE         0x0100

int CDRomLoaded,CDRomDrive;

#define CD_READ_LONG         128
#define READ_IOCTL_COMMAND   3
#define WRITE_IOCTL_COMMAND  12

#define CD_STATUS_COMMAND     6

#define GET_AUDIO_DISKINFO    10
#define GET_AUDIO_TRACKINFO   11


#define ADDR_HSG 0
#define ADDR_RED 1

#define COOKED 0
#define RAW    1

#define FALSE  0
#define TRUE   1


static int StatusWord;

typedef struct {
  unsigned char ParamLength;
  unsigned char SubUnit;
  unsigned char CommandCode;
  unsigned int  Status;
  unsigned long Reserved1;
  unsigned long Reserved2;

  unsigned char AddressMode;
  unsigned long Transfaddr;
  unsigned int  Numsec;
  unsigned long Startsec;
  unsigned char Readmode;
  unsigned char Interlsiz;
  unsigned char Interlskip;
} ReadLongStru;


typedef struct {
  unsigned char ParamLength;
  unsigned char SubUnit;
  unsigned char CommandCode;
  unsigned int  Status;
  unsigned long Reserved1;
  unsigned long Reserved2;

  unsigned char Meddescr;
  unsigned long Transfaddr;
  unsigned int  Numbytes;
  unsigned int  Startsec;
  unsigned long volID;
} IOCTLStru;

typedef struct {
  unsigned char CntrlCode;
  unsigned char LowTrack;
  unsigned char HighTrack;
  unsigned long StartLeadout;
} DiskInfoStruc;

typedef struct {
  unsigned char CntrlCode;
  unsigned char Tracknum;
  unsigned long Startpoint;
  unsigned char TrackCtrlInfo;
} TrackInfoStruc;

ReadLongStru ReadLongBlock;
IOCTLStru IOCTLBlock;
DiskInfoStruc DiskInfoBlock;
TrackInfoStruc TrackInfoBlock[100];

unsigned long Red2HSG(unsigned long RedValue);

long LastSector;
int NumTracks;

int *buffer;

main(int argc, char *argv[])
{
unsigned long ssec,esec;
unsigned int nsec,secstograb,i,j,offs;
unsigned char filename[80];
FILE *outfp;

int Track,StartMin,StartSec,EndMin,EndSec,StartFrame,EndFrame;
float TempFloat;
char LocalBuffer[132];
char c = ':';
unsigned char skip;

               if (!CheckCD2F()){
                       printf("MSCDEX NOT LOADED\n");
                       exit(1);
               }

               GetDiskInfo();

               for(i = DiskInfoBlock.LowTrack; i <= DiskInfoBlock.HighTrack; i++)
                       GetTrackInfo(i);

               ssec = atol(argv[1]);

               buffer = calloc(5000,1);

               outfp = fopen("1sect.raw","wb");

               ReadLong(ssec,1);
               while(ReadLongBlock.Status & STAT_HAS_AN_ERROR)
                               ReadLong(ssec,1);

               fwrite(&buffer[i],2,1176,outfp);

               fclose(outfp);
               free(buffer);
}



CheckCD2F()
{
union REGS regs;

       regs.x.ax = INIT_MP_INT;
       int86(MULTIPLEX_INT,&regs,&regs);
       CDRomLoaded = regs.x.bx;
       CDRomDrive = regs.x.cx;
}

GetDiskInfo()
{
union REGS regs;
struct SREGS sregs;

       DiskInfoBlock.CntrlCode = GET_AUDIO_DISKINFO;

       IOCTLBlock.ParamLength = 13;
       IOCTLBlock.SubUnit     = 0;
       IOCTLBlock.CommandCode = READ_IOCTL_COMMAND;
       IOCTLBlock.Status      = 0;

       IOCTLBlock.Meddescr = 0;
       IOCTLBlock.Transfaddr =  (unsigned long)&DiskInfoBlock;
       IOCTLBlock.Numbytes = 7;
       IOCTLBlock.Startsec = 0;
       IOCTLBlock.volID = 0;

       regs.x.ax = CDREQ_MP_INT;
       regs.x.bx = FP_OFF(&IOCTLBlock);
       regs.x.cx = CDRomDrive;
       sregs.es  = FP_SEG(&IOCTLBlock);

       int86x(MULTIPLEX_INT,&regs,&regs,&sregs);

       return(IOCTLBlock.Status);
}

GetTrackInfo(unsigned char trk)
{
union REGS regs;
struct SREGS sregs;

       TrackInfoBlock[trk].CntrlCode = GET_AUDIO_TRACKINFO;
       TrackInfoBlock[trk].Tracknum = trk;

       IOCTLBlock.ParamLength = 13;
       IOCTLBlock.SubUnit     = 0;
       IOCTLBlock.CommandCode = READ_IOCTL_COMMAND;
       IOCTLBlock.Status      = 0;

       IOCTLBlock.Meddescr = 0;
       IOCTLBlock.Transfaddr =  (unsigned long)&(TrackInfoBlock[trk]);
       IOCTLBlock.Numbytes = 7;
       IOCTLBlock.Startsec = 0;
       IOCTLBlock.volID = 0;

       regs.x.ax = CDREQ_MP_INT;
       regs.x.bx = FP_OFF(&IOCTLBlock);
       regs.x.cx = CDRomDrive;
       sregs.es  = FP_SEG(&IOCTLBlock);

       int86x(MULTIPLEX_INT,&regs,&regs,&sregs);

       return(IOCTLBlock.Status);
}


ReadLong(unsigned long SSec,unsigned int numsecs)
{
union REGS regs;
struct SREGS sregs;

       ReadLongBlock.ParamLength = 13;
       ReadLongBlock.SubUnit     = 0;
       ReadLongBlock.CommandCode = CD_READ_LONG;
       ReadLongBlock.Status      = 0;
       ReadLongBlock.AddressMode = ADDR_HSG;

       ReadLongBlock.Transfaddr = (int far*) buffer;
       ReadLongBlock.Numsec     = numsecs;
       ReadLongBlock.Startsec   = SSec;
       ReadLongBlock.Readmode   = RAW;
       ReadLongBlock.Interlsiz  = 0;
       ReadLongBlock.Interlskip = 0;

       regs.x.ax = CDREQ_MP_INT;
       regs.x.bx = FP_OFF(&ReadLongBlock);
       regs.x.cx = CDRomDrive;
       sregs.es  = FP_SEG(&ReadLongBlock);

       int86x(MULTIPLEX_INT,&regs,&regs,&sregs);

       return(ReadLongBlock.Status);
}


unsigned long Red2HSG(unsigned long RedValue)
{
unsigned long Mins;
unsigned long Secs;
unsigned long PlusFrames;

       PlusFrames = RedValue & 0x000000ffL;

       Secs = ((RedValue & 0x0000ff00L) >> 8);

       Mins = ((RedValue & 0x00ff0000L) >> 16);

       return((Mins*60+Secs)*75+PlusFrames);
}