/*  CDP plays arbitrary segment of a Music CD               */

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

#define FALSE  0
#define TRUE   1

int cdrom_loaded, cdrom_drive;

struct ioctl_struc ioctl_block;
struct diskinfo_struc diskinfo_block;
struct trackinfo_struc trackinfo_block[100];

unsigned long red2hsg(unsigned long redval);

main(int argc, char *argv[])
{
       int drive, i;

       unsigned long start_sect, end_sect, leadout_sect, num_sect;
       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 > 1) {
               if (! check_cd2f()){
                       printf("MSCDEX NOT LOADED\n");
                       exit(1);
               }

               Stop();
               if((argv[1][0] == 's') || (argv[1][0] == 'S'))
                       exit(1);

               while(get_diskinfo() != STAT_DONE);

               for(i = diskinfo_block.low_track; i <= diskinfo_block.high_track; i++)
                       get_trackinfo(i);

               leadout_sect = red2hsg(diskinfo_block.start_leadout);

               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;

               if(argc > 2)
               {
                       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]);
               }
               start_sect = red2hsg(trackinfo_block[track].start_point)+(start_min*60L+((long)start_sec))*75L+((long)start_frame) -150L;

               if(argc > 3)
               {
                       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]);
                       end_sect = red2hsg(trackinfo_block[track].start_point)+(end_min*60L+((long)end_sec))*75L+((long)end_frame) -150L;
               }
               else end_sect = leadout_sect;

               num_sect = end_sect-start_sect;

               printf("Start sector     : %lu\n", start_sect);
               printf("End   sector     : %lu\n", end_sect);
               printf("Number of sectors: %lu\n", num_sect);
               printf("CDDA data size   : %lu bytes\n", num_sect * 2352L);

               play(start_sect, num_sect);
       }
       else {
               printf("CDP  Plays an arbitrary section of a CD\n");
               printf("usage: cdp <track> [<start MM:SS:FF>] [<end MM:SS:FF>]\n");
               printf("      \"cdp s\" stops playing\n");
       }
}


check_cd2f()
{
       union REGS regs;

       regs.x.ax = INIT_MP_INT;
       int86(MULTIPLEX_INT,&regs,&regs);
       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,&regs,&regs,&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,&regs,&regs,&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,&regs,&regs,&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_sec = 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,&regs,&regs,&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,&regs,&regs,&sregs);
       return(stop_block.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()
{
       exit(1);
}