ADD: AC3, DTS, OptimFROG and WAVPack support

This commit is contained in:
Alexander Koblov 2016-04-23 16:20:35 +00:00
commit 42462fe816
6 changed files with 1192 additions and 2 deletions

View file

@ -9,7 +9,8 @@ uses
const
DETECT_STRING: String = '(EXT="MP3") | (EXT="MP2") | (EXT="MP1") | (EXT="OGG") | (EXT="WMA") | ' +
'(EXT="WAV") | (EXT="VQF") | (EXT="AAC") | (EXT="APE") | (EXT="MPC") | ' +
'(EXT="FLAC") | (EXT="CDA") | (EXT="TTA")';
'(EXT="FLAC") | (EXT="CDA") | (EXT="TTA") | (EXT="AC3") | (EXT="DTS") | ' +
'(EXT="WV") | (EXT="WVC") | (EXT="OFR") | (EXT="OFS")';
const
FIELD_COUNT = 20;

View file

@ -0,0 +1,190 @@
{ *************************************************************************** }
{ }
{ Audio Tools Library }
{ Class TAC3 - for manipulating with AC3 Files }
{ }
{ http://mac.sourceforge.net/atl/ }
{ e-mail: macteam@users.sourceforge.net }
{ }
{ Copyright (c) 2005 by Gambit }
{ }
{ Version 1.1 (April 2005) by Gambit }
{ - updated to unicode file access }
{ }
{ Version 1.0 (05 January 2005) }
{ }
{ This library is free software; you can redistribute it and/or }
{ modify it under the terms of the GNU Lesser General Public }
{ License as published by the Free Software Foundation; either }
{ version 2.1 of the License, or (at your option) any later version. }
{ }
{ This library is distributed in the hope that it will be useful, }
{ but WITHOUT ANY WARRANTY; without even the implied warranty of }
{ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU }
{ Lesser General Public License for more details. }
{ }
{ You should have received a copy of the GNU Lesser General Public }
{ License along with this library; if not, write to the Free Software }
{ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA }
{ }
{ *************************************************************************** }
unit AC3;
interface
uses
Classes, SysUtils, DCClassesUtf8;
const
BIRATES: array[0..18] of Integer = (32, 40, 48, 56, 64, 80, 96, 112, 128, 160,
192, 224, 256, 320, 384, 448, 512, 576, 640);
type
{ Class TAC3 }
TAC3 = class(TObject)
private
{ Private declarations }
FFileSize: Int64;
FValid: Boolean;
FChannels: Cardinal;
FBits: Cardinal;
FSampleRate: Cardinal;
FBitrate: Word;
FDuration: Double;
function FGetRatio: Double;
procedure FResetData;
public
{ Public declarations }
constructor Create; { Create object }
destructor Destroy; override; { Destroy object }
function ReadFromFile(const FileName: String): Boolean; { Load header }
property FileSize: Int64 read FFileSize;
property Valid: Boolean read FValid;
property Channels: Cardinal read FChannels;
property Bits: Cardinal read FBits;
property SampleRate: Cardinal read FSampleRate;
property Bitrate: Word read FBitrate;
property Duration: Double read FDuration;
property Ratio: Double read FGetRatio; { Compression ratio (%) }
end;
implementation
{ ********************** Private functions & procedures ********************* }
procedure TAC3.FResetData;
begin
{ Reset all data }
FFileSize := 0;
FValid := False;
FChannels := 0;
FBits := 0;
FSampleRate := 0;
FBitrate := 0;
FDuration := 0;
end;
{ ********************** Public functions & procedures ********************** }
constructor TAC3.Create;
begin
{ Create object }
inherited;
FResetData;
end;
(* -------------------------------------------------------------------------- *)
destructor TAC3.Destroy;
begin
inherited;
end;
(* -------------------------------------------------------------------------- *)
function TAC3.ReadFromFile(const FileName: String): Boolean;
var
f: TFileStreamEx;
SignatureChunk: Word;
tehByte: Byte;
begin
Result := False;
FResetData;
f:=nil;
try
f := TFileStreamEx.create(FileName, fmOpenRead or fmShareDenyWrite);
//0x0B77
if (f.Read(SignatureChunk, SizeOf(SignatureChunk)) = SizeOf(SignatureChunk)) and (SignatureChunk = 30475) then
begin
FillChar(tehByte, SizeOf(tehByte),0);
f.Seek(2, soFromCurrent);
f.Read(tehByte, SizeOf(tehByte));
FFileSize := f.Size;
FValid := TRUE;
case (tehByte and $C0) of
0: FSampleRate := 48000;
$40: FSampleRate := 44100;
$80: FSampleRate := 32000;
else FSampleRate := 0;
end;
FBitrate := BIRATES[(tehByte and $3F) shr 1];
FillChar(tehByte, SizeOf(tehByte),0);
f.Seek(1, soFromCurrent);
f.Read(tehByte, SizeOf(tehByte));
case (tehByte and $E0) of
0: FChannels := 2;
$20: FChannels := 1;
$40: FChannels := 2;
$60: FChannels := 3;
$80: FChannels := 3;
$A0: FChannels := 4;
$C0: FChannels := 4;
$E0: FChannels := 5;
else FChannels := 0;
end;
FBits := 16;
FDuration := FFileSize * 8 / 1000 / FBitrate;
Result := True;
end;
finally
f.free;
end;
end;
(* -------------------------------------------------------------------------- *)
function TAC3.FGetRatio: Double;
begin
{ Get compression ratio }
if FValid then
Result := FFileSize / ((FDuration * FSampleRate) * (FChannels * FBits / 8) + 44) * 100
else
Result := 0;
end;
(* -------------------------------------------------------------------------- *)
end.

View file

@ -0,0 +1,209 @@
{ *************************************************************************** }
{ }
{ Audio Tools Library }
{ Class TDTS - for manipulating with DTS Files }
{ }
{ http://mac.sourceforge.net/atl/ }
{ e-mail: macteam@users.sourceforge.net }
{ }
{ Copyright (c) 2005 by Gambit }
{ }
{ Version 1.1 (April 2005) by Gambit }
{ - updated to unicode file access }
{ }
{ Version 1.0 (10 January 2005) }
{ }
{ This library is free software; you can redistribute it and/or }
{ modify it under the terms of the GNU Lesser General Public }
{ License as published by the Free Software Foundation; either }
{ version 2.1 of the License, or (at your option) any later version. }
{ }
{ This library is distributed in the hope that it will be useful, }
{ but WITHOUT ANY WARRANTY; without even the implied warranty of }
{ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU }
{ Lesser General Public License for more details. }
{ }
{ You should have received a copy of the GNU Lesser General Public }
{ License along with this library; if not, write to the Free Software }
{ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA }
{ }
{ *************************************************************************** }
unit DTS;
interface
uses
Classes, SysUtils, DCClassesUtf8;
const
BIRATES: array[0..31] of Integer = (32, 56, 64, 96, 112, 128, 192, 224, 256,
320, 384, 448, 512, 576, 640, 768, 960,
1024, 1152, 1280, 1344, 1408, 1411, 1472,
1536, 1920, 2048, 3072, 3840, 0, -1, 1);
//open, variable, lossless
type
{ Class TDTS }
TDTS = class(TObject)
private
{ Private declarations }
FFileSize: Int64;
FValid: Boolean;
FChannels: Cardinal;
FBits: Cardinal;
FSampleRate: Cardinal;
FBitrate: Word;
FDuration: Double;
function FGetRatio: Double;
procedure FResetData;
public
{ Public declarations }
constructor Create; { Create object }
destructor Destroy; override; { Destroy object }
function ReadFromFile(const FileName: String): Boolean; { Load header }
property FileSize: Int64 read FFileSize;
property Valid: Boolean read FValid;
property Channels: Cardinal read FChannels;
property Bits: Cardinal read FBits;
property SampleRate: Cardinal read FSampleRate;
property Bitrate: Word read FBitrate;
property Duration: Double read FDuration;
property Ratio: Double read FGetRatio; { Compression ratio (%) }
end;
implementation
{ ********************** Private functions & procedures ********************* }
procedure TDTS.FResetData;
begin
{ Reset all data }
FFileSize := 0;
FValid := False;
FChannels := 0;
FBits := 0;
FSampleRate := 0;
FBitrate := 0;
FDuration := 0;
end;
{ ********************** Public functions & procedures ********************** }
constructor TDTS.Create;
begin
{ Create object }
inherited;
FResetData;
end;
(* -------------------------------------------------------------------------- *)
destructor TDTS.Destroy;
begin
inherited;
end;
(* -------------------------------------------------------------------------- *)
function TDTS.ReadFromFile(const FileName: String): Boolean;
var
f: TFileStreamEx;
SignatureChunk: Cardinal;
tehWord: Word;
gayDTS: array[0..7] of Byte;
begin
Result := False;
FResetData;
f:=nil;
try
f := TFileStreamEx.create(FileName, fmOpenRead or fmShareDenyWrite);
//0x7FFE8001
if (f.Read(SignatureChunk, SizeOf(SignatureChunk)) = SizeOf(SignatureChunk)) and (SignatureChunk = 25230975) then
begin
FillChar(gayDTS, SizeOf(gayDTS),0);
f.Seek(3, soFromCurrent);
f.Read(gayDTS, SizeOf(gayDTS));
FFileSize := f.Size;
FValid := TRUE;
tehWord := gayDTS[1] or (gayDTS[0] shl 8);
case ((tehWord and $0FC0) shr 6) of
0: FChannels := 1;
1..4: FChannels := 2;
5..6: FChannels := 3;
7..8: FChannels := 4;
9: FChannels := 5;
10..12: FChannels := 6;
13: FChannels := 7;
14..15: FChannels := 8;
else FChannels := 0;
end;
case ((tehWord and $3C) shr 2) of
1: FSampleRate := 8000;
2: FSampleRate := 16000;
3: FSampleRate := 32000;
6: FSampleRate := 11025;
7: FSampleRate := 22050;
8: FSampleRate := 44100;
11: FSampleRate := 12000;
12: FSampleRate := 24000;
13: FSampleRate := 48000;
else FSampleRate := 0;
end;
tehWord := 0;
tehWord := gayDTS[2] or (gayDTS[1] shl 8);
FBitrate := BIRATES[(tehWord and $03E0) shr 5];
tehWord := 0;
tehWord := gayDTS[7] or (gayDTS[6] shl 8);
case ((tehWord and $01C0) shr 6) of
0..1: FBits := 16;
2..3: FBits := 20;
4..5: FBits := 24;
else FBits := 16;
end;
FDuration := FFileSize * 8 / 1000 / FBitrate;
Result := True;
end;
finally
f.free;
end;
end;
(* -------------------------------------------------------------------------- *)
function TDTS.FGetRatio: Double;
begin
{ Get compression ratio }
if FValid then
Result := FFileSize / ((FDuration * FSampleRate) * (FChannels * FBits / 8) + 44) * 100
else
Result := 0;
end;
(* -------------------------------------------------------------------------- *)
end.

View file

@ -0,0 +1,274 @@
{ *************************************************************************** }
{ }
{ Audio Tools Library }
{ Class TOptimFROG - for manipulating with OptimFROG file information }
{ }
{ http://mac.sourceforge.net/atl/ }
{ e-mail: macteam@users.sourceforge.net }
{ }
{ Copyright (c) 2003-2005 by Erik Stenborg }
{ }
{ Version 1.1 (April 2005) by Gambit }
{ - updated to unicode file access }
{ }
{ Version 1.0 (10 July 2003) }
{ - Support for OptimFROG files via modification of TMonkey class by Jurgen }
{ - Class TID3v1: reading & writing support for ID3v1 tags }
{ - Class TID3v2: reading & writing support for ID3v2 tags }
{ - Class TAPEtag: reading & writing support for APE tags }
{ }
{ This library is free software; you can redistribute it and/or }
{ modify it under the terms of the GNU Lesser General Public }
{ License as published by the Free Software Foundation; either }
{ version 2.1 of the License, or (at your option) any later version. }
{ }
{ This library is distributed in the hope that it will be useful, }
{ but WITHOUT ANY WARRANTY; without even the implied warranty of }
{ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU }
{ Lesser General Public License for more details. }
{ }
{ You should have received a copy of the GNU Lesser General Public }
{ License along with this library; if not, write to the Free Software }
{ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA }
{ }
{ *************************************************************************** }
unit OptimFROG;
interface
uses
Classes, SysUtils, ID3v1, ID3v2, APEtag, DCClassesUtf8;
const
OFR_COMPRESSION: array [0..9] of String = ('fast', 'normal', 'high', 'extra',
'best', 'ultra', 'insane', 'highnew', 'extranew', 'bestnew');
OFR_BITS: array [0..10] of ShortInt = (8, 8, 16, 16, 24, 24, 32, 32,
-32, -32, -32); //negative value corresponds to floating point type.
OFR_CHANNELMODE: array [0..1] of String = ('Mono', 'Stereo');
type
{ Real structure of OptimFROG header }
TOfrHeader = packed record
ID: array [1..4] of Char; { Always 'OFR ' }
Size: Cardinal;
Length: Cardinal;
HiLength: Word;
SampleType, ChannelMode: Byte;
SampleRate: Integer;
EncoderID: Word;
CompressionID: Byte;
end;
{ Class TOptimFrog }
TOptimFrog = class(TObject)
private
{ Private declarations }
FFileLength: Int64;
FHeader: TOfrHeader;
FID3v1: TID3v1;
FID3v2: TID3v2;
FAPEtag: TAPEtag;
procedure FResetData;
function FGetValid: Boolean;
function FGetVersion: string;
function FGetCompression: string;
function FGetBits: ShortInt;
function FGetChannelMode: string;
function FGetSamples: Int64;
function FGetDuration: Double;
function FGetRatio: Double;
function FGetSampleRate: Integer;
function FGetChannels: Byte;
function FGetBitrate: Integer;
public
{ Public declarations }
constructor Create; { Create object }
destructor Destroy; override; { Destroy object }
function ReadFromFile(const FileName: String): Boolean; {Load header }
property FileLength: Int64 read FFileLength; { File length (bytes) }
property Header: TOfrHeader read FHeader; { OptimFROG header }
property ID3v1: TID3v1 read FID3v1; { ID3v1 tag data }
property ID3v2: TID3v2 read FID3v2; { ID3v2 tag data }
property APEtag: TAPEtag read FAPEtag; { APE tag data }
property Valid: Boolean read FGetValid; { True if header valid }
property Version: string read FGetVersion; { Encoder version }
property Compression: string read FGetCompression; { Compression level }
property Bits: ShortInt read FGetBits; { Bits per sample }
property ChannelMode: string read FGetChannelMode; { Channel mode }
property Samples: Int64 read FGetSamples; { Number of samples }
property Duration: Double read FGetDuration; { Duration (seconds) }
property SampleRate: Integer read FGetSampleRate; { Sample rate (Hz) }
property Ratio: Double read FGetRatio; { Compression ratio (%) }
property Channels: Byte read FGetChannels;
property Bitrate: Integer read FGetBitrate;
end;
implementation
{ ********************** Private functions & procedures ********************* }
procedure TOptimFrog.FResetData;
begin
{ Reset data }
FFileLength := 0;
FillChar(FHeader, SizeOf(FHeader), 0);
FID3v1.ResetData;
FID3v2.ResetData;
FAPEtag.ResetData;
end;
{ --------------------------------------------------------------------------- }
function TOptimFrog.FGetValid: Boolean;
begin
Result :=
(FHeader.ID = 'OFR ') and
(FHeader.SampleRate > 0) and
(FHeader.SampleType in [0..10]) and
(FHeader.ChannelMode in [0..1]) and
(FHeader.CompressionID shr 3 in [0..9]);
end;
{ --------------------------------------------------------------------------- }
function TOptimFrog.FGetVersion: string;
begin
{ Get encoder version }
Result := Format('%5.3f', [((FHeader.EncoderID shr 4) + 4500) / 1000]);
end;
{ --------------------------------------------------------------------------- }
function TOptimFrog.FGetCompression: string;
begin
{ Get compression level }
Result := OFR_COMPRESSION[FHeader.CompressionID shr 3]
end;
{ --------------------------------------------------------------------------- }
function TOptimFrog.FGetBits: ShortInt;
begin
{ Get number of bits per sample }
Result := OFR_BITS[FHeader.SampleType]
end;
{ --------------------------------------------------------------------------- }
function TOptimFrog.FGetChannelMode: string;
begin
{ Get channel mode }
Result := OFR_CHANNELMODE[FHeader.ChannelMode]
end;
{ --------------------------------------------------------------------------- }
function TOptimFrog.FGetSamples: Int64;
var
Res: array [0..1] of Cardinal absolute Result;
begin
{ Get number of samples }
Res[0] := Header.Length shr Header.ChannelMode;
Res[1] := Header.HiLength shr Header.ChannelMode;
end;
{ --------------------------------------------------------------------------- }
function TOptimFrog.FGetDuration: Double;
begin
{ Get song duration }
if FHeader.SampleRate > 0 then
Result := FGetSamples / FHeader.SampleRate
else
Result := 0;
end;
{ --------------------------------------------------------------------------- }
function TOptimFrog.FGetSampleRate: Integer;
begin
Result := Header.SampleRate;
end;
{ --------------------------------------------------------------------------- }
function TOptimFrog.FGetRatio: Double;
begin
{ Get compression ratio }
if FGetValid then
Result := FFileLength /
(FGetSamples * ((FHeader.ChannelMode+1) * Abs(FGetBits) / 8) + 44) * 100
else
Result := 0;
end;
{ ********************** Public functions & procedures ********************** }
constructor TOptimFrog.Create;
begin
{ Create object }
inherited;
FID3v1 := TID3v1.Create;
FID3v2 := TID3v2.Create;
FAPEtag := TAPEtag.Create;
FResetData;
end;
{ --------------------------------------------------------------------------- }
destructor TOptimFrog.Destroy;
begin
{ Destroy object }
FID3v1.Free;
FID3v2.Free;
FAPEtag.Free;
inherited;
end;
{ --------------------------------------------------------------------------- }
function TOptimFrog.ReadFromFile(const FileName: String): Boolean;
var
SourceFile: TFileStreamEx;
begin
Result := False;
SourceFile := nil;
try
{ Reset data and search for file tag }
FResetData;
FID3v1.ReadFromFile(FileName);
FID3v2.ReadFromFile(FileName);
FAPEtag.ReadFromFile(FileName);
{ Set read-access, open file and get file length }
SourceFile := TFileStreamEx.Create(FileName, fmOpenRead or fmShareDenyWrite);
FFileLength := SourceFile.Size;
{ Read header data }
SourceFile.Seek(ID3v2.Size, soFromBeginning);
SourceFile.Read(FHeader, SizeOf(FHeader));
if FHeader.ID = 'OFR ' then
Result := True;
finally
SourceFile.Free;
end;
end;
{ --------------------------------------------------------------------------- }
function TOptimFrog.FGetChannels: Byte;
begin
Result := Header.ChannelMode + 1;
end;
{ --------------------------------------------------------------------------- }
function TOptimFrog.FGetBitrate: Integer;
begin
Result := Round(FFileLength * 8.0 / (FGetSamples / FHeader.SampleRate * 1000));
end;
{ --------------------------------------------------------------------------- }
end.

View file

@ -0,0 +1,426 @@
{ *************************************************************************** }
{ }
{ Audio Tools Library }
{ Class TWAVPackFile - for manipulating with WAVPack Files }
{ }
{ http://mac.sourceforge.net/atl/ }
{ e-mail: macteam@users.sourceforge.net }
{ }
{ Copyright (c) 2003-2005 by Mattias Dahlberg }
{ }
{ Version 1.2 (09 August 2004) by jtclipper }
{ - updated to support WavPack version 4 files }
{ - added encoder detection }
{ }
{ Version 1.1 (April 2004) by Gambit }
{ - Added Ratio and Samples property }
{ }
{ Version 1.0 (August 2003) }
{ }
{ This library is free software; you can redistribute it and/or }
{ modify it under the terms of the GNU Lesser General Public }
{ License as published by the Free Software Foundation; either }
{ version 2.1 of the License, or (at your option) any later version. }
{ }
{ This library is distributed in the hope that it will be useful, }
{ but WITHOUT ANY WARRANTY; without even the implied warranty of }
{ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU }
{ Lesser General Public License for more details. }
{ }
{ You should have received a copy of the GNU Lesser General Public }
{ License along with this library; if not, write to the Free Software }
{ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA }
{ }
{ *************************************************************************** }
unit WAVPackfile;
interface
uses
Classes, SysUtils, APEtag, DCClassesUtf8;
type
TWAVPackfile = class(TObject)
private
FFileSize: int64;
FValid: boolean;
FFormatTag: integer;
FVersion: integer;
FChannels: integer;
FSampleRate: integer;
FBits: integer;
FBitrate: double;
FDuration: double;
FEncoder: string;
FAPEtag : TAPEtag;
FTagSize: integer;
FSamples: Int64;
FBSamples: Int64;
procedure FResetData;
function FGetRatio: Double;
function FGetChannelMode: string;
public
constructor Create;
destructor Destroy; override;
function ReadFromFile(const FileName: String): Boolean;
function _ReadV3( f: TFileStreamEx ): boolean;
function _ReadV4( f: TFileStreamEx ): boolean;
property FileSize: int64 read FFileSize;
property Valid: boolean read FValid;
property FormatTag: integer read FFormatTag;
property Version: integer read FVersion;
property Channels: integer read FChannels;
property ChannelMode: string read FGetChannelMode;
property SampleRate: integer read FSamplerate;
property Bits: integer read FBits;
property Bitrate: double read FBitrate;
property Duration: double read FDuration;
property Samples: Int64 read FSamples;
property BSamples: Int64 read FBSamples;
property Ratio: Double read FGetRatio;
property Encoder: string read FEncoder;
property APEtag: TAPEtag read FAPEtag;
end;
implementation
type
wavpack_header3 = record
ckID: array[0..3] of char;
ckSize: longword;
version: word;
bits: word ;
flags: word;
shift: word;
total_samples: longword;
crc: longword;
crc2: longword;
extension: array[0..3] of char;
extra_bc: byte;
extras: array[0..2] of char;
end;
wavpack_header4 = record
ckID: array[0..3] of char;
ckSize: longword;
version: word;
track_no: byte;
index_no: byte;
total_samples: longword;
block_index: longword;
block_samples: longword;
flags: longword;
crc: longword;
end;
fmt_chunk = record
wformattag: word;
wchannels: word;
dwsamplespersec: longword;
dwavgbytespersec: longword;
wblockalign: word;
wbitspersample: word;
end;
riff_chunk = record
id: array[0..3] of char;
size: longword;
end;
const
//version 3 flags
MONO_FLAG_v3 = 1; // not stereo
FAST_FLAG_v3 = 2; // non-adaptive predictor and stereo mode
// RAW_FLAG_v3 = 4; // raw mode (no .wav header)
// CALC_NOISE_v3 = 8; // calc noise in lossy mode (no longer stored)
HIGH_FLAG_v3 = $10; // high quality mode (all modes)
// BYTES_3_v3 = $20; // files have 3-byte samples
// OVER_20_v3 = $40; // samples are over 20 bits
WVC_FLAG_v3 = $80; // create/use .wvc (no longer stored)
// LOSSY_SHAPE_v3 = $100; // noise shape (lossy mode only)
// VERY_FAST_FLAG_v3 = $200; // double fast (no longer stored)
NEW_HIGH_FLAG_v3 = $400; // new high quality mode (lossless only)
// CANCEL_EXTREME_v3 = $800; // cancel EXTREME_DECORR
// CROSS_DECORR_v3 = $1000; // decorrelate chans (with EXTREME_DECORR flag)
// NEW_DECORR_FLAG_v3 = $2000; // new high-mode decorrelator
// JOINT_STEREO_v3 = $4000; // joint stereo (lossy and high lossless)
EXTREME_DECORR_v3 = $8000; // extra decorrelation (+ enables other flags)
sample_rates: array[0..14] of integer = ( 6000, 8000, 9600, 11025, 12000, 16000, 22050,
24000, 32000, 44100, 48000, 64000, 88200, 96000, 192000 );
{ --------------------------------------------------------------------------- }
procedure TWAVPackfile.FResetData;
begin
FFileSize := 0;
FTagSize := 0;
FValid := false;
FFormatTag := 0;
FChannels := 0;
FSampleRate := 0;
FBits := 0;
FBitrate := 0;
FDuration := 0;
FVersion := 0;
FEncoder := '';
FSamples := 0;
FBSamples := 0;
FAPEtag.ResetData;
end;
{ --------------------------------------------------------------------------- }
constructor TWAVPackfile.Create;
begin
inherited;
FAPEtag := TAPEtag.Create;
FResetData;
end;
destructor TWAVPackfile.Destroy;
begin
FAPEtag.Free;
inherited;
end;
{ --------------------------------------------------------------------------- }
function TWAVPackfile.FGetChannelMode: string;
begin
case FChannels of
1: result := 'Mono';
2: result := 'Stereo';
else result := 'Surround';
end;
end;
{ --------------------------------------------------------------------------- }
function TWAVPackfile.ReadFromFile(const FileName: String): Boolean;
var
f: TFileStreamEx;
marker: array[0..3] of char;
begin
FResetData;
FAPEtag.ReadFromFile(FileName);
FTagSize := FAPEtag.Size;
try
f := TFileStreamEx.create(FileName, fmOpenRead or fmShareDenyWrite);
FFileSize := f.Size;
//read first bytes
FillChar( marker, SizeOf( marker ), 0 );
f.Read( marker, SizeOf( marker) );
f.Seek( 0, soFromBeginning );
if marker = 'RIFF' then begin
result := _ReadV3( f );
end else if marker = 'wvpk' then begin
result := _ReadV4( f );
end else begin
result := False;
end;
finally
FreeAndNil( f );
end;
end;
{ --------------------------------------------------------------------------- }
function TWAVPackfile._ReadV4( f: TFileStreamEx ): boolean;
var
wvh4: wavpack_header4;
EncBuf : array[1..4096] of Byte;
tempo : Integer;
encoderbyte: Byte;
begin
result := false;
FillChar( wvh4, SizeOf(wvh4) ,0);
f.Read( wvh4, SizeOf(wvh4) );
if wvh4.ckID = 'wvpk' then // wavpack header found
begin
Result := true;
FValid := true;
FVersion := wvh4.version shr 8;
FChannels := 2 - (wvh4.flags and 4); // mono flag
FBits := ((wvh4.flags and 3) * 16); // bytes stored flag
FSamples := wvh4.total_samples;
FBSamples := wvh4.block_samples;
FSampleRate := (wvh4.flags and ($1F shl 23)) shr 23;
if (FSampleRate > 14) or (FSampleRate < 0) then
begin
FSampleRate := 44100;
end
else
begin
FSampleRate := sample_rates[ FSampleRate ];
end;
if ((wvh4.flags and 8) = 8) then // hybrid flag
begin
FEncoder := 'hybrid lossy';
end
else
begin //if ((wvh4.flags and 2) = 2) then begin // lossless flag
FEncoder := 'lossless';
end;
{
if ((wvh4.flags and $20) > 0) then // MODE_HIGH
begin
FEncoder := FEncoder + ' (high)';
end
else if ((wvh4.flags and $40) > 0) then // MODE_FAST
begin
FEncoder := FEncoder + ' (fast)';
end;
}
FDuration := wvh4.total_samples / FSampleRate;
if FDuration > 0 then
FBitrate := (FFileSize - int64( FTagSize ) ) * 8 / (FSamples / FSampleRate) / 1000;
FillChar(EncBuf, SizeOf(EncBuf), 0);
f.Read(EncBuf, SizeOf(EncBuf));
for tempo := 1 to 4094 do
begin
If EncBuf[tempo] = $65 then if
EncBuf[tempo + 1] = $02 then
begin
encoderbyte := EncBuf[tempo + 2];
if encoderbyte = 8 then
FEncoder := FEncoder + ' (high)'
else if encoderbyte = 0 then
FEncoder := FEncoder + ' (normal)'
else if encoderbyte = 2 then
FEncoder := FEncoder + ' (fast)'
else if encoderbyte = 6 then
FEncoder := FEncoder + ' (very fast)';
Break;
end;
end;
end;
end;
{ --------------------------------------------------------------------------- }
function TWAVPackfile._ReadV3( f: TFileStreamEx ): boolean;
var
chunk: riff_chunk;
wavchunk: array[0..3] of char;
fmt: fmt_chunk;
hasfmt: boolean;
fpos: int64;
wvh3: wavpack_header3;
begin
result := false;
hasfmt := false;
// read and evaluate header
FillChar( chunk, sizeof(chunk), 0 );
if (f.Read(chunk, sizeof(chunk)) <> SizeOf( chunk )) or
(f.Read(wavchunk, sizeof(wavchunk)) <> SizeOf(wavchunk)) or (wavchunk <> 'WAVE') then exit;
// start looking for chunks
FillChar( chunk, SizeOf(chunk), 0 );
while (f.Position < f.Size) do begin
if (f.read(chunk, sizeof(chunk)) < sizeof(chunk)) or (chunk.size <= 0) then break;
fpos := f.Position;
if chunk.id = 'fmt ' then begin // Format chunk found read it
if (chunk.size >= sizeof(fmt)) and (f.Read(fmt, sizeof(fmt)) = sizeof(fmt)) then begin
hasfmt := true;
result := True;
FValid := true;
FFormatTag := fmt.wformattag;
FChannels := fmt.wchannels;
FSampleRate := fmt.dwsamplespersec;
FBits := fmt.wbitspersample;
FBitrate := fmt.dwavgbytespersec / 125.0; // 125 = 1/8*1000
end else begin
break;
end;
end else if (chunk.id = 'data') and hasfmt then begin
FillChar( wvh3, SizeOf(wvh3) ,0);
f.Read( wvh3, SizeOf(wvh3) );
if wvh3.ckID = 'wvpk' then begin // wavpack header found
result := true;
FValid := true;
FVersion := wvh3.version;
FChannels := 2 - (wvh3.flags and 1); // mono flag
FSamples := wvh3.total_samples;
// Encoder guess
if wvh3.bits > 0 then begin
if (wvh3.flags and NEW_HIGH_FLAG_v3) > 0 then begin
FEncoder := 'hybrid';
if (wvh3.flags and WVC_FLAG_v3) > 0 then begin
FEncoder := FEncoder + ' lossless';
end else begin
FEncoder := FEncoder + ' lossy';
end;
if (wvh3.flags and EXTREME_DECORR_v3) > 0 then FEncoder := FEncoder + ' (high)';
end else if (wvh3.flags and (HIGH_FLAG_v3 or FAST_FLAG_v3)) = 0 then begin
FEncoder := IntToStr( wvh3.bits + 3 ) + '-bit lossy';
end else begin
FEncoder := IntToStr( wvh3.bits + 3 ) + '-bit lossy';
if (wvh3.flags and HIGH_FLAG_v3) > 0 then begin
FEncoder := FEncoder + ' high';
end else begin
FEncoder := FEncoder + ' fast';
end
end;
end else begin
if (wvh3.flags and HIGH_FLAG_v3) = 0 then begin
FEncoder := 'lossless (fast mode)';
end else if (wvh3.flags and EXTREME_DECORR_v3) > 0 then begin
FEncoder := 'lossless (high mode)';
end else begin
FEncoder := 'lossless';
end;
end;
if FSampleRate <= 0 then FSampleRate := 44100;
FDuration := wvh3.total_samples / FSampleRate;
if FDuration > 0 then FBitrate := 8.0*(FFileSize - int64( FTagSize ) - int64(wvh3.ckSize))/(FDuration*1000.0);
end;
break;
end else begin // not a wv file
break;
end;
f.seek( fpos + chunk.size, soFromBeginning );
end; // while
end;
{ --------------------------------------------------------------------------- }
function TWAVPackfile.FGetRatio: Double;
begin
{ Get compression ratio }
if FValid then
Result := FFileSize / (FSamples * (FChannels * FBits / 8) + 44) * 100
else
Result := 0;
end;
{ --------------------------------------------------------------------------- }
end.

View file

@ -28,7 +28,8 @@ interface
uses
Classes, SysUtils, DCStrUtils, MPEGaudio, Musepack, OggVorbis, ID3v1, ID3v2,
APEtag, FLACfile, Monkey, AACfile, CDAtrack, WMAfile, WAVfile, TTA, TwinVQ;
APEtag, FLACfile, Monkey, AACfile, CDAtrack, WMAfile, WAVfile, TTA, TwinVQ,
AC3, DTS, WAVPackfile, OptimFROG;
type
@ -36,6 +37,8 @@ type
TAudioData = class
private
FDTS: TDTS;
FAC3: TAC3;
FTTA: TTTA;
FTwinVQ: TTwinVQ;
FMonkey: TMonkey;
@ -47,6 +50,8 @@ type
FCDAtrack: TCDAtrack;
FMPEGaudio: TMPEGaudio;
FOggVorbis: TOggVorbis;
FOptimFrog: TOptimFrog;
FWAVPackfile: TWAVPackfile;
private
procedure Clear;
procedure ReadID3v1(ID3v1: TID3v1);
@ -57,6 +62,8 @@ type
procedure UpdateValue(var AValue: String; const AData: String);
protected
FFileName: String;
function ReadDTS: Boolean;
function ReadAC3: Boolean;
function ReadTTA: Boolean;
function ReadTwinVQ: Boolean;
function ReadMonkey: Boolean;
@ -68,6 +75,8 @@ type
function ReadCDAtrack: Boolean;
function ReadMPEGaudio: Boolean;
function ReadOggVorbis: Boolean;
function ReadOptimFrog: Boolean;
function ReadWAVPackfile: Boolean;
public
Album, Artist, Title: String;
Track,
@ -179,6 +188,32 @@ begin
if Length(AValue) = 0 then AValue:= AData;
end;
function TAudioData.ReadDTS: Boolean;
begin
Result:= FDTS.ReadFromFile(FFileName) and FDTS.Valid;
if Result then
begin
BitRate:= FDTS.BitRate;
// Channels:= FDTS.ChannelMode;
Duration:= Round(FDTS.Duration);
DurationHMS:= FormatDuration(Duration);
SampleRate:= FDTS.SampleRate;
end;
end;
function TAudioData.ReadAC3: Boolean;
begin
Result:= FAC3.ReadFromFile(FFileName) and FAC3.Valid;
if Result then
begin
BitRate:= FAC3.BitRate;
// Channels:= FAC3.ChannelMode;
Duration:= Round(FAC3.Duration);
DurationHMS:= FormatDuration(Duration);
SampleRate:= FAC3.SampleRate;
end;
end;
function TAudioData.ReadTTA: Boolean;
begin
Result:= FTTA.ReadFromFile(FFileName) and FTTA.Valid;
@ -377,8 +412,41 @@ begin
end;
end;
function TAudioData.ReadOptimFrog: Boolean;
begin
Result:= FOptimFrog.ReadFromFile(FFileName) and FOptimFrog.Valid;
if Result then
begin
BitRate:= FOptimFrog.BitRate;
Channels:= FOptimFrog.ChannelMode;
Duration:= Round(FOptimFrog.Duration);
DurationHMS:= FormatDuration(Duration);
SampleRate:= FOptimFrog.SampleRate;
ReadID3v2(FOptimFrog.ID3v2);
ReadID3v1(FOptimFrog.ID3v1);
ReadAPEtag(FOptimFrog.APEtag);
end;
end;
function TAudioData.ReadWAVPackfile: Boolean;
begin
Result:= FWAVPackfile.ReadFromFile(FFileName) and FWAVPackfile.Valid;
if Result then
begin
Encoder:= FWAVPackfile.Encoder;
Channels:= FWAVPackfile.ChannelMode;
BitRate:= Round(FWAVPackfile.BitRate);
Duration:= Round(FWAVPackfile.Duration);
DurationHMS:= FormatDuration(Duration);
SampleRate:= FWAVPackfile.SampleRate;
ReadAPEtag(FWAVPackfile.APEtag);
end;
end;
constructor TAudioData.Create;
begin
FDTS:= TDTS.Create;
FAC3:= TAC3.Create;
FTTA:= TTTA.Create;
FTwinVQ:= TTwinVQ.Create;
FMonkey:= TMonkey.Create;
@ -390,10 +458,14 @@ begin
FFLACfile:= TFLACfile.Create;
FMPEGaudio:= TMPEGaudio.Create;
FOggVorbis:= TOggVorbis.Create;
FOptimFrog:= TOptimFrog.Create;
FWAVPackfile:= TWAVPackfile.Create;
end;
destructor TAudioData.Destroy;
begin
FDTS.Free;
FAC3.Free;
FTTA.Free;
FTwinVQ.Free;
FMonkey.Free;
@ -405,6 +477,8 @@ begin
FFLACfile.Free;
FMPEGaudio.Free;
FOggVorbis.Free;
FOptimFrog.Free;
FWAVPackfile.Free;
inherited Destroy;
end;
@ -461,6 +535,22 @@ begin
begin
Result:= ReadTwinVQ;
end
else if (FileExt = 'ac3') then
begin
Result:= ReadAC3;
end
else if (FileExt = 'dts') then
begin
Result:= ReadDTS;
end
else if (FileExt = 'wv') or (FileExt = 'wvc') then
begin
Result:= ReadWAVPackfile;
end
else if (FileExt = 'ofr') or (FileExt = 'ofs') then
begin
Result:= ReadOptimFrog;
end
else Result:= False;
if Result then