home *** CD-ROM | disk | FTP | other *** search
/ Groovy Bytes: Behind the Moon / groovybytes.iso / GROOVY / SND_TOOL / CDREADER.ZIP / CTCDREAD.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1994-08-04  |  35.8 KB  |  801 lines

  1. PROGRAM CTCDREAD;
  2.  
  3. {CD-ROM Audio Dump V1.1, U. Rohbeck, 13-Juli-94
  4.                    V1.2, U. Rohbeck, 15-Juli-94 -SONY-}
  5.  
  6. {literature
  7.   Kai Schwitzke: Das VOC- und das WAVE-Dateiformat, c't 01/93 - S.213
  8.   Dr. Bernd Steinbrink: Entwirrung der diversen CD-ROM-Formate, c't 02/93 - S.178
  9.   Small Computer System Interface X3.131-199x, X3T9.2375 Revision 10k,17-Mar-93, Working Draft (SCSI-2)
  10.   Ulf Rohbeck: ASPI-Bibliothek für Assembler, Turbo-Pascal und C, c't 12/93 - S.212}
  11.  
  12. USES CRT,DOS,ASPIxDOS;
  13.  
  14. CONST
  15.  CDRsupport= 4;
  16.  CDRtypeLST: ARRAY[1..CDRsupport] of STRING[16] = ('TOSHIBA','HITACHI',
  17.                                                    'NEC','SONY');
  18. TYPE
  19.  InquireDataFormat = Record
  20.     ConfigPara: ARRAY[0..7] of BYTE;
  21.     VendorID  : ARRAY[1..8] of char;
  22.     ProductID : ARRAY[1..16] of char;
  23.     ProductRev: ARRAY[1..4] of char;
  24.  END;
  25.  AbsCDRaddrFormat = Record
  26.     MSF_rsvd    : Byte;
  27.     MSF_MM      : Byte;
  28.     MSF_SS      : Byte;
  29.     MSF_DD      : Byte;
  30.  END;
  31.  TOCTrackDescriptor = Record
  32.     rsvd01    : Byte;
  33.     AdrControl: Byte;
  34.     TrackNum  : Byte;
  35.     rsvd02    : Byte;
  36.     AbsCDRaddr: AbsCDRaddrFormat;
  37.  END;
  38.  ReadTOCDataFormat = Record
  39.     TOCdataLEN: Word;
  40.     firstTrack: Byte;
  41.     lastTrack : Byte;
  42.     TOCtd     : ARRAY[1..99] of TOCTrackDescriptor;
  43.  END;
  44.  SubChannelDataHeader = Record
  45.     rsvd        : Byte;
  46.     AudioStatus : Byte;
  47.     SubCDataLEN : Array[0..1] of Byte;
  48.  END;
  49.  TrackISRCDataFormat = Record
  50.     SubCHDR   : SubChannelDataHeader;
  51.     SubCDFcode: Byte;   {Sub Channel Data Format Code}
  52.     AdrControl: Byte;
  53.     TNO       : Byte;   {Track Number}
  54.     rsvd      : Byte;
  55.     TCVal     : Byte;
  56.     TrackISRC : Array[0..14] of Byte; {Track International-Standard-Recording-Code}
  57.  END;
  58.  CDROM_CurrentPositionDataFormat = Record
  59.     SubCHDR   : SubChannelDataHeader;
  60.     SubCDFcode: Byte;   {Sub Channel Data Format Code}
  61.     AdrControl: Byte;
  62.     TNO       : Byte;   {Track Number}
  63.     INO       : Byte;   {Index Number}
  64.     AbsCDRaddr: AbsCDRaddrFormat; {Absolute CD-ROM Address}
  65.     TrackRaddr: AbsCDRaddrFormat; {Track Relative CD-ROM Address}
  66.  END;
  67.  MediaCatalogNumberDataFormat = Record
  68.     SubCHDR   : SubChannelDataHeader;
  69.     SubCDFcode: Byte;   {Sub Channel Data Format Code}
  70.     rsvd      : Array[0..2] of Byte;
  71.     MCVal     : Byte;
  72.     MCN       : Array[0..14] of Byte; {Media Catalog Number (UPC/Bar Code}
  73.  END;
  74.  ReadSubQDataFormat = Record
  75.     SubCHDR   : SubChannelDataHeader;
  76.     SubCDFcode: Byte;  {Sub Channel Data Format Code}
  77.     AdrControl: Byte;
  78.     TNO       : Byte;  {Track Number}
  79.     INO       : Byte;  {Index Number}
  80.     AbsCDRaddr: AbsCDRaddrFormat; {Absolute CD-ROM Address}
  81.     TrackRaddr: AbsCDRaddrFormat; {Track Relative CD-ROM Address}
  82.     MCVal     : Byte;
  83.     MCN       : Array[0..14] of Byte; {Media Catalog Number (UPC/Bar Code}
  84.     TCVal     : Byte;
  85.     TrackISRC : Array[0..14] of Byte; {Track International-Standard-Recording-Code}
  86.  END;
  87.  _WAVEhdr = RECORD
  88.     MainDesc  : LongInt;
  89.     lenFile   : LongInt;
  90.     FileType  : LongInt;
  91.     SubDesc   : LongInt;
  92.     lenSubDesc: LongInt;
  93.     Format    : Word;
  94.     Mode      : Word;
  95.     SampleFreq: LongInt;
  96.     BytePerSec: LongInt;
  97.     BytePerSam: Word;
  98.     BitPerSam : Word;
  99.     DataDesc  : LongInt;
  100.     lenData   : LongInt;
  101.  END;
  102.  _ASPI_01 = _ASPI_SRB_GetDeviceType;
  103.  _ASPI_02 = _ASPI_SRB_ExecuteSCSI_IORequest;
  104.  
  105. CONST
  106.  PVer = 1.1;
  107.  PName= 'CDR-AD';
  108.  ModeSelectData : ARRAY[0..11] of BYTE = (
  109.                    $00, {reserved}
  110.                    $00,    {Medium Type}
  111.                    $00, {Device Specific Parameter}
  112.                    $08, {Block Descriptor Length}
  113.                    $82, {Density Code=CDDA transfer over SCSI support mode}
  114.            $00,$00,$00, {Number of Blocks}
  115.                    $00, {reserved}
  116.            $00,$09,$30);{Block Length = 2352}
  117. VAR
  118.  ReadCDDA    : FUNCTION(LBA:LongInt;TransLEN:Byte;PtrBuf:pointer;AllocLEN:WORD):BYTE;
  119.  Option      : BYTE;
  120.  Os          : String;
  121.  ModeDataBuf : ARRAY[0..11] of Byte;
  122.  SubCData01  : CDROM_CurrentPositionDataFormat;
  123.  SubCData02  : MediaCatalogNumberDataFormat;
  124.  SubCData03  : TrackISRCDataFormat;
  125.  INQBuf      : InquireDataFormat;
  126.  ReadTOCdata : ReadTOCDataFormat;
  127.  AudioDataBuf: ARRAY[0..2351] of Byte;
  128.  startTrack, endTrack       : BYTE;
  129.  currMSF, startMSF, endMSF  : AbsCDRaddrFormat;
  130.  startLBN, endLBN           : LongInt;
  131.  InstHost    : BYTE; {installed Hostadapter}
  132.  NumHost     : BYTE; {number of Hostadapters}
  133.  InstCDROMdev: BOOLEAN; {installed CD-ROM device}
  134.  PDevTyp     : BYTE; {peripheral device type}
  135.  WaveHDR     : _WAVEhdr;
  136.  WaveFile    : FILE;
  137.  FileName    : PathStr;
  138.  CDRtype     : BYTE;
  139.  WaveFileName: NameStr;
  140.  WaveFilePath: DirStr;
  141.  WaveFileExt : ExtStr;
  142.  CurrentPath : DirStr;
  143.  Ix          : BYTE;
  144.  VC1,VC2     : Integer;
  145.  CurrLine    : BYTE;
  146.  ISRCcode    : LongInt;
  147.  Umleitung   : BOOLEAN;
  148.  CON         : TEXT;
  149.  
  150. PROCEDURE TestUmleitung (VAR umleitung:BOOLEAN);
  151. BEGIN
  152.  Umleitung:= mem[prefixseg:$19]<> 1;
  153.  IF Umleitung THEN BEGIN
  154.   assignCRT(CON);
  155.   rewrite(CON);
  156.   assign(Output,'');
  157.   rewrite(Output);
  158.  END;
  159. END;
  160. {------------------------------------------------------}
  161. PROCEDURE ErrorDetect(ErrorText:STRING);
  162. BEGIN
  163.  WRITELN('+++ error ExecuteSCSI_IORequest [',_ASPI_02(SRB_ParBlock.pbASPIsrb^)._.Status,']');
  164.  if Length(ErrorText)>0 THEN WRITELN('SCSI Function=',ErrorText);
  165.  HALT;
  166. END;
  167. {------------------------------------------------------}
  168. FUNCTION MSFtoLBN(MSF:AbsCDRaddrFormat):LongInt;
  169. BEGIN
  170.  MSFtoLBN:=MSF.MSF_MM*LongInt($1194)+MSF.MSF_SS*75+MSF.MSF_DD;
  171. END;
  172. PROCEDURE LBNtoMSF(LBN:LongInt;var MSF:AbsCDRaddrFormat);
  173. BEGIN
  174.  MSF.MSF_MM:=(LBN DIV $1194);
  175.  MSF.MSF_SS:=(LBN-((LBN DIV $1194)*longint($1194))) DIV 75;
  176.  MSF.MSF_DD:=(LBN MOD 75);
  177. END;
  178. {------------------------------------------------------}
  179. FUNCTION LBNtoMSFstr(LBN:LongInt):STRING;
  180. VAR
  181.  MSF   : AbsCDRaddrFormat;
  182.  
  183. FUNCTION INTtoSTR(DezVAL:BYTE;OSize:BYTE):STRING;
  184. VAR
  185.  DezStr: STRING[8];
  186. BEGIN
  187.  STR(DezVAL:OSize,DezStr);
  188.  WHILE Pos(' ',DezStr) > 0 do DezStr[Pos(' ',DezStr)] := '0';
  189.  INTtoSTR:=DezStr;
  190. END;
  191.  
  192. BEGIN
  193.  LBNtoMSF(LBN,MSF);
  194.  LBNtoMSFstr:=INTtoSTR(MSF.MSF_MM,2)+':'+INTtoStr(MSF.MSF_SS,2)+'.'+INTtoStr(MSF.MSF_DD,2);
  195. END;
  196. {------------------------------------------------------------------------------}
  197. FUNCTION MSFSTRtoMSF(MSFstr:STRING;var MSF:AbsCDRaddrFormat):BOOLEAN;
  198. VAR
  199.  VCmm,VCss,VCdd: Integer;
  200. BEGIN
  201.  VAL(COPY(MSFstr,1,POS(':',MSFstr)-1),MSF.MSF_MM,VCmm);
  202.  VAL(COPY(MSFstr,POS(':',MSFstr)+1,POS('.',MSFstr)-POS(':',MSFstr)-1),MSF.MSF_SS,VCss);
  203.  VAL(COPY(MSFstr,POS('.',MSFstr)+1,LENGTH(MSFstr)-POS('.',MSFstr)),MSF.MSF_DD,VCdd);
  204.  IF (VCmm OR VCss OR VCss) <> 0 THEN MSFSTRtoMSF:=FALSE
  205.   ELSE MSFSTRtoMSF:=TRUE;
  206. END;
  207. {------------------------------------------------------------------------------}
  208. FUNCTION MSFSTRtoLBN(MSFstr:STRING;var LBN:LongInt):BOOLEAN;
  209. VAR
  210.  MSF: AbsCDRaddrFormat;
  211. BEGIN
  212.  IF MSFSTRtoMSF(MSFstr,MSF) THEN BEGIN
  213.   LBN:=MSFtoLBN(MSF);
  214.   MSFSTRtoLBN:=TRUE;
  215.  END ELSE MSFSTRtoLBN:=FALSE;
  216. END;
  217. {;*******************************************************************************
  218.  ;*                               I n q u i r e                                 *
  219.  ;*      Inquire                 PtrBuf,AllocLEN                                *
  220.  ;*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*
  221.  ;* parameter:                                                                  *
  222.  ;* PtrBuf  : pointer of buffer data                                            *
  223.  ;* AllocLEN: specifies the number of bytes that the initiator has allocated    *
  224.  ;*           for data                                                          *
  225.  ;* result:                                                                     *
  226.  ;* AL:     status of SRB                                                       *
  227.  ;*         FF: Error_no_unused_SRB                                             *
  228.  ;*******************************************************************************}
  229. FUNCTION Inquire(INQBuf:pointer;AllocLEN:BYTE):BYTE;
  230. CONST
  231.  OpC:Array[0..5] of BYTE =($12,0,0,0,0,0);
  232. BEGIN
  233.  IF AllocSRBExecute(@OpC,6) THEN BEGIN
  234.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^)._.SCSIReqFlags:=$00;
  235.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).DataBufPtrOfs:=Ofs(InqBuf^);
  236.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).DataBufPtrSeg:=Seg(InqBuf^);
  237.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).DataAllocLen:=AllocLEN;
  238.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).SCSI_CDB[4]:=AllocLEN;
  239.   Inquire:=ExecuteSCSI_IORequest;
  240.  END;
  241. END;
  242. {;*******************************************************************************
  243.  ;*                         P l a y A u d i o M S F                             *
  244.  ;*      PlayAudioMSF            MSFstart,MSFend                                *
  245.  ;*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*
  246.  ;* parameter:                                                                  *
  247.  ;* MSFstart: specifies the absolute MSF address at which the audio playback    *
  248.  ;*           operation shall begin                                             *
  249.  ;* MSFend  : specifies the absolute MSF address at which the audio playback    *
  250.  ;*           operation shall end.                                              *
  251.  ;* result:                                                                     *
  252.  ;* AL:     status of SRB                                                       *
  253.  ;*         FF: Error_no_unused_SRB                                             *
  254.  ;*******************************************************************************}
  255. FUNCTION PlayAudioMSF(MSFstart,MSFend:AbsCDRaddrFormat):BYTE;
  256. CONST
  257.  OpC:Array[0..9] of BYTE =($47,0,0,0,0,0,0,0,0,0);
  258. BEGIN
  259.  IF AllocSRBExecute(@OpC,10) THEN BEGIN
  260.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^)._.SCSIReqFlags:=$18;
  261.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).SCSI_CDB[3]:=MSFstart.MSF_MM;
  262.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).SCSI_CDB[4]:=MSFstart.MSF_SS;
  263.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).SCSI_CDB[5]:=MSFstart.MSF_DD;
  264.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).SCSI_CDB[6]:=MSFend.MSF_MM;
  265.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).SCSI_CDB[7]:=MSFend.MSF_SS;
  266.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).SCSI_CDB[8]:=MSFend.MSF_DD;
  267.   PlayAudioMSF:=ExecuteSCSI_IORequest;
  268.  END;
  269. END;
  270. {;*******************************************************************************
  271.  ;*                           M o d e S e l e c t                               *
  272.  ;*      ModeSelect              PtrBuf,AllocLEN                                *
  273.  ;*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*
  274.  ;* parameter:                                                                  *
  275.  ;* PtrBuf  : pointer of buffer data                                            *
  276.  ;* AllocLEN: specifies the number of bytes that the initiator has allocated    *
  277.  ;*           for data                                                          *
  278.  ;* result:                                                                     *
  279.  ;* AL:     status of SRB                                                       *
  280.  ;*         FF: Error_no_unused_SRB                                             *
  281.  ;*******************************************************************************}
  282. FUNCTION ModeSelect(ModeDataBuf:pointer;AllocLEN:BYTE):BYTE;
  283. CONST
  284.  OpC:Array[0..5] of BYTE =($15,0,0,0,0,0);
  285. BEGIN
  286.  IF AllocSRBExecute(@OpC,6) THEN BEGIN
  287.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^)._.SCSIReqFlags:=$10;
  288.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).DataBufPtrOfs:=Ofs(ModeDataBuf^);
  289.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).DataBufPtrSeg:=Seg(ModeDataBuf^);
  290.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).DataAllocLen:=AllocLEN;
  291.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).SCSI_CDB[4]:=AllocLEN;
  292.   ModeSelect:=ExecuteSCSI_IORequest;
  293.  END;
  294. END;
  295. {;*******************************************************************************
  296.  ;*                           M o d e S e n s e                                 *
  297.  ;*      ModeSense               PtrBuf,AllocLEN                                *
  298.  ;*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*
  299.  ;* parameter:                                                                  *
  300.  ;* PtrBuf  : pointer of buffer data                                            *
  301.  ;* AllocLEN: specifies number of bytes that initiator has allocated for data   *
  302.  ;* result:                                                                     *
  303.  ;* AL:     status of SRB                                                       *
  304.  ;*         FF: Error_no_unused_SRB                                             *
  305.  ;*******************************************************************************}
  306. FUNCTION ModeSense(ModeDataBuf:pointer;AllocLEN:BYTE):BYTE;
  307. CONST
  308.  OpC:Array[0..5] of BYTE =($1A,0,0,0,0,0);
  309. BEGIN
  310.  IF AllocSRBExecute(@OpC,6) THEN BEGIN
  311.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^)._.SCSIReqFlags:=$08;
  312.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).DataBufPtrOfs:=Ofs(ModeDataBuf^);
  313.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).DataBufPtrSeg:=Seg(ModeDataBuf^);
  314.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).DataAllocLen:=AllocLEN;
  315.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).SCSI_CDB[4]:=AllocLEN;
  316.   ModeSense:=ExecuteSCSI_IORequest;
  317.  END;
  318. END;
  319. {;*******************************************************************************
  320.  ;*                              R e a d  ( 6 )                                 *
  321.  ;*      Read6                   LBA,TransLEN,PtrBuf,AllocLEN                   *
  322.  ;*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*
  323.  ;* parameter:                                                                  *
  324.  ;* LBA     : the logical block address at which the read operation shall begin *
  325.  ;* TransLEN: specifies the number of logical blocks to be transfered           *
  326.  ;* PtrBuf  : pointer of buffer data                                            *
  327.  ;* AllocLEN: specifies number of bytes that initiator has allocated for data   *
  328.  ;* result:                                                                     *
  329.  ;* AL:     status of SRB                                                       *
  330.  ;*         FF: Error_no_unused_SRB                                             *
  331.  ;*******************************************************************************}
  332. FUNCTION Read6(LBA:LongInt;TransLEN:Byte;PtrBuf:pointer;AllocLEN:WORD):BYTE;far;
  333. CONST
  334.  OpC:Array[0..5] of BYTE =($08,0,0,0,0,0);
  335. BEGIN
  336.  IF AllocSRBExecute(@OpC,6) THEN BEGIN
  337.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^)._.SCSIReqFlags:=$08;
  338.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).DataBufPtrOfs:=Ofs(PtrBuf^);
  339.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).DataBufPtrSeg:=Seg(PtrBuf^);
  340.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).DataAllocLen:=AllocLEN;
  341.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).SCSI_CDB[1]:=LO(LBA SHR 16);
  342.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).SCSI_CDB[2]:=HI(LBA AND $FFFF);
  343.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).SCSI_CDB[3]:=LO(LBA AND $FFFF);
  344.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).SCSI_CDB[4]:=TransLEN;
  345.   Read6:=ExecuteSCSI_IORequest;
  346.  END;
  347. END;
  348. {;*******************************************************************************
  349.  ;*                              R e a d C D D A (12)                           *
  350.  ;*      ReadCDDA12              LBA,TransLEN,PtrBuf,AllocLEN                   *
  351.  ;*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*
  352.  ;* parameter:                                                                  *
  353.  ;* LBA     : the logical block address at which the read operation shall begin *
  354.  ;* TransLEN: specifies the number of logical blocks to be transfered           *
  355.  ;* PtrBuf  : pointer of buffer data                                            *
  356.  ;* AllocLEN: specifies number of bytes that initiator has allocated for data   *
  357.  ;* result:                                                                     *
  358.  ;* AL:     status of SRB                                                       *
  359.  ;*         FF: Error_no_unused_SRB                                             *
  360.  ;*******************************************************************************}
  361. FUNCTION ReadCDDA12(LBA:LongInt;TransLEN:Byte;PtrBuf:pointer;AllocLEN:WORD):BYTE;far;
  362. CONST
  363.  OpC:Array[0..11] of BYTE =($D8,0,0,0,0,0,0,0,0,0,0,0);
  364. BEGIN
  365.  IF AllocSRBExecute(@OpC,12) THEN BEGIN
  366.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^)._.SCSIReqFlags:=$08;
  367.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).DataBufPtrOfs:=Ofs(PtrBuf^);
  368.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).DataBufPtrSeg:=Seg(PtrBuf^);
  369.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).DataAllocLen:=AllocLEN;
  370.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).SCSI_CDB[3]:=LO(LBA SHR 16);
  371.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).SCSI_CDB[4]:=HI(LBA AND $FFFF);
  372.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).SCSI_CDB[5]:=LO(LBA AND $FFFF);
  373.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).SCSI_CDB[9]:=TransLEN;
  374.   ReadCDDA12:=ExecuteSCSI_IORequest;
  375.  END;
  376. END;
  377. {;*******************************************************************************
  378.  ;*                              R e a d C D D A (10)                           *
  379.  ;*      ReadCDDA10              LBA,TransLEN,PtrBuf,AllocLEN                   *
  380.  ;*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*
  381.  ;* parameter:                                                                  *
  382.  ;* LBA     : the logical block address at which the read operation shall begin *
  383.  ;* TransLEN: specifies the number of logical blocks to be transfered           *
  384.  ;* PtrBuf  : pointer of buffer data                                            *
  385.  ;* AllocLEN: specifies number of bytes that initiator has allocated for data   *
  386.  ;* result:                                                                     *
  387.  ;* AL:     status of SRB                                                       *
  388.  ;*         FF: Error_no_unused_SRB                                             *
  389.  ;*******************************************************************************}
  390. FUNCTION ReadCDDA10(LBA:LongInt;TransLEN:Byte;PtrBuf:pointer;AllocLEN:WORD):BYTE;far;
  391. CONST
  392.  OpC:Array[0..9] of BYTE =($D4,0,0,0,0,0,0,0,0,0);
  393. BEGIN
  394.  IF AllocSRBExecute(@OpC,10) THEN BEGIN
  395.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^)._.SCSIReqFlags:=$08;
  396.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).DataBufPtrOfs:=Ofs(PtrBuf^);
  397.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).DataBufPtrSeg:=Seg(PtrBuf^);
  398.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).DataAllocLen:=AllocLEN;
  399.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).SCSI_CDB[2]:=LO(LBA SHR 16);
  400.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).SCSI_CDB[3]:=HI(LBA AND $FFFF);
  401.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).SCSI_CDB[4]:=LO(LBA AND $FFFF);
  402.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).SCSI_CDB[8]:=TransLEN;
  403.   ReadCDDA10:=ExecuteSCSI_IORequest;
  404.  END;
  405. END;
  406. {;*******************************************************************************
  407.  ;*                              R e a d  T O C                                 *
  408.  ;*      ReadTOC                 Track,PtrBuf,AllocLEN                          *
  409.  ;*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*
  410.  ;* parameter:                                                                  *
  411.  ;* STrack  : specifies the starting track that the logical block address       *
  412.  ;*           format should be used for the CD-ROM address field                *
  413.  ;* PtrBuf  : pointer of buffer data                                            *
  414.  ;* AllocLEN: specifies number of bytes that initiator has allocated for data   *
  415.  ;* result:                                                                     *
  416.  ;* AL:     status of SRB                                                       *
  417.  ;*         FF: Error_no_unused_SRB                                             *
  418.  ;*******************************************************************************}
  419. FUNCTION ReadTOC(STrack:Byte;TOCdataBuf:pointer;AllocLEN:WORD):BYTE;
  420. CONST
  421.  OpC:Array[0..9] of BYTE =($43,2,0,0,0,0,0,0,0,0);
  422. BEGIN
  423.  IF AllocSRBExecute(@OpC,10) THEN BEGIN
  424.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^)._.SCSIReqFlags:=$08;
  425.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).DataBufPtrOfs:=Ofs(TOCdataBuf^);
  426.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).DataBufPtrSeg:=Seg(TOCdataBuf^);
  427.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).DataAllocLen:=AllocLEN;
  428.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).SCSI_CDB[6]:=STrack;
  429.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).SCSI_CDB[7]:=hi(AllocLEN);
  430.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).SCSI_CDB[8]:=lo(AllocLEN);
  431.   ReadTOC:=ExecuteSCSI_IORequest;
  432.  END;
  433. END;
  434. {;*******************************************************************************
  435.  ;*                              R e a d  S u b C                               *
  436.  ;*      ReadSubC               STrack,SubCDF,PtrBuf,AllocLEN                   *
  437.  ;*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*
  438.  ;* parameter:                                                                  *
  439.  ;* STrack  : specifies the starting track that the logical block address       *
  440.  ;*           format should be used for the CD-ROM address field                *
  441.  ;* SubCDF  : specifies the format of returned sub-channel data                 *
  442.  ;* PtrBuf  : pointer of buffer data                                            *
  443.  ;* AllocLEN: specifies number of bytes that initiator has allocated for data   *
  444.  ;* result:                                                                     *
  445.  ;* AL:     status of SRB                                                       *
  446.  ;*         FF: Error_no_unused_SRB                                             *
  447.  ;*******************************************************************************}
  448. FUNCTION ReadSubC(STrack,SubCDF:Byte;SubCdataBuf:pointer;AllocLEN:WORD):BYTE;
  449. CONST
  450.  OpC:Array[0..9] of BYTE =($42,2,$40,0,0,0,0,0,0,0);
  451. BEGIN
  452.  IF AllocSRBExecute(@OpC,10) THEN BEGIN
  453.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^)._.SCSIReqFlags:=$08;
  454.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).DataBufPtrOfs:=Ofs(SubCdataBuf^);
  455.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).DataBufPtrSeg:=Seg(SubCdataBuf^);
  456.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).DataAllocLen:=AllocLEN;
  457.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).SCSI_CDB[3]:=SubCDF;
  458.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).SCSI_CDB[6]:=STrack;
  459.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).SCSI_CDB[7]:=hi(AllocLEN);
  460.   _ASPI_02 (SRB_ParBlock.pbASPIsrb^).SCSI_CDB[8]:=lo(AllocLEN);
  461.   ReadSubC:=ExecuteSCSI_IORequest;
  462.  END;
  463. END;
  464.  
  465. BEGIN { MAIN }
  466.  ClrScr;
  467.  TestUmleitung(Umleitung);
  468.  WRITELN;
  469.  WRITELN(PName,' version ',PVer:4:2,' U. Rohbeck, 05/07/94');
  470.  { no parameter, display help text }
  471.  IF ParamCount = 0 THEN BEGIN
  472.   WRITELN('syntax: ',PNAME,' [option] WaveFile[.WAV]');
  473.   WRITELN('  -l                   track listing of CD');
  474.   WRITELN('  -d:<type>            device select');
  475.   WRITELN('     <type>: HITACHI');
  476.   WRITELN('             NEC');
  477.   WRITELN('             SONY');
  478.   WRITELN('             TOSHIBA (default)');
  479.   WRITELN('  -mp                  mode: play audio');
  480.   WRITELN('  -mw                  mode: write to file in WAVE format');
  481.   WRITELN('  -fT[=[start][,end]]  format: send whole track to file');
  482.   WRITELN('  -fM[=[start][,end]]  format: send sector using MSF format MM:SS.DD');
  483.   WRITELN('  -w                   watching audio');
  484.   HALT;
  485.  END;
  486.  { search ASPI manager }
  487.  IF NOT (InitSCSIMgr) THEN BEGIN
  488.   WRITELN('+++ no SCSIMgr installed');
  489.   HALT;
  490.  END;
  491.  { get number of hostadapters }
  492.  GetInstHostAdapters(InstHost,NumHost);
  493.  SRB_ParBlock.pbHostAdapNum:=0;
  494.  { find first CD-ROM drive }
  495.  WHILE ((NumHost>0) AND (NOT InstCDROMdev)) DO BEGIN
  496.   IF ((InstHost SHR SRB_ParBlock.pbHostAdapNum) AND $01)=01 THEN BEGIN
  497.    {get device information}
  498.    InstCDROMdev:=FALSE;
  499.    SRB_ParBlock.pbTargetID:=0;
  500.    SRB_ParBlock.pbLUN:=0;
  501.    { scan SCSI ID for CD-ROM (01) }
  502.    WHILE (SRB_ParBlock.pbTargetID<8) AND (NOT InstCDROMdev) DO BEGIN
  503.     IF GetDeviceType=01 THEN BEGIN
  504.      IF _ASPI_01 (SRB_ParBlock.pbASPIsrb^).PDevTyp=$05 THEN BEGIN
  505.       InstCDROMdev:=TRUE;
  506.       IF Inquire(@InqBuf,SizeOf(InqBuf)) = $0FF THEN ErrorDetect('Inquire(@InqBuf,SizeOf(InqBuf))') ELSE BEGIN
  507.        IF SRB_ParBlock.pbASPIstatus = $01 THEN BEGIN
  508.         WRITELN(InqBuf.VendorID,' ',InqBuf.ProductID,' CD-DA Audio Dump');
  509.         CDRtype:=1;
  510.         { check if CD-ROM is supported }
  511.         WHILE (CDRtype<=CDRsupport) AND (COPY(InqBuf.VendorID,1,length(CDRtypeLST[CDRtype]))<>CDRtypeLST[CDRtype])
  512.          DO INC(CDRtype);
  513.         IF CDRtype > CDRsupport THEN BEGIN
  514.          WRITELN('+++ device type <',OS,'> not supported');
  515.          HALT; {disable this line to force other drives}
  516.         END;
  517.        END ELSE ErrorDetect('');
  518.        { read CD-ROM parameter table }
  519.        IF ModeSense(@ModeDataBuf,sizeof(ModeDataBuf)) <> 01 THEN ErrorDetect('ModeSense(@ModeDataBuf,sizeof(ModeDataBuf))');
  520.        BREAK;
  521.       END;
  522.      END;
  523.     END;
  524.     INC(SRB_ParBlock.pbTargetID);
  525.    END; { WHILE }
  526.    DEC(NumHost);
  527.   END;
  528.  END; { WHILE }
  529.  WRITELN;
  530.  IF NOT InstCDROMdev THEN BEGIN
  531.   WRITELN('+++ error: no CD-ROM device installed');
  532.   HALT;
  533.  END;
  534.  { read TOC }
  535.  IF ReadTOC(00,@ReadTOCdata,sizeof(ReadTOCdata))<>01 THEN ErrorDetect('ReadTOC(00,@ReadTOCdata,sizeof(ReadTOCdata))');
  536.  FileName:='';
  537.  CDRtype:=1;    {TOSHIBA, default}
  538.  Option:=0;
  539.  Ix:=1;
  540.  { check command line }
  541.  WHILE Ix<=ParamCount DO BEGIN
  542.   Os:= ParamStr(Ix);
  543.   IF (Os[1]= '-') OR (Os[1]='/') THEN BEGIN
  544.    CASE Os[2] of
  545.     'l','L':BEGIN { -l: Track listing of CD }
  546.              Option:=Option OR $80;
  547.             END;
  548.     'd','D':BEGIN { -d: Drive Type }
  549.              OS:=COPY(OS,POS(':',OS)+1,LENGTH(OS)-POS(':',OS)+1);
  550.              FOR VC1:=1 TO LENGTH(OS) DO OS[VC1]:=UpCase(OS[VC1]);
  551.              WHILE (CDRtype<=CDRsupport) AND (OS<>CDRtypeLST[CDRtype]) DO
  552.               INC(CDRtype);
  553.              IF CDRtype > CDRsupport THEN BEGIN
  554.               WRITELN('+++ device type <',OS,'> not supported');
  555.               HALT;
  556.              END ELSE WRITELN('set device to: ',CDRtypeLST[CDRtype]);
  557.             END;
  558.     'f','F':BEGIN { -fx.. format }
  559.              CASE Os[3] of
  560.               't','T':BEGIN { -fT: send whole Track to file }
  561.                        Option:=(Option AND $FE) OR $1;
  562.                        startTrack:=0;
  563.                        VC1:=0;
  564.                        endTrack  :=0;
  565.                        VC2:=0;
  566.                        IF POS('=',Os)>0 THEN BEGIN
  567.                         IF POS(',',Os)>0 THEN BEGIN
  568.                          VAL(COPY(Os,POS('=',Os)+1,POS(',',Os)-POS('=',Os)-1),
  569.                                   startTrack,VC1);
  570.                          VAL(COPY(Os,POS(',',Os)+1,LENGTH(Os)-POS(',',Os)+1),
  571.                                   endTrack,VC2);
  572.                         END ELSE VAL(COPY(Os,POS('=',Os)+1,LENGTH(Os)-POS('=',Os)+1),
  573.                                           startTrack,VC1);
  574.                         IF (VC1 OR VC2)<>0 THEN BEGIN
  575.                          WRITELN('+++ illegal track number format');
  576.                          HALT;
  577.                         END;
  578.                        END;
  579.                        IF startTrack=0 THEN StartTrack:=ReadTOCdata.firstTrack;
  580.                        IF endTrack=0 THEN endTrack:=ReadTOCdata.lastTrack;
  581.                        startLBN:=MSFtoLBN(ReadTOCdata.TOCtd[startTrack].AbsCDRaddr);
  582.                        INC(endTrack);
  583.                        endLBN:=MSFtoLBN(ReadTOCdata.TOCtd[endTrack].AbsCDRaddr)-1;
  584.                       END;
  585.               'm','M':BEGIN { -fM: send sector using MSF format MM:SS:DD }
  586.                        Option:=(Option AND $FE) OR $1;
  587.                        startLBN:=0;
  588.                        VC1:=0;
  589.                        endLBN:=0;
  590.                        VC2:=0;
  591.                        IF POS('=',Os)>0 THEN BEGIN
  592.                         IF POS(',',Os)>0 THEN BEGIN
  593.                          IF POS(',',Os)-1 = POS('=',Os) THEN MSFSTRtoLBN('00:02.00',startLBN)
  594.                           ELSE BEGIN
  595.                           IF NOT MSFSTRtoLBN(COPY(Os,POS('=',Os)+1,POS(',',Os)-POS('=',Os)-1),startLBN)
  596.                            THEN VC1:=$FF;
  597.                          END;
  598.                          IF NOT MSFSTRtoLBN(COPY(Os,POS(',',Os)+1,LENGTH(Os)-POS(',',Os)+1),endLBN)
  599.                           THEN VC1:=$FF;
  600.                         END ELSE BEGIN
  601.                          IF NOT MSFSTRtoLBN(COPY(Os,POS('=',Os)+1,LENGTH(Os)-POS('=',Os)-1),startLBN)
  602.                           THEN VC1:=$FF;
  603.                         END;
  604.                        END;
  605.                        IF (VC1 OR VC2)<>0 THEN BEGIN
  606.                         WRITELN('+++ illegal MSF format');
  607.                         HALT;
  608.                        END;
  609.                        IF startLBN=0 THEN MSFSTRtoLBN('00:02.00',startLBN);
  610.                        IF endLBN=0 THEN endLBN:=MSFtoLBN(ReadTOCdata.TOCtd[ReadTOCdata.lastTrack].AbsCDRaddr);
  611.                       END; { -fM }
  612.              END; { Case -fx }
  613.             END; { -f }
  614.     'm','M':BEGIN { -mx mode select, play or write }
  615.              CASE Os[3] of
  616.               'p','P': Option:=(Option AND $CF) OR $10; { -mP play audio }
  617.               'w','W': Option:=(Option AND $CF) OR $20; { -mW write WAV  }
  618.              END;
  619.             END;
  620.     'w','W':Option:=(Option AND $BF) OR $40; { -w watching audio }
  621.    END; { CASE }
  622.   END ELSE FileName:=ParamStr(Ix);
  623.   INC(Ix);
  624.  END; (* WHILE *)
  625.  IF ((Option AND $10)<>0) AND ((Option AND $01)=0) THEN BEGIN
  626.   WRITELN('+++ format parameter required');
  627.   HALT;
  628.  END;
  629.  { -l, display CD ROM Track list }
  630.  IF (Option AND $80) <> 0 THEN BEGIN
  631.   WITH ReadTOCdata DO BEGIN
  632.    WRITELN('*** TRACK LISTING OF CD ***');
  633.    WRITELN;
  634.    WRITELN('Start track: ',firstTrack:2);
  635.    WRITELN('Last  track: ',lastTrack:2);
  636.    WRITELN('Total time : ',TOCtd[ReadTOCdata.lastTrack+1].AbsCDRaddr.MSF_MM,' minutes ',
  637.             TOCtd[ReadTOCdata.lastTrack+1].AbsCDRaddr.MSF_SS,' seconds ',
  638.             TOCtd[ReadTOCdata.lastTrack+1].AbsCDRaddr.MSF_DD,' frames (75th/s)');
  639.    IF ReadSubC(startTrack,$02,@SubCData02,sizeof(SubCData02)) <> 01
  640.     THEN ErrorDetect('ReadSubC(startTrack,$02,@SubCData02,sizeof(SubCData02))');
  641.    WRITE('UPC/BarCode: ');
  642.    IF (subCData02.MCVAL AND $80) = 0 THEN WRITELN('*** not available ***')
  643.     ELSE BEGIN
  644.     FOR Ix:=0 TO 4 DO WRITE(SubCData02.MCN[Ix]);
  645.     WRITE(' ');
  646.     FOR Ix:=5 TO 7 DO WRITE(SubCData02.MCN[Ix]);
  647.     WRITE('-');
  648.     FOR Ix:=8 TO 10 DO WRITE(SubCData02.MCN[Ix]);
  649.     WRITE('-');
  650.     FOR Ix:=11 TO 11 DO WRITE(SubCData02.MCN[Ix]);
  651.     WRITE(' ');
  652.     FOR Ix:=12 TO 14 DO WRITE(SubCData02.MCN[Ix]);
  653.    END;
  654.    WRITELN;
  655.    WRITELN;
  656.    WRITELN('====================================================================');
  657.    WRITELN('|     |       | MSF_start |              | Digital Copy | Audio    |');
  658.    WRITELN('| No. | Type  | time      | Pre-Emphasis | Permitted    | Channels |');
  659.    WRITELN('|-----+-------+-----------+--------------+--------------+----------|');
  660.    FOR Ix:=firstTrack TO lastTrack DO BEGIN
  661.     WRITE('| ',Ix:2,'  |');
  662.     IF (TOCtd[Ix].AdrControl AND $04) <> 0 THEN WRITE(' data ')
  663.      ELSE WRITE(' audio');
  664.     WRITE(' | ',LBNtoMSFstr(MSFtoLBN(TOCtd[Ix].AbsCDRaddr)),'  |');
  665.     IF (TOCtd[Ix].AdrControl AND $02) = 0 THEN WRITE('    without   |')
  666.      ELSE WRITE('    with      |');
  667.     IF (TOCtd[Ix].AdrControl AND $01) <> 0 THEN WRITE('      yes     |')
  668.      ELSE WRITE('      no      |');
  669.     IF (TOCtd[Ix].AdrControl AND $08) = 0 THEN WRITELN('     2    |')
  670.      ELSE WRITELN('     4    |');
  671.    END;
  672.    WRITELN('====================================================================');
  673.    WRITELN;
  674.   END;
  675.  END;
  676.  IF (Option AND $30) <> 0 THEN BEGIN
  677.   IF ((Option AND $01)=0) OR (startLBN > endLBN) THEN BEGIN
  678.    WRITELN('+++ error format parameter detected');
  679.    HALT;
  680.   END;
  681.   Ix:=ReadTOCdata.firstTrack;
  682.   WHILE ((Ix<(ReadTOCdata.lastTrack)+1) AND (MSFtoLBN(ReadTOCdata.TOCtd[IX].AbsCDRaddr) < startLBN))
  683.    DO INC(Ix);
  684.   IF (ReadTOCdata.TOCtd[IX].AdrControl AND $04) <> 0 THEN BEGIN
  685.    WRITELN('+++ error: data track detected');
  686.    HALT;
  687.   END;
  688.   WHILE ((Ix<(ReadTOCdata.lastTrack)+1) AND (MSFtoLBN(ReadTOCdata.TOCtd[IX].AbsCDRaddr) < endLBN))
  689.    DO BEGIN
  690.    IF (ReadTOCdata.TOCtd[IX].AdrControl AND $04) <> 0 THEN BEGIN
  691.     WRITELN('+++ error: data track detected');
  692.     HALT;
  693.    END;
  694.    INC(Ix);
  695.   END;
  696.  END;
  697.  {play audio}
  698.  IF (Option AND $10) <> 0 THEN BEGIN
  699.   LBNtoMSF(startLBN,startMSF);
  700.   LBNtoMSF(endLBN,endMSF);
  701.   IF PlayAudioMSF(startMSF,endMSF) <> 01 THEN ErrorDetect('PlayAudioMSF(startMSF,endMSF)');
  702.   { watch audio }
  703.   IF (Option AND $40) <> 0 THEN BEGIN
  704.    LBNtoMSF($00,SubCData01.AbsCDRaddr);
  705.    WRITELN('... watching audio');
  706.    WRITELN;
  707.    WRITELN('Country Code :       --');
  708.    WRITELN('Owner Code   :      ---');
  709.    WRITELN('year of recording: 19xx');
  710.    WRITELN;
  711.    WRITE('position: ');
  712.    CurrLine:=WHEREY;
  713.    WHILE (MSFtoLBN(SubCData01.AbsCDRaddr)) <= endLBN DO BEGIN
  714.     IF (SubCData01.TNO<>SubCData03.TNO)    THEN BEGIN
  715.      IF ReadSubC(SubCData01.TNO,03,@SubCData03,sizeof(SubCData03)) <> 01
  716.       THEN ErrorDetect('ReadSubC(SubCData01.TNO,03,@SubCData03,sizeof(SubCData03))');
  717.      IF (SubCData03.TCVAL AND $80) <>0 THEN BEGIN
  718.       WITH SubCData03 DO BEGIN
  719.        ISRCcode:=0;
  720.        FOR Ix:=0 TO 7 DO ISRCcode:=(ISRCcode SHL 4) OR (TrackISRC[Ix] AND $0F);
  721.        GOTOXY(22,CurrLine-4);
  722.        WRITE(CHR($30+((ISRCcode SHR 26) AND $3F))+
  723.        CHR($30+((ISRCcode SHR 20) AND $3F)));
  724.        GOTOXY(21,CurrLine-3);
  725.        WRITE(CHR($30+((ISRCcode SHR 14) AND $3F))+
  726.             CHR($30+((ISRCcode SHR 8) AND $3F))+
  727.             CHR($30+((ISRCcode SHR 2) AND $3F)));
  728.        GOTOXY(20,CurrLine-2);
  729.        WRITE('19',TrackISRC[8]*10+TrackISRC[9]);
  730.       END;
  731.      END;
  732.     END;
  733.     ReadSubC(00,01,@SubCData01,sizeof(SubCData01));
  734.     GotoXY(12,CurrLine);
  735.     WRITE('Track: #',SubCData01.TNO);
  736.     WRITE('  abs: ',LBNtoMSFstr(MSFtoLBN(SubCData01.AbsCDRaddr)));
  737.     WRITE('  rel: ',LBNtoMSFstr(MSFtoLBN(SubCData01.TrackRaddr)));
  738.    END;
  739.   END;
  740.  END;
  741.  {write to file in WAVE-format}
  742.  IF (Option AND $20) <> 0 THEN BEGIN
  743.   IF FileName='' THEN BEGIN
  744.    WRITELN('+++ no valid filename');
  745.    HALT;
  746.   END;
  747.   GetDir($0,CurrentPath);
  748.   IF CurrentPath[Length(CurrentPath)]<>'\' THEN CurrentPath:=CurrentPath+'\';
  749.   FSPLIT(FileName,WaveFilePath,WaveFileName,WaveFileExt);
  750.   IF WaveFilePath='' THEN WaveFilePath:=CurrentPath;
  751.   IF WaveFilePath[Length(WaveFilePath)]<>'\' THEN WaveFilePath:=WaveFilePath+'\';
  752.   IF WaveFileExt='' THEN WaveFileExt:='.WAV';
  753.   CASE CDRtype of
  754.    $01:BEGIN {TOSHIBA}
  755.         IF ModeSelect(@ModeSelectData,sizeof(ModeSelectData)) <> 01
  756.          THEN ErrorDetect('ModeSelect(@ModeSelectData,sizeof(ModeSelectData))');
  757.         ReadCDDA:=Read6;
  758.        END;
  759.    $02:ReadCDDA:=ReadCDDA12; {HITACHI}
  760.    $03:ReadCDDA:=ReadCDDA10; {NEC}
  761.    $04:ReadCDDA:=ReadCDDA12; {SONY}
  762.   END;
  763.   ASSIGN(WaveFile,WaveFilePath+WaveFileName+WaveFileExt);
  764.   REWRITE(WaveFile,1);
  765.   {initialize WAVEheader}
  766.   WAVEhdr.MainDesc:=$46464952; {'RIFF'}
  767.   WAVEhdr.FileType:=$45564157; {'WAVE'}
  768.   WAVEhdr.SubDesc:=$20746D66;  {'fmt '}
  769.   WAVEhdr.lenSubDesc:=$10;
  770.   WAVEhdr.Format:=$01;    {PCM}
  771.   WAVEhdr.Mode:=$02;        {Stereo}
  772.   WAVEhdr.SampleFreq:=$0AC44;    {44.1 KHz}
  773.   WAVEhdr.BytePerSec:=$2B110;    {16Bit-Stereo-Sound}
  774.   WAVEhdr.BytePerSam:=$04;    {16Bit-Stereo-Sound}
  775.   WAVEhdr.BitPerSam:=$10;    {16-Bit}
  776.   WAVEhdr.DataDesc:=$61746164;    {'data'}
  777.   WAVEhdr.lenData:=longInt((endLBN+1)-startLBN)*$930;
  778.   WAVEhdr.lenFile:=sizeof(WAVEhdr)-8+WAVEhdr.lenData;
  779.   WRITELN('total bytes requested: ',WAVEhdr.lenFile,' Byte');
  780.   IF DiskFree(ORD(WaveFilePath[1])-$40)< WAVEhdr.lenFile THEN BEGIN
  781.    WRITELN('+++ not enough space available on target drive');
  782.    HALT;
  783.   END;
  784.   BLOCKWRITE(WaveFile,WAVEhdr,sizeof(WAVEhdr));
  785.   WRITELN;
  786.   WHILE startLBN <= endLBN DO BEGIN
  787.    IF READCDDA(150+startLBN,1,@AudioDataBuf,sizeof(AudioDataBuf))<>01
  788.     THEN ErrorDetect('READCDDA(150+startLBN,1,@AudioDataBuf,sizeof(AudioDataBuf))');
  789.    BLOCKWRITE(WaveFile,AudioDataBuf,sizeof(AudioDataBuf));
  790.    GotoXY(1,WhereY);
  791.    WRITE('MSF: ',LBNtoMSFstr(startLBN));
  792.    INC(startLBN);
  793.   END;
  794.   CLOSE(WaveFile);
  795.   WRITELN;
  796.  END;
  797.  ModeDataBuf[0]:=0;
  798.  IF ModeSelect(@ModeDataBuf,sizeof(ModeDataBuf)) <> 01
  799.   THEN ErrorDetect('ModeSelect(@ModeDataBuf,sizeof(ModeDataBuf))');
  800. END.
  801.