unit AudioAC3;
 
interface

uses KOL, ATLCommon;

type TAC3AudioInfo = PAudioInfo;

function NewAudioAC3: TAC3AudioInfo;

implementation

uses ATLLib;

const _SampleRates: array [0..3] of Integer = (48000, 44100, 32000, 0);
      _Channels: array [0..7] of Byte = ( 2, 1, 2, 3, 3, 4, 4, 5);
      _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);
      _FrameSize : array [0..37, 0..2] of Integer = (
			( 64 , 69 , 96 ), ( 64 , 70 , 96 ), ( 80 , 87 , 120 ), ( 80 , 88 , 120 ),
		        ( 96 , 104 , 144 ), ( 96 , 105 , 144 ), ( 112 , 121 , 168 ), ( 112 , 122 , 168 ),
		        ( 128 , 139 , 192 ), ( 128 , 140 , 192 ), ( 160 , 174 , 240 ), ( 160 , 175 , 240 ),
		        ( 192 , 208 , 288 ), ( 192 , 209 , 288 ), ( 224 , 243 , 336 ), ( 224 , 244 , 336 ),
		        ( 256 , 278 , 384 ), ( 256 , 279 , 384 ), ( 320 , 348 , 480 ), ( 320 , 349 , 480 ),
		        ( 384 , 417 , 576 ), ( 384 , 418 , 576 ), ( 448 , 487 , 672 ), ( 448 , 488 , 672 ),
		        ( 512 , 557 , 768 ), ( 512 , 558 , 768 ), ( 640 , 696 , 960 ), ( 640 , 697 , 960 ),
		        ( 768 , 835 , 1152 ), ( 768 , 836 , 1152 ), ( 896 , 975 , 1344 ), ( 896 , 976 , 1344 ),
		        ( 1024 , 1114 , 1536 ), ( 1024 , 1115 , 1536 ), ( 1152 , 1253 , 1728 ), ( 1152 , 1254 , 1728 ),
		        ( 1280 , 1393 , 1920 ), ( 1280 , 1394 , 1920 ));
      AC3_SAMPLESPERFRAME = 1536;
      _SignatureChunk = $770B;
type
  TSyncBlock = packed record
    SignatureChunk, CRC: Word;
    Buff: array [1..3] of Byte;
  end;

  TAudioAC3 = object(TAudioInfo)
  private
  end;

function AudioAC3Reader(const AFileName: KOLstring; AudioInfo: TAC3AudioInfo): Boolean; forward;

function NewAudioAC3: TAC3AudioInfo;
begin
    New(Result, Create);
    Result.ResetData;
    with TAudioAC3(Result^) do begin
      FAudioVendor:= aAC3;
      FExistsProps:= [apSampleRate, apBitrate, apChannels, apBits, apDuration, apRatio];
      FReader:= AudioAC3Reader;
    end;
end;

function AudioAC3Reader(const AFileName: KOLstring; AudioInfo: TAC3AudioInfo): Boolean;
var Source: PStream;
    SyncBlock: TSyncBlock;
    frmsize: Integer;
begin
    with TAudioAC3(AudioInfo^) do begin
      Result := False;
      try
        ResetData;
        Source:= OpenFileRead(AFileName);
        try
          if (Source.Read(SyncBlock, SizeOf(TSyncBlock)) = SizeOf(TSyncBlock)) and
             (SyncBlock.SignatureChunk = _SignatureChunk) then begin

            FFileSize := Source.Size;
            FValid := TRUE;

            FSampleRate:= _SampleRates[(SyncBlock.Buff[1] and $C0) shr 6];
            FBitrate := _Birates[(SyncBlock.Buff[1] and $3F) shr 1];

            FChannels:= _Channels[(SyncBlock.Buff[3] and $E0) shr 5];

            frmsize:= _framesize[(SyncBlock.Buff[1] and $3F)][(SyncBlock.Buff[1] and $C0) shr 6] * 2;
            FBits:= 8 * Round((FChannels * AC3_SAMPLESPERFRAME)/frmsize);

            FDuration:= ((FFileSize - SizeOf(TSyncBlock)) * 8) / (1000 * FBitrate);
            FRatio:= (FFileSize - SizeOf(TSyncBlock)) / (FDuration * FSampleRate * (FChannels * FBits / 8) + 44) * 100;

            {$IFDEF USE_OtherAudioProps}
            OtherProps.Add('Version='+Int2Str((SyncBlock.Buff[2] and $F8) shr 3));
            {$ENDIF}
            Result := True;
          end;
        finally
          Source.free;
        end;
      except end;
    end;
end;

end.
