______________________________________________________________________________ | SECTION 1 PART A SUBPART 2 | CD Programming Part 3 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Part 3: Getting Information About the Audio-CD Hi! I'm back! In the third part of the guide we are going to get some info about the Audio-CD which is hopefully inserted at this point. Actually, it doesn't really matter whether you have an audio cd in the drive or not. So, another WARNING at this point: NEVER EVER try to play DATA CD's with this program! I have never tried it, since others have warned me, so I'll just pass this warning along to you. If you remember the last piece of code we wrote RESET the drive. Well, that's nice isn't it, especially since it is so useful and impressive (I hope you catch the sarcasm). So ... what are we gonna do now? We have two more things to do in order to play the entire disk: Determine the total playtime and instruct the drive to play all sectors from 0 to the lead-out track (end) of the CD. Oh, an IMPORTANT note: Whenever you have to DETERMINE something, you use IOCTL INPUT and sometimes when you INSTRUCT the drive to do something, you use IOCTL OUTPUT. Remember when we reset the drive, we instructed the drive to perform an action, so we used IOCTL OUTPUT. The way we address these I/O functions is by modifying the request header command code field. In the reset code we used 12, which tells the driver to use OUTPUT. Since there are many instructions you can output to the drive (EJECT uses OUTPUT), we needed another control block to give the driver some extra info. The next routine will READ information from the drive in drv%. So we will use IOCTL INPUT which is command code 3 in the request header. Compare the Reset and DiskInfo routines if you don't understand what I am talking about. This particular routine will need a buffer of 7 bytes where we put our information. This is also termed the control block, since the first byte, cb(0), gives the driver instructions. In our routine cb(0) will be 10, which will return the lowest track number, highest track number and the location of the lead-out track (end of CD). The code looks very similar to the reset routine. 'Get DiskInfo REDIM cb(6) AS STRING * 1 'We will resize our arrays, which sets them REDIM rh(25) AS STRING * 1 'also equal to zero 'Declare the contents we want in the buffer after the call cb(0) = CHR$(10) 'Control block code: 10 is DiskInfo 'Construct our request header! Notice that the only differences are in rh(2) 'and rh(19) rh(0) = CHR$(26) 'Length of request header in bytes rh(2) = CHR$(3) 'Request header command code field: 3 is IOCTL Input rh(14) = CHR$(lbyte%(VARPTR(cb(0)))) 'The next four lines reference the rh(15) = CHR$(hbyte%(VARPTR(cb(0)))) 'address of our control block rh(16) = CHR$(lbyte%(VARSEG(cb(0)))) rh(17) = CHR$(hbyte%(VARSEG(cb(0)))) rh(18) = CHR$(0) 'Number of bytes to transfer;Highbyte rh(19) = CHR$(7) 'Number of bytes to transfer;Lowbyte 'Call interrupt again inregsx.ax = &H1510 inregsx.es = VARSEG(rh(0)) inregsx.bx = VARPTR(rh(0)) inregsx.cx = drv% CALL interruptx(&H2F, inregsx, outregsx) 'Looky here! Our control block now contains data! CDEndMin = ASC(cb(5)) CDEndSec = ASC(cb(4)) CDEndFrm = ASC(cb(3)) 'CDLength is the length of the CD in High Sierra sectors the formula for 'computing it is: CDLength = CDEndMin * 60 * 75 + CDEndSec * 75 + CDEndFrm - 150 PRINT "Total Playtime of CD: "; CDEndMin; ":"; CDEndSec; "."; CDEndFrm Oh, the lowest track number is in cb(1) and the highest track number in cb(2). Now we are ready to play the entire disk. I guess since the PLAY function is used quite a bit, Microsoft gave it its own command code for the request header, which is 132. The following routine does the play thing. It takes a transfer mode value in rh(13). I used High Sierra format, since we will have to use sectors to specify the playing time. Well...Here's the code. ' Play Audio REDIM rh(21) AS STRING * 1 'Redimension our request header rh(0) = CHR$(22) 'Give it's length in bytes rh(2) = CHR$(132) 'Command code for PLAY rh(13) = CHR$(0) 'Transfer Mode (0 HSG/1 RBA) rh(14) = CHR$(0) 'Start Address rh(15) = CHR$(0) 'Start Address rh(16) = CHR$(0) 'Start Address rh(17) = CHR$(0) 'Start Address rh(18) = CHR$((CDLength MOD 256)) 'Number of Sectors to play rh(19) = CHR$((CDLength MOD 65536) \ 256) 'Number of Sectors to play rh(20) = CHR$(CDLength \ 65536) 'Number of Sectors to play rh(21) = CHR$(&H0) 'Number of Sectors to play 'Call our interrupt inregsx.ax = &H1510 inregsx.es = VARSEG(rh(0)) inregsx.bx = VARPTR(rh(0)) inregsx.cx = drv% CALL interruptx(&H2F, inregsx, outregsx) END That's it! A short note: If you want to start later in the disk you have to decrease the length to play. For example, if you would want to start playing at sector 150 (2 seconds) you would have to decrease the number of sectors to play by 150. If you have reached this point of the guide and pretty much understand everything, I urge you to go get MSCDEX21.ZIP of the internet. The documentation might confuse you at first, but look up the functions which I discussed in the guide and you'll figure it out. Now, nothing can stop you! Hope hearing from you, Marco Koegler (marco@umr.edu)! -------------------------------------------------------- * EDITOR'S NOTE: * This article was originally printed in Peter Cooper's BASIX Fanzine, * Issue #7 from November 1996.