//FBits - ?

unit AudioWMA;
interface

uses KOL, TagWMA, ATLCommon;

type TWMAAudioInfo = PAudioInfo;

function NewAudioWMA: TWMAAudioInfo;

implementation

uses ATLLib;

const
  WMA_CM_UNKNOWN = 0;                                               { Unknown }
  WMA_CM_MONO = 1;                                                     { Mono }
  WMA_CM_STEREO = 2;                                                 { Stereo }

type                                          
  TAudioWMA = object(TAudioInfo)
  private
  end;

function AudioWMAReader(const AFileName: KOLstring; AudioInfo: TWMAAudioInfo): Boolean; forward;

function NewAudioWMA: TWMAAudioInfo;
begin
    New(Result, Create);
    with TAudioWMA(Result^) do begin
      FAudioVendor:= aWMA;
      FExistsProps:= [apSampleRate, apBitrate, apChannels, apBits, apDuration, apRatio];
      TagAdd(tWMA, NewTagWMA);
      TagAdd(tExWMA, NewTagExWMA);
      FReader:= AudioWMAReader;
    end;
end;

function AudioWMAReader(const AFileName: KOLstring; AudioInfo: TWMAAudioInfo): Boolean;
var MaxBitRate: Cardinal;
  procedure ReadObject(const ID: String; Source: PStream);
    {$IFDEF USE_OtherAudioProps}
    procedure ReadTagStream;
    var i : Integer;
        FieldCount, DataSize : Word;
        FieldValue: String;
    begin
        Source.Seek(20, spCurrent);
        Source.Read(FieldCount, SizeOf(FieldCount));
        for I:= 1 to FieldCount do begin
          Source.Read(DataSize, SizeOf(DataSize));
          DataSize:= DataSize * 2;
          FieldValue:= ReadFieldString(Source, DataSize);
          case I of
              1: TAudioWMA(AudioInfo^).OtherProps.Add('Version='+FieldValue);
              2: TAudioWMA(AudioInfo^).OtherProps.Add('StreamProperty='+FieldValue);
          end;
        end;
    end;
    {$ENDIF}
  begin
      with TAudioWMA(AudioInfo^) do begin
        if ID = WMA_FILE_PROPERTIES_ID then begin
          {.Read FileSize from Tag ..}
          Source.Seek(20, spCurrent);
          ReadFieldInteger(Source, 8);
          {.Decode Play Time}
          Source.Seek(16, spCurrent);
          FDuration:= (ReadFieldInteger(Source, 8) / 10000000);
          Source.Seek(8, spCurrent);
          FDuration:= FDuration - (ReadFieldInteger(Source, 8) / 1000);

          Source.Seek(12, spCurrent);
          Source.Read(MaxBitRate, SizeOf(MaxBitRate));
        end;

        if ID = WMA_STREAM_PROPERTIES_ID then begin
          Source.Seek(60, spCurrent);
          Source.Read(FChannels, SizeOf(FChannels));
          Source.Read(FSampleRate, SizeOf(FSampleRate));
          Source.Read(FBitRate, SizeOf(FBitRate));
        end;

        {$IFDEF USE_OtherAudioProps}
        if ID = WMA_STREAM_DESCRIPTION_ID then begin
          Source.Seek(4, spCurrent);
          ReadTagStream;
        end;
        {$ENDIF}
      end;
  end;
  function GetDataSize(const Source: PStream): Cardinal;
  var ID : String;
      Position : Cardinal;
      Size: Int64;
  begin
      Result:= Source.Size;

      Source.Seek(16, spBegin);
      Source.Read(Size, SizeOf(Size));      {Total TAG Size}
      Source.Seek(Size, spBegin);

      ID:= Source.ReadStrLen(16);
      if WMA_DATA_ID <> ID then begin
        Source.Seek(0, spBegin);
        while Source.Position < Source.Size-16 do begin
          ID:= Source.ReadStrLen(16);
          if WMA_DATA_ID = ID then Break;
          Position:= Source.Position - 15;
          Source.Seek(Position, spBegin);
          if Position > Source.Size - 15 then Exit;
        end;
      end;
      Result:= Result - (Source.Position - 16);
  end;
var Source: PStream;
    ID: String;
    i, ObjectCount, ObjectSize, Position: Integer;
    Size : Cardinal;
begin
    with TAudioWMA(AudioInfo^) do begin
      Result:= False;
      try
        ResetData;
        Source:= OpenFileRead(AFileName);
        try
          FFileSize:= Source.Size;
          MaxBitRate:= 0;

          ID:= Source.ReadStrLen(16);
          if ID <> WMA_HEADER_ID then Exit;

          TagInfo[tWMA].ReadFromFile(AFileName);
          TagInfo[tExWMA].ReadFromFile(AFileName);

          Source.Read(Size, SizeOf(Size));
          Source.Seek(4, spCurrent);
          Source.Read(ObjectCount, SizeOf(ObjectCount));
          Source.Seek(2, spCurrent);

          for i:= 1 to ObjectCount do begin
            Position:= Source.Position;

            ID:= Source.ReadStrLen(16);
            Source.Read(ObjectSize, SizeOf(ObjectSize));
            ReadObject(ID, Source);

            Source.Seek(Position + ObjectSize, spBegin);
          end;

          FBits:= 16;
          //if FChannelMode = btVBR then
            FBitRate:= MaxBitRate div 1000;
          //else FBitRate:= FBitRate * 8 div 1000;

          FRatio:= GetDataSize(Source) / ((FDuration * FSampleRate) * (FChannels * FBits / 8) + 44) * 100;

          FValid:= (MaxBitRate > 0) and
    //             (FMaxBitRate < 320000) and
                   ((FChannels = WMA_CM_MONO) or
                   (FChannels = WMA_CM_STEREO)) and
                   (FSampleRate >= 8000) and
                   (FSampleRate <= 96000) and
                   (BitRate > 0) and
                   (BitRate < 400000);
  {       Enc:= ExTagByNameString[WMATagsEx[tgENCODER]];
          if (Enc <> '') and (FMaxBitRate <> 0) then
            if (Enc[1] <> '9') and (FMaxBitRate < 320000) then
              FDuration:= (FFileSize - FTagSize) * 8 / FMaxBitRate
            else
              if (Enc[1] = '9') and (FMaxBitRate < 256000) and (FDuration < 100) then
                FDuration:= (FFileSize - FTagSize - FMaxBitRate div 8) / FBitRate - 2;
          if FDuration < 0 then FDuration:= 0;}

          Result:= True;
        finally
          Source.Free;
        end;
      except
        Result:= False;
      end;
    end;  
end;

end.

