DEADSOFTWARE

Sound: OpenAL: Add Opus support
authorfgsfds <pvt.fgsfds@gmail.com>
Tue, 3 Sep 2019 17:13:38 +0000 (20:13 +0300)
committerfgsfds <pvt.fgsfds@gmail.com>
Tue, 3 Sep 2019 17:13:38 +0000 (20:13 +0300)
src/engine/e_soundfile_opus.pas [new file with mode: 0644]
src/engine/e_soundfile_vorbis.pas [moved from src/engine/e_soundfile_ogg.pas with 79% similarity]
src/game/Doom2DF.lpr
src/lib/opus/opus.pas [new file with mode: 0644]
src/lib/vorbis/ogg.pas

diff --git a/src/engine/e_soundfile_opus.pas b/src/engine/e_soundfile_opus.pas
new file mode 100644 (file)
index 0000000..6a73609
--- /dev/null
@@ -0,0 +1,176 @@
+(* Copyright (C)  Doom 2D: Forever Developers
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *)
+{$INCLUDE ../shared/a_modes.inc}
+unit e_soundfile_opus;
+
+interface
+
+uses e_soundfile, opus, classes;
+
+type
+  // Opus loader
+
+  TOpusLoader = 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 FillBuffer(Buf: Pointer; Len: LongWord): LongWord; override;
+    function GetAll(var OutPtr: Pointer): LongWord; override;
+    procedure Free(); override;
+  private
+    FOpus: POggOpusFile;
+    FBuf: Pointer;
+  end;
+
+  TOpusLoaderFactory = class (TSoundLoaderFactory)
+  public
+    function MatchHeader(Data: Pointer; Len: LongWord): Boolean; override;
+    function MatchExtension(FName: string): Boolean; override;
+    function GetLoader(): TSoundLoader; override;
+  end;
+
+implementation
+
+uses sysutils, utils, e_log, xstreams, ogg, ctypes;
+
+function TOpusLoaderFactory.MatchHeader(Data: Pointer; Len: LongWord): Boolean;
+const
+  OGG_HEADER = $5367674F; // 'OggS'
+var
+  F: POggOpusFile = nil;
+begin
+  Result := False;
+
+  if Len < 27 then // header is at least 27 bytes
+    Exit;
+  if PLongWord(Data)^ <> OGG_HEADER then
+    Exit;
+
+  // now we gotta check that this is indeed an opus file and not a vorbis file
+
+  F := op_test_memory(Data, Len, nil);
+  Result := F <> nil;
+  if Result then op_free(F);
+end;
+
+function TOpusLoaderFactory.MatchExtension(FName: string): Boolean;
+begin
+  Result := GetFilenameExt(FName) = '.opus';
+end;
+
+function TOpusLoaderFactory.GetLoader(): TSoundLoader;
+begin
+  Result := TOpusLoader.Create();
+end;
+
+(* TOpusLoader *)
+
+function TOpusLoader.Load(Data: Pointer; Len: LongWord; SStreaming: Boolean): Boolean;
+begin
+  Result := False;
+
+  FBuf := GetMem(Len);
+  if FBuf = nil then
+  begin
+    e_LogWriteln('Opus: Load(Data) failed: out of memory on copy');
+    Exit;
+  end;
+  Move(Data^, FBuf^, Len);
+
+  FOpus := op_open_memory(FBuf, Len, nil);
+  if FOpus = nil then
+  begin
+    Free();
+    e_LogWriteln('Opus: Load(Data) failed: op_open_memory failed');
+    Exit;
+  end;
+
+  FFormat.Channels := 2; // we use ov_read_stereo
+  FFormat.SampleBits := 16;
+  FFormat.SampleRate := 48000; // is this even correct?
+  FStreaming := True; // opus is always streaming
+
+  Result := True;
+end;
+
+function TOpusLoader.Load(FName: string; SStreaming: Boolean): Boolean;
+begin
+  Result := False;
+
+  FOpus := op_open_file(PChar(FName), nil);
+  if FOpus = nil then
+  begin
+    e_LogWritefln('Opus: Load(%s) failed: op_open_file failed', [FName]);
+    Exit;
+  end;
+
+  FFormat.Channels := 2; // we use ov_read_stereo
+  FFormat.SampleBits := 16;
+  FFormat.SampleRate := 48000; // is this even correct?
+  FStreaming := True; // opus is always streaming
+
+  Result := True;
+end;
+
+function TOpusLoader.SetPosition(Pos: LongWord): Boolean;
+begin
+  Result := False;
+  if (FOpus = nil) or (op_seekable(FOpus) = 0) then Exit;
+  Result := op_pcm_seek(FOpus, Pos) = 0;
+end;
+
+function TOpusLoader.FillBuffer(Buf: Pointer; Len: LongWord): LongWord;
+var
+  Ret: cint;
+  Rx: Integer;
+begin
+  Result := 0;
+  if FOpus = nil then Exit;
+
+  Rx := 0;
+
+  while Rx < Len do
+  begin
+    Ret := op_read_stereo(FOpus, Buf + Rx, (Len - Rx) div 2);
+    if Ret = OP_HOLE then continue;
+    if Ret < 0 then break;
+    if FLooping and (Ret = 0) then op_pcm_seek(FOpus, 0); // loop
+    Rx := Rx + Ret * 4;
+  end;
+
+  Result := Rx;
+end;
+
+function TOpusLoader.GetAll(var OutPtr: Pointer): LongWord;
+begin
+  Result := 0; // always streaming
+end;
+
+procedure TOpusLoader.Free();
+begin
+  if FOpus <> nil then
+    op_free(FOpus);
+  if FBuf <> nil then
+    FreeMem(FBuf);
+  FOpus := nil;
+  FBuf := nil;
+  FStreaming := False;
+end;
+
+initialization
+  e_AddSoundLoader(TOpusLoaderFactory.Create());
+end.
similarity index 79%
rename from src/engine/e_soundfile_ogg.pas
rename to src/engine/e_soundfile_vorbis.pas
index 220fbd27f1dd681bfe0ff7bd66e3d28e7f063201..1c237c132413e3e363948df6d39317ad92e15a43 100644 (file)
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *)
 {$INCLUDE ../shared/a_modes.inc}
-unit e_soundfile_ogg;
+unit e_soundfile_vorbis;
 
 interface
 
 uses e_soundfile, vorbis, classes;
 
 type
-  // OGG Vorbis loader
+  // Ogg Vorbis loader
 
-  TOGGLoader = class (TSoundLoader)
+  TVorbisLoader = class (TSoundLoader)
   public
     function Load(Data: Pointer; Len: LongWord; SStreaming: Boolean): Boolean; override; overload;
     function Load(FName: string; SStreaming: Boolean): Boolean; override; overload;
@@ -43,7 +43,7 @@ type
     function LoadEntireStream(): Pointer;
   end;
 
-  TOGGLoaderFactory = class (TSoundLoaderFactory)
+  TVorbisLoaderFactory = class (TSoundLoaderFactory)
   public
     function MatchHeader(Data: Pointer; Len: LongWord): Boolean; override;
     function MatchExtension(FName: string): Boolean; override;
@@ -107,33 +107,43 @@ var
     tell:        streamTell;
   );
 
-(* TOGGLoaderFactory *)
+(* TVorbisLoaderFactory *)
 
-function TOGGLoaderFactory.MatchHeader(Data: Pointer; Len: LongWord): Boolean;
+function TVorbisLoaderFactory.MatchHeader(Data: Pointer; Len: LongWord): Boolean;
 const
   OGG_HEADER = $5367674F; // 'OggS'
+var
+  S: TStream;
+  F: OggVorbis_File;
 begin
+  Result := False;
+
   if Len < 27 then // header is at least 27 bytes
-  begin
-    Result := False;
-    exit;
-  end;
-  Result := (PLongWord(Data)^ = OGG_HEADER);
+    Exit;
+  if PLongWord(Data)^ <> OGG_HEADER then
+    Exit;
+
+  // now we gotta check that this is indeed a vorbis file and not an opus file
+
+  S := TSFSMemoryStreamRO.Create(Data, Len);
+  Result := ov_test_callbacks(S, F, nil, 0, oggIO) = 0;
+  if Result then ov_clear(F);
+  S.Free();
 end;
 
-function TOGGLoaderFactory.MatchExtension(FName: string): Boolean;
+function TVorbisLoaderFactory.MatchExtension(FName: string): Boolean;
 begin
   Result := GetFilenameExt(FName) = '.ogg';
 end;
 
-function TOGGLoaderFactory.GetLoader(): TSoundLoader;
+function TVorbisLoaderFactory.GetLoader(): TSoundLoader;
 begin
-  Result := TOGGLoader.Create();
+  Result := TVorbisLoader.Create();
 end;
 
-(* TOGGLoader *)
+(* TVorbisLoader *)
 
-function TOGGLoader.LoadEntireStream(): Pointer;
+function TVorbisLoader.LoadEntireStream(): Pointer;
 var
   Samples: ogg_int64_t;
   Ret: clong;
@@ -157,7 +167,7 @@ begin
     FTotal := Ret;
 end;
 
-function TOGGLoader.LoadStream(Stream: TStream; SStreaming: Boolean): Boolean;
+function TVorbisLoader.LoadStream(Stream: TStream; SStreaming: Boolean): Boolean;
 var
   Ret, Bit: clong;
   Info: pvorbis_info;
@@ -197,7 +207,7 @@ begin
     end;
 
     ov_clear(FOgg);
-    Stream.Destroy();
+    Stream.Free();
 
     FreeMem(FBuf);
     FBuf := FullBuf;
@@ -213,7 +223,7 @@ begin
   Result := True;
 end;
 
-function TOGGLoader.Load(Data: Pointer; Len: LongWord; SStreaming: Boolean): Boolean;
+function TVorbisLoader.Load(Data: Pointer; Len: LongWord; SStreaming: Boolean): Boolean;
 var
   S: TStream;
 begin
@@ -230,13 +240,13 @@ begin
 
   if not Result and (S <> nil) then
   begin
-    S.Destroy();
+    S.Free();
     FreeMem(FBuf);
     FBuf := nil;
   end;
 end;
 
-function TOGGLoader.Load(FName: string; SStreaming: Boolean): Boolean;
+function TVorbisLoader.Load(FName: string; SStreaming: Boolean): Boolean;
 var
   S: TStream = nil;
 begin
@@ -251,17 +261,17 @@ begin
   end;
 
   if not Result and (S <> nil) then
-    S.Destroy();
+    S.Free();
 end;
 
-function TOGGLoader.SetPosition(Pos: LongWord): Boolean;
+function TVorbisLoader.SetPosition(Pos: LongWord): Boolean;
 begin
   Result := False;
   if not FOpen or (ov_seekable(FOgg) = 0) then Exit;
   Result := ov_pcm_seek(FOgg, Pos) = 0;
 end;
 
-function TOGGLoader.FillBuffer(Buf: Pointer; Len: LongWord): LongWord;
+function TVorbisLoader.FillBuffer(Buf: Pointer; Len: LongWord): LongWord;
 var
   Ret: clong;
 begin
@@ -269,10 +279,12 @@ begin
   if not FOpen or not FStreaming then Exit;
   Ret := ov_read_ext(FOgg, Buf, Len, False, 2, True);
   if Ret < 0 then Exit;
+  if FLooping and (Ret = 0) then
+    ov_pcm_seek(FOgg, 0);
   Result := Ret; 
 end;
 
-function TOGGLoader.GetAll(var OutPtr: Pointer): LongWord;
+function TVorbisLoader.GetAll(var OutPtr: Pointer): LongWord;
 begin
   Result := 0;
   if FStreaming or (FTotal = 0) then Exit;
@@ -280,12 +292,12 @@ begin
   OutPtr := FBuf;
 end;
 
-procedure TOGGLoader.Free();
+procedure TVorbisLoader.Free();
 begin
   if FOpen then
     ov_clear(FOgg);
   if FData <> nil then
-    FData.Destroy();
+    FData.Free();
   if FBuf <> nil then
     FreeMem(FBuf);
   FData := nil;
@@ -296,5 +308,5 @@ begin
 end;
 
 initialization
-  e_AddSoundLoader(TOGGLoaderFactory.Create());
+  e_AddSoundLoader(TVorbisLoaderFactory.Create());
 end.
index 0e7d21877ce2ee6ffa2867fdc7b1d8da3bda1807..834de4eb23b2de64b8fae90d328f0bf7c9339afe 100644 (file)
@@ -65,8 +65,7 @@ uses
   e_soundfile_wav in '../engine/e_soundfile_wav.pas',
   {$IFDEF USE_VORBIS}
     vorbis in '../lib/vorbis/vorbis.pas',
-    ogg in '../lib/vorbis/ogg.pas',
-    e_soundfile_ogg in '../engine/e_soundfile_ogg.pas',
+    e_soundfile_vorbis in '../engine/e_soundfile_vorbis.pas',
   {$ENDIF}
   {$IFDEF USE_FLUIDSYNTH}
     fluidsynth in '../lib/fluidsynth/fluidsynth.pas',
@@ -84,6 +83,13 @@ uses
     mpg123 in '../lib/mpg123/mpg123.pas',
     e_soundfile_mp3 in '../engine/e_soundfile_mp3.pas',
   {$ENDIF}
+  {$IFDEF USE_OPUS}
+    opus in '../lib/opus/opus.pas',
+    e_soundfile_opus in '../engine/e_soundfile_opus.pas',
+  {$ENDIF}
+  {$IF DEFINED(USE_VORBIS) OR DEFINED(USE_OPUS)}
+    ogg in '../lib/vorbis/ogg.pas', // this has to come last because link order
+  {$ENDIF}
 {$ENDIF}
   ENet in '../lib/enet/enet.pp',
   e_graphics in '../engine/e_graphics.pas',
diff --git a/src/lib/opus/opus.pas b/src/lib/opus/opus.pas
new file mode 100644 (file)
index 0000000..b236e47
--- /dev/null
@@ -0,0 +1,174 @@
+unit opus;
+
+{$MODE OBJFPC}{$H+}
+{$PACKRECORDS C}
+{$MINENUMSIZE 4}
+
+interface
+
+uses
+  CTypes, SysUtils, ogg;
+
+{$IF DEFINED(WINDOWS)}
+  {$IFDEF OPUS_WINDOZE_STATIC}
+    {$LINKLIB libopusfile.a}
+    {$LINKLIB libopus.a}
+  {$ELSE}
+    {$DEFINE OPUS_DYNAMIC}
+    const opuslib = 'libopus-0.dll';
+    const opusfilelib = 'libopusfile-0.dll';
+  {$ENDIF}
+{$ELSEIF DEFINED(UNIX)}
+  {$DEFINE OPUS_DYNAMIC}
+  const opuslib = 'libopus.so';
+  const opusfilelib = 'libopusfile.so';
+{$ELSE}
+  {$ERROR libopus not supported on this platform. Fix it!}
+{$ENDIF}
+
+const
+  OP_FALSE = -1;
+  OP_HOLE = -3;
+  OP_EREAD = -128;
+  OP_EFAULT = -129;
+  OP_EIMPL = -130;
+  OP_EINVAL = -131;
+  OP_ENOTVORBIS = -132;
+  OP_EBADHEADER = -133;
+  OP_EVERSION = -134;
+  OP_ENOTAUDIO = -135;
+  OP_EBADPACKET = -136;
+  OP_EBADLINK = -137;
+  OP_ENOSEEK = -138;
+  OP_EBADTIMESTAMP = -139;
+
+const
+  OPUS_OK = 0;
+  OPUS_BAD_ARG = -1;
+  OPUS_BUFFER_TOO_SMALL = -2;
+  OPUS_INTERNAL_ERROR = -3;
+  OPUS_INVALID_PACKET = -4;
+  OPUS_UNIMPLEMENTED = -5;
+  OPUS_INVALID_STATE = -6;
+  OPUS_ALLOC_FAIL = -7;
+
+  OPUS_APPLICATION_VOIP = 2048;
+  OPUS_APPLICATION_AUDIO = 2049;
+  OPUS_APPLICATION_RESTRICTED_LOWDELAY = 2051;
+
+  OPUS_SIGNAL_VOICE = 3001; // Signal being encoded is voice
+  OPUS_SIGNAL_MUSIC = 3002; // Signal being encoded is music
+
+  OPUS_BANDWIDTH_NARROWBAND = 1101; // 4 kHz bandpass @hideinitializer
+  OPUS_BANDWIDTH_MEDIUMBAND = 1102; // 6 kHz bandpass @hideinitializer
+  OPUS_BANDWIDTH_WIDEBAND = 1103;  // 8 kHz bandpass @hideinitializer
+  OPUS_BANDWIDTH_SUPERWIDEBAND = 1104; // 12 kHz bandpass @hideinitializer
+  OPUS_BANDWIDTH_FULLBAND = 1105; // 20 kHz bandpass @hideinitializer
+
+  OPUS_FRAMESIZE_ARG = 5000; // Select frame size from the argument (default)
+  OPUS_FRAMESIZE_2_5_MS = 5001; // Use 2.5 ms frames
+  OPUS_FRAMESIZE_5_MS = 5002; // Use 5 ms frames
+  OPUS_FRAMESIZE_10_MS = 5003; // Use 10 ms frames
+  OPUS_FRAMESIZE_20_MS = 5004; // Use 20 ms frames
+  OPUS_FRAMESIZE_40_MS = 5005; // Use 40 ms frames
+  OPUS_FRAMESIZE_60_MS = 5006; // Use 60 ms frames
+
+  OPUS_CHANNEL_COUNT_MAX = 255;
+
+const
+  OPUS_SET_APPLICATION_REQUEST = 4000;
+  OPUS_GET_APPLICATION_REQUEST = 4001;
+  OPUS_SET_BITRATE_REQUEST = 4002;
+  OPUS_GET_BITRATE_REQUEST = 4003;
+  OPUS_SET_MAX_BANDWIDTH_REQUEST = 4004;
+  OPUS_GET_MAX_BANDWIDTH_REQUEST = 4005;
+  OPUS_SET_VBR_REQUEST = 4006;
+  OPUS_GET_VBR_REQUEST = 4007;
+  OPUS_SET_BANDWIDTH_REQUEST = 4008;
+  OPUS_GET_BANDWIDTH_REQUEST = 4009;
+  OPUS_SET_COMPLEXITY_REQUEST = 4010;
+  OPUS_GET_COMPLEXITY_REQUEST = 4011;
+  OPUS_SET_INBAND_FEC_REQUEST = 4012;
+  OPUS_GET_INBAND_FEC_REQUEST = 4013;
+  OPUS_SET_PACKET_LOSS_PERC_REQUEST = 4014;
+  OPUS_GET_PACKET_LOSS_PERC_REQUEST = 4015;
+  OPUS_SET_DTX_REQUEST = 4016;
+  OPUS_GET_DTX_REQUEST = 4017;
+  OPUS_SET_VBR_CONSTRAINT_REQUEST = 4020;
+  OPUS_GET_VBR_CONSTRAINT_REQUEST = 4021;
+  OPUS_SET_FORCE_CHANNELS_REQUEST = 4022;
+  OPUS_GET_FORCE_CHANNELS_REQUEST = 4023;
+  OPUS_SET_SIGNAL_REQUEST = 4024;
+  OPUS_GET_SIGNAL_REQUEST = 4025;
+  OPUS_GET_LOOKAHEAD_REQUEST = 4027;
+  OPUS_RESET_STATE_REQUEST = 4028;
+  OPUS_GET_SAMPLE_RATE_REQUEST = 4029;
+  OPUS_GET_FINAL_RANGE_REQUEST = 4031;
+  OPUS_GET_PITCH_REQUEST = 4033;
+  OPUS_SET_GAIN_REQUEST = 4034;
+  OPUS_GET_GAIN_REQUEST = 4045;
+  OPUS_SET_LSB_DEPTH_REQUEST = 4036;
+  OPUS_GET_LSB_DEPTH_REQUEST = 4037;
+  OPUS_GET_LAST_PACKET_DURATION_REQUEST = 4039;
+  OPUS_SET_EXPERT_FRAME_DURATION_REQUEST = 4040;
+  OPUS_GET_EXPERT_FRAME_DURATION_REQUEST = 4041;
+  OPUS_SET_PREDICTION_DISABLED_REQUEST = 4042;
+  OPUS_GET_PREDICTION_DISABLED_REQUEST = 4043;
+  OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST = 5120;
+  OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST = 5122;
+
+type
+  OpusHead = record
+    version: cint;
+    channel_count: cint;
+    pre_skip: cuint;
+    input_sample_rate: cuint32;
+    output_gain: cint;
+    mapping_family: cint;
+    stream_count: cint;
+    coupled_count: cint;
+    mapping: array [0..OPUS_CHANNEL_COUNT_MAX-1] of byte;
+  end;
+  POpusHead = ^OpusHead;
+
+type
+  OggOpusFile = record end;
+  POggOpusFile = ^OggOpusFile;
+
+type
+  op_read_func = function (stream: Pointer; buffer: pointer; nbytes: cint): cint; cdecl;
+  op_seek_func = function (stream: Pointer; offset: Int64; whence: cint): cint; cdecl;
+  op_tell_func = function (stream: Pointer): Int64; cdecl;
+  op_close_func = function (stream: Pointer): cint; cdecl;
+
+  OpusFileCallbacks = record
+    read: op_read_func;
+    seek: op_seek_func;
+    tell: op_tell_func;
+    close: op_close_func;
+  end;
+
+function opus_get_version_string(): PAnsiChar; cdecl; external {$IFDEF OPUS_DYNAMIC}opuslib{$ENDIF};
+function opus_strerror(error: cint): PAnsiChar; cdecl; external {$IFDEF OPUS_DYNAMIC}opuslib{$ENDIF};
+
+function op_open_file(path: pchar; err: pcint): POggOpusFile; cdecl; external {$IFDEF OPUS_DYNAMIC}opusfilelib{$ENDIF};
+function op_open_memory(data: pointer; size: csize_t; err: pcint): POggOpusFile; cdecl; external {$IFDEF OPUS_DYNAMIC}opusfilelib{$ENDIF};
+
+function op_test_file(path: pchar; err: pcint): POggOpusFile; cdecl; external {$IFDEF OPUS_DYNAMIC}opusfilelib{$ENDIF};
+function op_test_memory(data: pointer; size: csize_t; err: pcint): POggOpusFile; cdecl; external {$IFDEF OPUS_DYNAMIC}opusfilelib{$ENDIF};
+
+procedure op_free(opf: POggOpusFile); cdecl; external {$IFDEF OPUS_DYNAMIC}opusfilelib{$ENDIF};
+
+function op_seekable(opf: POggOpusFile): cint; cdecl; external {$IFDEF OPUS_DYNAMIC}opusfilelib{$ENDIF};
+function op_channel_count(opf: POggOpusFile): cuint32; cdecl; external {$IFDEF OPUS_DYNAMIC}opusfilelib{$ENDIF};
+function op_head(opf: POggOpusFile; li: cint): POpusHead; cdecl; external {$IFDEF OPUS_DYNAMIC}opusfilelib{$ENDIF};
+function op_pcm_tell(opf: POggOpusFile): cint64; cdecl; external {$IFDEF OPUS_DYNAMIC}opusfilelib{$ENDIF};
+function op_pcm_total(opf: POggOpusFile; li: cint): cint64; cdecl; external {$IFDEF OPUS_DYNAMIC}opusfilelib{$ENDIF};
+
+function op_read(opf: POggOpusFile; pcm: pcint16; bufsiz: cint; li: cint): cint; cdecl; external {$IFDEF OPUS_DYNAMIC}opusfilelib{$ENDIF};
+function op_read_stereo(opf: POggOpusFile; pcm: pcint16; bufsiz: cint): cint; cdecl; external {$IFDEF OPUS_DYNAMIC}opusfilelib{$ENDIF};
+function op_pcm_seek(opf: POggOpusFile; pos: cint64): cint;  cdecl; external {$IFDEF OPUS_DYNAMIC}opusfilelib{$ENDIF};
+
+implementation
+
+end.
index 118fbad8b9b67df20450b8f743eb50b13b2e84cf..9ce03af74e391c9d2a541eefac63153d458a5ef4 100644 (file)
@@ -27,7 +27,7 @@ uses
   ctypes;
 
 {$IF DEFINED(WINDOWS)}
-  {$IFDEF VORBIS_WINDOZE_STATIC}
+  {$IF DEFINED(VORBIS_WINDOZE_STATIC) OR DEFINED(OPUS_WINDOZE_STATIC)}
     {$LINKLIB libogg.a}
   {$ELSE}
     {$DEFINE OGG_DYNAMIC}