unit dgSoundUses;
// ---------------------------------------------------------------------------//
// Copyright © 2005-2011 DunconGames. All rights reserved. BSD License. Authors: Duncon (07.11.2010)
// ---------------------------------------------------------------------------//
interface

const
  vStartQuantity: Integer = 128;//Количество ячеек создаваемое под элементы списков по умолчанию, во избежание фрагментации.
  {$IFDEF MSWINDOWS}
    kernel32  = 'kernel32.dll';
    user32    = 'user32.dll';
    VorbisLib = 'soundlib/vorbisfile.dll';
    AL32 = 'soundlib/OpenAL32.dll'; //v6.14.357.22, wrap_oal.dll v2.1.8.1
  {$ENDIF}
  {$IFDEF LINUX}
    {$IFDEF FPC} //freepascal/Lazarus
      //???
    {$ELSE}         //Delphi for linux? Don't think..
      //kernel32  = 'libwine.borland.so';
      //user32    = 'libwine.borland.so';
      //VorbisLib = 'soundlib/vorbisfile.so';
      //AL32 = 'soundlib/openal.so';
    {$ENDIF}
  {$ENDIF}
  LANG_USER_DEFAULT = ($01{SUBLANG_DEFAULT} shl 10) or $00{LANG_NEUTRAL};
  LOCALE_USER_DEFAULT = ($0{SORT_DEFAULT} shl 16) or LANG_USER_DEFAULT;
  PathDelim = {$IFDEF MSWINDOWS} '\'; {$ELSE} '/'; {$ENDIF}
  DriveDelim = {$IFDEF MSWINDOWS} ':'; {$ELSE} ''; {$ENDIF}
  MAX_PATH = 260; {$EXTERNALSYM MAX_PATH}
  faReadOnly  = $00000001 platform;
  faHidden    = $00000002 platform;
  faSysFile   = $00000004 platform;
  faDirectory = $00000010;
  faAnyFile   = $000001FF;

var
  LeadBytes: set of AnsiChar = [];
type
  //DWORD = LongWord;{$EXTERNALSYM DWORD}
  //DWORD = Types.DWORD;{$EXTERNALSYM DWORD}
  TSysCharSet = set of AnsiChar;
  TMbcsByteType = (mbSingleByte, mbLeadByte, mbTrailByte);
  TSysLocale = packed record
    DefaultLCID, PriLangID, SubLangID: Integer;
    FarEast, MiddleEast: Boolean;
  end;
  PSecurityAttributes = ^TSecurityAttributes;
  _SECURITY_ATTRIBUTES = record
    nLength: LongWord{DWORD};
    lpSecurityDescriptor: Pointer;
    bInheritHandle: LongBool{BOOL};
  end;
  {$EXTERNALSYM _SECURITY_ATTRIBUTES}
  TSecurityAttributes = _SECURITY_ATTRIBUTES;
  POverlapped = ^TOverlapped;
  _OVERLAPPED = record
    Internal: LongWord{DWORD};
    InternalHigh: LongWord{DWORD};
    Offset: LongWord{DWORD};
    OffsetHigh: LongWord{DWORD};
    hEvent: THandle;
  end;
  {$EXTERNALSYM _OVERLAPPED}
  TOverlapped = _OVERLAPPED;
  HWND = type LongWord;
  {$EXTERNALSYM HWND}
  TFarProc = Pointer;
  TFNTimerProc = TFarProc;

{$IFDEF MSWINDOWS}
  { File System time stamps are represented with the following structure: }
  PFileTime = ^TFileTime;
  _FILETIME = record
    dwLowDateTime: LongWord{DWORD};
    dwHighDateTime: LongWord{DWORD};
  end;
  {$EXTERNALSYM _FILETIME}
  TFileTime = _FILETIME;
  FILETIME = _FILETIME;
  {$EXTERNALSYM FILETIME}
{$ENDIF}
{$IFDEF LINUX}
  _FILETIME = Types._FILETIME;
  {$EXTERNALSYM _FILETIME}
  PFileTime = Types.PFileTime;
  TFileTime = Types.TFileTime;
  FILETIME = Types.FILETIME;
  {$EXTERNALSYM FILETIME}
{$ENDIF}
  _WIN32_FIND_DATAW = record
    dwFileAttributes: LongWord{DWORD};
    ftCreationTime: TFileTime;
    ftLastAccessTime: TFileTime;
    ftLastWriteTime: TFileTime;
    nFileSizeHigh: LongWord{DWORD};
    nFileSizeLow: LongWord{DWORD};
    dwReserved0: LongWord{DWORD};
    dwReserved1: LongWord{DWORD};
    cFileName: array[0..MAX_PATH - 1] of WideChar;
    cAlternateFileName: array[0..13] of WideChar;
  end;
  {$EXTERNALSYM _WIN32_FIND_DATAW}
  TWin32FindDataW = _WIN32_FIND_DATAW;
  TWin32FindData = TWin32FindDataW;
  TFileName = type string;
  TSearchRec = record
    Time: Integer;
    Size: Int64;
    Attr: Integer;
    Name: TFileName;
    ExcludeAttr: Integer;
{$IFDEF MSWINDOWS}
    FindHandle: Int64;{THandle  platform;}
    FindData: TWin32FindData  platform;
{$ENDIF MSWINDOWS}
{$IFDEF POSIX}
    Mode: mode_t  platform;
    FindHandle: Pointer  platform;
    PathOnly: String  platform;
    Pattern: String  platform;
{$ENDIF POSIX}
  end;
  LongRec = packed record
    case Integer of
      0: (Lo, Hi: Word);
      1: (Words: array [0..1] of Word);
      2: (Bytes: array [0..3] of Byte);
  end;
//------------------------------------------------------------------------------
{$IFDEF dgR}{$REGION '      EAX2.0      '}{$ENDIF}
const
  EAX_ListenerProperties: TGuid = '{0306A6A8-B224-11d2-99E5-0000E8D8C722}';
  EAX_BufferProperties: TGuid = '{0306A6A7-B224-11d2-99E5-0000E8D8C722}';
  //Enumerations EAX_ListenerProperties
  DSPROPERTY_EAXLISTENER_NONE = 0;
  DSPROPERTY_EAXLISTENER_ALLPARAMETERS = 1;
  EAX_ListenerEnvironment = 11;
  //DSPROPERTY_EAXLISTENER_FLAGS             = 15;
  // OR these flags with property id
  DSPROPERTY_EAXLISTENER_IMMEDIATE = $00000000;
  DSPROPERTY_EAXLISTENER_DEFERRED = LongWord($80000000);//DWord($80000000);// changes take effect immediately
  DSPROPERTY_EAXLISTENER_COMMITDEFERREDSETTINGS = (DSPROPERTY_EAXLISTENER_NONE or DSPROPERTY_EAXLISTENER_IMMEDIATE);
  // used by DSPROPERTY_EAXLISTENER_ENVIRONMENT
  //Enummetation
  EAX_Generic = 0; //Родильная
  EAX_PaddedCell = 1; //Обитая войлоком палата
  EAX_Room = 2; //Комната
  EAX_BathRoom = 3; //Ванная комната
  EAX_LivingRoom = 4; //Гостиная комната
  EAX_StoneRoom = 5; //Каменная комната
  EAX_Auditorium = 6; //Аудитория
  EAX_ConcertHall = 7; //Концертный зал
  EAX_Cave = 8; //Пещера
  EAX_Arena = 9; //Арена
  EAX_Hangar = 10; //Ангар
  EAX_CarpetedHallway = 11; //Покрытая коврами Прихожая
  EAX_Hallway = 12; //Прихожая
  EAX_StoneCorridor = 13; //Каменный Коридор
  EAX_Alley = 14; //Аллея, Узкая улица, Переулок
  EAX_Forest = 15; //Лес
  EAX_City = 16; //Город
  EAX_Mountains = 17; //Горы
  EAX_Quarry = 18; //Карьер
  EAX_Plain = 19; //Равнина
  EAX_ParkingLot = 20; //Автостоянка
  EAX_SewerPipe = 21; //Труба Коллектора
  EAX_UnderWater = 22; //Под Водой
  EAX_Drugged = 23; //Наркотический
  EAX_Dizzy = 24; //Головокружительный
  EAX_Psychotic = 25; //Психотический
  EAX_Count = 26;
  // Used by DSPROPERTY_EAXLISTENER_FLAGS
  //
  // Note: The number and order of flags may change in future EAX versions.
  //       It is recommended to use the flag defines as follows:
  //              myFlags = EAXLISTENERFLAGS_DECAYTIMESCALE | EAXLISTENERFLAGS_REVERBSCALE;
  //       instead of:
  //              myFlags = 0x00000009;
  //
  // These flags determine what properties are affected by environment size.
  EAXLISTENERFLAGS_DECAYTIMESCALE = $00000001;
  // reverberation decay time
  EAXLISTENERFLAGS_REFLECTIONSSCALE = $00000002; // reflection level
  EAXLISTENERFLAGS_REFLECTIONSDELAYSCALE = $00000004;
  // initial reflection delay time
  EAXLISTENERFLAGS_REVERBSCALE = $00000008; // reflections level
  EAXLISTENERFLAGS_REVERBDELAYSCALE = $00000010;
  // late reverberation delay time

  // This flag limits high-frequency decay time according to air absorption.
  EAXLISTENERFLAGS_DECAYHFLIMIT = $00000020;
  EAXLISTENERFLAGS_RESERVED = $FFFFFFC0; // reserved future use
  {
  // property ranges and defaults:
  EAXLISTENER_MINROOM                      = -10000;
  EAXLISTENER_MAXROOM                      = 0;
  EAXLISTENER_DEFAULTROOM                  = -1000;

  EAXLISTENER_MINROOMHF                    = -10000;
  EAXLISTENER_MAXROOMHF                    = 0;
  EAXLISTENER_DEFAULTROOMHF                = -100;

  EAXLISTENER_MINROOMROLLOFFFACTOR         = 0.0;
  EAXLISTENER_MAXROOMROLLOFFFACTOR         = 10.0;
  EAXLISTENER_DEFAULTROOMROLLOFFFACTOR     = 0.0;

  EAXLISTENER_MINDECAYTIME                 = 0.1;
  EAXLISTENER_MAXDECAYTIME                 = 20.0;
  EAXLISTENER_DEFAULTDECAYTIME             = 1.49;

  EAXLISTENER_MINDECAYHFRATIO              = 0.1;
  EAXLISTENER_MAXDECAYHFRATIO              = 2.0;
  EAXLISTENER_DEFAULTDECAYHFRATIO          = 0.83;

  EAXLISTENER_MINREFLECTIONS               = -10000;
  EAXLISTENER_MAXREFLECTIONS               = 1000;
  EAXLISTENER_DEFAULTREFLECTIONS           = -2602;

  EAXLISTENER_MINREFLECTIONSDELAY          = 0.0;
  EAXLISTENER_MAXREFLECTIONSDELAY          = 0.3;
  EAXLISTENER_DEFAULTREFLECTIONSDELAY      = 0.007;

  EAXLISTENER_MINREVERB                    = -10000;
  EAXLISTENER_MAXREVERB                    = 2000;
  EAXLISTENER_DEFAULTREVERB                = 200;

  EAXLISTENER_MINREVERBDELAY               = 0.0;
  EAXLISTENER_MAXREVERBDELAY               = 0.1;
  EAXLISTENER_DEFAULTREVERBDELAY           = 0.011;

  EAXLISTENER_MINENVIRONMENT               = 0;
  EAXLISTENER_MAXENVIRONMENT               = EAX_Count - 1;
  EAXLISTENER_DEFAULTENVIRONMENT           = EAX_Generic;

  EAXLISTENER_MINENVIRONMENTSIZE           = 1.0;
  EAXLISTENER_MAXENVIRONMENTSIZE           = 100.0;
  EAXLISTENER_DEFAULTENVIRONMENTSIZE       = 7.5;

  EAXLISTENER_MINENVIRONMENTDIFFUSION      = 0.0;
  EAXLISTENER_MAXENVIRONMENTDIFFUSION      = 1.0;
  EAXLISTENER_DEFAULTENVIRONMENTDIFFUSION  = 1.0;

  EAXLISTENER_MINAIRABSORPTIONHF           = -100.0;
  EAXLISTENER_MAXAIRABSORPTIONHF           = 0.0;
  EAXLISTENER_DEFAULTAIRABSORPTIONHF       = -5.0;
  }

  EAXLISTENER_DEFAULTFLAGS = EAXLISTENERFLAGS_DECAYTIMESCALE or
    EAXLISTENERFLAGS_REFLECTIONSSCALE or EAXLISTENERFLAGS_REFLECTIONSDELAYSCALE or
    EAXLISTENERFLAGS_REVERBSCALE or EAXLISTENERFLAGS_REVERBDELAYSCALE or
    EAXLISTENERFLAGS_DECAYHFLIMIT;
  // For compatibility with future EAX versions:
  //DSPROPSETID_EAX_BufferProperties = DSPROPSETID_EAX20_BufferProperties;

  //Enumeration DSPROPERTY_EAX_BUFFERPROPERTY
  DSPROPERTY_EAXBUFFER_NONE = 0;
  //DSPROPERTY_EAXBUFFER_ALLPARAMETERS       = 1;
  //  DSPROPERTY_EAXBUFFER_DIRECT              = 2;
  //  DSPROPERTY_EAXBUFFER_DIRECTHF            = 3;
  //  DSPROPERTY_EAXBUFFER_ROOM                = 4;
  //  DSPROPERTY_EAXBUFFER_ROOMHF              = 5;
  //  DSPROPERTY_EAXBUFFER_ROOMROLLOFFFACTOR   = 6;
  //  DSPROPERTY_EAXBUFFER_OBSTRUCTION         = 7;
  //  DSPROPERTY_EAXBUFFER_OBSTRUCTIONLFRATIO  = 8;
  //  DSPROPERTY_EAXBUFFER_OCCLUSION           = 9;
  //  DSPROPERTY_EAXBUFFER_OCCLUSIONLFRATIO    = 10;
  //  DSPROPERTY_EAXBUFFER_OCCLUSIONROOMRATIO  = 11;
  //  DSPROPERTY_EAXBUFFER_OUTSIDEVOLUMEHF     = 12;
  //  DSPROPERTY_EAXBUFFER_AIRABSORPTIONFACTOR = 13;
  DSPROPERTY_EAXBUFFER_FLAG = 14;

  // OR these flags with property id
  DSPROPERTY_EAXBUFFER_IMMEDIATE = $00000000;
  // changes take effect immediately
  DSPROPERTY_EAXBUFFER_DEFERRED = LongWord($80000000);//DWord($80000000);
  DSPROPERTY_EAXBUFFER_COMMITDEFERREDSETTINGS = DSPROPERTY_EAXBUFFER_NONE or
    DSPROPERTY_EAXBUFFER_IMMEDIATE;

  // Used by DSPROPERTY_EAXBUFFER_FLAGS
  //    TRUE:    value is computed automatically - property is an offset
  //    FALSE:   value is used directly
  //
  // Note: The number and order of flags may change in future EAX versions.
  //       To insure future compatibility, use flag defines as follows:
  //              myFlags = EAXBUFFERFLAGS_DIRECTHFAUTO | EAXBUFFERFLAGS_ROOMAUTO;
  //       instead of:
  //              myFlags = 0x00000003;
  //
  EAXBUFFERFLAGS_DIRECTHFAUTO = $00000001; //affects DSPROPERTY_EAXBUFFER_DIRECTHF
  EAXBUFFERFLAGS_ROOMAUTO = $00000002; //affects DSPROPERTY_EAXBUFFER_ROOM
  EAXBUFFERFLAGS_ROOMHFAUTO = $00000004; //affects DSPROPERTY_EAXBUFFER_ROOMHF
  EAXBUFFERFLAGS_RESERVED = $FFFFFFF8; // reserved future use
  {
  // property ranges and defaults:
  EAXBUFFER_MINDIRECT                      = -10000;
  EAXBUFFER_MAXDIRECT                      = 1000;
  EAXBUFFER_DEFAULTDIRECT                  = 0;

  EAXBUFFER_MINDIRECTHF                    = -10000;
  EAXBUFFER_MAXDIRECTHF                    = 0;
  EAXBUFFER_DEFAULTDIRECTHF                = 0;

  EAXBUFFER_MINROOM                        = -10000;
  EAXBUFFER_MAXROOM                        = 1000;
  EAXBUFFER_DEFAULTROOM                    = 0;

  EAXBUFFER_MINROOMHF                      = -10000;
  EAXBUFFER_MAXROOMHF                      = 0;
  EAXBUFFER_DEFAULTROOMHF                  = 0;

  EAXBUFFER_MINROOMROLLOFFFACTOR           = 0.0;
  EAXBUFFER_MAXROOMROLLOFFFACTOR           = 10.;
  EAXBUFFER_DEFAULTROOMROLLOFFFACTOR       = 0.0;

  EAXBUFFER_MINOBSTRUCTION                 = -10000;
  EAXBUFFER_MAXOBSTRUCTION                 = 0;
  EAXBUFFER_DEFAULTOBSTRUCTION             = 0;

  EAXBUFFER_MINOBSTRUCTIONLFRATIO          = 0.0;
  EAXBUFFER_MAXOBSTRUCTIONLFRATIO          = 1.0;
  EAXBUFFER_DEFAULTOBSTRUCTIONLFRATIO      = 0.0;

  EAXBUFFER_MINOCCLUSION                   = -10000;
  EAXBUFFER_MAXOCCLUSION                   = 0;
  EAXBUFFER_DEFAULTOCCLUSION               = 0;

  EAXBUFFER_MINOCCLUSIONLFRATIO            = 0.0;
  EAXBUFFER_MAXOCCLUSIONLFRATIO            = 1.0;
  EAXBUFFER_DEFAULTOCCLUSIONLFRATIO        = 0.25;

  EAXBUFFER_MINOCCLUSIONROOMRATIO          = 0.0;
  EAXBUFFER_MAXOCCLUSIONROOMRATIO          = 10.0;
  EAXBUFFER_DEFAULTOCCLUSIONROOMRATIO      = 0.5;

  EAXBUFFER_MINOUTSIDEVOLUMEHF             = -10000;
  EAXBUFFER_MAXOUTSIDEVOLUMEHF             = 0;
  EAXBUFFER_DEFAULTOUTSIDEVOLUMEHF         = 0;

  EAXBUFFER_MINAIRABSORPTIONFACTOR         = 0.0;
  EAXBUFFER_MAXAIRABSORPTIONFACTOR         = 10.0;
  EAXBUFFER_DEFAULTAIRABSORPTIONFACTOR     = 1.0;
  }

  EAXBUFFER_DEFAULTFLAGS = EAXBUFFERFLAGS_DIRECTHFAUTO or EAXBUFFERFLAGS_ROOMAUTO or EAXBUFFERFLAGS_ROOMHFAUTO;
  // Material transmission presets
  // 3 values in this order:
  //     1: occlusion (or obstruction)
  //     2: occlusion LF Ratio (or obstruction LF Ratio)
  //     3: occlusion Room Ratio

  // Single window material preset
  EAX_MATERIAL_SINGLEWINDOW = -2800;
  EAX_MATERIAL_SINGLEWINDOWLF = 0.71;
  EAX_MATERIAL_SINGLEWINDOWROOMRATIO = 0.43;
  // Double window material preset
  EAX_MATERIAL_DOUBLEWINDOW = -5000;
  EAX_MATERIAL_DOUBLEWINDOWHF = 0.40;
  EAX_MATERIAL_DOUBLEWINDOWROOMRATIO = 0.24;
  // Thin door material preset
  EAX_MATERIAL_THINDOOR = -1800;
  EAX_MATERIAL_THINDOORLF = 0.66;
  EAX_MATERIAL_THINDOORROOMRATIO = 0.66;
  // Thick door material preset
  EAX_MATERIAL_THICKDOOR = -4400;
  EAX_MATERIAL_THICKDOORLF = 0.64;
  EAX_MATERIAL_THICKDOORROOMRTATION = 0.27;
  // Wood wall material preset
  EAX_MATERIAL_WOODWALL = -4000;
  EAX_MATERIAL_WOODWALLLF = 0.50;
  EAX_MATERIAL_WOODWALLROOMRATIO = 0.30;
  // Brick wall material preset
  EAX_MATERIAL_BRICKWALL = -5000;
  EAX_MATERIAL_BRICKWALLLF = 0.60;
  EAX_MATERIAL_BRICKWALLROOMRATIO = 0.24;
  // Stone wall material preset
  EAX_MATERIAL_STONEWALL = -6000;
  EAX_MATERIAL_STONEWALLLF = 0.68;
  EAX_MATERIAL_STONEWALLROOMRATIO = 0.20;
  // Curtain material preset
  EAX_MATERIAL_CURTAIN = -1200;
  EAX_MATERIAL_CURTAINLF = 0.15;
  EAX_MATERIAL_CURTAINROOMRATIO = 1.00;

type
  DSPROPERTY_EAX_LISTENERPROPERTY = LongWord;//DWord;
  DSPROPERTY_EAX_BUFFERPROPERTY = LongWord;//DWord;
  // Use this structure for DSPROPERTY_EAXLISTENER_ALLPARAMETERS
  // - all levels are hundredths of decibels
  // - all times are in seconds
  // - the reference for high frequency controls is 5 kHz
  //
  // NOTE: This structure may change in future EAX versions.
  //       It is recommended to initialize fields by name:
  //              myListener.lRoom = -1000;
  //              myListener.lRoomHF = -100;
  //              ...
  //              myListener.dwFlags = myFlags /* see EAXLISTENERFLAGS below */ ;
  //       instead of:
  //              myListener = { -1000, -100, ... , 0x00000009 };
  //       If you want to save and load presets in binary form, you
  //       should define your own structure to insure future compatibility.
  //
  PEaxListenerProperties = ^TEaxListenerProperties;
  TEaxListenerProperties = packed record
    lRoom, // room effect level at low frequencies
      lRoomHF: Integer; // room effect high-frequency level re. low frequency levelimplementation
    flRoomRolloffFactor, // like DS3D flRolloffFactor but for room effect
      flDecayTime, // reverberation decay time at low frequenciesend.
      flDecayHFRatio: double; // high-frequency to low-frequency decay time ratio
    lReflections: Integer; // early reflections level relative to room effect
    flReflectionsDelay: double; // initial reflection delay time
    lReverb: Integer; // late reverberation level relative to room effect
    flReverbDelay: double; // late reverberation delay time relative to initial reflection
    dwEnvironment: cardinal; // sets all listener properties
    flEnvironmentSize, // environment size in meters
      flEnvironmentDiffusion, // environment diffusion
      flAirAbsorptionHF: double; // change in level per meter at 5 kHz
    dwFlags: cardinal; // modifies the behavior of properties
  end;
  // Use this structure for DSPROPERTY_EAXBUFFER_ALLPARAMETERS
  // - all levels are hundredths of decibels
  //
  // NOTE: This structure may change in future EAX versions.
  //       It is recommended to initialize fields by name:
  //              myBuffer.lDirect = 0;
  //              myBuffer.lDirectHF = -200;
  //              ...
  //              myBuffer.dwFlags = myFlags /* see EAXBUFFERFLAGS below */ ;
  //       instead of: myBuffer = { 0, -200, ... , 0x00000003 };
  PEaxBufferProperties = ^TEaxBufferProperties;
  TEaxBufferProperties = packed record
    lDirect, // direct path level
      lDirectHF, // direct path level at high frequencies
      lRoom, // room effect level
      lRoomHF: Integer; // room effect level at high frequencies
    flRoomRolloffFactor: double; // like DS3D flRolloffFactor but for room effect
    lObstruction: Integer; // main obstruction control (attenuation at high frequencies)
    flObstructionLFRatio: double; // obstruction low-frequency level re. main control
    lOcclusion: Integer; // main occlusion control (attenuation at high frequencies)
    flOcclusionLFRatio, // occlusion low-frequency level re. main control
      flOcclusionRoomRatio: double; // occlusion room effect level re. main control
    lOutsideVolumeHF: Integer; // outside sound cone level at high frequencies
    flAirAbsorptionFactor: double; // multiplies DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF
    dwFlags: Cardinal; // modifies the behavior of properties
  end;
var
  EAXSet: function(const Guid: TGUID; Int1: Cardinal; Int2: Cardinal; point: Pointer; Int3: Cardinal): Cardinal; cdecl; {$EXTERNALSYM EAXSet}
    //EAXGet: Function(const Guid: TGUID; Int1: Cardinal; Int2: Cardinal; point: Pointer; Int3: Cardinal): Cardinal; cdecl; {$EXTERNALSYM EAXGet}
{$IFDEF dgR}{$ENDREGION}{$ENDIF} 
//------------------------------------------------------------------------------
{$IFDEF dgR}{$REGION '      al const      '}{$ENDIF}
const
  AL_INVALID = -1; // Bad value.
  AL_NONE = 0; // Disable value
  AL_FALSE = 0; // Boolean False.
  AL_TRUE = 1; // Boolean True.
  ALC_DEFAULT_DEVICE_SPECIFIER = $1004;
  ALC_DEVICE_SPECIFIER = $1005;
  //----------------------------------------------------------------------------
  //Indicate the gain (volume amplification) applied. * Type:   ALfloat. * Range:[0.0 - 1.0] A value of 1.0 means un-attenuated/unchanged.
  //Each division by 2 equals an attenuation of -6dB.
  //Each multiplicaton with 2 equals an amplification of +6dB.
  //A value of 0.0 is meaningless with respect to a logarithmic scale; it is interpreted as zero volume - the channel is effectively disabled.
  AL_GAIN = $100A;
  AL_SOURCE_STATE = $1010;
  AL_PLAYING = $1012;
  AL_BUFFERS_QUEUED = $1015;
  AL_BUFFERS_PROCESSED = $1016;
  AL_FORMAT_MONO16 = $1101;
  AL_FORMAT_STEREO16 = $1103;
  AL_FREQUENCY = $2001;
  AL_NO_ERROR = AL_FALSE;
  AL_DISTANCE_MODEL = $D000;
  AL_INVERSE_DISTANCE = $D001;
  AL_INVERSE_DISTANCE_CLAMPED = $D002;
{$IFDEF dgR}{$ENDREGION}{$ENDIF}
//------------------------------------------------------------------------------
{$IFDEF dgR}{$REGION '      OGG      '}{$ENDIF}
type
  t_PChar_array = packed array[0..maxint div SizeOf(PAnsiChar) - 1] of PAnsiChar;
  p_PChar_array = ^t_PChar_array;
  t_int_array = packed array[0..maxint div SizeOf(Integer) - 1] of Integer;
  p_int_array = ^t_int_array;
  t_float_array = packed array[0..maxint div SizeOf(Single) - 1] of Single;
  p_float_array = ^t_float_array;
  t_float_p_float_array = packed array[0..maxint div SizeOf(p_float_array) - 1] of p_float_array;
  p_p_float_p_float_array = ^p_float_p_float_array;
  p_float_p_float_array = ^t_float_p_float_array;
  p_oggpack_buffer = ^oggpack_buffer;
  oggpack_buffer = record
    endByte, endbit: Integer;
    buffer, ptr: PAnsiChar;
    storage: Integer;
  end;
  p_ogg_stream_state = ^ogg_stream_state;
  ogg_stream_state = record
    body_data: PAnsiChar; //Bytes from packet bodies
    body_storage, body_fill, body_returned: Integer; //storage elements allocated, elements stored; fill mark, elements of fill returned
    lacing_vals: p_int_array; //The values that will go to the segment table
    granule_vals: Pointer; //Int64 granulepos values for headers. Not compact this way, but it is simple coupled to the lacing fifo
    lacing_storage, lacing_fill, lacing_packet, lacing_returned: Integer;
    header: array[0..282] of AnsiChar; // working space for header encode
    header_fill, e_o_s, b_o_s, serialno, pageno: Integer; // set when we have buffered the last packet in the logical biTdgStream , set after we've written the initial page of a logical biTdgStream
    packetno, granulepos: Int64; // 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;
  p_ogg_sync_state = ^ogg_sync_state;
  ogg_sync_state = record
    data: PAnsiChar;
    storage, fill, returned, unsynced, headerBytes, bodyBytes: Integer;
  end;
  //----Codec-------------------------------------------------------------------
  p_vorbis_info = ^vorbis_info;
  vorbis_info = record
    version, channels, rate, bitrate_upper, bitrate_nominal, bitrate_lower, bitrate_window: Integer;
    codec_setup: Pointer;
  end;
  p_vorbis_dsp_state = ^vorbis_dsp_state;
  vorbis_dsp_state = record
    analysisp: Integer;
    vi: p_vorbis_info;
    pcm: p_float_p_float_array;
    pcmret: p_float_p_float_array;
    pcm_storage, pcm_current, pcm_returned, preextrapolate, eofflag, lW, W, nW, centerW: Integer;
    granulepos, sequence, glue_bits, time_bits, floor_bits, res_bits: Int64;
    backend_state: Pointer;
  end;
  p_alloc_chain = ^alloc_chain;
  alloc_chain = record
    ptr: Pointer;
    next: p_alloc_chain;
  end;
  p_vorbis_block = ^vorbis_block;
  vorbis_block = record
    pcm: p_float_p_float_array; // this is a pointer into local storage
    opb: oggpack_buffer;
    lW, W, nW, pcmend, mode, eofflag: Integer;
    granulepos, sequence: Int64;
    vd: p_vorbis_dsp_state; // For read-only access of configuration
    localstore: Pointer;
    localtop, localalloc, totaluse: Integer;
    reap: p_alloc_chain;
    glue_bits, time_bits, floor_bits, res_bits: Integer; // bitmetrics for the frame
    internal: Pointer;
  end;
  p_vorbis_comment = ^vorbis_comment;
  vorbis_comment = record
    user_comments: p_PChar_array;
    comment_lengths: p_int_array;
    comments: Integer;
    vendor: PAnsiChar;
  end;
  //----------------------------------------------------------------------------
  read_func_t = function(var ptr; size: cardinal; nmemb: cardinal; const datasource): cardinal; cdecl;
  seek_func_t = function(const datasource; offset: Int64; whence: Integer): Integer; cdecl;
  close_func_t = function(const datasource): Integer; cdecl;
  tell_func_t = function(const datasource): Int64; cdecl;
  //----------------------------------------------------------------------------
  p_ov_callbacks = ^ov_callbacks;
  ov_callbacks = record
    read_func: read_func_t;
    seek_func: seek_func_t;
    close_func: close_func_t;
    tell_func: tell_func_t;
  end;
  POggVorbis_File = ^OggVorbis_File;
  OggVorbis_File = record
    datasource: Pointer; // Pointer to a FILE *, etc.
    seekable: Integer;
    offset, end_v: Int64;
    oy: ogg_sync_state;
    // If the FILE handle isn't seekable (eg, a pipe), only the current stream appears
    links: Integer;
    offsets, dataoffsets, serialnos, pcmlengths: Pointer;
    vi: p_vorbis_info;
    vc: p_vorbis_comment;
    // Decoding working state local storage
    pcm_offset: Int64;
    ready_state, current_serialno, current_link: Integer;
    bittrack, samptrack: double;
    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 ops_read_func(var ptr; size, nmemb: cardinal; const datasource): cardinal; cdecl;
function ops_seek_func(const datasource; offset: Int64; whence: Integer): Integer; cdecl;
function ops_close_func(const datasource): Integer; cdecl;
function ops_tell_func(const datasource): Int64; cdecl;

function ov_open_callbacks(const datasource; var vf: OggVorbis_File; initial: PAnsiChar; iBytes: Integer; callbacks: ov_callbacks): Integer; cdecl; external VorbisLib;
function ov_info(var vf: OggVorbis_File; link: Integer): p_vorbis_info; cdecl; external VorbisLib;
function ov_read(var vf: OggVorbis_File; const buffer; length: Integer; bigendianp: Integer; Word: Integer; sgned: Integer; biTdgStream: PInteger): Integer; cdecl; external VorbisLib;
function ov_time_tell(var vf: OggVorbis_File): Double; cdecl; external VorbisLib;
function ov_time_total(var vf: OggVorbis_File; i: Integer): Double; cdecl; external VorbisLib;
function ov_time_seek(var vf: OggVorbis_File; pos: Double): Integer; cdecl; external VorbisLib;
{$IFDEF dgR}{$ENDREGION}{$ENDIF}
//------------------------------------------------------------------------------
{$IFDEF dgR}{$REGION '      al func      '}{$ENDIF}
function alcGetString(device: Pointer; param: Integer): PAnsiChar; cdecl; external AL32;
function alcOpenDevice(deviceName: PAnsiChar): Pointer; cdecl; external AL32;
procedure alcCloseDevice(device: Pointer); cdecl; external AL32;
function alcCreateContext(device: Pointer; attrlist: PInteger): Pointer; cdecl; external AL32;
function alcMakeContextCurrent(context: Pointer): Integer; cdecl; external AL32;
function alcGetCurrentContext: Pointer; cdecl; external AL32;
function alcGetContextsDevice(context: Pointer): Pointer; cdecl; external AL32;
procedure alcSuspendContext(context: Pointer); cdecl; external AL32;
function alcIsExtensionPresent(device: Pointer; extName: PAnsiChar): Boolean; cdecl; external AL32;
function alcGetEnumValue(device: Pointer; enumName: PAnsiChar): Integer; cdecl; external AL32;
function alcGetError(device: Pointer): Integer; cdecl; external AL32;
procedure alcGetIntegerv(device: Pointer; param: Integer; size: Integer; data: PInteger); cdecl; external AL32;
function alcGetProcAddress(device: Pointer; funcName: PAnsiChar): Pointer; cdecl; external AL32;
procedure alcProcessContext(context: Pointer); cdecl; external AL32;
procedure alcDestroyContext(context: Pointer); cdecl; external AL32;

function alGetError: Integer; cdecl; external AL32;

function alIsExtensionPresent(fname: PAnsiChar): Boolean; cdecl; external AL32;
function alGetProcAddress(fname: PAnsiChar): Pointer; cdecl; external AL32;
procedure alDistanceModel(value: Integer); cdecl; external AL32;
procedure alListenerf(param: Integer; value: Single); cdecl; external AL32;
procedure alListenerfv(param: Integer; values: PSingle); cdecl; external AL32;
procedure alGenSources(n: Cardinal; sources: PCardinal); cdecl; external AL32;
procedure alDeleteSources(n: Cardinal; sources: PCardinal); cdecl; external AL32;
procedure alSourcef(source: Cardinal; param: Integer; value: Single); cdecl; external AL32;
procedure alSourcefv(source: Cardinal; param: Integer; values: PSingle); cdecl; external AL32;
procedure alGetSourcei(source: Cardinal; param: Integer; value: PInteger); cdecl; external AL32;
procedure alSourcePlay(source: Cardinal); cdecl; external AL32;
procedure alGenBuffers(n: Cardinal; buffers: PCardinal); cdecl; external AL32;
procedure alDeleteBuffers(n: Cardinal; buffers: PCardinal); cdecl; external AL32;
procedure alBufferData(buffer: Cardinal; format: Integer; data: Pointer; size, freq: Cardinal); cdecl; external AL32;
procedure alSourceQueueBuffers(source: Cardinal; n: Cardinal; buffers: PCardinal); cdecl; external AL32;
procedure alSourceUnqueueBuffers(source: Cardinal; n: Cardinal; buffers: PCardinal); cdecl; external AL32;
{$IFDEF dgR}{$ENDREGION}{$ENDIF}
//------------------------------------------------------------------------------
{$IFDEF dgR}{$REGION '      TdgStream type      '}{$ENDIF}
type
  TdgStream = class
  public
    function Seek(aPos: Cardinal): Cardinal; virtual; abstract;
    function Read(out Buf; Count: Cardinal): Cardinal; virtual; abstract;
    function GetSize: Cardinal; virtual; abstract;
    function GetPos: Cardinal; virtual; abstract;
  end;
  //----------------------------------------------------------------------------
  TdgFileStream = class(TdgStream)
    constructor Create(const aFileName: String);
    destructor Destroy; override;
  private
    fHandle: Integer;
    fSize: Cardinal;
  public
    function Seek(aPos: Cardinal): Cardinal; override;
    function Read(out Buf; Count: Cardinal): Cardinal; override;
    function GetSize: Cardinal; override;
    function GetPos: Cardinal; override;
  end;
  //----------------------------------------------------------------------------
  TdgMemoryStream = class(TdgStream)
    constructor Create(const Buf; const MemSize: Cardinal); overload;
    constructor Create(const aFileName: String); overload;
    destructor Destroy; override;
  protected
    fSize, fPos: Cardinal;
    fMem: Pointer;
  public
    function Seek(aPos: Cardinal): Cardinal; override;
    function Read(out Buf; Count: Cardinal): Cardinal; override;
    function GetSize: Cardinal; override;
    function GetPos: Cardinal; override;
    property Memory: Pointer read fMem;
  end;
{$IFDEF dgR}{$ENDREGION}{$ENDIF} 
//------------------------------------------------------------------------------
{$IFDEF dgR}{$REGION '      TdgFloat      '}{$ENDIF}
  TdgFloat = Single;
  PdgFloat = ^TdgFloat;

  TdgArray3f = array[0..2] of TdgFloat;
  PdgArray3f = ^TdgArray3f;

  TdgVector3f = record
    case Integer of
      0: (X: TdgFloat;
        Y: TdgFloat;
        Z: TdgFloat);
      1: (R: TdgFloat;
        G: TdgFloat;
        B: TdgFloat);
      2: (V: TdgArray3f);
  end;
  PdgVector3f = ^TdgVector3f;
{$IFDEF dgR}{$ENDREGION}{$ENDIF} 
//------------------------------------------------------------------------------
{$IFDEF dgR}{$REGION '      TdgList type      '}{$ENDIF}
const
  MaxListSize = Maxint div 16;

type
  PPointerList = ^TPointerList;
  TPointerList = array[0..MaxListSize - 1] of Pointer;

  TdgList = class(TObject)
  private
    FList: PPointerList;
    FCount, FCapacity: Integer;
  protected
    function Get(Index: Integer): Pointer;
    procedure Grow; virtual;
    procedure Put(Index: Integer; Item: Pointer);
    procedure SetCapacity(NewCapacity: Integer);
    procedure SetCount(NewCount: Integer);
  public
    constructor Create(const aSize:Integer = 0);
    destructor Destroy; override;
    function Add(Item: Pointer): Integer;
    procedure Clear; virtual;
    procedure Delete(Index: Integer);
    function IndexOf(Item: Pointer): Integer;
    function Remove(Item: Pointer): Integer;
    property Count: Integer read FCount write SetCount;
    property Items[Index: Integer]: Pointer read Get write Put; default;
  end;
//------------------------------------------------------------------------------
{$IFDEF dgR}{$ENDREGION}{$ENDIF} 
//------------------------------------------------------------------------------
{$IFDEF dgR}{$REGION '      TdgTimer type      '}{$ENDIF}
//------------------------------------------------------------------------------
  TNotifyEvent = procedure(Sender: TObject) of object;
  TdgTimer = class(TObject)
  private
    FActive: Boolean;
    FHandle, FInterval: Integer;
    FOnTimer: TNotifyEvent;
    procedure SetActive(const Value: Boolean);
    procedure SetInterval(const Value: Integer);
  public
    constructor Create;
    destructor Destroy; override;
    property Active: Boolean read FActive write SetActive;
    property Interval: Integer read FInterval write SetInterval;
    property OnTimer: TNotifyEvent read FOnTimer write FOnTimer;
  end;
//------------------------------------------------------------------------------
  TdgTimerList = class(TdgList)
  protected
    function Get(index: Integer): TdgTimer;
    procedure Put(index: Integer; Item: TdgTimer);
  public
    property Items[index: Integer]: TdgTimer read Get write Put; default;
  end;
//------------------------------------------------------------------------------
{$IFDEF dgR}{$ENDREGION}{$ENDIF} 
//------------------------------------------------------------------------------
procedure seLogMe(txt: String; Rewr: Boolean = False);
function seIntToStr(aValue: Integer): String;
function seSingleToStr(const aValue: Single; const aCutLength: Byte = 2): String;
function sedgVector3f(const aX, aY, aZ: TdgFloat): TdgVector3f;
function seWideCompareStr(const S1, S2: WideString): Integer;
function seSameStr(const S1, S2: String): Boolean; {$IFDEF dgR}inline;{$ENDIF}
function seExtractFileDir(const FileName: String): String;
function seFileExists(const aFileName: String): Boolean;
function seExtractFileName(const FileName: String): String;
function seExtractFileExt(const FileName: String): String;
function seCharInSet(C: AnsiChar; const CharSet: TSysCharSet): Boolean; overload; {$IFDEF dgR}inline;{$ENDIF}
function seCharInSet(C: WideChar; const CharSet: TSysCharSet): Boolean; overload; {$IFDEF dgR}inline;{$ENDIF}
function seIsLeadChar(C: AnsiChar): Boolean; overload; {$IFDEF dgR}inline;{$ENDIF}
function seIsLeadChar(C: WideChar): Boolean; overload; {$IFDEF dgR}inline;{$ENDIF}
function seStrScan(const Str: PAnsiChar; Chr: AnsiChar): PAnsiChar; overload;
function seStrScan(const Str: PWideChar; Chr: WideChar): PWideChar; overload;
function seByteType(const S: AnsiString; Index: Integer): TMbcsByteType; overload;
function seByteType(const S: WideString; Index: Integer): TMbcsByteType; overload;//Delphi-9,10 S: UnicodeString :)
function seLastDelimiter(const Delimiters, S: string): Integer;
function seFindFirst(const Path: string; Attr: Integer; var  F: TSearchRec): Integer;
function seFindNext(var F: TSearchRec): Integer;
procedure seFindClose(var F: TSearchRec);
{$IFDEF UNICODE}
function CreateFile(lpFileName: PWideChar; dwDesiredAccess, dwShareMode: LongWord{DWORD};
  lpSecurityAttributes: PSecurityAttributes; dwCreationDisposition, dwFlagsAndAttributes: LongWord{DWORD};
  hTemplateFile: THandle): THandle; stdcall; {$EXTERNALSYM CreateFile}
function DeleteFile(lpFileName: PWideChar): LongBool{BOOL}; stdcall; {$EXTERNALSYM DeleteFile}
function FindFirstFile(lpFileName: PWideChar; var lpFindFileData: TWIN32FindData): THandle; stdcall;{$EXTERNALSYM FindFirstFile}
{$ELSE}
function CreateFile(lpFileName: PChar; dwDesiredAccess, dwShareMode: LongWord{DWORD};
  lpSecurityAttributes: PSecurityAttributes; dwCreationDisposition, dwFlagsAndAttributes: LongWord{DWORD};
  hTemplateFile: THandle): THandle; stdcall;{$EXTERNALSYM CreateFile}
function DeleteFile(lpFileName: PChar): LongBool{BOOL}; stdcall;{$EXTERNALSYM DeleteFile}
function FindFirstFile(lpFileName: PChar; var lpFindFileData: TWIN32FindData): THandle; stdcall;{$EXTERNALSYM FindFirstFile}
{$ENDIF}
function GetFileSize(hFile: THandle; lpFileSizeHigh: Pointer): LongWord{DWORD}; stdcall; {$EXTERNALSYM GetFileSize}
function CloseHandle(hObject: THandle): LongBool{BOOL}; stdcall; {$EXTERNALSYM CloseHandle}
function SetFilePointer(hFile: THandle; lDistanceToMove: Longint;
  lpDistanceToMoveHigh: Pointer; dwMoveMethod: LongWord{DWORD}): LongWord{DWORD}; stdcall; {$EXTERNALSYM SetFilePointer}
function ReadFile(hFile: THandle; var Buffer; nNumberOfBytesToRead: LongWord{DWORD};
  var lpNumberOfBytesRead: LongWord{DWORD}; lpOverlapped: POverlapped): LongBool{BOOL}; stdcall; {$EXTERNALSYM ReadFile}
function SetTimer(hWnd: HWND; nIDEvent, uElapse: LongWord{UINT}; lpTimerFunc: TFNTimerProc): LongWord{UINT}; stdcall; {$EXTERNALSYM SetTimer}
function KillTimer(hWnd: HWND; uIDEvent: LongWord{UINT}): LongBool{BOOL}; stdcall; {$EXTERNALSYM KillTimer}
function CompareStringA(Locale: LongWord{LCID}; dwCmpFlags: LongWord{DWORD}; lpString1: PAnsiChar;
  cchCount1: Integer; lpString2: PAnsiChar; cchCount2: Integer): Integer; stdcall; {$EXTERNALSYM CompareStringA}
function CompareStringW(Locale: LongWord{LCID}; dwCmpFlags: LongWord{DWORD}; lpString1: PWideChar;
  cchCount1: Integer; lpString2: PWideChar; cchCount2: Integer): Integer; stdcall; {$EXTERNALSYM CompareStringW}
function FileTimeToDosDateTime(const lpFileTime: TFileTime; var lpFatDate, lpFatTime: Word): LongBool{BOOL}; stdcall;{$EXTERNALSYM FileTimeToDosDateTime}
function FileTimeToLocalFileTime(const lpFileTime: TFileTime; var lpLocalFileTime: TFileTime): LongBool{BOOL}; stdcall; {$EXTERNALSYM FileTimeToLocalFileTime}
function FindNextFile(hFindFile: THandle; var lpFindFileData: TWIN32FindData): LongBool{BOOL}; stdcall; {$EXTERNALSYM FindNextFile}
function wFindClose(hFindFile: THandle): LongBool{BOOL}; stdcall; {$EXTERNALSYM wFindClose}
{$IFDEF UNICODE}
function CreateFile; external kernel32 name 'CreateFileW';
function DeleteFile; external kernel32 name 'DeleteFileW';
function FindFirstFile; external kernel32 name 'FindFirstFileW';
{$ELSE}
function CreateFile; external kernel32 name 'CreateFileA';
function DeleteFile; external kernel32 name 'DeleteFileA';
function FindFirstFile; external kernel32 name 'FindFirstFileA';
{$ENDIF}
function GetFileSize; external kernel32 name 'GetFileSize';
function CloseHandle; external kernel32 name 'CloseHandle';
function SetFilePointer; external kernel32 name 'SetFilePointer';
function ReadFile; external kernel32 name 'ReadFile';
function KillTimer; external user32 name 'KillTimer';
function SetTimer; external user32 name 'SetTimer';
function CompareStringA; external kernel32 name 'CompareStringA';
function CompareStringW; external kernel32 name 'CompareStringW';
function FileTimeToDosDateTime; external kernel32 name 'FileTimeToDosDateTime';
function FileTimeToLocalFileTime; external kernel32 name 'FileTimeToLocalFileTime';
function wFindClose; external kernel32 name 'FindClose';
function FindNextFile; external kernel32 name 'FindNextFileW';

implementation

var
  TL: TdgTimerList;
  seSysLocale: TSysLocale;
//------------------------------------------------------------------------------
{$IFDEF dgR}{$REGION '      Help func       '}{$ENDIF}
//------------------------------------------------------------------------------
procedure seLogMe(txt: String; Rewr: Boolean = False);
var
  outf: TextFile;
  ofile: String;
begin
  ofile := seExtractFileDir(ParamStr(0)) + '\SoundEngineErrorLog.txt';
  if not seFileExists(ofile) then begin
    AssignFile(outf, ofile);
    Rewrite(outf);
    CloseFile(outf);
  end;
  AssignFile(outf, ofile);
  if Rewr then Rewrite(outf) else Append(outf);
  writeln(outf, 'Error: ' + txt);
  CloseFile(outf);
end;
//------------------------------------------------------------------------------
function seFileExists(const aFileName: String): Boolean;
{$IFDEF MSWINDOWS}
var
  h: Integer;
begin
  h := CreateFile(PChar(aFileName), LongWord($80000000){GENERIC_READ}, $00000001{FILE_SHARE_READ}, nil, 3{OPEN_EXISTING}, 0, 0);
  if h = -1{INVALID_HANDLE_VALUE} then Result := False
  else begin
    CloseHandle(h);
    Result := True;
  end;
end;
{$ENDIF MSWINDOWS}
{$IFDEF LINUX}
begin
  Result := euidaccess(PChar(aFileName), F_OK) = 0;
end;
{$ENDIF LINUX}
//------------------------------------------------------------------------------
function seIntToStr(aValue: Integer): string;
var
  s: ShortString;
begin
  Str(aValue, s);
  Result := string(s);
end;
//------------------------------------------------------------------------------
function seExtractFileName(const FileName: string): string;
var
  I: Integer;
begin
  I := seLastDelimiter(PathDelim + DriveDelim, FileName);
  Result := Copy(FileName, I + 1, MaxInt);
end;
//------------------------------------------------------------------------------
function seStrScan(const Str: PAnsiChar; Chr: AnsiChar): PAnsiChar;
begin
  Result := Str;
  while Result^ <> #0 do
  begin
    if Result^ = Chr then
      Exit;
    Inc(Result);
  end;
  if Chr <> #0 then
    Result := nil;
end;
//------------------------------------------------------------------------------
function seStrScan(const Str: PWideChar; Chr: WideChar): PWideChar;
begin
  Result := Str;
  while Result^ <> #0 do
  begin
    if Result^ = Chr then
      Exit;
    Inc(Result);
  end;
  if Chr <> #0 then
    Result := nil;
end;
//------------------------------------------------------------------------------
function seByteTypeTest(P: PAnsiChar; Index: Integer): TMbcsByteType;
{$IFDEF MSWINDOWS}
var
  I: Integer;
begin
  Result := mbSingleByte;
  if (P = nil) or (P[Index] = #$0) then Exit;
  if (Index = 0) then
    if seIsLeadChar(P[0]) then Result := mbLeadByte
  else begin
    I := Index - 1;
    while (I >= 0) and seIsLeadChar(P[I]) do Dec(I);
    if ((Index - I) mod 2) = 0 then Result := mbTrailByte
    else if seIsLeadChar(P[Index]) then Result := mbLeadByte;
  end;
end;
{$ENDIF}
{$IFDEF LINUX}
var
  I, L: Integer;
begin
  Result := mbSingleByte;
  if (P = nil) or (P[Index] = #$0) then Exit;
  I := 0;
  repeat
    if IsLeadChar(P[I]) then L := StrCharLength(P + I) else L := 1;
    Inc(I, L);
  until (I > Index);
  if (L <> 1) then
    if (I - L = Index) then Result := mbLeadByte
    else Result := mbTrailByte;
end;
{$ENDIF}
//------------------------------------------------------------------------------
function seByteType(const S: AnsiString; Index: Integer): TMbcsByteType;
begin
  Result := mbSingleByte;
  if seSysLocale.FarEast then Result := seByteTypeTest(PAnsiChar(S), Index-1);
end;

function seByteType(const S: WideString; Index: Integer): TMbcsByteType;
begin
  Result := mbSingleByte;
  if (Index > 0) and (Index <= Length(S)) and seIsLeadChar(S[Index]) then
    if (S[Index] >= #$D800) and (S[Index] <= #$DBFF) then Result := mbLeadByte
    else Result := mbTrailByte;
end;
//------------------------------------------------------------------------------
function seLastDelimiter(const Delimiters, S: string): Integer;
var
  P: PChar;
begin
  Result := Length(S);
  P := PChar(Delimiters);
  while Result > 0 do
  begin
    if (S[Result] <> #0) and (seStrScan(P, S[Result]) <> nil) then
{$IFDEF MSWINDOWS}
{$IFNDEF UNICODE}
      if (seByteType(S, Result) = mbTrailByte) then
        Dec(Result)
      else
{$ENDIF}
        Exit;
{$ENDIF}
{$IFDEF LINUX}
    begin
      if (seByteType(S, Result) <> mbTrailByte) then
        Exit;
      Dec(Result);
      while seByteType(S, Result) = mbTrailByte do Dec(Result);
    end;
{$ENDIF}
    Dec(Result);
  end;
end;
//------------------------------------------------------------------------------
function seIsDelimiter(const Delimiters, S: string; Index: Integer): Boolean;
begin
  Result := False;
  if (Index <= 0) or (Index > Length(S)) or (seByteType(S, Index) <> mbSingleByte) then exit;
  Result := seStrScan(PChar(Delimiters), S[Index]) <> nil;
end;
//------------------------------------------------------------------------------
function seExtractFileDir(const FileName: String): String;
var
  i: Integer;
begin
  i := seLastDelimiter(PathDelim + DriveDelim, Filename);
  if (i > 1) and (FileName[i] = PathDelim) and
    (not seIsDelimiter(PathDelim + DriveDelim, FileName, i - 1)) then Dec(i);
  Result := Copy(FileName, 1, i);
end;
//------------------------------------------------------------------------------
function seExtractFileExt(const FileName: string): string;
var
  I: Integer;
begin
  I := seLastDelimiter('.' + PathDelim + DriveDelim, FileName);
  if (I > 0) and (FileName[I] = '.') then
    Result := Copy(FileName, I, MaxInt) else
    Result := '';
end;
//------------------------------------------------------------------------------
{$IF DEFINED(MSWINDOWS) AND NOT DEFINED(UNICODE)}
function DumbItDownFor95(const S1, S2: WideString; CmpFlags: Integer): Integer;
var
  a1, a2: AnsiString;
begin
  a1 := string(s1);
  a2 := string(s2);
  Result := CompareStringA(LOCALE_USER_DEFAULT, CmpFlags, PAnsiChar(a1), Length(a1),
    PAnsiChar(a2), Length(a2)) - 2{CSTR_EQUAL};
end;
{$IFEND}
//------------------------------------------------------------------------------
function seWideCompareStr(const S1, S2: WideString): Integer;
{$IFDEF MSWINDOWS}
begin
  SetLastError(0);
  Result := CompareStringW(LOCALE_USER_DEFAULT, 0, PWideChar(S1), Length(S1),
    PWideChar(S2), Length(S2)) - 2{CSTR_EQUAL};
  case GetLastError of
    0: ;
{$IFNDEF UNICODE}
    120{ERROR_CALL_NOT_IMPLEMENTED}: Result := DumbItDownFor95(S1, S2, 0);
{$ENDIF}
  else
    seLogMe('Error: WideCompareStr - '+String(S1)+' ?= '+String(S2));
    //RaiseLastOSError;
  end;
end;
{$ENDIF}
{$IFDEF LINUX}
var
  UCS4_S1, UCS4_S2: UCS4String;
begin
  UCS4_S1 := WideStringToUCS4String(S1);
  UCS4_S2 := WideStringToUCS4String(S2);
  // glibc 2.1.2 / 2.1.3 implementations of wcscoll() and wcsxfrm()
  // have severe capacity limits.  Comparing two 100k strings may
  // exhaust the stack and kill the process.
  // Fixed in glibc 2.1.91 and later.
  SetLastError(0);
  Result := wcscoll(PUCS4Chars(UCS4_S1), PUCS4Chars(UCS4_S2));
  if GetLastError <> 0 then
    RaiseLastOSError;
end;
{$ENDIF}
//------------------------------------------------------------------------------
function seSameStr(const S1, S2: String): Boolean;
begin
  Result := seWideCompareStr(WideString(S1), WideString(S2)) = 0;
end;
//---- Обрезает по длинне вместо округления через Round к примеру --------------
function seSingleToStr(const aValue: Single; const aCutLength: Byte = 2): String;
var
  s: ShortString;
begin
  Str(aValue:0:aCutLength, s);
  Result := string(s);
end;
//------------------------------------------------------------------------------
function sedgVector3f(const aX, aY, aZ: TdgFloat): TdgVector3f;
begin
  with Result do
  begin
    x := aX;
    y := aY;
    z := aZ;
  end;
end;
//------------------------------------------------------------------------------
function seIsLeadChar(C: AnsiChar): Boolean;
begin
  Result := C in LeadBytes;
end;
//------------------------------------------------------------------------------
function seIsLeadChar(C: WideChar): Boolean;
begin
  Result := (C >= #$D800) and (C <= #$DFFF);
end;
//------------------------------------------------------------------------------
function seCharInSet(C: AnsiChar; const CharSet: TSysCharSet): Boolean;
begin
  Result := C in CharSet;
end;
//------------------------------------------------------------------------------
function seCharInSet(C: WideChar; const CharSet: TSysCharSet): Boolean;
begin
  Result := (C < #$0100) and (AnsiChar(C) in CharSet);
end;
//------------------------------------------------------------------------------
{$WARNINGS OFF}
function FindMatchingFile(var F: TSearchRec): Integer;
{$IFDEF MSWINDOWS}
var
  LocalFileTime: TFileTime;
begin
  with F do
  begin
    while FindData.dwFileAttributes and ExcludeAttr <> 0 do
      if not FindNextFile(FindHandle, FindData) then
      begin
        Result := GetLastError;
        Exit;
      end;
    FileTimeToLocalFileTime(FindData.ftLastWriteTime, LocalFileTime);
    FileTimeToDosDateTime(LocalFileTime, LongRec(Time).Hi,
      LongRec(Time).Lo);
    Size := FindData.nFileSizeLow or Int64(FindData.nFileSizeHigh) shl 32;
    Attr := FindData.dwFileAttributes;
    Name := FindData.cFileName;
  end;
  Result := 0;
end;
{$ENDIF}
{$IFDEF LINUX}
var
  PtrDirEnt: PDirEnt;
  Scratch: TDirEnt;
  StatBuf: TStatBuf;
  LinkStatBuf: TStatBuf;
  FName: string;
  Attr: Integer;
  Mode: mode_t;
begin
  Result := -1;
  PtrDirEnt := nil;
  if readdir_r(F.FindHandle, @Scratch, PtrDirEnt) <> 0 then
    Exit;
  while PtrDirEnt <> nil do
  begin
    if fnmatch(PChar(F.Pattern), PtrDirEnt.d_name, 0) = 0 then
    begin   // F.PathOnly must include trailing backslash
      FName := F.PathOnly + string(PtrDirEnt.d_name);

      if lstat(PChar(FName), StatBuf) = 0 then
      begin
        Attr := 0;
        Mode := StatBuf.st_mode;

        if S_ISDIR(Mode) then
          Attr := Attr or faDirectory
        else
        if not S_ISREG(Mode) then  // directories shouldn't be treated as system files
        begin
          if S_ISLNK(Mode) then
          begin
            Attr := Attr or faSymLink;
            if (stat(PChar(FName), LinkStatBuf) = 0) and
              S_ISDIR(LinkStatBuf.st_mode) then
                Attr := Attr or faDirectory
          end;
          Attr := Attr or faSysFile;
        end;

        if (PtrDirEnt.d_name[0] = '.') and (PtrDirEnt.d_name[1] <> #0) then
        begin
          if not ((PtrDirEnt.d_name[1] = '.') and (PtrDirEnt.d_name[2] = #0)) then
            Attr := Attr or faHidden;
        end;

        if euidaccess(PChar(FName), W_OK) <> 0 then
          Attr := Attr or faReadOnly;

        if Attr and F.ExcludeAttr = 0 then
        begin
          F.Size := StatBuf.st_size;
          F.Attr := Attr;
          F.Mode := StatBuf.st_mode;
          F.Name := PtrDirEnt.d_name;
          F.Time := StatBuf.st_mtime;
          Result := 0;
          Break;
        end;
      end;
    end;
    Result := -1;
    if readdir_r(F.FindHandle, @Scratch, PtrDirEnt) <> 0 then
      Break;
  end // End of While
end;
{$ENDIF}
//------------------------------------------------------------------------------
function seFindFirst(const Path: string; Attr: Integer; var  F: TSearchRec): Integer;
const
  faSpecial = faHidden or faSysFile or faDirectory;
{$IFDEF MSWINDOWS}
begin
  F.ExcludeAttr := not Attr and faSpecial;
  F.FindHandle := FindFirstFile(PChar(Path), F.FindData);
  if F.FindHandle <> -1{INVALID_HANDLE_VALUE} then
  begin
    Result := FindMatchingFile(F);
    if Result <> 0 then seFindClose(F);
  end else
    Result := GetLastError;
end;
{$ENDIF}
{$IFDEF LINUX}
begin
  F.ExcludeAttr := not Attr and faSpecial;
  F.PathOnly := ExtractFilePath(Path);
  F.Pattern := ExtractFileName(Path);
  if F.PathOnly = '' then
    F.PathOnly := IncludeTrailingPathDelimiter(GetCurrentDir);

  F.FindHandle := opendir(PChar(F.PathOnly));
  if F.FindHandle <> nil then
  begin
    Result := FindMatchingFile(F);
    if Result <> 0 then
      FindClose(F);
  end
  else
    Result:= GetLastError;
end;
{$ENDIF}
//------------------------------------------------------------------------------
function seFindNext(var F: TSearchRec): Integer;
begin
{$IFDEF MSWINDOWS}
  if Boolean(FindNextFile(F.FindHandle, F.FindData)) then
    Result := FindMatchingFile(F)
  else
    Result := GetLastError;
{$ENDIF}
{$IFDEF LINUX}
  Result := FindMatchingFile(F);
{$ENDIF}
end;
{$WARNINGS ON}
//------------------------------------------------------------------------------
procedure seFindClose(var F: TSearchRec);
begin
{$IFDEF MSWINDOWS}
  if F.FindHandle <> -1{INVALID_HANDLE_VALUE} then
  begin
    {Windows.}wFindClose(F.FindHandle);
    F.FindHandle := -1{INVALID_HANDLE_VALUE};
  end;
{$ENDIF}
{$IFDEF LINUX}
  if F.FindHandle <> nil then
  begin
    closedir(F.FindHandle);
    F.FindHandle := nil;
  end;
{$ENDIF}
end;
{$IFDEF dgR}{$ENDREGION}{$ENDIF}
//------------------------------------------------------------------------------
{$IFDEF dgR}{$REGION '      TdgStream      '}{$ENDIF}

{$IFDEF dgR}{$REGION 'TFileStream'}{$ENDIF}
//------------------------------------------------------------------------------
constructor TdgFileStream.Create(const aFileName: String);
begin
  inherited Create;
  fHandle := CreateFile(PChar(aFileName), LongWord($80000000){GENERIC_READ}, $00000001{FILE_SHARE_READ}, nil, 3{OPEN_EXISTING}, 0, 0);
  if fHandle = -1{INVALID_HANDLE_VALUE} then begin seLogMe('File not found: ' + aFileName + '. Called in TdgFileStream.Create'); Exit; end;
  if GetFileSize(fHandle, nil) <= 0 then begin seLogMe('Wrong file size: ' + aFileName + '. Called in TdgFileStream.Create'); Exit; end;
  fSize := GetFileSize(fHandle, nil);
end;
//------------------------------------------------------------------------------
destructor TdgFileStream.Destroy;
begin
  if fHandle <> -1{INVALID_HANDLE_VALUE} then CloseHandle(fHandle);
  inherited Destroy;
end;
//------------------------------------------------------------------------------
function TdgFileStream.Seek(aPos: Cardinal): Cardinal;
begin
  SetFilePointer(fHandle, aPos, nil, 0{FILE_BEGIN});
  Result := aPos;
end;
//------------------------------------------------------------------------------
function TdgFileStream.Read(out Buf; Count: Cardinal): Cardinal;
begin
  try
    ReadFile(fHandle, Buf, Count, Result, nil);
  except
    Result := 0;
  end;
end;
//------------------------------------------------------------------------------
function TdgFileStream.GetSize: Cardinal;
begin
  Result := fSize;
end;
//------------------------------------------------------------------------------
function TdgFileStream.GetPos: Cardinal;
begin
  Result := SetFilePointer(fHandle, 0, nil, 1{FILE_CURRENT});
end;
//------------------------------------------------------------------------------
{$IFDEF dgR}{$ENDREGION}{$ENDIF} 
//------------------------------------------------------------------------------
{$IFDEF dgR}{$REGION 'TdgMemoryStream'}{$ENDIF}
//------------------------------------------------------------------------------
constructor TdgMemoryStream.Create(const Buf; const MemSize: Cardinal);
begin
  inherited Create;
  GetMem(fMem, MemSize);
  fSize := MemSize;
  Move(Buf, Pointer(Cardinal(fMem) + fPos)^, MemSize);
  fPos := 0;
end;
//------------------------------------------------------------------------------
constructor TdgMemoryStream.Create(const aFileName: String);
var
  cFileStream: TdgFileStream;
begin
  inherited Create;
  cFileStream := TdgFileStream.Create(aFileName);
  fSize := cFileStream.GetSize;
  GetMem(fMem, fSize);
  cFileStream.Read(fMem^, fSize);
  cFileStream.free;
  fPos := 0;
end;
//------------------------------------------------------------------------------
destructor TdgMemoryStream.Destroy;
begin
  FreeMem(fMem);
  inherited Destroy;
end;
//------------------------------------------------------------------------------
function TdgMemoryStream.Seek(aPos: Cardinal): Cardinal;
begin
  if aPos > fSize then aPos := fSize;
  fPos := aPos;
  Result := aPos;
end;
//------------------------------------------------------------------------------
function TdgMemoryStream.Read(out Buf; Count: Cardinal): Cardinal;
begin
  if fSize - fPos < Count then Result := fSize - fPos
  else Result := Count;
  if Result > 0 then Move(Pointer(Cardinal(fMem) + fPos)^, Buf, Result);
  fPos := fPos + Result;
end;
//------------------------------------------------------------------------------
function TdgMemoryStream.GetSize: Cardinal;
begin
  Result := fSize;
end;
//------------------------------------------------------------------------------
function TdgMemoryStream.GetPos: Cardinal;
begin
  Result := fPos;
end;
//------------------------------------------------------------------------------
{$IFDEF dgR}{$ENDREGION}{$ENDIF} 

{$IFDEF dgR}{$ENDREGION}{$ENDIF}
//------------------------------------------------------------------------------
{$IFDEF dgR}{$REGION '      ops_func      '}{$ENDIF}
//------------------------------------------------------------------------------
function ops_read_func(var ptr; size, nmemb: cardinal; const datasource): cardinal;
begin
  if (size = 0) or (nmemb = 0) then begin Result := 0; Exit; end;
  try
    Result := Int64(TdgStream(datasource).Read(ptr, size * nmemb)) div Int64(size);
  except
    Result := 0;
  end;
end;
//------------------------------------------------------------------------------
function ops_seek_func(const datasource; offset: Int64; whence: Integer): Integer;
begin
  try
    with TdgStream(datasource) do
      case whence of
        0: Seek(offset);
        1: Seek(GetPos + offset);
        2: Seek(GetSize - offset);
      end;
    result := 0;
  except
    result := -1;
  end;
end;
//------------------------------------------------------------------------------
function ops_close_func(const datasource): Integer;
begin
  try
    TdgStream(datasource).Free;
    result := 0;
  except
    result := -1;
  end;
end;
//------------------------------------------------------------------------------
function ops_tell_func(const datasource): Int64;
begin
  try
    result := TdgStream(datasource).GetPos;
  except
    result := -1;
  end;
end;
{$IFDEF dgR}{$ENDREGION}{$ENDIF} 
//------------------------------------------------------------------------------
{$IFDEF dgR}{$REGION '      TdgList       '}{$ENDIF}
constructor TdgList.Create(const aSize:Integer = 0);
begin
  inherited Create;
  if aSize <> 0 then SetCapacity(aSize);
end;
//------------------------------------------------------------------------------
destructor TdgList.Destroy;
begin
  Clear;
  inherited Destroy;
end;
//------------------------------------------------------------------------------
function TdgList.Add(Item: Pointer): Integer;
begin
  Result := FCount;
  if Result = FCapacity then Grow;
  FList^[Result] := Item;
  Inc(FCount);
end;
//------------------------------------------------------------------------------
procedure TdgList.Clear;
begin
  SetCount(0);
  SetCapacity(0);
end;
//------------------------------------------------------------------------------
procedure TdgList.Delete(Index: Integer);
begin
  if (Index < 0) or (Index >= FCount) then
  begin
    seLogMe('Index(' + seIntToStr(Index) + ') not found. Called in TdgList.Delete');
    Exit;
  end;
  Dec(FCount);
  if Index < FCount then System.Move(FList^[Index + 1], FList^[Index], (FCount - Index) * SizeOf(Pointer));
end;
//------------------------------------------------------------------------------
function TdgList.Get(Index: Integer): Pointer;
begin
  if (Index < 0) or (Index >= FCount) then
  begin
    seLogMe('Index(' + seIntToStr(Index) + ') not found. Called in TdgList.Get');
    Result := nil;
    Exit;
  end;
  Result := FList^[Index];
end;
//------------------------------------------------------------------------------
procedure TdgList.Grow;
var
  Delta: Integer;
begin
  if FCapacity > 64 then Delta := FCapacity div 4
  else if FCapacity > 8 then Delta := 16 else Delta := 4;
  SetCapacity(FCapacity + Delta);
end;
//------------------------------------------------------------------------------
function TdgList.IndexOf(Item: Pointer): Integer;
begin
  Result := 0;
  while (Result < FCount) and (FList^[Result] <> Item) do Inc(Result);
  if Result = FCount then Result := -1;
end;
//------------------------------------------------------------------------------
procedure TdgList.Put(Index: Integer; Item: Pointer);
begin
  if (Index < 0) or (Index >= FCount) then
  begin
    seLogMe('Index(' + seIntToStr(Index) + ') < 0 or >= FCount(' + seIntToStr(FCount) + '). Called in TdgList.Put');
    Exit;
  end;
  if Item <> FList^[Index] then FList^[Index] := Item;
end;
//------------------------------------------------------------------------------
function TdgList.Remove(Item: Pointer): Integer;
begin
  Result := IndexOf(Item);
  if Result >= 0 then Delete(Result);
end;
//------------------------------------------------------------------------------
procedure TdgList.SetCapacity(NewCapacity: Integer);
begin
  if (NewCapacity < FCount) or (NewCapacity > MaxListSize) then
  begin
    seLogMe('NewCapacity(' + seIntToStr(NewCapacity) + ') < FCount or > MaxListSize(' + seIntToStr(MaxListSize) + '). Called in TdgList.SetCapacity');
    Exit;
  end;
  if NewCapacity <> FCapacity then
  begin
    ReallocMem(FList, NewCapacity * SizeOf(Pointer));
    FCapacity := NewCapacity;
  end;
end;
//------------------------------------------------------------------------------
procedure TdgList.SetCount(NewCount: Integer);
var
  I: Integer;
begin
  if (NewCount < 0) or (NewCount > MaxListSize) then
  begin
    seLogMe('NewCount(' + seIntToStr(NewCount) + ') < 0 or > MaxListSize(' + seIntToStr(MaxListSize) + '). Called in TdgList.SetCount');
    Exit;
  end;
  if NewCount > FCapacity then SetCapacity(NewCount);
  if NewCount > FCount then FillChar(FList^[FCount], (NewCount - FCount) * SizeOf(Pointer), #0)
  else for i := FCount - 1 downto NewCount do Delete(I);
  FCount := NewCount;
end;
{$IFDEF dgR}{$ENDREGION}{$ENDIF}
//------------------------------------------------------------------------------
{$IFDEF dgR}{$REGION '      TdgTimer      '}{$ENDIF}
//-- процедура обрабытывающая сообщения, поступающие от таймеров ---------------
procedure TimerProc(HWND, uMsg, idEvent, dwTime: Integer); stdcall;
var
  i: Integer;
  Timer: TdgTimer;
begin
  for i := TL.Count-1 downto 0 do
  begin
    Timer := TL.Items[i];
    if (idEvent = Timer.FHandle) and (Assigned(Timer.OnTimer)) then
    begin
      Timer.OnTimer(Timer);
      Exit;
    end;
  end;
end;
//------------------------------------------------------------------------------
constructor TdgTimer.Create;
begin
  inherited;
  FActive := False;
  FInterval := 50;//Значение связанно с кодированием битрэйда
  FOnTimer := nil;
  TL.Add(Self);
end;
//------------------------------------------------------------------------------
destructor TdgTimer.Destroy;
begin
  Active := False;
  TL.Remove(Self);
  inherited;
end;
//------------------------------------------------------------------------------
procedure TdgTimer.SetActive(const Value: Boolean);
begin
  if FActive = Value then Exit;
  if FActive then begin
    KillTimer(0, FHandle);
    FHandle := 0;
  end;
  if Value then FHandle := SetTimer(0, 0, FInterval, @TimerProc);
  FActive := Value;
end;
//------------------------------------------------------------------------------
procedure TdgTimer.SetInterval(const Value: Integer);
begin
  if not Active then FInterval := Value
  else begin
    Active := False;
    FInterval := Value;
    Active := True;
  end;
end;
//------------------------------------------------------------------------------
function TdgTimerList.Get(index: Integer): TdgTimer;
begin
  Result := TdgTimer(inherited Get(index));
end;
//------------------------------------------------------------------------------
procedure TdgTimerList.Put(index: Integer; Item: TdgTimer);
begin
  inherited Put(index, Item);
end;
//------------------------------------------------------------------------------
{$IFDEF dgR}{$ENDREGION}{$ENDIF} 
initialization
  TL := TdgTimerList.Create(vStartQuantity);
  if seFileExists(seExtractFileDir(ParamStr(0)) + '\SoundEngineErrorLog.txt') then DeleteFile(PChar(seExtractFileDir(ParamStr(0)) + '\SoundEngineErrorLog.txt'));
finalization
  while TL.Count > 0 do TL.Items[TL.Count-1].Free;
  TL.Free;
end.

