index 5f60a864bb726d8ed1a1ac9507e8e54de746301d..c49f376b574c01abe207f062ee934890884333c4 100644 (file)
*
* 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
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
(* 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;
(* 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
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
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
end;
end;
-function TMP3Loader.Load(FName: string; SStreaming: Boolean): Boolean;
+function TMP3Loader.Load(FName: string; Loop: Boolean): Boolean;
var
S: TStream = nil;
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;
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();
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