unit cdrom;
{
this program will allow the control of multiple cd-rom audio drives
simultaniously.
I am not sure just yet what sort of an interface I'm going to provide
but we will soon see eh?
}
{ prototype #1, just get talking to an audio CD-ROM
}
interface
uses crt;
const
MAX_TRACKS_PER_CD = 30;
type
TAudioTrackRec = record
code : byte;
track : byte;
startPoint : longint;
trackInfo : byte;
end;
TAudioDiskRec = record
code : byte;
lowTrack : byte;
highTrack : byte;
startPoint : longint;
end;
TTrackRec = record
number : byte;
start : longint;
finish : longint;
end;
TTrackArray = array[1 .. MAX_TRACKS_PER_CD] of TTrackRec;
var
tracks : TTrackArray;
{ This is a VERY simple CD-player. It only plays from the first
{ available CD, and only tracks from 1 - 9 and stops after every
{ track... but it will give you and idea!
}
procedure playATrack;
{Stop the CD player "drive", no errors, even when already stopped}
procedure stopCD( drive : word );
{ Play a track from the presumably already loaded tracks array
{ NO ERROR CHECKING ON THIS!. Programmer to make sure that
{ this procedured is proceeded at some point by calling of the
{ procedure "getAllTrackDetails"}
procedure playTrack( drive, track : word );
{ Play from sectors start to finish on drive.
{ NO ERROR CHECKING }
procedure playTrack2(drive : word; start, finish : longint);
{ If used after a STOPCD, this will resume play at where the CD
{ was stopped, assuming same drive }
procedure resumePlay( drive : word );
{ Gets all the track details for the currently loaded CD and places
{ it into the "TRACKS" array }
procedure getAllTrackDetails( drive : word );
{ Stops and causes the CD tray to eject (if supported) }
procedure ejectCD( drive : word );
{ Closes the CD tray (not supported under OS/2, and many CD players }
procedure closeCD( drive : word );
{ Locks the CD tray, prevents ejection from eject button pressing }
procedure lockCD( drive : word );
{ Unlocks the CD track, allows ejection from eject button pressing }
procedure unlockCD( drive : word );
{ Refreshes the buffers in the CD player, ensures the information is
{ correct }
procedure resetCD( drive : word );
{ Get the Universal Product code of the CD, not usually available }
procedure getUPC( drive : word; var upc : string );
{ Get the VTOC from the CD }
procedure readVTOC( drive : word );
{ Get the details of a particular track on the CD }
procedure getTrackDetails( drive : word;
trk : byte;
var t : TAudioTrackRec
);
{ Get the number of CD players, and the first CD number }
function getNumberOfCDs( var sLetter : word ) : word;
function getUnique( drive : word ) : string;
{ Get the Details of the currently loaded CD }
function getCDDetails( drive : word; var t : TAudioDiskRec ) : word;
{ Get the number of tracks of the currently loaded CD }
function getNumberOfTracks( drive : word ) : word;
{ Get the running time of the currently playing track }
function getRunningTime( drive : word; var min,sec : byte ) : word;
{ Returns true if the CD player has been changed and no update of
{ information has occured }
function mediaChanged( drive : word ) : boolean;
{ Returns TRUE if the CD-tray is ejected }
function doorOpen(drive : word) : boolean;
implementation
const
EJECT_TRAY = 0;
CLOSE_TRAY = 5;
PLAY_TRACK = 132;
STOP_TRACK = 133;
RESUME_TRACK = 136;
RESET_CD = 2;
GET_TRACK_INFO = 11;
GET_DISK_INFO = 10;
READ_IOCTL = 3;
WRITE_IOCTL = 12;
MAX_CDS = 10;
UPC_CODE = 14;
LOCK_CODE = 1;
LOCK_CD = 0;
UNLOCK_CD = 1;
Q_INFO = 12;
MEDIA_CHANGE = 9;
DEVICE_STATUS = 6;
type
rHRec = record
length : byte;
subUnitCode : byte;
commandCode : byte;
status : word;
reserved : array[1..8] of byte;
end;
IOCTLRec = record
r : rHRec;
MDB : byte;
tAOfs : word;
tASeg : word;
bytesToTransfer : word;
startingSector : word;
error : longint;
end;
TLockRec = record
r : rHRec;
code : byte;
lock : byte;
end;
TUPCRec = record
code : byte;
control : byte;
UPC : array[1..7] of byte;
zero : byte;
aFrame : byte;
end;
TPlayAudioTrackRec = record
r : rHRec;
mode : byte;
start : longint;
sectors : longint;
end;
TQRec = record
code : byte;
ADR : byte;
Track : byte;
Point : byte;
min : byte;
sec : byte;
frame : byte;
zero : byte;
pMin : byte;
pSec : byte;
pFrame : byte;
end;
TMediaRec = record
code : byte;
media : byte;
end;
TStatusRec = record
code : byte;
status : longint;
end;
TTrackNameArray = array[1 .. MAX_TRACKS_PER_CD] of string[40];
TCDROMRec = record
UPC : longint;
cdName : string[40];
trackNames : TTrackNameArray;
maxTrack : byte;
end;
TCDRackRec = record
status : array[1 .. MAX_CDS] of word;
rack : array[1 .. MAX_CDS] of TTrackArray;
info : array[1 .. MAX_CDS] of TCDROMRec;
end;
var
CDRack : TCDRackRec;
result : word;
startLetter : word;
{--------------------------------------------------------------------}
{Play A Track
{ This is a very simple CD player, which only plays the first
{ available CD, and only tracks 1-9. However, it does give
{ the idea.
}
procedure playATrack;
var
k : char;
trk : word;
e : integer;
drive : word;
quit : boolean;
begin
getNumberOfCDs(drive);
getAllTrackDetails(drive);
quit := FALSE;
repeat
repeat until keypressed;
k := readKey;
stopCD(drive);
if (k >= '1') and (k <= '9') then begin
write('Playing track : ',k,' ');
val(k,trk,e);
playTrack(drive,trk);
end
else quit := TRUE;
until quit;
end;
{--------------------------------------------------------------------}
{
{
{
{
}
function getNumberOfCDs( var sLetter : word) : word;
var drives, startLetter : word;
begin
asm
mov ax,1500h
int 2fh;
mov startLetter,CX
mov drives,BX
end;
sLetter := startLetter;
getNumberOfCDs := drives;
end;
{--------------------------------------------------------------------}
{
{
{
{
}
procedure setIOCTL( var i : IOCTLRec );
var index : byte;
begin
with i do begin
with r do begin
length := 0;
subUnitCode := 0;
commandCode := 0;
status := 0;
for index := 1 to 8 do reserved[index] := 0;
end;{with R}
MDB := 0;
tASeg := 0;
tAOfs := 0;
bytesToTransfer := 0;
startingSector := 0;
error := 0;
end;{with i}
end;
{--------------------------------------------------------------------}
{
{
{
{
}
procedure getTrackDetails( drive : word;
trk : byte;
var t : TAudioTrackRec
);
var index : word;
i : IOCTLRec;
s,o : word;
begin
setIOCTL(i);
with i do begin
bytesToTransfer := 7;
tAOfs := ofs(t);
tASeg := seg(t);
end;
with i.r do begin
length := sizeof(i);
commandCode := READ_IOCTL;
end;
with t do begin
track := trk;
code := GET_TRACK_INFO;
end;
s := seg(i);
o := ofs(i);
asm
mov ax,1510h
mov cx,drive
mov es,S
mov bx,O
int 2fh
end;
{ t will now contain the relevant information }
end;
{--------------------------------------------------------------------}
{
{
{
{
}
function getCDDetails( drive : word;
var t : TAudioDiskRec
) : word;
var index : word;
i : IOCTLRec;
s,o : word;
begin
setIOCTL(i);
with i do begin
bytesToTransfer := 7;
tAOfs := ofs(t);
tASeg := seg(t);
end;
with i.r do begin
length := sizeof(i);
commandCode := READ_IOCTL;
end;
with t do begin
code := GET_DISK_INFO;
lowTrack := 0;
highTrack := 0;
startPoint := 0;
end;
s := seg(i);
o := ofs(i);
asm
mov ax,1510h
mov cx,drive
mov es,S
mov bx,O
int 2fh
end;
{ t will now contain the relevant information }
getCDDetails := i.r.status;
end;
{--------------------------------------------------------------------}
{
{
{
{
}
function redBookToSectors( red : longint ) : longint;
var
frame, minute, second : byte;
temp : longint;
begin
frame := (red AND $000000FF);
second := (red AND $0000FF00) shr 8;
minute := (red AND $00FF0000) shr 16;
temp := minute *60;
temp := temp *75;
temp := temp + second *75;
temp := temp + frame -150;
redBookToSectors := temp;
end;
{--------------------------------------------------------------------}
{
{
{
{
}
procedure getAllTrackDetails( drive : word );
var
diskInfo : TAudioDiskRec;
aTrack : TAudioTrackRec;
firstCD : word;
currentTrack : byte;
index1, index2 : byte;
pos1,pos2,pos3 : word;
begin
getCDDetails(drive,diskInfo);
for currentTrack := diskInfo.lowTrack to diskInfo.highTrack do begin
getTrackDetails(firstCD,currentTrack,aTrack);
with tracks[currentTrack] do begin
number := currentTrack;
start := aTrack.startPoint;
if (currentTrack > 1) then begin
tracks[currentTrack-1].finish := tracks[currentTrack].start-1;
end;
end;{with}
end;{for}
end;
{--------------------------------------------------------------------}
{
{
{
{
}
procedure stopCD(drive : word);
var r : rHRec;
s,o : word;
begin
r.commandCode := 133;
r.length := sizeOf(r);
s := seg(r);
o := ofs(r);
asm
mov ax,1510h
mov cx,drive
mov es,S
mov bx,O
int 2fh
end;
end;
{--------------------------------------------------------------------}
{
{
{
{
}
procedure playTrack(drive,track : word);
var index : word;
p : TPlayAudioTrackRec;
s,o : word;
st,fi : longint;
begin
p.r.subUnitCode := 0;
p.r.status := 0;
p.r.commandcode := 132;
p.r.length := sizeOf(p);
for index := 1 to 8 do begin
p.r.reserved[index] := 0;
end;
p.start := tracks[track].start;
fi := redBookToSectors(tracks[track].finish);
st := redBookToSectors(tracks[track].start);
p.sectors := fi-st;
p.mode := 1;
s := seg(p);
o := ofs(p);
asm
mov ax,1510h
mov cx,drive
mov es,S
mov bx,O
int 2fh
end;
end;
{--------------------------------------------------------------------}
{
{
{
{
}
procedure playTrack2(drive : word;
start, finish : longint);
var index : word;
p : TPlayAudioTrackRec;
s,o : word;
st,fi : longint;
begin
p.r.subUnitCode := 0;
p.r.status := 0;
p.r.commandcode := 132;
p.r.length := sizeOf(p);
for index := 1 to 8 do begin
p.r.reserved[index] := 0;
end;
p.start := start;
fi := redBookToSectors(finish);
st := redBookToSectors(start);
p.sectors := fi-st;
p.mode := 1;
s := seg(p);
o := ofs(p);
asm
mov ax,1510h
mov cx,drive
mov es,S
mov bx,O
int 2fh
end;
end;
{--------------------------------------------------------------------}
{
{
{
{
}
procedure ejectCD( drive : word );
var index : word;
ejRec : record
code : byte;
end;
i : IOCTLRec;
rq : rHRec;
s,o : word;
begin
setIOCTL(i);
with i do begin
bytesToTransfer := 1;
tAOfs := ofs(ejRec);
tASeg := seg(ejRec);
end;
with i.r do begin
length := sizeof(i);
commandCode := 12;
end;
ejRec.code := EJECT_TRAY;
s := seg(i);
o := ofs(i);
asm
mov ax,1510h
mov cx,drive
mov es,S
mov bx,O
int 2fh
end;
end;
{--------------------------------------------------------------------}
{
{
{
{
}
procedure closeCD( drive : word );
var index : word;
ejRec : record
code : byte;
end;
i : IOCTLRec;
rq : rHRec;
s,o : word;
begin
setIOCTL(i);
with i do begin
bytesToTransfer := 1;
tAOfs := ofs(ejRec);
tASeg := seg(ejRec);
end;
with i.r do begin
length := sizeof(i);
commandCode := 12;
end;
ejRec.code := CLOSE_TRAY;
s := seg(i);
o := ofs(i);
asm
mov ax,1510h
mov cx,drive
mov es,S
mov bx,O
int 2fh
end;
end;
{--------------------------------------------------------------------}
{
{
{
{
}
procedure resetCD( drive : word );
var index : word;
resetRec : record
code : byte;
end;
i : IOCTLRec;
rq : rHRec;
s,o : word;
begin
setIOCTL(i);
with i do begin
bytesToTransfer := 1;
tAOfs := ofs(resetRec);
tASeg := seg(resetRec);
end;
with i.r do begin
length := sizeof(i);
commandCode := 12;
end;
resetRec.code := RESET_CD;
s := seg(i);
o := ofs(i);
asm
mov ax,1510h
mov cx,drive
mov es,S
mov bx,O
int 2fh
end;
end;
{--------------------------------------------------------------------}
{
{
{
{
}
procedure lockCD( drive : word );
var index : word;
lockRec : record
code : byte;
lock : byte;
end;
i : IOCTLRec;
rq : rHRec;
s,o : word;
begin
setIOCTL(i);
with i do begin
bytesToTransfer := 2;
tAOfs := ofs(lockRec);
tASeg := seg(lockRec);
end;
with i.r do begin
length := sizeof(i);
commandCode := 12;
end;
lockRec.code := LOCK_CODE;
lockRec.lock := LOCK_CD;
s := seg(i);
o := ofs(i);
asm
mov ax,1510h
mov cx,drive
mov es,S
mov bx,O
int 2fh
end;
end;
{--------------------------------------------------------------------}
{
{
{
{
}
procedure unlockCD( drive : word );
var index : word;
lockRec : record
code : byte;
lock : byte;
end;
i : IOCTLRec;
rq : rHRec;
s,o : word;
begin
setIOCTL(i);
with i do begin
bytesToTransfer := 2;
tAOfs := ofs(lockRec);
tASeg := seg(lockRec);
end;
with i.r do begin
length := sizeof(i);
commandCode := 12;
end;
lockRec.code := LOCK_CODE;
lockRec.lock := LOCK_CD;
s := seg(i);
o := ofs(i);
asm
mov ax,1510h
mov cx,drive
mov es,S
mov bx,O
int 2fh
end;
end;
{--------------------------------------------------------------------}
{
{
{
{
}
function getUnique( drive : word ) : string;
var
a : TAudioDiskRec;
s : string;
begin
getCDDetails(drive,a);
Str(a.startPoint,s);
getUnique := s;
end;
{--------------------------------------------------------------------}
{
{
{
{
}
procedure getUPC( drive : word; var UPC : string );
var u : TUPCRec;
s,o : word;
index : integer;
res : byte;
i : IOCTLRec;
begin
setIOCTL(i);
with i do begin
bytesToTransfer := 11;
tAOfs := ofs(u);
tASeg := seg(u);
end;
with i.r do begin
length := 23{sizeof(i);};
commandCode := READ_IOCTL;
end;
u.code := UPC_CODE;
u.control := 2;
s := seg(i);
o := ofs(i);
asm
mov ax,1510h
mov cx,drive
mov es,S
mov bx,O
int 2fh
end;
upc := '';
for index := 1 to 7 do begin
res := (u.upc[index] AND $0F);
upc := concat(upc,chr(res+48));
if (index < 7) then begin
res := ((u.upc[index] AND $F0) SHR 4);
upc := concat(upc,chr(res+48));
end;
end;{for}
end;
{--------------------------------------------------------------------}
{
{
{
{
}
function getNumberOfTracks( drive : word ) : word;
var a : TAudioDiskRec;
begin
getCDDetails(drive,a);
getNumberOfTracks := a.highTrack;
end;
{--------------------------------------------------------------------}
{
{
{
{
}
procedure readVTOC( drive : word );
var
buffer : array[1..2048] of byte;
s,o : word;
begin
o := ofs(buffer);
s := seg(buffer);
asm
mov ax,1508h;
mov cx,drive;
mov si,s ;
mov di,o ;
mov dx,1 ;
int 2fh;
end
end;
{--------------------------------------------------------------------}
{
{
{
{
}
procedure resumePlay( drive : word );
var r : rHRec;
o,s : word;
begin
r.commandCode := RESUME_TRACK;
r.length := 1;
o := ofs(r);
s := seg(r);
asm
mov ax,1510h;
mov cx,drive;
mov es,s ;
mov bx,o ;
int 2fh;
end
end;
{--------------------------------------------------------------------}
{
{
{
{
}
function getRunningTime( drive : word; var min,sec : byte ) : word;
var q : TQRec;
index : word;
i : IOCTLRec;
rq : rHRec;
s,o : word;
begin
setIOCTL(i);
with i do begin
bytesToTransfer := 1;
tAOfs := ofs(q);
tASeg := seg(q);
end;
with i.r do begin
length := sizeof(i);
commandCode := READ_IOCTL;
end;
q.code := Q_INFO;
s := seg(i);
o := ofs(i);
asm
mov ax,1510h
mov cx,drive
mov es,S
mov bx,O
int 2fh
end;
min := q.min;
sec := q.sec;
getRunningTime := i.r.status;
end;
{--------------------------------------------------------------------}
{
{
{
{
}
function mediaChanged( drive : word ) : boolean;
var q : TMediaRec;
index : word;
i : IOCTLRec;
s,o : word;
begin
setIOCTL(i);
with i do begin
bytesToTransfer := 2;
tAOfs := ofs(q);
tASeg := seg(q);
end;
with i.r do begin
length := sizeof(i);
commandCode := READ_IOCTL;
end;
q.code := MEDIA_CHANGE;
q.media := 0;
s := seg(i);
o := ofs(i);
asm
mov ax,1510h
mov cx,drive
mov es,S
mov bx,O
int 2fh
end;
if (q.media < 1) then
mediaChanged := TRUE
else mediaChanged := FALSE;
end;
{--------------------------------------------------------------------}
{
{
{
{
}
function doorOpen( drive : word ) : boolean;
var q : TStatusRec;
index : word;
i : IOCTLRec;
s,o : word;
begin
setIOCTL(i);
with i do begin
bytesToTransfer := 5;
tAOfs := ofs(q);
tASeg := seg(q);
end;
with i.r do begin
length := sizeof(i);
commandCode := READ_IOCTL;
end;
q.code := DEVICE_STATUS;
q.status := 0;
s := seg(i);
o := ofs(i);
asm
mov ax,1510h
mov cx,drive
mov es,S
mov bx,O
int 2fh
end;
if (q.status AND $01)=1 then
doorOpen := TRUE
else doorOpen := FALSE;
end;
{--------------------------------------------------------------------}
{
{
{
{
}
procedure init;
var index : word;
begin
{ initially we start this unit by reading all the available
{ CD-ROMs and taking in their track details.
}
for index := 1 to MAX_CDS do begin
with CDRack do begin
status[index] := 0;
info[index].maxTrack := 0;
end;
end;
end;
{--------------------------------------------------------------------}
{
{
{
{
}
begin
{ initially we start this unit by reading all the available
{ CD-ROMs and taking in their track details.
}
init;
end.
{
Paul L Daniels
Software Development (DOS, OS/2)
jackdan@ibm.net
jackdan@ozemail.com.au
}
               (
geocities.com/SiliconValley/2926)                   (
geocities.com/SiliconValley)