📄 bincuereader.pas
字号:
{-----------------------------------------------------------------------------
Unit Name: BinCueReader
Author: Dancemammal
Purpose: Read and extract tracks from BIN / CUE files
History: First Release
-----------------------------------------------------------------------------}
unit BinCueReader;
interface
Uses Classes,Windows,sysutils,StrUtils;
Const
MODE_UNKNOWN = 0;
MODE_AUDIO = 1;
MODE_MODE1 = 2;
MODE_MODE2 = 3;
MODE_MODE2_FORM1 = 4;
MODE_MODE2_FORM2 = 5;
MODE_MODE1_2048 = 6;
MODE_MODE2_2048 = 7;
CUE_OK = 0;
CUE_CUEMISSING = 1;
CUE_BINMISSING = 2;
CUE_CUEFILEEXPECTED = 3;
CUE_BINFILEEXPECTED = 4;
CUE_BINARYEXPECTED = 5;
CUE_TRACKEXPECTED = 6;
CUE_TRACKNUMEXPECTED = 7;
CUE_INDEXEXPECTED = 8;
CUE_INDEXNUMEXPECTED = 9;
CUE_INDEXMSFEXPECTED = 10;
CUE_UNKNOWN_ERROR = 11;
PostLeadInGapTime = 150;
type
TWaveHeader = record
{ RIFF file header }
RIFFHeader : array[1..4] of Char; { Must be "RIFF" }
FileSize : Integer; { Must be "RealFileSize - 8" }
WAVEHeader : array[1..4] of Char; { Must be "WAVE" }
{ Format information }
FormatHeader : array[1..4] of Char; { Must be "fmt " }
FormatSize : DWord; { Must be 16 (decimal) }
FormatCode : Word; { Must be 1 }
ChannelNumber: Word; { Number of channels }
SampleRate : DWord; { Sample rate (hz) }
BytesPerSecond: DWord; { Bytes per second }
BytesPerSample: Word; { Bytes per Sample }
BitsPerSample : Word; { Bits per sample }
ExtraFormatBytes: Word;
{ Data area }
DataHeader : array[1..4] of Char; { Must be "data" }
DataSize : DWord; { Data size }
end;
Type
TATIPCue = Packed Record
CTL_ADR : Byte; // control field
TNO : Byte; // track number
Index : Byte; // Index number
DataForm : Byte; // data form ??
SCMS : Byte; // Serial Copy Managment system
Min : Byte;
Sec : Byte;
Frame : Byte;
end;
Type
TATIPCueList = Packed Record
Cues : Array[0..98] of TATIPCue;
Count : Integer;
BurnMode : Integer;
end;
Type
TIndex = Packed Record
LBA : Integer;
ATIP : Integer;
IndexNum : Integer;
end;
Type
TTrack = Packed Record
Mode : Integer;
ModeDesc : String[30];
FileType : String[20];
FileName : String[255];
FileSize : LongInt;
PreGap : Integer;
PreATIP : Integer;
Index : Array[0..98] of TIndex;
FirstIndex : Integer;
IndexCount : Integer;
TrackNumber : Integer;
end;
Type
TTrackList = Packed Record
Tracks : Array[0..98] of TTrack;
Count : Integer;
end;
TExtractProgress = procedure(PercentDone: Integer; Cancel : Boolean) of object;
Type
TBinCueReader = Class
Private
CurrentTrack : Integer;
CurrentFileType : String;
CurrentIndexCount : Integer;
CueBuilderIndex : Integer;
FCueFileName : String;
FBinFileName : String;
FExtractProcess : TExtractProgress;
FBinTracks : TTrackList;
FCUEList : Tstringlist;
FTitle : String;
FPerformer : String;
FSongWriter : String;
FCatalog : String;
FATIPCounter : Integer;
FATIPCueList : TATIPCueList;
FCuePath : String;
Function GetATIPCueList : TATIPCueList;
Function TrackModeToString(TrackMode : Integer): String;
Function StrToMode(TrackVal : String): Integer;
Function Parse(CueLine : String) : Integer;
Procedure AddPostLeadInGap;
Procedure SetupLeadIn;
Procedure SetupLeadOut;
Procedure CheckPreGap(Track : TTrack);
Procedure AddTrackToCUE(Track : TTrack);
Function BinLength(FileName : String):Integer;
Function WavLength(FileName : String):Integer;
Public
Function ExtractTrack(TrackNo : Integer; ToFileName : String ) : Boolean;
Function TrackMode(TrackNo : Integer): Integer;
Function OpenCueFile(FileName : String) : Integer;
Procedure SaveATIPCueToFile(FileName : String);
Constructor Create;
Destructor Destroy; override;
Published
property OnExtractProcess: TExtractProgress read FExtractProcess write FExtractProcess;
property CueFileName: String read FCueFileName write FCueFileName;
property BinFileName: String read FBinFileName write FBinFileName;
Property BinTrackList : TTrackList Read FBinTracks;
Property ATIPCueList : TATIPCueList Read GetATIPCueList;
property Title : String read FTitle write FTitle;
property Performer : String read FPerformer write FPerformer;
property SongWriter : String read FSongWriter write FSongWriter;
property Catalog : String read FCatalog write FCatalog;
end;
implementation
uses covertfuncs,ReadWave;
function HMSFtoLBA(const AMinute, ASecond, AFrame: Byte): LongWord;
begin
Result := (AMinute * 60 * 75) + (ASecond * 75) + AFrame;
end;
Function StrToLBA(HSF : String) : LongWord;
var
AMinute, ASecond, AFrame :Byte;
TempStr,Coded : String;
begin
Coded := HSF;
TempStr := copy(Coded,0,pos(':',Coded)-1);
AMinute := strtoint(TempStr);
delete(Coded,1,pos(':',Coded));
TempStr := copy(Coded,0,pos(':',Coded)-1);
ASecond := strtoint(TempStr);
delete(Coded,1,pos(':',Coded));
TempStr := copy(Coded,0,99);
AFrame := strtoint(TempStr);
Result := HMSFtoLBA(AMinute,ASecond,AFrame);
end;
Constructor TBinCueReader.Create;
begin
FCUEList := Tstringlist.create;
FATIPCounter := 0;
end;
Destructor TBinCueReader.Destroy;
begin
FCUEList.Clear;
FCUEList.Free;
end;
Function TBinCueReader.StrToMode(TrackVal : String): Integer;
begin
Result := MODE_UNKNOWN;
If TrackVal = 'AUDIO' then Result := MODE_AUDIO;
If TrackVal = 'MODE1/2352' then Result := MODE_MODE1;
If TrackVal = 'MODE2/2352' then Result := MODE_MODE2;
If TrackVal = 'MODE2FORM1/2352' then Result := MODE_MODE2_FORM1;
If TrackVal = 'MODE2FORM2/2352' then Result := MODE_MODE2_FORM2;
If TrackVal = 'MODE1/2048' then Result := MODE_MODE1_2048;
If TrackVal = 'MODE2/2048' then Result := MODE_MODE2_2048;
End;
Function TBinCueReader.TrackModeToString(TrackMode : Integer): String;
begin
Result := 'MODE UNKNOWN';
Case TrackMode of
1 : Result := 'AUDIO';
2 : Result := 'MODE1 / 2352';
3 : Result := 'MODE2 / 2352';
4 : Result := 'MODE2 FORM1 / 2352';
5 : Result := 'MODE2 FORM2 / 2352';
6 : Result := 'MODE1 / 2048';
7 : Result := 'MODE2 / 2048';
end;
end;
Function TBinCueReader.TrackMode(TrackNo : Integer):Integer;
begin
Result := FBinTracks.Tracks[TrackNo -1].Mode;
end;
Function TBinCueReader.WavLength(FileName : String):Integer;
var
Header: PWaveInformation;
Count : LongInt;
Secs, Mins, Frames : Integer;
begin
Result := 0;
Header := GetWaveInformationFromFile(FileName);
Count := round(Header^.Length);
Dispose(Header);
Result := Count;
end;
Function TBinCueReader.BinLength(FileName : String):Integer;
begin
Result := 0;
with TFileStream.Create(FileName, fmOpenRead) do
try
Result := Size;
finally
Free;
end;
end;
{
FILE "VIDEOC~1.BIN" BINARY
TRACK 01 MODE2/2352
INDEX 01 00:00:00
TRACK 02 MODE2/2352
INDEX 00 00:04:00
INDEX 01 00:06:00
TRACK 03 MODE2/2352
INDEX 00 00:37:52
INDEX 01 00:39:52
TITLE "Enter title (disc or track)"
PERFORMER "Enter Performer (disc or track)"
SONGWRITER "Enter Songwriter (disc or track)"
CATALOG 1234567890123
FILE "C:\TRACK1.WAV" WAVE
TRACK 01 AUDIO
PREGAP 00:02:00
INDEX 01 00:00:00
FILE "C:\TRACK2.WAV" WAVE
TRACK 02 AUDIO
PREGAP 00:02:00
INDEX 01 00:00:00
}
Function TBinCueReader.Parse(CueLine : String) : Integer;
var
Filename,Filetype : String;
TrackNo, TrackType, IndexNo, TrackSecs : String;
TempCopy,Line : String;
IndexInt, TrackLength : Integer;
begin
Line := Trim(CueLine);
TempCopy := Copy(Line,0,Pos(' ',Line)-1); // get KeyWord (FILE, TRACK, INDEX etc)
Delete(Line,1,Pos(' ',Line));
if (TempCopy = 'FILE') then //FILE "VIDEOC~1.BIN" BINARY
begin
Delete(Line,1,Pos('"',Line));
Filename := Copy(Line,0,pos('"',Line)-1); // filename
FileName := AnsiReplaceStr(FileName,'"','');
Delete(Line,1,Pos('"',Line));
Filetype := Copy(Line,0,100);
FBinFileName := trim(FileName);
CurrentFileType := trim(Filetype);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -