unit AudioOptimFrog;

interface

uses KOL, ATLCommon, TagID3v1, TagID3v2, TagAPE;

type TOptimFrogAudioInfo = PAudioInfo;

function NewAudioOptimFrog: TOptimFrogAudioInfo;

implementation

uses ATLLib;

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.

type
  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;

type
  TAudioOptimFrog = object(TAudioInfo)
  private
  end;

function AudioOptimFrogReader(const AFileName: KOLstring; AudioInfo: TOptimFrogAudioInfo): Boolean; forward;

function NewAudioOptimFrog: TOptimFrogAudioInfo;
begin
    New(Result, Create);
    with TAudioOptimFrog(Result^) do begin
      TagAdd(tID3v1, NewTagID3v1);
      TagAdd(tID3v2, NewTagID3v2);
      TagAdd(tAPE, NewTagAPE);
      FAudioVendor:= aOptimFrog;
      FExistsProps:= [apSampleRate, apBitrate, apChannels, apBits, apSamples, apDuration, apRatio];
      FReader:= AudioOptimFrogReader;
    end;
end;

function AudioOptimFrogReader(const AFileName: KOLstring; AudioInfo: TOptimFrogAudioInfo): Boolean;
type TSamples = array [0..1] of Cardinal;
var SourceFile: PStream;
    TagSize: Integer;
    Header: TOfrHeader;
    Smpls: Int64;
begin
    with TAudioOptimFrog(AudioInfo^) do begin
      Result := False;
      try
        SourceFile := OpenFileRead(AFileName);
        try
          ResetData;
          TagInfo[tID3v1].ReadFromFile(AFileName);
          TagInfo[tID3v2].ReadFromFile(AFileName);
          TagInfo[tAPE].ReadFromFile(AFileName);

          TagSize:= TagInfo[tID3v1].TagSize + PTagID3v1(TagInfo[tID3v1]).Lyrics.TagSize + TagInfo[tID3v2].TagSize + TagInfo[tAPE].TagSize;
          FFileSize:= SourceFile.Size;

          SourceFile.Seek(TagInfo[tID3v2].TagSize, spBegin);
          if SourceFile.Read(Header, SizeOf(TOfrHeader)) <> SizeOf(TOfrHeader) then Exit;
          if Header.ID <> 'OFR ' then Exit;

          FValid := (Header.SampleRate > 0) and
                    (Header.SampleType in [0..10]) and
                    (Header.ChannelMode in [0..1]) and
                    (Header.CompressionID shr 3 in [0..9]);

          if FValid then begin
            TSamples(Smpls)[0]:= Header.Length shr Header.ChannelMode;
            TSamples(Smpls)[1]:= Header.HiLength shr Header.ChannelMode;
            FSamples:= Smpls;
            FSampleRate:= Header.SampleRate;
            FChannels:= Header.ChannelMode + 1;
            FBits:= OFR_BITS[Header.SampleType];

            if Header.SampleRate > 0 then begin

              FBitrate:= 8 * Round((FFileSize - TagSize - SizeOf(TOfrHeader)) / (FSamples / Header.SampleRate * 1000));
              FDuration := FSamples / Header.SampleRate
            end;

            FRatio:= (FFileSize - TagSize - SizeOf(TOfrHeader) - SizeOf(TOfrHeader)) / (FSamples * (Header.ChannelMode * Abs(FBits) / 8) + 44) * 100;
            {$IFDEF USE_OtherAudioProps}
            OtherProps.Add('Version='+format('%u.%u', [((Header.EncoderID shr 4) + 4500) div 1000, ((Header.EncoderID shr 4) + 4500) mod 1000]));
            OtherProps.Add('Compression='+OFR_COMPRESSION[Header.CompressionID shr 3]);
            {$ENDIF}
          end;
          Result := True;
        finally
          SourceFile.Free;
        end;
      except end;
    end;
end;

end.
