X-Git-Url: https://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fengine%2Fe_soundfile_mp3.pas;h=c49f376b574c01abe207f062ee934890884333c4;hb=9193a04898bdd4020400c8acd8b1bcaccbe33dbf;hp=5f60a864bb726d8ed1a1ac9507e8e54de746301d;hpb=a4b97dbff3c995c7dda7fcfd5fc61e0aa19e7547;p=d2df-sdl.git diff --git a/src/engine/e_soundfile_mp3.pas b/src/engine/e_soundfile_mp3.pas index 5f60a86..c49f376 100644 --- a/src/engine/e_soundfile_mp3.pas +++ b/src/engine/e_soundfile_mp3.pas @@ -2,8 +2,7 @@ * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * the Free Software Foundation, version 3 of the License ONLY. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -25,32 +24,29 @@ type TMP3Loader = class (TSoundLoader) public - function Load(Data: Pointer; Len: LongWord; SStreaming: Boolean): Boolean; override; overload; - function Load(FName: string; SStreaming: Boolean): Boolean; override; overload; - function SetPosition(Pos: LongWord): Boolean; override; + function Load(Data: Pointer; Len: LongWord; Loop: Boolean): Boolean; override; overload; + function Load(FName: string; Loop: Boolean): Boolean; override; overload; + function Finished(): Boolean; override; + function Restart(): Boolean; override; function FillBuffer(Buf: Pointer; Len: LongWord): LongWord; override; - function GetAll(var OutPtr: Pointer): LongWord; override; procedure Free(); override; private FMPG: pmpg123_handle; FData: TStream; FBuf: Pointer; - FAllSamples: Pointer; FOpen: Boolean; + FFinished: Boolean; + FLooping: Boolean; - function LoadStream(Stream: TStream; SStreaming: Boolean): Boolean; + function LoadStream(Stream: TStream): Boolean; end; TMP3LoaderFactory = class (TSoundLoaderFactory) public - constructor Create(); - destructor Destroy(); override; function MatchHeader(Data: Pointer; Len: LongWord): Boolean; override; function MatchExtension(FName: string): Boolean; override; function GetLoader(): TSoundLoader; override; - private - FMPG: pmpg123_handle; // tester context end; implementation @@ -89,49 +85,43 @@ end; (* TMP3LoaderFactory *) -constructor TMP3LoaderFactory.Create(); -begin - FMPG := mpg123_new(nil, nil); - if FMPG <> nil then - mpg123_replace_reader_handle(FMPG, streamRead, streamLSeek, nil); -end; - -destructor TMP3LoaderFactory.Destroy(); -begin - if FMPG <> nil then mpg123_delete(FMPG); -end; function TMP3LoaderFactory.MatchHeader(Data: Pointer; Len: LongWord): Boolean; var - ID3: array [0..9] of Byte; - HeaderLen: LongInt; - S: TSFSMemoryStreamRO; - Info: mpg123_frameinfo; + P: PByte; + N: LongInt; begin Result := False; - if Len < 10 then Exit; + if Len < 10 then Exit; // way too short even without an ID3 + + P := PByte(Data); - // try and check for an ID3 header - Move(Data^, ID3, 10); - if (ID3[0] = Ord('I')) and (ID3[1] = Ord('D')) and (ID3[2] = Ord('3')) then + // try to check for an ID3v2 header + if ((P+0)^ = $49) and ((P+1)^ = $44) and ((P+2)^ = $33) then // 'ID3' begin - HeaderLen := ID3[9] + (ID3[8] shl 7) + (ID3[7] shl 14) + (ID3[6] shl 21); - Result := Len > (HeaderLen + 10); + N := (P+9)^ + ((P+8)^ shl 7) + ((P+7)^ shl 14) + ((P+6)^ shl 21); + Result := Len > (N + 10); if Result then Exit; end; - // if there isn't one, employ heavier shit - if FMPG = nil then Exit; - - S := TSFSMemoryStreamRO.Create(Data, Len); - - if mpg123_open_handle(FMPG, S) = MPG123_OK then + // try to read the frame sync word, bits 0-10 should be 1 + if ((P+0)^ = $FF) and (((P+1)^ and $E0) = $E0) then begin - Result := mpg123_info(FMPG, @Info) = MPG123_OK; - mpg123_close(FMPG); + // bits 11-12: mpeg version, can't be 01 + if (((P+1)^ and $10) = 0) and (((P+1)^ and $08) = $08) then + Exit; + // bits 13-14: layer: can't be 00 + if ((P+1)^ and $06) = 0 then + Exit; + // bits 16-19: bitrate index: can't be 1111 or 0000 + if (((P+2)^ and $F0) = 0) or (((P+2)^ and $F0) = $F0) then + Exit; + // bits 20-21: samplerate index: can't be 11 + if ((P+2)^ and $0C) = $0C then + Exit; + // this is probably an MP3 then + Result := True; end; - - S.Destroy(); end; function TMP3LoaderFactory.MatchExtension(FName: string): Boolean; @@ -149,9 +139,10 @@ end; (* TMP3Loader *) -function TMP3Loader.LoadStream(Stream: TStream; SStreaming: Boolean): Boolean; +function TMP3Loader.LoadStream(Stream: TStream): Boolean; var - SRate, SEnc, SChans: LongInt; + SRate: clong; + SEnc, SChans: LongInt; begin FMPG := mpg123_new(nil, nil); if FMPG = nil then @@ -192,12 +183,13 @@ begin FFormat.SampleRate := SRate; FFormat.SampleBits := 16; FFormat.Channels := SChans; - FStreaming := SStreaming; + FStreaming := True; + FFinished := False; Result := True; end; -function TMP3Loader.Load(Data: Pointer; Len: LongWord; SStreaming: Boolean): Boolean; +function TMP3Loader.Load(Data: Pointer; Len: LongWord; Loop: Boolean): Boolean; var S: TStream; begin @@ -210,7 +202,8 @@ begin Move(Data^, FBuf^, Len); S := TSFSMemoryStreamRO.Create(FBuf, Len{, True}); - Result := LoadStream(S, SStreaming); + Result := LoadStream(S); + FLooping := Loop; if not Result and (S <> nil) then begin @@ -220,7 +213,7 @@ begin end; end; -function TMP3Loader.Load(FName: string; SStreaming: Boolean): Boolean; +function TMP3Loader.Load(FName: string; Loop: Boolean): Boolean; var S: TStream = nil; begin @@ -228,21 +221,28 @@ begin try S := openDiskFileRO(FName); - Result := LoadStream(S, SStreaming); + Result := LoadStream(S); + FLooping := Loop; except on E: Exception do - e_LogWritefln('ModPlug: ERROR: could not read file `%s`: %s', [FName, E.Message]); + e_LogWritefln('MPG123: ERROR: could not read file `%s`: %s', [FName, E.Message]); end; if not Result and (S <> nil) then S.Destroy(); end; -function TMP3Loader.SetPosition(Pos: LongWord): Boolean; +function TMP3Loader.Finished(): Boolean; +begin + Result := FFinished; +end; + +function TMP3Loader.Restart(): Boolean; begin Result := False; if FMPG = nil then Exit; - Result := mpg123_seek(FMPG, Pos, 0) = MPG123_OK; + FFinished := False; + Result := mpg123_seek(FMPG, 0, 0) = MPG123_OK; end; function TMP3Loader.FillBuffer(Buf: Pointer; Len: LongWord): LongWord; @@ -253,18 +253,19 @@ begin Result := 0; Got := 0; if FMPG = nil then Exit; + Ret := mpg123_read(FMPG, Buf, Len, @Got); - if FLooping and (Ret = MPG123_DONE) then - mpg123_seek(FMPG, 0, 0); // loop - Result := Got; -end; -function TMP3Loader.GetAll(var OutPtr: Pointer): LongWord; -begin - Result := 0; - if FMPG = nil then Exit; - if FStreaming then Exit; - // TODO + if (Ret = MPG123_DONE) or (Got = 0) then + begin + if FLooping then + Ret := mpg123_seek(FMPG, 0, 0) // loop + else + FFinished := True; + end; + + if (Ret = MPG123_OK) or FFinished then + Result := Got; end; procedure TMP3Loader.Free(); @@ -273,12 +274,12 @@ begin if FMPG <> nil then mpg123_delete(FMPG); if FData <> nil then FData.Destroy(); if FBuf <> nil then FreeMem(FBuf); - if FAllSamples <> nil then FreeMem(FAllSamples); FOpen := False; + FFinished := False; + FLooping := False; FMPG := nil; FData := nil; FBuf := nil; - FAllSamples := nil; end; initialization