/* DAGRABX grabs 16 bit 44.1 KHz CD Audio digitally to a file */
/* This version uses XMS as an intermediate buffer to avoid */
/* the "glitches" that otherwise occur */
#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include <string.h>
#include <alloc.h>
#include <xmslib.h>
#include <cdrom.h>
#define FALSE 0
#define TRUE 1
int CDRomLoaded,CDRomDrive;
struct EMMMoveStruct moverec;
unsigned int xmshandle, xmsfree,xmstot;
struct ReadLongStruc ReadLongBlock;
struct IOCTLStruc IOCTLBlock;
struct DiskInfoStruc DiskInfoBlock;
struct TrackInfoStruc TrackInfoBlock[100];
unsigned long Red2HSG(unsigned long RedValue);
int *buffer;
main(int argc, char *argv[])
{
struct dfree diskfree;
long avail;
int drive;
unsigned long ssec,esec,ssec2,nsec,nsec2;
unsigned int secstograb,secstowrite,i,j,k,offs;
unsigned char filename[80];
FILE *outfp;
int Track,StartMin,StartSec,EndMin,EndSec,StartFrame,EndFrame;
float TempFloat;
char LocalBuffer[132];
char c = ':';
if(argc > 3) {
if (!CheckCD2F()){
printf("MSCDEX NOT LOADED\n");
exit(1);
}
if(!XMS_Setup()) {
printf("No XMS handler installed!\n");
exit(1);
}
while(GetDiskInfo() != STAT_DONE);
for(i = DiskInfoBlock.LowTrack; i <= DiskInfoBlock.HighTrack; i++)
GetTrackInfo(i);
Track = atoi(argv[1]);
if( (Track < 1) || (Track > DiskInfoBlock.HighTrack)) {
printf("Error: Track must be between %d and %d\n",DiskInfoBlock.LowTrack,DiskInfoBlock.HighTrack);
errexit();
}
StartMin = 0;
StartSec = 0;
StartFrame = 0;
EndMin = 0;
EndSec = 0;
EndFrame = 0;
strcpy(LocalBuffer,argv[2]);
StartMin = atoi(strtok(LocalBuffer,":"));
StartSec = atoi(strtok(NULL,":"));
StartFrame = atoi(&LocalBuffer[strrchr(argv[2],c)+1-LocalBuffer]);
strcpy(LocalBuffer,argv[3]);
EndMin = atoi(strtok(LocalBuffer,":"));
EndSec = atoi(strtok(NULL,":"));
EndFrame = atoi(&LocalBuffer[strrchr(argv[3],c)+1-LocalBuffer]);
ssec = Red2HSG(TrackInfoBlock[Track].Startpoint)+(StartMin*60L+((long)StartSec))*75L+((long)StartFrame) -150L;
esec = Red2HSG(TrackInfoBlock[Track].Startpoint)+(EndMin*60L+((long)EndSec))*75L+((long)EndFrame) -150L;
nsec = esec-ssec;
nsec2 = nsec;
ssec2 = ssec;
printf("Start sector : %ld\n",ssec);
printf("End sector : %ld\n",esec);
printf("Number of sectors: %ld\n",nsec);
printf("CDDA data size : %ld bytes\n",nsec*2352l);
if(argc > 4) {
if((buffer = malloc(59000)) == NULL){
printf("Malloc error!\n");
errexit();
}
XMS_FreeMem(&xmsfree,&xmstot);
XMS_AllocEMB(xmsfree,&xmshandle);
if(xmsfree < (unsigned int)(nsec*2352l/1024l)) {
printf("Not enough XMS memory!\n");
errexit();
}
drive = getdisk();
getdfree(drive+1,&diskfree);
avail = (long) diskfree.df_avail *
(long) diskfree.df_bsec *
(long) diskfree.df_sclus;
if(avail < (nsec*2352l)) {
printf("Not enough disk space!\n");
errexit();
}
strcpy(filename,argv[4]);
outfp = fopen(filename,"wb");
moverec.TLen = 58800l; /* 2352 bytes * 25 sectors */
moverec.SHand = 0;
moverec.SOff = (unsigned long)buffer;
moverec.DHand = xmshandle;
moverec.DOff = 0l;
do{
secstograb = 25;
if(nsec2 < 25l) {
secstograb = (unsigned int)nsec2;
moverec.TLen = (unsigned long)(secstograb*2352);
}
ReadLong(ssec2,secstograb);
while(ReadLongBlock.ReqHdr.Status & STAT_HAS_AN_ERROR)
ReadLong(ssec2,secstograb);
XMS_MoveEMB(&moverec);
ssec2+=25l;
nsec2-=25l;
moverec.DOff += 58800l;
} while ((long)nsec2 > 0l);
moverec.TLen = 58800;
moverec.SHand = xmshandle;
moverec.SOff = 0l;
moverec.DHand = 0;
moverec.DOff = (unsigned long)buffer;
do {
secstowrite = 25;
if(nsec < 25l) {
secstowrite = (unsigned int)nsec;
moverec.TLen = (unsigned long)(secstowrite*2352);
}
XMS_MoveEMB(&moverec);
fwrite(buffer,2,1176*secstowrite,outfp);
moverec.SOff += 58800l;
nsec -= 25l;
} while ((long)nsec > 0l);
fclose(outfp);
free(buffer);
XMS_FreeEMB(xmshandle);
}
else
{
printf("\nPlaying only...\n");
Play(ssec,nsec);
}
}
else {
printf("DAGRAB CD-DA Audio grabber v0.1\n");
printf("usage: dagrab <track> <start MM:SS:FF> <end MM:SS:FF> [<filename>]\n");
}
}
CheckCD2F()
{
union REGS regs;
regs.x.ax = INIT_MP_INT;
int86(MULTIPLEX_INT,®s,®s);
CDRomLoaded = regs.x.bx;
CDRomDrive = regs.x.cx;
}
GetDiskInfo()
{
union REGS regs;
struct SREGS sregs;
DiskInfoBlock.CntrlCode = GET_AUDIO_DISKINFO;
IOCTLBlock.ReqHdr.ParamLength = 13;
IOCTLBlock.ReqHdr.SubUnit = 0;
IOCTLBlock.ReqHdr.CommandCode = READ_IOCTL_COMMAND;
IOCTLBlock.ReqHdr.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,®s,®s,&sregs);
return(IOCTLBlock.ReqHdr.Status);
}
GetTrackInfo(unsigned char trk)
{
union REGS regs;
struct SREGS sregs;
TrackInfoBlock[trk].CntrlCode = GET_AUDIO_TRACKINFO;
TrackInfoBlock[trk].Tracknum = trk;
IOCTLBlock.ReqHdr.ParamLength = 13;
IOCTLBlock.ReqHdr.SubUnit = 0;
IOCTLBlock.ReqHdr.CommandCode = READ_IOCTL_COMMAND;
IOCTLBlock.ReqHdr.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,®s,®s,&sregs);
return(IOCTLBlock.ReqHdr.Status);
}
Play(unsigned long SSec,unsigned long numsecs)
{
union REGS regs;
struct SREGS sregs;
struct PlayStruc PlayBlock;
struct QInfoStruc QInfoBlock;
PlayBlock.ReqHdr.ParamLength = 13;
PlayBlock.ReqHdr.SubUnit = 0;
PlayBlock.ReqHdr.CommandCode = CD_PLAY_AUDIO;
PlayBlock.ReqHdr.Status = 0;
PlayBlock.AddressMode = ADDR_HSG;
PlayBlock.Startsec = SSec;
PlayBlock.Numsec = numsecs;
regs.x.ax = CDREQ_MP_INT;
regs.x.bx = FP_OFF(&PlayBlock);
regs.x.cx = CDRomDrive;
sregs.es = FP_SEG(&PlayBlock);
int86x(MULTIPLEX_INT,®s,®s,&sregs);
do {
QInfoBlock.CntrlCode = GET_QCHAN_INFO;
IOCTLBlock.ReqHdr.ParamLength = 13;
IOCTLBlock.ReqHdr.SubUnit = 0;
IOCTLBlock.ReqHdr.CommandCode = READ_IOCTL_COMMAND;
IOCTLBlock.ReqHdr.Status = 0;
IOCTLBlock.Meddescr = 0;
IOCTLBlock.Transfaddr = (unsigned long)&QInfoBlock;
IOCTLBlock.Numbytes = 11;
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,®s,®s,&sregs);
if(kbhit()){
getch();
Stop();
break;
}
} while (IOCTLBlock.ReqHdr.Status & STAT_BUSY);
}
Stop()
{
union REGS regs;
struct SREGS sregs;
struct ReqHdrStruc StopBlock;
StopBlock.ParamLength = 13;
StopBlock.SubUnit = 0;
StopBlock.CommandCode = CD_STOP_AUDIO;
StopBlock.Status = 0;
regs.x.ax = CDREQ_MP_INT;
regs.x.bx = FP_OFF(&StopBlock);
regs.x.cx = CDRomDrive;
sregs.es = FP_SEG(&StopBlock);
int86x(MULTIPLEX_INT,®s,®s,&sregs);
return(StopBlock.Status);
}
ReadLong(unsigned long SSec,unsigned int numsecs)
{
union REGS regs;
struct SREGS sregs;
ReadLongBlock.ReqHdr.ParamLength = 13;
ReadLongBlock.ReqHdr.SubUnit = 0;
ReadLongBlock.ReqHdr.CommandCode = CD_READ_LONG;
ReadLongBlock.ReqHdr.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,®s,®s,&sregs);
return(ReadLongBlock.ReqHdr.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);
}
errexit()
{
XMS_FreeEMB(xmshandle);
exit(1);
}