{This unit is part of United Openlibraries of Sound (uos)}

{This is the Dynamic loading version with reference counting of LibSndFile.pas.
 Load the library with sf_load() and release with sf_unload().
 Thanks to Phoenix for sf_open_virtual (TMemoryStream as input)
 License : modified LGPL.
 Fred van Stappen / fiens@hotmail.com }

unit uos_libsndfile;

{$IFDEF FPC}
  {$mode objfpc}{$H+}
  {$PACKENUM 4}(* use 4-byte enums *)
  {$PACKRECORDS C}(* C/C++-compatible record packing *)
  {$MACRO ON}//don't know whatfor !
{$ELSE}
  {$MINENUMSIZE 4}(* use 4-byte enums *)
{** MINENUMSIZE is equivalent to Z+}
{$ENDIF}

{$LONGSTRINGS ON}
{** LONGSTRINGS is equivalent to H+}

interface

uses
  dynlibs, classes,
  ctypes;

const
libsf=
 {$IFDEF unix}
 {$IFDEF darwin}
 'libsndfile.1.dylib';
  {$ELSE}
 'libsndfile.so.1';
  {$ENDIF}    
  {$ELSE}
 'sndfile.dll';
  {$ENDIF}    
  
type   
  PMemoryStream = ^TMemoryStream;
 
type 
 {$IF Defined(MSWINDOWS)} 
  off_t = int64;
  {$ELSE}  
  off_t    = clonglong;  
  size_t   = culong; 
  {$ENDIF} 

const
  //* Major formats. *//
  SF_FORMAT_WAV = $010000;    // Microsoft WAV format (little endian default).
  SF_FORMAT_AIFF = $020000;    // Apple/SGI AIFF format (big endian).
  SF_FORMAT_AU = $030000;    // Sun/NeXT AU format (big endian).
  SF_FORMAT_RAW = $040000;    // RAW PCM data.
  SF_FORMAT_PAF = $050000;    // Ensoniq PARIS file format.
  SF_FORMAT_SVX = $060000;    // Amiga IFF / SVX8 / SV16 format.
  SF_FORMAT_NIST = $070000;    // Sphere NIST format.
  SF_FORMAT_VOC = $080000;    // VOC files.
  SF_FORMAT_IRCAM = $0A0000;    // Berkeley/IRCAM/CARL
  SF_FORMAT_W64 = $0B0000;    // Sonic Foundry's 64 bit RIFF/WAV
  SF_FORMAT_MAT4 = $0C0000;    // Matlab (tm) V4.2 / GNU Octave 2.0
  SF_FORMAT_MAT5 = $0D0000;    // Matlab (tm) V5.0 / GNU Octave 2.1
  SF_FORMAT_PVF = $0E0000;    // Portable Voice Format
  SF_FORMAT_XI = $0F0000;    // Fasttracker 2 Extended Instrument
  SF_FORMAT_HTK = $100000;    // HMM Tool Kit format
  SF_FORMAT_SDS = $110000;    // Midi Sample Dump Standard
  SF_FORMAT_AVR = $120000;    // Audio Visual Research
  SF_FORMAT_WAVEX = $130000;    // MS WAVE with WAVEFORMATEX
  SF_FORMAT_SD2 = $160000;    // Sound Designer 2
  SF_FORMAT_FLAC = $170000;    // FLAC lossless file format
  SF_FORMAT_CAF = $180000;    // Core Audio File format
  SF_FORMAT_OGG = $200000;   // Xiph OGG container
        

const
  //Subtypes from here on.
  SF_FORMAT_PCM_S8 = $0001;    // Signed 8 bit data
  SF_FORMAT_PCM_16 = $0002;    // Signed 16 bit data
  SF_FORMAT_PCM_24 = $0003;    // Signed 24 bit data
  SF_FORMAT_PCM_32 = $0004;    // Signed 32 bit data

  SF_FORMAT_PCM_U8 = $0005;    // Unsigned 8 bit data (WAV and RAW only)

  SF_FORMAT_FLOAT = $0006;    // 32 bit float data
  SF_FORMAT_DOUBLE = $0007;    // 64 bit float data

  SF_FORMAT_ULAW = $0010;    // U-Law encoded.
  SF_FORMAT_ALAW = $0011;    // A-Law encoded.
  SF_FORMAT_IMA_ADPCM = $0012;    // IMA ADPCM.
  SF_FORMAT_MS_ADPCM = $0013;    // Microsoft ADPCM.

  SF_FORMAT_GSM610 = $0020;    // GSM 6.10 encoding.
  SF_FORMAT_VOX_ADPCM = $0021;    // OKI / Dialogix ADPCM

  SF_FORMAT_G721_32 = $0030;    // 32kbs G721 ADPCM encoding.
  SF_FORMAT_G723_24 = $0031;    // 24kbs G723 ADPCM encoding.
  SF_FORMAT_G723_40 = $0032;    // 40kbs G723 ADPCM encoding.

  SF_FORMAT_DWVW_12 = $0040;    // 12 bit Delta Width Variable Word encoding.
  SF_FORMAT_DWVW_16 = $0041;    // 16 bit Delta Width Variable Word encoding.
  SF_FORMAT_DWVW_24 = $0042;    // 24 bit Delta Width Variable Word encoding.
  SF_FORMAT_DWVW_N = $0043;    // N bit Delta Width Variable Word encoding.

  SF_FORMAT_DPCM_8 = $0050;    // 8 bit differential PCM (XI only)
  SF_FORMAT_DPCM_16 = $0051;    // 16 bit differential PCM (XI only)

  SF_FORMAT_VORBIS  = $0060;   // Xiph Vorbis encoding.


const
  //* Endian-ness options. *//
  SF_ENDIAN_FILE = $00000000;  // Default file endian-ness.
  SF_ENDIAN_LITTLE = $10000000;  // Force little endian-ness.
  SF_ENDIAN_BIG = $20000000;  // Force big endian-ness.
  SF_ENDIAN_CPU = $30000000;  // Force CPU endian-ness.

  SF_FORMAT_SUBMASK = $0000FFFF;
  SF_FORMAT_TYPEMASK = $0FFF0000;
  SF_FORMAT_ENDMASK = $30000000;

{
** The following are the valid command numbers for the sf_command()
** interface.  The use of these commands is documented in the file
** command.html in the doc directory of the source code distribution.
}
const
  SFC_GET_LIB_VERSION = $1000;
  SFC_GET_LOG_INFO = $1001;

  SFC_GET_NORM_DOUBLE = $1010;
  SFC_GET_NORM_FLOAT = $1011;
  SFC_SET_NORM_DOUBLE = $1012;
  SFC_SET_NORM_FLOAT = $1013;
  SFC_SET_SCALE_FLOAT_INT_READ = $1014;

  SFC_GET_SIMPLE_FORMAT_COUNT = $1020;
  SFC_GET_SIMPLE_FORMAT = $1021;

  SFC_GET_FORMAT_INFO = $1028;

  SFC_GET_FORMAT_MAJOR_COUNT = $1030;
  SFC_GET_FORMAT_MAJOR = $1031;
  SFC_GET_FORMAT_SUBTYPE_COUNT = $1032;
  SFC_GET_FORMAT_SUBTYPE = $1033;

  SFC_CALC_SIGNAL_MAX = $1040;
  SFC_CALC_NORM_SIGNAL_MAX = $1041;
  SFC_CALC_MAX_ALL_CHANNELS = $1042;
  SFC_CALC_NORM_MAX_ALL_CHANNELS = $1043;
  SFC_GET_SIGNAL_MAX = $1044;
  SFC_GET_MAX_ALL_CHANNELS = $1045;

  SFC_SET_ADD_PEAK_CHUNK = $1050;

  SFC_UPDATE_HEADER_NOW = $1060;
  SFC_SET_UPDATE_HEADER_AUTO = $1061;

  SFC_FILE_TRUNCATE = $1080;

  SFC_SET_RAW_START_OFFSET = $1090;

  SFC_SET_DITHER_ON_WRITE = $10A0;
  SFC_SET_DITHER_ON_READ = $10A1;

  SFC_GET_DITHER_INFO_COUNT = $10A2;
  SFC_GET_DITHER_INFO = $10A3;

  SFC_GET_EMBED_FILE_INFO = $10B0;

  SFC_SET_CLIPPING = $10C0;
  SFC_GET_CLIPPING = $10C1;

  SFC_GET_INSTRUMENT = $10D0;
  SFC_SET_INSTRUMENT = $10D1;

  SFC_GET_LOOP_INFO = $10E0;

  SFC_GET_BROADCAST_INFO = $10F0;
  SFC_SET_BROADCAST_INFO = $10F1;

  // Following commands for testing only.
  SFC_TEST_IEEE_FLOAT_REPLACE = $6001;

  {
  ** SFC_SET_ADD_* values are deprecated and will disappear at some
  ** time in the future. They are guaranteed to be here up to and
  ** including version 1.0.8 to avoid breakage of existing software.
  ** They currently do nothing and will continue to do nothing.
  }
  SFC_SET_ADD_DITHER_ON_WRITE = $1070;
  SFC_SET_ADD_DITHER_ON_READ = $1071;

{
** String types that can be set and read from files. Not all file types
** support this and even the file types which support one, may not support
** all string types.
}
const
  SF_STR_TITLE = $01;
  SF_STR_COPYRIGHT = $02;
  SF_STR_SOFTWARE = $03;
  SF_STR_ARTIST = $04;
  SF_STR_COMMENT = $05;
  SF_STR_DATE = $06;
  SF_STR_ALBUM = $07;
  SF_STR_LICENSE = $08;
  SF_STR_TRACKNUMBER = $09;
  SF_STR_GENRE = $10;

{
** Use the following as the start and end index when doing metadata
** transcoding.
}
  SF_STR_FIRST = SF_STR_TITLE;
  SF_STR_LAST = SF_STR_GENRE;

const
  // True and false
  SF_FALSE = 0;
  SF_TRUE = 1;

const
  // Modes for opening files.
  SFM_READ = $10;
  SFM_WRITE = $20;
  SFM_RDWR = $30;

{
** Public error values. These are guaranteed to remain unchanged
** for the duration of the library major version number.
** There are also a large number of private error numbers which are
** internal to the library which can change at any time.
}
const
  SF_ERR_NO_ERROR = 0;
  SF_ERR_UNRECOGNISED_FORMAT = 1;
  SF_ERR_SYSTEM = 2;
  SF_ERR_MALFORMED_FILE = 3;
  SF_ERR_UNSUPPORTED_ENCODING = 4;

//A SNDFILE* pointer can be passed around much like stdio.h's FILE* pointer.

type
  TSNDFILE_HANDLE = pointer;  // this is not a usual pointer, more like a THandle ..
// so NOT called  "PSndFile_handle"
// => we never access members of the internal
//    structure where the pointer points to !
//    Everything is managed by the DLL internally !!!
//PSNDFILE_tag = PSNDFILE;

  {
** The following typedef is system specific and is defined when libsndfile is.
** compiled. uos_count_t can be one of loff_t (Linux), off_t (*BSD),
** off64_t (Solaris), __int64_t (Win32) etc.
}
type
  Puos_count_t = ^Tuos_count_t;
  Tuos_count_t = off_t;

const
  SF_COUNT_MAX = ctypes.clonglong($7FFFFFFFFFFFFFFF);

{
** A pointer to a SF_INFO structure is passed to sf_open_read () and filled in.
** On write, the SF_INFO structure is filled in by the user and passed into
** sf_open_write ().
}

type
  PSF_INFO = ^TSF_INFO;

  TSF_INFO = record
    frames: Tuos_count_t;
    // Used to be called samples.  Changed to avoid confusion.
    samplerate: ctypes.cint;
    channels: ctypes.cint;
    format: ctypes.cint;
    sections: ctypes.cint;
    seekable: ctypes.cint;
  end;

{
** The SF_FORMAT_INFO struct is used to retrieve information about the sound
** file formats libsndfile supports using the sf_command () interface.
**
** Using this interface will allow applications to support new file formats
** and encoding types when libsndfile is upgraded, without requiring
** re-compilation of the application.
**
** Please consult the libsndfile documentation (particularly the information
** on the sf_command () interface) for examples of its use.
}

type
  PSF_FORMAT_INFO = ^TSF_FORMAT_INFO;

  TSF_FORMAT_INFO = record
    format: ctypes.cint;
    Name: ctypes.pcchar;
    extention: ctypes.pcchar;
  end;

{
** Enums and typedefs for adding dither on read and write.
** See the html documentation for sf_command(), SFC_SET_DITHER_ON_WRITE
** and SFC_SET_DITHER_ON_READ.
}
const
  SFD_DEFAULT_LEVEL = 0;
  SFD_CUSTOM_LEVEL = $40000000;

  SFD_NO_DITHER = 500;
  SFD_WHITE = 501;
  SFD_TRIANGULAR_PDF = 502;

type
  PSF_DITHER_INFO = ^TSF_DITHER_INFO;

  TSF_DITHER_INFO = record
    type_: ctypes.cint;
    level: ctypes.cdouble;
    Name: ctypes.pcchar;
  end;

{
** Struct used to retrieve information about a file embedded within a
** larger file. See SFC_GET_EMBED_FILE_INFO.
}
type
  PSF_EMBED_FILE_INFO = ^TSF_EMBED_FILE_INFO;

  TSF_EMBED_FILE_INFO = record
    offset: Tuos_count_t;
    length: Tuos_count_t;
  end;

// Structs used to retrieve music sample information from a file.

const
  // The loop mode field in SF_INSTRUMENT will be one of the following.
  SF_LOOP_NONE = 800;
  SF_LOOP_FORWARD = 801;
  SF_LOOP_BACKWARD = 802;
  SF_LOOP_ALTERNATING = 803;

type
  PSF_INSTRUMENT = ^TSF_INSTRUMENT;

  TSF_INSTRUMENT = record
    gain: ctypes.cint;
    basenote,
    detune: ctypes.cchar;
    velocity_lo,
    velocity_hi: ctypes.cchar;
    loop_count: ctypes.cint;
    loops: array[0..15] of record
      mode: ctypes.cint;
      start: ctypes.cuint;
      end_: ctypes.cuint;
      Count: ctypes.cuint;
    end;
  end;

// Struct used to retrieve loop information from a file.
type
  PSF_LOOP_INFO = ^TSF_LOOP_INFO;

  TSF_LOOP_INFO = record
    time_sig_num: ctypes.cushort;
    // any positive integer    > 0
    time_sig_den: ctypes.cushort;
    // any positive power of 2 > 0
    loop_mode: ctypes.cint;                // see SF_LOOP enum

    num_beats: ctypes.cint;
    // this is NOT the amount of quarter notes !!!
    // a full bar of 4/4 is 4 beats
    // a full bar of 7/8 is 7 beats

    bpm: ctypes.cfloat;
    // suggestion, as it can be calculated using other fields:
    // file's lenght, file's sampleRate and our time_sig_den
    // -> bpms are always the amount of _quarter notes_ per minute

    root_key: ctypes.cint;
    // MIDI note, or -1 for None
    future: array[0..5] of ctypes.cint;
  end;


{
**  Struct used to retrieve broadcast (EBU) information from a file.
**  Strongly (!) based on EBU "bext" chunk format used in Broadcast WAVE.
}
type
  PSF_BROADCAST_INFO = ^TSF_BROADCAST_INFO;

  TSF_BROADCAST_INFO = record
    description: array[0..255] of char;//ctypes.cchar;
    originator: array[0..31] of char;//ctypes.cchar;
    originator_reference: array[0..31] of char;//ctypes.cchar;
    origination_date: array[0..9] of char;//ctypes.cchar;
    origination_time: array[0..7] of char;//ctypes.cchar;
    time_reference_low: ctypes.cuint;//ctypes.cint;
    time_reference_high: ctypes.cuint;//ctypes.cint;
    version: ctypes.cshort;
    umid: array[0..63] of char;//ctypes.cchar;
    reserved: array[0..189] of char;//ctypes.cchar;
    coding_history_size: ctypes.cuint;
    coding_history: array[0..255] of char;//ctypes.cchar;
  end;

 // Thanks to Phoenix
 type
 //pm_get_filelen = ^tm_get_filelen;
 tm_get_filelen =
  function (pms: PMemoryStream): Tuos_count_t; cdecl; 
 //pm_seek = ^tm_seek;
 tm_seek =
  function (offset: Tuos_count_t; whence: cint32; pms: PMemoryStream): Tuos_count_t; cdecl; 
 //pm_read = ^tm_read;
 tm_read =
  function (const buf: Pointer; count: Tuos_count_t; pms: PMemoryStream): Tuos_count_t; cdecl; 
 //pm_write = ^tm_write;
 tm_write =
  function (const buf: Pointer; count: Tuos_count_t; pms: PMemoryStream): Tuos_count_t; cdecl; 
 //pm_tell = ^tm_tell;
 tm_tell =
  function (pms: PMemoryStream): Tuos_count_t; cdecl; 
 
 TSF_VIRTUAL = packed record
  sf_vio_get_filelen  : tm_get_filelen;
  seek         : tm_seek;
  read         : tm_read;
  write        : tm_write;
  tell         : tm_tell;
 end;
 
 PSF_VIRTUAL = ^TSF_VIRTUAL;  
 
{
** Open the specified file for read, write or both. On error, this will
** return a NULL pointer. To find the error number, pass a NULL SNDFILE
** to sf_perror () or sf_error_str ().
** All calls to sf_open() should be matched with a call to sf_close().
}
////////////////////////////////////////////////////////////////////////////////////////

function sf_open(path: string; mode: ctypes.cint;
  var sfinfo: TSF_INFO): TSNDFILE_HANDLE;

////// Dynamic load : Vars that will hold our dynamically loaded functions..
var
  sf_open_native: function(path: PChar;
  mode: ctypes.cint; sfinfo: PSF_INFO): TSNDFILE_HANDLE; cdecl;

var
sf_version_string: function(): PChar; cdecl;

var
  sf_open_fd: function(fd: ctypes.cint; mode: ctypes.cint; sfinfo: PSF_INFO;
  close_desc: ctypes.cint): TSNDFILE_HANDLE; cdecl;

var
  sf_open_virtual: function(sfvirtual: PSF_VIRTUAL; mode: ctypes.cint;
  sfinfo: PSF_INFO; user_data: Pointer): TSNDFILE_HANDLE; cdecl;

var
  sf_error: function(sndfile: TSNDFILE_HANDLE): ctypes.cint; cdecl;

var
  sf_strerror: function(sndfile: TSNDFILE_HANDLE): PChar; cdecl;

var
  sf_error_number: function(errnum: ctypes.cint): PChar; cdecl;

var
  sf_perror: function(sndfile: TSNDFILE_HANDLE): ctypes.cint; cdecl;

var
  sf_error_str: function(sndfile: TSNDFILE_HANDLE;
  str: ctypes.pcchar; len: size_t): ctypes.cint; cdecl;

{
 In libsndfile there are 4 functions with the same name (sf_command), 3 of them use the parameter "overload".
 In dynamic loading (because of var) we use 4 different names for the 4 functions sf_command :
 sf_command_pointer, sf_command_double, sf_command_array, sf_command_tsf. All that 4 functions gonna point
 to sf_command in libsndfile library.
}

var
  sf_command_pointer: function(sndfile: TSNDFILE_HANDLE; command: ctypes.cint;
  Data: Pointer; datasize: ctypes.cint): ctypes.cint; cdecl;

var
  sf_command_double: function(sndfile: TSNDFILE_HANDLE; command: ctypes.cint;
  var Data: double; datasize: ctypes.cint): ctypes.cint; cdecl;

var
  sf_command_array: function(sndfile: TSNDFILE_HANDLE; command: ctypes.cint;
  var Data: array of char; datasize: ctypes.cint): ctypes.cint; cdecl;

var
  sf_command_tsf: function(sndfile: TSNDFILE_HANDLE; command: ctypes.cint;
  var Data: TSF_BROADCAST_INFO; datasize: ctypes.cint): ctypes.cint; cdecl;

var
  sf_format_check: function(var info: TSF_INFO): ctypes.cint; cdecl;

{
** Seek within the waveform data chunk of the SNDFILE. sf_seek () uses
** the same values for whence (SEEK_SET, SEEK_CUR and SEEK_END) as
** stdio.h function fseek ().
** An offset of zero with whence set to SEEK_SET will position the
** read / write pointer to the first data sample.
** On success sf_seek returns the current position in (multi-channel)
** samples from the start of the file.
** Please see the libsndfile documentation for moving the read pointer
** separately from the write pointer on files open in mode SFM_RDWR.
** On error all of these functions return -1.
}

//the following CONST values originally are NOT in libsndfile.pas:
const
  SEEK_SET = 0;       //* seek relative to beginning of file */

const
  SEEK_CUR = 1;       //* seek relative to current file position */

const
  SEEK_END = 2;       //* seek relative to end of file */

const
  SEEK_DATA = 3;       //* seek to the next data */

const
  SEEK_HOLE = 4;       //* seek to the next hole */

const
  SEEK_MAX = SEEK_HOLE;

var
  sf_seek: function(sndfile: TSNDFILE_HANDLE; frame: Tuos_count_t;
  whence: ctypes.cint): Tuos_count_t; cdecl;

{
** Functions for retrieving and setting string data within sound files.
** Not all file types support this features; AIFF and WAV do. For both
** functions, the str_type parameter must be one of the SF_STR_* values
** defined above.
** On error, sf_set_string() returns non-zero while sf_get_string()
** returns NULL.
}
var
  sf_set_string: function(sndfile: TSNDFILE_HANDLE; str_type: ctypes.cint;
  str: ctypes.pcchar): ctypes.cint; cdecl;

var
  sf_get_string: function(sndfile: TSNDFILE_HANDLE;
  str_type: ctypes.cint): PChar; cdecl;

var
  sf_read_raw: function(sndfile: TSNDFILE_HANDLE; ptr: Pointer;
  bytes: Tuos_count_t): Tuos_count_t; cdecl;

var
  sf_write_raw: function(sndfile: TSNDFILE_HANDLE; ptr: Pointer;
  bytes: Tuos_count_t): Tuos_count_t; cdecl;

{
** Functions for reading and writing the data chunk in terms of frames.
** The number of items actually read/written = frames * number of channels.
**     sf_xxxx_raw  read/writes the raw data bytes from/to the file
**     sf_xxxx_short  passes data in the native short format
**     sf_xxxx_int  passes data in the native int format
**     sf_xxxx_float  passes data in the native float format
**     sf_xxxx_double  passes data in the native double format
** All of these read/write function return number of frames read/written.
}
var
  sf_readf_short: function(sndfile: TSNDFILE_HANDLE; ptr: ctypes.pcshort;
  frames: Tuos_count_t): Tuos_count_t; cdecl;

var
  sf_writef_short: function(sndfile: TSNDFILE_HANDLE; ptr: ctypes.pcshort;
  frames: Tuos_count_t): Tuos_count_t; cdecl;

var
  sf_readf_int: function(sndfile: TSNDFILE_HANDLE; ptr: ctypes.pcint;
  frames: Tuos_count_t): Tuos_count_t; cdecl;

var
  sf_writef_int: function(sndfile: TSNDFILE_HANDLE; ptr: ctypes.pcint;
  frames: Tuos_count_t): Tuos_count_t; cdecl;

var
  sf_readf_float: function(sndfile: TSNDFILE_HANDLE; ptr: ctypes.pcfloat;
  frames: Tuos_count_t): Tuos_count_t; cdecl;

var
  sf_writef_float: function(sndfile: TSNDFILE_HANDLE; ptr: ctypes.pcfloat;
  frames: Tuos_count_t): Tuos_count_t; cdecl;

var
  sf_readf_double: function(sndfile: TSNDFILE_HANDLE; ptr: ctypes.pcdouble;
  frames: Tuos_count_t): Tuos_count_t; cdecl;

var
  sf_writef_double: function(sndfile: TSNDFILE_HANDLE; ptr: ctypes.pcdouble;
  frames: Tuos_count_t): Tuos_count_t; cdecl;

{
** Functions for reading and writing the data chunk in terms of items.
** Otherwise similar to above.
** All of these read/write function return number of items read/written.
}
var
  sf_read_short: function(sndfile: TSNDFILE_HANDLE; ptr: ctypes.pcshort;
  frames: Tuos_count_t): Tuos_count_t; cdecl;

var
  sf_write_short: function(sndfile: TSNDFILE_HANDLE; ptr: ctypes.pcshort;
  frames: Tuos_count_t): Tuos_count_t; cdecl;

var
  sf_read_int: function(sndfile: TSNDFILE_HANDLE; ptr: ctypes.pcint;
  frames: Tuos_count_t): Tuos_count_t; cdecl;

var
  sf_write_int: function(sndfile: TSNDFILE_HANDLE; ptr: ctypes.pcint;
  frames: Tuos_count_t): Tuos_count_t; cdecl;

var
  sf_read_float: function(sndfile: TSNDFILE_HANDLE; ptr: ctypes.pcfloat;
  frames: Tuos_count_t): Tuos_count_t; cdecl;

var
  sf_write_float: function(sndfile: TSNDFILE_HANDLE; ptr: ctypes.pcfloat;
  frames: Tuos_count_t): Tuos_count_t; cdecl;

var
  sf_read_double: function(sndfile: TSNDFILE_HANDLE; ptr: ctypes.pcdouble;
  frames: Tuos_count_t): Tuos_count_t; cdecl;

var
  sf_write_double: function(sndfile: TSNDFILE_HANDLE; ptr: ctypes.pcdouble;
  frames: Tuos_count_t): Tuos_count_t; cdecl;

{
** Close the SNDFILE and clean up all memory allocations associated
** with this file.
** Returns 0 on success, or an error number.
}
var
  sf_close: function(sndfile: TSNDFILE_HANDLE): ctypes.cint; cdecl;

{
** If the file is opened SFM_WRITE or SFM_RDWR, call fsync() on the file
** to force the writing of data to disk. If the file is opened SFM_READ
** no action is taken.
}
var
  sf_write_sync: function(sndfile: TSNDFILE_HANDLE): ctypes.cint; cdecl;

{Special function for dynamic loading of lib ...}

var
  sf_Handle: TLibHandle;
// this will hold our handle for the lib; it functions nicely as a mutli-lib prevention unit as well...

function sf_Load(const libfilename: string): boolean; // load the lib

procedure sf_Unload();
// unload and frees the lib from memory : do not forget to call it before close application.

function sf_IsLoaded: boolean;

implementation

var
  ReferenceCounter: cardinal = 0;  // Reference counter

function sf_Load(const libfilename: string): boolean;
var
thelib: string; 
begin
  Result := False;
  if sf_Handle <> 0 then
  begin
    Result := True {is it already there ?};
    //Reference counting
    Inc(ReferenceCounter);
  end
  else
  begin {go & load the library}
   if Length(libfilename) = 0 then thelib := libsf else thelib := libfilename;
    sf_Handle := DynLibs.SafeLoadLibrary(thelib); // obtain the handle we want
    if sf_Handle <> DynLibs.NilHandle then
    begin {now we tie the functions to the VARs from above}
      
      Pointer(sf_version_string) := DynLibs.GetProcedureAddress(sf_Handle, PChar('sf_version_string'));
      Pointer(sf_open_native) := DynLibs.GetProcedureAddress(sf_Handle, PChar('sf_open'));
      Pointer(sf_open_fd) := DynLibs.GetProcedureAddress(sf_Handle, PChar('sf_open_fd'));
      Pointer(sf_open_virtual) := DynLibs.GetProcedureAddress(
        sf_Handle, PChar('sf_open_virtual'));
      Pointer(sf_error) := DynLibs.GetProcedureAddress(sf_Handle, PChar('sf_error'));
      Pointer(sf_strerror) := DynLibs.GetProcedureAddress(sf_Handle, PChar('sf_strerror'));
      Pointer(sf_error_number) := DynLibs.GetProcedureAddress(
        sf_Handle, PChar('sf_error_number'));
      Pointer(sf_perror) := DynLibs.GetProcedureAddress(sf_Handle, PChar('sf_perror'));
      Pointer(sf_error_str) := DynLibs.GetProcedureAddress(sf_Handle, PChar('sf_error_str'));
      Pointer(sf_command_pointer) := DynLibs.GetProcedureAddress(sf_Handle, PChar('sf_command'));
      Pointer(sf_command_array) := DynLibs.GetProcedureAddress(sf_Handle, PChar('sf_command'));
      Pointer(sf_command_double) := DynLibs.GetProcedureAddress(sf_Handle, PChar('sf_command'));
      Pointer(sf_command_tsf) := DynLibs.GetProcedureAddress(sf_Handle, PChar('sf_command'));
      Pointer(sf_format_check) := DynLibs.GetProcedureAddress(
        sf_Handle, PChar('sf_format_check'));
      Pointer(sf_seek) := DynLibs.GetProcedureAddress(sf_Handle, PChar('sf_seek'));
      Pointer(sf_set_string) := DynLibs.GetProcedureAddress(sf_Handle, PChar('sf_set_string'));
      Pointer(sf_get_string) := DynLibs.GetProcedureAddress(sf_Handle, PChar('sf_get_string'));
      Pointer(sf_read_raw) := DynLibs.GetProcedureAddress(sf_Handle, PChar('sf_read_raw'));
      Pointer(sf_write_raw) := DynLibs.GetProcedureAddress(sf_Handle, PChar('sf_write_raw'));
      Pointer(sf_readf_short) := DynLibs.GetProcedureAddress(sf_Handle, PChar('sf_readf_short'));
      Pointer(sf_writef_short) := DynLibs.GetProcedureAddress(
        sf_Handle, PChar('sf_writef_short'));
      Pointer(sf_readf_int) := DynLibs.GetProcedureAddress(sf_Handle, PChar('sf_readf_int'));
      Pointer(sf_writef_int) := DynLibs.GetProcedureAddress(sf_Handle, PChar('sf_writef_int'));
      Pointer(sf_readf_float) := DynLibs.GetProcedureAddress(sf_Handle, PChar('sf_readf_float'));
      Pointer(sf_writef_float) := DynLibs.GetProcedureAddress(
        sf_Handle, PChar('sf_writef_float'));
      Pointer(sf_readf_double) := DynLibs.GetProcedureAddress(
        sf_Handle, PChar('sf_readf_double'));
      Pointer(sf_writef_double) := DynLibs.GetProcedureAddress(
        sf_Handle, PChar('sf_writef_double'));
      Pointer(sf_read_short) := DynLibs.GetProcedureAddress(sf_Handle, PChar('sf_read_short'));
      Pointer(sf_write_short) := DynLibs.GetProcedureAddress(sf_Handle, PChar('sf_write_short'));
      Pointer(sf_read_int) := DynLibs.GetProcedureAddress(sf_Handle, PChar('sf_read_int'));
      Pointer(sf_write_int) := DynLibs.GetProcedureAddress(sf_Handle, PChar('sf_write_int'));
      Pointer(sf_read_float) := DynLibs.GetProcedureAddress(sf_Handle, PChar('sf_read_float'));
      Pointer(sf_write_float) := DynLibs.GetProcedureAddress(sf_Handle, PChar('sf_write_float'));
      Pointer(sf_read_double) := DynLibs.GetProcedureAddress(sf_Handle, PChar('sf_read_double'));
      Pointer(sf_write_double) := DynLibs.GetProcedureAddress(
        sf_Handle, PChar('sf_write_double'));
      Pointer(sf_close) := DynLibs.GetProcedureAddress(sf_Handle, PChar('sf_close'));
      Pointer(sf_write_sync) := DynLibs.GetProcedureAddress(sf_Handle, PChar('sf_write_sync'));

    end;
    Result := sf_IsLoaded;
    ReferenceCounter := 1;
  end;

end;

procedure sf_Unload;
begin
  // < Reference counting
  if ReferenceCounter > 0 then
    Dec(ReferenceCounter);
  if ReferenceCounter > 0 then
    exit;
  // >
  if sf_IsLoaded then
  begin
    DynLibs.UnloadLibrary(sf_Handle);
    sf_Handle := DynLibs.NilHandle;
  end;

end;

function sf_open(path: string; mode: ctypes.cint;
  var sfinfo: TSF_INFO): TSNDFILE_HANDLE;
begin
  Result := sf_open_native(PChar(path), mode, @sfinfo);
end;

function sf_IsLoaded: boolean;
begin
  Result := (sf_Handle <> dynlibs.NilHandle);
end;

end.
