(* this file is a part of audio components suite v 2.3. copyright (c) 2002-2005 andrei borovsky. all rights reserved. see the license file for more details. you can contact me at mail@z0m3ie.de *) { $Log: acs_lame.pas,v $ Revision 1.5 2006/07/04 17:12:45 z0m3ie ACS 2.4 alt wiederhergestellt (unterschiedliche Sampleformate ...) Revision 1.2 2006/01/01 18:46:40 z0m3ie *** empty log message *** Revision 1.1 2005/12/19 18:36:38 z0m3ie *** empty log message *** Revision 1.6 2005/12/18 17:01:54 z0m3ie delphi compatibility Revision 1.5 2005/12/04 16:54:34 z0m3ie All classes are renamed, Style TACS... than T... to avoid conflicts with other components (eg TMixer is TACSMixer now) Revision 1.4 2005/11/28 21:57:24 z0m3ie mostly FileOut fixes moved PBuffer to PBuffer8 set all to dynamically Buffering Revision 1.3 2005/11/28 19:10:14 z0m3ie *** empty log message *** Revision 1.2 2005/09/13 04:04:50 z0m3ie First release without Components for Fileformats only TFileIn and TFileOut are Visible Revision 1.1 2005/09/12 22:04:52 z0m3ie modified structure again, fileformats are now in an sperat folder. all File In/Out classes are capsulated from TFileIn and TFileOut Revision 1.2 2005/08/22 20:17:01 z0m3ie changed Headers to log changed mail adress } unit acs_lame; {$ifdef fpc} {$mode delphi} {$endif} interface uses ACS_File,Classes, SysUtils, ACS_Classes, lame, {$IFDEF LINUX} baseunix; {$ENDIF} {$IFDEF WINDOWS} Windows; {$ENDIF} type TMP3Quality = (ql0, ql1, ql2, ql3, ql4, ql5, ql6, ql7, ql8, ql9); TMP3Mode = (STEREO = 0, JOINT_STEREO, DUAL_CHANNEL, // LAME doesn't supports this! MONO); TMP3SampleRate = (srDefault, sr32kHz, sr41kHz, sr48kHz); TMP3BitRate = (br8, br16, br24, br32, br40, br48, br56, br64, br80, br96, br112, br128, br144, br160, br192, br224, br256, br320); BOOL = Boolean; TMP3Out = class(TACSCustomFileOut) private FBitRate : TMP3BitRate; _plgf : PLame_global_flags; mp3buf : PByte; mp3buf_size : Integer; FTitle : String; FArtist : String; FAlbum : String; FYear : String; FTrack : String; FComment : String; FGenre : String; FCopyright: BOOL; FOriginal: BOOL; FEnableVBR: BOOL; FWriteVBRHeader: BOOL; FCRC: BOOL; FVBRQuality: TMP3Quality; FVBRMinBitrate: integer; FVBRMaxBitrate: integer; FQuality: TMP3Quality; FMode: TMP3Mode; FSampleRate: TMP3SampleRate; protected procedure Done; override; function DoOutput(Abort : Boolean):Boolean; override; procedure Prepare; override; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; published property BitRate : TMP3BitRate read FBitRate write FBitRate stored True; property Id3TagTitle : String read FTitle write FTitle; property Id3TagArtist : String read FArtist write FArtist; property Id3TagAlbum : String read FAlbum write FAlbum; property Id3TagYear : String read FYear write FYear; property Id3TagTrack : String read FTrack write FTrack; property Id3TagComment : String read FComment write FComment; property Id3TagGenre : String read FGenre write FGenre; property Quality : TMP3Quality read FQuality write FQuality default ql5; property SampleRate : TMP3SampleRate read FSampleRate write FSampleRate default srDefault; property Mode : TMP3Mode read FMode write FMode default STEREO; //Extras property CRC : BOOL read FCRC write FCRC default false; property Copyright : BOOL read FCopyright write FCopyright default false; property Original : BOOL read FOriginal write FOriginal default true; //VBR encoding property WriteVBRHeader : BOOL read FWriteVBRHeader write FWriteVBRHeader default false; property EnableVBR : BOOL read FEnableVBR write FEnableVBR default false; property VBRQuality : TMP3Quality read FVBRQuality write FVBRQuality default ql5; property VBRMinBitrate : integer read FVBRMinBitrate write FVBRMinBitrate default 128; property VBRMaxBitrate : integer read FVBRMaxBitrate write FVBRMaxBitrate default 192; end; implementation constructor TMP3Out.Create(AOwner: TComponent); begin inherited Create(AOwner); LoadLAME; FBitRate := br128; FBufferSize := $4000; FQuality := ql5; FSampleRate := srDefault; FMode := STEREO; FCRC := false; FCopyright := false; FOriginal := true; FWriteVBRHeader := false; FEnableVBR := false; FVBRQuality := ql5; FVBRMinBitrate := 128; FVBRMaxBitrate := 192; if not (csDesigning in ComponentState) then if not LameLoaded then raise EACSException.Create(LAME_PATH + ' library could not be loaded.'); end; destructor TMP3Out.Destroy; begin UnloadLAME; inherited Destroy; end; procedure TMP3Out.Prepare; var samples, br, tbr, sr, ql : Integer; begin GetMem(FBuffer,FBufferSize); if not FStreamAssigned then begin if FFileName = '' then raise EACSException.Create('File name is not assigned.'); FStream := TFileStream.Create(FFileName, fmCreate or fmShareExclusive, FAccessMask); end; FInput.Init; _plgf := lame_init; if FInput.Size > 0 then samples := FInput.Size div ((Finput.BitsPerSample shr 3)*Finput.Channels); lame_set_num_samples(_plgf, samples); lame_set_in_samplerate(_plgf, Finput.SampleRate); lame_set_num_channels(_plgf, 2); // not Finput.Channels see the note below case FBitRate of br8 : br := 8; br16 : br := 16; br24 : br := 24; br32 : br := 32; br40 : br := 40; br48 : br := 48; br56 : br := 56; br64 : br := 64; br80 : br := 80; br96 : br := 96; br112 : br := 112; br128 : br := 128; br144 : br := 144; br160 : br := 160; br192 : br := 192; br224 : br := 224; br256 : br := 256; br320 : br := 320; end; case FSampleRate of srDefault: sr := 0; sr32kHz: sr := 32000; sr41kHz: sr := 41000; sr48kHz: sr := 48000; end; lame_set_out_samplerate(_plgf,sr); { lame_set_mode(_plgf, Integer(FMode)); if FCopyright then lame_set_copyright(_plgf,1) else lame_set_copyright(_plgf,0); if FOriginal then lame_set_original(_plgf,1) else lame_set_original(_plgf,0); if FCRC then lame_set_error_protection(_plgf,1) else lame_set_error_protection(_plgf,0); if not EnableVBR then begin lame_set_brate(_plgf, br); case FQuality of ql0: ql:=0; ql1: ql:=1; ql2: ql:=2; ql3: ql:=3; ql4: ql:=4; ql5: ql:=5; ql6: ql:=6; ql7: ql:=7; ql8: ql:=8; ql9: ql:=9; end; lame_set_quality(_plgf,ql); end else begin if FWriteVBRHeader then lame_set_bWriteVbrTag(_plgf,1); lame_set_VBR(_plgf,2); case FVBRQuality of ql0: ql:=0; ql1: ql:=1; ql2: ql:=2; ql3: ql:=3; ql4: ql:=4; ql5: ql:=5; ql6: ql:=6; ql7: ql:=7; ql8: ql:=8; ql9: ql:=9; end; lame_set_VBR_q(_plgf,ql); if FVBRMinBitrate > FVBRMaxBitrate then begin tbr := FVBRMinBitrate; FVBRMinBitrate := FVBRMaxBitrate; FVBRMinBitrate := tbr; end; lame_set_VBR_min_bitrate_kbps(_plgf,FVBRMinBitrate); lame_set_VBR_max_bitrate_kbps(_plgf,FVBRMaxBitrate); end; } lame_init_params(_plgf); mp3buf_size := (FBufferSize shr 1) + (FBufferSize shr 3) + 7200; GetMem(mp3buf, mp3buf_size); end; procedure TMP3Out.Done; var res : Integer; begin id3tag_init(_plgf); id3tag_set_title(_plgf, PChar(FTitle)); id3tag_set_artist(_plgf, PChar(FArtist)); id3tag_set_album(_plgf, PChar(FAlbum)); id3tag_set_year(_plgf, PChar(FYear)); id3tag_set_track(_plgf, PChar(FTrack)); id3tag_set_comment(_plgf, PChar(FComment)); id3tag_set_genre(_plgf, PChar(FGenre)); res := lame_encode_flush(_plgf, mp3buf, mp3buf_size); FStream.Write(mp3buf^, res); if not FStreamAssigned then FStream.Free; lame_close(_plgf); FreeMem(mp3buf); FInput.Flush; FreeMem(FBuffer); end; function TMP3Out.DoOutput(Abort : Boolean):Boolean; var Len, res, ns : Integer; begin // No exceptions Here Result := True; if not CanOutput then Exit; if Abort then begin Result := False; Exit; end; while InputLock do; InputLock := True; Len := Finput.GetData(@FBuffer, FBufferSize); InputLock := False; if Len <> 0 then begin if FInput.Channels = 2 then begin ns := Len shr 2; res := lame_encode_buffer_interleaved(_plgf, @FBuffer, ns, mp3buf, mp3buf_size); end else begin (* If the input stream is mono we turn it into stereo here. This is the way to bypass some pour performance on mono streams, maybe not the best way, but for a while ...*) ns := Len shr 1; res := lame_encode_buffer(_plgf, @FBuffer, @FBuffer, ns, mp3buf, mp3buf_size); end; if res < 0 then begin Result := False; Exit; end; FStream.Write(mp3buf^, res); end else begin Result := False; Exit; end; end; initialization FileFormats.Add('mp3','Mpeg Layer III',TMP3Out); end.