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, version 3 of the License ONLY.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 {$INCLUDE ../shared/a_modes.inc}
16 unit e_soundfile_opus
;
20 uses e_soundfile
, opus
, classes
;
25 TOpusLoader
= class (TSoundLoader
)
27 function Load(Data
: Pointer; Len
: LongWord; SStreaming
: Boolean): Boolean; override; overload
;
28 function Load(FName
: string; SStreaming
: Boolean): Boolean; override; overload
;
29 function SetPosition(Pos
: LongWord): Boolean; override;
30 function FillBuffer(Buf
: Pointer; Len
: LongWord): LongWord; override;
31 function GetAll(var OutPtr
: Pointer): LongWord; override;
32 procedure Free(); override;
38 TOpusLoaderFactory
= class (TSoundLoaderFactory
)
40 function MatchHeader(Data
: Pointer; Len
: LongWord): Boolean; override;
41 function MatchExtension(FName
: string): Boolean; override;
42 function GetLoader(): TSoundLoader
; override;
47 uses sysutils
, utils
, e_log
, xstreams
, ogg
, ctypes
;
49 function TOpusLoaderFactory
.MatchHeader(Data
: Pointer; Len
: LongWord): Boolean;
51 OGG_HEADER
= $5367674F; // 'OggS'
53 F
: POggOpusFile
= nil;
57 if Len
< 27 then // header is at least 27 bytes
59 if PLongWord(Data
)^ <> OGG_HEADER
then
62 // now we gotta check that this is indeed an opus file and not a vorbis file
64 F
:= op_test_memory(Data
, Len
, nil);
66 if Result
then op_free(F
);
69 function TOpusLoaderFactory
.MatchExtension(FName
: string): Boolean;
71 Result
:= GetFilenameExt(FName
) = '.opus';
74 function TOpusLoaderFactory
.GetLoader(): TSoundLoader
;
76 Result
:= TOpusLoader
.Create();
81 function TOpusLoader
.Load(Data
: Pointer; Len
: LongWord; SStreaming
: Boolean): Boolean;
88 e_LogWriteln('Opus: Load(Data) failed: out of memory on copy');
91 Move(Data
^, FBuf
^, Len
);
93 FOpus
:= op_open_memory(FBuf
, Len
, nil);
97 e_LogWriteln('Opus: Load(Data) failed: op_open_memory failed');
101 FFormat
.Channels
:= 2; // we use ov_read_stereo
102 FFormat
.SampleBits
:= 16;
103 FFormat
.SampleRate
:= 48000; // is this even correct?
104 FStreaming
:= True; // opus is always streaming
109 function TOpusLoader
.Load(FName
: string; SStreaming
: Boolean): Boolean;
113 FOpus
:= op_open_file(PChar(FName
), nil);
116 e_LogWritefln('Opus: Load(%s) failed: op_open_file failed', [FName
]);
120 FFormat
.Channels
:= 2; // we use ov_read_stereo
121 FFormat
.SampleBits
:= 16;
122 FFormat
.SampleRate
:= 48000; // is this even correct?
123 FStreaming
:= True; // opus is always streaming
128 function TOpusLoader
.SetPosition(Pos
: LongWord): Boolean;
131 if (FOpus
= nil) or (op_seekable(FOpus
) = 0) then Exit
;
132 Result
:= op_pcm_seek(FOpus
, Pos
) = 0;
135 function TOpusLoader
.FillBuffer(Buf
: Pointer; Len
: LongWord): LongWord;
141 if FOpus
= nil then Exit
;
147 Ret
:= op_read_stereo(FOpus
, Buf
+ Rx
, (Len
- Rx
) div 2);
148 if Ret
= OP_HOLE
then continue
;
149 if Ret
< 0 then break
;
150 if FLooping
and (Ret
= 0) then op_pcm_seek(FOpus
, 0); // loop
157 function TOpusLoader
.GetAll(var OutPtr
: Pointer): LongWord;
159 Result
:= 0; // always streaming
162 procedure TOpusLoader
.Free();
174 e_AddSoundLoader(TOpusLoaderFactory
.Create());