/* 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 cdrom_loaded, cdrom_drive;
struct EMMMoveStruct moverec;
unsigned int xmshandle, xmsfree,xmstot;
struct readlong_struc readlong_block;
struct ioctl_struc ioctl_block;
struct diskinfo_struc diskinfo_block;
struct trackinfo_struc trackinfo_block[100];
unsigned long red2hsg(unsigned long redval);
int *buffer;
struct wavhdr_str {
unsigned char riff[4];
unsigned long riff_len;
unsigned char wave[4];
unsigned char fmt[4];
unsigned long fmt_len;
unsigned int fmt_tag;
unsigned int channels;
unsigned long smp_sec;
unsigned long avg_smp_sec;
unsigned int blk_align;
unsigned int bits_per_sample;
unsigned char data[4];
unsigned long smpdata_len;
} wavhdr;
main(int argc, char *argv[])
{
struct dfree diskfree;
long avail;
int drive;
unsigned long start_sect, end_sect, start_sect2;
unsigned int num_sect, num_sect2, sects_to_grab, sects_to_write,i,j,k,offs;
unsigned char filename[80];
FILE *outfp;
int track, start_min, start_sec, start_frame, end_min, end_sec, end_frame;
char local_buffer[132];
char c = ':';
if(argc > 3) {
if (! check_cd2f()){
printf("MSCDEX NOT LOADED\n");
exit(1);
}
if(!XMS_Setup()) {
printf("No XMS handler installed!\n");
exit(1);
}
while(get_diskinfo() != STAT_DONE);
for(i = diskinfo_block.low_track; i <= diskinfo_block.high_track; i++)
get_trackinfo(i);
track = atoi(argv[1]);
if( (track < 1) || (track > diskinfo_block.high_track)) {
printf("Error: Track must be between %d and %d\n",
diskinfo_block.low_track, diskinfo_block.high_track);
errexit();
}
start_min = 0;
start_sec = 0;
start_frame = 0;
end_min = 0;
end_sec = 0;
end_frame = 0;
strcpy(local_buffer, argv[2]);
start_min = atoi(strtok(local_buffer, ":"));
start_sec = atoi(strtok(NULL, ":"));
start_frame = atoi(&local_buffer[strrchr(argv[2],c)+1-local_buffer]);
strcpy(local_buffer, argv[3]);
end_min = atoi(strtok(local_buffer, ":"));
end_sec = atoi(strtok(NULL, ":"));
end_frame = atoi(&local_buffer[strrchr(argv[3],c)+1-local_buffer]);
start_sect = red2hsg(trackinfo_block[track].start_point)+(start_min*60L+((long)start_sec))*75L+((long)start_frame) -150L;
end_sect = red2hsg(trackinfo_block[track].start_point)+(end_min*60L+((long)end_sec))*75L+((long)end_frame) -150L;
num_sect = (unsigned int)(end_sect-start_sect);
num_sect2 = num_sect;
start_sect2 = start_sect;
printf("Start sector : %ld\n", start_sect);
printf("End sector : %ld\n", end_sect);
printf("Number of sectors: %d\n", num_sect);
printf("CDDA data size : %ld bytes\n", ((unsigned long)num_sect)*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 long)num_sect)*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 < ((unsigned long)num_sect)*2352L) {
printf("Not enough disk space!\n");
errexit();
}
strcpy(filename,argv[4]);
outfp = fopen(filename,"wb");
if(strstr(strupr(filename), ".WAV"))
{
strncpy(wavhdr.riff, "RIFF", 4);
strncpy(wavhdr.wave, "WAVE", 4);
strncpy(wavhdr.fmt, "fmt ", 4);
wavhdr.fmt_len = 0x10L;
wavhdr.fmt_tag = 0x01;
wavhdr.channels = 0x02;
wavhdr.smp_sec = 44100L;
wavhdr.avg_smp_sec = 44100L;
wavhdr.blk_align = 0x02;
wavhdr.bits_per_sample = 16;
strncpy(wavhdr.data, "data", 4);
wavhdr.smpdata_len = ((unsigned long)num_sect)*2352L;
wavhdr.riff_len = wavhdr.smpdata_len + 36L;
fwrite(&wavhdr, sizeof(wavhdr), 1,outfp);
}
moverec.TLen = 58800L; /* 2352 bytes * 25 sectors */
moverec.SHand = 0;
moverec.SOff = (unsigned long)buffer;
moverec.DHand = xmshandle;
moverec.DOff = 0L;
do{
sects_to_grab = 25;
if(num_sect2 < 25) {
sects_to_grab = num_sect2;
moverec.TLen = (unsigned long)(sects_to_grab*2352);
}
read_long(start_sect2, sects_to_grab);
while(readlong_block.req_hdr.status & STAT_HAS_AN_ERROR)
read_long(start_sect2, sects_to_grab);
XMS_MoveEMB(&moverec);
start_sect2 += 25;
num_sect2 -= 25;
moverec.DOff += 58800L;
} while ((int)num_sect2 > 0);
moverec.TLen = 58800;
moverec.SHand = xmshandle;
moverec.SOff = 0L;
moverec.DHand = 0;
moverec.DOff = (unsigned long)buffer;
do {
sects_to_write = 25;
if(num_sect < 25) {
sects_to_write = num_sect;
moverec.TLen = (unsigned long)(sects_to_write*2352);
}
XMS_MoveEMB(&moverec);
fwrite(buffer,2,1176*sects_to_write,outfp);
moverec.SOff += 58800L;
num_sect -= 25;
} while ((int)num_sect > 0);
fclose(outfp);
free(buffer);
XMS_FreeEMB(xmshandle);
}
else
{
printf("\nPlaying only...\n");
play(start_sect, (unsigned long)num_sect);
}
}
else {
printf("DAGRAB CD-DA Audio grabber v0.1\n");
printf("usage: dagrab <track> <start MM:SS:FF> <end MM:SS:FF> [<filename>]\n");
}
}
check_cd2f()
{
union REGS regs;
regs.x.ax = INIT_MP_INT;
int86(MULTIPLEX_INT,®s,®s);
cdrom_loaded = regs.x.bx;
cdrom_drive = regs.x.cx;
}
get_diskinfo()
{
union REGS regs;
struct SREGS sregs;
diskinfo_block.cntrl_code = GET_AUDIO_DISKINFO;
ioctl_block.req_hdr.param_length = 13;
ioctl_block.req_hdr.sub_unit = 0;
ioctl_block.req_hdr.command_code = READ_IOCTL_COMMAND;
ioctl_block.req_hdr.status = 0;
ioctl_block.med_descr = 0;
ioctl_block.transf_addr = (unsigned long)&diskinfo_block;
ioctl_block.num_bytes = 7;
ioctl_block.start_sect = 0;
ioctl_block.vol_id = 0;
regs.x.ax = CDREQ_MP_INT;
regs.x.bx = FP_OFF(&ioctl_block);
regs.x.cx = cdrom_drive;
sregs.es = FP_SEG(&ioctl_block);
int86x(MULTIPLEX_INT,®s,®s,&sregs);
return(ioctl_block.req_hdr.status);
}
get_trackinfo(unsigned char trk)
{
union REGS regs;
struct SREGS sregs;
trackinfo_block[trk].cntrl_code = GET_AUDIO_TRACKINFO;
trackinfo_block[trk].track_num = trk;
ioctl_block.req_hdr.param_length = 13;
ioctl_block.req_hdr.sub_unit = 0;
ioctl_block.req_hdr.command_code = READ_IOCTL_COMMAND;
ioctl_block.req_hdr.status = 0;
ioctl_block.med_descr = 0;
ioctl_block.transf_addr = (unsigned long)&(trackinfo_block[trk]);
ioctl_block.num_bytes = 7;
ioctl_block.start_sect = 0;
ioctl_block.vol_id = 0;
regs.x.ax = CDREQ_MP_INT;
regs.x.bx = FP_OFF(&ioctl_block);
regs.x.cx = cdrom_drive;
sregs.es = FP_SEG(&ioctl_block);
int86x(MULTIPLEX_INT,®s,®s,&sregs);
return(ioctl_block.req_hdr.status);
}
play(unsigned long ssec,unsigned long numsecs)
{
union REGS regs;
struct SREGS sregs;
struct play_struc play_block;
struct qinfo_struc qinfo_block;
play_block.req_hdr.param_length = 13;
play_block.req_hdr.sub_unit = 0;
play_block.req_hdr.command_code = CD_PLAY_AUDIO;
play_block.req_hdr.status = 0;
play_block.address_mode = ADDR_HSG;
play_block.start_sect = ssec;
play_block.num_sect = numsecs;
regs.x.ax = CDREQ_MP_INT;
regs.x.bx = FP_OFF(&play_block);
regs.x.cx = cdrom_drive;
sregs.es = FP_SEG(&play_block);
int86x(MULTIPLEX_INT,®s,®s,&sregs);
do {
qinfo_block.cntrl_code = GET_QCHAN_INFO;
ioctl_block.req_hdr.param_length = 13;
ioctl_block.req_hdr.sub_unit = 0;
ioctl_block.req_hdr.command_code = READ_IOCTL_COMMAND;
ioctl_block.req_hdr.status = 0;
ioctl_block.med_descr = 0;
ioctl_block.transf_addr = (unsigned long)&qinfo_block;
ioctl_block.num_bytes = 11;
ioctl_block.start_sect = 0;
ioctl_block.vol_id = 0;
regs.x.ax = CDREQ_MP_INT;
regs.x.bx = FP_OFF(&ioctl_block);
regs.x.cx = cdrom_drive;
sregs.es = FP_SEG(&ioctl_block);
int86x(MULTIPLEX_INT,®s,®s,&sregs);
if(kbhit()){
getch();
stop();
break;
}
} while (ioctl_block.req_hdr.status & STAT_BUSY);
}
stop()
{
union REGS regs;
struct SREGS sregs;
struct reqhdr_struc stop_block;
stop_block.param_length = 13;
stop_block.sub_unit = 0;
stop_block.command_code = CD_STOP_AUDIO;
stop_block.status = 0;
regs.x.ax = CDREQ_MP_INT;
regs.x.bx = FP_OFF(&stop_block);
regs.x.cx = cdrom_drive;
sregs.es = FP_SEG(&stop_block);
int86x(MULTIPLEX_INT,®s,®s,&sregs);
return(stop_block.status);
}
read_long(unsigned long ssec,unsigned int numsecs)
{
union REGS regs;
struct SREGS sregs;
readlong_block.req_hdr.param_length = 13;
readlong_block.req_hdr.sub_unit = 0;
readlong_block.req_hdr.command_code = CD_READ_LONG;
readlong_block.req_hdr.status = 0;
readlong_block.address_mode = ADDR_HSG;
readlong_block.transf_addr = (int far*)buffer;
readlong_block.num_sect = numsecs;
readlong_block.start_sect = ssec;
readlong_block.read_mode = RAW;
readlong_block.interl_size = 0;
readlong_block.interl_skip = 0;
regs.x.ax = CDREQ_MP_INT;
regs.x.bx = FP_OFF(&readlong_block);
regs.x.cx = cdrom_drive;
sregs.es = FP_SEG(&readlong_block);
int86x(MULTIPLEX_INT,®s,®s,&sregs);
return(readlong_block.req_hdr.status);
}
unsigned long red2hsg(unsigned long redval)
{
unsigned long mins;
unsigned long secs;
unsigned long plus_frames;
plus_frames = redval & 0x000000ffL;
secs = ((redval & 0x0000ff00L) >> 8);
mins = ((redval & 0x00ff0000L) >> 16);
return((mins*60+secs)*75+plus_frames);
}
errexit()
{
XMS_FreeEMB(xmshandle);
exit(1);
}