DEADSOFTWARE

Sound: OpenAL: OGG/Vorbis support
authorfgsfds <pvt.fgsfds@gmail.com>
Tue, 3 Sep 2019 01:28:35 +0000 (04:28 +0300)
committerfgsfds <pvt.fgsfds@gmail.com>
Tue, 3 Sep 2019 01:28:43 +0000 (04:28 +0300)
src/engine/e_soundfile_ogg.pas [new file with mode: 0644]
src/game/Doom2DF.lpr
src/lib/vorbis/ogg.pas [new file with mode: 0644]
src/lib/vorbis/vorbis.pas [new file with mode: 0644]

diff --git a/src/engine/e_soundfile_ogg.pas b/src/engine/e_soundfile_ogg.pas
new file mode 100644 (file)
index 0000000..220fbd2
--- /dev/null
@@ -0,0 +1,300 @@
+(* 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_ogg;
+
+interface
+
+uses e_soundfile, vorbis, classes;
+
+type
+  // OGG Vorbis loader
+
+  TOGGLoader = 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
+    FOgg: OggVorbis_File;
+    FData: TStream;
+    FBuf: Pointer;
+    FTotal: LongWord;
+    FOpen: Boolean;
+
+    function LoadStream(Stream: TStream; SStreaming: Boolean): Boolean;
+    function LoadEntireStream(): Pointer;
+  end;
+
+  TOGGLoaderFactory = 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;
+
+(* Reader functions for ov_callbacks *)
+
+function streamSeek(h: Pointer; off: ogg_int64_t; whence: cint): cint; cdecl;
+var
+  S: TStream;
+begin
+  Result := -1;
+  if h = nil then Exit;
+  S:= TStream(h);
+  try
+    case whence of
+      0: s.Seek(off, soBeginning); // SEEK_SET
+      1: s.Seek(off, soCurrent);   // SEEK_CUR
+      2: s.Seek(off, soEnd);       // SEEK_END
+    end;
+    Result := 0;
+  except
+    Result := -1;
+  end;
+end;
+
+function streamRead(buf: Pointer; sz, nmemb: csize_t; h: Pointer): csize_t; cdecl;
+var
+  S: TStream;
+begin
+  Result := 0;
+  if h = nil then Exit;
+  S:= TStream(h);
+  try
+    Result := S.Read(buf^, sz*nmemb) div sz;
+  except
+    Result := 0;
+  end;
+end;
+
+function streamTell(h: Pointer): clong; cdecl;
+var
+  S: TStream;
+begin
+  Result := -1;
+  if h = nil then Exit;
+  S := TStream(h);
+  Result := S.Position;
+end;
+
+var
+  oggIO: ov_callbacks = (
+    read:        streamRead;
+    seek:        streamSeek;
+    close:       nil; // the loader's gonna handle that
+    tell:        streamTell;
+  );
+
+(* TOGGLoaderFactory *)
+
+function TOGGLoaderFactory.MatchHeader(Data: Pointer; Len: LongWord): Boolean;
+const
+  OGG_HEADER = $5367674F; // 'OggS'
+begin
+  if Len < 27 then // header is at least 27 bytes
+  begin
+    Result := False;
+    exit;
+  end;
+  Result := (PLongWord(Data)^ = OGG_HEADER);
+end;
+
+function TOGGLoaderFactory.MatchExtension(FName: string): Boolean;
+begin
+  Result := GetFilenameExt(FName) = '.ogg';
+end;
+
+function TOGGLoaderFactory.GetLoader(): TSoundLoader;
+begin
+  Result := TOGGLoader.Create();
+end;
+
+(* TOGGLoader *)
+
+function TOGGLoader.LoadEntireStream(): Pointer;
+var
+  Samples: ogg_int64_t;
+  Ret: clong;
+begin
+  Result := nil;
+
+  Samples := ov_pcm_total(FOgg, -1);
+  if Samples < 0 then Exit;
+
+  FTotal := Samples * 2 * FFormat.Channels;
+  Result := GetMem(FTotal);
+  if Result = nil then Exit;
+
+  Ret := ov_read_ext(FOgg, Result, FTotal, False, 2, True);
+  if Ret < 0 then
+  begin
+    FreeMem(Result);
+    Result := nil;
+  end
+  else
+    FTotal := Ret;
+end;
+
+function TOGGLoader.LoadStream(Stream: TStream; SStreaming: Boolean): Boolean;
+var
+  Ret, Bit: clong;
+  Info: pvorbis_info;
+  FullBuf: Pointer;
+begin
+  Result := False;
+
+  Ret := ov_open_callbacks(Stream, FOgg, nil, 0, oggIO);
+  if Ret < 0 then
+  begin
+    e_LogWriteln('OGG: Load(Data) failed: ov_open_callbacks failed');
+    Exit;
+  end;
+
+  Info := ov_info(FOgg, -1);
+  if Info = nil then
+  begin
+    e_LogWriteln('OGG: Load(Data) failed: ov_info returned NULL');
+    ov_clear(FOgg);
+    Exit;
+  end;
+
+  FFormat.SampleRate := Info^.rate;
+  FFormat.Channels := Info^.channels;
+  FFormat.SampleBits := 16;
+
+  if not SStreaming then
+  begin
+    FullBuf := LoadEntireStream();
+
+    if FullBuf = nil then
+    begin
+      e_LogWriteln('OGG: Load(Data) failed: couldn''t allocate for non-streaming chunk');
+      ov_clear(FOgg);
+      FTotal := 0;
+      Exit;
+    end;
+
+    ov_clear(FOgg);
+    Stream.Destroy();
+
+    FreeMem(FBuf);
+    FBuf := FullBuf;
+  end
+  else
+  begin
+    FTotal := 0;
+    FOpen := True;
+    FData := Stream;
+  end;
+
+  FStreaming := SStreaming;
+  Result := True;
+end;
+
+function TOGGLoader.Load(Data: Pointer; Len: LongWord; SStreaming: Boolean): Boolean;
+var
+  S: TStream;
+begin
+  Result := False;
+
+  // TODO: have to make a dupe here because Data gets deallocated after loading
+  //       this is obviously very shit
+  FBuf := GetMem(Len);
+  if FBuf = nil then Exit;
+  Move(Data^, FBuf^, Len);
+
+  S := TSFSMemoryStreamRO.Create(FBuf, Len{, True});
+  Result := LoadStream(S, SStreaming);
+
+  if not Result and (S <> nil) then
+  begin
+    S.Destroy();
+    FreeMem(FBuf);
+    FBuf := nil;
+  end;
+end;
+
+function TOGGLoader.Load(FName: string; SStreaming: Boolean): Boolean;
+var
+  S: TStream = nil;
+begin
+  Result := False;
+
+  try
+    S := openDiskFileRO(FName);
+    Result := LoadStream(S, SStreaming);
+  except
+    on E: Exception do
+      e_LogWritefln('OGG: ERROR: could not read file `%s`: %s', [FName, E.Message]);
+  end;
+
+  if not Result and (S <> nil) then
+    S.Destroy();
+end;
+
+function TOGGLoader.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;
+var
+  Ret: clong;
+begin
+  Result := 0;
+  if not FOpen or not FStreaming then Exit;
+  Ret := ov_read_ext(FOgg, Buf, Len, False, 2, True);
+  if Ret < 0 then Exit;
+  Result := Ret; 
+end;
+
+function TOGGLoader.GetAll(var OutPtr: Pointer): LongWord;
+begin
+  Result := 0;
+  if FStreaming or (FTotal = 0) then Exit;
+  Result := FTotal;
+  OutPtr := FBuf;
+end;
+
+procedure TOGGLoader.Free();
+begin
+  if FOpen then
+    ov_clear(FOgg);
+  if FData <> nil then
+    FData.Destroy();
+  if FBuf <> nil then
+    FreeMem(FBuf);
+  FData := nil;
+  FBuf := nil;
+  FOpen := False;
+  FTotal := 0;
+  FStreaming := False;
+end;
+
+initialization
+  e_AddSoundLoader(TOGGLoaderFactory.Create());
+end.
index 9277239bbda6ce8dce35792842adea6f05382be7..cd61dfefbf0ab826d393d10d69b6b65e8e51e21c 100644 (file)
@@ -63,6 +63,11 @@ uses
   AL in '../lib/openal/al.pas',
   e_soundfile in '../engine/e_soundfile.pas',
   e_soundfile_wav in '../engine/e_soundfile_wav.pas',
+  {$IFDEF USE_VORBIS}
+    ogg in '../lib/vorbis/ogg.pas',
+    vorbis in '../lib/vorbis/vorbis.pas',
+    e_soundfile_ogg in '../engine/e_soundfile_ogg.pas',
+  {$ENDIF}
   {$IFDEF USE_FLUIDSYNTH}
     fluidsynth in '../lib/fluidsynth/fluidsynth.pas',
     e_soundfile_fluid in '../engine/e_soundfile_fluid.pas',
diff --git a/src/lib/vorbis/ogg.pas b/src/lib/vorbis/ogg.pas
new file mode 100644 (file)
index 0000000..118fbad
--- /dev/null
@@ -0,0 +1,215 @@
+{
+  Translation of the ogg headers for FreePascal
+  Copyright (C) 2006 by Ivo Steinmann
+}
+
+(********************************************************************
+ *                                                                  *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE.   *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
+ *                                                                  *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002             *
+ * by the Xiph.Org Foundation http://www.xiph.org/                  *
+ *                                                                  *
+ ********************************************************************)
+
+unit ogg;
+
+{$MODE OBJFPC}
+{$MINENUMSIZE 4}
+{$PACKRECORDS C}
+
+interface
+
+uses
+  ctypes;
+
+{$IF DEFINED(WINDOWS)}
+  {$IFDEF VORBIS_WINDOZE_STATIC}
+    {$LINKLIB libogg.a}
+  {$ELSE}
+    {$DEFINE OGG_DYNAMIC}
+    const ogglib = 'libogg-0.dll';
+  {$ENDIF}
+{$ELSEIF DEFINED(UNIX)}
+  {$DEFINE OGG_DYNAMIC}
+  const ogglib = 'libogg.so';
+{$ELSE}
+  {$ERROR libogg not supported on this platform. Fix it!}
+{$ENDIF}
+
+(***********************************************************************)
+(* Header : os_types.h                                                 *)
+(***********************************************************************)
+type
+  ogg_int64_t    = cint64;              pogg_int64_t    = ^ogg_int64_t;
+  ogg_int32_t    = cint32;              pogg_int32_t    = ^ogg_int32_t;
+  ogg_uint32_t   = cuint32;             pogg_uint32_t   = ^ogg_uint32_t;
+  ogg_int16_t    = cint16;              pogg_int16_t    = ^ogg_int16_t;
+  ogg_uint16_t   = cuint16;             pogg_uint16_t   = ^ogg_uint16_t;
+
+
+(***********************************************************************)
+(* Header : ogg.h                                                      *)
+(***********************************************************************)
+type
+  poggpack_buffer = ^oggpack_buffer;
+  oggpack_buffer = record
+    endbyte         : clong;
+    endbit          : cint;
+    buffer          : pcuchar;
+    ptr             : pcuchar;
+    storage         : clong;
+  end;
+
+{ ogg_page is used to encapsulate the data in one Ogg bitstream page }
+
+  pogg_page = ^ogg_page;
+  ogg_page = record
+    header          : pcuchar;
+    header_len      : clong;
+    body            : pcuchar;
+    body_len        : clong;
+  end;
+
+{ ogg_stream_state contains the current encode/decode state of a logical Ogg bitstream }
+
+  pogg_stream_state = ^ogg_stream_state;
+  ogg_stream_state = record
+    body_data       : pcuchar;                 { bytes from packet bodies }
+    body_storage    : clong;                           { storage elements allocated }
+    body_fill       : clong;                           { elements stored; fill mark }
+    body_returned   : clong;                           { elements of fill returned }
+
+    lacing_vals     : pcint;                            { The values that will go to the segment table }
+    granule_vals    : pogg_int64_t;                    { granulepos values for headers. Not compact this way, but it is simple coupled to the lacing fifo }
+
+    lacing_storage  : clong;
+    lacing_fill     : clong;
+    lacing_packet   : clong;
+    lacing_returned : clong;
+
+    header          : array[0..281] of cuchar; { working space for header encode }
+    header_fill     : cint;
+
+    e_o_s           : cint;                            { set when we have buffered the last packet in the logical bitstream }
+    b_o_s           : cint;                            { set after we've written the initial page of a logical bitstream }
+
+    serialno        : clong;
+    pageno          : clong;
+    packetno        : ogg_int64_t;                    { sequence number for decode; the framing knows where there's a hole in the data,
+                                                        but we need coupling so that the codec (which is in a seperate abstraction layer) also knows about the gap }
+    granulepos      : ogg_int64_t;
+  end;
+
+{ ogg_packet is used to encapsulate the data and metadata belonging to a single raw Ogg/Vorbis packet }
+
+  pogg_packet = ^ogg_packet;
+  ogg_packet = record
+    packet          : pcuchar;
+    bytes           : clong;
+    b_o_s           : clong;
+    e_o_s           : clong;
+
+    granulepos      : ogg_int64_t;
+    packetno        : ogg_int64_t;             { sequence number for decode; the framing knows where there's a hole in the data,
+                                                 but we need coupling so that the codec (which is in a seperate abstraction layer) also knows about the gap }
+  end;
+
+  ogg_sync_state = record
+    data            : pcuchar;
+    storage         : cint;
+    fill            : cint;
+    returned        : cint;
+
+    unsynced        : cint;
+    headerbytes     : cint;
+    bodybytes       : cint;
+  end;
+
+{ Ogg BITSTREAM PRIMITIVES: bitstream }
+
+procedure oggpack_writeinit(var b: oggpack_buffer); cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+procedure oggpack_writetrunc(var b: oggpack_buffer; bits: clong); cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+procedure oggpack_writealign(var b: oggpack_buffer); cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+procedure oggpack_writecopy(var b: oggpack_buffer; source: pointer; bits: clong); cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+procedure oggpack_reset(var b: oggpack_buffer); cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+procedure oggpack_writeclear(var b: oggpack_buffer); cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+procedure oggpack_readinit(var b: oggpack_buffer; buf: pointer; bytes: cint); cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+procedure oggpack_write(var b: oggpack_buffer; value: culong; bits: cint); cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+function  oggpack_look(var b: oggpack_buffer; bits: cint): clong; cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+function  oggpack_look1(var b: oggpack_buffer): clong; cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+procedure oggpack_adv(var b: oggpack_buffer; bits: cint); cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+procedure oggpack_adv1(var b: oggpack_buffer); cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+function  oggpack_read(var b: oggpack_buffer; bits: cint): clong; cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+function  oggpack_read1(var b: oggpack_buffer): clong; cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+function  oggpack_bytes(var b: oggpack_buffer): clong; cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+function  oggpack_bits(var b: oggpack_buffer): clong; cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+function  oggpack_get_buffer(var b: oggpack_buffer): pointer; cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+
+procedure oggpackB_writeinit(var b: oggpack_buffer); cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+procedure oggpackB_writetrunc(var b: oggpack_buffer; bits: clong); cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+procedure oggpackB_writealign(var b: oggpack_buffer); cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+procedure oggpackB_writecopy(var b: oggpack_buffer; source: pointer; bits: clong); cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+procedure oggpackB_reset(var b: oggpack_buffer); cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+procedure oggpackB_writeclear(var b: oggpack_buffer); cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+procedure oggpackB_readinit(var b: oggpack_buffer; buf: pointer; bytes: cint); cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+procedure oggpackB_write(var b: oggpack_buffer; value: culong; bits: cint); cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+function  oggpackB_look(var b: oggpack_buffer; bits: cint): clong; cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+function  oggpackB_look1(var b: oggpack_buffer): clong; cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+procedure oggpackB_adv(var b: oggpack_buffer; bits: cint); cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+procedure oggpackB_adv1(var b: oggpack_buffer); cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+function  oggpackB_read(var b: oggpack_buffer; bits: cint): clong; cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+function  oggpackB_read1(var b: oggpack_buffer): clong; cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+function  oggpackB_bytes(var b: oggpack_buffer): clong; cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+function  oggpackB_bits(var b: oggpack_buffer): clong; cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+function  oggpackB_get_buffer(var b: oggpack_buffer): pointer; cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+
+{ ogglib BITSTREAM PRIMITIVES: encoding }
+
+function  ogg_stream_packetin(var os: ogg_stream_state; var op: ogg_packet): cint; cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+function  ogg_stream_pageout(var os: ogg_stream_state; var op: ogg_page): cint; cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+function  ogg_stream_flush(var os: ogg_stream_state; var op: ogg_page): cint; cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+
+{ ogglib BITSTREAM PRIMITIVES: decoding }
+
+function  ogg_sync_init(var oy: ogg_sync_state): cint; cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+function  ogg_sync_clear(var oy: ogg_sync_state): cint; cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+function  ogg_sync_reset(var oy: ogg_sync_state): cint; cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+function  ogg_sync_destroy(var oy: ogg_sync_state): cint; cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+
+function  ogg_sync_buffer(var oy: ogg_sync_state; size: clong): pointer; cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+function  ogg_sync_wrote(var oy: ogg_sync_state; bytes: clong): cint; cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+function  ogg_sync_pageseek(var oy: ogg_sync_state; var og: ogg_page): pointer; cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+function  ogg_sync_pageout(var oy: ogg_sync_state; var og: ogg_page): cint; cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+function  ogg_stream_pagein(var os: ogg_stream_state; var og: ogg_page): cint; cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+function  ogg_stream_packetout(var os: ogg_stream_state; var op: ogg_packet): cint; cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+function  ogg_stream_packetpeek(var os: ogg_stream_state; var op: ogg_packet): cint; cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+
+{ ogglib BITSTREAM PRIMITIVES: general }
+
+function  ogg_stream_init(var os: ogg_stream_state; serialno: cint): cint; cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+function  ogg_stream_clear(var os: ogg_stream_state): cint; cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+function  ogg_stream_reset(var os: ogg_stream_state): cint; cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+function  ogg_stream_reset_serialno(var os: ogg_stream_state; serialno: cint): cint; cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+function  ogg_stream_destroy(var os: ogg_stream_state): cint; cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+function  ogg_stream_eos(var os: ogg_stream_state): cint; cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+
+procedure ogg_page_checksum_set(var og: ogg_page); cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+
+function  ogg_page_version(var og: ogg_page): cint; cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+function  ogg_page_continued(var og: ogg_page): cint; cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+function  ogg_page_bos(var og: ogg_page): cint; cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+function  ogg_page_eos(var og: ogg_page): cint; cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+function  ogg_page_granulepos(var og: ogg_page): ogg_int64_t; cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+function  ogg_page_serialno(var og: ogg_page): cint; cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+function  ogg_page_pageno(var og: ogg_page): clong; cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+function  ogg_page_packets(var og: ogg_page): cint; cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+
+procedure ogg_packet_clear(var op: ogg_packet); cdecl; external {$IFDEF OGG_DYNAMIC}ogglib{$ENDIF};
+
+implementation
+
+end.
diff --git a/src/lib/vorbis/vorbis.pas b/src/lib/vorbis/vorbis.pas
new file mode 100644 (file)
index 0000000..8962f50
--- /dev/null
@@ -0,0 +1,449 @@
+{
+  Translation of the vorbis headers for FreePascal
+  Copyright (C) 2006 by Ivo Steinmann
+}
+
+(********************************************************************
+ *                                                                  *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE.   *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
+ *                                                                  *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001             *
+ * by the XIPHOPHORUS Company http://www.xiph.org/                  *
+ *                                                                  *
+ ********************************************************************)
+
+unit vorbis;
+
+{$MODE OBJFPC}
+{$MINENUMSIZE 4}
+{$PACKRECORDS C}
+
+interface
+
+uses
+  ctypes, ogg;
+
+{$IF DEFINED(WINDOWS)}
+  {$IFDEF VORBIS_WINDOZE_STATIC}
+    {$LINKLIB libvorbis.a}
+    {$LINKLIB libvorbisfile.a}
+  {$ELSE}
+    {$DEFINE OGG_DYNAMIC}
+    const vorbislib = 'libvorbis-0.dll';
+    const vorbisfilelib = 'libvorbisfile-3.dll';
+  {$ENDIF}
+{$ELSEIF DEFINED(UNIX)}
+  {$DEFINE OGG_DYNAMIC}
+  const vorbislib = 'libvorbis.so';
+  const vorbisfilelib = 'libvorbisfile.so';
+{$ELSE}
+  {$ERROR libvorbis not supported on this platform. Fix it!}
+{$ENDIF}
+
+(***********************************************************************)
+(* Header : codec.h                                                    *)
+(***********************************************************************)
+
+type
+  ppcfloat = ^pcfloat;
+
+  pvorbis_info = ^vorbis_info;
+  vorbis_info = record
+    version         : cint;
+    channels        : cint;
+    rate            : clong;
+
+  { The below bitrate declarations are *hints*.
+     Combinations of the three values carry the following implications:
+
+     all three set to the same value:
+       implies a fixed rate bitstream
+     only nominal set:
+       implies a VBR stream that averages the nominal bitrate.  No hard
+       upper/lower limit
+     upper and or lower set:
+       implies a VBR bitstream that obeys the bitrate limits. nominal
+       may also be set to give a nominal rate.
+     none set:
+       the coder does not care to speculate.
+  }
+
+    bitrate_upper   : clong;
+    bitrate_nominal : clong;
+    bitrate_lower   : clong;
+    bitrate_window  : clong;
+    codec_setup     : pointer;
+  end;
+
+{ vorbis_dsp_state buffers the current vorbis audio analysis/synthesis state.  The DSP state belongs to a specific logical bitstream }
+
+  pvorbis_dsp_state = ^vorbis_dsp_state;
+  vorbis_dsp_state = record
+    analysisp       : cint;
+    vi              : pvorbis_info;
+
+    pcm             : ppcfloat;
+    pcmret          : ppcfloat;
+    pcm_storage     : cint;
+    pcm_current     : cint;
+    pcm_returned    : cint;
+
+    preextrapolate  : cint;
+    eofflag         : cint;
+
+    lW              : clong;
+    W               : clong;
+    nW              : clong;
+    centerW         : clong;
+
+    granulepos      : ogg_int64_t;
+    sequence        : ogg_int64_t;
+
+    glue_bits       : ogg_int64_t;
+    time_bits       : ogg_int64_t;
+    floor_bits      : ogg_int64_t;
+    res_bits        : ogg_int64_t;
+
+    backend_state   : pointer;
+  end;
+
+{ vorbis_block is a single block of data to be processed as part of
+  the analysis/synthesis stream; it belongs to a specific logical
+  bitstream, but is independant from other vorbis_blocks belonging to
+  that logical bitstream. }
+
+  palloc_chain = ^alloc_chain;
+  alloc_chain = record
+    ptr             : pointer;
+    next            : palloc_chain;
+  end;
+
+  pvorbis_block = ^vorbis_block;
+  vorbis_block = record
+  { necessary stream state for linking to the framing abstraction }
+    pcm             : ppcfloat;            { this is a pointer into local storage }
+    opb             : oggpack_buffer;
+
+    lW              : clong;
+    W               : clong;
+    nW              : clong;
+    pcmend          : cint;
+    mode            : cint;
+
+    eofflag         : cint;
+    granulepos      : ogg_int64_t;
+    sequence        : ogg_int64_t;
+    vd              : pvorbis_dsp_state; { For read-only access of configuration }
+
+  { local storage to avoid remallocing; it's up to the mapping to structure it }
+    localstore      : pointer;
+    localtop        : clong;
+    localalloc      : clong;
+    totaluse        : clong;
+    reap            : palloc_chain;
+
+  { bitmetrics for the frame }
+    glue_bits       : clong;
+    time_bits       : clong;
+    floor_bits      : clong;
+    res_bits        : clong;
+
+    internal        : pointer;
+  end;
+
+{ vorbis_info contains all the setup information specific to the
+  specific compression/decompression mode in progress (eg,
+  psychoacoustic settings, channel setup, options, codebook
+  etc). vorbis_info and substructures are in backends.h. }
+
+{ the comments are not part of vorbis_info so that vorbis_info can be static storage }
+
+  pvorbis_comment = ^vorbis_comment;
+  vorbis_comment = record
+  { unlimited user comment fields.  libvorbis writes 'libvorbis' whatever vendor is set to in encode }
+    user_comments   : ^pcchar;
+    comment_lengths : pcint;
+    comments        : cint;
+    vendor          : pcchar;
+  end;
+
+
+{ libvorbis encodes in two abstraction layers; first we perform DSP
+  and produce a packet (see docs/analysis.txt).  The packet is then
+  coded into a framed OggSquish bitstream by the second layer (see
+  docs/framing.txt).  Decode is the reverse process; we sync/frame
+  the bitstream and extract individual packets, then decode the
+  packet back into PCM audio.
+
+  The extra framing/packetizing is used in streaming formats, such as
+  files.  Over the net (such as with UDP), the framing and
+  packetization aren't necessary as they're provided by the transport
+  and the streaming layer is not used }
+
+{ Vorbis PRIMITIVES: general }
+
+procedure vorbis_info_init(var vi: vorbis_info); cdecl; external {$IFDEF OGG_DYNAMIC}vorbislib{$ENDIF};
+procedure vorbis_info_clear(var vi: vorbis_info); cdecl; external {$IFDEF OGG_DYNAMIC}vorbislib{$ENDIF};
+function  vorbis_info_blocksize(var vi: vorbis_info; zo: cint): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbislib{$ENDIF};
+procedure vorbis_comment_init(var vc: vorbis_comment); cdecl; external {$IFDEF OGG_DYNAMIC}vorbislib{$ENDIF};
+procedure vorbis_comment_add(var vc: vorbis_comment; comment: pchar); cdecl; external {$IFDEF OGG_DYNAMIC}vorbislib{$ENDIF};
+procedure vorbis_comment_add_tag(var vc: vorbis_comment; tag: pchar; contents: pchar); cdecl; external {$IFDEF OGG_DYNAMIC}vorbislib{$ENDIF};
+function  vorbis_comment_query(var vc: vorbis_comment; tag: pchar; count: cint): pchar; cdecl; external {$IFDEF OGG_DYNAMIC}vorbislib{$ENDIF};
+function  vorbis_comment_query_count(var vc: vorbis_comment; tag: pchar): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbislib{$ENDIF};
+procedure vorbis_comment_clear(var vc: vorbis_comment); cdecl; external {$IFDEF OGG_DYNAMIC}vorbislib{$ENDIF};
+
+function  vorbis_block_init(var v: vorbis_dsp_state; var vb: vorbis_block): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbislib{$ENDIF};
+function  vorbis_block_clear(var vb: vorbis_block): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbislib{$ENDIF};
+procedure vorbis_dsp_clear(var v: vorbis_dsp_state); cdecl; external {$IFDEF OGG_DYNAMIC}vorbislib{$ENDIF};
+function  vorbis_granule_time(var v: vorbis_dsp_state; granulepos: ogg_int64_t): cdouble; cdecl; external {$IFDEF OGG_DYNAMIC}vorbislib{$ENDIF};
+
+{ vorbislib PRIMITIVES: analysis/DSP layer }
+
+function  vorbis_analysis_init(var v: vorbis_dsp_state; var vi: vorbis_info): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbislib{$ENDIF};
+function  vorbis_commentheader_out(var vc: vorbis_comment; var op: ogg_packet): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbislib{$ENDIF};
+function  vorbis_analysis_headerout(var v:vorbis_dsp_state; var vc: vorbis_comment; var op: ogg_packet; var op_comm: ogg_packet; var op_code: ogg_packet): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbislib{$ENDIF};
+function  vorbis_analysis_buffer(var v: vorbis_dsp_state; vals: cint): ppcfloat; cdecl; external {$IFDEF OGG_DYNAMIC}vorbislib{$ENDIF};
+function  vorbis_analysis_wrote(var v: vorbis_dsp_state; vals: cint): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbislib{$ENDIF};
+function  vorbis_analysis_blockout(var v: vorbis_dsp_state; var vb: vorbis_block): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbislib{$ENDIF};
+function  vorbis_analysis(var vb: vorbis_block; var op: ogg_packet): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbislib{$ENDIF};
+
+function  vorbis_bitrate_addblock(var vb: vorbis_block): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbislib{$ENDIF};
+function  vorbis_bitrate_flushpacket(var vd: vorbis_dsp_state; var op: ogg_packet): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbislib{$ENDIF};
+
+{ vorbislib PRIMITIVES: synthesis layer }
+
+function  vorbis_synthesis_headerin(var vi: vorbis_info; var vc: vorbis_comment; var op: ogg_packet): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbislib{$ENDIF};
+
+function  vorbis_synthesis_init(var v: vorbis_dsp_state; var vi: vorbis_info): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbislib{$ENDIF};
+function  vorbis_synthesis_restart(var v: vorbis_dsp_state): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbislib{$ENDIF};
+function  vorbis_synthesis(var vb: vorbis_block; var op: ogg_packet): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbislib{$ENDIF};
+function  vorbis_synthesis_trackonly(var vb: vorbis_block; var op: ogg_packet): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbislib{$ENDIF};
+function  vorbis_synthesis_blockin(var v: vorbis_dsp_state; var vb: vorbis_block): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbislib{$ENDIF};
+function  vorbis_synthesis_pcmout(var v: vorbis_dsp_state; var pcm: ppcfloat): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbislib{$ENDIF};
+function  vorbis_synthesis_lapout(var v: vorbis_dsp_state; var pcm: ppcfloat): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbislib{$ENDIF};
+function  vorbis_synthesis_read(var v: vorbis_dsp_state; samples: cint): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbislib{$ENDIF};
+function  vorbis_packet_blocksize(var vi: vorbis_info; var op: ogg_packet): clong; cdecl; external {$IFDEF OGG_DYNAMIC}vorbislib{$ENDIF};
+
+function  vorbis_synthesis_halfrate(var v: vorbis_info; flag: cint): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbislib{$ENDIF};
+function  vorbis_synthesis_halfrate_p(var v: vorbis_info): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbislib{$ENDIF};
+
+{ vorbislib ERRORS and return codes }
+Const
+  OV_FALSE          = -1;
+  OV_EOF            = -2;
+  OV_HOLE           = -3;
+
+  OV_EREAD          = -128;
+  OV_EFAULT         = -129;
+  OV_EIMPL          = -130;
+  OV_EINVAL         = -131;
+  OV_ENOTVORBIS     = -132;
+  OV_EBADHEADER     = -133;
+  OV_EVERSION       = -134;
+  OV_ENOTAUDIO      = -135;
+  OV_EBADPACKET     = -136;
+  OV_EBADLINK       = -137;
+  OV_ENOSEEK        = -138;
+
+
+(***********************************************************************)
+(* Header : vorbisfile.h                                               *)
+(***********************************************************************)
+
+type
+
+{* The function prototypes for the callbacks are basically the same as for
+
+ * the stdio functions fread, fseek, fclose, ftell.
+ * The one difference is that the FILE * arguments have been replaced with
+ * a void * - this is to be used as a pointer to whatever internal data these
+ * functions might need. In the stdio case, it's just a FILE * cast to a void *
+ *
+ * If you use other functions, check the docs for these functions and return
+ * the right values. For seek_func(), you *MUST* return -1 if the stream is
+ * unseekable
+ *}
+
+  read_func  = function(ptr: pointer; size, nmemb: csize_t; datasource: pointer): csize_t; cdecl;
+  seek_func  = function(datasource: pointer; offset: ogg_int64_t; whence: cint): cint; cdecl;
+  close_func = function(datasource: pointer): cint; cdecl;
+  tell_func  = function(datasource: pointer): clong; cdecl;
+
+  pov_callbacks = ^ov_callbacks;
+  ov_callbacks = record
+    read            : read_func;
+    seek            : seek_func;
+    close           : close_func;
+    tell            : tell_func;
+  end;
+
+const
+  NOTOPEN           = 0;
+  PARTOPEN          = 1;
+  OPENED            = 2;
+  STREAMSET         = 3;
+  INITSET           = 4;
+
+type
+  POggVorbis_File = ^OggVorbis_File;
+  OggVorbis_File = record
+    datasource      : pointer; { pointer to a FILE *, etc. }
+    seekable        : cint;
+    offset          : ogg_int64_t;
+    end_            : ogg_int64_t;
+    oy              : ogg_sync_state;
+
+  { If the FILE handle isn't seekable (eg, a pipe), only the current stream appears }
+    links           : cint;
+    offsets         : pogg_int64_t;
+    dataoffsets     : pogg_int64_t;
+    serialnos       : pclong;
+    pcmlengths      : pogg_int64_t; { overloaded to maintain binary compatability; x2 size, stores both beginning and end values }
+    vi              : pvorbis_info;
+    vc              : pvorbis_comment;
+
+  { Decoding working state local storage }
+    pcm_offset      : ogg_int64_t;
+    ready_state     : cint;
+    current_serialno: clong;
+    current_link    : cint;
+
+    bittrack        : cdouble;
+    samptrack       : cdouble;
+
+    os              : ogg_stream_state; { take physical pages, weld into a logical stream of packets }
+    vd              : vorbis_dsp_state; { central working state for the packet->PCM decoder }
+    vb              : vorbis_block;     { local working space for packet->PCM decode }
+
+    callbacks       : ov_callbacks;
+  end;
+
+
+function ov_clear(var vf: OggVorbis_File): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbisfilelib{$ENDIF};
+function ov_open(f: pointer; var vf: OggVorbis_File; initial: pointer; ibytes: clong): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbisfilelib{$ENDIF};
+function ov_open_callbacks(datasource: pointer; var vf: OggVorbis_File; initial: pointer; ibytes: clong; callbacks: ov_callbacks): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbisfilelib{$ENDIF};
+
+function ov_test(f: pointer; var vf: OggVorbis_File; initial: pointer; ibytes: clong): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbisfilelib{$ENDIF};
+function ov_test_callbacks(datasource: pointer; var vf: OggVorbis_File; initial: pointer; ibytes: clong; callbacks: ov_callbacks): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbisfilelib{$ENDIF};
+function ov_test_open(var vf: OggVorbis_File): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbisfilelib{$ENDIF};
+
+function ov_bitrate(var vf: OggVorbis_File; i: cint): clong; cdecl; external {$IFDEF OGG_DYNAMIC}vorbisfilelib{$ENDIF};
+function ov_bitrate_instant(var vf: OggVorbis_File): clong; cdecl; external {$IFDEF OGG_DYNAMIC}vorbisfilelib{$ENDIF};
+function ov_streams(var vf: OggVorbis_File): clong; cdecl; external {$IFDEF OGG_DYNAMIC}vorbisfilelib{$ENDIF};
+function ov_seekable(var vf: OggVorbis_File): clong; cdecl; external {$IFDEF OGG_DYNAMIC}vorbisfilelib{$ENDIF};
+function ov_serialnumber(var vf: OggVorbis_File; i: cint): clong; cdecl; external {$IFDEF OGG_DYNAMIC}vorbisfilelib{$ENDIF};
+
+function ov_raw_total(var vf: OggVorbis_File; i: cint): ogg_int64_t; cdecl; external {$IFDEF OGG_DYNAMIC}vorbisfilelib{$ENDIF};
+function ov_pcm_total(var vf: OggVorbis_File; i: cint): ogg_int64_t; cdecl; external {$IFDEF OGG_DYNAMIC}vorbisfilelib{$ENDIF};
+function ov_time_total(var vf: OggVorbis_File; i: cint): cdouble; cdecl; external {$IFDEF OGG_DYNAMIC}vorbisfilelib{$ENDIF};
+
+function ov_raw_seek(var vf: OggVorbis_File; pos: ogg_int64_t): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbisfilelib{$ENDIF};
+function ov_pcm_seek(var vf: OggVorbis_File; pos: ogg_int64_t): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbisfilelib{$ENDIF};
+function ov_pcm_seek_page(var vf: OggVorbis_File; pos: ogg_int64_t): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbisfilelib{$ENDIF};
+function ov_time_seek(var vf: OggVorbis_File; pos: cdouble): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbisfilelib{$ENDIF};
+function ov_time_seek_page(var vf: OggVorbis_File; pos: cdouble): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbisfilelib{$ENDIF};
+
+function ov_raw_seek_lap(var vf: OggVorbis_File; pos: ogg_int64_t): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbisfilelib{$ENDIF};
+function ov_pcm_seek_lap(var vf: OggVorbis_File; pos: ogg_int64_t): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbisfilelib{$ENDIF};
+function ov_pcm_seek_page_lap(var vf: OggVorbis_File; pos: ogg_int64_t): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbisfilelib{$ENDIF};
+function ov_time_seek_lap(var vf: OggVorbis_File; pos: cdouble): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbisfilelib{$ENDIF};
+function ov_time_seek_page_lap(var vf: OggVorbis_File; pos: cdouble): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbisfilelib{$ENDIF};
+
+function ov_raw_tell(var vf: OggVorbis_File): ogg_int64_t; cdecl; external {$IFDEF OGG_DYNAMIC}vorbisfilelib{$ENDIF};
+function ov_pcm_tell(var vf: OggVorbis_File): ogg_int64_t; cdecl; external {$IFDEF OGG_DYNAMIC}vorbisfilelib{$ENDIF};
+function ov_time_tell(var vf: OggVorbis_File): cdouble; cdecl; external {$IFDEF OGG_DYNAMIC}vorbisfilelib{$ENDIF};
+
+function ov_info(var vf: OggVorbis_File; link: cint): pvorbis_info; cdecl; external {$IFDEF OGG_DYNAMIC}vorbisfilelib{$ENDIF};
+function ov_comment(var vf: OggVorbis_File; link: cint): pvorbis_comment; cdecl; external {$IFDEF OGG_DYNAMIC}vorbisfilelib{$ENDIF};
+
+function ov_read_float(var vf: OggVorbis_File; var pcm_channels: ppcfloat; samples: cint; bitstream: pcint): clong; cdecl; external {$IFDEF OGG_DYNAMIC}vorbisfilelib{$ENDIF};
+function ov_read(var vf: OggVorbis_File; buffer: pointer; length: cint; bigendianp: cbool; word: cint; sgned: cbool; bitstream: pcint): clong; cdecl; external {$IFDEF OGG_DYNAMIC}vorbisfilelib{$ENDIF};
+function ov_crosslap(var vf1: OggVorbis_File; var vf2: OggVorbis_File): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbisfilelib{$ENDIF};
+
+function ov_halfrate(var vf: OggVorbis_File; flag: cint): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbisfilelib{$ENDIF};
+function ov_halfrate_p(var vf: OggVorbis_File): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbisfilelib{$ENDIF};
+
+
+{
+  Developer of the A52 helpers for FreePascal
+  Copyright (C) 2006 by Ivo Steinmann
+}
+
+function ov_read_ext(var vf: OggVorbis_File; buffer: pointer; length: cint; bigendianp: cbool; word: cint; sgned: cbool): clong;
+
+(***********************************************************************)
+(* Header : vorbisenc.h                                                *)
+(***********************************************************************)
+
+const
+  OV_ECTL_RATEMANAGE_GET       = $10;
+
+  OV_ECTL_RATEMANAGE_SET       = $11;
+  OV_ECTL_RATEMANAGE_AVG       = $12;
+  OV_ECTL_RATEMANAGE_HARD      = $13;
+
+  OV_ECTL_LOWPASS_GET          = $20;
+  OV_ECTL_LOWPASS_SET          = $21;
+
+  OV_ECTL_IBLOCK_GET           = $30;
+  OV_ECTL_IBLOCK_SET           = $31;
+
+type
+  povectl_ratemanage_arg = ^ovectl_ratemanage_arg;
+  ovectl_ratemanage_arg = record
+    management_active        : cint;
+
+    bitrate_hard_min         : clong;
+    bitrate_hard_max         : clong;
+    bitrate_hard_window      : cdouble;
+
+    bitrate_av_lo            : clong;
+    bitrate_av_hi            : clong;
+    bitrate_av_window        : cdouble;
+    bitrate_av_window_center : cdouble;
+  end;
+
+// function vorbis_encode_init(var vi: vorbis_info; channels, rate, max_bitrate, nominal_bitrate, min_bitrate: clong): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbisenclib{$ENDIF};
+// function vorbis_encode_setup_managed(var vi: vorbis_info; channels, rate, max_bitrate, nominal_bitrate, min_bitrate: clong): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbisenclib{$ENDIF};
+// function vorbis_encode_setup_vbr(var vi: vorbis_info; channels, rate: clong; quality: cfloat): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbisenclib{$ENDIF};
+// (* quality level from 0. (lo) to 1. (hi) *)
+// function vorbis_encode_init_vbr(var vi: vorbis_info; channels, rate: clong; base_quality: cfloat): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbisenclib{$ENDIF};
+// function vorbis_encode_setup_init(var vi: vorbis_info): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbisenclib{$ENDIF};
+// function vorbis_encode_ctl(var vi: vorbis_info; number: cint; arg: pointer): cint; cdecl; external {$IFDEF OGG_DYNAMIC}vorbisenclib{$ENDIF};
+
+implementation
+
+function ov_read_ext(var vf: OggVorbis_File; buffer: pointer; length: cint; bigendianp: cbool; word: cint; sgned: cbool): clong;
+var
+  ofs: cint;
+  Num: cint;
+  Res: cint;
+begin
+  // check blocksize here!
+  {if length mod 4 <> 0 then
+    Exit(0);}
+
+  ofs := 0;
+  num := length;
+
+  while num > 0 do
+  begin
+    res := ov_read(vf, buffer + ofs, num, bigendianp, word, sgned, nil);
+    if res < 0 then
+      Exit(res);
+
+    if res = 0 then
+      Break;
+
+    ofs := ofs + res;
+    num := num - res;
+  end;
+
+  Result := ofs;
+end;
+
+end.
+