220fbd27f1dd681bfe0ff7bd66e3d28e7f063201
1 (* Copyright (C) Doom 2D: Forever Developers
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 {$INCLUDE ../shared/a_modes.inc}
21 uses e_soundfile
, vorbis
, classes
;
26 TOGGLoader
= class (TSoundLoader
)
28 function Load(Data
: Pointer; Len
: LongWord; SStreaming
: Boolean): Boolean; override; overload
;
29 function Load(FName
: string; SStreaming
: Boolean): Boolean; override; overload
;
30 function SetPosition(Pos
: LongWord): Boolean; override;
31 function FillBuffer(Buf
: Pointer; Len
: LongWord): LongWord; override;
32 function GetAll(var OutPtr
: Pointer): LongWord; override;
33 procedure Free(); override;
42 function LoadStream(Stream
: TStream
; SStreaming
: Boolean): Boolean;
43 function LoadEntireStream(): Pointer;
46 TOGGLoaderFactory
= class (TSoundLoaderFactory
)
48 function MatchHeader(Data
: Pointer; Len
: LongWord): Boolean; override;
49 function MatchExtension(FName
: string): Boolean; override;
50 function GetLoader(): TSoundLoader
; override;
55 uses sysutils
, utils
, e_log
, xstreams
, ogg
, ctypes
;
57 (* Reader functions for ov_callbacks *)
59 function streamSeek(h
: Pointer; off
: ogg_int64_t
; whence
: cint
): cint
; cdecl;
68 0: s
.Seek(off
, soBeginning
); // SEEK_SET
69 1: s
.Seek(off
, soCurrent
); // SEEK_CUR
70 2: s
.Seek(off
, soEnd
); // SEEK_END
78 function streamRead(buf
: Pointer; sz
, nmemb
: csize_t
; h
: Pointer): csize_t
; cdecl;
86 Result
:= S
.Read(buf
^, sz
*nmemb
) div sz
;
92 function streamTell(h
: Pointer): clong
; cdecl;
103 oggIO
: ov_callbacks
= (
106 close
: nil; // the loader's gonna handle that
110 (* TOGGLoaderFactory *)
112 function TOGGLoaderFactory
.MatchHeader(Data
: Pointer; Len
: LongWord): Boolean;
114 OGG_HEADER
= $5367674F; // 'OggS'
116 if Len
< 27 then // header is at least 27 bytes
121 Result
:= (PLongWord(Data
)^ = OGG_HEADER
);
124 function TOGGLoaderFactory
.MatchExtension(FName
: string): Boolean;
126 Result
:= GetFilenameExt(FName
) = '.ogg';
129 function TOGGLoaderFactory
.GetLoader(): TSoundLoader
;
131 Result
:= TOGGLoader
.Create();
136 function TOGGLoader
.LoadEntireStream(): Pointer;
138 Samples
: ogg_int64_t
;
143 Samples
:= ov_pcm_total(FOgg
, -1);
144 if Samples
< 0 then Exit
;
146 FTotal
:= Samples
* 2 * FFormat
.Channels
;
147 Result
:= GetMem(FTotal
);
148 if Result
= nil then Exit
;
150 Ret
:= ov_read_ext(FOgg
, Result
, FTotal
, False, 2, True);
160 function TOGGLoader
.LoadStream(Stream
: TStream
; SStreaming
: Boolean): Boolean;
168 Ret
:= ov_open_callbacks(Stream
, FOgg
, nil, 0, oggIO
);
171 e_LogWriteln('OGG: Load(Data) failed: ov_open_callbacks failed');
175 Info
:= ov_info(FOgg
, -1);
178 e_LogWriteln('OGG: Load(Data) failed: ov_info returned NULL');
183 FFormat
.SampleRate
:= Info
^.rate
;
184 FFormat
.Channels
:= Info
^.channels
;
185 FFormat
.SampleBits
:= 16;
187 if not SStreaming
then
189 FullBuf
:= LoadEntireStream();
191 if FullBuf
= nil then
193 e_LogWriteln('OGG: Load(Data) failed: couldn''t allocate for non-streaming chunk');
212 FStreaming
:= SStreaming
;
216 function TOGGLoader
.Load(Data
: Pointer; Len
: LongWord; SStreaming
: Boolean): Boolean;
222 // TODO: have to make a dupe here because Data gets deallocated after loading
223 // this is obviously very shit
225 if FBuf
= nil then Exit
;
226 Move(Data
^, FBuf
^, Len
);
228 S
:= TSFSMemoryStreamRO
.Create(FBuf
, Len
{, True});
229 Result
:= LoadStream(S
, SStreaming
);
231 if not Result
and (S
<> nil) then
239 function TOGGLoader
.Load(FName
: string; SStreaming
: Boolean): Boolean;
246 S
:= openDiskFileRO(FName
);
247 Result
:= LoadStream(S
, SStreaming
);
250 e_LogWritefln('OGG: ERROR: could not read file `%s`: %s', [FName
, E
.Message]);
253 if not Result
and (S
<> nil) then
257 function TOGGLoader
.SetPosition(Pos
: LongWord): Boolean;
260 if not FOpen
or (ov_seekable(FOgg
) = 0) then Exit
;
261 Result
:= ov_pcm_seek(FOgg
, Pos
) = 0;
264 function TOGGLoader
.FillBuffer(Buf
: Pointer; Len
: LongWord): LongWord;
269 if not FOpen
or not FStreaming
then Exit
;
270 Ret
:= ov_read_ext(FOgg
, Buf
, Len
, False, 2, True);
271 if Ret
< 0 then Exit
;
275 function TOGGLoader
.GetAll(var OutPtr
: Pointer): LongWord;
278 if FStreaming
or (FTotal
= 0) then Exit
;
283 procedure TOGGLoader
.Free();
299 e_AddSoundLoader(TOGGLoaderFactory
.Create());