unit MP3Utils; interface uses Classes,Windows,Sysutils; type TMP3RawHeader = record b1,b2,b3,b4 : byte; end; type TMP3FrameHeader = record IsValidMP3 : boolean; framesync : boolean; // 31-21 Good or bad - bits compute 11 bits all set version : byte; //20-19 Version returns 0 = bad (01), 1 = MPEG v1 (11), 2 = MPEG v2 (10), 3=MPEG version 2.5 layer : byte; //18-17 Layver returns 0 = bad (00), 3 = Layer III (01), 2 = Layer II (10), 1 = Layer I (11) crcoff : boolean; //16 Protection bit returns 1 = Not protected (bitset), (0) Protected but CRC (16 bit crc follows header) (1) BitRate : integer; //15-12 Assume Layer 3 and return bitrate // 0 is free -1 is bad SampleRate : integer;// 11,10 Padding : boolean;//9 0 not set - 1 Frame padded with extrabit; Prvate : boolean; // 8 ChannelMode : byte; // 7,6 0= Stereo, 01 = Joint Stereo, 10 - Dual Channel Stereo, 11 - Single Channel (Mono) IntensityStereo : boolean; //Used for joint Stereo MSStereo : boolean; // Used for joint Stereo Copyright : boolean; // 3 = 0 Not Copyright 1, 1 = Copyright Original : boolean; // 3 = 0 Copy 1, 1 = Original Emphasis : byte; // 00 none 01 50/15ms 10 reserved - 11 CCIT J.17 end; type TMP3FileInfo = class(TObject) private fheader : TMP3FrameHeader; fs : TFileStream; raw : TMP3RawHeader; fFrameLength : dword; fDuration : real; fstartframe : dword; fFileSize : dword; fChannels : byte; p : dword; function findfirstframe(sp : dword) : dword; procedure GetFileStats; function readheader(sp : dword) : boolean; public constructor Create(fn : string); destructor Destroy;override; property header : TMP3FrameHeader read fheader write fheader; property FrameLength : dword read fFrameLength; property Duration : real read fDuration; function CalculatePositionFromFileSize(fp : dword) : real; function CalculateFilePositionFromTime(cp : dword) : dword; property StartFrameIsAt : dword read fstartframe; property Channels : byte read fChannels; end; implementation Constructor TMP3FileInfo.Create(fn : string); var n : byte; begin try fs:=TFileStream.Create(fn,fmOpenRead); except destroy; exit; end; // Try and read first frame. If it bails for any reason try up to 10 other frames and continue when a valid frame is found if readheader(0)=false then for n := 0 to 10 do if p+4<fs.size then begin if readheader(p+2)=true then break; end; if fheader.IsValidMP3=true then getfilestats; fs.free; end; Destructor TMP3FileInfo.Destroy; begin fs.Free; end; function TMP3FileInfo.findfirstframe(sp : dword) : dword; var found : boolean; b1,b2 : byte; begin found:=false; fs.position:=sp; while (found=false) and (fs.Position<fs.Size) do begin fs.Read(b1,1); if b1=$ff then begin fs.Read(b2,1); if (b2 and $e0) = $e0 then begin result:=fs.Position-2; exit; end; end; end; result:=fs.size; end; function TMP3FileInfo.readheader(sp : dword) : boolean; var v,o : byte; begin p:=findfirstframe(sp); if p+4>fs.size then begin fheader.IsValidMP3:=false; exit; end; fstartframe:=p; fs.position:=p; fs.read(raw,4); result:=true; fheader.IsValidMP3:=true; //Framesync if (raw.b1=$ff) and ((raw.b2 and $e0) = $e0) then fheader.framesync:=true else begin fheader.framesync:=false; fheader.IsValidMP3:=false; result:=false; exit; end; //Version asm mov o,00011000b; end; v:=raw.b2 AND o; v:=v shr 3; case v of 0 : fheader.version:=3; 1 : fheader.version:=0; 2 : fheader.version:=2; 3 : fheader.version:=1; end; //Layer asm mov o,00000110b; end; v:=raw.b2 AND o; v:=v shr 1; case v of 0 : fheader.layer:=0; 1 : fheader.layer:=3; 2 : fheader.layer:=2; 3 : fheader.layer:=1; end; if fheader.layer<>3 then begin //Only interested in layer 3, if incorrect bail out result:=false; exit; end; //CRC asm mov o,00000001b; end; v:=raw.b2 AND o; case v of 0 : fheader.crcoff:=false; 1 : fheader.crcoff:=true; end; //BitRate asm mov o,11110000b; end; //v:=raw.b3 AND o; v:=raw.b3 shr 4; fheader.BitRate:=-1; case v of 0: fheader.BitRate:=0; 1: fheader.BitRate := 32; 2: fheader.BitRate := 40; 3: fheader.BitRate := 48; 4: fheader.BitRate := 56; 5: fheader.BitRate := 64; 6: fheader.BitRate := 80; 7: fheader.BitRate := 96; 8: fheader.BitRate := 112; 9: fheader.BitRate := 128; 10: fheader.BitRate := 160; 11: fheader.BitRate := 192; 12: fheader.BitRate := 224; 13: fheader.BitRate := 256; 14: fheader.BitRate := 320; 15: fheader.BitRate := -1; end; if fheader.BitRate=-1 then begin fheader.IsValidMP3:=false; result:=false; exit; end; if fheader.bitrate=0 then fheader.bitrate:=320; // VBR //Sample Frequency asm mov o,00001100b; end; v:=raw.b3 AND o; v:=v shr 2; fheader.SampleRate:=-1; case v of 0: fheader.SampleRate:=44100; 1: fheader.SampleRate:=48000; 2: fheader.SampleRate:=32000; end; if fheader.SampleRate=-1 then begin fheader.IsValidMP3:=false; result:=false; exit; end; //Private bit asm mov o,00000010b; end; v:=raw.b3 AND o; v:=v shr 1; case v of 0: fheader.Prvate:=false; 1: fheader.Prvate:=true; end; //ChannelMode asm mov o,11000000b; end; v:=raw.b3 shr 6; fheader.ChannelMode:=v; case v of 0 : fChannels:=2; 1 : fChannels:=2; 2 : fChannels:=2; 3 : fChannels:=1; end; //Mode Extension for joint Stereo asm mov o,00110000b; end; v:=raw.b4 AND o; v:=v shr 4; case v of 0 : begin fheader.IntensityStereo:=false; fheader.MSStereo:=false; end; 1 : begin fheader.IntensityStereo:=true; fheader.MSStereo:=false; end; 2 : begin fheader.IntensityStereo:=false; fheader.MSStereo:=true; end; 3 : begin fheader.IntensityStereo:=true; fheader.MSStereo:=true; end; end; //Copyright asm mov o,00001000b; end; v:=raw.b4 AND o; v:=v shr 3; if v<>0 then fheader.Copyright:=true else fheader.Copyright:=false; //Original asm mov o,00000100b; end; v:=raw.b4 AND o; v:=v shr 2; if v<>0 then fheader.Original:=true else fheader.Original:=false; //Emphasis asm mov o,00000011b; end; v:=raw.b4 AND o; fheader.Emphasis:=v; end; procedure TMP3FileInfo.GetFileStats; const SamplesPerFrame=1152; var padding : byte; begin padding:=0; if fheader.Padding then padding:=1; FFrameLength:=round((SamplesPerFrame / 8 * (fheader.Bitrate*1000))/fheader.SampleRate)+padding; FDuration:=((fs.Size - fstartframe)/1024) / fheader.BitRate * 8; FFileSize:=fs.Size; end; function TMP3FileInfo.CalculatePositionFromFileSize(fp : dword) : real; begin result:=((fp - fstartframe)/1024) / fheader.BitRate * 8; end; function TMP3FileInfo.CalculateFilePositionFromTime(cp : dword) : dword; begin result:=round((cp)*((fheader.BitRate/8)*1024)); //result:=((fp - fstartframe)/1024) / fheader.BitRate * 8; end; end.