

{This unit is part of United Openlibraries of Sound (uos)
  This is the main uos unit.
  License : modified LGPL.3
  Fred van Stappen fiens@hotmail.com }

unit uos;

{$mode objfpc}{$H+}{$inline on}
{$PACKRECORDS C}

// For custom configuration of directive to compiler --->  uos_define.inc
{$I uos_define.inc}

interface

uses 

{$IF DEFINED(mse)}
msegui, msethread, 
{$endif}

{$IF (FPC_FULLVERSION < 20701) and DEFINED(fpgui)}
fpg_base, fpg_main, 
{$endif}

{$IF DEFINED(Java)}
uos_jni, 
{$endif}

{$IF DEFINED(webstream)}
uos_httpgetthread, Pipes, 
{$ENDIF}

{$IF DEFINED(portaudio)}
uos_portaudio, 
{$endif}

{$IF DEFINED(xmp)}
uos_libxmp, 
{$endif}

{$IF DEFINED(sndfile)}
uos_LibSndFile, 
{$endif}

{$IF DEFINED(mpg123)}
uos_Mpg123, 
{$endif}

{$IF DEFINED(soundtouch)}
uos_soundtouch, 
{$endif}

{$IF DEFINED(bs2b)}
uos_bs2b, 
{$endif}

{$IF DEFINED(noiseremoval)}
uos_dsp_noiseremoval, 
{$endif}

{$IF DEFINED(neaac)}
uos_aac, 
{$endif}

{$IF DEFINED(fdkaac)}
uos_fdkaacdecoder, 
{$endif}

{$IF DEFINED(opus)}
uos_opusfile, 
{$endif}

{$IF DEFINED(shout)}
uos_shout, uos_opus, 
{$endif}

{$IF DEFINED(cdrom)}
uos_cdrom, 
{$endif}

Classes, DynLibs, ctypes, Math, sysutils;

const 
  uos_version : cint32 = 2241001;

{$IF DEFINED(bs2b)}
  BS2B_HIGH_CLEVEL = (CInt32(700)) or ((CInt32(30)) shl 16);
  BS2B_MIDDLE_CLEVEL = (CInt32(500)) or ((CInt32(45)) shl 16);
  BS2B_LOW_CLEVEL = (CInt32(360)) or ((CInt32(60)) shl 16);
  { Easy crossfeed levels (Obsolete)  }
  BS2B_HIGH_ECLEVEL = (CInt32(700)) or ((CInt32(60)) shl 16);
  BS2B_MIDDLE_ECLEVEL = (CInt32(500)) or ((CInt32(72)) shl 16);
  BS2B_LOW_ECLEVEL = (CInt32(360)) or ((CInt32(84)) shl 16);
  BS2B_DEFAULT_CLEVEL = (CInt32(700)) or ((CInt32(45)) shl 16);
  BS2B_CMOY_CLEVEL = (CInt32(700)) or ((CInt32(60)) shl 16);
  BS2B_JMEIER_CLEVEL = (CInt32(650)) or ((CInt32(95)) shl 16);
{$endif}

{$IF DEFINED(synthesizer)}
const 
  // musical note ==> frequency in hertz
  // Latin: Do, Ré, Mi, Fa, Sol, La, Si 
  // Dièse = _d example la0_d 
  la0  = 55.0;
  la0_d = 58.3;
  si0 = 61.7;
  do0 =  65.4;
  do0_d = 69.3;
  re0 = 73.4;
  re0_d = 77.8;
  mi0  = 82.4;
  fa0  = 87.3;
  fa0_d = 92.5;
  sol0 = 98.0;
  sol0_d = 103.8;
  la1  = 110.0;
  la1_d = 116.5;
  si1 = 123.5;
  do1 =  130.8;
  do1_d = 138.6;
  re1 = 146.8;
  re1_d = 155.6;
  mi1  = 164.8;
  fa1  = 174.6;
  fa1_d = 185.0;
  sol1 = 196.0;
  sol1_d = 207.7;
  la2 = 220.0;
  la2_d = 233.1;
  si2 = 2246.9;
  do2 =  261.6;
  do2_d = 277.2;
  re2 = 293.7;
  re2_d = 311.1;
  mi2  = 329.6;
  fa2  = 349.2;
  fa2_d = 370.0;
  sol2 = 392.0;
  sol2_d = 415.3;
  la3  = 440.0;
  la3_d = 466.2;
  si3 = 493.9;
  do3 =  523.3;
  do3_d = 554.4;
  re3 = 587.3;
  re3_d = 622.3;
  mi3 = 659.3;
  fa3  = 698.5;
  fa3_d = 740.0;
  sol3 = 784.0;
  sol3_d = 830.6;
  la4 = 880.0;
  la4_d = 932.4;
  si4 = 987.8;
  do4 =  1046.6;
  do4_d = 1108.8;
  re4 = 1174.6;
  re4_d = 1244.6;
  mi4 = 1318.6;
  fa4  = 1397.0;
  fa4_d = 1480.0;
  sol4 = 1568.0;
  sol4_d = 1661.2;
  la5 = 1760.0;

  // English musique note
  // A, B, C, D, E, F, G
  a0  = 55.0;
  a0_s = 58.3;
  b0 = 61.7;
  c0 =  65.4;
  c0_s = 69.3;
  d0 = 73.4;
  d0_s = 77.8;
  e0  = 82.4;
  f0  = 87.3;
  f0_s = 92.5;
  g0 = 98.0;
  g0_s = 103.8;
  a1  = 110.0;
  a1_s = 116.5;
  b1 = 123.5;
  c1 =  130.8;
  c1_s = 138.6;
  d1 = 146.8;
  d1_s = 155.6;
  e1  = 164.8;
  f1  = 174.6;
  f1_s = 185.0;
  g1 = 196.0;
  g1_s = 207.7;
  a2 = 220.0;
  a2_s = 233.1;
  b2 = 2246.9;
  c2 =  261.6;
  c2_s = 277.2;
  d2 = 293.7;
  d2_s = 311.1;
  e2  = 329.6;
  f2  = 349.2;
  f2_s = 370.0;
  g2 = 392.0;
  g2_s = 415.3;
  a3  = 440.0;
  a3_s = 466.2;
  b3 = 493.9;
  c3 =  523.3;
  c3_s = 554.4;
  d3 = 587.3;
  d3_s = 622.3;
  e3 = 659.3;
  f3  = 698.5;
  f3_s = 740.0;
  g3 = 784.0;
  g3_s = 830.6;
  a4 = 880.0;
  a4_s = 932.4;
  b4 = 987.8;
  c4 =  1046.6;
  c4_s = 1108.8;
  d4 = 1174.6;
  d4_s = 1244.6;
  e4 = 1318.6;
  f4  = 1397.0;
  f4_s = 1480.0;
  g4 = 1568.0;
  g4_s = 1661.2;
  a5 = 1760.0;
{$endif}

{$IF DEFINED(shout)}
  cFRAME_SIZE = 960;
  cSAMPLE_RATE = 48000;
  cAPPLICATION = OPUS_APPLICATION_AUDIO;
  cBITRATE = 64000;
  cMAX_FRAME_SIZE = 6 * 960;
  cMAX_PACKET_SIZE = 3 * 1276;
{$endif}

type 
  TDummyThread = class(TThread)
    protected 
      procedure execute;
      override;
  end;

{$IF DEFINED(mse)}
{$else}

type 
  TuosThread = class(TThread)
    protected 
      procedure execute;
      override;
    public 
      theparent : Tobject;

      constructor Create(CreateSuspended: boolean; AParent: TObject;
                         Const StackSize: SizeUInt = DefaultStackSize);
      overload;
      virtual;
      procedure DoTerminate;
      override;
  end;
{$endif}

type 
  TDArFloat = array of cfloat;
  TDArShort = array of cInt16;
  TDArLong = array of cInt32;

  TDArPARFloat = array of TDArFloat;
  TDArIARFloat = array of TDArPARFloat;

  PDArFloat = ^TDArFloat;
  PDArShort = ^TDArShort;
  PDArLong = ^TDArLong;

  {$IF not DEFINED(windows)}
  THandle = pointer;
  TArray = single;
{$endif}

type 
  Tuos_BufferInfos = record
    SampleRate: CDouble;
    SampleRateRoot: CDouble;
    SampleFormat: cint32;
    Channels: cint32;
    Filename: UTF8String;
    Title: UTF8String;
    Copyright: UTF8String;
    Software: UTF8String;
    Artist: UTF8String;
    Comment: UTF8String;
    Date: string;
    Tag: array[0..2] of char;
    Album: UTF8String;
    Genre: string;
    Track: string;
    HDFormat: cint32;
    Sections: cint32;
    Encoding: cint32;
    bitrate: cint32;
    Length: cint32;
    //  length samples total
    LibOpen: shortint;
    Ratio: byte;
  end;

type 
{$if not defined(fs32bit)}
  Tcount_t  = cint64;  { used for file sizes }
{$else}
  Tcount_t  = cint32;
{$endif}

type 
  Tuos_LoadResult = record
    PAloadError: shortint;
    SFloadError: shortint;
    MPloadError: shortint;
    PCloadError: shortint;
    STloadError: shortint;
    BSloadError: shortint;
    AAloadError: shortint;
    OPloadError: shortint;
    XMloadError: shortint;
    FAloadError: shortint;
    PAinitError: shortint;
    MPinitError: shortint;
  end;

type 
  Tuos_Init = class(TObject)
    public 
      evGlobalPause: PRTLEvent;
      // for global pausing

      constructor Create;
    private 

      PA_FileName: pchar;
      // PortAudio
      SF_FileName: pchar;
      // SndFile
      MP_FileName: pchar;
      // Mpg123
      AA_FileName : PChar;
      // Faad
      M4_FileName : PChar;
      // Mp4ff
      OF_FileName : PChar;
      // opusfile
      XM_FileName : PChar;
      // XMP
      FA_FileName : PChar;
      // Fdkaac
      Plug_ST_FileName: pchar;
      // Plugin SoundTouch + GetBMP
      Plug_BS_FileName: pchar;
      // Plugin bs2b

{$IF DEFINED(portaudio)}
      DefDevOut: PaDeviceIndex;
      DefDevOutInfo: PPaDeviceInfo;
      DefDevOutAPIInfo: PPaHostApiInfo;
      DefDevIn: PaDeviceIndex;
      DefDevInInfo: PPaDeviceInfo;
      DefDevInAPIInfo: PPaHostApiInfo;
{$endif}

      function loadlib: cint32;
      procedure unloadlib;
      procedure unloadlibCust(PortAudio, SndFile, Mpg123, AAC, opus, xmp, fdkaac: boolean);
      function InitLib: cint32;
      procedure unloadPlugin(PluginName: Pchar);
  end;

type 
  Tuos_DeviceInfos = record
    DeviceNum: cint32;
    DeviceName: UTF8String;
    DeviceType: UTF8String;
    DefaultDevIn: boolean;
    DefaultDevOut: boolean;
    ChannelsIn: cint32;
    ChannelsOut: cint32;
    SampleRate: CDouble;
    LatencyHighIn: CDouble;
    LatencyLowIn: CDouble;
    LatencyHighOut: CDouble;
    LatencyLowOut: CDouble;
    HostAPIName: UTF8String;
  end;

type 
  Tuos_WaveHeaderChunk = packed record
    wFormatTag: smallint;
    wChannels: word;
    wSamplesPerSec: cint32;
    wAvgBytesPerSec: cint32;
    wBlockAlign: word;
    wBitsPerSample: word;
    wcbSize: word;
  end;

type 
  Tuos_FileBuffer = record
    ERROR: word;
    wSamplesPerSec: cint32;
    wBitsPerSample: word;
    wChannels: word;
    FileFormat: shortint;
    Data: TFileStream;
    DataMS: TMemoryStream;
  end;

type 
  Tuos_Data = record
    // Global data
    Enabled: boolean;

    TypePut: shortint;
    // -1 : nothing. 
    // for Input  : 0: from audio encoded file, 1: from input device (like mic),
    //              2: from internet audio stream, 3: from Synthesizer, 4: from memory buffer,
    //              5: from endless-muted, 6: from decoded memorystream

    // for Output : 0: into wav file from filestream, 1: into output device Portaudio, 2: into stream server,
    //              3: into memory buffer, 4: into wav file from memorystream, 5: into memorystream,
    //              6: into ogg file from filestream, 7: into ogg memorystream    

    Seekable: boolean;
    Status: byte;
    Buffer: TDArFloat;
    MemoryBuffer: TDArFloat;
    MemoryStream : Tmemorystream;

    posmem : longint;

  {$IF DEFINED(opus)}
    BufferTMP: tbytes;
  {$endif}

    DSPVolumeIndex : cint32;
    DSPNoiseIndex : cint32;
    VLeft, VRight: double;
    hasfilters : boolean;
    nbfilters : cint32;
    incfilters : cint32;
    levelfilters : string;
    levelfiltersar : TDArFloat;
    PositionEnable : shortint;
    LevelEnable : shortint;
    LevelLeft, LevelRight: cfloat;
    levelArrayEnable : shortint;

{$IF DEFINED(synthesizer)}
    LookupTableLeft, LookupTableRight: array [0..1023] of  CFloat;
    PosInTableLeft, PosInTableRight: Double;
    typLsine, typRsine: cint32;
    freqLsine, freqRsine: cfloat;
    dursine, posdursine: cint32;
    harmonic: cint32;
    evenharm: shortint;
{$endif}

{$if defined(cpu64)}
    Wantframes: Tcount_t;
    OutFrames: Tcount_t;
{$else}
    Wantframes: cint32;
    OutFrames: cint32;
{$endif}

    SamplerateRoot: CDouble;
    SampleRate: CDouble;
    SampleFormat: cint32;
    Channels: cint32;
    lastbuf: shortint;

    // audio file data
    HandleSt: pointer;
  {$IF DEFINED(opus)}
    HandleOP: TOpusFile;
  {$endif}
    Filename: UTF8String;
    Title: UTF8String;
    Copyright: UTF8String;
    Software: UTF8String;
    Artist: UTF8String;
    Comment: UTF8String;
    Date: string;
    Tag: array[0..2] of char;
    Album: UTF8String;
    Genre: string;
    Track: string;
    HDFormat: cint32;
  {$IF DEFINED(sndfile)}
    Frames: Tcount_t;
  {$else}
    Frames: cint32;
  {$endif}
    Sections: cint32;
    Encoding: cint32;
    bitrate: cint32;
    Length: cint32;
    //  length samples total 
    LibOpen: shortint;
    // -1: nothing open, 0: sndfile open, 1: mpg123 open, 2: aac open, 3: cdrom, 4: opus, 5: xmp
    Ratio: byte;
    //  if mpg123 or aac then ratio := 2

    BPM : cfloat;
    numbuf : integer;
    Output: cint32;

  {$if defined(cpu64)}
    // TO CHECK
    Position: cint32;
    Poseek:  cint32;
  {$else}
    Position: cint32;
    Poseek:  cint32;
  {$endif}

  end;

type 
  TArray01 = array[0..1] of cfloat;

  Tuos_FFT = class(TObject)
    public 

      TypeFilterL, TypeFilterR: byte;
      LowFrequencyL, HighFrequencyL: cfloat;
      LowFrequencyR, HighFrequencyR: cfloat;
      GainL, GainR: cfloat;

      // Left
      a3, a32: array[0..2] of cfloat;
      b2, x0, x1, y0, y1, b22, x02, x12, y02, y12: TArray01;
      C, D, C2, D2 : cfloat;

      // Right
      a3R, a32R: array[0..2] of cfloat;
      b2R, x0R, x1R, y0R, y1R, b22R, x02R, x12R, y02R, y12R: TArray01;
      CR, DR, C2R, D2R : cfloat;

      AlsoBuf: boolean;
      VirtualBuffer: TDArFloat;
      levelstring : string;

  {$IF DEFINED(noiseremoval)}
      FNoise : TuosNoiseRemoval;
  {$endif}

      constructor Create;
  end;

type 
  TFunc = function (Var Data: Tuos_Data; Var FFT: Tuos_FFT): TDArFloat;

  {$if DEFINED(java)}
  TProc = JMethodID ;
  {$else}
  TProc = procedure  of object;
  {$endif}

  TProcOnly = procedure ;

  {$IF DEFINED(bs2b) or  DEFINED(soundtouch)}
  TPlugFunc = function (bufferin: TDArFloat; plugHandle: THandle; Abs2bd : Tt_bs2bdp; Var inputData:
                        Tuos_Data;
                        param1: float; param2: float; param3: float; param4: float;
                        param5: float; param6: float;  param7: float; param8: float): TDArFloat;
  {$endif}

type 
  Tuos_DSP = class(TObject)
    public 
      Enabled: boolean;
      BefFunc: TFunc;
      // function to execute before buffer is filled
      AftFunc: TFunc;
      // function to execute after buffer is filled
      EndFunc: TFunc;
      // function to execute at end of thread;
      LoopProc: TProc;
      // External Procedure of object to synchronize after buffer is filled 

      // for FFT
      fftdata: Tuos_FFT;

  {$IF DEFINED(Java)}
      procedure LoopProcjava;
  {$endif}

      constructor Create;

      destructor Destroy;
      override;

  end;

type 
  Tuos_InStream = class(TObject)
  {$IF DEFINED(webstream)}
    private 
      procedure UpdateIcyMetaInterval;
  {$endif}
    public 
      Data: Tuos_Data;
      DSP: array of Tuos_DSP;

      MemoryStreamDec : TMemoryStream;

  {$IF DEFINED(neaac)}
      AACI: TAACInfo;
  {$endif}

  {$IF DEFINED(cdrom)}
      pCD: PCDROMInfo;
  {$endif}

      // for web streaming
  {$IF DEFINED(webstream)}
      httpget: TThreadHttpGetter;
      // threaded http getter
  {$IF DEFINED(windows)}
  {$if defined(cpu64)}
      InHandle : Qword;
      OutHandle: Qword;
  {$else}
      InHandle : longword;
      OutHandle: longword;
  {$ENDIF}
  {$else}
      InHandle : cint32;
      OutHandle: cint32;
  {$endif}
      InPipe: TInputPipeStream;
      OutPipe: TOutputPipeStream;
  {$ENDIF}
  {$IF DEFINED(portaudio)}
      PAParam: PaStreamParameters;
  {$endif}
      LoopProc: TProc;
      // External Procedure of object to synchronize after buffer is filled 

  {$IF DEFINED(Java)}
      procedure LoopProcjava;
  {$endif}

      constructor Create;

      destructor Destroy;
      override;
  end;

type 
  Tuos_OutStream = class(TObject)
    public 
      Data: Tuos_Data;
      BufferOut: PDArFloat;
      MemorySteamOut: TMemoryStream;
      DSP: array of Tuos_DSP;
  {$IF DEFINED(portaudio)}
      PAParam: PaStreamParameters;
  {$endif}
  {$IF DEFINED(shout)}
      encoder: TOpusEncoder;
      cbits: array [0..cMAX_PACKET_SIZE - 1] of Byte;
      // cbits: tbytes;
  {$endif}
      FileBuffer: Tuos_FileBuffer;
      LoopProc: TProc;
      // External Procedure of object to synchronize after buffer is filled 
  {$IF DEFINED(Java)}
      procedure LoopProcjava;
  {$endif}

      constructor Create;

      destructor Destroy;
      override;
  end;

  Tuos_Plugin = class(TObject)
    public 
      Enabled: boolean;
      Name: string;
      PlugHandle: THandle;

  {$IF DEFINED(bs2b) or DEFINED(soundtouch)}
      Abs2b : Tt_bs2bdp;
      PlugFunc: TPlugFunc;
  {$endif}
      param1: float;
      param2: float;
      param3: float;
      param4: float;
      param5: float;
      param6: float;
      param7: float;
      param8: float;
      Buffer: TDArFloat;

      constructor Create;
  end;

type 
  Tuos_Player = class(tobject)
    protected 
   {$IF DEFINED(mse)}
      thethread : tmsethread;
   {$else}
      thethread : TuosThread;
   {$endif}
      evPause: PRTLEvent;
      // for pausing
      procedure ReadFile(x : integer);
      inline;
  {$IF DEFINED(webstream)}
      procedure ReadUrl(x : integer);
      inline;
  {$endif}
  {$IF DEFINED(synthesizer)}
      procedure ReadSynth(x : integer);
      inline;
      procedure FillLookupTable(x, typewave, channel,
                                AHarmonics: Integer; EvenHarmonics: shortint);
      inline;
  {$endif}
      procedure ReadEndless(x : integer);
      inline;
      procedure ReadMem(x : integer);
      inline;
      procedure ReadMemDec(x : integer);
      inline;
  {$IF DEFINED(portaudio)}
      procedure ReadDevice(x : integer);
      inline;
  {$endif}
      procedure WriteOutPlug(x:integer;  x2 : integer);
      inline;
      procedure WriteOut(x:integer;  x2 : integer);
      inline;
      procedure CheckIfPaused ;
      inline;
      procedure DoBeginMethods;
      inline;
      procedure DoLoopBeginMethods;
      inline;
      procedure DoLoopEndMethods;
      inline;
      procedure DoArrayLevel(x: integer);
      inline;
      procedure DoSeek(x: integer);
      inline;
      procedure DoDSPinBeforeBufProc(x: integer);
      inline;
      procedure DoDSPinAfterBufProc(x: integer);
      inline;
      procedure DoDSPOutAfterBufProc(x: integer);
      inline;
      procedure DoMainLoopProc(x: integer);
      inline;
      procedure SeekIfTerminated;
      inline;
      procedure DoTerminateNoFreePlayer;
      inline;
      procedure DoTerminatePlayer;
      inline;
      procedure DoEndProc;
      inline;

  {$IF DEFINED(mse)}
      function execute(thread: tmsethread): integer;
      inline;
  {$endif}

    public 
      isAssigned: boolean ;
      isGlobalPause: boolean ;
      Status: cint32;

      //if use -1 value (default) -> not alterate uosPlayers[],..
      Index: cint32;

      intobuf : boolean;
      // to check, needed for filetobuf

      NLooped : Integer;
      // -1 infinite loop; 0 no loop; > 0 n-loop

      NoFree : boolean;
      // Do not free the player at end of thread.

      BeginProc: TProc ;
      // External procedure of object to execute at begin of thread

      LoopBeginProc: TProc;
      // External procedure of object to execute at each begin of loop

      LoopEndProc: TProc;
      // External procedure of object to execute at each end of loop

      EndProc: TProc;
      // Procedure of object to execute at end of thread

      EndProcOnly: TProcOnly ;
      // Procedure to execute at end of thread (not of object)

      StreamIn: array of Tuos_InStream;
      StreamOut: array of Tuos_OutStream;
      PlugIn: array of Tuos_Plugin;

  {$IF DEFINED(Java)}
      PEnv : PJNIEnv;
      Obj: JObject;
      procedure beginprocjava;
      procedure endprocjava;
      procedure LoopBeginProcjava;
      procedure LoopEndProcjava;
  {$endif}

      constructor create();

      destructor Destroy;
      override;

      function IsLooped: Boolean;

      function SetGlobalEvent(isenabled : boolean) : boolean;

// Set the RTL Events Global (will pause/start/replay all the players synchro with same rtl event)) 
      // result : true if set ok. 

      // Audio methods

      procedure PlayEx(no_free: Boolean; nloop: Integer; paused: boolean= false);
      // Start playing with free at end as parameter and assign loop

      procedure Play(nloop: Integer = 0) ;
      // Start playing with loop

      procedure PlayPaused(nloop: Integer = 0) ;
      // Start play paused with loop

      procedure RePlay();
      // Resume playing after pause

      procedure Stop();
      // Stop playing and free thread

      procedure Pause();
      // Pause playing

      procedure PlayNoFree(nloop: Integer = 0) ;
      // Starting but do not free the player after stop with loop

      procedure PlayNoFreePaused(nloop: Integer = 0) ;
      // Start play paused with loop but not free player at end

      procedure FreePlayer() ;
      // Free the player: works only when PlayNoFree() was called.

 {$IF DEFINED(portaudio)}
      function AddIntoDevOut(Device: cint32; Latency: CDouble;
                             SampleRate: CDouble; Channels: cint32; SampleFormat: cint32 ;
                             FramesCount: cint32 ; ChunkCount: cint32 ): cint32;
      // Add a Output into Device Output
      // Device ( -1 is default device )
      // Latency  ( -1 is latency suggested )
      // SampleRate : delault : -1 (44100)
      // Channels : delault : -1 (2:stereo) (0: no channels, 1:mono, 2:stereo, ...)
      // SampleFormat : default : -1 (2:Int16) (0: Float32, 1:Int32, 2:Int16)
      // FramesCount : default : -1 (= 65536)
      // ChunkCount : default : -1 (= 512)
      //  result :  Output Index in array  -1 = error
      // example : OutputIndex1 := AddIntoDevOut(-1,-1,-1,-1,0,-1,-1);  
{$endif}

      function AddIntoFile(Filenamepath: PChar; SampleRate: CDouble;
                           Channels: cint32; SampleFormat: cint32 ; FramesCount: cint32 ; FileFormat
                           : cint32): cint32;
      // Add a Output into audio wav file with custom parameters from TFileStream
      // FileName : filename of saved audio wav file
      // SampleRate : delault : -1 (44100)
      // Channels : delault : -1 (2:stereo) (0: no channels, 1:mono, 2:stereo, ...)
      // SampleFormat : default : -1 (2:Int16) ( 1:Int32, 2:Int16)
      // FramesCount : default : -1 (= 4096)
      // FileFormat : default : -1 (wav) (0:wav, 1:pcm, 2:custom, 3:ogg);
      //  result : Output Index in array  -1 = error
      // example : OutputIndex1 := AddIntoFile(edit5.Text,-1,-1, 0, -1, -1);

      function AddIntoFileFromMem(Filenamepath: PChar; SampleRate: CDouble;
                                  Channels: LongInt; SampleFormat: LongInt ; FramesCount: LongInt;
                                  FileFormat: cint32): LongInt;
      // Add a Output into audio wav file with custom parameters from TMemoryStream
      // FileName : filename of saved audio wav file
      // SampleRate : delault : -1 (44100)
      // Channels : delault : -1 (2:stereo) (0: no channels, 1:mono, 2:stereo, ...)
      // SampleFormat : default : -1 (2:Int16) ( 1:Int32, 2:Int16)
      // FramesCount : default : -1 (= 4096)
      // FileFormat : default : -1 (wav) (0:wav, 1:pcm, 2:custom);
      //  result : Output Index in array     -1 = error
      // example : OutputIndex1 := AddIntoFileFromBuf(edit5.Text,-1,-1, 0, -1);

      function AddIntoMemoryBuffer(outmemory: PDArFloat) : cint32;
      // Add a Output into memory buffer
      // outmemory : pointer of buffer to use to store memory.
      // example : OutputIndex1 := AddIntoMemoryBuffer(bufmemory);

      function  AddIntoMemoryBuffer(outmemory: PDArFloat; SampleRate: CDouble;  SampleFormat:
                                    LongInt;
                                    Channels: LongInt; FramesCount: LongInt): LongInt;
      // Add a Output into TMemoryStream
      // outmemory : pointer of buffer to use to store memory.
      // SampleRate : delault : -1 (44100)
      // SampleFormat : default : -1 (0:float32) ( 1:Int32, 2:Int16)
      // Channels : delault : -1 (2:stereo) (0: no channels, 1:mono, 2:stereo, ...)
      // FramesCount : default : -1 (= 65536) 

      function AddIntoMemoryStream(Var MemoryStream: TMemoryStream; SampleRate: CDouble;
                                   SampleFormat: LongInt ; Channels: LongInt; FramesCount: LongInt;
                                   AudioFormat: cint32): LongInt;
      // Add a Output into TMemoryStream
      // MemoryStream : the TMemoryStream to use to store memory.
      // SampleRate : delault : -1 (44100)
      // SampleFormat : default : -1 (2:Int16) ( 1:Int32, 2:Int16)
      // Channels : delault : -1 (2:stereo) (0: no channels, 1:mono, 2:stereo, ...)
      // FramesCount : default : -1 (= 4096)
      // AudioFormat : default : -1 (wav) (0:wav, 1:ogg);

 {$IF DEFINED(shout)}
      function AddIntoIceServer(SampleRate : CDouble; Channels: cint; SampleFormat: cint;
                                EncodeType: cint; Port: cint; Host: pchar; User: pchar; Password:
                                pchar; MountFile :pchar): cint32;
      // Add a Output into a IceCast server for audio-web-streaming 
      // SampleRate : delault : -1 (48000)
      // Channels : delault : -1 (2:stereo) (0: no channels, 1:mono, 2:stereo, ...)
      // SampleFormat : -1 default : float32 : (0:float32, 1:Int16)
      // EncodeType : default : -1 (0:Music) (0: Music, 1:Voice)
      // Port : default : -1 (= 8000)
      // Host : default : 'def' (= '127.0.0.1')
      // User : default : 'def' (= 'source')
      // Password : default : 'def' (= 'hackme')
      // MountFile : default : 'def' (= '/example.opus')
      //  result :  Output Index in array  -1 = error
 {$endif}

{$IF DEFINED(portaudio)}
      function AddFromDevIn(Device: cint32; Latency: CDouble;
                            SampleRate: CDouble; OutputIndex: cint32;
                            SampleFormat: cint32; FramesCount : cint32 ; ChunkCount: cint32): cint32
      ;

      // Add a Input from Device Input with custom parameters
      // Device ( -1 is default Input device )
      // Latency  ( -1 is latency suggested ) )
      // SampleRate : delault : -1 (44100)

// OutputIndex : Output index of used output// -1: all output, -2: no output, other cint32 refer to a existing OutputIndex  (if multi-output then OutName = name of each output separeted by ';')
      // SampleFormat : default : -1 (2:Int16) (0: Float32, 1:Int32, 2:Int16)
      // FramesCount : default : -1 (4096)
      // ChunkCount : default : -1 (= 512)
      //  result :  otherwise Output Index in array  -1 = error
      // example : OutputIndex1 := AddFromDevice(-1,-1,-1,-1,-1, -1);
{$endif}

      function AddFromEndlessMuted(Channels : cint32; FramesCount: cint32): cint32;
      // Add a input from Endless Muted dummy sine wav
      // FramesCount = FramesCount of input-to-follow 
      // Channels = Channels of input-to-follow.

      function InputGetBuffer(InputIndex: cint32): TDArFloat;
      // Get current buffer

{$IF DEFINED(synthesizer)}
      function AddFromSynth(Channels: integer; WaveTypeL, WaveTypeR: shortint;
                            FrequencyL, FrequencyR: float; VolumeL, VolumeR: float;
                            duration : cint32; NbHarmonics: cint32; EvenHarmonics: cint32;
                            OutputIndex: cint32;  SampleFormat: cint32 ; SampleRate: CDouble ;
                            FramesCount : cint32): cint32;
      // Add a input from Synthesizer with custom parameters
      // Channels: default: -1 (2) (1 = mono, 2 = stereo)

// WaveTypeL: default: -1 (0) (0 = sine-wave, 1 = square-wave, 2= triangle, 3=sawtooth used for mono and stereo) 

// WaveTypeR: default: -1 (0) (0 = sine-wave, 1 = square-wave, 2= triangle, , 3=sawtooth used for stereo, ignored for mono) 
      // FrequencyL: default: -1 (440 htz) (Left frequency, used for mono)
      // FrequencyR: default: -1 (440 htz) (Right frequency, used for stereo, ignored for mono)
      // VolumeL: default: -1 (= 1) (from 0 to 1) => volume left
      // VolumeR: default: -1 (= 1) (from 0 to 1) => volume rigth (ignored for mono)
      // Duration: default:  -1 (= 1000)  => duration in msec (0 = endless)
      // NbHarmonics: default:  -1 (= 0) Number of Harmonics
      // EvenHarmonics: default: -1 (= 0) (0 = all harmonics, 1 = Only even harmonics)
      // OutputIndex: Output index of used output
      // -1: all output, -2: no output, other cint32 refer to 
      // a existing OutputIndex 
      // (if multi-output then OutName = name of each output separeted by ';')
      // SampleFormat: default : -1 (0: Float32) (0: Float32, 1:Int32, 2:Int16)
      // SampleRate: delault : -1 (44100)
      // FramesCount: -1 default : 1024
      //  result:  Input Index in array  -1 = error

      procedure InputSetSynth(InputIndex: cint32; WaveTypeL, WaveTypeR: shortint;
                              FrequencyL, FrequencyR: float; VolumeL, VolumeR: float; duration:
                              cint32;
                              NbHarmonic: cint32; EvenHarmonics: cint32; Enable: boolean);
      // InputIndex: one existing input index   

// WaveTypeL: do not change: -1 (0 = sine-wave 1 = square-wave, 2= triangle, 3=sawtooth used for mono and stereo) 

// WaveTypeR: do not change: -1 (0 = sine-wave 1 = square-wave, 2= triangle, 3=sawtooth used for stereo, ignored for mono) 
      // FrequencyL: do not change: -1 (Left frequency, used for mono)

     // FrequencyR: do not change: -1 (440 htz) (Right frequency, used for stereo, ignored for mono)
      // VolumeL: do not change: -1 (= 1) (from 0 to 1) => volume left
      // VolumeR: do not change: -1 (from 0 to 1) => volume rigth (ignored for mono)
      // Duration: in msec (-1 = do not change)
      // NbHarmonic: Number of Harmonics (-1 not change)
      // EvenHarmonics: default: -1 (= 0) (0 = all harmonics, 1 = Only even harmonics)
      // Enable: true or false ;
{$endif}

      function AddFromFile(Filename: Pchar; OutputIndex: cint32;
                           SampleFormat: cint32 ; FramesCount: cint32): cint32;
      // Add a input from audio file with custom parameters
      // FileName : filename of audio file

// OutputIndex : Output index of used output// -1: all output, -2: no output, other cint32 refer to a existing OutputIndex  (if multi-output then OutName = name of each output separeted by ';')
      // SampleFormat : default : -1 (2:Int16) (0: Float32, 1:Int32, 2:Int16)
      // FramesCount : default : -1 (4096)
      //  result :  Input Index in array  -1 = error
      // example : InputIndex1 := AddFromFile(edit5.Text,-1,0,-1);

      function AddFromFileIntoMemory(Filename: Pchar; OutputIndex: cint32;
                                     SampleFormat: cint32 ; FramesCount: cint32 ; numbuf : cint):
                                                                                              cint32
      ;
      // Add a input from audio file and store it into memory with custom parameters
      // FileName : filename of audio file

// OutputIndex : Output index of used output// -1: all output, -2: no output, other cint32 refer to a existing OutputIndex  (if multi-output then OutName = name of each output separeted by ';')
      // SampleFormat : default : -1 (2:Int16) (0: Float32, 1:Int32, 2:Int16)
      // FramesCount : default : -1 (4096)

// numbuf : number of buffer to add to outmemory (default : -1 = all, otherwise number max of buffers) 
      //  result :  Input Index in array  -1 = error
      // example : InputIndex1 := AddFromFileIntoMemory(edit5.Text,-1,0,-1, -1);

      function AddFromMemoryBuffer(Var MemoryBuffer: TDArFloat; Var Bufferinfos: Tuos_bufferinfos;
                                   OutputIndex: cint32; FramesCount: cint32): cint32;
      // Add a input from memory buffer with custom parameters
      // MemoryBuffer : the buffer
      // Bufferinfos : infos of the buffer

// OutputIndex : Output index of used output// -1: all output, -2: no output, other cint32 refer to a existing OutputIndex  (if multi-output then OutName = name of each output separeted by ';')// Channels : delault : -1 (2:stereo) (0: no channels, 1:mono, 2:stereo, ...)// SampleRate : delault : -1 (44100)// FramesCount : default : -1 (4096)
      // FramesCount : default : -1 (65536 div Channels)
      //  result :  Input Index in array  -1 = error
      // example : InputIndex1 := AddFromMemoryBuffer(mybuffer, buffinfos,-1,1024);

      function AddFromMemoryStream(Var MemoryStream: TMemoryStream;
                                   TypeAudio: cint32; OutputIndex: cint32; SampleFormat: cint32 ;
                                   FramesCount: cint32): cint32;
      // MemoryStream : Memory stream of encoded audio.
      // TypeAudio : default : -1 --> 0 (0: flac, ogg, wav; 1: mp3; 2:opus)

// OutputIndex : Output index of used output// -1: all output, -2: no output, other cint32 refer to a existing OutputIndex  (if multi-output then OutName = name of each output separeted by ';')
      // SampleFormat : default : -1 (2:Int16) (0: Float32, 1:Int32, 2:Int16)
      // FramesCount : default : -1 (4096)
      //  result :  Input Index in array  -1 = error
      // example : InputIndex1 := AddFromMemoryStream(mymemorystream,-1,-1,0,1024);

      function AddFromMemoryStreamDec(Var MemoryStream: TMemoryStream; Var Bufferinfos:
                                      Tuos_bufferinfos;
                                      OutputIndex: cint32; FramesCount: cint32): cint32;
      // MemoryStream : Memory-stream of decoded audio (like created by AddIntoMemoryStream)
      // Bufferinfos : infos of the Memory-stream

// OutputIndex : Output index of used output// -1: all output, -2: no output, other cint32 refer to a existing OutputIndex  (if multi-output then OutName = name of each output separeted by ';')
      // FramesCount : default : -1 (4096)
      //  result :  Input Index in array  -1 = error

{$IF DEFINED(webstream)}
      function AddFromURL(URL: PChar; OutputIndex: cint32;
                          SampleFormat: cint32 ; FramesCount: cint32 ; AudioFormat: cint32 ; ICYon:
                          boolean): cint32;
      // Add a Input from Audio URL
      // URL : URL of audio file

// OutputIndex : OutputIndex of existing Output// -1: all output, -2: no output, other cint32 : existing Output
      // SampleFormat : -1 default : Int16 (0: Float32, 1:Int32, 2:Int16)
      // FramesCount : default : -1 (4096)
      // AudioFormat : default : -1 (mp3) (0: mp3, 1: opus)
      // ICYon : ICY data on/off
      // example : InputIndex := AddFromURL('http://someserver/somesound.mp3',-1,-1,-1,-1,false);
{$ENDIF}

      function AddPlugin(PlugName: Pchar; SampleRate: CDouble;
                         Channels: cint32): cint32;
      // Add a plugin , result is PluginIndex
      // SampleRate : delault : -1 (44100)
      // Channels : delault : -1 (2:stereo) (1:mono, 2:stereo, ...)
      // 'soundtouch' 'getbpm' and 'bs2b' PlugName are registred.

{$IF DEFINED(soundtouch)}
      procedure SetPluginSoundTouch(PluginIndex: cint32; Tempo: cfloat;
                                    Pitch: cfloat; Enable: boolean);
      // PluginIndex : PluginIndex Index of a existing Plugin.

      procedure SetPluginGetBPM(PluginIndex: cint32; numofframes: integer; loop : boolean;
                                Enable: boolean);
      // PluginIndex : PluginIndex Index of a existing Plugin.  
      // numofframes: number of frames to analyse (-1 = 512 x frames)
      // loop: do new detection after previous.
{$endif}

{$IF DEFINED(bs2b)}
      procedure SetPluginBs2b(PluginIndex: cint32; level: CInt32; fcut: CInt32;
                              feed: CInt32; Enable: boolean);
      // PluginIndex : PluginIndex Index of a existing Plugin.
{$endif}

      function GetStatus() : cint32 ;
      // Get the status of the player : 0 => has stopped, 1 => is running, 2 => is paused, 
      // -1 => error or not yet played, only created.

      procedure InputSeek(InputIndex:  cint32; pos: Tcount_t);
      // change position in sample

      procedure InputSeekSeconds(InputIndex: cint32; pos: cfloat);
      // change position in seconds

      procedure InputSeekTime(InputIndex: cint32; pos: TTime);
      // change position in time format

      procedure InputSetEnable(InputIndex: cint32; enabled: boolean);
      // set enable true or false

      function InputLength(InputIndex: cint32): cint32;
      inline;
      // InputIndex : InputIndex of existing input
      //  result : Length of Input in samples

      function InputLengthSeconds(InputIndex: cint32): cfloat;
      inline;
      // InputIndex : InputIndex of existing input
      //  result : Length of Input in seconds

      function InputLengthTime(InputIndex: cint32): TTime;
      inline;
      // InputIndex : InputIndex of existing input
      //  result : Length of Input in time format

      function InputPosition(InputIndex: cint32): cint32;
      inline;
      // InputIndex : InputIndex of existing input
      // result : current postion in sample

      function InputPositionSeconds(InputIndex: cint32): float;
      inline;
      // InputIndex : InputIndex of existing input
      //  result : current postion of Input in seconds

      function InputPositionTime(InputIndex: cint32): TTime;
      inline;
      // InputIndex : InputIndex of existing input
      //  result : current postion of Input in time format

      procedure InputSetFrameCount(InputIndex: cint32 ; framecount : cint32);
      inline;
      // set number of frames to be done. (usefull for recording and level precision)

      procedure InputSetLevelEnable(InputIndex: cint32 ; levelcalc : cint32);
      // set level calculation (default is 0)
      // 0 => no calcul
      // 1 => calcul before all DSP procedures.
      // 2 => calcul after all DSP procedures.
      // 3 => calcul before and after all DSP procedures.

      procedure InputSetPositionEnable(InputIndex: cint32 ; poscalc : cint32);
      // set position calculation (default is 0)
      // 0 => no calcul
      // 1 => calcul of position.

      procedure InputSetLevelArrayEnable(InputIndex: cint32 ; levelcalc : cint32);
      // set add level calculation in level-array (default is 0)
      // 0 => no calcul
      // 1 => calcul before all DSP procedures.
      // 2 => calcul after all DSP procedures.

      function InputGetLevelLeft(InputIndex: cint32): double;
      inline;
      // InputIndex : InputIndex of existing input
      // result : left level from 0 to 1

      function InputGetLevelRight(InputIndex: cint32): double;
      inline;
      // InputIndex : InputIndex of existing input
      // result : right level from 0 to 1

      function InputFiltersGetLevelString(InputIndex: cint32): string;
      inline;
      // InputIndex : InputIndex of existing input
      // filterIndex : Filterindex of existing filter
      // result : list of left|right levels separed by $ character

      function InputFiltersGetLevelArray(InputIndex: cint32): TDArFloat;
      inline;
      // InputIndex : InputIndex of existing input
      // result : array of float of each filter. 
      //in format levelfilter0left,levelfilter0right,levelfilter1left,levelfilter2right,...

{$IF DEFINED(soundtouch)}
      function InputGetBPM(InputIndex: cint32): CDouble;
      inline;
      // InputIndex : InputIndex of existing input
      // result : left level from 0 to 1
{$endif}

      function InputUpdateTag(InputIndex: cint32): boolean;
      inline;

{$IF DEFINED(webstream) and DEFINED(mpg123)}
      function InputUpdateICY(InputIndex: cint32; Var icy_data : pchar): integer;
      inline;
{$endif}

      function InputGetTagTitle(InputIndex: cint32): pchar;
      inline;
      function InputGetTagArtist(InputIndex: cint32): pchar;
      inline;
      function InputGetTagAlbum(InputIndex: cint32): pchar;
      inline;
      function InputGetTagDate(InputIndex: cint32): pchar;
      inline;
      function InputGetTagComment(InputIndex: cint32): pchar;
      inline;
      function InputGetTagTrack(InputIndex: cint32): pchar;
      inline;
      function InputGetTagGenre(InputIndex: cint32): pchar;
      inline;
      function InputGetTagTag(InputIndex: cint32): pchar;
      inline;
      // Tag infos

      function InputAddDSP(InputIndex: cint32; BeforeFunc: TFunc;
                           AfterFunc: TFunc; EndedFunc: TFunc; LoopProc: TProc ): cint32;
      // add a DSP procedure for input
      // InputIndex d: Input Index of a existing input
      // BeforeFunc : function to do before the buffer is filled
      // AfterFunc : function to do after the buffer is filled
      // EndedFunc : function to do after thread is finish
      // LoopProc : external procedure of object to synchronize after the buffer is filled
      //  result :  index of DSPin in array  (DSPinIndex)
      // example : DSPinIndex1 := InputAddDSP(InputIndex1,@beforereverse,@afterreverse,nil);

      procedure InputSetDSP(InputIndex: cint32; DSPinIndex: cint32; Enable: boolean);
      // InputIndex : Input Index of a existing input
      // DSPIndexIn : DSP Index of a existing DSP In
      // Enable :  DSP enabled
      // example : InputSetDSP(InputIndex1,DSPinIndex1,True);

      procedure OutputSetEnable(OutputIndex: cint32; enabled: boolean);
      // set enable true or false

      function OutputAddDSP(OutputIndex: cint32; BeforeFunc: TFunc;
                            AfterFunc: TFunc; EndedFunc: TFunc; LoopProc: TProc): cint32;
      // usefull if multi output
      // OutputIndex : OutputIndex of a existing Output
      // BeforeFunc : function to do before the buffer is filled
      // AfterFunc : function to do after the buffer is filled just before to give to output
      // EndedFunc : function to do after thread is finish
      // LoopProc : external procedure of object to synchronize after the buffer is filled
      //  result : index of DSPout in array
      // example :DSPoutIndex1 := OutputAddDSP(OutputIndex1,@volumeproc,nil,nil);

      procedure OutPutSetDSP(OutputIndex: cint32; DSPoutIndex: cint32; Enable: boolean);
      // OutputIndex : OutputIndex of a existing Output
      // DSPoutIndex : DSPoutIndex of existing DSPout
      // Enable :  DSP enabled
      // example : OutPutSetDSP(OutputIndex1,DSPoutIndex1,True);

      function InputAddFilter(InputIndex: cint32;
                              TypeFilterL: shortint; LowFrequencyL, HighFrequencyL, GainL: cfloat;
                              TypeFilterR: shortint; LowFrequencyR, HighFrequencyR, GainR: cfloat;
                              AlsoBuf: boolean; LoopProc: TProc): cint32;
      // InputIndex : InputIndex of a existing Input
      // TypeFilterL: Type of filter left: 
      // ( -1 = current filter ) (fBandAll = 0, fBandSelect = 1, fBandReject = 2
      // fBandPass = 3, fLowPass = 4, fHighPass = 5)
      // LowFrequencyL : Lowest frequency left( -1 : current LowFrequency )
      // HighFrequencyL : Highest frequency left( -1 : current HighFrequency )
      // GainL : gain left to apply to filter
      // TypeFilterR: Type of filter right (ignored if mono):
      // ( -1 = current filter ) (fBandAll = 0, fBandSelect = 1, fBandReject = 2
      // LowFrequencyR : Lowest frequency Right (ignored if mono) ( -1 : current LowFrequency )
      // HighFrequencyR : Highest frequency left( -1 : current HighFrequency )
      // GainR : gain right (ignored if mono) to apply to filter ( 0 to what reasonable )
      // AlsoBuf : The filter alter buffer aswell ( otherwise, only result is filled in fft.data )
      // LoopProc : external procedure of object to synchronize after DSP done
      //  result :  index of DSPIn in array

      procedure InputSetFilter(InputIndex: cint32; FilterIndex: cint32;
                               TypeFilterL: shortint; LowFrequencyL, HighFrequencyL, GainL: cfloat;
                               TypeFilterR: shortint; LowFrequencyR, HighFrequencyR, GainR: cfloat;
                               AlsoBuf: boolean; LoopProc: TProc; Enable: boolean);
      // InputIndex : InputIndex of a existing Input
      // DSPInIndex : DSPInIndex of existing DSPIn
      // TypeFilterL: Type of filter left: 
      // ( -1 = current filter ) (fBandAll = 0, fBandSelect = 1, fBandReject = 2
      // fBandPass = 3, fLowPass = 4, fHighPass = 5)
      // LowFrequencyL : Lowest frequency left( -1 : current LowFrequency )
      // HighFrequencyL : Highest frequency left( -1 : current HighFrequency )
      // GainL : gain left to apply to filter
      // TypeFilterR: Type of filter right (ignored if mono):
      // ( -1 = current filter ) (fBandAll = 0, fBandSelect = 1, fBandReject = 2
      // LowFrequencyR : Lowest frequency Right (ignored if mono) ( -1 : current LowFrequency )
      // HighFrequencyR : Highest frequency left( -1 : current HighFrequency )
      // GainR : gain right (ignored if mono) to apply to filter ( 0 to what reasonable )
      // AlsoBuf : The filter alter buffer aswell ( otherwise, only result is filled in fft.data )
      // LoopProc : external procedure of object to synchronize after DSP done
      // Enable :  Filter enabled

      function OutputAddFilter(OutputIndex: cint32;
                               TypeFilterL: shortint; LowFrequencyL, HighFrequencyL, GainL: cfloat;
                               TypeFilterR: shortint; LowFrequencyR, HighFrequencyR, GainR: cfloat;
                               AlsoBuf: boolean; LoopProc: TProc): cint32;
      // Output : InputIndex of a existing Output
      // TypeFilterL: Type of filter left: 
      // ( -1 = current filter ) (fBandAll = 0, fBandSelect = 1, fBandReject = 2
      // fBandPass = 3, fLowPass = 4, fHighPass = 5)
      // LowFrequencyL : Lowest frequency left( -1 : current LowFrequency )
      // HighFrequencyL : Highest frequency left( -1 : current HighFrequency )
      // GainL : gain left to apply to filter
      // TypeFilterR: Type of filter right (ignored if mono):
      // ( -1 = current filter ) (fBandAll = 0, fBandSelect = 1, fBandReject = 2
      // LowFrequencyR : Lowest frequency Right (ignored if mono) ( -1 : current LowFrequency )
      // HighFrequencyR : Highest frequency left( -1 : current HighFrequency )
      // GainR : gain right (ignored if mono) to apply to filter ( 0 to what reasonable )
      // AlsoBuf : The filter alter buffer aswell ( otherwise, only result is filled in fft.data )
      // LoopProc : external procedure of object to synchronize after DSP done
      //  result :  index of DSPIn in array

      procedure OutputSetFilter(OutputIndex: cint32; FilterIndex: cint32;
                                TypeFilterL: shortint; LowFrequencyL, HighFrequencyL, GainL: cfloat;
                                TypeFilterR: shortint; LowFrequencyR, HighFrequencyR, GainR: cfloat;
                                AlsoBuf: boolean; LoopProc: TProc; Enable: boolean);
      // OuputIndex : InputIndex of a existing Output
      // DSPInIndex : DSPInIndex of existing DSPIn
      // TypeFilterL: Type of filter left: 
      // ( -1 = current filter ) (fBandAll = 0, fBandSelect = 1, fBandReject = 2
      // fBandPass = 3, fLowPass = 4, fHighPass = 5)
      // LowFrequencyL : Lowest frequency left( -1 : current LowFrequency )
      // HighFrequencyL : Highest frequency left( -1 : current HighFrequency )
      // GainL : gain left to apply to filter
      // TypeFilterR: Type of filter right (ignored if mono):
      // ( -1 = current filter ) (fBandAll = 0, fBandSelect = 1, fBandReject = 2
      // LowFrequencyR : Lowest frequency Right (ignored if mono) ( -1 : current LowFrequency )
      // HighFrequencyR : Highest frequency left( -1 : current HighFrequency )
      // GainR : gain right (ignored if mono) to apply to filter ( 0 to what reasonable )
      // AlsoBuf : The filter alter buffer aswell ( otherwise, only result is filled in fft.data )
      // LoopProc : external procedure of object to synchronize after DSP done
      // Enable :  Filter enabled

      function DSPLevel(Data: Tuos_Data): Tuos_Data;
      inline;
      // to get level of buffer (volume)

      function InputAddDSP1ChanTo2Chan(InputIndex: cint32): cint32;
      //  Convert mono 1 channel input to stereo 2 channels input.
      // Works only if the input is mono 1 channel othewise stereo 2 chan is keeped.
      // InputIndex : InputIndex of a existing Input
      //  result :  index of DSPIn in array
      // example  DSPIndex1 := InputAddDSP1ChanTo2Chan(InputIndex1);

      function InputAddDSPVolume(InputIndex: cint32; VolLeft: double;
                                 VolRight: double): cint32;
      // DSP Volume changer
      // InputIndex : InputIndex of a existing Input
      // VolLeft : Left volume
      // VolRight : Right volume
      //  result :  index of DSPIn in array
      // example  DSPIndex1 := InputAddDSPVolume(InputIndex1,1,1);

      function OutputAddDSPVolume(OutputIndex: cint32; VolLeft: double;
                                  VolRight: double): cint32;
      // DSP Volume changer
      // OutputIndex : OutputIndex of a existing Output
      // VolLeft : Left volume
      // VolRight : Right volume
      //  result :  otherwise index of DSPIn in array
      // example  DSPIndex1 := OutputAddDSPVolume(InputIndex1,1,1);

{$IF DEFINED(noiseremoval)}
      function InputAddDSPNoiseRemoval(InputIndex: cint32): cint32;
      // DSP Noise Removal
      // InputIndex : InputIndex of a existing Input
      //  result :  otherwise index of DSPIn in array
      // example  DSPIndex1 := InputAddDSPNoiseRemoval(InputIndex1);

      procedure InputSetDSPNoiseRemoval(InputIndex: cint32; Enable: boolean);

      function OutputAddDSPNoiseRemoval(OutputIndex: cint32): cint32;
      // DSP Noise Removal
      // InputIndex : OutputIndex of a existing Output
      //  result :  otherwise index of DSPOut in array
      // example  DSPIndex1 := OutputAddDSPNoiseRemoval(OutputIndex1);

      procedure OutputSetDSPNoiseRemoval(OutputIndex: cint32; Enable: boolean);
{$endif}

      procedure InputSetDSPVolume(InputIndex: cint32; DSPVolIndex: cint32;
                                  VolLeft: double; VolRight: double; Enable: boolean);
      inline;
      // InputIndex : InputIndex of a existing Input
      // DSPIndex : DSPIndex of a existing DSP
      // VolLeft : Left volume
      // VolRight : Right volume
      // Enable : Enabled
      // example  InputSetDSPVolume(InputIndex1,DSPIndex1,1,0.8,True);

      procedure OutputSetDSPVolume(OutputIndex: cint32; DSPVolIndex: cint32;
                                   VolLeft: double; VolRight: double; Enable: boolean);
      inline;
      // OutputIndex : OutputIndex of a existing Output
      // DSPIndex : DSPIndex of a existing DSP
      // VolLeft : Left volume
      // VolRight : Right volume
      // Enable : Enabled
      // example  OutputSetDSPVolume(InputIndex1,DSPIndex1,1,0.8,True);

  end;

  // General public procedure/function (accessible for library uos too)

function uos_GetInfoLibraries() : Pansichar ;

 {$IF DEFINED(portaudio)}

procedure uos_UpdateDevice();

procedure uos_GetInfoDevice();

function uos_GetInfoDeviceStr() : Pansichar ;
  {$endif}

function uos_loadlib(PortAudioFileName, SndFileFileName, Mpg123FileName, Mp4ffFileName, FaadFileName
                     , opusfileFileName, XMPFileName, fdkaacFilename : PChar) : cint32;
// load libraries... if libraryfilename = '' =>  do not load it...  You may load what and when you want...
// PortAudio => needed for dealing with audio-device
// SndFile => needed for dealing with ogg, vorbis, flac and wav audio-files
// Mpg123 => needed for dealing with mp* audio-files
// Mp4ff and Faad => needed for dealing with acc, m4a audio-files
// opusfile => needed for dealing with opus audio-files
// XMP => needed for dealing with MOD audio-files
// Fdkaac => needed for webstreaming of aac files.

// If you want to load libraries from system, replace it by "'system'"
// If some libraries are not needed, replace it by "nil", 

// for example : uos_loadlib('system', SndFileFileName, 'system', nil, nil, nil, OpusFileFileName, nil, nil)

function uos_loadlib(PortAudioFileName, SndFileFileName, Mpg123FileName, Mp4ffFileName, FaadFileName
                     , opusfileFileName, XMPFileName : PChar) : cint32;
// The same but without fdkaac. (for compatibility with previous version)

function uos_loadlib(PortAudioFileName, SndFileFileName, Mpg123FileName, Mp4ffFileName, FaadFileName
                     , opusfileFileName : PChar) : cint32;
// The same but without libxmp and fdkaac. (for compatibility with previous version)

procedure uos_unloadlib();
// Unload all libraries... Do not forget to call it before close application...

{$IF DEFINED(shout)}
function uos_LoadServerLib(ShoutFileName, OpusFileName : PChar) : cint32;
// Shout => needed for dealing with IceCast server
// Opus => needed for dealing with encoding opus stream

procedure uos_unloadServerLib();
// Unload server libraries... Do not forget to call it before close application...
{$endif}

procedure uos_unloadlibCust(PortAudio, SndFile, Mpg123, AAC, opus, xmp, fdkaac: boolean);
// Custom Unload libraries... if true, then unload the library. You may unload what and when you want...

function uos_loadPlugin(PluginName, PluginFilename: PChar) : cint32;
// load plugin...

{$IF DEFINED(soundtouch)}
function uos_GetBPM(TheBuffer: TDArFloat;  Channels: cint32; SampleRate: CDouble) : CDouble;
inline;
// From SoundTouch plugin
{$endif}

procedure uos_unloadPlugin(PluginName: PChar);
// Unload Plugin...

procedure uos_Free();
// To call at end of application.
// If uos_flat.pas was used, it will free all the uos_player created.

function uos_GetVersion() : cint32 ;
inline;
// version of uos

function uos_File2Buffer(Filename: Pchar; SampleFormat: cint32 ; Var bufferinfos: Tuos_BufferInfos ;
                         frompos : cint; numbuf : cint ): TDArFloat;
// Create a memory buffer of a audio file.
// FileName : filename of audio file  
// SampleFormat : default : -1 (2:Int16) (0: Float32, 1:Int32, 2:Int16)
// bufferinfos : the infos of the buffer.
// frompos : from position (default : -1 = from begining, otherwise position in song) 


// numbuf : number of frames to add to outmemory (default : -1 = all, otherwise number max of frames) 
//  result :  The memory buffer
// example : buffmem := uos_File2buffer(edit5.Text,0,buffmem, buffinfos, -1, -1);

function uos_Stream2Buffer(AudioFile: TMemoryStream; SampleFormat: int32 ; Var outmemory: TDArFloat;
                           Var bufferinfos: Tuos_BufferInfos ; frompos : cint; numbuf : cint):
                                                                                           TDArFloat
;
// Create a memory buffer of a audio file.
// FileName : filename of audio file
// SampleFormat : default : -1 (2:Int16) (0: Float32, 1:Int32, 2:Int16)
// Outmemory : the buffer to store data.
// bufferinfos : the infos of the buffer.
// frompos : from position (default : -1 = from begining, otherwise position in song) 

// numbuf : number of buffer to add to outmemory (default : -1 = all, otherwise number max of buffers)
//  result :  The memory buffer
// example : buffmem := uos__Stream2Buffer(edit5.Text,0,buffmem, buffinfos, -1, -1);

procedure uos_File2File(FilenameIN: Pchar; FilenameOUT: Pchar; SampleFormat: cint32 ; typeout:
                        cint32 );
// Create a audio file from a audio file.
// FileNameIN : filename of audio file IN (ogg, flac, wav, mp3, opus, aac,...)
// FileNameOUT : filename of audio file OUT (wav, pcm, custom)
// SampleFormat : default : -1 (2:Int16) (0: Float32, 1:Int32, 2:Int16)
// typeout : Type of out file (-1:default=wav, 0:wav, 1:pcm, 2:custom)
// example : InputIndex1 := uos_File2File(edit5.Text,0,buffmem);

procedure uos_MemStream2Wavfile(FileName: UTF8String; Data: TMemoryStream; BitsPerSample, chan:
                                integer;
                                samplerate : CDouble);
// Create a audio wav file from a TMemoryStream.
// FileName : filename of wav saved file
// data : the memorystream
// BitsPerSample : 16 or 32 (bit)
// chan : number of channels
// samplerate : sample rate

function CvInt16ToFloat32(Inbuf: TDArFloat): TDArFloat;
inline;
// convert buffer int16 into float32.

procedure uos_CustBufferInfos(Var bufferinfos: Tuos_BufferInfos; SampleRate: CDouble; SampleFormat
                              : cint32; Channels: cint32 ; Length: cint32);
inline;
// to initialize a custom bufferinfos: needed for AddFromMemoryBuffer() if no bufferinfos was created.
// all infos refer to the buffer used ---> length = length of the buffer div channels.

function uos_TestLoadLibrary(Filename: Pchar): boolean; inline;
// test a library to check if it can be loaded;


const 
  // error
  noError = 0;
  FilePAError = 10;
  LoadPAError = 11;
  FileSFError = 20;
  LoadSFError = 21;
  FileMPError = 30;
  LoadMPError = 31;
  LoadOPError = 41;
  FileOPError = 50;
  // uos Audio
  Stereo = 2;
  Mono = 1;

  {$IF DEFINED(android)}
  DefRate = 48000;
  {$else}
  DefRate = 44100;
  {$endif}

  // Write wav file
  ReadError = 1;
  HeaderError = 2;
  DataError = 3;
  FileCorrupt = 4;
  IncorectFileFormat = 5;
  HeaderWriteError = 6;
  StreamError = 7;
  // FFT Filters
  fBandAll = 0;
  fBandSelect = 1;
  fBandReject = 2;
  fBandPass = 3;
  fLowPass = 4;
  fHighPass = 5;

  {$IF (FPC_FULLVERSION < 20701) and DEFINED(fpgui)}
  MSG_CUSTOM1 = FPGM_USER + 1;
  {$endif}

var 
  theinc : integer = 0;
  theincbpm : integer = 0;
  tempload : boolean = false;
  paversion : UTF8String = '';
  sfversion : UTF8String = '';
  mpversion : UTF8String = '';
  tempSamplerate : CDouble;
  tempSampleFormat, tempchan, tempratio, tempLibOpen, tempLength : cint32;
  tempoutmemory: TDArFloat;
  uosPlayers: array of Tuos_Player;
  uosPlayersStat : array of cint32;
  uosLevelArray : TDArIARFloat ;
  uosDeviceInfos: array of Tuos_DeviceInfos;
  uosLoadResult: Tuos_LoadResult;
  uosDeviceCount: cint32 = 0;
  uosDefaultDeviceIn: cint32 = -1;
  uosDefaultDeviceOut: cint32 = -1;
  uosInit: Tuos_Init = nil;
  uosisactif : boolean = true;

 {$IF DEFINED(windows)}
  old8087cw: word;
 {$endif}

  {$IF DEFINED(Java)}
  theclass : JClass;
  {$endif}

implementation

function uos_TestLoadLibrary(Filename: Pchar): boolean;
// test a library to check if it can be loaded;
var
test_Handle: TLibHandle = NilHandle;
begin
 result := false;
 test_Handle := DynLibs.SafeLoadLibrary(Filename);
 if test_Handle <> DynLibs.NilHandle then
  begin
    DynLibs.UnloadLibrary(test_Handle);
    test_Handle := DynLibs.NilHandle;
    result := true;
  end;
end;

procedure TDummyThread.Execute;
begin
  FreeOnTerminate := True;
  Terminate;
end;

function RoundMath(aV:double): int64;
overload;
begin
  if aV>=0 then
    result := Trunc(aV+0.5)
  else
    result := Trunc(aV-0.5);
end;

function RoundMath(aV:single): int64;
overload;
begin
  if aV>=0 then
    result := Trunc(aV+0.5)
  else
    result := Trunc(aV-0.5);
end;

function FormatBuf(Inbuf: TDArFloat; format: cint32): TDArFloat;
inline;
var 
  x: cint32;
  ps: PDArShort;
  // if input is Int16 format
  pl: PDArLong;
  // if input is Int32 format
  pf: PDArFloat;
  // if input is Float32 format
begin

  case format of 
    2:
       begin
         ps := @inbuf;
         for x := 0 to high(inbuf) do
           ps^[x] := cint16(trunc(ps^[x]));
       end;
    1:
       begin
         pl := @inbuf;
         for x := 0 to high(inbuf) do
           pl^[x] := cint32(trunc(pl^[x]));
       end;
    0:
       begin
         pf := @inbuf;
         for x := 0 to high(inbuf) do
           pf^[x] := cfloat(pf^[x]);
       end;
  end;
  Result := Inbuf;
end;

function CvFloat32ToInt16(Inbuf: TDArFloat): TDArShort;
inline;
var 
  x, i: cint32;
  arsh: TDArShort;
begin
  SetLength(arsh, length(inbuf));
  for x := 0 to high(Inbuf) do
    begin
      i := trunc(Inbuf[x] * 32768);
      if i > 32767 then
        i := 32767
      else
        if i < -32768 then
          i := -32768;
      arsh[x] := i;
    end;
  Result := arsh;
end;

function CvFloat32ToInt32(Inbuf: TDArFloat): TDArLong;
inline;
var 
  i: int64;
  x : cint32;
  arlo: TDArLong;
begin
  SetLength(arlo, length(inbuf));
  for x := 0 to high(Inbuf) do
    begin
      i := trunc(Inbuf[x] * 2147483647);
      if i > 2147483647 then
        i := 2147483647
      else
        if i < -2147483648 then
          i := -2147483648;
      arlo[x] := i;
    end;
  Result := arlo;
end;

function CvFloat32ToInt32fl(Inbuf: TDArFloat; nb:integer): TDArFloat;
inline;
var 
  x : cint32;
  pl2: PDArLong;
  // if input is Int32 format
  pf: PDArfloat;
  buffer2 : TDArFloat;

begin
  pf := @Inbuf;
  pl2 := @Buffer2;

  setlength(buffer2,nb);

  for x := 0 to nb -1 do
    begin
      pl2^[x] := trunc((pf^[x]) * 2147483647);
    end;
  Result := buffer2;
end;

function CvInt16ToFloat32(Inbuf: TDArFloat): TDArFloat;
inline;
var 
  x: cint32;
  arfl: TDArFloat;
  ps: PDArShort;
begin
  setlength(arfl,length(Inbuf));
  ps := @inbuf;
  for x := 0 to high(Inbuf) do
    arfl[x] := ps^[x] / 32768;
  Result := arfl;
end;

function CvSteroToMono(Inbuf: TDArFloat; len : cint32): TDArFloat;
inline;
var 
  x, y: cint32;
  arsh: TDArFloat;
begin

  if len > 0 then
    begin
      setlength(arsh, len);

      x := 0;
      y := 0;

      while x < (len * 2)-1 do
        begin


      // TODO -> this takes only chan1, not (chan1+chan2)/2 -> it get bad noise dont know why ???...
          // arsh[y]  := trunc((Inbuf[x] + Inbuf[x+1])/ 2) ;

          arsh[y]  := Inbuf[x+1] ;

          inc(y);
          x := x + 2 ;
        end;

      Result := arsh;
    end
  else Result := Inbuf;
end;

function CvInt32ToFloat32(Inbuf: TDArFloat): TDArFloat;
inline;
var 
  x: cint32;
  arfl: TDArFloat;
  pl: PDArLong;
begin
  setlength(arfl,length(Inbuf));
  pl := @inbuf;
  for x := 0 to high(Inbuf) do
    arfl[x] := pl^[x] / 2147483647;
  Result := arfl;
end;

// convert a Tmemory stream into a wav file.
procedure uos_MemStream2Wavfile(FileName: UTF8String; Data: TMemoryStream; BitsPerSample, chan:
                                integer;
                                samplerate : CDouble);
var 
  f: TFileStream;
  wFileSize: LongInt;
  wChunkSize: LongInt;
  ID: array[0..3] of char;
  Header: Tuos_WaveHeaderChunk;
begin
  f := Nil;
  f := TFileStream.Create(FileName, fmCreate);
  f.Seek(0, soFromBeginning);
  try
    ID := 'RIFF';
    f.WriteBuffer(ID, 4);
    wFileSize := 0;
    f.WriteBuffer(wFileSize, 4);
    ID := 'WAVE';
    f.WriteBuffer(ID, 4);
    ID := 'fmt ';
    f.WriteBuffer(ID, 4);
    wChunkSize := SizeOf(Header);
    f.WriteBuffer(wChunkSize, 4);
    Header.wFormatTag := 1;

    Header.wChannels := chan;

    Header.wSamplesPerSec := roundmath(samplerate);

    Header.wBitsPerSample := BitsPerSample;

    Header.wBlockAlign := chan * (BitsPerSample Div 8);

    Header.wAvgBytesPerSec := roundmath(samplerate) * Header.wBlockAlign;

    Header.wcbSize := 0;
    f.WriteBuffer(Header, SizeOf(Header));
  except

end;
try
  ID := 'data';
  f.WriteBuffer(ID, 4);
  wChunkSize := Data.Size;
  f.WriteBuffer(wChunkSize, 4);
except
end;

Data.Seek(0, soFromBeginning);
f.CopyFrom(Data, Data.Size);
f.Seek(SizeOf(ID), soFromBeginning);
wFileSize := f.Size - SizeOf(ID) - SizeOf(wFileSize);
f.write(wFileSize, 4);
f.Free;
end;

function WriteWaveFromMem(FileName: UTF8String; Data: Tuos_FileBuffer): word;
var 
  f: TFileStream;
  wFileSize: LongInt;
  wChunkSize: LongInt;
  ID: array[0..3] of char;
  Header: Tuos_WaveHeaderChunk;
begin
  Result := noError;
  f := Nil;
  f := TFileStream.Create(FileName, fmCreate);
  f.Seek(0, soFromBeginning);
  if Data.FileFormat = 0 then
    begin
      // wav file
      try
        ID := 'RIFF';
        f.WriteBuffer(ID, 4);
        wFileSize := 0;
        f.WriteBuffer(wFileSize, 4);
        ID := 'WAVE';
        f.WriteBuffer(ID, 4);
        ID := 'fmt ';
        f.WriteBuffer(ID, 4);
        wChunkSize := SizeOf(Header);
        f.WriteBuffer(wChunkSize, 4);
        Header.wFormatTag := 1;

        Header.wChannels := Data.wChannels;

        Header.wSamplesPerSec := Data.wSamplesPerSec;

        Header.wBlockAlign := Data.wChannels * (Data.wBitsPerSample Div 8);

        Header.wAvgBytesPerSec := Data.wSamplesPerSec * Header.wBlockAlign;
        Header.wBitsPerSample := Data.wBitsPerSample;
        Header.wcbSize := 0;
        f.WriteBuffer(Header, SizeOf(Header));
      except
        Result := HeaderWriteError;
    end;
  try
    ID := 'data';
    f.WriteBuffer(ID, 4);
    wChunkSize := Data.DataMS.Size;
    f.WriteBuffer(wChunkSize, 4);
  except
    Result := StreamError;
end;

end;

Data.DataMS.Seek(0, soFromBeginning);
f.CopyFrom(Data.DataMS, Data.DataMS.Size);
f.Seek(SizeOf(ID), soFromBeginning);
wFileSize := f.Size - SizeOf(ID) - SizeOf(wFileSize);
f.write(wFileSize, 4);
f.Free;
end;


procedure WriteWave(FileName: UTF8String; Data: Tuos_FileBuffer);
var 
  wFileSize: cint32;
  ID: array[0..3] of char;
begin
  Data.data.Position := 42;
  //(after 'data')
  Data.data.write(Data.data.Size, 4);
  ID := 'RIFF';
  Data.data.Seek(SizeOf(ID), soFromBeginning);
  wFileSize := Data.data.Size - SizeOf(ID) - SizeOf(wFileSize);
  Data.data.write(wFileSize, 4);
  Data.data.Free;
end;

{$IF DEFINED(sndfile) or DEFINED(mpg123)}
function mpg_read_stream(ahandle: Pointer; AData: Pointer; ACount: Integer): Integer;
inline;
cdecl;
var 
  Stream: TStream absolute ahandle;
begin
  Result := Stream.Read(AData^, ACount);
end;

function mpg_seek_stream(ahandle: Pointer; offset: Integer;
                         whence: Integer): Integer;
cdecl;
var 
  Stream: TStream absolute ahandle;
begin
  try
    case whence of 
      SEEK_SET  : Result := Stream.Seek(offset, soFromBeginning);
      SEEK_CUR  : Result := Stream.Seek(offset, soFromCurrent);
      SEEK_END  : Result := Stream.Seek(offset, soFromEnd);
      else
        Result := 0;
    end;
  except
    Result := 0;
end;
end;

procedure mpg_close_stream(ahandle: Pointer);
// not used, uos does it...
begin
  TObject(ahandle).Free;
end;
{$endif}

{$IF DEFINED(webstream)}
// should use this for pipes vs memorystream ?
function mpg_seek_url(ahandle: Pointer; aoffset: Integer): Integer;
cdecl;
var 
  Stream: TStream absolute ahandle;
begin
  // pipe streams are not seekable but memory and filestreams are
  Result := 0;
  try
    if aoffset > 0 then
      Result := Stream.Seek(aoffset, soFromCurrent);
  except
    Result := 0;
end;
end;
{$endif}

function Filetobuffer(Filename: Pchar; OutputIndex: cint32;
                      SampleFormat: cint32 ; FramesCount: cint32; Var outmemory: TDArFloat;
                      Var bufferinfos: Tuos_BufferInfos; frompos: cint; numbuf : cint ): TDArFloat;
// Add a input from audio file with custom parameters
// FileName : filename of audio file

// OutputIndex : Output index of used output// -1: all output, -2: no output, other cint32 refer to a existing OutputIndex  (if multi-output then OutName = name of each output separeted by ';')
// SampleFormat : default : -1 (2:Int16) (0: Float32, 1:Int32, 2:Int16)
// FramesCount : default : -1 (4096)
// Outmemory : the buffer to store data.
// bufferinfos : the infos of the buffer
// frompos : from position (default : -1 = from begining, otherwise position in song) 

// numbuf : number of buffer to add to outmemory (default : -1 = all, otherwise number max of buffers) 
//  result :  Input Index in array  -1 = error
// example : InputIndex1 := Filetobuffer(edit5.Text,-1,0,-1, buffmem, buffinfos, -1);
var 
  theplayer : Tuos_Player;
  in1 : cint32;
begin
  theplayer := Tuos_Player.Create();

  {$IF DEFINED(uos_debug) and DEFINED(unix)}
  writeln('begin Filetobuffer');
  {$endif}

  In1 := theplayer.AddFromFile( pchar(Filename), OutputIndex, SampleFormat, FramesCount) ;
  if in1 > -1 then
    begin

  {$IF DEFINED(uos_debug) and DEFINED(unix)}
      writeln('in1 = ' + inttostr(in1));
      writeln('theplayer.InputLength(In1) = ' + inttostr(theplayer.InputLength(In1)));
  {$endif}

      SetLength(outmemory, 0);

      tempchan := theplayer.StreamIn[in1].Data.Channels;
      tempratio := theplayer.StreamIn[in1].Data.ratio;
      tempSampleFormat := theplayer.StreamIn[in1].Data.SampleFormat;
      tempSamplerate := theplayer.StreamIn[in1].Data.Samplerate;
      templength := theplayer.StreamIn[in1].Data.Length;

      bufferinfos.SampleRate := theplayer.StreamIn[in1].Data.Samplerate;
      bufferinfos.SampleRateRoot := theplayer.StreamIn[in1].Data.Samplerate;
      bufferinfos.SampleFormat := theplayer.StreamIn[in1].Data.SampleFormat;
      bufferinfos.Channels := theplayer.StreamIn[in1].Data.Channels;
      bufferinfos.Filename := theplayer.StreamIn[in1].Data.Filename;
      bufferinfos.Title := theplayer.StreamIn[in1].Data.Title;
      bufferinfos.Copyright := theplayer.StreamIn[in1].Data.Copyright;
      bufferinfos.Software := theplayer.StreamIn[in1].Data.Software;
      bufferinfos.Artist := theplayer.StreamIn[in1].Data.Artist;
      bufferinfos.Comment := theplayer.StreamIn[in1].Data.Comment;
      bufferinfos.Date := theplayer.StreamIn[in1].Data.Date;
      bufferinfos.Tag := theplayer.StreamIn[in1].Data.Tag;
      bufferinfos.Album := theplayer.StreamIn[in1].Data.Album;
      bufferinfos.Genre :=  theplayer.StreamIn[in1].Data.Genre;
      bufferinfos.Track :=  theplayer.StreamIn[in1].Data.Track;
      bufferinfos.HDFormat := theplayer.StreamIn[in1].Data.HDFormat;
      bufferinfos.Sections := theplayer.StreamIn[in1].Data.Sections;
      bufferinfos.Encoding := theplayer.StreamIn[in1].Data.Encoding;
      bufferinfos.bitrate := theplayer.StreamIn[in1].Data.bitrate;
      bufferinfos.Length := theplayer.StreamIn[in1].Data.Length;
      bufferinfos.LibOpen := 0;
      bufferinfos.Ratio := 2 ;

      theplayer.StreamIn[in1].Data.numbuf := numbuf;

      theplayer.AddIntoMemoryBuffer( @outmemory );
      theplayer.Play(0);

      if frompos > 0 then theplayer.inputseek(in1,frompos);

      while (theplayer.getstatus > 0)  do
        sleep(100);

    end;

  {$IF DEFINED(mse)}
  theplayer.destroy;
  {$endif}
  result := outmemory;
end;

 {$IF DEFINED(soundtouch)}
function uos_GetBPM(TheBuffer: TDArFloat;  Channels: cint32; SampleRate: CDouble) : CDouble;
inline;
// From SoundTouch plugin
var 
  BPMhandle : THandle;
  sr, ch : cint32;
begin

  if SampleRate = -1 then sr := 44100
  else sr := roundmath(SampleRate);
  if Channels = -1 then ch := 2
  else ch := Channels;

  BPMhandle := bpm_createInstance(ch,sr);
  bpm_putSamples(BPMhandle,  pcfloat(thebuffer),  length(thebuffer) div Channels);

  result := bpm_getBpm(BPMhandle);

  bpm_destroyInstance(BPMhandle);

end;
 {$endif}

function uos_File2Buffer(Filename: Pchar; SampleFormat: cint32 ; Var bufferinfos: Tuos_BufferInfos ;
                         frompos : cint; numbuf : cint ): TDArFloat;
// Create a memory buffer of a audio file.
// FileName : filename of audio file  
// SampleFormat : default : -1 (2:Int16) (0: Float32, 1:Int32, 2:Int16)
// bufferinfos : the infos of the buffer.
// frompos : from position (default : -1 = from begining, otherwise position in song) 

// numbuf : number of frames to add to outmemory (default : -1 = all, otherwise number max of frames) 
//  result :  The memory buffer
// example : buffmem := uos_File2buffer(edit5.Text,0,buffmem, buffinfos, -1, -1);
   {$IF DEFINED(uos_debug) and DEFINED(unix)}
var 
  i : integer;
  st : string;
   {$endif}
begin

  result :=  Filetobuffer(Filename,-1, SampleFormat, 1024, result, bufferinfos, frompos, numbuf);

  {$IF DEFINED(uos_debug) and DEFINED(unix)}
  writeln('After Filetobuffer');
  writeln('length(result) =' +inttostr(length(result)));
  st := '';
  for i := 0 to length(result) -1 do
    st := st + '|' + inttostr(i) + '=' + floattostr(result[i]);
  WriteLn('OUTPUT DATA into portaudio------------------------------');
  WriteLn(st);
  {$endif}

end;

function Streamtobuffer(AudioFile:TMemoryStream; OutputIndex: cint32;SampleFormat: cint32 ;
                        FramesCount: cint32;
                        Var outmemory: TDArFloat; Var bufferinfos: Tuos_BufferInfos; frompos: cint;
                        numbuf : cint): TDArFloat;
// Add a input from audio file with custom parameters
// FileName : filename of audio file

// OutputIndex : Output index of used output// -1: all output, -2: no output, other cint32 refer to a existing OutputIndex  (if multi-output then OutName = name of each output separeted by ';')
// SampleFormat : default : -1 (2:Int16) (0: Float32, 1:Int32, 2:Int16)
// FramesCount : default : -1 (4096)
// Outmemory : the buffer to store data.
// bufferinfos : the infos of the buffer
// frompos : from position (default : -1 = from begining, otherwise position in song) 

// numbuf : number of buffer to add to outmemory (default : -1 = all, otherwise number max of buffers)
//  result :  Input Index in array  -1 = error
// example : InputIndex1 := streamtobuffer(edit5.Text,-1,0,-1, buffmem, buffinfos, -1);

var 
  theplayer : Tuos_Player;
  in1 : cint32;

begin
  theplayer := Tuos_Player.Create();
   {$IF DEFINED(uos_debug) and DEFINED(unix)}
  writeln('begin Filetobuffer');
   {$endif}

  //In1 := theplayer.AddFromFile( pchar(Filename), OutputIndex, SampleFormat, FramesCount) ;
  In1 := theplayer.AddFromMemoryStream( AudioFile,-1, OutputIndex, SampleFormat, FramesCount) ;

  if in1 > -1 then
    begin
      {$IF DEFINED(uos_debug) and DEFINED(unix)}
      writeln('in1 = ' + inttostr(in1));
      writeln('theplayer.InputLength(In1) = ' + inttostr(theplayer.InputLength(In1)));
      {$endif}

      SetLength(outmemory, 0);

      tempchan := theplayer.StreamIn[in1].Data.Channels;
      tempratio := theplayer.StreamIn[in1].Data.ratio;
      tempSampleFormat := theplayer.StreamIn[in1].Data.SampleFormat;
      tempSamplerate := theplayer.StreamIn[in1].Data.Samplerate;
      templength := theplayer.StreamIn[in1].Data.Length;

      bufferinfos.SampleRate := theplayer.StreamIn[in1].Data.Samplerate;
      bufferinfos.SampleRateRoot := theplayer.StreamIn[in1].Data.Samplerate;
      bufferinfos.SampleFormat := theplayer.StreamIn[in1].Data.SampleFormat;
      bufferinfos.Channels := theplayer.StreamIn[in1].Data.Channels;
      bufferinfos.Filename := theplayer.StreamIn[in1].Data.Filename;
      bufferinfos.Title := theplayer.StreamIn[in1].Data.Title;
      bufferinfos.Copyright := theplayer.StreamIn[in1].Data.Copyright;
      bufferinfos.Software := theplayer.StreamIn[in1].Data.Software;
      bufferinfos.Artist := theplayer.StreamIn[in1].Data.Artist;
      bufferinfos.Comment := theplayer.StreamIn[in1].Data.Comment;
      bufferinfos.Date := theplayer.StreamIn[in1].Data.Date;
      bufferinfos.Tag := theplayer.StreamIn[in1].Data.Tag;
      bufferinfos.Album := theplayer.StreamIn[in1].Data.Album;
      bufferinfos.Track := theplayer.StreamIn[in1].Data.Track;
      bufferinfos.Genre := theplayer.StreamIn[in1].Data.Genre;
      bufferinfos.HDFormat := theplayer.StreamIn[in1].Data.HDFormat;
      bufferinfos.Sections := theplayer.StreamIn[in1].Data.Sections;
      bufferinfos.Encoding := theplayer.StreamIn[in1].Data.Encoding;
      bufferinfos.bitrate := theplayer.StreamIn[in1].Data.bitrate;
      bufferinfos.Length := theplayer.StreamIn[in1].Data.Length;
      bufferinfos.LibOpen := 0;
      bufferinfos.Ratio := 2 ;

      theplayer.StreamIn[in1].Data.numbuf := numbuf;

      theplayer.AddIntoMemoryBuffer( @outmemory );
      theplayer.Play(0);
      if frompos > 0 then theplayer.inputseek(in1,frompos);

      while (theplayer.getstatus > 0) do
        sleep(100);

    end;
  {$IF DEFINED(mse)}
  theplayer.destroy;
  {$endif}
  result := outmemory;
end;

function uos_Stream2Buffer(AudioFile: TMemoryStream; SampleFormat: int32 ;
                           Var outmemory: TDArFloat; Var bufferinfos: Tuos_BufferInfos ; frompos:
                           cint;  numbuf : cint): TDArFloat;
// Create a memory buffer of a audio file.
// FileName : filename of audio file
// SampleFormat : default : -1 (2:Int16) (0: Float32, 1:Int32, 2:Int16)
// Outmemory : the buffer to store data.
// bufferinfos : the infos of the buffer.
// frompos : from position (default : -1 = from begining, otherwise position in song) 

// numbuf : number of buffer to add to outmemory (default : -1 = all, otherwise number max of buffers)
//  result :  The memory buffer
// example : buffmem := uos_File2buffer(edit5.Text,0,buffmem, buffinfos, -1);
begin
  result := Streamtobuffer(AudioFile,-1, SampleFormat, -1, outmemory, bufferinfos, frompos, numbuf);
end;

procedure uos_File2File(FilenameIN: Pchar; FilenameOUT: Pchar; SampleFormat: cint32 ; typeout:
                        cint32 );
// Create a audio file from a audio file.
// FileNameIN : filename of audio file IN (ogg, flac, wav, mp3, opus, aac,...)
// FileNameOUT : filename of audio file OUT (wav, pcm, custom)
// SampleFormat : default : -1 (2:Int16) (0: Float32, 1:Int32, 2:Int16)

// typeout : Type of out file (-1:default=wav, 0:wav, 1:pcm, 2:custom)// example : InputIndex1 := uos_File2File(edit5.Text,0,buffmem); 
var 
  theplayer : Tuos_Player;
  in1 : cint32;
begin

  theplayer := Tuos_Player.Create();

  {$IF DEFINED(uos_debug) and DEFINED(unix)}
  writeln('begin File2file');
  {$endif}
  In1 := theplayer.AddFromFile( pchar(FilenameIN), -1, SampleFormat, -1) ;
  if in1 > -1 then
    begin
  {$IF DEFINED(uos_debug) and DEFINED(unix)}
      writeln('in1 = ' + inttostr(in1));
      writeln('theplayer.InputLength(In1) = ' + inttostr(theplayer.InputLength(In1)));
  {$endif}

      theplayer.AddIntoFile(FilenameOUT, theplayer.StreamIn[0].data.samplerate,
                            theplayer.StreamIn[0].data.channels, SampleFormat, -1 , typeout);

      theplayer.Play(0);

      while (theplayer.getstatus > 0) do
        sleep(100);
    end;
  {$IF DEFINED(mse)}
  theplayer.destroy;
  {$endif}
end;

   {$IF DEFINED(mse)}
    {$else}

constructor TuosThread.Create(CreateSuspended: boolean; AParent: TObject;
                              Const StackSize: SizeUInt);
begin
  theparent := AParent;
  FreeOnTerminate := true;
  inherited Create(CreateSuspended, StackSize);
  Priority :=  tpTimeCritical;
end;
 {$endif}

function Tuos_Player.GetStatus() : cint32 ;


// Get the status of the player : -1 => error or not yet played, 0 => has stopped, 1 => is running, 2 => is paused.
begin
  result := -1 ;
  if (isAssigned = True) then  result := Status
  else result := -1 ;
end;

function Tuos_Player.IsLooped: Boolean;
inline;
begin
  Result := (NLooped <> 0) And
            (NLooped <> 1);
end;

procedure Tuos_Player.PlayEx(no_free: Boolean; nloop: Integer; paused: boolean= false);
var 
  x: cint32;
begin
  if (isAssigned = True) and (not IsLooped) then
    begin
      NLooped := nloop;
      NoFree := no_free;

  {$IF DEFINED(portaudio)}
      for x := 0 to high(StreamOut) do
        if StreamOut[x].Data.HandleSt <> nil then
          Pa_StartStream(StreamOut[x].Data.HandleSt);
  {$endif}

      for x := 0 to high(StreamIn) do
        begin
  {$IF DEFINED(portaudio)}
          if (StreamIn[x].Data.HandleSt <> nil) and (StreamIn[x].Data.TypePut = 1) then
            Pa_StartStream(StreamIn[x].Data.HandleSt);
  {$endif}

          if (no_free = true) and (StreamIn[x].Data.HandleSt <> nil)
             and (StreamIn[x].Data.TypePut = 4) then
            StreamIn[x].Data.posmem := 0;

          if (no_free = true) and (StreamIn[x].Data.HandleSt <> nil)
             and ((StreamIn[x].Data.TypePut = 0) or (StreamIn[x].Data.TypePut = 4)) then
            InputSeek(x, 0);

          StreamIn[x].Data.status  := 1 ;

        end;

      Status := 1;

      if isGlobalPause = true then
        RTLeventSetEvent(uosInit.evGlobalPause)
      else
        RTLeventSetEvent(evPause);

      if  paused = true then
        begin
          if isGlobalPause = true then
            RTLeventReSetEvent(uosInit.evGlobalPause)
          else
            RTLeventResetEvent(evPause);
        end;

      //protect from multiple instances of thread
      if thethread = nil then
        begin
  {$IF DEFINED(mse)}
          thethread := tmsethread.create(@execute);
  {$else}
          thethread := tuosthread.Create(false,self);
  {$endif}
        end;
    end;
end;

procedure Tuos_Player.PlayPaused(nloop: Integer = 0) ;
inline;
// Start play paused with loop
begin
  PlayEx(False,nloop,true);
end;

procedure Tuos_Player.PlayNoFreePaused(nloop: Integer = 0) ;
inline;
// Start play paused with loop and not free player at end
begin
  PlayEx(true,nloop,true);
end;

procedure Tuos_Player.Play(nloop: Integer = 0) ;
inline;
begin
  PlayEx(False,nloop);
end;

procedure Tuos_Player.PlayNoFree(nloop: Integer = 0) ;
inline;
begin
  PlayEx(True,nloop);
end;

procedure Tuos_Player.FreePlayer();
// Works only when PlayNoFree() was used: free the player
begin
  if isAssigned then
    begin
      NLooped := 0;
      NoFree := False;
      //if it has never been put into play (= there is no thread for free)..
      if thethread = nil then
        Play();
      Stop;
    end;
end;

procedure Tuos_Player.RePlay();
// Resume Playing after Pause
begin
  if  (Status > 0) and (isAssigned = True) and
     (not IsLooped) then
    begin
      Status := 1;
      if isGlobalPause = true then
        RTLeventSetEvent(uosInit.evGlobalPause)
      else
        RTLeventSetEvent(evPause);
    end;
end;

procedure Tuos_Player.Stop();
begin
  //writeln(inttostr(Status));
  if (Status <> 0) and (isAssigned = True) then
    begin
      if status < 0 then playpaused;
      NLooped := 0;
      if isGlobalPause = true then
        RTLeventSetEvent(uosInit.evGlobalPause)
      else
        RTLeventSetEvent(evPause);
      Status := 0;
    end;
end;

procedure Tuos_Player.Pause();
begin
  if (Status > 0) and (isAssigned = True) then
    begin
      if isGlobalPause = true then
        RTLeventReSetEvent(uosInit.evGlobalPause)
      else
        RTLeventResetEvent(evPause);
      Status := 2;
    end;
end;

procedure Tuos_Player.InputSeek(InputIndex:cint32; pos: Tcount_t);
// change position in samples
begin
  if (isAssigned = True) then StreamIn[InputIndex].Data.Poseek := pos;
end;

procedure Tuos_Player.InputSeekSeconds(InputIndex: cint32; pos: cfloat);
// change position in seconds
begin
  if  (isAssigned = True) then  StreamIn[InputIndex].Data.Poseek := 
                                                                    trunc(pos * StreamIn[InputIndex]
                                                                    .Data.SampleRate);
end;

procedure Tuos_Player.InputSeekTime(InputIndex: cint32; pos: TTime);
// change position in time format
var 
  ho, mi, se, ms: word;
  possample : cint32;
begin
  if (isAssigned = True) then
    begin
      sysutils.DecodeTime(pos, ho, mi, se, ms);

      possample := trunc(((ho * 3600) + (mi * 60) + se + (ms / 1000)) *
                   StreamIn[InputIndex].Data.SampleRate);

      StreamIn[InputIndex].Data.Poseek := possample;

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
      WriteLn('TTime: '+ timetostr(pos));
      WriteLn('SeekTime() : Data.Poseek: '+ inttostr(possample));
 {$endif}
    end;
end;

procedure Tuos_Player.InputSetEnable(InputIndex: cint32; enabled: boolean);
// set enable true or false
begin
  StreamIn[InputIndex].data.Enabled := enabled;
end;

function Tuos_Player.InputLength(InputIndex: cint32): cint32;
// gives length in samples
begin
  result := 0;
  if (isAssigned = True) then Result := StreamIn[InputIndex].Data.Length;
end;

function Tuos_Player.InputLengthSeconds(InputIndex: cint32): cfloat;
begin
  result := 0;
  if  (isAssigned = True) then Result := StreamIn[InputIndex].Data.Length / StreamIn[InputIndex].
                                         Data.SampleRate;
end;

function Tuos_Player.InputLengthTime(InputIndex: cint32): TTime;
var 
  tmp: cfloat;
  h, m, s, ms: word;
begin
  Result := sysutils.EncodeTime(0, 0, 0, 0);
  if (isAssigned = True) then tmp := InputLengthSeconds(InputIndex);
  ms := trunc(frac(tmp) * 1000);
  h := trunc(tmp / 3600);
  m := trunc(tmp / 60 - h * 60);
  s := trunc(tmp - (h * 3600 + m * 60));
  Result := sysutils.EncodeTime(h, m, s, ms);
end;

function Tuos_Player.InputPosition(InputIndex: cint32): cint32;
// gives current position
begin
  Result := 0;
  if (isAssigned = True) then Result := StreamIn[InputIndex].Data.Position;
end;

procedure Tuos_Player.InputSetFrameCount(InputIndex: cint32 ; framecount : cint32);
begin
  if (isAssigned = True) then

    case StreamIn[InputIndex].Data.LibOpen of 
      0:
         StreamIn[InputIndex].Data.Wantframes := (framecount * StreamIn[InputIndex].Data.Channels) ;

      1:
         StreamIn[InputIndex].Data.Wantframes := (framecount * StreamIn[InputIndex].Data.Channels)
                                                 * 2  ;

      2:
         StreamIn[InputIndex].Data.Wantframes := (framecount * StreamIn[InputIndex].Data.Channels) ;

      3:
         StreamIn[InputIndex].Data.Wantframes := (framecount * StreamIn[InputIndex].Data.Channels) ;

      4:
         StreamIn[InputIndex].Data.Wantframes := (framecount * StreamIn[InputIndex].Data.Channels) ;

    end;
end;

procedure Tuos_Player.InputSetLevelArrayEnable(InputIndex: cint32 ; levelcalc : cint32);
// set add level calculation in level-array (default is 0)
// 0 => no calcul
// 1 => calcul before all DSP procedures.
// 2 => calcul after all DSP procedures.
begin
  if (isAssigned = True) then
    begin
      if index + 1 > length(uosLevelArray) then
        setlength(uosLevelArray,index + 1) ;
      if InputIndex + 1 > length(uosLevelArray[index]) then
        setlength(uosLevelArray[index],InputIndex + 1) ;
      setlength(uosLevelArray[index][InputIndex],0) ;
      StreamIn[InputIndex].Data.levelArrayEnable := levelcalc;
    end;
end;

procedure Tuos_Player.InputSetLevelEnable(InputIndex: cint32 ; levelcalc : cint32);
// set level calculation (default is 0)
// 0 => no calcul
// 1 => calcul before all DSP procedures.
// 2 => calcul after all DSP procedures.
// 3 => calcul before and after all DSP procedures.

begin
  if (isAssigned = True) then
    StreamIn[InputIndex].Data.levelEnable := levelcalc;
end;

procedure Tuos_Player.InputSetPositionEnable(InputIndex: cint32 ; poscalc : cint32);
// set position calculation (default is 0)
// 0 => no calcul
// 1 => calcul position procedures.
begin
  if (isAssigned = True) then
    StreamIn[InputIndex].Data.PositionEnable := poscalc;
end;

function Tuos_Player.InputGetLevelLeft(InputIndex: cint32): double;
// InputIndex : InputIndex of existing input
// result : left level(volume) from 0 to 1
begin
  Result := 0;
  if (isAssigned = True) then Result := StreamIn[InputIndex].Data.LevelLeft;
end;

function Tuos_Player.InputGetLevelRight(InputIndex: cint32): double;
// InputIndex : InputIndex of existing input
// result : right level(volume) from 0 to 1
begin
  Result := 0;
  if (isAssigned = True) then Result := StreamIn[InputIndex].Data.LevelRight;
end;

function Tuos_Player.InputFiltersGetLevelString(InputIndex: cint32): string;
// InputIndex : InputIndex of existing input
// result : list of left|right levels separed by $ character
begin
  Result := '';
  if (isAssigned = True) then Result := StreamIn[InputIndex].data.Levelfilters;
end;

function Tuos_Player.InputFiltersGetLevelArray(InputIndex: cint32): TDArFloat;
// InputIndex : InputIndex of existing input
// result : array of float of each filter. 
//in format levelfilter0left,levelfilter0right,levelfilter1left,levelfilter2right,...
begin
  if (isAssigned = True) then Result := StreamIn[InputIndex].data.Levelfiltersar;
end;

{$IF DEFINED(soundtouch)}
function Tuos_Player.InputGetBPM(InputIndex: cint32): CDouble;
// InputIndex : InputIndex of existing input
// result : Beat per minuts
begin
  Result := 0;
  if (isAssigned = True) then Result := StreamIn[InputIndex].Data.BPM;
end;
{$endif}

function Tuos_Player.InputPositionSeconds(InputIndex: cint32): float;
begin
  Result := 0;
  if (isAssigned = True) then Result := StreamIn[InputIndex].Data.Position / StreamIn[InputIndex].
                                        Data.SampleRate;
end;

function Tuos_Player.InputPositionTime(InputIndex: cint32): TTime;
var 
  tmp: float = 0.0;
  h: word = 0;
  m: word = 0;
  s: word = 0;
  ms: word = 0;

begin
  Result := sysutils.EncodeTime(0, 0, 0, 0);
  if (isAssigned = True) then
    begin
      tmp := InputPositionSeconds(InputIndex);
     {$IF DEFINED(uos_debug) and DEFINED(unix)}
      WriteLn('InputPositionTime(): InputPositionSeconds: '+ floattostr(tmp));
     {$endif}
      ms := trunc(frac(tmp) * 1000);
      h := trunc(tmp / 3600);
      m := trunc(tmp / 60 - h * 60);
      s := trunc(tmp - (h * 3600 + m * 60));
      Result := sysutils.EncodeTime(h, m, s, ms);
    end;
 {$IF DEFINED(uos_debug) and DEFINED(unix)}
  WriteLn('EncodeTime(): '+ timetostr(Result));
  {$endif}
end;

// for mp3 and opus files only
function Tuos_Player.InputUpdateTag(InputIndex: cint32): boolean;

{$IF DEFINED(mpg123) or DEFINED(opus) }
var 
 {$endif}

 {$IF DEFINED(mpg123)}
  // problems with mpg123 
  // mpinfo: Tmpg123_frameinfo;
  // mpid3v2: Tmpg123_id3v2;
  BufferTag: array[1..128] of char;
  F: file;
  {$endif}

  {$IF DEFINED(opus)}
  s: UTF8String;
  j: Integer;
  OpusTag: POpusTags;
  LComment: PPAnsiChar;
  LcommentLength: PInteger;
  {$endif}

begin

  Result := false;
  if (isAssigned = True) then
    begin
 {$IF DEFINED(mpg123)}
      if StreamIn[InputIndex].Data.LibOpen = 1 then// mp3
        begin
          //mpg123_info(StreamIn[InputIndex].Data.HandleSt, MPinfo);
          // custom code for reading ID3Tag ---> problems with  mpg123_id3() 

          AssignFile(F, StreamIn[InputIndex].Data.Filename);
          FileMode := fmOpenRead + fmShareDenyNone;
          Reset(F, 1);
          Seek(F, FileSize(F) - 128);
          BlockRead(F, BufferTag, SizeOf(BufferTag));
          CloseFile(F);

          StreamIn[InputIndex].Data.tag :=  copy(BufferTag, 1, 3);
          StreamIn[InputIndex].Data.title := copy(BufferTag, 4, 30);
          StreamIn[InputIndex].Data.artist := copy(BufferTag, 34, 30);
          StreamIn[InputIndex].Data.album := copy(BufferTag, 64, 30);
          StreamIn[InputIndex].Data.date :=  copy(BufferTag, 94, 4);
          StreamIn[InputIndex].Data.comment := copy(BufferTag, 98, 29);
          StreamIn[InputIndex].Data.track := inttostr(ord(BufferTag[127]));
          StreamIn[InputIndex].Data.genre := inttostr(ord(BufferTag[128]));

          Result := true;
          // ?  freeandnil(MPinfo);
        end;
{$endif}

{$IF DEFINED(opus)}
      if StreamIn[InputIndex].Data.LibOpen = 4 then// opus
        begin
          OpusTag := op_tags(StreamIn[InputIndex].Data.HandleOP, Nil);

          if OpusTag<>nil

            then
            begin

              if OpusTag^.comments>0
                then
                begin

                  LComment := OpusTag^.user_comments;
                  LcommentLength := OpusTag^.comment_lengths;
                  for j := 0 to OpusTag^.comments - 1 do
                    begin
                      SetLength(s, LcommentLength^);
                      move(Pointer(LComment^)^, Pointer(s)^, LcommentLength^);

                      if j = 1 then StreamIn[InputIndex].Data.title := s;
                      if j = 2 then StreamIn[InputIndex].Data.artist := s;
                      if j = 3 then StreamIn[InputIndex].Data.album := s;
                      if j = 4 then StreamIn[InputIndex].Data.date := s;
                      if j = 5 then StreamIn[InputIndex].Data.comment := s;
                      if j = 6 then StreamIn[InputIndex].Data.tag := s;

                      inc(LComment);
                      inc(LcommentLength);
                    end;
                  result := true;
                end;
            end;
        end;
 {$endif}
    end;
end;

{$IF DEFINED(webstream)}
// for mp3 files only
function Tuos_Player.InputUpdateICY(InputIndex: cint32; Var icy_data : pchar): integer;
begin
  Result := -1;
  if (isAssigned = True) then
    begin
      if StreamIn[InputIndex].Data.LibOpen = 1 then// mp3
        if assigned(StreamIn[InputIndex].httpget) then
          if StreamIn[InputIndex].httpget.ICYenabled = true then
            begin
 {$IF DEFINED(mpg123)}
              Result := mpg123_icy(StreamIn[InputIndex].Data.HandleSt, icy_data);
 {$endif}
            end;
    end;
end;
{$ENDIF}

function Tuos_Player.InputGetTagTitle(InputIndex: cint32): pchar;
begin
  Result := Nil;
  if (isAssigned = True) then Result := pchar(StreamIn[InputIndex].Data.title);
end;

function Tuos_Player.InputGetTagArtist(InputIndex: cint32): pchar;
begin
  Result := Nil;
  if (isAssigned = True) then Result := pchar(StreamIn[InputIndex].Data.Artist);
end;

function Tuos_Player.InputGetTagAlbum(InputIndex: cint32): pchar;
begin
  Result := Nil;
  if (isAssigned = True) then Result := pchar(StreamIn[InputIndex].Data.album);
end;

function Tuos_Player.InputGetTagComment(InputIndex: cint32): pchar;
begin
  Result := Nil;
  if (isAssigned = True) then Result := pchar(StreamIn[InputIndex].Data.comment);
end;

function Tuos_Player.InputGetTagTrack(InputIndex: cint32): pchar;
begin
  Result := Nil;
  if (isAssigned = True) then Result := pchar(StreamIn[InputIndex].Data.track);
end;

function Tuos_Player.InputGetTagGenre(InputIndex: cint32): pchar;
begin
  Result := Nil;
  if (isAssigned = True) then Result := pchar(StreamIn[InputIndex].Data.genre);
end;

function Tuos_Player.InputGetTagTag(InputIndex: cint32): pchar;
begin
  Result := Nil;
  if (isAssigned = True) then Result := pchar(StreamIn[InputIndex].Data.tag);
end;

function Tuos_Player.InputGetTagDate(InputIndex: cint32): pchar;
begin
  Result := Nil;
  if (isAssigned = True) then Result := pchar(StreamIn[InputIndex].Data.date);
end;

procedure Tuos_Player.InputSetDSP(InputIndex: cint32; DSPinIndex: cint32;
                                  Enable: boolean);
begin
  StreamIn[InputIndex].DSP[DSPinIndex].Enabled := Enable;
end;

procedure Tuos_Player.OutputSetDSP(OutputIndex: cint32; DSPoutIndex: cint32;
                                   Enable: boolean);
begin
  StreamOut[OutputIndex].DSP[DSPoutIndex].Enabled := Enable;
end;

function Tuos_Player.InputAddDSP(InputIndex: cint32; BeforeFunc: TFunc;
                                 AfterFunc: TFunc; EndedFunc: TFunc; LoopProc: TProc ): cint32;
begin
  SetLength(StreamIn[InputIndex].DSP, Length(StreamIn[InputIndex].DSP) + 1);
  StreamIn[InputIndex].DSP[Length(StreamIn[InputIndex].DSP) - 1] := Tuos_DSP.Create();
  StreamIn[InputIndex].DSP[Length(StreamIn[InputIndex].DSP) - 1].Enabled := false;
  StreamIn[InputIndex].DSP[Length(StreamIn[InputIndex].DSP) - 1].BefFunc := BeforeFunc;
  StreamIn[InputIndex].DSP[Length(StreamIn[InputIndex].DSP) - 1].AftFunc := AfterFunc;
  StreamIn[InputIndex].DSP[Length(StreamIn[InputIndex].DSP) - 1].EndFunc := EndedFunc;
  StreamIn[InputIndex].DSP[Length(StreamIn[InputIndex].DSP) - 1].LoopProc := LoopProc;
  StreamIn[InputIndex].DSP[Length(StreamIn[InputIndex].DSP) - 1].Enabled := True;

  Result := Length(StreamIn[InputIndex].DSP) - 1;
end;

procedure Tuos_Player.OutputSetEnable(OutputIndex: cint32; enabled: boolean);
// set enable true or false
begin
  StreamOut[OutputIndex].data.Enabled := enabled;
end;

function Tuos_Player.OutputAddDSP(OutputIndex: cint32; BeforeFunc: TFunc;
                                  AfterFunc: TFunc; EndedFunc: TFunc; LoopProc: TProc): cint32;
begin
  SetLength(StreamOut[OutputIndex].DSP, Length(StreamOut[OutputIndex].DSP) + 1);
  StreamOut[OutputIndex].DSP[Length(StreamOut[OutputIndex].DSP) - 1] := 
                                                                        Tuos_DSP.Create;
  StreamOut[OutputIndex].DSP[Length(StreamOut[OutputIndex].DSP) - 1].Enabled := false;
  StreamOut[OutputIndex].DSP[Length(StreamOut[OutputIndex].DSP) - 1].BefFunc := 
                                                                                BeforeFunc;
  StreamOut[OutputIndex].DSP[Length(StreamOut[OutputIndex].DSP) - 1].AftFunc := 
                                                                                AfterFunc;
  StreamOut[OutputIndex].DSP[Length(StreamOut[OutputIndex].DSP) - 1].EndFunc := 
                                                                                EndedFunc;
  StreamOut[OutputIndex].DSP[Length(StreamOut[OutputIndex].DSP) - 1].LoopProc := 
                                                                                 LoopProc;
  StreamOut[OutputIndex].DSP[Length(StreamOut[OutputIndex].DSP) - 1].Enabled := True;
  Result := Length(StreamOut[OutputIndex].DSP) - 1;
end;

procedure Tuos_Player.InputSetFilter(InputIndex: cint32; FilterIndex: cint32;
                                     TypeFilterL: shortint; LowFrequencyL, HighFrequencyL, GainL:
                                     cfloat;
                                     TypeFilterR: shortint; LowFrequencyR, HighFrequencyR, GainR:
                                     cfloat;
                                     AlsoBuf: boolean; LoopProc: TProc; Enable: boolean);
// InputIndex : InputIndex of a existing Input
// DSPInIndex : DSPInIndex of existing DSPIn
// TypeFilterL: Type of filter left: 
// ( -1 = current filter ) (fBandAll = 0, fBandSelect = 1, fBandReject = 2
// LowFrequencyL : Lowest frequency left( -1 : current LowFrequency )
// HighFrequencyL : Highest frequency left( -1 : current HighFrequency )
// GainL : gain left to apply to filter
// TypeFilterR: Type of filter right (ignored if mono):
// ( -1 = current filter ) (fBandAll = 0, fBandSelect = 1, fBandReject = 2
// LowFrequencyR : Lowest frequency Right (ignored if mono) ( -1 : current LowFrequency )
// HighFrequencyR : Highest frequency left( -1 : current HighFrequency )
// GainR : gain right (ignored if mono) to apply to filter ( 0 to what reasonable )
// AlsoBuf : The filter alter buffer aswell ( otherwise, only result is filled in fft.data )
// LoopProc : external procedure of object to synchronize after DSP done
// Enable :  Filter enabled

begin
  if isAssigned = true then
    begin
      StreamIn[InputIndex].DSP[FilterIndex].fftdata.AlsoBuf := AlsoBuf;
      StreamIn[InputIndex].DSP[FilterIndex].Enabled := Enable;

      if LowFrequencyL = -1 then
        LowFrequencyL := StreamIn[InputIndex].DSP[FilterIndex].fftdata.LowFrequencyL;
      if LowFrequencyL = -1 then
        LowFrequencyL := StreamIn[InputIndex].DSP[FilterIndex].fftdata.HighFrequencyL;
      if GainL <> -1 then
        StreamIn[InputIndex].DSP[FilterIndex].fftdata.Gainl := cfloat(Gainl);

      if LowFrequencyR = -1 then
        LowFrequencyR := StreamIn[InputIndex].DSP[FilterIndex].fftdata.LowFrequencyR;
      if LowFrequencyR = -1 then
        LowFrequencyR := StreamIn[InputIndex].DSP[FilterIndex].fftdata.HighFrequencyR;
      if GainR <> -1 then
        StreamIn[InputIndex].DSP[FilterIndex].fftdata.GainR := cfloat(GainR);

      if TypeFilterL <> -1 then
        begin
          StreamIn[InputIndex].DSP[FilterIndex].fftdata.typefilterL := TypeFilterL;
          StreamIn[InputIndex].DSP[FilterIndex].fftdata.C := 0.0;
          StreamIn[InputIndex].DSP[FilterIndex].fftdata.D := 0.0;
          StreamIn[InputIndex].DSP[FilterIndex].fftdata.a3[0] := 0.0;
          StreamIn[InputIndex].DSP[FilterIndex].fftdata.a3[1] := 0.0;
          StreamIn[InputIndex].DSP[FilterIndex].fftdata.a3[2] := 0.0;
          StreamIn[InputIndex].DSP[FilterIndex].fftdata.b2[0] := 0.0;
          StreamIn[InputIndex].DSP[FilterIndex].fftdata.b2[1] := 0.0;
          StreamIn[InputIndex].DSP[FilterIndex].fftdata.C2 := 0.0;
          StreamIn[InputIndex].DSP[FilterIndex].fftdata.D2 := 0.0;
          StreamIn[InputIndex].DSP[FilterIndex].fftdata.a32[0] := 0.0;
          StreamIn[InputIndex].DSP[FilterIndex].fftdata.a32[1] := 0.0;
          StreamIn[InputIndex].DSP[FilterIndex].fftdata.a32[2] := 0.0;
          StreamIn[InputIndex].DSP[FilterIndex].fftdata.b22[0] := 0.0;
          StreamIn[InputIndex].DSP[FilterIndex].fftdata.b22[1] := 0.0;

          case TypeFilterL of 
            1: // DSPFFTBandSelect := DSPFFTBandReject + DSPFFTBandPass
               begin
                 //  DSPFFTBandReject

                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.C := 
                                                                    Tan(Pi * (HighFrequencyL -
                                                                    LowFrequencyl + 1) /
                                                                    StreamIn[InputIndex].Data.
                                                                    SampleRate);
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.D := 
                                                                    2 * Cos(2 * Pi * (roundmath(
                                                                    HighFrequencyl + LowFrequencyl)
                                                                    shr 1) /
                                                                    StreamIn[InputIndex].Data.
                                                                    SampleRate);
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.a3[0] := 
                                                                        1 / (1 + StreamIn[InputIndex
                                                                        ].DSP[FilterIndex].fftdata.C
                                                                        );
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.a3[1] := 
                                                                        -StreamIn[InputIndex].DSP[
                                                                        FilterIndex].fftdata.D *
                                                                        StreamIn[InputIndex].DSP[
                                                                        FilterIndex].fftdata.a3[0];
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.a3[2] := 
                                                                        StreamIn[InputIndex].DSP[
                                                                        FilterIndex].fftdata.a3[0];
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.b2[0] := 
                                                                        StreamIn[InputIndex].DSP[
                                                                        FilterIndex].fftdata.a3[1];
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.b2[1] := 
                                                                        (1 - StreamIn[InputIndex].
                                                                        DSP[FilterIndex].fftdata.C)
                                                                        *
                                                                        StreamIn[InputIndex].DSP[
                                                                        FilterIndex].fftdata.a3[0];
                 //  DSPFFTBandPass
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.C2 := 
                                                                     1 / Tan(Pi * (HighFrequencyl -
                                                                     LowFrequencyl + 1) /
                                                                     StreamIn[InputIndex].Data.
                                                                     SampleRate);
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.D2 := 
                                                                     2 * Cos(2 * Pi * (roundmath(
                                                                     HighFrequencyl + LowFrequencyl)
                                                                     shr 1) /
                                                                     StreamIn[InputIndex].Data.
                                                                     SampleRate);
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.a32[0] := 
                                                                         1 / (1 + StreamIn[
                                                                         InputIndex].DSP[FilterIndex
                                                                         ].fftdata.C2);
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.a32[1] := 0.0;
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.a32[2] := 
                                                                         -StreamIn[InputIndex].DSP[
                                                                         FilterIndex].fftdata.a32[0]
                 ;
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.b22[0] := 
                                                                         -StreamIn[InputIndex].DSP[
                                                                         FilterIndex].fftdata.C2 *
                                                                         StreamIn[InputIndex].DSP[
                                                                         FilterIndex].fftdata.D2 *
                                                                         StreamIn[InputIndex].DSP[
                                                                         FilterIndex].fftdata.a32[0]
                 ;
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.b22[1] := 
                                                                         (StreamIn[InputIndex].DSP[
                                                                         FilterIndex].fftdata.C2 - 1
                                                                         ) *
                                                                         StreamIn[InputIndex].DSP[
                                                                         FilterIndex].fftdata.a32[0]
                 ;
                 //
               end;

            2: //  DSPFFTBandReject
               begin
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.C := 
                                                                    Tan(Pi * (HighFrequencyl -
                                                                    LowFrequencyl + 1) /
                                                                    StreamIn[InputIndex].Data.
                                                                    SampleRate);
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.D := 
                                                                    2 * Cos(2 * Pi * (roundmath(
                                                                    HighFrequencyl + LowFrequencyl)
                                                                    shr 1) /
                                                                    StreamIn[InputIndex].Data.
                                                                    SampleRate);
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.a3[0] := 
                                                                        1 / (1 + StreamIn[InputIndex
                                                                        ].DSP[FilterIndex].fftdata.C
                                                                        );
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.a3[1] := 
                                                                        -StreamIn[InputIndex].DSP[
                                                                        FilterIndex].fftdata.D *
                                                                        StreamIn[InputIndex].DSP[
                                                                        FilterIndex].fftdata.a3[0];
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.a3[2] := 
                                                                        StreamIn[InputIndex].DSP[
                                                                        FilterIndex].fftdata.a3[0];
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.b2[0] := 
                                                                        StreamIn[InputIndex].DSP[
                                                                        FilterIndex].fftdata.a3[1];
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.b2[1] := 
                                                                        (1 - StreamIn[InputIndex].
                                                                        DSP[FilterIndex].fftdata.C)
                                                                        *
                                                                        StreamIn[InputIndex].DSP[
                                                                        FilterIndex].fftdata.a3[0];
               end;

            3: //  DSPFFTBandPass
               begin

                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.C := 
                                                                    1 / Tan(Pi * (HighFrequencyl -
                                                                    LowFrequencyl + 1) /
                                                                    StreamIn[InputIndex].Data.
                                                                    SampleRate);
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.D := 
                                                                    2 * Cos(2 * Pi * (roundmath(
                                                                    HighFrequencyl + LowFrequencyl)
                                                                    shr 1) /
                                                                    StreamIn[InputIndex].Data.
                                                                    SampleRate);
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.a3[0] := 
                                                                        1 / (1 + StreamIn[InputIndex
                                                                        ].DSP[FilterIndex].fftdata.C
                                                                        );
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.a3[1] := 0.0;
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.a3[2] := 
                                                                        -StreamIn[InputIndex].DSP[
                                                                        FilterIndex].fftdata.a3[0];
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.b2[0] := 
                                                                        -StreamIn[InputIndex].DSP[
                                                                        FilterIndex].fftdata.C *
                                                                        StreamIn[InputIndex].DSP[
                                                                        FilterIndex].fftdata.D *
                                                                        StreamIn[InputIndex].DSP[
                                                                        FilterIndex].fftdata.a3[0];
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.b2[1] := 
                                                                        (StreamIn[InputIndex].DSP[
                                                                        FilterIndex].fftdata.C - 1)
                                                                        *
                                                                        StreamIn[InputIndex].DSP[
                                                                        FilterIndex].fftdata.a3[0];
               end;

            4: //  DSPFFTLowPass
               begin

                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.C := 
                                                                    1 / Tan(Pi * LowFrequencyl /
                                                                    StreamIn[InputIndex].Data.
                                                                    SampleRate);

                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.a3[0] := 
                                                                        1 / (1 + Sqrt(2) * StreamIn[
                                                                        InputIndex].DSP[FilterIndex]
                                                                        .fftdata.C +
                                                                        StreamIn[InputIndex].DSP[
                                                                        FilterIndex].fftdata.C *
                                                                        StreamIn[InputIndex].DSP[
                                                                        FilterIndex].fftdata.C);
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.a3[1] := 
                                                                        2 * StreamIn[InputIndex].DSP
                                                                        [FilterIndex].fftdata.a3[0];
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.a3[2] := 
                                                                        StreamIn[InputIndex].DSP[
                                                                        FilterIndex].fftdata.a3[0];
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.b2[0] := 
                                                                        2 * (1 - StreamIn[InputIndex
                                                                        ].DSP[FilterIndex].fftdata.C
                                                                        *
                                                                        StreamIn[InputIndex].DSP[
                                                                        FilterIndex].fftdata.C) *
                                                                        StreamIn[InputIndex].DSP[
                                                                        FilterIndex].fftdata.a3[0];
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.b2[1] := 
                                                                        (1 - Sqrt(2) * StreamIn[
                                                                        InputIndex].DSP[FilterIndex]
                                                                        .fftdata.C +
                                                                        StreamIn[InputIndex].DSP[
                                                                        FilterIndex].fftdata.C *
                                                                        StreamIn[InputIndex].DSP[
                                                                        FilterIndex].fftdata.C) *
                                                                        StreamIn[InputIndex].DSP[
                                                                        FilterIndex].fftdata.a3[0];
               end;

            5: //  DSPFFTHighPass
               begin
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.C := 
                                                                    Tan(Pi * HighFrequencyl /
                                                                    StreamIn[InputIndex].Data.
                                                                    SampleRate);

                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.a3[0] := 
                                                                        1 / (1 + Sqrt(2) * StreamIn[
                                                                        InputIndex].DSP[FilterIndex]
                                                                        .fftdata.C +
                                                                        StreamIn[InputIndex].DSP[
                                                                        FilterIndex].fftdata.C *
                                                                        StreamIn[InputIndex].DSP[
                                                                        FilterIndex].fftdata.C);
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.a3[1] := 

                                                                        -2 * StreamIn[InputIndex].
                                                                        DSP[FilterIndex].fftdata.a3[
                                                                        0];
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.a3[2] := 
                                                                        StreamIn[InputIndex].DSP[
                                                                        FilterIndex].fftdata.a3[0];
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.b2[0] := 
                                                                        2 * (StreamIn[InputIndex].
                                                                        DSP[FilterIndex].fftdata.C *
                                                                        StreamIn[InputIndex].DSP[
                                                                        FilterIndex].fftdata.C - 1)
                                                                        *
                                                                        StreamIn[InputIndex].DSP[
                                                                        FilterIndex].fftdata.a3[0];
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.b2[1] := 
                                                                        (1 - Sqrt(2) * StreamIn[
                                                                        InputIndex].DSP[FilterIndex]
                                                                        .fftdata.C +
                                                                        StreamIn[InputIndex].DSP[
                                                                        FilterIndex].fftdata.C *
                                                                        StreamIn[InputIndex].DSP[
                                                                        FilterIndex].fftdata.C) *
                                                                        StreamIn[InputIndex].DSP[
                                                                        FilterIndex].fftdata.a3[0];
               end;
          end;
        end;

      if TypeFilterR <> -1 then
        begin
          StreamIn[InputIndex].DSP[FilterIndex].fftdata.typefilterR := TypeFilterR;
          StreamIn[InputIndex].DSP[FilterIndex].fftdata.Cr := 0.0;
          StreamIn[InputIndex].DSP[FilterIndex].fftdata.Dr := 0.0;
          StreamIn[InputIndex].DSP[FilterIndex].fftdata.a3r[0] := 0.0;
          StreamIn[InputIndex].DSP[FilterIndex].fftdata.a3r[1] := 0.0;
          StreamIn[InputIndex].DSP[FilterIndex].fftdata.a3r[2] := 0.0;
          StreamIn[InputIndex].DSP[FilterIndex].fftdata.b2r[0] := 0.0;
          StreamIn[InputIndex].DSP[FilterIndex].fftdata.b2r[1] := 0.0;
          StreamIn[InputIndex].DSP[FilterIndex].fftdata.C2r := 0.0;
          StreamIn[InputIndex].DSP[FilterIndex].fftdata.D2r := 0.0;
          StreamIn[InputIndex].DSP[FilterIndex].fftdata.a32r[0] := 0.0;
          StreamIn[InputIndex].DSP[FilterIndex].fftdata.a32r[1] := 0.0;
          StreamIn[InputIndex].DSP[FilterIndex].fftdata.a32r[2] := 0.0;
          StreamIn[InputIndex].DSP[FilterIndex].fftdata.b22r[0] := 0.0;
          StreamIn[InputIndex].DSP[FilterIndex].fftdata.b22r[1] := 0.0;

          case TypeFilterR of 
            1: // DSPFFTBandSelect := DSPFFTBandReject + DSPFFTBandPass
               begin
                 //  DSPFFTBandReject
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.Cr := 
                                                                     Tan(Pi * (HighFrequencyr -
                                                                     LowFrequencyr + 1) /
                                                                     StreamIn[InputIndex].Data.
                                                                     SampleRate);
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.Dr := 
                                                                     2 * Cos(2 * Pi * (roundmath(
                                                                     HighFrequencyr + LowFrequencyr)
                                                                     shr 1) /
                                                                     StreamIn[InputIndex].Data.
                                                                     SampleRate);
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.a3r[0] := 
                                                                         1 / (1 + StreamIn[
                                                                         InputIndex].DSP[FilterIndex
                                                                         ].fftdata.Cr);
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.a3r[1] := 
                                                                         -StreamIn[InputIndex].DSP[
                                                                         FilterIndex].fftdata.Dr *
                                                                         StreamIn[InputIndex].DSP[
                                                                         FilterIndex].fftdata.a3r[0]
                 ;
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.a3r[2] := 
                                                                         StreamIn[InputIndex].DSP[
                                                                         FilterIndex].fftdata.a3r[0]
                 ;
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.b2r[0] := 
                                                                         StreamIn[InputIndex].DSP[
                                                                         FilterIndex].fftdata.a3r[1]
                 ;
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.b2r[1] := 
                                                                         (1 - StreamIn[InputIndex].
                                                                         DSP[FilterIndex].fftdata.Cr
                                                                         ) *
                                                                         StreamIn[InputIndex].DSP[
                                                                         FilterIndex].fftdata.a3r[0]
                 ;
                 //  DSPFFTBandPass
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.C2r := 
                                                                      1 / Tan(Pi * (HighFrequencyr -
                                                                      LowFrequencyr + 1) /
                                                                      StreamIn[InputIndex].Data.
                                                                      SampleRate);
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.D2r := 
                                                                      2 * Cos(2 * Pi * (roundmath(
                                                                      HighFrequencyr + LowFrequencyr
                                                                      ) shr 1) /
                                                                      StreamIn[InputIndex].Data.
                                                                      SampleRate);
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.a32r[0] := 
                                                                          1 / (1 + StreamIn[
                                                                          InputIndex].DSP[
                                                                          FilterIndex].fftdata.C2r);
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.a32r[1] := 0.0;
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.a32r[2] := 
                                                                          -StreamIn[InputIndex].DSP[
                                                                          FilterIndex].fftdata.a32r[
                                                                          0];
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.b22r[0] := 
                                                                          -StreamIn[InputIndex].DSP[
                                                                          FilterIndex].fftdata.C2r *
                                                                          StreamIn[InputIndex].DSP[
                                                                          FilterIndex].fftdata.D2r *
                                                                          StreamIn[InputIndex].DSP[
                                                                          FilterIndex].fftdata.a32r[
                                                                          0];
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.b22r[1] := 
                                                                          (StreamIn[InputIndex].DSP[
                                                                          FilterIndex].fftdata.C2r -
                                                                          1) *
                                                                          StreamIn[InputIndex].DSP[
                                                                          FilterIndex].fftdata.a32r[
                                                                          0];
                 //
               end;

            2: //  DSPFFTBandReject
               begin
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.Cr := 
                                                                     Tan(Pi * (HighFrequencyr -
                                                                     LowFrequencyr + 1) /
                                                                     StreamIn[InputIndex].Data.
                                                                     SampleRate);
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.Dr := 
                                                                     2 * Cos(2 * Pi * (roundmath(
                                                                     HighFrequencyr + LowFrequencyr)
                                                                     shr 1) /
                                                                     StreamIn[InputIndex].Data.
                                                                     SampleRate);
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.a3r[0] := 
                                                                         1 / (1 + StreamIn[
                                                                         InputIndex].DSP[FilterIndex
                                                                         ].fftdata.Cr);
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.a3r[1] := 
                                                                         -StreamIn[InputIndex].DSP[
                                                                         FilterIndex].fftdata.Dr *
                                                                         StreamIn[InputIndex].DSP[
                                                                         FilterIndex].fftdata.a3r[0]
                 ;
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.a3r[2] := 
                                                                         StreamIn[InputIndex].DSP[
                                                                         FilterIndex].fftdata.a3r[0]
                 ;
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.b2r[0] := 
                                                                         StreamIn[InputIndex].DSP[
                                                                         FilterIndex].fftdata.a3r[1]
                 ;
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.b2r[1] := 
                                                                         (1 - StreamIn[InputIndex].
                                                                         DSP[FilterIndex].fftdata.Cr
                                                                         ) *
                                                                         StreamIn[InputIndex].DSP[
                                                                         FilterIndex].fftdata.a3r[0]
                 ;
               end;

            3: //  DSPFFTBandPass
               begin

                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.Cr := 
                                                                     1 / Tan(Pi * (HighFrequencyr-
                                                                     LowFrequencyr + 1) /
                                                                     StreamIn[InputIndex].Data.
                                                                     SampleRate);
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.Dr := 
                                                                     2 * Cos(2 * Pi * (roundmath(
                                                                     HighFrequencyr + LowFrequencyr)
                                                                     shr 1) /
                                                                     StreamIn[InputIndex].Data.
                                                                     SampleRate);
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.a3r[0] := 
                                                                         1 / (1 + StreamIn[
                                                                         InputIndex].DSP[FilterIndex
                                                                         ].fftdata.Cr);
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.a3r[1] := 0.0;
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.a3r[2] := 
                                                                         -StreamIn[InputIndex].DSP[
                                                                         FilterIndex].fftdata.a3r[0]
                 ;
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.b2r[0] := 
                                                                         -StreamIn[InputIndex].DSP[
                                                                         FilterIndex].fftdata.Cr *
                                                                         StreamIn[InputIndex].DSP[
                                                                         FilterIndex].fftdata.Dr *
                                                                         StreamIn[InputIndex].DSP[
                                                                         FilterIndex].fftdata.a3r[0]
                 ;
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.b2r[1] := 
                                                                         (StreamIn[InputIndex].DSP[
                                                                         FilterIndex].fftdata.Cr - 1
                                                                         ) *
                                                                         StreamIn[InputIndex].DSP[
                                                                         FilterIndex].fftdata.a3r[0]
                 ;
               end;

            4: //  DSPFFTLowPass
               begin

                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.Cr := 
                                                                     1 / Tan(Pi * LowFrequencyr /
                                                                     StreamIn[InputIndex].Data.
                                                                     SampleRate);

                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.a3r[0] := 
                                                                         1 / (1 + Sqrt(2) * StreamIn
                                                                         [InputIndex].DSP[
                                                                         FilterIndex].fftdata.Cr +
                                                                         StreamIn[InputIndex].DSP[
                                                                         FilterIndex].fftdata.Cr *
                                                                         StreamIn[InputIndex].DSP[
                                                                         FilterIndex].fftdata.Cr);
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.a3r[1] := 
                                                                         2 * StreamIn[InputIndex].
                                                                         DSP[FilterIndex].fftdata.
                                                                         a3r[0];
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.a3r[2] := 
                                                                         StreamIn[InputIndex].DSP[
                                                                         FilterIndex].fftdata.a3r[0]
                 ;
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.b2r[0] := 
                                                                         2 * (1 - StreamIn[
                                                                         InputIndex].DSP[FilterIndex
                                                                         ].fftdata.Cr *
                                                                         StreamIn[InputIndex].DSP[
                                                                         FilterIndex].fftdata.Cr) *
                                                                         StreamIn[InputIndex].DSP[
                                                                         FilterIndex].fftdata.a3r[0]
                 ;
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.b2r[1] := 
                                                                         (1 - Sqrt(2) * StreamIn[
                                                                         InputIndex].DSP[FilterIndex
                                                                         ].fftdata.Cr +
                                                                         StreamIn[InputIndex].DSP[
                                                                         FilterIndex].fftdata.Cr *
                                                                         StreamIn[InputIndex].DSP[
                                                                         FilterIndex].fftdata.Cr) *
                                                                         StreamIn[InputIndex].DSP[
                                                                         FilterIndex].fftdata.a3r[0]
                 ;
               end;

            5: //  DSPFFTHighPass
               begin
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.Cr := 
                                                                     Tan(Pi * HighFrequencyr /
                                                                     StreamIn[InputIndex].Data.
                                                                     SampleRate);

                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.a3r[0] := 
                                                                         1 / (1 + Sqrt(2) * StreamIn
                                                                         [InputIndex].DSP[
                                                                         FilterIndex].fftdata.Cr +
                                                                         StreamIn[InputIndex].DSP[
                                                                         FilterIndex].fftdata.Cr *
                                                                         StreamIn[InputIndex].DSP[
                                                                         FilterIndex].fftdata.Cr);
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.a3r[1] := 

                                                                         -2 * StreamIn[InputIndex].
                                                                         DSP[FilterIndex].fftdata.
                                                                         a3r[0];
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.a3r[2] := 
                                                                         StreamIn[InputIndex].DSP[
                                                                         FilterIndex].fftdata.a3r[0]
                 ;
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.b2r[0] := 
                                                                         2 * (StreamIn[InputIndex].
                                                                         DSP[FilterIndex].fftdata.Cr
                                                                         *
                                                                         StreamIn[InputIndex].DSP[
                                                                         FilterIndex].fftdata.Cr - 1
                                                                         ) *
                                                                         StreamIn[InputIndex].DSP[
                                                                         FilterIndex].fftdata.a3r[0]
                 ;
                 StreamIn[InputIndex].DSP[FilterIndex].fftdata.b2r[1] := 
                                                                         (1 - Sqrt(2) * StreamIn[
                                                                         InputIndex].DSP[FilterIndex
                                                                         ].fftdata.Cr +
                                                                         StreamIn[InputIndex].DSP[
                                                                         FilterIndex].fftdata.Cr *
                                                                         StreamIn[InputIndex].DSP[
                                                                         FilterIndex].fftdata.Cr) *
                                                                         StreamIn[InputIndex].DSP[
                                                                         FilterIndex].fftdata.a3r[0]
                 ;
               end;
          end;
        end;
    end;
end;

procedure Tuos_Player.OutputSetFilter(OutputIndex: cint32; FilterIndex: cint32;
                                      TypeFilterL: shortint; LowFrequencyL, HighFrequencyL, GainL:
                                      cfloat;
                                      TypeFilterR: shortint; LowFrequencyR, HighFrequencyR, GainR:
                                      cfloat;
                                      AlsoBuf: boolean; LoopProc: TProc; Enable: boolean);
// OuputIndex : InputIndex of a existing Output
// DSPInIndex : DSPInIndex of existing DSPIn
// TypeFilterL: Type of filter left: 
// ( -1 = current filter ) (fBandAll = 0, fBandSelect = 1, fBandReject = 2
// fBandPass = 3, fLowPass = 4, fHighPass = 5)
// LowFrequencyL : Lowest frequency left( -1 : current LowFrequency )
// HighFrequencyL : Highest frequency left( -1 : current HighFrequency )
// GainL : gain left to apply to filter
// TypeFilterR: Type of filter right (ignored if mono):
// ( -1 = current filter ) (fBandAll = 0, fBandSelect = 1, fBandReject = 2
// LowFrequencyR : Lowest frequency Right (ignored if mono) ( -1 : current LowFrequency )
// HighFrequencyR : Highest frequency left( -1 : current HighFrequency )
// GainR : gain right (ignored if mono) to apply to filter ( 0 to what reasonable )
// AlsoBuf : The filter alter buffer aswell ( otherwise, only result is filled in fft.data )
// LoopProc : external procedure of object to synchronize after DSP done
// Enable :  Filter enabled
begin
  if isAssigned = true then
    begin
      StreamOut[OutputIndex].DSP[FilterIndex].fftdata.AlsoBuf := AlsoBuf;
      StreamOut[OutputIndex].DSP[FilterIndex].Enabled := Enable;

      if LowFrequencyL = -1 then
        LowFrequencyL := StreamOut[OutputIndex].DSP[FilterIndex].fftdata.LowFrequencyL;
      if LowFrequencyL = -1 then
        LowFrequencyL := StreamOut[OutputIndex].DSP[FilterIndex].fftdata.HighFrequencyL;
      if GainL <> -1 then
        StreamOut[OutputIndex].DSP[FilterIndex].fftdata.Gainl := cfloat(Gainl);

      if LowFrequencyR = -1 then
        LowFrequencyR := StreamOut[OutputIndex].DSP[FilterIndex].fftdata.LowFrequencyR;
      if LowFrequencyR = -1 then
        LowFrequencyR := StreamOut[OutputIndex].DSP[FilterIndex].fftdata.HighFrequencyR;
      if GainR <> -1 then
        StreamOut[OutputIndex].DSP[FilterIndex].fftdata.GainR := cfloat(GainR);

      if TypeFilterL <> -1 then
        begin
          StreamOut[OutputIndex].DSP[FilterIndex].fftdata.typefilterL := TypeFilterL;
          StreamOut[OutputIndex].DSP[FilterIndex].fftdata.C := 0.0;
          StreamOut[OutputIndex].DSP[FilterIndex].fftdata.D := 0.0;
          StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a3[0] := 0.0;
          StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a3[1] := 0.0;
          StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a3[2] := 0.0;
          StreamOut[OutputIndex].DSP[FilterIndex].fftdata.b2[0] := 0.0;
          StreamOut[OutputIndex].DSP[FilterIndex].fftdata.b2[1] := 0.0;
          StreamOut[OutputIndex].DSP[FilterIndex].fftdata.C2 := 0.0;
          StreamOut[OutputIndex].DSP[FilterIndex].fftdata.D2 := 0.0;
          StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a32[0] := 0.0;
          StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a32[1] := 0.0;
          StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a32[2] := 0.0;
          StreamOut[OutputIndex].DSP[FilterIndex].fftdata.b22[0] := 0.0;
          StreamOut[OutputIndex].DSP[FilterIndex].fftdata.b22[1] := 0.0;

          case TypeFilterL of 
            1: // DSPFFTBandSelect := DSPFFTBandReject + DSPFFTBandPass
               begin
                 //  DSPFFTBandReject

                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.C := 
                                                                      Tan(Pi * (HighFrequencyL -
                                                                      LowFrequencyl + 1) /
                                                                      StreamOut[OutputIndex].Data.
                                                                      SampleRate);
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.D := 
                                                                      2 * Cos(2 * Pi * (roundmath(
                                                                      HighFrequencyl + LowFrequencyl
                                                                      ) shr 1) /
                                                                      StreamOut[OutputIndex].Data.
                                                                      SampleRate);
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a3[0] := 
                                                                          1 / (1 + StreamOut[
                                                                          OutputIndex].DSP[
                                                                          FilterIndex].fftdata.C);
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a3[1] := 
                                                                          -StreamOut[OutputIndex].
                                                                          DSP[FilterIndex].fftdata.D
                                                                          *
                                                                          StreamOut[OutputIndex].DSP
                                                                          [FilterIndex].fftdata.a3[0
                                                                          ];
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a3[2] := 
                                                                          StreamOut[OutputIndex].DSP
                                                                          [FilterIndex].fftdata.a3[0
                                                                          ];
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.b2[0] := 
                                                                          StreamOut[OutputIndex].DSP
                                                                          [FilterIndex].fftdata.a3[1
                                                                          ];
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.b2[1] := 
                                                                          (1 - StreamOut[OutputIndex
                                                                          ].DSP[FilterIndex].fftdata
                                                                          .C) *
                                                                          StreamOut[OutputIndex].DSP
                                                                          [FilterIndex].fftdata.a3[0
                                                                          ];
                 //  DSPFFTBandPass
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.C2 := 
                                                                       1 / Tan(Pi * (HighFrequencyl
                                                                       - LowFrequencyl + 1) /
                                                                       StreamOut[OutputIndex].Data.
                                                                       SampleRate);
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.D2 := 
                                                                       2 * Cos(2 * Pi * (roundmath(
                                                                       HighFrequencyl +
                                                                       LowFrequencyl) shr 1) /
                                                                       StreamOut[OutputIndex].Data.
                                                                       SampleRate);
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a32[0] := 
                                                                           1 / (1 + StreamOut[
                                                                           OutputIndex].DSP[
                                                                           FilterIndex].fftdata.C2);
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a32[1] := 0.0;
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a32[2] := 
                                                                           -StreamOut[OutputIndex].
                                                                           DSP[FilterIndex].fftdata.
                                                                           a32[0];
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.b22[0] := 
                                                                           -StreamOut[OutputIndex].
                                                                           DSP[FilterIndex].fftdata.
                                                                           C2 *
                                                                           StreamOut[OutputIndex].
                                                                           DSP[FilterIndex].fftdata.
                                                                           D2 *
                                                                           StreamOut[OutputIndex].
                                                                           DSP[FilterIndex].fftdata.
                                                                           a32[0];
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.b22[1] := 
                                                                           (StreamOut[OutputIndex].
                                                                           DSP[FilterIndex].fftdata.
                                                                           C2 - 1) *
                                                                           StreamOut[OutputIndex].
                                                                           DSP[FilterIndex].fftdata.
                                                                           a32[0];
                 //
               end;

            2: //  DSPFFTBandReject
               begin
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.C := 
                                                                      Tan(Pi * (HighFrequencyl -
                                                                      LowFrequencyl + 1) /
                                                                      StreamOut[OutputIndex].Data.
                                                                      SampleRate);
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.D := 
                                                                      2 * Cos(2 * Pi * (roundmath(
                                                                      HighFrequencyl + LowFrequencyl
                                                                      ) shr 1) /
                                                                      StreamOut[OutputIndex].Data.
                                                                      SampleRate);
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a3[0] := 
                                                                          1 / (1 + StreamOut[
                                                                          OutputIndex].DSP[
                                                                          FilterIndex].fftdata.C);
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a3[1] := 
                                                                          -StreamOut[OutputIndex].
                                                                          DSP[FilterIndex].fftdata.D
                                                                          *
                                                                          StreamOut[OutputIndex].DSP
                                                                          [FilterIndex].fftdata.a3[0
                                                                          ];
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a3[2] := 
                                                                          StreamOut[OutputIndex].DSP
                                                                          [FilterIndex].fftdata.a3[0
                                                                          ];
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.b2[0] := 
                                                                          StreamOut[OutputIndex].DSP
                                                                          [FilterIndex].fftdata.a3[1
                                                                          ];
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.b2[1] := 
                                                                          (1 - StreamOut[OutputIndex
                                                                          ].DSP[FilterIndex].fftdata
                                                                          .C) *
                                                                          StreamOut[OutputIndex].DSP
                                                                          [FilterIndex].fftdata.a3[0
                                                                          ];
               end;

            3: //  DSPFFTBandPass
               begin

                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.C := 
                                                                      1 / Tan(Pi * (HighFrequencyl -
                                                                      LowFrequencyl + 1) /
                                                                      StreamOut[OutputIndex].Data.
                                                                      SampleRate);
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.D := 
                                                                      2 * Cos(2 * Pi * (roundmath(
                                                                      HighFrequencyl + LowFrequencyl
                                                                      ) shr 1) /
                                                                      StreamOut[OutputIndex].Data.
                                                                      SampleRate);
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a3[0] := 
                                                                          1 / (1 + StreamOut[
                                                                          OutputIndex].DSP[
                                                                          FilterIndex].fftdata.C);
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a3[1] := 0.0;
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a3[2] := 
                                                                          -StreamOut[OutputIndex].
                                                                          DSP[FilterIndex].fftdata.
                                                                          a3[0];
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.b2[0] := 
                                                                          -StreamOut[OutputIndex].
                                                                          DSP[FilterIndex].fftdata.C
                                                                          *
                                                                          StreamOut[OutputIndex].DSP
                                                                          [FilterIndex].fftdata.D *
                                                                          StreamOut[OutputIndex].DSP
                                                                          [FilterIndex].fftdata.a3[0
                                                                          ];
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.b2[1] := 
                                                                          (StreamOut[OutputIndex].
                                                                          DSP[FilterIndex].fftdata.C
                                                                          - 1) *
                                                                          StreamOut[OutputIndex].DSP
                                                                          [FilterIndex].fftdata.a3[0
                                                                          ];
               end;

            4: //  DSPFFTLowPass
               begin

                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.C := 
                                                                      1 / Tan(Pi * LowFrequencyl /
                                                                      StreamOut[OutputIndex].Data.
                                                                      SampleRate);

                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a3[0] := 
                                                                          1 / (1 + Sqrt(2) *
                                                                          StreamOut[OutputIndex].DSP
                                                                          [FilterIndex].fftdata.C +
                                                                          StreamOut[OutputIndex].DSP
                                                                          [FilterIndex].fftdata.C *
                                                                          StreamOut[OutputIndex].DSP
                                                                          [FilterIndex].fftdata.C);
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a3[1] := 
                                                                          2 * StreamOut[OutputIndex]
                                                                          .DSP[FilterIndex].fftdata.
                                                                          a3[0];
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a3[2] := 
                                                                          StreamOut[OutputIndex].DSP
                                                                          [FilterIndex].fftdata.a3[0
                                                                          ];
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.b2[0] := 
                                                                          2 * (1 - StreamOut[
                                                                          OutputIndex].DSP[
                                                                          FilterIndex].fftdata.C *
                                                                          StreamOut[OutputIndex].DSP
                                                                          [FilterIndex].fftdata.C) *
                                                                          StreamOut[OutputIndex].DSP
                                                                          [FilterIndex].fftdata.a3[0
                                                                          ];
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.b2[1] := 
                                                                          (1 - Sqrt(2) * StreamOut[
                                                                          OutputIndex].DSP[
                                                                          FilterIndex].fftdata.C +
                                                                          StreamOut[OutputIndex].DSP
                                                                          [FilterIndex].fftdata.C *
                                                                          StreamOut[OutputIndex].DSP
                                                                          [FilterIndex].fftdata.C) *
                                                                          StreamOut[OutputIndex].DSP
                                                                          [FilterIndex].fftdata.a3[0
                                                                          ];
               end;

            5: //  DSPFFTHighPass
               begin
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.C := 
                                                                      Tan(Pi * HighFrequencyl /
                                                                      StreamOut[OutputIndex].Data.
                                                                      SampleRate);

                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a3[0] := 
                                                                          1 / (1 + Sqrt(2) *
                                                                          StreamOut[OutputIndex].DSP
                                                                          [FilterIndex].fftdata.C +
                                                                          StreamOut[OutputIndex].DSP
                                                                          [FilterIndex].fftdata.C *
                                                                          StreamOut[OutputIndex].DSP
                                                                          [FilterIndex].fftdata.C);
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a3[1] := 

                                                                          -2 * StreamOut[OutputIndex
                                                                          ].DSP[FilterIndex].fftdata
                                                                          .a3[0];
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a3[2] := 
                                                                          StreamOut[OutputIndex].DSP
                                                                          [FilterIndex].fftdata.a3[0
                                                                          ];
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.b2[0] := 
                                                                          2 * (StreamOut[OutputIndex
                                                                          ].DSP[FilterIndex].fftdata
                                                                          .C *
                                                                          StreamOut[OutputIndex].DSP
                                                                          [FilterIndex].fftdata.C -
                                                                          1) *
                                                                          StreamOut[OutputIndex].DSP
                                                                          [FilterIndex].fftdata.a3[0
                                                                          ];
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.b2[1] := 
                                                                          (1 - Sqrt(2) * StreamOut[
                                                                          OutputIndex].DSP[
                                                                          FilterIndex].fftdata.C +
                                                                          StreamOut[OutputIndex].DSP
                                                                          [FilterIndex].fftdata.C *
                                                                          StreamOut[OutputIndex].DSP
                                                                          [FilterIndex].fftdata.C) *
                                                                          StreamOut[OutputIndex].DSP
                                                                          [FilterIndex].fftdata.a3[0
                                                                          ];
               end;

          end;
        end;

      if TypeFilterR <> -1 then
        begin
          StreamOut[OutputIndex].DSP[FilterIndex].fftdata.typefilterR := TypeFilterR;
          StreamOut[OutputIndex].DSP[FilterIndex].fftdata.Cr := 0.0;
          StreamOut[OutputIndex].DSP[FilterIndex].fftdata.Dr := 0.0;
          StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a3r[0] := 0.0;
          StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a3r[1] := 0.0;
          StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a3r[2] := 0.0;
          StreamOut[OutputIndex].DSP[FilterIndex].fftdata.b2r[0] := 0.0;
          StreamOut[OutputIndex].DSP[FilterIndex].fftdata.b2r[1] := 0.0;
          StreamOut[OutputIndex].DSP[FilterIndex].fftdata.C2r := 0.0;
          StreamOut[OutputIndex].DSP[FilterIndex].fftdata.D2r := 0.0;
          StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a32r[0] := 0.0;
          StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a32r[1] := 0.0;
          StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a32r[2] := 0.0;
          StreamOut[OutputIndex].DSP[FilterIndex].fftdata.b22r[0] := 0.0;
          StreamOut[OutputIndex].DSP[FilterIndex].fftdata.b22r[1] := 0.0;

          case TypeFilterR of 
            1: // DSPFFTBandSelect := DSPFFTBandReject + DSPFFTBandPass
               begin
                 //  DSPFFTBandReject
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.Cr := 
                                                                       Tan(Pi * (HighFrequencyr -
                                                                       LowFrequencyr + 1) /
                                                                       StreamOut[OutputIndex].Data.
                                                                       SampleRate);
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.Dr := 
                                                                       2 * Cos(2 * Pi * (roundmath(
                                                                       HighFrequencyr +
                                                                       LowFrequencyr) shr 1) /
                                                                       StreamOut[OutputIndex].Data.
                                                                       SampleRate);
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a3r[0] := 
                                                                           1 / (1 + StreamOut[
                                                                           OutputIndex].DSP[
                                                                           FilterIndex].fftdata.Cr);
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a3r[1] := 
                                                                           -StreamOut[OutputIndex].
                                                                           DSP[FilterIndex].fftdata.
                                                                           Dr *
                                                                           StreamOut[OutputIndex].
                                                                           DSP[FilterIndex].fftdata.
                                                                           a3r[0];
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a3r[2] := 
                                                                           StreamOut[OutputIndex].
                                                                           DSP[FilterIndex].fftdata.
                                                                           a3r[0];
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.b2r[0] := 
                                                                           StreamOut[OutputIndex].
                                                                           DSP[FilterIndex].fftdata.
                                                                           a3r[1];
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.b2r[1] := 
                                                                           (1 - StreamOut[
                                                                           OutputIndex].DSP[
                                                                           FilterIndex].fftdata.Cr)
                                                                           *
                                                                           StreamOut[OutputIndex].
                                                                           DSP[FilterIndex].fftdata.
                                                                           a3r[0];
                 //  DSPFFTBandPass
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.C2r := 
                                                                        1 / Tan(Pi * (HighFrequencyr
                                                                        - LowFrequencyr + 1) /
                                                                        StreamOut[OutputIndex].Data.
                                                                        SampleRate);
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.D2r := 
                                                                        2 * Cos(2 * Pi * (roundmath(
                                                                        HighFrequencyr +
                                                                        LowFrequencyr) shr 1) /
                                                                        StreamOut[OutputIndex].Data.
                                                                        SampleRate);
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a32r[0] := 
                                                                            1 / (1 + StreamOut[
                                                                            OutputIndex].DSP[
                                                                            FilterIndex].fftdata.C2r
                                                                            );
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a32r[1] := 0.0;
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a32r[2] := 
                                                                            -StreamOut[OutputIndex].
                                                                            DSP[FilterIndex].fftdata
                                                                            .a32r[0];
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.b22r[0] := 
                                                                            -StreamOut[OutputIndex].
                                                                            DSP[FilterIndex].fftdata
                                                                            .C2r *
                                                                            StreamOut[OutputIndex].
                                                                            DSP[FilterIndex].fftdata
                                                                            .D2r *
                                                                            StreamOut[OutputIndex].
                                                                            DSP[FilterIndex].fftdata
                                                                            .a32r[0];
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.b22r[1] := 
                                                                            (StreamOut[OutputIndex].
                                                                            DSP[FilterIndex].fftdata
                                                                            .C2r - 1) *
                                                                            StreamOut[OutputIndex].
                                                                            DSP[FilterIndex].fftdata
                                                                            .a32r[0];
                 //
               end;

            2: //  DSPFFTBandReject
               begin
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.Cr := 
                                                                       Tan(Pi * (HighFrequencyr -
                                                                       LowFrequencyr + 1) /
                                                                       StreamOut[OutputIndex].Data.
                                                                       SampleRate);
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.Dr := 
                                                                       2 * Cos(2 * Pi * (roundmath(
                                                                       HighFrequencyr +
                                                                       LowFrequencyr) shr 1) /
                                                                       StreamOut[OutputIndex].Data.
                                                                       SampleRate);
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a3r[0] := 
                                                                           1 / (1 + StreamOut[
                                                                           OutputIndex].DSP[
                                                                           FilterIndex].fftdata.Cr);
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a3r[1] := 
                                                                           -StreamOut[OutputIndex].
                                                                           DSP[FilterIndex].fftdata.
                                                                           Dr *
                                                                           StreamOut[OutputIndex].
                                                                           DSP[FilterIndex].fftdata.
                                                                           a3r[0];
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a3r[2] := 
                                                                           StreamOut[OutputIndex].
                                                                           DSP[FilterIndex].fftdata.
                                                                           a3r[0];
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.b2r[0] := 
                                                                           StreamOut[OutputIndex].
                                                                           DSP[FilterIndex].fftdata.
                                                                           a3r[1];
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.b2r[1] := 
                                                                           (1 - StreamOut[
                                                                           OutputIndex].DSP[
                                                                           FilterIndex].fftdata.Cr)
                                                                           *
                                                                           StreamOut[OutputIndex].
                                                                           DSP[FilterIndex].fftdata.
                                                                           a3r[0];
               end;

            3: //  DSPFFTBandPass
               begin

                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.Cr := 
                                                                       1 / Tan(Pi * (HighFrequencyr-
                                                                       LowFrequencyr + 1) /
                                                                       StreamOut[OutputIndex].Data.
                                                                       SampleRate);
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.Dr := 
                                                                       2 * Cos(2 * Pi * (roundmath(
                                                                       HighFrequencyr +
                                                                       LowFrequencyr) shr 1) /
                                                                       StreamOut[OutputIndex].Data.
                                                                       SampleRate);
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a3r[0] := 
                                                                           1 / (1 + StreamOut[
                                                                           OutputIndex].DSP[
                                                                           FilterIndex].fftdata.Cr);
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a3r[1] := 0.0;
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a3r[2] := 
                                                                           -StreamOut[OutputIndex].
                                                                           DSP[FilterIndex].fftdata.
                                                                           a3r[0];
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.b2r[0] := 
                                                                           -StreamOut[OutputIndex].
                                                                           DSP[FilterIndex].fftdata.
                                                                           Cr *
                                                                           StreamOut[OutputIndex].
                                                                           DSP[FilterIndex].fftdata.
                                                                           Dr *
                                                                           StreamOut[OutputIndex].
                                                                           DSP[FilterIndex].fftdata.
                                                                           a3r[0];
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.b2r[1] := 
                                                                           (StreamOut[OutputIndex].
                                                                           DSP[FilterIndex].fftdata.
                                                                           Cr - 1) *
                                                                           StreamOut[OutputIndex].
                                                                           DSP[FilterIndex].fftdata.
                                                                           a3r[0];
               end;

            4: //  DSPFFTLowPass
               begin

                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.Cr := 
                                                                       1 / Tan(Pi * LowFrequencyr /
                                                                       StreamOut[OutputIndex].Data.
                                                                       SampleRate);

                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a3r[0] := 
                                                                           1 / (1 + Sqrt(2) *
                                                                           StreamOut[OutputIndex].
                                                                           DSP[FilterIndex].fftdata.
                                                                           Cr +
                                                                           StreamOut[OutputIndex].
                                                                           DSP[FilterIndex].fftdata.
                                                                           Cr *
                                                                           StreamOut[OutputIndex].
                                                                           DSP[FilterIndex].fftdata.
                                                                           Cr);
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a3r[1] := 
                                                                           2 * StreamOut[OutputIndex
                                                                           ].DSP[FilterIndex].
                                                                           fftdata.a3r[0];
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a3r[2] := 
                                                                           StreamOut[OutputIndex].
                                                                           DSP[FilterIndex].fftdata.
                                                                           a3r[0];
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.b2r[0] := 
                                                                           2 * (1 - StreamOut[
                                                                           OutputIndex].DSP[
                                                                           FilterIndex].fftdata.Cr *
                                                                           StreamOut[OutputIndex].
                                                                           DSP[FilterIndex].fftdata.
                                                                           Cr) *
                                                                           StreamOut[OutputIndex].
                                                                           DSP[FilterIndex].fftdata.
                                                                           a3r[0];
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.b2r[1] := 
                                                                           (1 - Sqrt(2) * StreamOut[
                                                                           OutputIndex].DSP[
                                                                           FilterIndex].fftdata.Cr +
                                                                           StreamOut[OutputIndex].
                                                                           DSP[FilterIndex].fftdata.
                                                                           Cr *
                                                                           StreamOut[OutputIndex].
                                                                           DSP[FilterIndex].fftdata.
                                                                           Cr) *
                                                                           StreamOut[OutputIndex].
                                                                           DSP[FilterIndex].fftdata.
                                                                           a3r[0];
               end;

            5: //  DSPFFTHighPass
               begin
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.Cr := 
                                                                       Tan(Pi * HighFrequencyr /
                                                                       StreamOut[OutputIndex].Data.
                                                                       SampleRate);

                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a3r[0] := 
                                                                           1 / (1 + Sqrt(2) *
                                                                           StreamOut[OutputIndex].
                                                                           DSP[FilterIndex].fftdata.
                                                                           Cr +
                                                                           StreamOut[OutputIndex].
                                                                           DSP[FilterIndex].fftdata.
                                                                           Cr *
                                                                           StreamOut[OutputIndex].
                                                                           DSP[FilterIndex].fftdata.
                                                                           Cr);
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a3r[1] := 

                                                                           -2 * StreamOut[
                                                                           OutputIndex].DSP[
                                                                           FilterIndex].fftdata.a3r[
                                                                           0];
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.a3r[2] := 
                                                                           StreamOut[OutputIndex].
                                                                           DSP[FilterIndex].fftdata.
                                                                           a3r[0];
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.b2r[0] := 
                                                                           2 * (StreamOut[
                                                                           OutputIndex].DSP[
                                                                           FilterIndex].fftdata.Cr *
                                                                           StreamOut[OutputIndex].
                                                                           DSP[FilterIndex].fftdata.
                                                                           Cr - 1) *
                                                                           StreamOut[OutputIndex].
                                                                           DSP[FilterIndex].fftdata.
                                                                           a3r[0];
                 StreamOut[OutputIndex].DSP[FilterIndex].fftdata.b2r[1] := 
                                                                           (1 - Sqrt(2) * StreamOut[
                                                                           OutputIndex].DSP[
                                                                           FilterIndex].fftdata.Cr +
                                                                           StreamOut[OutputIndex].
                                                                           DSP[FilterIndex].fftdata.
                                                                           Cr *
                                                                           StreamOut[OutputIndex].
                                                                           DSP[FilterIndex].fftdata.
                                                                           Cr) *
                                                                           StreamOut[OutputIndex].
                                                                           DSP[FilterIndex].fftdata.
                                                                           a3r[0];
               end;
          end;
        end;
    end;
end;

{$IF DEFINED(soundtouch)}
function SoundTouchPlug(bufferin: TDArFloat; plugHandle: THandle; notneeded :Tt_bs2bdp; Var
                        inputData: Tuos_Data;
                        notused1: float; notused2: float; notused3: float;  notused4: float;
                        notused5: float; notused6: float; notused7: float;  notused8: float):

                                                                                           TDArFloat
;
var 
  ratio : shortint;
  numoutbuf, x1, x2: cint32;
  BufferplugFLTMP: TDArFloat;
  BufferplugFL: TDArFloat;
begin

  case inputData.LibOpen of 
    0: ratio := 1;
    // sndfile
    1:
       begin
         // mpg123
         case inputData.SampleFormat of 
           0: ratio := 2;
           // float32
           1: ratio := 2;
           // int32
           2: ratio := 1;
           // int16
         end;
       end;
    2: ratio := 1;
    3: ratio := 1;
    // cdrom
    4: ratio := 1;
    // opus
    5: ratio := 1;
    // xmp
  end;

  if inputData.LibOpen <> 4 then//not working yet for opus files
    begin
  {$IF DEFINED(uos_debug) and DEFINED(unix)}
      writeln();
      writeln('_____Begin Sound touch_____');
      writeln('soundtouch_putSamples: Length(bufferin)  = ' + inttostr(length(bufferin)));
      writeln('outframes  = ' + inttostr(inputData.outframes)+
      ' ratio  = ' + inttostr(ratio)+' channels  = ' + inttostr(inputData.Channels));
  {$endif}

      if inputData.outframes > 0 then
        begin
          soundtouch_putSamples(plugHandle, pcfloat(bufferin), 
          inputData.outframes div cint(inputData.Channels * ratio));

  {$IF DEFINED(uos_debug) and DEFINED(unix)}
          writeln('inputData.outframes div trunc(inputData.Channels * ratio) = '
                  + inttostr(inputData.outframes Div inputData.Channels * ratio));
  {$endif}

          SetLength(BufferplugFL, 0);
          SetLength(BufferplugFLTMP, 0);

  {$IF DEFINED(uos_debug) and DEFINED(unix)}
          writeln('Length(BufferplugFL) = '
                  + inttostr(Length(BufferplugFL)));
          writeln('Length(Bufferin) = '
                  + inttostr(Length(Bufferin)));
          writeln('Length(BufferplugFLTMP) = '
                  + inttostr(Length(BufferplugFLTMP)));
  {$endif}

          SetLength(BufferplugFLTMP,(Length(Bufferin)));


{  
  x2 := 0 ;
while x2 < Length(BufferplugFLTMP) do 
begin
BufferplugFLTMP[x2] := 0.0 ;
inc(x2);
end;
}
  {$IF DEFINED(uos_debug) and DEFINED(unix)}
          writeln('2_Length(BufferplugFLTMP) = '
                  + inttostr(Length(BufferplugFLTMP)));
  {$endif}

          numoutbuf := 1;

          while numoutbuf > 0 do
            begin

              numoutbuf := soundtouch_receiveSamples(PlugHandle,
                           pcfloat(BufferplugFLTMP), inputData.outframes);

  {$IF DEFINED(uos_debug) and DEFINED(unix)}
              writeln('numoutbuf = '  + inttostr(numoutbuf));
  {$endif}

              if numoutbuf > 0 then
                begin
  {$IF DEFINED(uos_debug) and DEFINED(unix)}
                  writeln('SetLength(BufferplugFL) = '  + inttostr(length(BufferplugFL) + trunc(

                                                                                           numoutbuf
                                                                                                *

                                                                                           inputData
                                                                                                .

                                                                                            Channels
                  )));
  {$endif}

                  SetLength(BufferplugFL, length(BufferplugFL) + trunc(numoutbuf * inputData.
                                                                       Channels));
                  // works only with 2 channels.

                  x2 := Length(BufferplugFL) - (numoutbuf * inputData.Channels);

                  for x1 := 0 to trunc(numoutbuf * inputData.Channels) -1 do
                    begin
                      BufferplugFL[x1 + x2] := BufferplugFLTMP[x1];
                    end;
                end;
            end;
        end;

  {$IF DEFINED(uos_debug) and DEFINED(unix)}
      writeln('inputData.outframes = Length(BufferplugFL) = ' + inttostr(inputData.outframes));
      writeln('_____End Sound touch_____');
  {$endif}

      inputData.outframes := Length(BufferplugFL) Div inputData.Channels;

      Result := BufferplugFL;
    end
  else
    begin
      SetLength(bufferin, inputData.outframes);
      Result := bufferin;
    end;
end;

function GetBPMPlug(bufferin: TDArFloat; plugHandle: THandle; notneeded :Tt_bs2bdp; Var inputData:
                    Tuos_Data;
                    numframes: float; loop: float; notused3: float;  notused4: float;
                    notused5: float; notused6: float; notused7: float;  notused8: float): TDArFloat;
var 
  ratio : shortint;
begin

  case inputData.LibOpen of 
    0: ratio := 1;
    // sndfile
    1:
       begin
         // mpg123
         case inputData.SampleFormat of 
           0: ratio := 2;
           // float32
           1: ratio := 2;
           // int32
           2: ratio := 1;
           // int16
         end;
       end;
    2: ratio := 1;
    3: ratio := 1;
    // cdrom
    4: ratio := 1;
    // opus
    5: ratio := 1;
    // xmp
  end;

  if inputData.LibOpen <> 4 then//not working yet for opus files
    begin
      // writeln('getBPM init ');
      if (theincbpm < numframes) and (theincbpm > -1) then
        begin
          bpm_putSamples(plugHandle,  pcfloat(bufferin),  length(bufferin) div inputData.channels);
        end
      else
        begin
          if theincbpm > -1 then
            begin
              inputData.BPM := bpm_getBpm(plugHandle);
              //  writeln('inputData.BPM := ' + floattostr(inputData.BPM));
              if loop = 1 then theincbpm := 0
              else theincbpm := -1;

            end;
        end;

      if theincbpm > -1 then inc(theincbpm);

      SetLength(bufferin, inputData.outframes Div ratio);
      Result := bufferin;
    end;
end;


{$endif}

{$IF DEFINED(bs2b)}
function bs2bPlug(bufferin: TDArFloat; notneeded: THandle; Abs2bd : Tt_bs2bdp; Var inputData:
                  Tuos_Data;
                  notused1: float; notused2: float; notused3: float;  notused4: float;
                  notused5: float; notused6: float; notused7: float;  notused8: float): TDArFloat;
var 
  x, x2: cint32;
  Bufferplug: TDArFloat;
begin

  if (inputData.libopen = 0) or (inputData.libopen = 2)  or (inputData.libopen = 3) or (inputData.
     libopen = 4) or (inputData.libopen = 5) then
    x2 := trunc(inputData.ratio * (inputData.outframes Div trunc(inputData.channels))) ;

  if (inputData.libopen = 1)  then
    begin
      if inputData.SampleFormat < 2 then
        x2 := trunc((inputData.outframes Div trunc(inputData.channels)))
      else x2 := trunc(inputData.ratio * (inputData.outframes Div trunc(inputData.channels))) ;
    end;

  SetLength(Bufferplug,x2);

  x := 0;

  while x < x2  do
    begin

      Bufferplug[x] := bufferin[x] ;
      Bufferplug[x+1] := bufferin[x+1] ;
      bs2b_cross_feed_f(Abs2bd,Bufferplug[x],1);
      bs2b_cross_feed_f(Abs2bd,Bufferplug[x+1],2);
      x := x +2;
    end;
  Result :=  Bufferplug;
end;
{$endif}

function Tuos_Player.AddPlugin(PlugName: PChar; SampleRate: CDouble;
                               Channels: cint32): cint32;
// SampleRate : delault : -1 (44100)
// Channels : delault : -1 (2:stereo) (0: no channels, 1:mono, 2:stereo, ...)
// Result is PluginIndex
var 
  x: cint32;
  chan, sr : integer;
begin
  x := -1 ;
 {$IF DEFINED(soundtouch)}
  if lowercase(PlugName) = 'soundtouch' then
    begin
      // 
      SetLength(Plugin, Length(Plugin) + 1);
      x := Length(Plugin) - 1;
      Plugin[x] := Tuos_Plugin.Create();
      Plugin[x].Enabled := false;
      Plugin[x].Name := lowercase(PlugName);
      Plugin[x].param1 := -1;
      Plugin[x].param2 := -1;
      Plugin[x].param3 := -1;
      Plugin[x].param4 := -1;
      Plugin[x].param5 := -1;
      Plugin[x].param6 := -1;
      Plugin[x].param7 := -1;
      Plugin[x].param8 := -1;
      Plugin[x].PlugHandle := soundtouch_createInstance();
      if SampleRate = -1 then
        soundtouch_setSampleRate(Plugin[x].PlugHandle, 44100)
      else
        soundtouch_setSampleRate(Plugin[x].PlugHandle, roundmath(SampleRate));
      if Channels = -1 then
        soundtouch_setChannels(Plugin[x].PlugHandle, 2)
      else
        soundtouch_setChannels(Plugin[x].PlugHandle, Channels);
      soundtouch_setRate(Plugin[x].PlugHandle, 1);
      soundtouch_setTempo(Plugin[x].PlugHandle, 1);
      soundtouch_clear(Plugin[x].PlugHandle);
      Plugin[x].PlugFunc := @soundtouchplug;
    end;

  if lowercase(PlugName) = 'getbpm' then
    begin
      // 
      SetLength(Plugin, Length(Plugin) + 1);
      x := Length(Plugin) - 1;
      Plugin[x] := Tuos_Plugin.Create();
      Plugin[x].Enabled := true;
      Plugin[x].Name := lowercase(PlugName);
      Plugin[x].param1 := -1;
      Plugin[x].param2 := -1;
      Plugin[x].param3 := -1;
      Plugin[x].param4 := -1;
      Plugin[x].param5 := -1;
      Plugin[x].param6 := -1;
      Plugin[x].param7 := -1;
      Plugin[x].param8 := -1;

      if SampleRate = -1 then
        sr := 44100
      else
        sr := roundmath(SampleRate);
      if Channels = -1 then
        chan := 2
      else
        chan := Channels;

      Plugin[x].PlugHandle := bpm_createInstance(chan,sr);

      Plugin[x].PlugFunc := @getbpmplug;
    end;
  {$endif}

 {$IF DEFINED(bs2b)}
  if lowercase(PlugName) = 'bs2b' then
    begin
      SetLength(Plugin, Length(Plugin) + 1);
      Plugin[Length(Plugin) - 1] := Tuos_Plugin.Create();
      x := Length(Plugin) - 1;
      Plugin[x].Name := lowercase(PlugName);
      Plugin[x].Enabled := true;
      if assigned(Plugin[x].Abs2b) then bs2b_close(Plugin[x].Abs2b) ;
      Plugin[x].Abs2b := bs2b_open() ;

      if SampleRate = -1 then
        bs2b_set_srate(Plugin[x].Abs2b, 44100)
      else
        bs2b_set_srate(Plugin[x].Abs2b, roundmath(SampleRate));

      Plugin[x].param1 := -1;
      Plugin[x].param2 := -1;
      Plugin[x].param3 := -1;
      Plugin[x].param4 := -1;
      Plugin[x].param5 := -1;
      Plugin[x].param6 := -1;
      Plugin[x].param7 := -1;
      Plugin[x].param8 := -1;
      Plugin[x].PlugFunc := @bs2bplug;
    end;
  {$endif}
  Plugin[x].Enabled := true;
  Result := x;
end;

{$IF DEFINED(soundtouch)}
procedure Tuos_Player.SetPluginSoundTouch(PluginIndex: cint32;
                                          Tempo: cfloat; Pitch: cfloat; Enable: boolean);
begin
  soundtouch_setRate(Plugin[PluginIndex].PlugHandle, Pitch);
  soundtouch_setTempo(Plugin[PluginIndex].PlugHandle, Tempo);
  Plugin[PluginIndex].Enabled := Enable;
  Plugin[PluginIndex].param1 := Tempo;
  Plugin[PluginIndex].param2 := Pitch;
end;

procedure Tuos_Player.SetPluginGetBPM(PluginIndex: cint32; numofframes: integer; loop : boolean;
                                      Enable: boolean);
// PluginIndex : PluginIndex Index of a existing Plugin.  
// numofframes: number of frames to analyse (-1 = 512 frames)
// loop: do new detection after previous.
begin

  Plugin[PluginIndex].Enabled := Enable;

  Plugin[PluginIndex].param1 := numofframes;

  if (loop = true) then
    Plugin[PluginIndex].param2 := 1
  else Plugin[PluginIndex].param2 := 0; ;
end;
{$endif}

{$IF DEFINED(bs2b)}
procedure Tuos_Player.SetPluginBs2b(PluginIndex: cint32;
                                    level: CInt32; fcut: CInt32; feed: CInt32; Enable: boolean);
begin

  Plugin[PluginIndex].Enabled := Enable;

  if level > -1 then
    begin
      bs2b_set_level(Plugin[PluginIndex].Abs2b,level);
      Plugin[PluginIndex].param1 := level;
    end;

  if fcut > -1 then
    begin
      bs2b_set_level_fcut(Plugin[PluginIndex].Abs2b,fcut);
      Plugin[PluginIndex].param2 := fcut;
    end;

  if feed > -1 then
    begin
      bs2b_set_level_feed(Plugin[PluginIndex].Abs2b,feed);
      Plugin[PluginIndex].param3 := feed;
    end;

end;
{$endif}

function uos_InputGetLevelArray(PlayerIndex: cint32; InputIndex: cint32) : TDArFloat;
begin
  result :=  uosLevelArray[PlayerIndex][InputIndex] ;
end;

{$IF DEFINED(noiseremoval)}
function uos_NoiseRemoval(Var Data: Tuos_Data; Var fft: Tuos_FFT): TDArFloat;
var 
  ratio, x: cint32;
  Outfr : cint32;
  tempr : PSingle;
  pf: TDArFloat;
begin

  case Data.LibOpen of 
    0: ratio := 1;
    // sndfile
    1: ratio := 2;
    // mpg123
    2: ratio := 1;
    // aac
    3: ratio := 1;
    // cdrom
    4: ratio := 1;
    // opus
    5: ratio := 1;
    // xmp
  end;

  if Data.SampleFormat = 0 then// TODO for Array of integer.
    begin

      tempr := fft.FNoise.FilterNoise(pointer(Data.Buffer) ,
               (Data.OutFrames Div ratio) , Outfr);

      setlength(pf,length(Data.Buffer));

      for x := 0 to length(pf) -1 do
        begin
          if x < Outfr then
            pf[x] := tempr[x]
          else pf[x] := 0.0;
        end;

      result := pf ;

    end
  else result := Data.Buffer;
  // TODO for Array of integer.
end;
 {$endif}

function uos_DSPVolumeIn(Var Data: Tuos_Data;Var fft: Tuos_FFT): TDArFloat;
var 
  x, ratio: cint32;
  vleft, vright: cfloat;

  // volumearray : array of double;

  ps: PDArShort;
  // if input is Int16 format
  pl: PDArLong;
  // if input is Int32 format
  pf: PDArFloat;
  // if input is Float32 format
begin
  //setlength(volumearray,Data.channels);
  vleft := Data.VLeft;
  vright := Data.VRight;

  case Data.SampleFormat of 
    2: // int16
       begin
         ps := @Data.Buffer;
         for x := 0 to (Data.OutFrames -1) do
           begin
             if (Data.VLeft <> 1)  or (Data.Vright <> 1) then
               begin
                 if odd(x) then
                   ps^[x] := trunc(ps^[x] * vright)
                 else
                   ps^[x] := trunc(ps^[x] * vleft);
               end;
             // This to avoid distortion
             if ps^[x] < (-32760) then ps^[x] := -32760 ;
             if ps^[x] > (32760) then ps^[x] := 32760 ;

           end;

       end;
    1: // int32
       begin
         pl := @Data.Buffer;
         for x := 0 to (Data.OutFrames -1) do
           begin
             if (Data.VLeft <> 1)  or (Data.Vright <> 1) then
               begin
                 if odd(x) then
                   pl^[x] := trunc(pl^[x] * vright)
                 else
                   pl^[x] := trunc(pl^[x] * vleft);
               end;

             // This to avoid distortion
             if pl^[x] < (-2147000000) then pl^[x] := -2147000000 ;
             if pl^[x] > (2147000000) then pl^[x] := 2147000000 ;

           end;

       end;
    0: // float32
       begin
         case Data.LibOpen of 
           0: ratio := 1;
           // sndfile
           1: ratio := 2;
           // mpg123
           2: ratio := 1;
           // aac
           3: ratio := 1;
           // cdrom
           4: ratio := 1;
           // opus
           5: ratio := 1;
           // xmp
         end;

         pf := @Data.Buffer;

         for x := 0 to (Data.OutFrames div ratio) -1 do
           begin
             if (Data.VLeft <> 1)  or (Data.Vright <> 1) then
               begin
                 if odd(x) then
                   pf^[x] := pf^[x] * vright
                 else
                   pf^[x] := pf^[x] * vleft;
               end;

             // This to avoid distortion
             if pf^[x] < -1 then pf^[x] := -1;
             if pf^[x] > 1 then pf^[x] := 1 ;

           end;

       end;
  end;

  Result := Data.Buffer;
end;

function uos_DSPVolumeOut(Var Data: Tuos_Data;Var fft: Tuos_FFT): TDArFloat;
var 
  x: cint32;
  vleft, vright: cfloat;
  ps: PDArShort;
  // if output is Int16 format
  pl: PDArLong;
  // if output is Int32 format
  pf: PDArFloat;
  // if output is Float32 format
begin

  vleft := Data.VLeft;
  vright := Data.VRight;

  case Data.SampleFormat of 
    2: // int16
       begin
         ps := @Data.Buffer;
         for x := 0 to (length(Data.Buffer) -1) do
           begin
             if (Data.VLeft <> 1)  or (Data.Vright <> 1) then
               begin
                 if odd(x) then
                   ps^[x] := trunc(ps^[x] * vright)
                 else
                   ps^[x] := trunc(ps^[x] * vleft);
               end;
             // This to avoid distortion
             if ps^[x] < (-32760) then ps^[x] := -32760 ;
             if ps^[x] > (32760) then ps^[x] := 32760 ;

           end;

       end;
    1: // int32
       begin
         pl := @Data.Buffer;
         for x := 0 to (length(Data.Buffer) -1) do
           begin
             if (Data.VLeft <> 1)  or (Data.Vright <> 1) then
               begin
                 if odd(x) then
                   pl^[x] := trunc(pl^[x] * vright)
                 else
                   pl^[x] := trunc(pl^[x] * vleft);
               end;

             // This to avoid distortion
             if pl^[x] < (-2147000000) then pl^[x] := -2147000000 ;
             if pl^[x] > (2147000000) then pl^[x] := 2147000000 ;

           end;

       end;
    0: // float32
       begin

         pf := @Data.Buffer;

         for x := 0 to (length(Data.Buffer)) -1 do
           begin
             if (Data.VLeft <> 1)  or (Data.Vright <> 1) then
               begin
                 if odd(x) then
                   pf^[x] := pf^[x] * vright
                 else
                   pf^[x] := pf^[x] * vleft;
               end;

             // This to avoid distortion
             if pf^[x] < -1 then pf^[x] := -1;
             if pf^[x] > 1 then pf^[x] := 1 ;

           end;

       end;
  end;

  Result := Data.Buffer;
end;

function Tuos_Player.DSPLevel(Data: Tuos_Data): Tuos_Data;
var 
  x, ratio: cint32;
  ps: PDArShort;
  // if input is Int16 format
  pl: PDArLong;
  // if input is Int32 format
  pf: PDArFloat;
  // if input is Float32 format
  mins, maxs: array[0..1] of cInt16;
  // if input is Int16 format
  minl, maxl: array[0..1] of cInt32;
  // if input is Int32 format
  minf, maxf: array[0..1] of cfloat;
  // if input is Float32 format
begin

  case Data.SampleFormat of 
    2:
       begin
         mins[0] := 32767;
         mins[1] := 32767;
         maxs[0] := -32768;
         maxs[1] := -32768;
         ps := @Data.Buffer;
         x := 0;
         while x < Data.OutFrames -1 do
           begin
             if ps^[x] < mins[0] then
               mins[0] := ps^[x];
             if ps^[x] > maxs[0] then
               maxs[0] := ps^[x];

             Inc(x, 1);

             if ps^[x] < mins[1] then
               mins[1] := ps^[x];
             if ps^[x] > maxs[1] then
               maxs[1] := ps^[x];

             Inc(x, 1);
           end;

         if Abs(mins[0]) > Abs(maxs[0]) then
           Data.LevelLeft := Sqrt(Abs(mins[0]) / 32768)
         else
           Data.LevelLeft := Sqrt(Abs(maxs[0]) / 32768);

         if Abs(mins[1]) > Abs(maxs[1]) then
           Data.Levelright := Sqrt(Abs(mins[1]) / 32768)
         else
           Data.Levelright := Sqrt(Abs(maxs[1]) / 32768);

       end;

    1:
       begin
         minl[0] := 2147483647;
         minl[1] := 2147483647;
         maxl[0] := -2147483648;
         maxl[1] := -2147483648;
         pl := @Data.Buffer;
         x := 0;
         while x < Data.OutFrames -1 do
           begin
             if pl^[x] < minl[0] then
               minl[0] := pl^[x];
             if pl^[x] > maxl[0] then
               maxl[0] := pl^[x];

             Inc(x, 1);

             if pl^[x] < minl[1] then
               minl[1] := pl^[x];
             if pl^[x] > maxl[1] then
               maxl[1] := pl^[x];

             Inc(x, 1);
           end;

         if Abs(minl[0]) > Abs(maxl[0]) then
           Data.LevelLeft := Sqrt(Abs(minl[0]) / 2147483648)
         else
           Data.LevelLeft := Sqrt(Abs(maxl[0]) / 2147483648);

         if Abs(minl[1]) > Abs(maxl[1]) then
           Data.Levelright := Sqrt(Abs(minl[1]) / 2147483648)
         else
           Data.Levelright := Sqrt(Abs(maxl[1]) / 2147483648);
       end;

    0:
       begin
         case Data.LibOpen of 
           0: ratio := 1;
           // sndfile
           1: ratio := 2;
           // mpg123
           2: ratio := 2;
           // aac
           3: ratio := 2;
           // cdrom
           4: ratio := 2;
           // opus
           5: ratio := 1;
           // xmp
         end;

         minf[0] := 1;
         minf[1] := 1;
         maxf[0] := -1;
         maxf[1] := -1;
         pf := @Data.Buffer;
         x := 0;
         while x < (Data.OutFrames div ratio)-1 do
           begin
             if pf^[x] < minf[0] then
               minf[0] := pf^[x];
             if pf^[x] > maxf[0] then
               maxf[0] := pf^[x];

             Inc(x, 1);

             if pf^[x] < minf[1] then
               minf[1] := pf^[x];
             if pf^[x] > maxf[1] then
               maxf[1] := pf^[x];

             Inc(x, 1);
           end;

         if Abs(minf[0]) > Abs(maxf[0]) then
           Data.LevelLeft := Sqrt(Abs(minf[0]))
         else
           Data.LevelLeft := Sqrt(Abs(maxf[0]));

         if Abs(minf[1]) > Abs(maxf[1]) then
           Data.Levelright := Sqrt(Abs(minf[1]))
         else
           Data.Levelright := Sqrt(Abs(maxf[1]));
       end;
  end;

  Result := Data;
end;

function DSPLevelString(Buffer: TDArFloat; SampleFormat, Ratio : cint32; Var resfloatleft : cfloat;
                        Var resfloatright : cfloat): string;
var 
  x, OutFrames: cint32;
  ps: PDArShort;
  // if input is Int16 format
  pl: PDArLong;
  // if input is Int32 format
  pf: PDArFloat;
  // if input is Float32 format
  mins, maxs: array[0..1] of cInt16;
  // if input is Int16 format
  minl, maxl: array[0..1] of cInt32;
  // if input is Int32 format
  minf, maxf: array[0..1] of cfloat;
  // if input is Float32 format
begin

  OutFrames := length(buffer);

  case SampleFormat of 
    2:
       begin
         mins[0] := 32767;
         mins[1] := 32767;
         maxs[0] := -32768;
         maxs[1] := -32768;
         ps := @Buffer;
         x := 0;
         while x < OutFrames -1 do
           begin
             if ps^[x] < mins[0] then
               mins[0] := ps^[x];
             if ps^[x] > maxs[0] then
               maxs[0] := ps^[x];

             Inc(x, 1);

             if ps^[x] < mins[1] then
               mins[1] := ps^[x];
             if ps^[x] > maxs[1] then
               maxs[1] := ps^[x];

             Inc(x, 1);
           end;

         if Abs(mins[0]) > Abs(maxs[0]) then
           resfloatLeft := Sqrt(Abs(mins[0]) / 32768)
         else
           resfloatLeft := Sqrt(Abs(maxs[0]) / 32768);

         if Abs(mins[1]) > Abs(maxs[1]) then
           resfloatright := Sqrt(Abs(mins[1]) / 32768)
         else
           resfloatright := Sqrt(Abs(maxs[1]) / 32768);

       end;

    1:
       begin
         minl[0] := 2147483647;
         minl[1] := 2147483647;
         maxl[0] := -2147483648;
         maxl[1] := -2147483648;
         pl := @Buffer;
         x := 0;
         while x < OutFrames -1 do
           begin
             if pl^[x] < minl[0] then
               minl[0] := pl^[x];
             if pl^[x] > maxl[0] then
               maxl[0] := pl^[x];

             Inc(x, 1);

             if pl^[x] < minl[1] then
               minl[1] := pl^[x];
             if pl^[x] > maxl[1] then
               maxl[1] := pl^[x];

             Inc(x, 1);
           end;

         if Abs(minl[0]) > Abs(maxl[0]) then
           resfloatLeft := Sqrt(Abs(minl[0]) / 2147483648)
         else
           resfloatLeft := Sqrt(Abs(maxl[0]) / 2147483648);

         if Abs(minl[1]) > Abs(maxl[1]) then
           resfloatright := Sqrt(Abs(minl[1]) / 2147483648)
         else
           resfloatright := Sqrt(Abs(maxl[1]) / 2147483648);
       end;

    0:
       begin

         minf[0] := 1;
         minf[1] := 1;
         maxf[0] := -1;
         maxf[1] := -1;
         pf := @Buffer;
         x := 0;
         while x < (OutFrames div ratio) -1 do
           begin
             if pf^[x] < minf[0] then
               minf[0] := pf^[x];
             if pf^[x] > maxf[0] then
               maxf[0] := pf^[x];

             Inc(x, 1);

             if pf^[x] < minf[1] then
               minf[1] := pf^[x];
             if pf^[x] > maxf[1] then
               maxf[1] := pf^[x];

             Inc(x, 1);
           end;

         if Abs(minf[0]) > Abs(maxf[0]) then
           resfloatLeft := Sqrt(Abs(minf[0]))
         else
           resfloatLeft := Sqrt(Abs(maxf[0]));

         if Abs(minf[1]) > Abs(maxf[1]) then
           resfloatright := Sqrt(Abs(minf[1]))
         else
           resfloatright := Sqrt(Abs(maxf[1]));
       end;
  end;
  Result := floattostr(resfloatleft) + '|' + floattostr(resfloatright);
end;


function uos_BandFilter(Var Data: Tuos_Data; Var fft: Tuos_FFT): TDArFloat;
var 
  i, ratio: cint32;
  ifbuf: boolean;
  arg, res, res2: cfloat;
  ps, ps2: PDArShort;
  // if input is Int16 format
  pl, pl2: PDArLong;
  // if input is Int32 format
  pf, pf2: PDArFloat;
  // if input is Float32 format
begin

  ratio := 1;
  ifbuf := fft.AlsoBuf;

  case Data.SampleFormat of 
    2:
       begin
         ps := @Data.Buffer;
         ps2 := @fft.VirtualBuffer;
       end;
    1:
       begin
         pl := @Data.Buffer;
         pl2 := @fft.VirtualBuffer;
       end;
    0:
       begin
         case Data.LibOpen of 
           0: ratio := 1;
           // sndfile
           1: ratio := 2;
           // mpg123
           2: ratio := 2;
           // aac
           3: ratio := 2;
           // cdrom
           4: ratio := 2;
           // opus
           5: ratio := 1;
           // xmp
         end;
         pf := @Data.Buffer;
         pf2 := @fft.VirtualBuffer;
       end;
  end;
  i := 0;
  while i < (Data.OutFrames div ratio) -1 do
    begin

      case Data.SampleFormat of 
        2: arg := ps^[i];
        1: arg := pl^[i];
        0: arg := pf^[i];
      end;

      res := fft.a3[0] * arg + fft.a3[1] * fft.x0[0] + fft.a3[2] *
             fft.x1[0] - fft.b2[0] * fft.y0[0] - fft.b2[1] * fft.y1[0];

      if fft.typefilterL = 1 then
        begin
          res2 := fft.a32[0] * arg + fft.a32[1] * fft.x02[0] + fft.a32[2] *
                  fft.x12[0] - fft.b22[0] * fft.y02[0] - fft.b22[1] * fft.y12[0];

          case Data.SampleFormat of 
            2:
               begin
                 if ifbuf = True then
                   ps^[i] := trunc((res * 1) + (res2 * fft.gainl))
                 else
                   ps2^[i] := trunc((res * 1) + (res2 * fft.gainl));
               end;
            1:
               begin
                 if ifbuf = True then
                   pl^[i] := trunc((res * 1) + (res2 * fft.gainl))
                 else
                   pl2^[i] := trunc((res * 1) + (res2 * fft.gainl));
               end;
            0:
               begin

                 if ifbuf = True then
                   pf^[i] := ((res * 1) + (res2 * fft.gainl))
                 else
                   pf2^[i] := ((res * 1) + (res2 * fft.gainl));
               end;
          end;

        end
      else
        case Data.SampleFormat of 
          2:
             begin

               if ifbuf = True then
                 ps^[i] := trunc((res * fft.gainl))
               else
                 ps2^[i] := trunc(res * fft.gainl);
             end;
          1:
             begin
               if ifbuf = True then
                 pl^[i] := trunc((res * fft.gainl))
               else
                 pl2^[i] := trunc(res * fft.gainl);
             end;
          0:
             begin
               if ifbuf = True then
                 pf^[i] := ((res * fft.gainl))
               else
                 pf2^[i] := ((res * fft.gainl));
             end;
        end;

      fft.x1[0] := fft.x0[0];
      fft.x0[0] := arg;
      fft.y1[0] := fft.y0[0];
      fft.y0[0] := res;

      if fft.typefilterL = 1 then
        begin
          fft.x12[0] := fft.x02[0];
          fft.x02[0] := arg;
          fft.y12[0] := fft.y02[0];
          fft.y02[0] := res2;
        end;

      if Data.Channels = 2 then
        begin
          Inc(i);
          case Data.SampleFormat of 
            2: arg := ps^[i];
            1: arg := pl^[i];
            0: arg := pf^[i];
          end;
          res := fft.a3r[0] * arg + fft.a3r[1] * fft.x0r[1] + fft.a3r[2] *
                 fft.x1r[1] - fft.b2r[0] * fft.y0r[1] - fft.b2r[1] * fft.y1r[1];

          if fft.typefilterR = 1 then
            begin
              res2 := fft.a32r[0] * arg + fft.a32r[1] * fft.x02r[1] +
                      fft.a32r[2] * fft.x12r[1] - fft.b22r[0] * fft.y02r[1] -
                      fft.b22r[1] * fft.y12r[1];

              case Data.SampleFormat of 
                2:
                   begin
                     if ifbuf = True then
                       ps^[i] := trunc((res * 1) + (res2 * fft.gainr))
                     else
                       ps2^[i] := trunc((res * 1) + (res2 * fft.gainr));
                   end;
                1:
                   begin
                     if ifbuf = True then
                       pl^[i] := trunc((res * 1) + (res2 * fft.gainr))
                     else
                       pl2^[i] := trunc((res * 1) + (res2 * fft.gainr));
                   end;
                0:
                   begin
                     if ifbuf = True then
                       pf^[i] := ((res * 1) + (res2 * fft.gainr))
                     else
                       pf2^[i] := ((res * 1) + (res2 * fft.gainr));
                   end;
              end;

            end
          else
            case Data.SampleFormat of 
              2:
                 begin
                   if ifbuf = True then
                     ps^[i] := trunc((res * fft.gainr))
                   else
                     ps2^[i] := trunc((res * fft.gainr));
                 end;
              1:
                 begin
                   if ifbuf = True then
                     pl^[i] := trunc((res * fft.gainr))
                   else
                     pl2^[i] := trunc((res * fft.gainr));
                 end;
              0:
                 begin
                   if ifbuf = True then
                     pf^[i] := ((res * fft.gainr))
                   else
                     pf2^[i] := ((res * fft.gainr));
                 end;
            end;

          fft.x1r[1] := fft.x0r[1];
          fft.x0r[1] := arg;
          fft.y1r[1] := fft.y0r[1];
          fft.y0r[1] := res;

          if fft.typefilterR = 1 then
            begin
              fft.x12r[1] := fft.x02r[1];
              fft.x02r[1] := arg;
              fft.y12r[1] := fft.y02r[1];
              fft.y02r[1] := res2;
            end;

        end;
      Inc(i);
    end;

  if ifbuf = false then
    begin
      data.levelfilters  := data.levelfilters + '%'+ DSPLevelString(fft.VirtualBuffer, Data.
                            SampleFormat, data.Ratio, data.levelleft, data.levelright) ;
      inc(Data.incfilters);
      Data.levelfiltersar[Data.incfilters-1] := data.levelleft;
      inc(Data.incfilters);
      Data.levelfiltersar[Data.incfilters-1] := data.levelright;
    end;

  Result := Data.Buffer;

end;

function uos_InputAddDSP1ChanTo2Chan(Var Data: Tuos_Data; Var fft: Tuos_FFT): TDArFloat;
//  Convert mono 1 chan input into stereo 2 channels input.
// Works only if the input is mono 1 channel othewise stereo 2 chan is keeped.
// InputIndex : InputIndex of a existing Input
//  result :  index of DSPIn in array
// example  DSPIndex1 := InputAdd1ChanTo2Chan(InputIndex1);
var 
  x, x2: integer ;

  ps, ps2: PDArShort;
  // if input is Int16 format
  pl, pl2: PDArLong;
  // if input is Int32 format
  pf, pf2: PDArFloat;
  // if input is Float32 format

  buffer2 : TDArFloat;

begin
  if (Data.channels = 1) then
    begin
      setlength(Buffer2, Data.OutFrames);
      x := 0 ;
      x2 := 0 ;

      case Data.SampleFormat of 
        2:
           begin
             ps := @Data.Buffer;
             ps2 := @Buffer2;
             while x < Data.OutFrames -1 do
               begin
                 ps2^[x2] := (ps^[x]);
                 ps2^[x2+1] := (ps^[x]);
                 x := x + 1;
                 x2 := x2 + 2;
               end;
           end;

        1:
           begin
             pl := @Data.Buffer;
             pl2 := @Buffer2;
             while x < Data.OutFrames -1  do
               begin
                 pl2^[x2] := (pl^[x]);
                 pl2^[x2+1] := (pl^[x]);
                 x := x + 1;
                 x2 := x2 + 2;
               end;
           end;

        0:
           begin
             pf := @Data.Buffer;
             pf2 := @Buffer2;
             while x < Data.OutFrames -1  do
               begin
                 pf2^[x2] := (pf^[x]);
                 pf2^[x2+1] := (pf^[x]);
                 x := x + 1;
                 x2 := x2 + 2;
               end;
           end;
      end;
      data.outframes := length(buffer2);
      Result := Buffer2;;
    end
  else
    begin
      Result := data.Buffer;
    end;

end;

function ConvertSampleFormat(Data: Tuos_Data): TDArFloat;
var 
  x : integer ;

  ps, ps2: PDArShort;
  // if input is Int16 format
  pl, pl2: PDArLong;
  // if input is Int32 format
  buffer2 : TDArFloat;

begin
  if (Data.SampleFormat > 0) then
    begin
      setlength(Buffer2, Data.OutFrames);
      x := 0 ;

      case Data.SampleFormat of 
        2:
           begin
             ps := @Data.Buffer;
             ps2 := @Buffer2;
             while x < Data.OutFrames  do
               begin
                 ps2^[x] := (ps^[x]);
                 x := x + 1;
               end;
           end;

        1:
           begin
             pl := @Data.Buffer;
             pl2 := @Buffer2;
             while x < Data.OutFrames  do
               begin
                 pl2^[x] := (pl^[x]);
                 x := x + 1;
               end;
           end;
      end;
      Result := Buffer2;
    end
  else
    begin
      Result := data.Buffer;
    end;

end;

  {$IF DEFINED(noiseremoval)}
function Tuos_Player.InputAddDSPNoiseRemoval(InputIndex: cint32): cint32;
// DSP Noise Removal
// InputIndex : InputIndex of a existing Input
//  result :  otherwise index of DSPIn in array
// example  DSPIndex1 := InputAddDSPNoiseRemoval(InputIndex1);
begin

  Result := InputAddDSP(InputIndex, Nil, @uos_NoiseRemoval, Nil, Nil);

  StreamIn[InputIndex].data.DSPNoiseIndex := Result ;

  StreamIn[InputIndex].DSP[result].fftdata := Tuos_FFT.Create();

  StreamIn[InputIndex].DSP[result].fftdata.FNoise := 
                                                     TuosNoiseRemoval.Create(StreamIn[InputIndex].
                                                     data.Channels,roundmath(StreamIn[InputIndex].
                                                     data.
                                                     SampleRate));

  StreamIn[InputIndex].DSP[result].fftdata.FNoise.samprate := 
                                                              roundmath(StreamIn[InputIndex].data.
                                                              SampleRate);

  StreamIn[InputIndex].DSP[result].fftdata.FNoise.WriteProc := 
                                                               @StreamIn[InputIndex].DSP[result].
                                                               fftdata.FNoise.WriteData;

  StreamIn[InputIndex].DSP[result].fftdata.FNoise.isprofiled := false;

end;

procedure Tuos_Player.InputSetDSPNoiseRemoval(InputIndex: cint32; Enable: boolean);

begin
  StreamIn[InputIndex].DSP[StreamIn[InputIndex].data.DSPNoiseIndex].enabled := Enable ;
end;

function Tuos_Player.OutputAddDSPNoiseRemoval(OutputIndex: cint32): cint32;
// DSP Noise Removal
// OutputIndex : OutputIndex of a existing Output
//  result :  otherwise index of DSPInOut in array
// example  DSPIndex1 := OutputAddDSPNoiseRemoval(OutputIndex1);
begin

  Result := OutputAddDSP(OutputIndex, Nil, @uos_NoiseRemoval, Nil, Nil);

  StreamOut[OutputIndex].data.DSPNoiseIndex := Result ;

  StreamOut[OutputIndex].DSP[result].fftdata :=  Tuos_FFT.Create();

  StreamOut[OutputIndex].DSP[result].fftdata.FNoise := 
                                                       TuosNoiseRemoval.Create(StreamOut[OutputIndex
                                                       ].data.Channels,roundmath(StreamOut[
                                                       OutputIndex].data.
                                                       SampleRate));

  StreamOut[OutputIndex].DSP[result].fftdata.FNoise.samprate := 
                                                                roundmath(StreamOut[OutputIndex].
                                                                data.
                                                                SampleRate);

  StreamOut[OutputIndex].DSP[result].fftdata.FNoise.WriteProc := 
                                                                 @StreamOut[OutputIndex].DSP[result]
                                                                 .fftdata.FNoise.WriteData;

  StreamOut[OutputIndex].DSP[result].fftdata.FNoise.isprofiled := false;

end;

procedure Tuos_Player.OutputSetDSPNoiseRemoval(OutputIndex: cint32; Enable: boolean);
begin
  StreamOut[OutputIndex].DSP[StreamOut[OutputIndex].data.DSPNoiseIndex].enabled := Enable ;
end;

{$endif}

function Tuos_Player.InputAddDSPVolume(InputIndex: cint32; VolLeft: double;
                                       VolRight: double): cint32;
// DSP Volume changer
// InputIndex : InputIndex of a existing Input
// VolLeft : Left volume
// VolRight : Right volume
//  result : index of DSPIn in array
// example  DSPIndex1 := InputAddDSPVolume(InputIndex1,1,1);
begin
  Result := InputAddDSP(InputIndex, Nil, @uos_DSPVolumeIn, Nil, Nil);
  StreamIn[InputIndex].Data.VLeft := VolLeft;
  StreamIn[InputIndex].Data.VRight := VolRight;
end;

function Tuos_Player.InputAddDSP1ChanTo2Chan(InputIndex: cint32): cint32;
//  Convert mono 1 channel input to stereo 2 channels input.
// Works only if the input is mono 1 channel othewise stereo 2 chan is keeped.
// InputIndex : InputIndex of a existing Input
//  result :  index of DSPIn in array
// example  DSPIndex1 := InputAddDSP1ChanTo2Chan(InputIndex1);
begin
  Result := InputAddDSP(InputIndex, Nil, @uos_InputAddDSP1ChanTo2Chan, Nil, Nil);
end;

function Tuos_Player.OutputAddDSPVolume(OutputIndex: cint32; VolLeft: double;
                                        VolRight: double): cint32;
// DSP Volume changer
// OutputIndex : OutputIndex of a existing Output
// VolLeft : Left volume ( 1 = max)
// VolRight : Right volume ( 1 = max)
//  result :  index of DSPIn in array
// example  DSPIndex1 := OutputAddDSPVolume(OutputIndex1,1,1);
begin
  Result := OutputAddDSP(OutputIndex, Nil, @uos_DSPVolumeOut, Nil, Nil);
  StreamOut[OutputIndex].Data.VLeft := VolLeft;
  StreamOut[OutputIndex].Data.VRight := VolRight;
end;

procedure Tuos_Player.InputSetDSPVolume(InputIndex: cint32; DSPVolIndex: cint32;
                                        VolLeft: double; VolRight: double; Enable: boolean);
// InputIndex : InputIndex of a existing Input
// DSPIndex : DSPVolIndex of a existing DSPVolume
// VolLeft : Left volume ( -1 = do not change)
// VolRight : Right volume ( -1 = do not change)
// Enable : Enabled
// example  InputSetDSPVolume(InputIndex1,DSPVolIndex1,1,0.8,True);
begin
  if VolLeft <> -1 then
    StreamIn[InputIndex].Data.VLeft := VolLeft;
  if VolRight <> -1 then
    StreamIn[InputIndex].Data.VRight := VolRight;
  StreamIn[InputIndex].DSP[DSPVolIndex].Enabled := Enable;
end;

procedure Tuos_Player.OutputSetDSPVolume(OutputIndex: cint32;
                                         DSPVolIndex: cint32; VolLeft: double; VolRight: double;
                                         Enable: boolean);
// OutputIndex : OutputIndex of a existing Output
// DSPIndex : DSPIndex of a existing DSP
// VolLeft : Left volume
// VolRight : Right volume
// Enable : Enabled
// example  OutputSetDSPVolume(InputIndex1,DSPIndex1,1,0.8,True);
begin
  if VolLeft <> -1 then
    StreamOut[OutputIndex].Data.VLeft := VolLeft;
  if VolRight <> -1 then
    StreamOut[OutputIndex].Data.VRight := VolRight;
  StreamOut[OutputIndex].DSP[DSPVolIndex].Enabled := Enable;
end;

function Tuos_Player.InputAddFilter(InputIndex: cint32;
                                    TypeFilterL: shortint; LowFrequencyL, HighFrequencyL, GainL:
                                    cfloat;
                                    TypeFilterR: shortint; LowFrequencyR, HighFrequencyR, GainR:
                                    cfloat;
                                    AlsoBuf: boolean; LoopProc: TProc): cint32;
// InputIndex : InputIndex of a existing Input
// TypeFilterL: Type of filter left: 
// ( -1 = current filter ) (fBandAll = 0, fBandSelect = 1, fBandReject = 2
// LowFrequencyL : Lowest frequency left( -1 : current LowFrequency )
// HighFrequencyL : Highest frequency left( -1 : current HighFrequency )
// GainL : gain left to apply to filter
// TypeFilterR: Type of filter right (ignored if mono):
// ( -1 = current filter ) (fBandAll = 0, fBandSelect = 1, fBandReject = 2
// LowFrequencyR : Lowest frequency Right (ignored if mono) ( -1 : current LowFrequency )
// HighFrequencyR : Highest frequency left( -1 : current HighFrequency )
// GainR : gain right (ignored if mono) to apply to filter ( 0 to what reasonable )
// AlsoBuf : The filter alter buffer aswell ( otherwise, only result is filled in fft.data )
// LoopProc : external procedure of object to synchronize after DSP done
//  result :  index of DSPIn in array

var 
  FilterIndex: cint32;
begin
  FilterIndex := InputAddDSP(InputIndex, Nil, @uos_BandFilter, Nil, LoopProc);

  if alsobuf = false then
    begin
      StreamIn[InputIndex].data.hasfilters := true;
      inc(StreamIn[InputIndex].data.nbfilters);
    end;

  StreamIn[InputIndex].DSP[FilterIndex].fftdata := 
                                                   Tuos_FFT.Create();

  setlength(StreamIn[InputIndex].DSP[FilterIndex].fftdata.Virtualbuffer, length(StreamIn[InputIndex]
            .data.buffer));

  if TypeFilterL = -1 then  TypeFilterL := 1;
  if TypeFilterR = -1 then  TypeFilterR := 1;

  InputSetFilter(InputIndex, FilterIndex, TypeFilterL, LowFrequencyL, HighFrequencyL, GainL,
                 TypeFilterR, LowFrequencyR, HighFrequencyR, GainR, AlsoBuf, LoopProc, True);

  Result := FilterIndex;
end;

function Tuos_Player.OutputAddFilter(OutputIndex: cint32;
                                     TypeFilterL: shortint; LowFrequencyL, HighFrequencyL, GainL:
                                     cfloat;
                                     TypeFilterR: shortint; LowFrequencyR, HighFrequencyR, GainR:
                                     cfloat;
                                     AlsoBuf: boolean; LoopProc: TProc): cint32;
// OutputIndex : InputIndex of a existing Output
// TypeFilterL: Type of filter left: 
// ( -1 = current filter ) (fBandAll = 0, fBandSelect = 1, fBandReject = 2
// LowFrequencyL : Lowest frequency left( -1 : current LowFrequency )
// HighFrequencyL : Highest frequency left( -1 : current HighFrequency )
// GainL : gain left to apply to filter
// TypeFilterR: Type of filter right (ignored if mono):
// ( -1 = current filter ) (fBandAll = 0, fBandSelect = 1, fBandReject = 2
// LowFrequencyR : Lowest frequency Right (ignored if mono) ( -1 : current LowFrequency )
// HighFrequencyR : Highest frequency left( -1 : current HighFrequency )
// GainR : gain right (ignored if mono) to apply to filter ( 0 to what reasonable )
// AlsoBuf : The filter alter buffer aswell ( otherwise, only result is filled in fft.data )
// LoopProc : external procedure of object to synchronize after DSP done
//  result :  index of DSPIn in array

var 
  FilterIndex: cint32;
begin
  FilterIndex := OutputAddDSP(OutputIndex, Nil, @uos_BandFilter, Nil, LoopProc);

  if alsobuf = false then
    begin
      StreamOut[OutputIndex].data.hasfilters := true;
      inc(StreamOut[OutputIndex].data.nbfilters);
    end;

  StreamOut[OutputIndex].DSP[FilterIndex].fftdata := 
                                                     Tuos_FFT.Create();

  setlength(StreamOut[OutputIndex].DSP[FilterIndex].fftdata.Virtualbuffer,
            length(StreamOut[OutputIndex].data.buffer));

  if TypeFilterL = -1 then  TypeFilterL := 1;
  if TypeFilterR = -1 then  TypeFilterR := 1;

  OutputSetFilter(OutputIndex, FilterIndex, TypeFilterL, LowFrequencyL, HighFrequencyL, GainL,
                  TypeFilterR, LowFrequencyR, HighFrequencyR, GainR, AlsoBuf, LoopProc, True);

  Result := FilterIndex;
end;


{$IF DEFINED(portaudio)}
function Tuos_Player.AddFromDevIn(Device: cint32; Latency: CDouble;
                                  SampleRate: CDouble; OutputIndex: cint32;
                                  SampleFormat: cint32; FramesCount : cint32; ChunkCount: cint32):
                                                                                              cint32
;
// Add Input from IN device with custom parameters
// Device ( -1 is default Input device )
// Latency  ( -1 is latency suggested ) 
// SampleRate : delault : -1 (44100)

// OutputIndex : Output index of used output// -1: all output, -2: no output, other cint32 refer to a existing OutputIndex
// (if multi-output then OutName = name of each output separeted by ';')
// SampleFormat : -1 default : Int16 (0: Float32, 1:Int32, 2:Int16)
// FramesCount : -1 default : 4096
// ChunkCount : default : -1 (= 512)
var 
  x, err: cint32;
begin
  result := -1 ;

  if device = -1 then
    err :=  Pa_GetDefaultInputDevice();
  if err = -1 then result := -2;

  if result <> -2 then
    begin
      x := 0;
      err := -1;
      SetLength(StreamIn, Length(StreamIn) + 1);
      StreamIn[Length(StreamIn) - 1] := Tuos_InStream.Create();
      x := Length(StreamIn) - 1;
      StreamIn[x].Data.Enabled := false;
      StreamIn[x].Data.levelEnable := 0;
      StreamIn[x].Data.PositionEnable := 0;
      StreamIn[x].Data.levelArrayEnable := 0;

      StreamIn[x].PAParam.HostApiSpecificStreamInfo := Nil;

      if device = -1 then
        StreamIn[x].PAParam.device := 
                                      Pa_GetDefaultInputDevice()
      else
        StreamIn[x].PAParam.device := cint32(device);

      if SampleRate = -1 then
        StreamIn[x].Data.SampleRate := DefRate
      else
        StreamIn[x].Data.SampleRate := SampleRate;

      StreamIn[x].PAParam.SuggestedLatency := CDouble(0);

      StreamIn[x].PAParam.SampleFormat := paInt16;

      case SampleFormat of 
        0: StreamIn[x].PAParam.SampleFormat := paFloat32;
        1: StreamIn[x].PAParam.SampleFormat := paInt32;
        2: StreamIn[x].PAParam.SampleFormat := paInt16;
      end;

      if SampleFormat = -1 then
        StreamIn[x].Data.SampleFormat := CInt32(2)
      else
        StreamIn[x].Data.SampleFormat := CInt32(SampleFormat);

      if  ((Pa_GetDeviceInfo(StreamIn[x].PAParam.device)^.
         maxInputChannels)) > 1 then
        StreamIn[x].PAParam.channelCount := CInt32(2)
      else
        StreamIn[x].PAParam.channelCount := CInt32(1) ;

      StreamIn[x].data.channels := StreamIn[x].PAParam.channelCount;

      if FramesCount = -1 then  StreamIn[x].Data.Wantframes :=  4096
      else
        StreamIn[x].Data.Wantframes := (FramesCount) ;

      if ChunkCount = -1 then  ChunkCount := 512;

      SetLength(StreamIn[x].Data.Buffer, StreamIn[x].Data.Wantframes* StreamIn[x].Data.channels);

      // StreamIn[x].Data.outframes := length(StreamIn[x].Data.Buffer);
      StreamIn[x].Data.outframes := 0;

      StreamIn[x].Data.Status := 1;
      StreamIn[x].Data.TypePut := 1;
      StreamIn[x].Data.ratio := 2;
      StreamIn[x].Data.Output := OutputIndex;
      StreamIn[x].Data.seekable := False;
      StreamIn[x].Data.LibOpen := 2;
      StreamIn[x].LoopProc := Nil;

      err := Pa_OpenStream(@StreamIn[x].Data.HandleSt, @StreamIn[x].PAParam,
             Nil, CDouble(StreamIn[x].Data.SampleRate), CULong(ChunkCount), paClipOff, Nil, Nil);

      if err <> 0 then
      else
        begin
          StreamIn[x].Data.Enabled := True;
          Result := x;
        end;
    end
  else Result := -1;
end;
{$endif}

function Tuos_Player.InputGetBuffer(InputIndex: cint32): TDArFloat;
// Get current buffer
begin
  result := StreamIn[InputIndex].data.Buffer;
end;

function Tuos_Player.AddFromEndlessMuted(Channels : cint32; FramesCount: cint32): cint32;
// Add a input from Endless Muted dummy sine wav
// FramesCountByChan = FramesCount of input-to-follow div channels of input-to-follow.
var 
  x, i : cint32;
begin
  result := -1 ;
  x := 0;

  SetLength(StreamIn, Length(StreamIn) + 1);
  StreamIn[Length(StreamIn) - 1] := Tuos_InStream.Create();
  x := Length(StreamIn) - 1;
  StreamIn[x].Data.Enabled := false;
  StreamIn[x].Data.levelEnable := 0;
  StreamIn[x].Data.PositionEnable := 0;
  StreamIn[x].Data.levelArrayEnable := 0;

  if channels = -1 then
    StreamIn[x].data.channels := 2
  else
    StreamIn[x].data.channels := Channels;

  StreamIn[x].Data.SampleRate := DefRate;

  if FramesCount = -1 then  StreamIn[x].Data.Wantframes :=  trunc(1024 * 2 Div StreamIn[x].Data.
                                                           channels)
  else
    StreamIn[x].Data.Wantframes := FramesCount * 2 Div channels  ;

  SetLength(StreamIn[x].Data.Buffer, StreamIn[x].Data.Wantframes* StreamIn[x].Data.channels);

  StreamIn[x].Data.OutFrames :=  StreamIn[x].Data.WantFrames ;

  for i := 0 to length(StreamIn[x].Data.Buffer) -1 do
    StreamIn[x].Data.Buffer[i] := 0.0;

  StreamIn[x].Data.SampleFormat := CInt32(0);

  StreamIn[x].Data.VLeft := 0;

  StreamIn[x].Data.Vright := 0;

  StreamIn[x].Data.Status := 1;
  StreamIn[x].Data.TypePut := 5;
  StreamIn[x].Data.HandleSt := pchar('endless');
  StreamIn[x].Data.ratio := 2;
  StreamIn[x].Data.Output := -1;
  StreamIn[x].Data.seekable := False;
  StreamIn[x].Data.LibOpen := -1;
  StreamIn[x].LoopProc := Nil;
  StreamIn[x].Data.Enabled := True;
  Result := x;
end;

{$IF DEFINED(synthesizer)}
function Tuos_Player.AddFromSynth(Channels: integer; WaveTypeL, WaveTypeR: shortint;
                                  FrequencyL, FrequencyR: float; VolumeL, VolumeR: float;
                                  duration : cint32; NbHarmonics: cint32; EvenHarmonics: cint32;
                                  OutputIndex: cint32;  SampleFormat: cint32 ; SampleRate: CDouble ;
                                  FramesCount : cint32): cint32;
// Add a input from Synthesizer with custom parameters
// Channels: default: -1 (2) (1 = mono, 2 = stereo)

// WaveTypeL: default: -1 (0) (0 = sine-wave 1 = square-wave, 2 = triangle, 2= triangle, 3=sawtooth used for mono and stereo) 

// WaveTypeR: default: -1 (0) (0 = sine-wave 1 = square-wave,2 = triangle, 2= triangle, 3=sawtooth used, used for stereo, ignored for mono) 
// FrequencyL: default: -1 (440 htz) (Left frequency, used for mono)
// FrequencyR: default: -1 (440 htz) (Right frequency, used for stereo, ignored for mono)
// VolumeL: default: -1 (= 1) (from 0 to 1) => volume left
// VolumeR: default: -1 (= 1) (from 0 to 1) => volume rigth (ignored for mono)
// Duration: default:  -1 (= 1000)  => duration in msec (0 = endless)
// NbHarmonics: default:  -1 (= 0) Number of Harmonies
// EvenHarmonics: default: -1 (= 0) (0 = all harmonics, 1 = Only even harmonics)

// OutputIndex: Output index of used output// -1: all output, -2: no output, other cint32 refer to a existing OutputIndex  (if multi-output then OutName = name of each output separeted by ';')
// SampleFormat: default : -1 (0: Float32) (0: Float32, 1:Int32, 2:Int16)
// SampleRate: delault : -1 (44100)
// FramesCount: -1 default : 1024
//  result:  Input Index in array  -1 = error

var 
  x : cint32;
begin
  result := -1 ;
  x := 0;

  SetLength(StreamIn, Length(StreamIn) + 1);
  StreamIn[Length(StreamIn) - 1] := Tuos_InStream.Create();
  x := Length(StreamIn) - 1;
  StreamIn[x].Data.Enabled := false;
  StreamIn[x].Data.levelEnable := 0;
  StreamIn[x].Data.PositionEnable := 0;
  StreamIn[x].Data.levelArrayEnable := 0;

  if channels < 1 then
    StreamIn[x].data.channels := 2
  else
    StreamIn[x].data.channels := channels;

  if SampleRate = -1 then
    StreamIn[x].Data.SampleRate := DefRate
  else
    StreamIn[x].Data.SampleRate := SampleRate;

  if FramesCount = -1 then  StreamIn[x].Data.Wantframes :=  1024
  else
    StreamIn[x].Data.Wantframes := FramesCount ;

  if FrequencyL = -1 then
    StreamIn[x].Data.freqLsine := 440
  else
    StreamIn[x].Data.freqLsine := FrequencyL ;

  if FrequencyR = -1 then
    StreamIn[x].Data.freqRsine := 440
  else
    StreamIn[x].Data.freqRsine := FrequencyR ;

  if WaveTypeL < 1 then
    StreamIn[x].Data.typLsine := 0
  else
    StreamIn[x].Data.typLsine := WaveTypeL;

  if WaveTypeR < 1 then
    StreamIn[x].Data.typRsine := 0
  else
    StreamIn[x].Data.typRsine := WaveTypeR;

  StreamIn[x].Data.PosInTableLeft := 0;
  StreamIn[x].Data.PosInTableRight := 0;

  if NbHarmonics < 1 then
    StreamIn[x].data.harmonic := 0
  else
    StreamIn[x].data.harmonic := NbHarmonics;

  if EvenHarmonics < 1 then
    StreamIn[x].data.evenharm := 0
  else
    StreamIn[x].data.evenharm := 1;

  SetLength(StreamIn[x].Data.Buffer, StreamIn[x].Data.Wantframes* StreamIn[x].Data.channels);

  StreamIn[x].Data.posdursine := 0 ;

  if duration = -1 then duration := 1000;
  StreamIn[x].Data.dursine := trunc( StreamIn[x].Data.SampleRate * duration / 1000);

  if SampleFormat = -1 then
    StreamIn[x].Data.SampleFormat := CInt32(0)
  else
    StreamIn[x].Data.SampleFormat := CInt32(SampleFormat);

  if VolumeL = -1 then StreamIn[x].Data.VLeft := 1
  else
    StreamIn[x].Data.VLeft := VolumeL;

  if VolumeR = -1 then StreamIn[x].Data.Vright := 1
  else
    StreamIn[x].Data.Vright := VolumeR;

  StreamIn[x].Data.Status := 1;
  StreamIn[x].Data.TypePut := 3;
  StreamIn[x].Data.HandleSt := pchar('synth');

  if (StreamIn[x].Data.SampleFormat = 2) then
    StreamIn[x].Data.ratio := StreamIn[x].data.channels
  else StreamIn[x].Data.ratio := 2;

  StreamIn[x].Data.Output := OutputIndex;
  StreamIn[x].Data.seekable := False;
  StreamIn[x].Data.LibOpen := -1;
  StreamIn[x].LoopProc := Nil;
  StreamIn[x].Data.Enabled := True;

  FillLookupTable(x, StreamIn[x].Data.typLsine, 1,StreamIn[x].data.harmonic, StreamIn[x].data.
                  evenharm);
  FillLookupTable(x, StreamIn[x].Data.typRsine, 2,StreamIn[x].data.harmonic, StreamIn[x].data.
                  evenharm);

  Result := x;
end;

procedure Tuos_Player.InputSetSynth(InputIndex: cint32; WaveTypeL, WaveTypeR: shortint;
                                    FrequencyL, FrequencyR: float; VolumeL, VolumeR: float; duration
                                    : cint32;
                                    NbHarmonic: cint32; EvenHarmonics: cint32; Enable: boolean);
// InputIndex: one existing input index   

// WaveTypeL : do not change: -1 (0 = sine-wave 1 = square-wave, 2 = triangle, 2= triangle, 3=sawtooth used for mono and stereo) 

// WaveTypeR : do not change: -1 (0 = sine-wave 1 = square-wave, 2 = triangle, 2= triangle, 3=sawtooth used for stereo, ignored for mono) 
// FrequencyL : do not change: -1 (Left frequency, used for mono)
// FrequencyR : do not change: -1 (440 htz) (Right frequency, used for stereo, ignored for mono)
// VolumeL : do not change: -1 (= 1) (from 0 to 1) => volume left
// VolumeR : do not change: -1 (from 0 to 1) => volume rigth (ignored for mono)
// Duration : in msec (-1 = do not change)
// NbHarmonic : Number of Harmonies (-1 not change)
// EvenHarmonics: default: -1 (= 0) (0 = all harmonics, 1 = Only even harmonics)
// Enable : true or false ;

var 
  newtable : boolean = false;
begin
  StreamIn[InputIndex].Data.Enabled := Enable;

  if NbHarmonic <> -1 then
    begin
      StreamIn[InputIndex].Data.harmonic := NbHarmonic;
      newtable := true;
    end;

  if EvenHarmonics <> - 1 then
    begin
      if EvenHarmonics = 0 then
        StreamIn[InputIndex].data.evenharm := 0
      else
        StreamIn[InputIndex].data.evenharm := 1;
      newtable := true;
    end;

  if WaveTypeL <> -1 then
    begin
      StreamIn[InputIndex].Data.typLsine := WaveTypeL;
      newtable := true;
    end;

  if WaveTypeR <> -1 then
    begin
      StreamIn[InputIndex].Data.typRsine := WaveTypeR;
      newtable := true;
    end;

  if FrequencyL <> -1 then
    begin
      StreamIn[InputIndex].Data.freqLsine := FrequencyL ;
    end;

  if FrequencyR <> -1 then
    begin
      StreamIn[InputIndex].Data.freqRsine := FrequencyR ;
    end;

  if VolumeL <> -1 then
    begin
      StreamIn[InputIndex].Data.VLeft := VolumeL;
    end;

  if VolumeR <> -1 then
    begin
      StreamIn[InputIndex].Data.Vright := VolumeR;
    end;

  if Duration <> -1 then  StreamIn[InputIndex].Data.dursine := 
                                                               trunc( StreamIn[InputIndex].Data.
                                                               SampleRate * duration / 1000);

  if newtable then
    begin
      FillLookupTable(InputIndex,StreamIn[InputIndex].Data.typLsine, 1,
                      StreamIn[InputIndex].Data.harmonic, StreamIn[InputIndex].data.evenharm);
      FillLookupTable(InputIndex,StreamIn[InputIndex].Data.typRsine, 2,
                      StreamIn[InputIndex].Data.harmonic, StreamIn[InputIndex].data.evenharm);
    end;

end;
{$endif}

{$IF DEFINED(shout)}
function Tuos_Player.AddIntoIceServer(SampleRate : CDouble; Channels: cint; SampleFormat: cint;
                                      EncodeType: cint; Port: cint; Host: pchar; User: pchar;
                                      Password: pchar; MountFile :pchar): cint32;
// Add a Output into a IceCast server for audio-web-streaming 
// SampleRate : delault : -1 (48100)
// Channels : delault : -1 (2:stereo) (0: no channels, 1:mono, 2:stereo, ...)
// SampleFormat : -1 default : float32 : (0:float32, 1:Int16)
// EncodeType : default : -1 (0:Music) (0: Music, 1:Voice)
// Port : default : -1 (= 8000)
// Host : default : 'def' (= '127.0.0.1')
// User : default : 'def' (= 'source')
// Password : default : 'def' (= 'hackme')
// MountFile : default : 'def' (= '/example.opus')
//  result :  Output Index in array  -1 = error

var 
  x, typeenc : cint32;
  err : integer = -1;

begin

  result := -1 ;
  x := 0;
  err := -1;
  SetLength(StreamOut, Length(StreamOut) + 1);
  StreamOut[Length(StreamOut) - 1] := Tuos_OutStream.Create();
  x := Length(StreamOut) - 1;

  StreamOut[x].Data.Enabled := false;

  if (EncodeType = -1) or (EncodeType = 0)  then typeenc := OPUS_APPLICATION_AUDIO
  else
    typeenc := OPUS_APPLICATION_VOIP ;

  if SampleRate = -1 then StreamOut[x].Data.SampleRate := 48000
  else
    StreamOut[x].Data.SampleRate := SampleRate;

  if Channels = -1 then StreamOut[x].Data.Channels := 2
  else
    StreamOut[x].Data.Channels := Channels;

  if SampleFormat = -1 then StreamOut[x].Data.SampleFormat := 0
  else
    StreamOut[x].Data.SampleFormat := SampleFormat;

  StreamOut[x].Data.TypePut := 2 ;

  setlength(StreamOut[x].Data.Buffer,1024 *2);

  //  setlength(StreamOut[x].Data.Buffer,960); 

  {$IF DEFINED(uos_debug) and DEFINED(unix)}
  WriteLn('before opus_encoder_create ' );
  {$endif}

  // opus encoder
  StreamOut[x].encoder := opus_encoder_create(StreamOut[x].Data.SampleRate,
                          StreamOut[x].Data.Channels, typeenc, err);

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
  if (err<0)
    then
    begin
      WriteLn(Format('failed to create an encoder: %s', [opus_strerror(err)]));
    end;
  {$endif}
  // if (err=0) then
  //  err := opus_encoder_ctl(StreamOut[x].encoder , OPUS_SET_BITRATE(cBITRATE));
  {$IF DEFINED(uos_debug) and DEFINED(unix)}
  if (err<0)
    then
    begin
      WriteLn(Format('failed opus_encoder_ctl: %s', [opus_strerror(err)]));
    end;
  {$endif}

  if err =0 then
    begin

      StreamOut[x].Data.HandleSt := Nil;

      shout_init();

      StreamOut[x].Data.HandleSt := shout_new();

      if assigned(StreamOut[x].Data.HandleSt) then
        begin
  {$IF DEFINED(uos_debug) and DEFINED(unix)}
          WriteLn('shhandle assigned');
  {$endif}
          err := shout_set_host( StreamOut[x].Data.HandleSt, pchar(Host));

  {$IF DEFINED(uos_debug) and DEFINED(unix)}
          if err = SHOUTERR_SUCCESS then
            WriteLn('shout_set_host ok ' + inttostr(err))
          else
            WriteLn('shout_set_host error: ' + pchar(shout_get_error(StreamOut[x].Data.HandleSt)));
  {$endif}
          err := shout_set_protocol(StreamOut[x].Data.HandleSt, SHOUT_PROTOCOL_HTTP);
  {$IF DEFINED(uos_debug) and DEFINED(unix)}
          if err = SHOUTERR_SUCCESS then
            WriteLn('shout_set_protocol ' + inttostr(err))
          else
            WriteLn('shout_set_protocol error: ' + pchar(shout_get_error(StreamOut[x].Data.HandleSt)
            ));
  {$endif}
          err := shout_set_port(StreamOut[x].Data.HandleSt, Port);
  {$IF DEFINED(uos_debug) and DEFINED(unix)}
          if err = SHOUTERR_SUCCESS then
            WriteLn('shout_set_port ok ' + inttostr(err))
          else
            WriteLn('shout_set_port error: ' + pchar(shout_get_error(StreamOut[x].Data.HandleSt)));
  {$endif}
          err := shout_set_password(StreamOut[x].Data.HandleSt, pchar(Password));
  {$IF DEFINED(uos_debug) and DEFINED(unix)}
          if err = SHOUTERR_SUCCESS then
            WriteLn('set_password ok ' + inttostr(err))
          else
            WriteLn('set_password error: ' + pchar(shout_get_error(StreamOut[x].Data.HandleSt)));
  {$endif}
          err := shout_set_mount(StreamOut[x].Data.HandleSt, pchar(MountFile));
  {$IF DEFINED(uos_debug) and DEFINED(unix)}
          if err = SHOUTERR_SUCCESS then
            WriteLn('shout_set_mount ok ' + inttostr(err))
          else
            WriteLn('shout_set_mount error: ' + pchar(shout_get_error(StreamOut[x].Data.HandleSt)));
  {$endif}
          err := shout_set_user(StreamOut[x].Data.HandleSt, pchar(user));
  {$IF DEFINED(uos_debug) and DEFINED(unix)}
          if err = SHOUTERR_SUCCESS then
            WriteLn('shout_set_user ok ' + inttostr(err))
          else
            WriteLn('shout_set_user error: ' + pchar(shout_get_error(StreamOut[x].Data.HandleSt)));
  {$endif}
          err := shout_set_format(StreamOut[x].Data.HandleSt,  SHOUT_FORMAT_OGG);
  {$IF DEFINED(uos_debug) and DEFINED(unix)}
          if err = SHOUTERR_SUCCESS then
            WriteLn('shout_set_format ok ' + inttostr(err))
          else
            WriteLn('shout_set_format error: ' + pchar(shout_get_error(StreamOut[x].Data.HandleSt)))
          ;
  {$endif}
          err := shout_open(StreamOut[x].Data.HandleSt);
  {$IF DEFINED(uos_debug) and DEFINED(unix)}
          if err = SHOUTERR_SUCCESS then
            WriteLn('shout_open ok ' + inttostr(err))
          else
            WriteLn('shout_open error: ' + pchar(shout_get_error(StreamOut[x].Data.HandleSt)));
  {$endif}

          if err = SHOUTERR_SUCCESS then
            begin
              StreamOut[x].Data.Enabled := True;
              result := x
            end
          else
            begin
              shout_free(StreamOut[x].Data.HandleSt);
              StreamOut[Length(StreamOut) - 1].Destroy;
              setlength(StreamOut, Length(StreamOut) - 1);
            end;
        end
      else
        begin
          StreamOut[Length(StreamOut) - 1].Destroy;
          setlength(StreamOut, Length(StreamOut) - 1);
  {$IF DEFINED(uos_debug) and DEFINED(unix)}
          WriteLn('shhandle not assigned')  {$endif} ;
        end;
    end;
end;
 {$endif}

procedure uos_CustBufferInfos(Var bufferinfos: Tuos_BufferInfos; SampleRate: CDouble; SampleFormat
                              : cint32; Channels: cint32 ; Length: cint32);
begin
  bufferinfos.SampleRate := Samplerate;
  bufferinfos.SampleRateRoot := Samplerate;
  bufferinfos.SampleFormat := SampleFormat;
  bufferinfos.Channels := Channels;
  bufferinfos.Length := Length;
  bufferinfos.LibOpen := 0;
  bufferinfos.Ratio := 2 ;
end;


function Tuos_Player.AddIntoFileFromMem(Filenamepath: PChar; SampleRate: CDouble;
                                        Channels: LongInt; SampleFormat: LongInt; FramesCount:
                                        LongInt; FileFormat: cint32): LongInt;
// Add a Output into audio wav file with Custom parameters
// FileName : filename of saved audio wav file
// SampleRate : delault : -1 (44100)
// Channels : delault : -1 (2:stereo) (1:mono, 2:stereo, ...)
//  SampleFormat : -1 default : Int16 : (1:Int32, 2:Int16)
// FramesCount : -1 default : 65536 div channels
// FileFormat : default : -1 (wav) (0:wav, 1:pcm, 2:custom);
//  result :  Output Index in array    -1 = error
// example : OutputIndex1 := AddIntoFileFromMem(edit5.Text,-1,-1,0, -1);
var 
  x: LongInt;
begin
  result := -1 ;
  x := 0;
  SetLength(StreamOut, Length(StreamOut) + 1);
  StreamOut[Length(StreamOut) - 1] := Tuos_OutStream.Create();
  x := Length(StreamOut) - 1;
  StreamOut[x].Data.Enabled := false;
  StreamOut[x].FileBuffer.ERROR := 0;
  StreamOut[x].Data.Filename := Filenamepath;
  if (FileFormat = -1) or (FileFormat = 0) then
    StreamOut[x].FileBuffer.FileFormat := 0
  else StreamOut[x].FileBuffer.FileFormat := FileFormat;
  StreamOut[x].Data.TypePut := 4;
  FillChar(StreamOut[x].FileBuffer, sizeof(StreamOut[x].FileBuffer), 0);
  StreamOut[x].FileBuffer.DataMS := TMemoryStream.Create;

  result := x;

  if (Channels = -1) then
    StreamOut[x].FileBuffer.wChannels := 2
  else
    StreamOut[x].FileBuffer.wChannels := Channels;

  StreamOut[x].Data.Channels := StreamOut[x].FileBuffer.wChannels;

  if FramesCount = -1 then  StreamOut[x].Data.Wantframes :=  65536 Div StreamOut[x].Data.Channels
  else
    StreamOut[x].Data.Wantframes := FramesCount ;

  SetLength(StreamOut[x].Data.Buffer, StreamOut[x].Data.Wantframes*StreamOut[x].Data.Channels);

  if (SampleFormat = -1) or (SampleFormat = 2) then
    begin
      StreamOut[x].FileBuffer.wBitsPerSample := 16;
      StreamOut[x].Data.SampleFormat := 2;
    end;

  if (SampleFormat = 1) then
    begin
      StreamOut[x].FileBuffer.wBitsPerSample := 32;
      StreamOut[x].Data.SampleFormat := 1;
    end;

  if SampleRate = -1 then
    StreamOut[x].FileBuffer.wSamplesPerSec := 44100
  else
    StreamOut[x].FileBuffer.wSamplesPerSec := roundmath(samplerate);

  StreamOut[x].Data.Samplerate := StreamOut[x].FileBuffer.wSamplesPerSec;
  StreamOut[x].LoopProc := Nil;
  StreamOut[x].Data.Enabled := True;
end;

function Tuos_Player.AddIntoFile(Filenamepath: PChar; SampleRate: CDouble;
                                 Channels: cint32; SampleFormat: cint32 ; FramesCount: cint32 ;
                                 FileFormat: cint32): cint32;
// Add a Output into audio wav file with custom parameters
// FileName : filename of saved audio wav file
// SampleRate : delault : -1 (44100)
// Channels : delault : -1 (2:stereo) (0: no channels, 1:mono, 2:stereo, ...)
// SampleFormat : default : -1 (2:Int16) ( 1:Int32, 2:Int16)
// FramesCount : default : -1 (= 4096)
// FileFormat : default : -1 (wav) (0:wav, 1:pcm, 2:custom, 3:ogg);
//  result : Output Index in array  -1 = error
// example : OutputIndex1 := AddIntoFile(edit5.Text,-1,-1, 0, -1, -1);
var 
  x: cint32;
  wChunkSize: cint32;
  wFileSize: cint32;
  IDwav: array[0..3] of char;
  Header: Tuos_WaveHeaderChunk;
  {$IF DEFINED(sndfile)}
  sfInfo: TSF_INFO;
  {$endif}

begin
  result := -1 ;
  x := 0;
  SetLength(StreamOut, Length(StreamOut) + 1);
  StreamOut[Length(StreamOut) - 1] := Tuos_OutStream.Create();
  x := Length(StreamOut) - 1;
  StreamOut[x].Data.Enabled := false;
  StreamOut[x].FileBuffer.ERROR := 0;
  StreamOut[x].Data.Filename := filenamepath;
  if (FileFormat = -1) or (FileFormat = 0) then
    StreamOut[x].FileBuffer.FileFormat := 0
  else StreamOut[x].FileBuffer.FileFormat := FileFormat;

  FillChar(StreamOut[x].FileBuffer, sizeof(StreamOut[x].FileBuffer), 0);

  result := x;

  if (Channels = -1) then
    StreamOut[x].FileBuffer.wChannels := 2
  else
    StreamOut[x].FileBuffer.wChannels := Channels;

  StreamOut[x].Data.Channels := StreamOut[x].FileBuffer.wChannels;

  if FramesCount = -1 then  StreamOut[x].Data.Wantframes :=  65536 Div StreamOut[x].Data.Channels
  else
    StreamOut[x].Data.Wantframes := FramesCount ;

  SetLength(StreamOut[x].Data.Buffer, StreamOut[x].Data.Wantframes*StreamOut[x].Data.Channels);

  if (SampleFormat = -1) or (SampleFormat = 2) then
    begin
      StreamOut[x].FileBuffer.wBitsPerSample := 16;
      StreamOut[x].Data.SampleFormat := 2;
    end;

  if (SampleFormat = 1) then
    begin
      StreamOut[x].FileBuffer.wBitsPerSample := 32;
      StreamOut[x].Data.SampleFormat := 1;
    end;

  if (SampleFormat = 0) then
    begin
      StreamOut[x].FileBuffer.wBitsPerSample := 32;
      StreamOut[x].Data.SampleFormat := 0;
    end;

  if SampleRate = -1 then
    StreamOut[x].FileBuffer.wSamplesPerSec := 44100
  else
    StreamOut[x].FileBuffer.wSamplesPerSec := roundmath(samplerate);

  StreamOut[x].Data.Samplerate := StreamOut[x].FileBuffer.wSamplesPerSec;
  StreamOut[x].LoopProc := Nil;

  if fileformat = 3 then
    begin
      // ogg file
  {$IF DEFINED(sndfile)}
      StreamOut[x].FileBuffer.FileFormat := 3;
      StreamOut[x].Data.TypePut := 6 ;
      sfInfo.format := SF_FORMAT_OGG Or SF_FORMAT_VORBIS;
      sfInfo.channels := StreamOut[x].Data.Channels;
      sfInfo.frames :=  streamOut[x].Data.Wantframes;
      SFinfo.samplerate := StreamOut[x].FileBuffer.wSamplesPerSec;
      SFinfo.seekable := 0;
      StreamOut[x].Data.Enabled := True;
      StreamOut[x].Data.HandleSt := sf_open(pchar(FileNamepath), SFM_WRITE, sfInfo);
  {$endif}
    end
  else
    begin
      // wav file
      StreamOut[x].FileBuffer.Data := TFileStream.Create(filenamepath,fmCreate);
      StreamOut[x].FileBuffer.Data.Seek(0, soFromBeginning);
      StreamOut[x].Data.TypePut := 0 ;
      IDwav := 'RIFF';
      StreamOut[x].FileBuffer.Data.WriteBuffer(IDwav, 4);
      wFileSize := 0;
      StreamOut[x].FileBuffer.Data.WriteBuffer(wFileSize, 4);
      IDwav := 'WAVE';
      StreamOut[x].FileBuffer.Data.WriteBuffer(IDwav, 4);
      IDwav := 'fmt ';
      StreamOut[x].FileBuffer.Data.WriteBuffer(IDwav, 4);
      wChunkSize := SizeOf(Header);
      StreamOut[x].FileBuffer.Data.WriteBuffer(wChunkSize, 4);
      Header.wFormatTag := 1;

      Header.wChannels := StreamOut[x].FileBuffer.wChannels;

      Header.wSamplesPerSec := StreamOut[x].FileBuffer.wSamplesPerSec;

      Header.wBlockAlign := StreamOut[x].FileBuffer.wChannels * (StreamOut[x].FileBuffer.
                            wBitsPerSample Div 8);

      Header.wAvgBytesPerSec := StreamOut[x].FileBuffer.wSamplesPerSec * Header.wBlockAlign;
      Header.wBitsPerSample := StreamOut[x].FileBuffer.wBitsPerSample;
      Header.wcbSize := 0;
      StreamOut[x].FileBuffer.Data.WriteBuffer(Header, SizeOf(Header));
      IDwav := 'data';
      StreamOut[x].FileBuffer.Data.WriteBuffer(IDwav, 4);
      wChunkSize := 0;
      StreamOut[x].FileBuffer.Data.WriteBuffer(wChunkSize, 4);
      StreamOut[x].Data.Enabled := True;

    end;
end;

function  Tuos_Player.AddIntoMemoryBuffer(outmemory: PDArFloat): cint32;
// Add a Output into memory-bufffer
// outmemory : buffer to use to store memory buffer
// example : OutputIndex1 := AddIntoMemoryBuffer(bufmemory);

var 
  x: integer;
begin
  result := -1 ;
  x := 0;
  SetLength(StreamOut, Length(StreamOut) + 1);
  StreamOut[Length(StreamOut) - 1] := Tuos_OutStream.Create();
  x := Length(StreamOut) - 1;
  StreamOut[x].Data.Enabled := false;
  StreamOut[x].Data.TypePut := 3;
  Streamout[x].Data.posmem := 0;
  Streamout[x].BufferOut := outmemory;
  StreamOut[x].Data.channels := 2;
  StreamOut[x].Data.Wantframes := 65536 ;
  StreamOut[x].Data.SampleFormat := 0;
  StreamOut[x].Data.SampleRate := 44100 ;
  SetLength(StreamOut[x].Data.Buffer,65536*2);
  intobuf := true;
  // to check, why ?
  result := x;
  StreamOut[x].Data.Enabled := True;
end;

function  Tuos_Player.AddIntoMemoryBuffer(outmemory: PDArFloat; SampleRate: CDouble;  SampleFormat:
                                          LongInt;
                                          Channels: LongInt; FramesCount: LongInt): LongInt;
// Add a Output into Memory Buffer with parameters.
// outmemory : pointer of buffer to use to store memory.
// SampleRate : delault : -1 (44100)
// SampleFormat : default : -1 (0:Float32) ( 1:Int32, 2:Int16)
// Channels : delault : -1 (2:stereo) (0: no channels, 1:mono, 2:stereo, ...)
// FramesCount : default : -1 (= 65536) 

var 
  x, ch, sr, sf, fr: integer;
begin
  result := -1 ;
  x := 0;
  SetLength(StreamOut, Length(StreamOut) + 1);
  StreamOut[Length(StreamOut) - 1] := Tuos_OutStream.Create();
  x := Length(StreamOut) - 1;
  StreamOut[x].Data.Enabled := false;
  StreamOut[x].Data.TypePut := 3;
  Streamout[x].Data.posmem := 0;
  Streamout[x].BufferOut := outmemory;
  if channels = -1 then ch := 2
  else ch := channels;
  StreamOut[x].Data.channels := ch;
  if SampleFormat = -1 then sf := 0
  else sf := SampleFormat;
  StreamOut[x].Data.SampleFormat := sf;
  if FramesCount = -1 then fr := 65536
  else fr := FramesCount;
  StreamOut[x].Data.Wantframes := fr ;
  if SampleRate = -1 then sr := 44100
  else sr := roundmath(SampleRate);
  StreamOut[x].Data.SampleRate := sr ;

  SetLength(StreamOut[x].Data.Buffer,fr*ch);
  intobuf := true;
  // to check, why ?
  result := x;
  StreamOut[x].Data.Enabled := True;
end;

  {$IF DEFINED(portaudio)}
function Tuos_Player.AddIntoDevOut(Device: cint32; Latency: CDouble;
                                   SampleRate: CDouble; Channels: cint32; SampleFormat: cint32 ;
                                   FramesCount: cint32 ; ChunkCount: cint32): cint32;
// Add a Output into Device Output
// Device ( -1 is default device )
// Latency  ( -1 is latency suggested )
// SampleRate : delault : -1 (44100)
// Channels : delault : -1 (2:stereo) (0: no channels, 1:mono, 2:stereo, ...)
// SampleFormat : default : -1 (2:Int16) (0: Float32, 1:Int32, 2:Int16)
// FramesCount : default : -1 (= 65536)
// ChunkCount : default : -1 (= 512)
//  result :  Output Index in array  -1 = error
// example : OutputIndex1 := AddIntoDevOut(-1,-1,-1,-1,0,-1,-1);
var 
  x, x2, err: cint32;

begin
  result := -1 ;

  if device = -1 then
    err := Pa_GetDefaultOutputDevice();
  if err = -1 then result := -2;

  if result <> -2 then
    begin
      x := 0;
      err := -1;
      SetLength(StreamOut, Length(StreamOut) + 1);
      StreamOut[Length(StreamOut) - 1] := Tuos_OutStream.Create();
      x := Length(StreamOut) - 1;

      StreamOut[x].Data.Enabled := false;

   {$IF DEFINED(portaudio)}
      StreamOut[x].PAParam.hostApiSpecificStreamInfo := Nil;
      if device = -1 then
        StreamOut[x].PAParam.device := Pa_GetDefaultOutputDevice()
      else
        StreamOut[x].PAParam.device := device;
  {$endif}

      if SampleRate = -1 then
        StreamOut[x].Data.SampleRate := DefRate
      else
        StreamOut[x].Data.SampleRate := SampleRate;

 {$IF DEFINED(portaudio)}

      if Latency = -1 then
        StreamOut[x].PAParam.SuggestedLatency :=    CDouble((Pa_GetDeviceInfo(StreamOut[x].PAParam.
                                                 device)^.   defaultHighOutputLatency)) * 1
      else   StreamOut[x].PAParam.SuggestedLatency := CDouble(Latency);


  {$IF DEFINED(android)}
      StreamOut[x].PAParam.SampleFormat := paFloat32;
  {$else}
      StreamOut[x].PAParam.SampleFormat := paInt16;
  {$endif}

      case SampleFormat of 
        0: StreamOut[x].PAParam.SampleFormat := paFloat32;
        1: StreamOut[x].PAParam.SampleFormat := paInt32;
        2: StreamOut[x].PAParam.SampleFormat := paInt16;
      end;
 {$endif}

      if SampleFormat = -1 then
        StreamOut[x].Data.SampleFormat := 2
      else
        StreamOut[x].Data.SampleFormat := SampleFormat;

      if Channels = -1 then
        begin
  {$IF DEFINED(portaudio)}
          StreamOut[x].PAParam.channelCount := 2  ;
  {$endif}
          StreamOut[x].Data.Channels := 2  ;
        end
      else
        begin
   {$IF DEFINED(portaudio)}
          StreamOut[x].PAParam.channelCount := CInt32(Channels);
   {$endif}
          StreamOut[x].Data.Channels := CInt32(Channels);
        end;

      if FramesCount = -1 then  StreamOut[x].Data.Wantframes := 

  {$IF DEFINED(android)}
                                                                1024 * 64
      else
  {$else}
        65536 div StreamOut[x].Data.Channels
      else
  {$endif}
        StreamOut[x].Data.Wantframes := FramesCount ;

      if ChunkCount = -1 then  ChunkCount := 512;

      SetLength(StreamOut[x].Data.Buffer, StreamOut[x].Data.Wantframes*StreamOut[x].Data.Channels);

      x2 := 0 ;
      while x2 < Length(StreamOut[x].Data.Buffer) do
        begin
          StreamOut[x].Data.Buffer[x2] := 0.0 ;
          inc(x2);
        end;

      StreamOut[x].Data.TypePut := 1;

  {$IF DEFINED(portaudio)}
      err := Pa_OpenStream(@StreamOut[x].Data.HandleSt, Nil, @StreamOut[x].PAParam, CDouble(
             StreamOut[x]
             .Data.SampleRate), CULong(ChunkCount), paClipOff, Nil, Nil);


//   err := Pa_OpenDefaultStream(@StreamOut[x].Data.HandleSt, 2, 2, paFloat32, DefRate, 512, nil, nil);
  {$endif}

      StreamOut[x].LoopProc := Nil;
      if err <> 0 then Result := -1
      else
        begin
          StreamOut[x].Data.Enabled := True;
          Result := x;
        end;
    end
  else Result := -1;
end;

 {$endif}

{$IF DEFINED(webstream)}

function Tuos_Player.AddFromURL(URL: PChar; OutputIndex: cint32;
                                SampleFormat: cint32 ; FramesCount: cint32 ; AudioFormat: cint32 ;
                                ICYon : boolean): cint32;
// Add a Input from Audio URL
// URL : URL of audio file

// OutputIndex : OutputIndex of existing Output// -1: all output, -2: no output, other cint32 : existing Output
// SampleFormat : -1 default : Int16 (0: Float32, 1:Int32, 2:Int16)
// FramesCount : default : -1 (4096)
// AudioFormat : default : -1 (mp3) (0: mp3, 1: opus, 2:aac)
// ICYon : ICY data on/off
// example : InputIndex := AddFromURL('http://someserver/somesound.mp3',-1,-1,-1,-1,-1, false);

var 
  x, err, len, len2, i : cint32;
  PipeBufferSize, totsamples : integer;
  buffadd : tbytes;
  samprat : cint32;

  {$IF DEFINED(mpg123)}
  mpinfo: Tmpg123_frameinfo;
  // BufferTag: array[1..128] of char; 
  // F: file; 
  // mpid3v2: Tmpg123_id3v2;
  {$endif}

  {$IF DEFINED(opus)}
  s: UTF8String;
  j: Integer;
  OpusTag: POpusTags;
  LComment: PPAnsiChar;
  LcommentLength: PInteger;
  {$endif}

begin
  result := -1 ;
  x := 0;
  err := -1;

  SetLength(StreamIn, Length(StreamIn) + 1);

  StreamIn[Length(StreamIn) - 1] := Tuos_InStream.Create;
  x := Length(StreamIn) - 1;

  StreamIn[x].Data.Enabled := false;

  StreamIn[x].Data.LibOpen := -1;
  StreamIn[x].Data.levelEnable := 0;
  StreamIn[x].Data.positionEnable := 0;
  StreamIn[x].Data.levelArrayEnable := 0;
  
  {$IF DEFINED(fdkaac)}
  if (AudioFormat = 2)
    then
    begin
 {$IF DEFINED(uos_debug) and DEFINED(unix)}
      WriteLn('Begin fdkaac');
  {$endif}
  
      
      PipeBufferSize :=  1024 * 4;

      CreatePipeHandles(StreamIn[x].InHandle, StreamIn[x].OutHandle, PipeBufferSize);

      StreamIn[x].InPipe := TInputPipeStream.Create(StreamIn[x].InHandle);
      StreamIn[x].OutPipe := TOutputPipeStream.Create(StreamIn[x].OutHandle);
      
      

      StreamIn[x].httpget := TThreadHttpGetter.Create(url, StreamIn[x].OutPipe);
             
      StreamIn[x].httpget.freeonterminate := true;

      StreamIn[x].httpget.ICYenabled := ICYon;

      //writeln('avant httpget.Start');
      StreamIn[x].httpget.Start;
      // writeln('apres httpget.Start');
      
      sleep(2000);
      
     if StreamIn[x].httpget.IsRunning then
     begin
    
     if StreamIn[x].httpget.ICYenabled = true then
        CheckSynchronize(1000);

      StreamIn[x].Data.HandleSt := aacDecoder_Open(TRANSPORT_TYPE.TT_MP4_ADTS, 1);

      if StreamIn[x].Data.HandleSt = nil then
        begin
          // writeln('NOT OK aacDecoder_Open()');
          exit;
        end;
      // else writeln('OK aacDecoder_Open()');

      if (aacDecoder_SetParam(StreamIn[x].Data.HandleSt, AAC_CONCEAL_METHOD, 1) <> AAC_DECODER_ERROR
         .AAC_DEC_OK) then
        begin
          // writeln('Unable to set the AAC_CONCEAL_METHOD');
          exit;
        end;

      if (aacDecoder_SetParam(StreamIn[x].Data.HandleSt, AAC_PCM_LIMITER_ENABLE, 0) <>
         AAC_DECODER_ERROR.AAC_DEC_OK) then
        begin
          // writeln('Unable to set the AAC_PCM_LIMITER_ENABLE');
          exit;
        end;

      // writeln('FIN INIT ------------- AACDecDecode');      
      
      StreamIn[x].Data.LibOpen := 2;

      if SampleFormat = -1 then
        StreamIn[x].Data.SampleFormat := 2
      else StreamIn[x].Data.SampleFormat := SampleFormat;
      
       if FramesCount = -1 then
        StreamIn[x].Data.Wantframes :=  65536
      else
        StreamIn[x].Data.Wantframes := FramesCount ;

      StreamIn[x].Data.Channels := 2;
      StreamIn[x].Data.samplerate := 44100;
      StreamIn[x].Data.ratio := 2;
     
      SetLength(StreamIn[x].Data.Buffer, StreamIn[x].Data.Wantframes * StreamIn[x].Data.channels);

      StreamIn[x].Data.Output := OutputIndex;
      StreamIn[x].Data.Status := 1;
      StreamIn[x].Data.Position := 0;
      StreamIn[x].Data.OutFrames := 0;
      StreamIn[x].Data.Poseek := 0;
      StreamIn[x].Data.TypePut := 2;
      StreamIn[x].Data.seekable := false;
      Err := 0;
     
     end else
     begin
         result := -1;
         StreamIn[x].httpget.Terminate;
         sleep(100);
         StreamIn[x].inpipe.destroy;
         StreamIn[x].outpipe.destroy;
     end;     
     // writeln('----------- FIN add URL -------------' ); 

    end;
  {$endif}

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
  WriteLn('ac StreamIn[x].Data.LibOpen = ' + inttostr(StreamIn[x].Data.LibOpen));
 {$endif}

  ////////////////// end aac

  {$IF DEFINED(opus)}
  if  (AudioFormat = 1)
     // or (AudioFormat = -1)
    then
    begin

  {$IF DEFINED(uos_debug) and DEFINED(unix)}
      WriteLn('Begin opus test');
  {$endif}

      if FramesCount= -1 then
        totsamples := 4096
      else
        totsamples := FramesCount;

      PipeBufferSize := totsamples * sizeOf(Single);
      // * 2

  {$IF DEFINED(uos_debug) and DEFINED(unix)}
      WriteLn('totsamples: ' + inttostr(totsamples));
      WriteLn('PipeBufferSize: ' + inttostr(PipeBufferSize));
  {$endif}

      CreatePipeHandles(StreamIn[x].InHandle, StreamIn[x].OutHandle, PipeBufferSize);
      StreamIn[x].InPipe := TInputPipeStream.Create(StreamIn[x].InHandle);
      StreamIn[x].OutPipe := TOutputPipeStream.Create(StreamIn[x].OutHandle);

      StreamIn[x].httpget := TThreadHttpGetter.Create(url, StreamIn[x].OutPipe);
      StreamIn[x].httpget.freeonterminate := true;
      StreamIn[x].httpget.ICYenabled := false;
      // TODO

     // StreamIn[x].httpget.FIsRunning := True;

      StreamIn[x].httpget.Start;
      //  WriteLn('StreamIn[x].httpget.Start');
      
      sleep(2000);
      
     if StreamIn[x].httpget.IsRunning then
     begin

      len := 1 ;
      len2 := 0 ;

      setlength(buffadd, PipeBufferSize);
      setlength(StreamIn[x].data.BufferTMP, PipeBufferSize);

      while (len2 < PipeBufferSize) and (len > 0) do
        begin
          len := StreamIn[x].InPipe.Read(buffadd[0],PipeBufferSize-len2);
          if len > 0 then  for i := 0 to len -1 do
                             StreamIn[x].data.BufferTMP[i+len2] := buffadd[i] ;
          len2 := len2 + len;
        end;

  {$IF DEFINED(uos_debug) and DEFINED(unix)}
      WriteLn('PipeBufferSize = ' + inttostr(PipeBufferSize));
      WriteLn('InPipe.Read = ' + inttostr(len2));
      WriteLn('----------------------------------');
      //writeln(tencoding.utf8.getstring(StreamIn[x].data.BufferTMP));
  {$endif}

      StreamIn[x].Data.HandleSt := pchar('opusurl');
 {$IF DEFINED(uos_debug) and DEFINED(unix)}
      WriteLn('StreamIn[x].Data.HandleSt url assisgned');
  {$endif}

      StreamIn[x].Data.HandleOP := 


// op_open_callbacks(StreamIn[x].InPipe, uos_callbacks, StreamIn[x].data.BufferTMP[0], PipeBufferSize, err); 
                                   op_test_callbacks(StreamIn[x].InPipe, uos_callbacks, StreamIn[x].
                                   data.BufferTMP[0], PipeBufferSize, err);
      //  op_test_memory(StreamIn[x].data.BufferTMP[0],PipeBufferSize, Err);

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
      WriteLn('error: op_test_*: ' + inttostr(err));
 {$endif}

      if Err=0
        then
        begin
          Err := op_test_open(StreamIn[x].Data.HandleOP);

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
          WriteLn('error: op_test_open: ' + inttostr(err));
 {$endif}

          if (Err=0) and (op_link_count(StreamIn[x].Data.HandleOP)=1)
            then
            begin

  {$IF DEFINED(uos_debug) and DEFINED(unix)}
              WriteLn('OK open');
 {$endif}

              if SampleFormat = -1 then
                StreamIn[x].Data.SampleFormat := 2
              else
                StreamIn[x].Data.SampleFormat := SampleFormat;

              //tag  

              OpusTag := op_tags(StreamIn[x].Data.HandleOP, Nil);

              if OpusTag<>nil

                then
                begin

                  if OpusTag^.comments>0
                    then
                    begin

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
                      WriteLn((Format('OpusTag.comments = %d', [OpusTag^.comments])));
 {$endif}
                      LComment := OpusTag^.user_comments;
                      LcommentLength := OpusTag^.comment_lengths;

                      for j := 0 to OpusTag^.comments - 1 do
                        begin
                          SetLength(s, LcommentLength^);
                          move(Pointer(LComment^)^, Pointer(s)^, LcommentLength^);

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
                          WriteLn(s);
 {$endif}
                          if j = 1 then StreamIn[x].Data.title := s;
                          if j = 2 then StreamIn[x].Data.artist := s;
                          if j = 3 then StreamIn[x].Data.album := s;
                          if j = 4 then StreamIn[x].Data.date := s;
                          if j = 5 then StreamIn[x].Data.comment := s;
                          if j = 6 then StreamIn[x].Data.tag := s;
                          if j > 6 then StreamIn[x].Data.comment := StreamIn[x].Data.comment + ' ' +
                                                                    s;

                          inc(LComment);
                          inc(LcommentLength);
                        end;
                    end;
                end;

              StreamIn[x].Data.Length := op_pcm_total(StreamIn[x].Data.HandleOP, Nil);
              StreamIn[x].Data.filename := url;
              StreamIn[x].Data.channels := op_channel_count(StreamIn[x].Data.HandleOP, Nil);

  {$IF DEFINED(uos_debug) and DEFINED(unix)}
              WriteLn((Format('op_bitrate = %d', [op_bitrate(StreamIn[x].Data.HandleOP, Nil)])));
              WriteLn('Length ' + inttostr(StreamIn[x].Data.Length));
              WriteLn('Data.Channels ' + inttostr(StreamIn[x].Data.channels));
  {$endif}

              StreamIn[x].Data.samplerate :=  48000 ;
              StreamIn[x].Data.samplerateroot :=  StreamIn[x].Data.samplerate ;
              StreamIn[x].Data.Wantframes := totsamples ;

              SetLength(StreamIn[x].Data.Buffer, StreamIn[x].Data.Wantframes);

              StreamIn[x].Data.LibOpen := 4;
              StreamIn[x].Data.Status := 1;
              StreamIn[x].Data.Position := 0;
              StreamIn[x].Data.OutFrames := 0;
              StreamIn[x].Data.Poseek := -1;
              StreamIn[x].Data.TypePut := 2;
              StreamIn[x].Data.ratio := 1;
              StreamIn[x].Data.seekable := false;
              StreamIn[x].LoopProc := Nil;
              StreamIn[x].Data.Enabled := True;

  {$IF DEFINED(uos_debug) and DEFINED(unix)}
              WriteLn('End opus');
  {$endif}

            end;
        end;
        end else
        begin
         result := -1;
         StreamIn[x].httpget.Terminate;
         sleep(100);
         StreamIn[x].inpipe.destroy;
         StreamIn[x].outpipe.destroy;
        end;
    end;
  {$endif}

  {$IF DEFINED(mpg123)}
  if (StreamIn[x].Data.LibOpen = -1) and ((AudioFormat = 0) or (AudioFormat = -1)) then
    begin
  {$IF DEFINED(uos_debug) and DEFINED(unix)}
      WriteLn('Begin mpg123');
 {$endif}

      if FramesCount= -1 then
        totsamples := $4000
      else
        totsamples := FramesCount;

      PipeBufferSize := totsamples ;

      CreatePipeHandles(StreamIn[x].InHandle, StreamIn[x].OutHandle, PipeBufferSize);

      StreamIn[x].InPipe := TInputPipeStream.Create(StreamIn[x].InHandle);
      StreamIn[x].OutPipe := TOutputPipeStream.Create(StreamIn[x].OutHandle);

      StreamIn[x].httpget := TThreadHttpGetter.Create(url, StreamIn[x].OutPipe);
      
      //  if StreamIn[x].httpget = nil then  writeln('httpget = NIL') else  writeln('httpget = OK');
    
      StreamIn[x].httpget.freeonterminate := true;

      StreamIn[x].httpget.ICYenabled := ICYon;
      
      if StreamIn[x].httpget.ICYenabled = true then
       StreamIn[x].UpdateIcyMetaInterval ;

      StreamIn[x].httpget.Start;

      sleep(2000);
      
      if StreamIn[x].httpget.IsRunning then
      begin
        if StreamIn[x].httpget.ICYenabled = true then
            CheckSynchronize(1000);

      StreamIn[x].Data.HandleSt := mpg123_new(Nil, Err);

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
      if err = 0 then writeln('===> mpg123_new => ok.')
      else writeln('===> mpg123_new NOT ok.') ;
 {$endif}

      if Err = 0 then
        begin
          if SampleFormat = -1 then
            StreamIn[x].Data.SampleFormat := 2
          else
            StreamIn[x].Data.SampleFormat := SampleFormat;

          mpg123_format_none(StreamIn[x].Data.HandleSt);
          case StreamIn[x].Data.SampleFormat of 
            0: mpg123_format(StreamIn[x].Data.HandleSt, DefRate, Stereo,
                             MPG123_ENC_FLOAT_32);
            1: mpg123_format(StreamIn[x].Data.HandleSt, DefRate, Stereo,
                             MPG123_ENC_SIGNED_32);
            2: mpg123_format(StreamIn[x].Data.HandleSt, DefRate, Stereo,
                             MPG123_ENC_SIGNED_16);
          end;



// mpg123_replace_reader_handle(StreamIn[x].Data.HandleSt, @mpg_read_stream, @mpg_seek_url, @mpg_close_stream);
          mpg123_replace_reader_handle(StreamIn[x].Data.HandleSt,
                                       @mpg_read_stream, @mpg_seek_url, Nil);

  {$IF DEFINED(uos_debug) and DEFINED(unix)}
          if err = 0 then writeln('===> mpg123_replace_reader_handle => ok.') ;
  {$endif}

          Err :=  mpg123_open_handle(StreamIn[x].Data.HandleSt, Pointer(StreamIn[x].InPipe));

  {$IF DEFINED(uos_debug) and DEFINED(unix)}
          if err = 0 then writeln('===> mpg123_open_handle => ok.')
          else
            writeln('===> mpg123_open_handle => NOT ok.') ;
  {$endif}

          sleep(10);
        end;

  {$IF DEFINED(uos_debug) and DEFINED(unix)}
      if err = 0 then
        writeln('===> mpg123_open_handle all => ok.')
      else
        writeln('===> mpg123_open_handle all => NOT ok.');
  {$endif}

      if err = 0 then
        begin
          StreamIn[x].Data.filename := URL ;

          if FramesCount = -1 then  StreamIn[x].Data.Wantframes :=  1024
          else
            StreamIn[x].Data.Wantframes := FramesCount ;

          // StreamIn[x].Data.Wantframes := totsamples;

          StreamIn[x].Data.Output := OutputIndex;
          StreamIn[x].Data.Status := 1;
          StreamIn[x].Data.Position := 0;
          StreamIn[x].Data.OutFrames := 0;
          StreamIn[x].Data.Poseek := -1;
          StreamIn[x].Data.TypePut := 2;
          StreamIn[x].Data.seekable := false;
          StreamIn[x].LoopProc := Nil;

          samprat := roundmath(StreamIn[x].Data.samplerate);

          Err := mpg123_getformat(StreamIn[x].Data.HandleSt,
                 samprat, StreamIn[x].Data.channels,
                 StreamIn[x].Data.encoding);

  {$IF DEFINED(uos_debug) and DEFINED(unix)}
          if err = 0 then
            writeln('===> mpg123_getformat => ok.')
          else
            writeln('===> mpg123_getformat => NOT ok.');
  {$endif}

          if err <> 0 then
            begin
              sleep(50);
              samprat := roundmath(StreamIn[x].Data.samplerate);

              Err := mpg123_getformat(StreamIn[x].Data.HandleSt,
                     samprat, StreamIn[x].Data.channels,
                     StreamIn[x].Data.encoding);

            end;
          if err = 0 then
            begin

  {$IF DEFINED(uos_debug) and DEFINED(unix)}
              writeln('===> mpg123_getformat => ok');
  {$endif}

              SetLength(StreamIn[x].Data.Buffer, StreamIn[x].Data.Wantframes*StreamIn[x].Data.
                        Channels);

              StreamIn[x].Data.LibOpen := 1;

              if SampleFormat = -1 then
                StreamIn[x].Data.SampleFormat := 2
              else
                StreamIn[x].Data.SampleFormat := SampleFormat;

              if StreamIn[x].Data.SampleFormat = 2 then
                StreamIn[x].Data.ratio := sizeof(int16)
              else
                StreamIn[x].Data.ratio := sizeof(int32);

              mpg123_info(StreamIn[x].Data.HandleSt, MPinfo);

              // problems with mpg123 
              // mpg123_id3(StreamIn[x].Data.HandleSt, mpid3v1, @mpid3v2);
              // mpg123_icy(StreamIn[x].Data.HandleSt, pointer(icytext));

              StreamIn[x].Data.samplerateroot :=  StreamIn[x].Data.samplerate ;
              StreamIn[x].Data.hdformat := MPinfo.layer;
              StreamIn[x].Data.frames := MPinfo.framesize;
              StreamIn[x].Data.Length := mpg123_length(StreamIn[x].Data.HandleSt);

              if StreamIn[x].Data.SampleFormat = 0 then
                mpg123_param(StreamIn[x].Data.HandleSt, StreamIn[x].Data.Channels,
                             MPG123_FORCE_FLOAT, 0);

              StreamIn[x].Data.Enabled := True;
  {$IF DEFINED(uos_debug) and DEFINED(unix)}
              writeln('===> mpg123_infos end => ok');
  {$endif}

            end;
        end;
        end else
        begin
         result := -1;
         StreamIn[x].httpget.Terminate;
         sleep(100);
         StreamIn[x].inpipe.destroy;
         StreamIn[x].outpipe.destroy;
        end; 
         
    end;
  {$endif}

  {$IF DEFINED(uos_debug) and DEFINED(unix)}
  WriteLn('Before result ' + inttostr(result));
  WriteLn('error ' + inttostr(err));
  WriteLn('StreamIn[x].Data.LibOpen ' + inttostr(StreamIn[x].Data.LibOpen));
  WriteLn('Before Length(StreamIn) ' + inttostr(Length(StreamIn)));
  {$endif}
  sleep(10);
  if StreamIn[x].Data.LibOpen = -1 then
    begin
      if err <> -133 then
        begin
          StreamIn[Length(StreamIn) - 1].Destroy;
          setlength(StreamIn, Length(StreamIn) - 1);
  {$IF DEFINED(uos_debug) and DEFINED(unix)}
          WriteLn('After Length(StreamIn) ' + inttostr(Length(StreamIn)));
          WriteLn('Result: ' + inttostr(result));
  {$endif}
        end;

      result := -1
    end
  else
    begin
      StreamIn[x].Data.Enabled := True;
      result := x ;
    end;
end;
  {$ENDIF}

function Tuos_Player.AddFromMemoryBuffer(Var MemoryBuffer: TDArFloat; Var Bufferinfos:
                                         Tuos_bufferinfos;
                                         OutputIndex: cint32; FramesCount: cint32): cint32;
// Add a input from memory buffer with custom parameters
// MemoryBuffer : the buffer
// Bufferinfos : infos of the buffer

// OutputIndex : Output index of used output// -1: all output, -2: no output, other cint32 refer to a existing OutputIndex  (if multi-output then OutName = name of each output separeted by ';')// Channels : delault : -1 (2:stereo) (0: no channels, 1:mono, 2:stereo, ...)// SampleRate : delault : -1 (44100)
// FramesCount : default : -1 (65536 div Channels)
//  result :  Input Index in array  -1 = error
// example : InputIndex1 := AddFromMemoryBuffer(mybuffer, buffinfos,-1,1024);

var 
  x : cint32;
  {$IF DEFINED(uos_debug) and DEFINED(unix)}
  st: string;
  i : cint32;
  {$endif}
begin

  result := -1 ;

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
  WriteLn('AddFromMemoryBuffer Before all.');
  writeln('length(MemoryBuffer) =' +inttostr(length(MemoryBuffer)));
  st := '';
  for i := 0 to length(MemoryBuffer) -1 do
    st := st + '|' + inttostr(i) + '=' + floattostr(MemoryBuffer[i]);
  WriteLn(st);
 {$endif}

  //  writeln('length(MemoryBuffer) =' +inttostr(length(MemoryBuffer)));

  SetLength(StreamIn, Length(StreamIn) + 1);
  StreamIn[Length(StreamIn) - 1] := Tuos_InStream.Create;
  x := Length(StreamIn) - 1;

  StreamIn[x].Data.Enabled := false;
  StreamIn[x].Data.levelEnable := 0;
  StreamIn[x].Data.typeput := 4;
  StreamIn[x].Data.positionEnable := 0;
  StreamIn[x].Data.levelArrayEnable := 0;


{  
  setlength(StreamIn[x].Data.memorybuffer, length(MemoryBuffer));
  
   writeln('length(Data.memorybuffer) =' +inttostr(length(StreamIn[x].Data.memorybuffer)));
   
  for i := 0 to length(MemoryBuffer) -1 do
  StreamIn[x].Data.memorybuffer[i] := MemoryBuffer[i];
 }

  StreamIn[x].Data.memorybuffer := MemoryBuffer;

  sleep(50);
  //TODO: it is necessary?

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
  WriteLn('AddFromMemoryBuffer Before all.');
  writeln('length(MemoryBuffer) =' +inttostr(length(MemoryBuffer)));
  st := '';
  for i := 0 to length(MemoryBuffer) -1 do
    st := st + '|' + inttostr(i) + '=' + floattostr(StreamIn[x].Data.memorybuffer[i]);
  WriteLn(st);
 {$endif}

  StreamIn[x].Data.Length := length(MemoryBuffer);
  StreamIn[x].Data.LibOpen := 0;

  StreamIn[x].Data.Channels := Bufferinfos.Channels;

  if FramesCount = -1 then
    StreamIn[x].Data.Wantframes :=  4096
  else
    StreamIn[x].Data.Wantframes := FramesCount;

  StreamIn[x].Data.Samplerate := bufferinfos.SampleRate;
  StreamIn[x].Data.SampleRateRoot := Bufferinfos.Samplerate;
  StreamIn[x].Data.SampleFormat := Bufferinfos.SampleFormat;
  StreamIn[x].Data.Filename := BufferInfos.Filename;
  StreamIn[x].Data.Title := BufferInfos.Title;
  StreamIn[x].Data.Copyright := BufferInfos.Copyright;
  StreamIn[x].Data.Software := BufferInfos.Software;
  StreamIn[x].Data.Artist := BufferInfos.Artist;
  StreamIn[x].Data.Comment := BufferInfos.Comment;
  StreamIn[x].Data.Date := BufferInfos.Date;
  StreamIn[x].Data.Tag := BufferInfos.Tag;
  StreamIn[x].Data.track := BufferInfos.track;
  StreamIn[x].Data.Album := BufferInfos.Album;
  StreamIn[x].Data.Genre := BufferInfos.Genre;
  StreamIn[x].Data.HDFormat := BufferInfos.HDFormat;
  StreamIn[x].Data.Sections := BufferInfos.Sections;
  StreamIn[x].Data.Encoding := BufferInfos.Encoding;
  StreamIn[x].Data.bitrate := BufferInfos.bitrate;
  //StreamIn[x].Data.Length := BufferInfos.Length;
  StreamIn[x].Data.LibOpen := 0;
  StreamIn[x].Data.ratio := StreamIn[x].Data.Channels;

  StreamIn[x].Data.posmem := 0;
  StreamIn[x].Data.Output := OutputIndex;
  StreamIn[x].Data.Status := 1;
  StreamIn[x].Data.Position := 0;
  StreamIn[x].Data.OutFrames := 0;
  StreamIn[x].Data.Poseek := -1;
  StreamIn[x].Data.seekable := true;
  StreamIn[x].LoopProc := Nil;
  setlength(StreamIn[x].Data.buffer,StreamIn[x].Data.wantframes*StreamIn[x].Data.Channels);
  StreamIn[x].Data.Enabled := True;
  result := x;
end;

function Tuos_Player.AddFromFileIntoMemory(Filename: Pchar; OutputIndex: cint32;
                                           SampleFormat: cint32 ; FramesCount: cint32; numbuf : cint
): cint32;
// Add a input from audio file and store it into memory with custom parameters
// FileName : filename of audio file

// OutputIndex : Output index of used output// -1: all output, -2: no output, other cint32 refer to a existing OutputIndex  (if multi-output then OutName = name of each output separeted by ';')
// SampleFormat : default : -1 (2:Int16) (0: Float32, 1:Int32, 2:Int16)
// FramesCount : default : -1 (4096)
//  result :  Input Index in array  -1 = error
// example : InputIndex1 := AddFromFileIntoMemory(edit5.Text,-1,0,-1);
var 
  x, i : cint32;
  bufferinfos: Tuos_bufferinfos;

  {$IF DEFINED(uos_debug) and DEFINED(unix)}
  st: string;
  {$endif}

begin
  result := -1 ;

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
  WriteLn('AddFromFileIntoMemory Before all.');
 {$endif}

  if fileexists(filename) then
    begin

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
      WriteLn('Before setlength.');
 {$endif}

      SetLength(StreamIn, Length(StreamIn) + 1);
      StreamIn[Length(StreamIn) - 1] := Tuos_InStream.Create;
      x := Length(StreamIn) - 1;
      StreamIn[x].Data.Enabled := false;
      StreamIn[x].Data.levelEnable := 0;
      StreamIn[x].Data.typeput := 4;
      StreamIn[x].Data.lastbuf := 0;
      StreamIn[x].Data.positionEnable := 0;
      StreamIn[x].Data.levelArrayEnable := 0;
      // StreamIn[x].Data.wantframes := FramesCount;

  {$IF DEFINED(uos_debug) and DEFINED(unix)}
      writeln('Before Filetobuffer');
  {$endif}

      for i := 0 to length(tempoutmemory) -1 do
        tempoutmemory[i] := 0.0;

      setlength(tempoutmemory, 0);

      Filetobuffer(Filename, -1, SampleFormat, FramesCount, tempoutmemory, bufferinfos, -1, numbuf);
      sleep(50);

      setlength(StreamIn[x].Data.memorybuffer, length(tempoutmemory));
      for i := 0 to length(tempoutmemory) -1 do
        StreamIn[x].Data.memorybuffer[i] := tempoutmemory [i];

  {$IF DEFINED(uos_debug) and DEFINED(unix)}
      writeln('After Filetobuffer');
      writeln('length(tempoutmemory) =' +inttostr(length(tempoutmemory)));
      st := '';
      for i := 0 to length(tempoutmemory) -1 do
        st := st + '|' + inttostr(i) + '=' + floattostr(tempoutmemory[i]);
      WriteLn('OUTPUT DATA into portaudio------------------------------');
      WriteLn(st);
  {$endif}

      StreamIn[x].Data.Length := tempLength;
      StreamIn[x].Data.Samplerate := tempSamplerate;
      StreamIn[x].Data.SampleFormat := tempSampleFormat;
      StreamIn[x].Data.LibOpen := tempLibOpen;
      StreamIn[x].Data.Channels := tempchan;

      if FramesCount = -1 then  StreamIn[x].Data.Wantframes := 65536 Div  StreamIn[x].Data.Channels
      else
        StreamIn[x].Data.Wantframes := FramesCount ;

      StreamIn[x].Data.ratio := tempratio;
      StreamIn[x].Data.posmem := 0;
      StreamIn[x].Data.Output := OutputIndex;
      StreamIn[x].Data.Status := 1;
      StreamIn[x].Data.Position := 0;
      StreamIn[x].Data.OutFrames := 0;
      StreamIn[x].Data.Poseek := -1;
      StreamIn[x].Data.seekable := true;
      StreamIn[x].LoopProc := Nil;
      StreamIn[x].Data.Samplerate := bufferinfos.SampleRate;
      StreamIn[x].Data.SampleRateRoot := Bufferinfos.Samplerate;
      StreamIn[x].Data.SampleFormat := Bufferinfos.SampleFormat;
      StreamIn[x].Data.Filename := BufferInfos.Filename;
      StreamIn[x].Data.Title := BufferInfos.Title;
      StreamIn[x].Data.Copyright := BufferInfos.Copyright;
      StreamIn[x].Data.Software := BufferInfos.Software;
      StreamIn[x].Data.Artist := BufferInfos.Artist;
      StreamIn[x].Data.Comment := BufferInfos.Comment;
      StreamIn[x].Data.Date := BufferInfos.Date;
      StreamIn[x].Data.Tag := BufferInfos.Tag;
      StreamIn[x].Data.Album := BufferInfos.Album;
      StreamIn[x].Data.Genre := BufferInfos.Genre;
      StreamIn[x].Data.track := BufferInfos.track;
      StreamIn[x].Data.HDFormat := BufferInfos.HDFormat;
      StreamIn[x].Data.Sections := BufferInfos.Sections;
      StreamIn[x].Data.Encoding := BufferInfos.Encoding;
      StreamIn[x].Data.bitrate := BufferInfos.bitrate;
      StreamIn[x].Data.Length := BufferInfos.Length;
      StreamIn[x].Data.LibOpen := 0;
      StreamIn[x].Data.Ratio := 2 ;

      setlength(StreamIn[x].Data.buffer,StreamIn[x].Data.wantframes*StreamIn[x].Data.Channels);
      StreamIn[x].Data.Enabled := True;
      result := x;
    end
  else  result := -2;

end;

{$IF DEFINED(sndfile)}
function m_get_filelen(pms: PMemoryStream): tuos_count_t;
cdecl;
begin
  Result := pms^.Size;
end;

function m_seek(offset: tuos_count_t; whence: cint32; pms: PMemoryStream): tuos_count_t;
cdecl;
const 
  SEEK_SET = 0;
  SEEK_CUR = 1;
  SEEK_END = 2;
begin
  Result := 0 ;
  case whence of 
    SEEK_SET: Result := pms^.Seek(offset, soFromBeginning);
    SEEK_CUR: Result := pms^.Seek(offset, soFromCurrent);
    SEEK_END: Result := pms^.Seek(offset, soFromEnd);
  end;

end;

function m_read(Const buf: Pointer; count: Tuos_count_t; pms: PMemoryStream): Tuos_count_t;
cdecl;

begin
  Result := pms^.Read(buf^,count);
end;

function m_write(Const buf: Pointer; count: Tuos_count_t; pms: PMemoryStream): Tuos_count_t;
cdecl;
begin
  Result := pms^.Write(buf^,count);
end;

function m_tell(pms: PMemoryStream): Tuos_count_t;
cdecl;
begin
  Result := pms^.Position;
end;
{$endif}

function Tuos_Player.AddIntoMemoryStream(Var MemoryStream: TMemoryStream; SampleRate: CDouble;
                                         SampleFormat: LongInt ; Channels: LongInt; FramesCount:
                                         LongInt; AudioFormat: cint32): LongInt;
// Add a Output into TMemoryStream
// MemoryStream : the TMemoryStream to use to store memory.
// SampleRate : delault : -1 (44100)
// SampleFormat : default : -1 (2:Int16) ( 1:Int32, 2:Int16)
// Channels : delault : -1 (2:stereo) (0: no channels, 1:mono, 2:stereo, ...)
// FramesCount : default : -1 (= 4096)
// AudioFormat : default : -1 (wav) (0:wav, 1:ogg);

var 
  x, ch, sr, sf, fr: integer;
  {$IF DEFINED(sndfile)}
  sfInfo: TSF_INFO;
  sfVirtual: TSF_VIRTUAL;
  {$endif}

begin
  result := -1 ;
  x := 0;
  SetLength(StreamOut, Length(StreamOut) + 1);
  StreamOut[Length(StreamOut) - 1] := Tuos_OutStream.Create();
  x := Length(StreamOut) - 1;
  StreamOut[x].Data.Enabled := false;

  if channels = -1 then ch := 2
  else ch := channels;
  StreamOut[x].Data.channels := ch;
  if SampleFormat = -1 then sf := 2
  else sf := SampleFormat;
  StreamOut[x].Data.SampleFormat := sf;
  if FramesCount = -1 then fr := 4096
  else fr := FramesCount;
  StreamOut[x].Data.Wantframes := fr ;
  if SampleRate = -1 then sr := 44100
  else sr := roundmath(SampleRate);
  StreamOut[x].Data.SampleRate := sr ;

  SetLength(StreamOut[x].Data.Buffer, StreamOut[x].Data.Wantframes*StreamOut[x].Data.Channels);

  if MemoryStream = nil then
    MemoryStream := Tmemorystream.create;

  Streamout[x].MemorySteamOut := MemoryStream;

  Streamout[x].Data.posmem := 0;

  StreamOut[x].Data.TypePut := 5;

  {$IF DEFINED(sndfile)}
  with sfVirtual do
    begin
      sf_vio_get_filelen  := @m_get_filelen;
      seek  := @m_seek;
      read  := @m_read;
      write := @m_write;
      tell  := @m_tell;
    end;

  if (AudioFormat = 0) then
    sfInfo.format := SF_FORMAT_WAV Or SF_FORMAT_PCM_16;
  if (AudioFormat = 1) then
    sfInfo.format := SF_FORMAT_OGG Or SF_FORMAT_VORBIS;

  sfInfo.channels := StreamOut[x].Data.Channels;
  sfInfo.frames :=  streamOut[x].Data.Wantframes;
  SFinfo.samplerate := roundmath(StreamOut[x].Data.SampleRate);
  SFinfo.seekable := 0;
  StreamOut[x].Data.HandleSt := sf_open_virtual(@sfVirtual, SFM_WRITE, @sfInfo,
                                @StreamOut[x].MemorySteamOut);
   {$endif}
  result := x;
  StreamOut[x].Data.Enabled := True;
end;

function Tuos_Player.AddFromMemoryStreamDec(Var MemoryStream: TMemoryStream; Var Bufferinfos:
                                            Tuos_bufferinfos;
                                            OutputIndex: cint32; FramesCount: cint32): cint32;
// MemoryStream : Memory-stream of decoded audio (like created by AddIntoMemoryStream)
// Bufferinfos : infos of the Memory-stream

// OutputIndex : Output index of used output// -1: all output, -2: no output, other cint32 refer to a existing OutputIndex  (if multi-output then OutName = name of each output separeted by ';')
// FramesCount : default : -1 (4096)
//  result :  Input Index in array  -1 = error
var 
  x : integer;
begin
  result := -1 ;

   {$IF DEFINED(uos_debug) and DEFINED(unix)}
  WriteLn('Before all.');
   {$endif}

  if assigned(MemoryStream) then
    begin
      x := 0;
      MemoryStream.Position := 0;

      {$IF DEFINED(uos_debug) and DEFINED(unix)}
      WriteLn('Before setlength.');
      {$endif}

      SetLength(StreamIn, Length(StreamIn) + 1);
      StreamIn[Length(StreamIn) - 1] := Tuos_InStream.Create;
      x := Length(StreamIn) - 1;

      StreamIn[x].Data.LibOpen := -1;
      StreamIn[x].Data.levelEnable := 0;
      StreamIn[x].Data.Output := OutputIndex;
      StreamIn[x].Data.Status := 1;
      StreamIn[x].Data.Position := 0;
      StreamIn[x].Data.lastbuf := -1;
      StreamIn[x].Data.OutFrames := 0;
      StreamIn[x].Data.Poseek := -1;
      StreamIn[x].Data.TypePut := 6;
      StreamIn[x].Data.seekable := True;
      StreamIn[x].LoopProc := Nil;

      StreamIn[x].Data.Channels := Bufferinfos.Channels;

      if FramesCount = -1 then
        StreamIn[x].Data.Wantframes :=  4096
      else
        StreamIn[x].Data.Wantframes := FramesCount;

      StreamIn[x].Data.Samplerate := bufferinfos.SampleRate;
      StreamIn[x].Data.SampleRateRoot := Bufferinfos.Samplerate;
      StreamIn[x].Data.SampleFormat := Bufferinfos.SampleFormat;
      StreamIn[x].Data.Filename := BufferInfos.Filename;
      StreamIn[x].Data.Title := BufferInfos.Title;
      StreamIn[x].Data.Copyright := BufferInfos.Copyright;
      StreamIn[x].Data.Software := BufferInfos.Software;
      StreamIn[x].Data.Artist := BufferInfos.Artist;
      StreamIn[x].Data.Comment := BufferInfos.Comment;
      StreamIn[x].Data.Date := BufferInfos.Date;
      StreamIn[x].Data.Tag := BufferInfos.Tag;
      StreamIn[x].Data.Album := BufferInfos.Album;
      StreamIn[x].Data.Track := BufferInfos.Track;
      StreamIn[x].Data.Genre := BufferInfos.Genre;
      StreamIn[x].Data.HDFormat := BufferInfos.HDFormat;
      StreamIn[x].Data.Sections := BufferInfos.Sections;
      StreamIn[x].Data.Encoding := BufferInfos.Encoding;
      StreamIn[x].Data.bitrate := BufferInfos.bitrate;
      //StreamIn[x].Data.Length := BufferInfos.Length;
      StreamIn[x].Data.LibOpen := -1;
      StreamIn[x].Data.ratio := StreamIn[x].Data.Channels;

      StreamIn[x].Data.posmem := 0;
      StreamIn[x].Data.Output := OutputIndex;
      StreamIn[x].Data.Status := 1;
      StreamIn[x].Data.Position := 0;
      StreamIn[x].Data.OutFrames := 0;
      StreamIn[x].Data.Poseek := -1;
      StreamIn[x].Data.seekable := false;
      StreamIn[x].LoopProc := Nil;
      streamIn[x].Data.ratio := StreamIn[x].Data.Channels;
      StreamIn[x].Data.positionEnable := 0;
      StreamIn[x].Data.levelArrayEnable := 0;
      StreamIn[x].MemoryStreamDec := MemoryStream;


      StreamIn[x].MemoryStreamDec.Position := 0;
      SetLength(StreamIn[x].Data.Buffer, StreamIn[x].Data.Wantframes*StreamIn[x].Data.Channels);

      StreamIn[x].Data.Enabled := true;
      result := x;
      {$IF DEFINED(uos_debug) and DEFINED(unix)}
      writeln('length(StreamIn[x].MemoryStreamDec) = '+inttostr(StreamIn[x].MemoryStreamDec.size)) ;
      writeln('length(MemoryStream) = '+inttostr(MemoryStream.size)) ;
      WriteLn('Length(StreamIn) = '+ inttostr(x));
      {$endif}
    end
  else result := -1;

end;

function Tuos_Player.AddFromMemoryStream(Var MemoryStream: TMemoryStream;
                                         TypeAudio: cint32; OutputIndex: cint32; SampleFormat:
                                         cint32 ; FramesCount: cint32): cint32;
// MemoryStream : Memory stream of encoded audio file.

// TypeAudio : default : -1 --> 0 (0: flac, ogg, wav; 1: mp3; 2:opus ; 3:decoded Tmemory-stream; 5:mod, it, xm, s3m)

// OutputIndex : Output index of used output// -1: all output, -2: no output, other cint32 refer to a existing OutputIndex  (if multi-output then OutName = name of each output separeted by ';')
// SampleFormat : default : -1 (2:Int16) (0: Float32, 1:Int32, 2:Int16)
// FramesCount : default : -1 (4096)
//  result :  Input Index in array  -1 = error
// example : InputIndex1 := AddFromMemoryStream(mymemorystream,-1,-1,0,1024);

var 
  x, x2, err, len, len2, i : cint32;
  PipeBufferSize, totsamples : integer;
  buffadd : tbytes;
  samprat : cint32;

      {$IF DEFINED(sndfile)}
  sfInfo: TSF_INFO;
  sfVirtual: TSF_VIRTUAL;
      {$endif}

     {$IF DEFINED(opus)}
  s: UTF8String;
  j: Integer;
  OpusTag: POpusTags;
  LComment: PPAnsiChar;
  LcommentLength: PInteger;
      {$endif}

      {$IF DEFINED(mpg123)}
  mpinfo: Tmpg123_frameinfo;
  // problems with mpg123
  mpid3v1: PPmpg123_id3v1;
  refmpid3v1: Tmpg123_id3v1;
  mpid3v2: Tmpg123_id3v2;
      {$endif}

  {$IF DEFINED(xmp)}
  mi: xmp_module_info;
  {$endif}

begin
  result := -1 ;

   {$IF DEFINED(uos_debug) and DEFINED(unix)}
  WriteLn('Before all.');
   {$endif}

  if assigned(MemoryStream) then
    begin
      x := 0;
      MemoryStream.Position := 0;

      {$IF DEFINED(uos_debug) and DEFINED(unix)}
      WriteLn('Before setlength.');
      {$endif}

      SetLength(StreamIn, Length(StreamIn) + 1);
      StreamIn[Length(StreamIn) - 1] := Tuos_InStream.Create;
      x := Length(StreamIn) - 1;
      err := -1;
      StreamIn[x].Data.Enabled := false;
      StreamIn[x].Data.LibOpen := -1;
      StreamIn[x].Data.lastbuf := -1;
      StreamIn[x].Data.levelEnable := 0;
      StreamIn[x].Data.positionEnable := 0;
      StreamIn[x].Data.levelArrayEnable := 0;
      StreamIn[x].data.MemoryStream := MemoryStream;
      StreamIn[x].data.MemoryStream.Position := 0;

      {$IF DEFINED(uos_debug) and DEFINED(unix)}
      WriteLn('Length(StreamIn) = '+ inttostr(x));
      {$endif}

      {$IF DEFINED(sndfile)}
      if ((TypeAudio = -1) or (TypeAudio = 0)) and (uosLoadResult.SFloadERROR = 0) then
        begin
          with sfVirtual do
            begin
              sf_vio_get_filelen  := @m_get_filelen;
              seek  := @m_seek;
              read  := @m_read;
              write := @m_write;
              tell  := @m_tell;
            end;

          try
            Streamin [x] .Data.HandleSt := sf_open_virtual(@sfVirtual, SFM_READ, @sfInfo, @StreamIn[
                                           x].Data.MemoryStream);
          except
            StreamIn[x].Data.HandleSt := Nil;
        end;
         (* try to open the file *)
      if StreamIn[x].Data.HandleSt = nil then
        begin
          StreamIn[x].Data.LibOpen := -1;
            {$IF DEFINED(uos_debug) and DEFINED(unix)}
          WriteLn('sf_open_virtual NOT OK');
            {$endif}
        end
      else
        begin
            {$IF DEFINED(uos_debug) and DEFINED(unix)}
          WriteLn('sf_open_virtual OK');
            {$endif}

          if SampleFormat = -1 then
            StreamIn[x].Data.SampleFormat := 2
          else StreamIn[x].Data.SampleFormat := SampleFormat;

          StreamIn[x].Data.LibOpen := 0;
          StreamIn[x].Data.channels := SFinfo.channels;
          if FramesCount = -1 then
            StreamIn[x].Data.Wantframes := 65536 Div StreamIn[x].Data.Channels
          else StreamIn[x].Data.Wantframes := FramesCount ;

          SetLength(StreamIn[x].Data.Buffer, StreamIn[x].Data.Wantframes*StreamIn[x].Data.Channels);

          StreamIn[x].Data.hdformat := SFinfo.format;
          StreamIn[x].Data.frames := SFinfo.frames;
          StreamIn[x].Data.samplerate := SFinfo.samplerate;
          StreamIn[x].Data.samplerateroot := SFinfo.samplerate;
          StreamIn[x].Data.sections := SFinfo.sections;
          StreamIn[x].Data.copyright := sf_get_string(StreamIn[x].Data.HandleSt, SF_STR_COPYRIGHT);
          StreamIn[x].Data.software := sf_get_string(StreamIn[x].Data.HandleSt, SF_STR_SOFTWARE);
          StreamIn[x].Data.comment := sf_get_string(StreamIn[x].Data.HandleSt, SF_STR_COMMENT);
          StreamIn[x].Data.artist := sf_get_string(StreamIn[x].Data.HandleSt, SF_STR_ARTIST);
          StreamIn[x].Data.title := sf_get_string(StreamIn[x].Data.HandleSt, SF_STR_TITLE);
          StreamIn[x].Data.date := sf_get_string(StreamIn[x].Data.HandleSt, SF_STR_DATE);
          StreamIn[x].Data.track := sf_get_string(StreamIn[x].Data.HandleSt, SF_STR_TRACKNUMBER);
          StreamIn[x].Data.genre := sf_get_string(StreamIn[x].Data.HandleSt, SF_STR_GENRE);
          StreamIn[x].Data.album := sf_get_string(StreamIn[x].Data.HandleSt, SF_STR_ALBUM);

          StreamIn[x].Data.Length := sfInfo.frames;
          err := 0;
            {$IF DEFINED(uos_debug) and DEFINED(unix)}
          WriteLn('sf_open END OK');
            {$endif}
        end;
    end;
      {$endif}

      {$IF DEFINED(xmp)}
  if ((StreamIn[x].Data.LibOpen = -1)) then
    if ((TypeAudio = 5)) and (uosLoadResult.XMloadERROR = 0) then
      begin
        StreamIn[x].Data.HandleSt := xmp_create_context();
        {$IF DEFINED(uos_debug) and DEFINED(unix)}
        if StreamIn[x].Data.HandleSt = nil then  WriteLn(' xmp_create_context() NOT OK')
        else   WriteLn('xmp_create_context() OK');
        {$endif}


        if xmp_load_module_from_memory(StreamIn[x].Data.HandleSt,
           StreamIn[x].Data.MemoryStream.Memory,
           StreamIn[x].Data.MemoryStream.size) <> 0 then
          begin
            StreamIn[x].Data.LibOpen := -1;
            {$IF DEFINED(uos_debug) and DEFINED(unix)}
            WriteLn('xmp_load_module_from_memory NOT OK');
            {$endif}
          end
        else
          begin
            {$IF DEFINED(uos_debug) and DEFINED(unix)}
            WriteLn('xmp_load_module_from_memory OK');
            {$endif}

            xmp_start_player(StreamIn[x].Data.HandleSt, 44100, 0);
            xmp_get_module_info(StreamIn[x].Data.HandleSt, mi);
            // xmp_get_frame_info(StreamIn[x].Data.HandleSt , fi);

            StreamIn[x].Data.LibOpen := 5;
            StreamIn[x].Data.channels := 2;
            // todo

            if SampleFormat = -1 then
              StreamIn[x].Data.SampleFormat := 2
            else
              StreamIn[x].Data.SampleFormat := SampleFormat;
            // Need conversion because xmp is always 16 bit     

            if FramesCount = -1 then  StreamIn[x].Data.Wantframes := 65536 Div StreamIn[x].Data.
                                                                     Channels
            else
              StreamIn[x].Data.Wantframes := FramesCount ;

            SetLength(StreamIn[x].Data.Buffer, StreamIn[x].Data.Wantframes*StreamIn[x].Data.
                      Channels);

            x2 := 0 ;
            while x2 < Length(Streamin[x].Data.Buffer) do
              begin
                Streamin[x].Data.Buffer[x2] := 0.0 ;
                inc(x2);
              end;

            //  StreamIn[x].Data.hdformat := SFinfo.format;
            //  StreamIn[x].Data.frames := SFinfo.frames;
            StreamIn[x].Data.samplerate := 44100;
            StreamIn[x].Data.samplerateroot := 44100;
            //  StreamIn[x].Data.sections := SFinfo.sections;
            StreamIn[x].Data.title := String(mi.module^.Name);

            StreamIn[x].Data.copyright := '';
            StreamIn[x].Data.software := '';

            StreamIn[x].Data.comment := String(mi.module^.typ);
            StreamIn[x].Data.artist := String(mi.comment);
            StreamIn[x].Data.date := '';

            StreamIn[x].Data.track := '';
            StreamIn[x].Data.genre := '';
            StreamIn[x].Data.album := '';

            StreamIn[x].Data.Length := 0;

            err := 0;
            {$IF DEFINED(uos_debug) and DEFINED(unix)}
            WriteLn('XMP_open END OK');
            {$endif}

          end;
      end;
  {$endif}

      {$IF DEFINED(mpg123)}
  // mpg123
  if (((TypeAudio = 1) and (StreamIn[x].Data.LibOpen = -1)
     and (uosLoadResult.MPloadERROR = 0))) then
    begin
      Err := -1;
      StreamIn[x].Data.HandleSt := mpg123_new(Nil, Err);

      if Err = 0 then
        begin
            {$IF DEFINED(uos_debug) and DEFINED(unix)}
          WriteLn('mpg123_new OK');
            {$endif}

          if SampleFormat = -1 then
            StreamIn[x].Data.SampleFormat := 2
          else StreamIn[x].Data.SampleFormat := 
                                                SampleFormat
          ;
          mpg123_format_none(StreamIn[x].Data.HandleSt);

          case StreamIn[x].Data.SampleFormat of 
            0: mpg123_format(StreamIn[x].Data.HandleSt,
                             DefRate, Stereo,
                             MPG123_ENC_FLOAT_32);
            1: mpg123_format(StreamIn[x].Data.HandleSt,
                             DefRate, Stereo,
                             MPG123_ENC_SIGNED_32);
            2: mpg123_format(StreamIn[x].Data.HandleSt,
                             DefRate, Stereo,
                             MPG123_ENC_SIGNED_16);
          end;

          err := mpg123_replace_reader_handle(StreamIn[x].
                 Data.HandleSt, @mpg_read_stream, @
                 mpg_seek_stream, Nil);

            {$IF DEFINED(uos_debug) and DEFINED(unix)}
          if err = 0 then
            writeln(
                    '===> mpg123_replace_reader_handle => ok.')
          else writeln(
                       '===> mpg123_replace_reader_handle => NOT OK.');
            {$endif}

          Err :=  mpg123_open_handle(StreamIn[x].Data.
                 HandleSt, pointer(StreamIn[x].Data.
                 MemoryStream));

            {$IF DEFINED(uos_debug) and DEFINED(unix)}
          if err = 0 then
            writeln('===> mpg123_open_handle => ok.')
          else
            writeln('===> mpg123_open_handle => NOT ok.');
            {$endif}

          sleep(10);
        end
      else
        begin
          StreamIn[x].Data.LibOpen := -1;
        end;

      samprat := roundmath(StreamIn[x].Data.samplerate);

      if Err = 0 then Err := mpg123_getformat(StreamIn[x].
                             Data.HandleSt,
                             samprat,
                             StreamIn[x].Data.channels,
                             StreamIn[x].Data.encoding);

         {$IF DEFINED(uos_debug) and DEFINED(unix)}
      if err = 0 then
        writeln('===> mpg123_getformat => ok.')
      else writeln('===> mpg123_getformat => NOT ok.') ;
         {$endif}

      if Err = 0 then
        begin
          mpg123_close(StreamIn[x].Data.HandleSt);
          mpg123_delete(StreamIn[x].Data.HandleSt);

          // Close handle and reload with forced resolution
          StreamIn[x].Data.HandleSt := mpg123_new(Nil, Err
                                       );

            {$IF DEFINED(uos_debug) and DEFINED(unix)}
          if err = 0 then
            writeln('===> mpg123_open_handle => ok.')
          else writeln(
                       '===> mpg123_open_handle => NOT ok.') ;
            {$endif}
          StreamIn[x].Data.HandleSt := Nil;
          StreamIn[x].Data.HandleSt := mpg123_new(Nil, Err);

          mpg123_format_none(StreamIn[x].Data.HandleSt);

          samprat := roundmath(StreamIn[x].Data.samplerate);


          case StreamIn[x].Data.SampleFormat of 
            0: mpg123_format(StreamIn[x].Data.HandleSt,
                             samprat,
                             StreamIn[x].Data.channels,
                             StreamIn[x].Data.encoding);
            1: mpg123_format(StreamIn[x].Data.HandleSt,
                             samprat,
                             StreamIn[x].Data.channels,
                             StreamIn[x].Data.encoding);
            2: mpg123_format(StreamIn[x].Data.HandleSt,
                             samprat,
                             StreamIn[x].Data.channels,
                             StreamIn[x].Data.encoding);
          end;

          err := mpg123_replace_reader_handle(StreamIn[x].
                 Data.HandleSt, @mpg_read_stream, @mpg_seek_stream, Nil);

            {$IF DEFINED(uos_debug) and DEFINED(unix)}
          if err = 0 then
            writeln('===> mpg123_replace_reader_handle => ok.')
          else writeln('===> mpg123_replace_reader_handle => NOT OK.');
            {$endif}

          Err :=  mpg123_open_handle(StreamIn[x].Data.
                 HandleSt, pointer(StreamIn[x].Data.
                 MemoryStream));

          samprat := roundmath(StreamIn[x].Data.samplerate);

          mpg123_getformat(StreamIn[x].Data.HandleSt,
                           samprat,
                           StreamIn[x].Data.channels,
                           StreamIn[x].Data.encoding);

          if FramesCount = -1 then
            StreamIn[x].Data.Wantframes := 65536 Div
                                           StreamIn[x].
                                           Data.Channels
          else StreamIn[x].Data.Wantframes := FramesCount;

          SetLength(StreamIn[x].Data.Buffer, StreamIn[x].
                    Data.Wantframes*StreamIn[x].Data.
                    Channels);
          mpg123_info(StreamIn[x].Data.HandleSt, MPinfo);


          // problems with mpg123 library
          mpg123_id3(StreamIn[x].Data.HandleSt, @mpid3v1, @mpid3v2);
          // to do : add id2v2
          if (mpid3v1 <> nil) and  (mpid3v1^ <> nil)  then
            begin
              refmpid3v1 := mpid3v1^^;
              StreamIn[x].Data.title := trim(refmpid3v1.title);
              StreamIn[x].Data.artist := refmpid3v1.artist;
              StreamIn[x].Data.album := refmpid3v1.album;
              StreamIn[x].Data.date := refmpid3v1.year;
              StreamIn[x].Data.comment := refmpid3v1.comment;
              //StreamIn[x].Data.track := refmpid3v1.comment;
              StreamIn[x].Data.tag := refmpid3v1.tag;
              StreamIn[x].Data.genre := inttostr(refmpid3v1.genre);
            end;

          StreamIn[x].Data.samplerateroot :=  StreamIn[x].Data.samplerate ;
          StreamIn[x].Data.hdformat := MPinfo.layer;
          StreamIn[x].Data.frames := MPinfo.framesize;

          if StreamIn[x].Data.SampleFormat = 0 then
            mpg123_param(StreamIn[x].Data.HandleSt,
                         StreamIn[x].Data.Channels,
                         MPG123_FORCE_FLOAT, 0);

          StreamIn[x].Data.LibOpen := 1;
          StreamIn[x].Data.Length := mpg123_length(StreamIn[x].Data.HandleSt);

            {$IF DEFINED(uos_debug) and DEFINED(unix)}
          writeln('StreamIn[x].Data.Length = ' + inttostr(
                  mpg123_length(StreamIn[x].Data.HandleSt));
          writeln('StreamIn[x].Data.frames = ' + inttostr(
                  StreamIn[x].Data.frames));
          writeln('END StreamIn[x].Data.samplerate = ' +
                  inttostr(roundmath(StreamIn[x].Data.samplerate)));
          writeln('END StreamIn[x].Data.channels = ' +
                  inttostr(StreamIn[x].Data.channels));
            {$endif}
        end
      else
        begin
          StreamIn[x].Data.LibOpen := -1;
        end;
    end;
      {$endif}

      {$IF DEFINED(opus)}
  if ((TypeAudio = 2) and (StreamIn[x].Data.LibOpen = -1) and 
                          (uosLoadResult.OPloadERROR = 0))

    then
    begin
      Err := -1;

         {$IF DEFINED(uos_debug) and DEFINED(unix)}
      WriteLn('Before Opus');
         {$endif}

      StreamIn[x].Data.HandleSt := pchar('opus');

      if FramesCount= -1 then
        totsamples := 4096
      else totsamples := FramesCount;

      PipeBufferSize := StreamIn[x].Data.MemoryStream.size;

         {$IF DEFINED(uos_debug) and DEFINED(unix)}
      WriteLn('totsamples: ' + inttostr(totsamples));
      WriteLn('PipeBufferSize: ' + inttostr(PipeBufferSize));
         {$endif}

      len := 1 ;
      len2 := 0 ;

      setlength(buffadd, PipeBufferSize);
      setlength(StreamIn[x].data.BufferTMP, PipeBufferSize);

      while (len2 < PipeBufferSize) and (len > 0) do
        begin
          len := StreamIn[x].Data.MemoryStream.Read(buffadd[0],PipeBufferSize-len2);

          if len > 0 then
            for i := 0 to len -1 do
              StreamIn[x].data.BufferTMP[i+len2] := buffadd[i] ;
          len2 := len2 + len;
        end;

      // memory stream not needed anymore ---> converted into buffer
      freeandnil(StreamIn[x].Data.MemoryStream);

         {$IF DEFINED(uos_debug) and DEFINED(unix)}
      WriteLn('PipeBufferSize = ' + inttostr(PipeBufferSize));
      WriteLn('Data.MemoryStream.Read = ' + inttostr(len2));
      WriteLn('----------------------------------');
      //writeln(tencoding.utf8.getstring(StreamIn[x].data.BufferTMP));
         {$endif}

      StreamIn[x].Data.HandleSt := pchar('opusstream');

         {$IF DEFINED(uos_debug) and DEFINED(unix)}
      WriteLn('StreamIn[x].Data.HandleSt assisgned');
         {$endif}

      // Can not make work...


// StreamIn[x].Data.HandleOP := op_test_callbacks(StreamIn[x].data.MemoryStream, uos_callbacksms, StreamIn[x].data.BufferTMP[0], PipeBufferSize, err);

      // this is a memorystream converted into a buffer, it works...
      StreamIn[x].Data.HandleOP := op_test_memory(StreamIn[x].data.BufferTMP[0],PipeBufferSize, Err);

         {$IF DEFINED(uos_debug) and DEFINED(unix)}
      WriteLn('op_test_file error = '+ inttostr(Err));
         {$endif}

      if Err=0 then
        begin
          Err := op_test_open(StreamIn[x].Data.HandleOP);
          if (Err=0) and (op_link_count(StreamIn[x].Data.HandleOP)=1) then
            begin
              if SampleFormat = -1 then
                StreamIn[x].Data.SampleFormat := 2
              else StreamIn[x].Data.SampleFormat := SampleFormat;

              //tag
              OpusTag := op_tags(StreamIn[x].Data.HandleOP, Nil);

              if OpusTag<>nil then
                begin
                  if OpusTag^.comments>0 then
                    begin
                     {$IF DEFINED(uos_debug) and DEFINED(unix)}
                      WriteLn((Format('OpusTag.comments = %d', [OpusTag^.comments])));
                     {$endif}
                      LComment := OpusTag^.user_comments;
                      LcommentLength := OpusTag^.comment_lengths;
                      for j := 0 to OpusTag^.comments - 1 do
                        begin
                          SetLength(s, LcommentLength^);
                          move(Pointer(LComment^)^, Pointer(s)^, LcommentLength^);

                        {$IF DEFINED(uos_debug) and DEFINED(unix)}
                          // WriteLn(s);
                        {$endif}

                          if j = 1 then StreamIn[x].Data.title := s;
                          if j = 2 then StreamIn[x].Data.artist := s;
                          if j = 3 then StreamIn[x].Data.album := s;
                          if j = 4 then StreamIn[x].Data.date := s;
                          if j = 5 then StreamIn[x].Data.comment := s;
                          if j = 6 then StreamIn[x].Data.tag := s;

                          inc(LComment);
                          inc(LcommentLength);
                        end;
                    end;
                end;
            //  WriteLn((Format('op_bitrate = %d', [op_bitrate(StreamIn[x].Data.HandleOP, nil)])));

              StreamIn[x].Data.Length := op_pcm_total(StreamIn[x].Data.HandleOP, Nil);
              StreamIn[x].Data.channels := op_channel_count(StreamIn[x].Data.HandleOP, Nil);
              StreamIn[x].Data.bitrate := op_bitrate(StreamIn[x].Data.HandleOP, Nil);

              // opus use constant sample rate 48k
              StreamIn[x].Data.samplerate :=  48000 ;
              StreamIn[x].Data.samplerateroot :=  StreamIn[x].Data.samplerate ;
              StreamIn[x].Data.Seekable  := true;

              if FramesCount = -1 then
                StreamIn[x].Data.Wantframes := 4096 * StreamIn[x].Data.Channels
              else StreamIn[x].Data.Wantframes := FramesCount ;

              SetLength(StreamIn[x].Data.Buffer,
                        StreamIn[x].Data.Wantframes*StreamIn[x].Data.Channels);

              StreamIn[x].Data.LibOpen := 4;
            end
          else
            begin
              StreamIn[x].Data.LibOpen := -1;
            end;
        end;
    end;
      {$endif}

      {$IF DEFINED(neaac)}
  if (StreamIn[x].Data.LibOpen = -1) and (uosLoadResult.AAloadERROR = 0) then
    begin
      Err := -1;

      StreamIn[x].AACI := TAACInfo.Create();

         {$IF DEFINED(uos_debug) and DEFINED(unix)}
      WriteLn('TAACInfo.Create() = ok');
         {$endif}
         {
         Case SampleFormat of
            0 : StreamIn[x].AACI:= MP4OpenFile(FileName, FAAD_FMT_FLOAT);
            1 : StreamIn[x].AACI:= MP4OpenFile(FileName, FAAD_FMT_32BIT);
            2 : StreamIn[x].AACI:= MP4OpenFile(FileName, FAAD_FMT_16BIT);
         End;
         }
      if StreamIn[x].AACI <> nil then
        begin
            {$IF DEFINED(uos_debug) and DEFINED(unix)}
          WriteLn('MP4OpenFile() = ok');
            {$endif}

          case StreamIn[x].AACI.outputFormat of 
            FAAD_FMT_16BIT : StreamIn[x].Data.SampleFormat := 2;
            //FAAD_FMT_24BIT : ;
            FAAD_FMT_32BIT : StreamIn[x].Data.SampleFormat := 1;
            FAAD_FMT_FLOAT : StreamIn[x].Data.SampleFormat := 0;
            //FAAD_FMT_DOUBLE: ;
          end;

          // StreamIn[x].Data.filename  := FileName;

          StreamIn[x].Data.HandleSt  := StreamIn[x].AACI.hMP4;

          StreamIn[x].Data.samplerate  := StreamIn[x].AACI.SampleRate;
          StreamIn[x].Data.channels  := StreamIn[x].AACI.Channels;

          case StreamIn[x].AACI.outputFormat of 
            FAAD_FMT_16BIT : StreamIn[x].Data.encoding := MPG123_ENC_SIGNED_16;
            //FAAD_FMT_24BIT : ;
            FAAD_FMT_32BIT : StreamIn[x].Data.encoding := MPG123_ENC_SIGNED_32;
            FAAD_FMT_FLOAT : StreamIn[x].Data.encoding := MPG123_ENC_FLOAT_32;
            //FAAD_FMT_DOUBLE: ;
          end;

          if FramesCount = -1 then
            StreamIn[x].Data.Wantframes :=  65536 Div StreamIn[x].Data.Channels
          else StreamIn[x].Data.Wantframes := FramesCount ;

          SetLength(StreamIn[x].Data.Buffer, StreamIn[x].Data.Wantframes * StreamIn[x].Data.Channels
          );

          StreamIn[x].Data.title  := StreamIn[x].AACI.Title;
          StreamIn[x].Data.artist  := StreamIn[x].AACI.Artist;
          StreamIn[x].Data.album  := StreamIn[x].AACI.Album;
          StreamIn[x].Data.date  := StreamIn[x].AACI.Date;
          StreamIn[x].Data.comment  := StreamIn[x].AACI.Comment;
          StreamIn[x].Data.tag[0]  := #0;
          StreamIn[x].Data.tag[1]  := #0;
          StreamIn[x].Data.tag[2]  := #0;
          StreamIn[x].Data.genre  := StreamIn[x].AACI.Genre;
          StreamIn[x].Data.samplerateroot := StreamIn[x].AACI.SampleRate;
          StreamIn[x].Data.hdformat  := 0;
          StreamIn[x].Data.frames  := 0;
          StreamIn[x].Data.Length  := StreamIn[x].AACI.TotalSamples;

          StreamIn[x].Data.Seekable  := StreamIn[x].AACI.Size > 0;

          StreamIn[x].Data.LibOpen := 2 ;
          Err := 0;
        end
      else
        begin
            {$IF DEFINED(uos_debug) and DEFINED(unix)}
          WriteLn('MP4OpenFile() NOT ok');
            {$endif}
        end;

    end;
      {$endif}

      {$IF DEFINED(cdrom)}
  if (StreamIn[x].Data.LibOpen = -1) then
    begin
      Err := -1;
      StreamIn[x].pCD := Nil;

      case SampleFormat of 
        2 : StreamIn[x].pCD := CDROM_OpenFile(StreamIn[x].Data.FileName);
      end;

      if StreamIn[x].pCD <> nil then
        begin
          case StreamIn[x].pCD^.BitsPerSample of 
            16 : StreamIn[x].Data.SampleFormat := 2;
          end;

          StreamIn[x].Data.HandleSt  := @StreamIn[x].pCD;
          // Uos requires an assigned pointer....

          StreamIn[x].Data.samplerate  := StreamIn[x].pCD^.SampleRate;
          StreamIn[x].Data.channels  := StreamIn[x].pCD^.Channels;

          case StreamIn[x].pCD^.BitsPerSample of 
            16 : StreamIn[x].Data.encoding := MPG123_ENC_SIGNED_16;
          end;

          if FramesCount = -1 then
            StreamIn[x].Data.Wantframes :=  65536 Div StreamIn[x].Data.Channels
          else StreamIn[x].Data.Wantframes := FramesCount;

          SetLength(StreamIn[x].Data.Buffer, StreamIn[x].Data.Wantframes * StreamIn[x].Data.Channels
          );

          StreamIn[x].Data.title  := '';
          StreamIn[x].Data.artist  := '';
          StreamIn[x].Data.album  := '';
          StreamIn[x].Data.date  := '';
          StreamIn[x].Data.comment  := '';
          StreamIn[x].Data.tag[0]  := #0;
          StreamIn[x].Data.tag[1]  := #0;
          StreamIn[x].Data.tag[2]  := #0;
          StreamIn[x].Data.genre  := 0;
          StreamIn[x].Data.samplerateroot := StreamIn[x].pCD^.SampleRate;
          StreamIn[x].Data.hdformat  := 0;
          StreamIn[x].Data.frames  := 0;
          StreamIn[x].Data.Length  := StreamIn[x].pCD^.TotalSamples;

          StreamIn[x].Data.LibOpen := 3;
          Err := 0;
        end;
    end;
      {$endif}

  if err <> 0 then
    begin
      result := -1 ;
      StreamIn[Length(StreamIn) - 1].Destroy;
      setlength(StreamIn, Length(StreamIn) - 1);
    end
  else
    begin
         {$IF DEFINED(uos_debug) and DEFINED(unix)}
      WriteLn('addfrom memorystream OK');
         {$endif}
      Result := x;
      StreamIn[x].Data.Output := OutputIndex;
      StreamIn[x].Data.Status := 1;
      StreamIn[x].Data.Position := 0;
      StreamIn[x].Data.OutFrames := 0;
      StreamIn[x].Data.Poseek := -1;
      StreamIn[x].Data.TypePut := 0;
      StreamIn[x].Data.seekable := True;
      StreamIn[x].LoopProc := Nil;
      if SampleFormat = -1 then
        StreamIn[x].Data.SampleFormat := 2
      else StreamIn[x].Data.SampleFormat := SampleFormat;


      case StreamIn[x].Data.LibOpen of 
        -1: ;
            {$IF DEFINED(sndfile)}
        0:  StreamIn[x].Data.ratio := StreamIn[x].Data.Channels;
            {$endif}
            {$IF DEFINED(mpg123)}
        1:
           begin
             if StreamIn[x].Data.SampleFormat = 2 then
               StreamIn[x].Data.ratio := streamIn[x].Data.Channels
             else StreamIn[x].Data.ratio := 2 * streamIn[x].Data.Channels;

             if StreamIn[x].Data.SampleFormat = 0 then
               mpg123_param(StreamIn[x].Data.HandleSt, StreamIn[x].Data.Channels, MPG123_FORCE_FLOAT
                            , 0);
           end;
            {$endif}
            {$IF DEFINED(neaac)}
        2 : StreamIn[x].Data.ratio := streamIn[x].AACI.Channels;
            {$endif}
            {$IF DEFINED(cdrom)}
        3 : StreamIn[x].Data.ratio := streamIn[x].pCD^.Channels;
            {$endif}
            {$IF DEFINED(opus)}
        4 : StreamIn[x].Data.ratio :=  streamIn[x].Data.Channels;
            {$endif}
            {$IF DEFINED(xmp)}
        5 : StreamIn[x].Data.ratio :=  streamIn[x].Data.Channels;
            {$endif}
      end;

      StreamIn[x].Data.Enabled := True;
    end;
end;
end;

function Tuos_Player.AddFromFile(Filename: PChar; OutputIndex: cint32;
                                 SampleFormat: cint32 ; FramesCount: cint32 ): cint32;
// Add a Input from Audio file with Custom parameters
// FileName : filename of audio file

// OutputIndex : OutputIndex of existing Output// -1: all output, -2: no output, other cint32 : existing Output
// SampleFormat : -1 default : Int16 (0: Float32, 1:Int32, 2:Int16)
// FramesCount : default : -1 (65536 div channels)
// example : InputIndex := AddFromFile('/usr/home/test.ogg',-1,-1,-1);
var 
  x, x2, err: cint32;

  samprat : integer;

  {$IF DEFINED(sndfile)}
  sfInfo: TSF_INFO;
  {$endif}

  {$IF DEFINED(opus)}
  s: UTF8String;
  j: Integer;
  OpusTag: POpusTags;
  LComment: PPAnsiChar;
  LcommentLength: PInteger;
  {$endif}

  {$IF DEFINED(xmp)}
  mi: xmp_module_info;
  {$endif}

  {$IF DEFINED(mpg123)}
  mpinfo: Tmpg123_frameinfo;
  BufferTag: array[1..128] of char;
  F: file;
  // problems with mpg123  
  //  mpid3v2: Tmpg123_id3v2;
  {$endif}

begin
  result := -1 ;

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
  WriteLn('Before all.');
 {$endif}

  if fileexists(filename) then
    begin
      x := 0;

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
      WriteLn('Before setlength.');
 {$endif}

      SetLength(StreamIn, Length(StreamIn) + 1);
      StreamIn[Length(StreamIn) - 1] := Tuos_InStream.Create;
      x := Length(StreamIn) - 1;
      err := -1;
      StreamIn[x].Data.Enabled := false;
      StreamIn[x].Data.LibOpen := -1;
      StreamIn[x].Data.levelEnable := 0;
      StreamIn[x].Data.positionEnable := 0;
      StreamIn[x].Data.levelArrayEnable := 0;
      StreamIn[x].Data.lastbuf := 0;

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
      WriteLn('Length(StreamIn) = '+ inttostr(x));
 {$endif}

  {$IF DEFINED(sndfile)}
      if (uosLoadResult.SFloadERROR = 0) then
        begin

          StreamIn[x].Data.HandleSt := sf_open(FileName, SFM_READ, sfInfo);

  (* try to open the file *)
          if StreamIn[x].Data.HandleSt = nil then
            begin
              StreamIn[x].Data.LibOpen := -1;
              err := -1;
  {$IF DEFINED(uos_debug) and DEFINED(unix)}
              WriteLn('sf_open NOT OK');
  {$endif}
            end
          else
            begin
  {$IF DEFINED(uos_debug) and DEFINED(unix)}
              WriteLn('sf_open OK');
  {$endif}
              StreamIn[x].Data.LibOpen := 0;
              StreamIn[x].Data.filename := FileName;
              StreamIn[x].Data.channels := SFinfo.channels;

              if FramesCount = -1 then  StreamIn[x].Data.Wantframes := 65536 Div StreamIn[x].Data.
                                                                       Channels
              else
                StreamIn[x].Data.Wantframes := FramesCount ;

              SetLength(StreamIn[x].Data.Buffer, StreamIn[x].Data.Wantframes*StreamIn[x].Data.
                        Channels);
              x2 := 0 ;
              while x2 < Length(Streamin[x].Data.Buffer) do
                begin
                  Streamin[x].Data.Buffer[x2] := 0.0 ;
                  inc(x2);
                end;

              if SampleFormat = -1 then
                StreamIn[x].Data.SampleFormat := 2
              else
                StreamIn[x].Data.SampleFormat := SampleFormat;

              StreamIn[x].Data.hdformat := SFinfo.format;
              StreamIn[x].Data.frames := SFinfo.frames;
              StreamIn[x].Data.samplerate := SFinfo.samplerate;
              StreamIn[x].Data.samplerateroot := SFinfo.samplerate;
              StreamIn[x].Data.sections := SFinfo.sections;
              StreamIn[x].Data.title := 
                                        sf_get_string(StreamIn[x].Data.HandleSt, SF_STR_TITLE);
              StreamIn[x].Data.copyright := 
                                            sf_get_string(StreamIn[x].Data.HandleSt,
                                            SF_STR_COPYRIGHT);
              StreamIn[x].Data.software := 
                                           sf_get_string(StreamIn[x].Data.HandleSt, SF_STR_SOFTWARE)
              ;
              StreamIn[x].Data.comment := 
                                          sf_get_string(StreamIn[x].Data.HandleSt, SF_STR_COMMENT);
              StreamIn[x].Data.artist := 
                                         sf_get_string(StreamIn[x].Data.HandleSt, SF_STR_ARTIST);
              StreamIn[x].Data.date := sf_get_string(StreamIn[x].Data.HandleSt, SF_STR_DATE);

              StreamIn[x].Data.track := sf_get_string(StreamIn[x].Data.HandleSt, SF_STR_TRACKNUMBER);
              StreamIn[x].Data.genre := sf_get_string(StreamIn[x].Data.HandleSt, SF_STR_GENRE);
              StreamIn[x].Data.album := sf_get_string(StreamIn[x].Data.HandleSt, SF_STR_ALBUM);

              StreamIn[x].Data.Length := sfInfo.frames;
              err := 0;
  {$IF DEFINED(uos_debug) and DEFINED(unix)}
              WriteLn('sf_open END OK');
  {$endif}
            end;
        end;

  {$endif}

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
      WriteLn('sf StreamIn[x].Data.LibOpen = ' + inttostr(StreamIn[x].Data.LibOpen));
      WriteLn('sf err = ' + inttostr(err));
 {$endif}

      // XMP
   {$IF DEFINED(xmp)}
      if (StreamIn[x].Data.LibOpen = -1) and (uosLoadResult.XMloadERROR = 0) then
        begin
          Err := -1;

          StreamIn[x].Data.HandleSt := xmp_create_context();
          {$IF DEFINED(uos_debug) and DEFINED(unix)}
          if StreamIn[x].Data.HandleSt = nil then  WriteLn(' xmp_create_context() NOT OK')
          else   WriteLn(' xmp_create_context() OK');
            {$endif}

          if xmp_load_module(StreamIn[x].Data.HandleSt, PChar(FileName)) <> 0 then
            begin
              StreamIn[x].Data.LibOpen := -1;
              err := -1;
             {$IF DEFINED(uos_debug) and DEFINED(unix)}
              WriteLn('xmp_load_module NOT OK');
            {$endif}
            end
          else
            begin

          {$IF DEFINED(uos_debug) and DEFINED(unix)}
              WriteLn('xmp_load_module() = ok');
         {$endif}
              xmp_start_player(StreamIn[x].Data.HandleSt, 44100, 0);
              xmp_get_module_info(StreamIn[x].Data.HandleSt, mi);
              // xmp_get_frame_info(StreamIn[x].Data.HandleSt , fi);

              StreamIn[x].Data.LibOpen := 5;
              StreamIn[x].Data.filename := FileName;
              StreamIn[x].Data.channels := 2;
              
              if SampleFormat = -1 then
                StreamIn[x].Data.SampleFormat := 2
              else
                StreamIn[x].Data.SampleFormat := SampleFormat;
              // Need conversion because xmp is always 16 bit     

              if FramesCount = -1 then  StreamIn[x].Data.Wantframes := 65536 Div StreamIn[x].Data.
                                                                       Channels
              else
                StreamIn[x].Data.Wantframes := FramesCount ;

              SetLength(StreamIn[x].Data.Buffer, StreamIn[x].Data.Wantframes*StreamIn[x].Data.
                        Channels);
              x2 := 0 ;
              while x2 < Length(Streamin[x].Data.Buffer) do
                begin
                  Streamin[x].Data.Buffer[x2] := 0.0 ;
                  inc(x2);
                end;

              StreamIn[x].Data.hdformat := 0;
              StreamIn[x].Data.frames := 0;
              StreamIn[x].Data.samplerate := 44100;
              StreamIn[x].Data.samplerateroot := 44100;
              //  StreamIn[x].Data.sections := SFinfo.sections;
              StreamIn[x].Data.title := String(mi.module^.Name);

              StreamIn[x].Data.copyright := '';
              StreamIn[x].Data.software := '';

              StreamIn[x].Data.comment := String(mi.module^.typ);
              StreamIn[x].Data.artist := String(mi.comment);
              StreamIn[x].Data.date := '';

              StreamIn[x].Data.track := '';
              StreamIn[x].Data.genre := '';
              StreamIn[x].Data.album := '';

              StreamIn[x].Data.Length := 0;

              err := 0;
  {$IF DEFINED(uos_debug) and DEFINED(unix)}
              WriteLn('XMP_open END OK');
  {$endif}
            end;
        end;
  {$endif}

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
      WriteLn('XMP StreamIn[x].Data.LibOpen = ' + inttostr(StreamIn[x].Data.LibOpen));
      WriteLn('XMP err = ' + inttostr(err));
 {$endif}

 {$IF DEFINED(mpg123)}
      if ((StreamIn[x].Data.LibOpen = -1)) and (uosLoadResult.MPloadERROR = 0) then
        begin
          Err := -1;

          StreamIn[x].Data.HandleSt := mpg123_new(Nil, Err);

          if Err = 0 then
            begin

  {$IF DEFINED(uos_debug) and DEFINED(unix)}
              WriteLn('mpg123_new OK');
  {$endif}

              if SampleFormat = -1 then
                StreamIn[x].Data.SampleFormat := 2
              else
                StreamIn[x].Data.SampleFormat := SampleFormat;
              mpg123_format_none(StreamIn[x].Data.HandleSt);
              case StreamIn[x].Data.SampleFormat of 
                0: mpg123_format(StreamIn[x].Data.HandleSt, DefRate, Stereo,
                                 MPG123_ENC_FLOAT_32);
                1: mpg123_format(StreamIn[x].Data.HandleSt, DefRate, Stereo,
                                 MPG123_ENC_SIGNED_32);
                2: mpg123_format(StreamIn[x].Data.HandleSt, DefRate, Stereo,
                                 MPG123_ENC_SIGNED_16);
              end;

              Err := mpg123_open(StreamIn[x].Data.HandleSt, PChar(FileName));
            end
          else
            begin
              StreamIn[x].Data.LibOpen := -1;
            end;

          samprat := roundmath(StreamIn[x].Data.samplerate);

          if Err = 0 then
            Err := mpg123_getformat(StreamIn[x].Data.HandleSt,
                   samprat, StreamIn[x].Data.channels,
                   StreamIn[x].Data.encoding);

          if Err = 0 then
            begin
              // Close handle and reload with forced resolution
              mpg123_close(StreamIn[x].Data.HandleSt);
              mpg123_delete(StreamIn[x].Data.HandleSt);
              StreamIn[x].Data.HandleSt := mpg123_new(Nil, Err);

              mpg123_format_none(StreamIn[x].Data.HandleSt);
              case StreamIn[x].Data.SampleFormat of 
                0: mpg123_format(StreamIn[x].Data.HandleSt, samprat,
                                 StreamIn[x].Data.channels, StreamIn[x].Data.encoding);
                1: mpg123_format(StreamIn[x].Data.HandleSt, samprat,
                                 StreamIn[x].Data.channels, StreamIn[x].Data.encoding);
                2: mpg123_format(StreamIn[x].Data.HandleSt, samprat,
                                 StreamIn[x].Data.channels, StreamIn[x].Data.encoding);
              end;
              mpg123_open(StreamIn[x].Data.HandleSt, (PChar(FileName)));
              mpg123_getformat(StreamIn[x].Data.HandleSt,
                               samprat, StreamIn[x].Data.channels,
                               StreamIn[x].Data.encoding);
              StreamIn[x].Data.filename := filename;

              if FramesCount = -1 then  StreamIn[x].Data.Wantframes := 
                                                                       65536 Div StreamIn[x].Data.
                                                                       Channels
              else
                StreamIn[x].Data.Wantframes := FramesCount ;

              SetLength(StreamIn[x].Data.Buffer, StreamIn[x].Data.Wantframes*StreamIn[x].Data.
                        Channels);

              mpg123_info(StreamIn[x].Data.HandleSt, MPinfo);

              // custom code for reading ID3Tag ---> problems with  mpg123_id3() 

              AssignFile(F, Filename);

              FileMode := fmOpenRead + fmShareDenyNone;

              Reset(F, 1);
              Seek(F, FileSize(F) - 128);
              BlockRead(F, BufferTag, SizeOf(BufferTag));
              CloseFile(F);

              StreamIn[x].Data.tag := copy(BufferTag, 1, 3);
              StreamIn[x].Data.title := copy(BufferTag, 4, 30);
              StreamIn[x].Data.artist := copy(BufferTag, 34, 30);
              StreamIn[x].Data.album := copy(BufferTag, 64, 30);
              StreamIn[x].Data.date :=  copy(BufferTag, 94, 4);
              StreamIn[x].Data.comment := copy(BufferTag, 98, 30);
              StreamIn[x].Data.track := inttostr(ord(BufferTag[127]));
              StreamIn[x].Data.genre := inttostr(ord(BufferTag[128]));

              StreamIn[x].Data.samplerateroot :=  StreamIn[x].Data.samplerate ;
              StreamIn[x].Data.hdformat := MPinfo.layer;
              StreamIn[x].Data.frames := MPinfo.framesize;
              StreamIn[x].Data.Length := mpg123_length(StreamIn[x].Data.HandleSt);
              StreamIn[x].Data.LibOpen := 1;
            end
          else
            begin
              StreamIn[x].Data.LibOpen := -1;
            end;
        end;

  {$endif}

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
      WriteLn('mp StreamIn[x].Data.LibOpen = ' + inttostr(StreamIn[x].Data.LibOpen));
      WriteLn('mp err = ' + inttostr(err));
 {$endif}

  {$IF DEFINED(opus)}
      if (StreamIn[x].Data.LibOpen = -1) and (uosLoadResult.OPloadERROR = 0) then
        begin
          Err := -1;

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
          WriteLn('Before Opus');
 {$endif}

          StreamIn[x].Data.HandleSt := pchar('opus');
          StreamIn[x].Data.HandleOP := op_test_file(PChar(FileName), Err);

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
          WriteLn('op_test_file error = '+ inttostr(Err));
 {$endif}

          if Err=0
            then
            begin
              Err := op_test_open(StreamIn[x].Data.HandleOP);
              if (Err=0) and (op_link_count(StreamIn[x].Data.HandleOP)=1)
                then
                begin

                  if SampleFormat = -1 then
                    StreamIn[x].Data.SampleFormat := 2
                  else
                    StreamIn[x].Data.SampleFormat := SampleFormat;

                  //tag  

                  OpusTag := op_tags(StreamIn[x].Data.HandleOP, Nil);

                  if OpusTag<>nil

                    then
                    begin

                      if OpusTag^.comments>0
                        then
                        begin

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
                          WriteLn((Format('OpusTag.comments = %d', [OpusTag^.comments])));
 {$endif}
                          LComment := OpusTag^.user_comments;
                          LcommentLength := OpusTag^.comment_lengths;
                          for j := 0 to OpusTag^.comments - 1 do
                            begin
                              SetLength(s, LcommentLength^);
                              move(Pointer(LComment^)^, Pointer(s)^, LcommentLength^);

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
                              // WriteLn(s);
 {$endif}

                              if j = 1 then StreamIn[x].Data.title := s;
                              if j = 2 then StreamIn[x].Data.artist := s;
                              if j = 3 then StreamIn[x].Data.album := s;
                              if j = 4 then StreamIn[x].Data.date := s;
                              if j = 5 then StreamIn[x].Data.comment := s;
                              if j = 6 then StreamIn[x].Data.tag := s;

                              inc(LComment);
                              inc(LcommentLength);
                            end;
                        end;
                    end;


           //  WriteLn((Format('op_bitrate = %d', [op_bitrate(StreamIn[x].Data.HandleOP, nil)])));  

                  StreamIn[x].Data.Length := op_pcm_total(StreamIn[x].Data.HandleOP, Nil);
                  StreamIn[x].Data.filename := FileName;
                  StreamIn[x].Data.channels := op_channel_count(StreamIn[x].Data.HandleOP, Nil);

                  // opus use constant sample rate 48k
                  StreamIn[x].Data.samplerate :=  48000 ;
                  StreamIn[x].Data.samplerateroot :=  StreamIn[x].Data.samplerate ;
                  StreamIn[x].Data.Seekable  := true;

                  if FramesCount = -1 then  StreamIn[x].Data.Wantframes := 4096 * StreamIn[x].Data.
                                                                           Channels
                  else
                    StreamIn[x].Data.Wantframes := FramesCount ;

                  SetLength(StreamIn[x].Data.Buffer, StreamIn[x].Data.Wantframes*StreamIn[x].Data.
                            Channels);

                  StreamIn[x].Data.LibOpen := 4;

                end
              else
                begin
                  StreamIn[x].Data.LibOpen := -1;
                end;
            end;
        end;
{$endif}

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
      WriteLn('op StreamIn[x].Data.LibOpen = ' + inttostr(StreamIn[x].Data.LibOpen));
      WriteLn('op err = ' + inttostr(err));
 {$endif}

  {$IF DEFINED(neaac)}
      if (StreamIn[x].Data.LibOpen = -1) and (uosLoadResult.AAloadERROR = 0) then
        begin
          Err := -1;

          StreamIn[x].AACI := TAACInfo.Create();

  {$IF DEFINED(uos_debug) and DEFINED(unix)}
          WriteLn('TAACInfo.Create() = ok');
  {$endif}

          case SampleFormat of 
            0 : StreamIn[x].AACI := MP4OpenFile(FileName, FAAD_FMT_FLOAT);
            1 : StreamIn[x].AACI := MP4OpenFile(FileName, FAAD_FMT_32BIT);
            2 : StreamIn[x].AACI := MP4OpenFile(FileName, FAAD_FMT_16BIT);
          end;

          if StreamIn[x].AACI <> nil then
            begin
  {$IF DEFINED(uos_debug) and DEFINED(unix)}
              WriteLn('MP4OpenFile() = ok');
  {$endif}

              case StreamIn[x].AACI.outputFormat of 
                FAAD_FMT_16BIT : StreamIn[x].Data.SampleFormat := 2;
                //FAAD_FMT_24BIT : ;
                FAAD_FMT_32BIT : StreamIn[x].Data.SampleFormat := 1;
                FAAD_FMT_FLOAT : StreamIn[x].Data.SampleFormat := 0;
                //FAAD_FMT_DOUBLE: ;
              end;

              StreamIn[x].Data.filename  := FileName;

              StreamIn[x].Data.HandleSt  := StreamIn[x].AACI.hMP4;

              StreamIn[x].Data.samplerate  := StreamIn[x].AACI.SampleRate;
              StreamIn[x].Data.channels  := StreamIn[x].AACI.Channels;

              case StreamIn[x].AACI.outputFormat of 
                FAAD_FMT_16BIT : StreamIn[x].Data.encoding := MPG123_ENC_SIGNED_16;
                //FAAD_FMT_24BIT : ;
                FAAD_FMT_32BIT : StreamIn[x].Data.encoding := MPG123_ENC_SIGNED_32;
                FAAD_FMT_FLOAT : StreamIn[x].Data.encoding := MPG123_ENC_FLOAT_32;
                //FAAD_FMT_DOUBLE: ;
              end;

              if FramesCount = -1 then
                StreamIn[x].Data.Wantframes :=  65536 Div StreamIn[x].Data.Channels
              else
                StreamIn[x].Data.Wantframes := FramesCount ;

              SetLength(StreamIn[x].Data.Buffer, StreamIn[x].Data.Wantframes * StreamIn[x].Data.
                        Channels);

              StreamIn[x].Data.title  := StreamIn[x].AACI.Title;
              StreamIn[x].Data.artist  := StreamIn[x].AACI.Artist;
              StreamIn[x].Data.album  := StreamIn[x].AACI.Album;
              StreamIn[x].Data.date  := StreamIn[x].AACI.Date;
              StreamIn[x].Data.comment  := StreamIn[x].AACI.Comment;
              StreamIn[x].Data.tag[0]  := #0;
              StreamIn[x].Data.tag[1]  := #0;
              StreamIn[x].Data.tag[2]  := #0;
              StreamIn[x].Data.genre  := StreamIn[x].AACI.Genre;
              StreamIn[x].Data.samplerateroot := StreamIn[x].AACI.SampleRate;
              StreamIn[x].Data.hdformat  := 0;
              StreamIn[x].Data.frames  := 0;
              StreamIn[x].Data.Length  := StreamIn[x].AACI.TotalSamples;

              StreamIn[x].Data.Seekable  := StreamIn[x].AACI.Size > 0;

              StreamIn[x].Data.LibOpen := 2 ;
              Err := 0;
            end
          else
            begin
  {$IF DEFINED(uos_debug) and DEFINED(unix)}
              WriteLn('MP4OpenFile() NOT ok');
  {$endif}
            end;

        end;
  {$endif}

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
      WriteLn('ac StreamIn[x].Data.LibOpen = ' + inttostr(StreamIn[x].Data.LibOpen));
      WriteLn('ac err = ' + inttostr(err));
 {$endif}


  {$IF DEFINED(cdrom)}
      if (StreamIn[x].Data.LibOpen = -1) then
        begin
          Err := -1;
          StreamIn[x].pCD := Nil;

          case SampleFormat of 
            2 : StreamIn[x].pCD := CDROM_OpenFile(FileName);
          end;

          if StreamIn[x].pCD <> nil then
            begin
              case StreamIn[x].pCD^.BitsPerSample of 
                16 : StreamIn[x].Data.SampleFormat := 2;
              end;

              StreamIn[x].Data.filename  := FileName;

              StreamIn[x].Data.HandleSt  := @StreamIn[x].pCD;
              // Uos requires an assigned pointer....

              StreamIn[x].Data.samplerate  := StreamIn[x].pCD^.SampleRate;
              StreamIn[x].Data.channels  := StreamIn[x].pCD^.Channels;

              case StreamIn[x].pCD^.BitsPerSample of 
                16 : StreamIn[x].Data.encoding := MPG123_ENC_SIGNED_16;
              end;

              if FramesCount = -1 then
                StreamIn[x].Data.Wantframes :=  65536 Div StreamIn[x].Data.Channels
              else
                StreamIn[x].Data.Wantframes := FramesCount;

              SetLength(StreamIn[x].Data.Buffer, StreamIn[x].Data.Wantframes * StreamIn[x].Data.
                        Channels);

              StreamIn[x].Data.title  := '';
              StreamIn[x].Data.artist  := '';
              StreamIn[x].Data.album  := '';
              StreamIn[x].Data.date  := '';
              StreamIn[x].Data.comment  := '';
              StreamIn[x].Data.tag[0]  := #0;
              StreamIn[x].Data.tag[1]  := #0;
              StreamIn[x].Data.tag[2]  := #0;
              StreamIn[x].Data.genre  := '0';
              StreamIn[x].Data.samplerateroot := StreamIn[x].pCD^.SampleRate;
              StreamIn[x].Data.hdformat  := 0;
              StreamIn[x].Data.frames  := 0;
              StreamIn[x].Data.Length  := StreamIn[x].pCD^.TotalSamples;

              StreamIn[x].Data.LibOpen := 3;
              Err := 0;
            end;
        end;
  {$endif}

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
      WriteLn('cd StreamIn[x].Data.LibOpen = ' + inttostr(StreamIn[x].Data.LibOpen));
      WriteLn('cd err = ' + inttostr(err));
 {$endif}

      if (err <> 0) or (StreamIn[x].Data.LibOpen = -1) then
        begin
   {$IF DEFINED(uos_debug) and DEFINED(unix)}
          WriteLn('not ok StreamIn[x].Data.LibOpen = -1');
          WriteLn('not ok cd err = ' + inttostr(err));
   {$endif}

          result := -1 ;
          StreamIn[Length(StreamIn) - 1].Destroy;
          setlength(StreamIn, Length(StreamIn) - 1);
        end
      else
        begin

  {$IF DEFINED(uos_debug) and DEFINED(unix)}
          WriteLn('addfromfile OK');
  {$endif}
          Result := x;
          StreamIn[x].Data.Output := OutputIndex;
          StreamIn[x].Data.Status := 1;
          StreamIn[x].Data.Position := 0;
          StreamIn[x].Data.OutFrames := 0;
          StreamIn[x].Data.Poseek := -1;
          StreamIn[x].Data.TypePut := 0;
          StreamIn[x].Data.seekable := True;
          StreamIn[x].LoopProc := Nil;
          if SampleFormat = -1 then
            StreamIn[x].Data.SampleFormat := 2
          else
            StreamIn[x].Data.SampleFormat := SampleFormat;

          case StreamIn[x].Data.LibOpen of 

            0:  StreamIn[x].Data.ratio := StreamIn[x].Data.Channels;

  {$IF DEFINED(mpg123)}
            1:
               begin
                 if StreamIn[x].Data.SampleFormat = 2 then
                   StreamIn[x].Data.ratio := streamIn[x].Data.Channels
                 else
                   StreamIn[x].Data.ratio := 2 * streamIn[x].Data.Channels;

                 if StreamIn[x].Data.SampleFormat = 0 then
                   mpg123_param(StreamIn[x].Data.HandleSt, StreamIn[x].Data.Channels,
                                MPG123_FORCE_FLOAT, 0);
               end;
  {$endif}
  {$IF DEFINED(neaac)}
            2 : StreamIn[x].Data.ratio := streamIn[x].AACI.Channels;
  {$endif}
  {$IF DEFINED(cdrom)}
            3 : StreamIn[x].Data.ratio := streamIn[x].pCD^.Channels;
  {$endif}
  {$IF DEFINED(opus)}
            4 : StreamIn[x].Data.ratio :=  streamIn[x].Data.Channels;
  {$endif}
  {$IF DEFINED(xmp)}
            5 : StreamIn[x].Data.ratio :=  streamIn[x].Data.Channels;
  {$endif}
          end;
          StreamIn[x].Data.Enabled := True;
        end;
    end
  else result := -2;

  {$IF DEFINED(uos_debug) and DEFINED(unix)}
  WriteLn('result = ' + inttostr(result));
  WriteLn('cd err = ' + inttostr(err));
  {$endif}
end;

procedure Tuos_Player.ReadEndless(x : integer);
begin
{ 
 Nothing to do: all is done with AddFromEndlessMuted.
  }
end;

{$IF DEFINED(synthesizer)}
procedure Tuos_Player.FillLookupTable(x, typewave, channel, AHarmonics: Integer;
                                      EvenHarmonics : shortint);
var 
  i, j, l: Integer;
  nPI_l, attenuation: Double;
  thesample: single;
begin
  l := 1024;
  nPI_l := 2*PI/l;

  for i:=0 to l-1 do
    begin
      if typewave = 0 then  // sine
        begin
          thesample   := sin(i * nPI_l);
          if thesample > 1 then
            thesample := 1;
          if thesample < -1 then
            thesample := -1;

          if Channel = 1 then
            StreamIn[x].Data.LookupTableLeft[i]  := thesample;
          //   writeln( floattostr((LookupTableLeft[i])) + ' left ');

          if Channel = 2 then
            StreamIn[x].Data.LookupTableRight[i] := thesample;
          //  writeln(  'right  ' + floattostr((LookupTableRight[i])));

        end;

      if typewave = 1 then // square
        begin
          if sin(i * nPI_l) >= 0 then
            thesample := 1
          else
            thesample := -1;

          if Channel = 1 then
            StreamIn[x].Data.LookupTableLeft[i]  := thesample;
          if Channel = 2 then
            StreamIn[x].Data.LookupTableRight[i] := thesample;
        end;

      if typewave = 2 then // triangle
        begin
          if Channel = 1 then
            begin
              if i < (l div 2) + 1 then
                thesample := (((l - (i * 2)) / (l / 2))) - 1
              else
                thesample := StreamIn[x].Data.LookupTableLeft[l - i];
              if thesample > 1 then
                thesample := 1;
              if thesample < -1 then
                thesample := -1;
              StreamIn[x].Data.LookupTableLeft[i] := thesample;
              //writeln( floattostr((LookupTableLeft[i])) + ' left '); 
            end;

          if Channel = 2 then
            begin
              if i < (l div 2) + 1 then
                thesample := (((l - (i * 2)) / (l / 2))) - 1
              else
                thesample := StreamIn[x].Data.LookupTableRight[l - i];
              if thesample > 1 then
                thesample := 1;
              if thesample < -1 then
                thesample := -1;
              StreamIn[x].Data.LookupTableRight[i] := thesample;
              // writeln( floattostr((LookupTableright[i])) + ' right '); 
            end;
        end;

      if typewave = 3 then // Sawtooth
        begin
          thesample :=  ((l - i) / (l / 2)) - 1;
          if thesample > 1 then
            thesample := 1;
          if thesample < -1 then
            thesample := -1;

          if Channel = 1 then
            StreamIn[x].Data.LookupTableLeft[i]  := thesample;
          if Channel = 2 then
            StreamIn[x].Data.LookupTableRight[i] := thesample;
        end;

    end;

  if AHarmonics > 0 then
    for j:=1 to AHarmonics do
      begin
        if ((((j mod 2) =1) and (EvenHarmonics=1)) or (EvenHarmonics=0)) then
          begin
            attenuation := power(j+1, 4);
            nPI_l := 2*j*pi/l;
            for i:=0 to l-1 do
              begin

                if typewave = 0 then
                  begin
                    if channel = 1 then
                      StreamIn[x].Data.LookupTableLeft[i] := 
                                                             StreamIn[x].Data.LookupTableLeft[i]+sin
                                                             (i*nPI_l)/attenuation;
                    if channel = 2 then
                      StreamIn[x].Data.LookupTableRight[i] := 
                                                              StreamIn[x].Data.LookupTableRight[i]+
                                                              sin(i*nPI_l)/attenuation;
                  end;

                if typewave = 1 then
                  begin
                    if channel = 1 then
                      begin
                        if sin(i*nPI_l) >= 0 then
                          StreamIn[x].Data.LookupTableLeft[i] := 
                                                                 StreamIn[x].Data.LookupTableLeft[i]
                                                                 +(1/attenuation)
                        else
                          StreamIn[x].Data.LookupTableLeft[i] := 
                                                                 StreamIn[x].Data.LookupTableLeft[i]
                                                                 +(-1/attenuation);
                      end ;
                    if channel = 2 then
                      begin
                        if sin(i*nPI_l) >= 0 then
                          StreamIn[x].Data.LookupTableRight[i] := 
                                                                  StreamIn[x].Data.LookupTableRight[
                                                                  i]+(1/attenuation)
                        else
                          StreamIn[x].Data.LookupTableRight[i] := 
                                                                  StreamIn[x].Data.LookupTableRight[
                                                                  i]+(-1/attenuation);
                      end ;
                  end;

              end;
          end;
      end;
end;

procedure Tuos_Player.ReadSynth(x :integer);
var 
  x2 : integer;
  sf1, sf2 : cfloat;
  ps: PDArShort;
  // if input is Int16 format
  pl: PDArLong;
  // if input is Int32 format
  pf: PDArFloat;
  // if input is Float32 format

  i: culong;
  chan : integer;
  aFreqL, aFreqR, aPosL, aPosR, aStepL, aStepR: cfloat;

begin

  //for x2 := 0 to length(StreamIn[x].Data.Buffer) 
  //  do StreamIn[x].Data.Buffer[x2] := 0;

  if StreamIn[x].Data.SampleFormat =  2 then ps := @StreamIn[x].Data.Buffer
  else
    if StreamIn[x].Data.SampleFormat =  1 then pl := @StreamIn[x].Data.Buffer
  else
    if StreamIn[x].Data.SampleFormat =  0 then pf := @StreamIn[x].Data.Buffer;

  chan := StreamIn[x].Data.channels;

  aPosL := StreamIn[x].Data.PosInTableLeft;
  aPosR := StreamIn[x].Data.PosInTableRight;

  aFreqL := StreamIn[x].Data.freqLsine;
  aFreqR := StreamIn[x].Data.freqRsine;

  aStepL := (aFreqL*1024/StreamIn[x].Data.samplerate);
  aStepR := (aFreqR*1024/StreamIn[x].Data.samplerate);;

  StreamIn[x].Data.posdursine := 
                                 StreamIn[x].Data.posdursine + (StreamIn[x].Data.WantFrames Div chan
                                 );

  x2 := 0 ;

  if (StreamIn[x].Data.posdursine <= StreamIn[x].Data.dursine) or (StreamIn[x].Data.dursine = 0)
    then
    begin

      while x2 < (length(StreamIn[x].Data.Buffer) div chan)  do
        begin

          sf2 := 0;
          sf1 := 0;

          sf1 := StreamIn[x].Data.VLeft*StreamIn[x].Data.LookupTableLeft[trunc(aPosL) And (1023)];
          aPosL := aPosL+aStepL;

          if chan = 2 then
            begin
              sf2 := StreamIn[x].Data.VRight*StreamIn[x].Data.LookupTableRight[trunc(aPosR) And (
                     1023)];
              aPosR := aPosR+aStepR;
            end;
          case StreamIn[x].Data.SampleFormat of 
            2: // int16
               begin
                 ps^[x2] := trunc(sf1 * 32768);
                 if chan = 2 then ps^[x2+1] := trunc(sf2 * 32768);
               end;
            1: // int32
               begin
                 pl^[x2] := trunc(sf1 * 2147483648);
                 if chan = 2 then pl^[x2+1] := trunc(sf2 * 2147483648);
               end;
            0: // float32
               begin
                 pf^[x2] := sf1;
                 if chan = 2 then pf^[x2+1] := sf2 ;
               end;
          end;

          inc(x2, chan);
        end;

      i := trunc(aPosL) Div 1024;
      StreamIn[x].Data.PosInTableLeft := aPosL-(i*1024);
      i := trunc(aPosR) Div 1024;
      StreamIn[x].Data.PosInTableRight := aPosR-(i*1024);

      StreamIn[x].Data.OutFrames :=  StreamIn[x].Data.WantFrames;
    end
  else StreamIn[x].Data.OutFrames :=  0 ;

end;
{$endif}

procedure Tuos_Player.ReadMem(X : integer);
var 
  x2, wantframestemp : integer;
{$IF DEFINED(uos_debug) and DEFINED(unix)}
  i : integer;
  st : string;
{$endif}
begin
  if length(StreamIn[x].Data.memorybuffer) - StreamIn[x].Data.posmem - (StreamIn[x].Data.WantFrames

     * StreamIn[x].Data.Channels) >= 0 then wantframestemp := (StreamIn[x].Data.WantFrames
                                                              * StreamIn[x].Data.Channels)
  else
    wantframestemp := length(StreamIn[x].Data.memorybuffer) - StreamIn[x].Data.posmem;

  // wantframestemp := StreamIn[x].Data.wantframes;

{$IF DEFINED(uos_debug) and DEFINED(unix)}
  writeln('length(StreamIn[x].Data.MemoryBuffer) = '+inttostr(length(StreamIn[x].Data.MemoryBuffer))
  ) ;
  writeln('StreamIn[x].Data.posmem = '+inttostr(StreamIn[x].Data.posmem)) ;
  writeln('wantframestemp = '+inttostr(wantframestemp)) ;
{$endif}

  for x2 := 0 to wantframestemp -1 do

    StreamIn[x].Data.Buffer[x2] := (StreamIn[x].Data.memorybuffer[StreamIn[x].Data.posmem + x2]);

  StreamIn[x].Data.posmem := StreamIn[x].Data.posmem + wantframestemp;

  StreamIn[x].Data.OutFrames := wantframestemp;

  if StreamIn[x].Data.SampleFormat > 0 then
    StreamIn[x].Data.Buffer := ConvertSampleFormat(StreamIn[x].Data);

{$IF DEFINED(uos_debug) and DEFINED(unix)}
  writeln('StreamIn[x].Data.posmem after = '+inttostr(StreamIn[x].Data.posmem)) ;
  writeln('StreamIn[x].Data.OutFrames = '+ inttostr(wantframestemp)) ;
  st := '';
  for i := 0 to length(StreamIn[x].data.Buffer) -1 do
    st := st + '|' + inttostr(i) + '=' + floattostr(StreamIn[x].data.Buffer[i]);
  WriteLn('OUTPUT DATA AFTER Input from memory ------------------------------');
  WriteLn(st);
{$endif}
end;

procedure Tuos_Player.ReadMemDec(X : integer);
var 
  wantframestemp : integer;
{$IF DEFINED(uos_debug) and DEFINED(unix)}
  i : integer;
  st : string;
{$endif}
begin


{
 if length(StreamIn[x].Data.MemoryStream) - StreamIn[x].Data.posmem - (StreamIn[x].Data.WantFrames

* StreamIn[x].Data.Channels) >= 0 then wantframestemp := (StreamIn[x].Data.WantFrames
* StreamIn[x].Data.Channels) else
 wantframestemp := length(StreamIn[x].Data.MemoryStream) - StreamIn[x].Data.posmem;
}

  wantframestemp := (StreamIn[x].Data.WantFrames * StreamIn[x].Data.channels);

{$IF DEFINED(uos_debug) and DEFINED(unix)}
  writeln('length(StreamIn[x].MemoryStreamDec) = '+inttostr(StreamIn[x].MemoryStreamDec.size)) ;
  writeln('StreamIn[x].Data.posmem = '+inttostr(StreamIn[x].Data.posmem)) ;
  writeln('wantframestemp = '+inttostr(wantframestemp)) ;
{$endif}

  StreamIn[x].Data.OutFrames := StreamIn[x].MemoryStreamDec.Read(StreamIn[x].Data.Buffer[0] ,
                                wantframestemp);

  StreamIn[x].Data.OutFrames := StreamIn[x].Data.OutFrames Div StreamIn[x].Data.channels;

  StreamIn[x].Data.posmem := StreamIn[x].Data.posmem + wantframestemp;

  // StreamIn[x].Data.OutFrames := wantframestemp;

  if StreamIn[x].Data.SampleFormat > 0 then
    StreamIn[x].Data.Buffer := ConvertSampleFormat(StreamIn[x].Data);

{$IF DEFINED(uos_debug) and DEFINED(unix)}
  writeln('StreamIn[x].Data.posmem after = '+inttostr(StreamIn[x].Data.posmem)) ;
  writeln('StreamIn[x].Data.OutFrames = '+ inttostr(wantframestemp)) ;
  st := '';
  for i := 0 to length(StreamIn[x].data.Buffer) -1 do
    st := st + '|' + inttostr(i) + '=' + floattostr(StreamIn[x].data.Buffer[i]);
  WriteLn('OUTPUT DATA AFTER Input from memory ------------------------------');
  WriteLn(st);
{$endif}
end;

procedure Tuos_Player.DoSeek( x : integer);
begin
  if StreamIn[x].Data.TypePut = 4 then
    StreamIn[x].Data.posmem := 0
  else

    case StreamIn[x].Data.LibOpen of 
      -1: ;
  {$IF DEFINED(sndfile)}
      0: sf_seek(StreamIn[x].Data.HandleSt, StreamIn[x].Data.Poseek, 0);
  {$endif}
  {$IF DEFINED(mpg123)}
      1: mpg123_seek(StreamIn[x].Data.HandleSt, StreamIn[x].Data.Poseek, 0);
  {$endif}
  {$IF DEFINED(neaac)}
      2 : MP4Seek(StreamIn[x].AACI, StreamIn[x].Data.Poseek);
  {$endif}
  {$IF DEFINED(cdrom)}
      3 : ;
  {$endif}
  {$IF DEFINED(opus)}
      4 : op_pcm_seek(StreamIn[x].Data.HandleOP, StreamIn[x].Data.Poseek);
  {$endif}
    end;
end;

procedure Tuos_Player.DoDSPOutAfterBufProc(x: integer);
var 
  x3 : integer;
{$IF (FPC_FULLVERSION < 20701) and DEFINED(fpgui)}
  msg: TfpgMessageParams;
  // for fpgui
 {$endif}
begin

  for x3 := 0 to high(StreamOut[x].DSP) do
    if (StreamOut[x].DSP[x3].Enabled = True) then
      begin
        if (StreamOut[x].DSP[x3].AftFunc <> nil) then
          StreamOut[x].Data.Buffer := 
                                      StreamOut[x].DSP[x3].AftFunc(StreamOut[x].Data,
                                      StreamOut[x].DSP[x3].fftdata);

  {$IF DEFINED(mse)}
        if (StreamOut[x].DSP[x3].LoopProc <> nil) then
          begin
            application.queueasynccall(StreamOut[x].DSP[x3].LoopProc);
          end;
   {$else}

  {$IF not DEFINED(Library)}
        if (StreamOut[x].DSP[x3].LoopProc <> nil) then
  {$IF FPC_FULLVERSION>=20701}
          thethread.{$IF DEFINED(usequeue)}Queue{$else}Synchronize{$endif}(thethread,StreamOut[x].
                                                                           DSP[x3].LoopProc);
  {$else}
 {$IF (FPC_FULLVERSION < 20701) and DEFINED(fpgui)}
        begin
          msg.user.Param1 := x3 ;
          // the index of the dsp
          msg.user.Param2 := 1;
          // it is a OUT DSP
          fpgPostMessage(self, refer, MSG_CUSTOM1, msg);
        end;
 {$else}
        thethread.{$IF DEFINED(usequeue)}Queue{$else}Synchronize{$endif}(thethread,StreamOut[x].DSP[
                                                                         x3].LoopProc);
  {$endif}
  {$endif}

  {$elseif not DEFINED(java)}
        if (StreamOut[x].DSP[x3].LoopProc <> nil) then
          StreamOut[x].DSP[x3].LoopProc;
  {$else}
        if (StreamOut[x].DSP[x3].LoopProc <> nil) then
  {$IF FPC_FULLVERSION >= 20701}
          thethread.{$IF DEFINED(usequeue)}Queue{$else}Synchronize{$endif}(thethread,@StreamOut[x].
                                                                           DSP[x3].LoopProcjava);
  {$else}
        thethread.{$IF DEFINED(usequeue)}Queue{$else}Synchronize{$endif}(thethread,@StreamOut[x].DSP
                                                                         [x3].LoopProcjava);
  {$endif}
  {$endif}

   {$endif}
      end;
end;

procedure Tuos_Player.DoArrayLevel(x: integer);
begin
  setlength(uosLevelArray[index][x],length(uosLevelArray[index][x]) +1);
  uosLevelArray[index][x][length(uosLevelArray[index][x]) -1 ] := StreamIn[x].Data.LevelLeft;

  setlength(uosLevelArray[index][x],length(uosLevelArray[index][x]) +1);
  uosLevelArray[index][x][length(uosLevelArray[index][x]) -1 ] := StreamIn[x].Data.LevelRight;

  // writeln('array length = ' + inttostr(length(uosLevelArray[index][x])));
end;

{$IF DEFINED(portaudio)}
procedure Tuos_Player.ReadDevice(x : integer);
var 
  x2 : integer;
begin
  for x2 := 0 to StreamIn[x].Data.WantFrames -1 do
    StreamIn[x].Data.Buffer[x2] := cfloat(0.0);
  // clear input
  Pa_ReadStream(StreamIn[x].Data.HandleSt,
                @StreamIn[x].Data.Buffer[0], StreamIn[x].Data.WantFrames);

  // err :=// if you want clean buffer
  StreamIn[x].Data.OutFrames := 
                                StreamIn[x].Data.WantFrames * StreamIn[x].Data.Channels;


//  if err = 0 then StreamIn[x].Data.Status := 1 else StreamIn[x].Data.Status := 0;// if you want clean buffer
end;
{$endif}

procedure Tuos_Player.DoDSPinBeforeBufProc(x: integer);
var 
  x2 : integer;
begin
  for x2 := 0 to high(StreamIn[x].DSP) do
    if (StreamIn[x].DSP[x2].Enabled = True) and
       (StreamIn[x].DSP[x2].BefFunc <> nil) then
      StreamIn[x].DSP[x2].BefFunc(StreamIn[x].Data, StreamIn[x].DSP[x2].fftdata);
end;

procedure Tuos_Player.DoDSPinAfterBufProc(x: integer);
var 
  x2 : integer;
{$IF (FPC_FULLVERSION < 20701) and DEFINED(fpgui)}
  msg: TfpgMessageParams;
  // for fpgui
 {$endif}
begin
  for x2 := 0 to high(StreamIn[x].DSP) do
    if (StreamIn[x].DSP[x2].Enabled = True) then
      begin

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
        writeln('DSPin AfterBuffProc 1.');
 {$endif}
        if (StreamIn[x].DSP[x2].AftFunc <> nil) then
          StreamIn[x].Data.Buffer := 
                                     StreamIn[x].DSP[x2].AftFunc(StreamIn[x].Data,
                                     StreamIn[x].DSP[x2].fftdata);

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
        writeln('DSPin AfterBuffProc 2.');
 {$endif}

  {$IF DEFINED(mse)}
        if (StreamIn[x].DSP[x2].LoopProc <> nil) then
          begin
            application.queueasynccall(StreamIn[x].DSP[x2].LoopProc) ;
          end;
   {$else}

    {$IF not DEFINED(Library)}
        if (StreamIn[x].DSP[x2].LoopProc <> nil) then
  {$IF FPC_FULLVERSION>=20701}
          thethread.{$IF DEFINED(usequeue)}Queue{$else}Synchronize{$endif}(thethread,StreamIn[x].DSP
                                                                           [x2].LoopProc);
  {$else}
  {$IF (FPC_FULLVERSION < 20701) and DEFINED(fpgui)}
        begin
          msg.user.Param1 := x2 ;
          // the index of the dsp
          msg.user.Param2 := 0;
          //  it is a In DSP
          fpgPostMessage(self, refer, MSG_CUSTOM1, msg);
        end;
  {$else}
        thethread.{$IF DEFINED(usequeue)}Queue{$else}Synchronize{$endif}(thethread,StreamIn[x].DSP[
                                                                         x2].LoopProc);
  {$endif}
  {$endif}
  {$elseif not DEFINED(java)}
        if (StreamIn[x].DSP[x2].LoopProc <> nil) then
          StreamIn[x].DSP[x2].LoopProc;
  {$else}
        if (StreamIn[x].DSP[x2].LoopProc <> nil) then
  {$IF FPC_FULLVERSION>=20701}
          thethread.{$IF DEFINED(usequeue)}Queue{$else}Synchronize{$endif}(thethread,@Streamin[x].
                                                                           DSP[x2].LoopProcjava);
  {$else}
        thethread.{$IF DEFINED(usequeue)}Queue{$else}Synchronize{$endif}(thethread,@Streamin[x].DSP[
                                                                         x2].LoopProcjava);
  {$endif}
  {$endif}
  {$endif}
      end;
end;

procedure Tuos_Player.SeekIfTerminated;
var 
  x, statustemp : integer;
begin

  statustemp := 0 ;
  for x := 0 to high(StreamIn) do
    begin
      if (StreamIn[x].Data.enabled = true)
        then
        begin

          if (StreamIn[x].Data.TypePut <> 1)
            then
            begin
              if StreamIn[x].Data.Status = 1 then
                statustemp := StreamIn[x].Data.Status;
              if (StreamIn[x].Data.Status = 2) and (statustemp = 0) then
                statustemp := StreamIn[x].Data.Status;
            end
          else
            if 
               (StreamIn[x].Data.TypePut = 1) then statustemp := status ;
        end ;
    end;

  if statustemp <> status then status := statustemp;

  if (status = 0) and IsLooped then
    begin
      for x:= 0 to high(StreamIn) do
        begin
          InputSeek(x, 0);
          if StreamIn[x].Data.TypePut = 4 then
            StreamIn[x].Data.posmem := 0;
          StreamIn[x].Data.status := 1;
        end;

      Status := 1;

   {$IF DEFINED(uos_debug) and DEFINED(unix)}
      WriteLn('Loop (NLooped: '+IntToStr(NLooped)+')----');
   {$endif}

      if NLooped > 0 then
        Dec(NLooped);
    end;

end;

procedure Tuos_Player.DoLoopEndMethods;
begin
{$IF DEFINED(mse)}
  if LoopEndProc <> nil then
    begin
      application.queueasynccall(LoopEndProc);
    end;
     {$else}

 {$IF not DEFINED(Library)}
  if LoopEndProc <> nil then

    //  Execute LoopEndProc procedure
   {$IF FPC_FULLVERSION>=20701}
    thethread.{$IF DEFINED(usequeue)}Queue{$else}Synchronize{$endif}(thethread,LoopEndProc);
   {$else}
   {$IF (FPC_FULLVERSION < 20701) and DEFINED(fpgui)}
  begin
    msg.user.Param1 := -2 ;
    // it is the first proc
    fpgPostMessage(self, refer, MSG_CUSTOM1, msg);
  end;
   {$else}
  thethread.{$IF DEFINED(usequeue)}Queue{$else}Synchronize{$endif}(thethread,LoopEndProc);
   {$endif}
   {$endif}
   {$elseif not DEFINED(java)}
  if LoopEndProc <> nil then
    LoopEndProc;
   {$else}
  if LoopEndProc <> nil then

   {$IF FPC_FULLVERSION>=20701}
    thethread.{$IF DEFINED(usequeue)}Queue{$else}Synchronize{$endif}(thethread,@endprocjava);
   {$else}
  thethread.{$IF DEFINED(usequeue)}Queue{$else}Synchronize{$endif}(thethread,@endprocjava);
  //  Execute EndProc procedure
   {$endif}
   {$endif}
   {$endif}
end;

procedure Tuos_Player.DoEndProc;
begin
{$IF DEFINED(mse)}
  if EndProc <> nil then
    application.queueasynccall(EndProc);
 {$else}

 {$IF not DEFINED(Library)}
  if EndProc <> nil then
    thethread.{$IF DEFINED(usequeue)}Queue{$else}Synchronize{$endif}(thethread,EndProc);
  //  Execute EndProc procedure

  //thethread.queue(thethread,EndProc);//  Execute EndProc procedure

  {$elseif not DEFINED(java)}
  if (EndProc <> nil) then
    EndProc;
  {$else}
  if (EndProc <> nil) then
    thethread.{$IF DEFINED(usequeue)}Queue{$else}Synchronize{$endif}(thethread,@endprocjava);
  //  Execute EndProc procedure

  {$endif}

  {$endif}
end;

procedure Tuos_Player.DoTerminateNoFreePlayer;
var 
  x, x2 : integer;
begin

  for x := 0 to high(StreamIn) do
    begin
      if (length(StreamIn[x].DSP) > 0) then
        for x2 := 0 to high(StreamIn[x].DSP) do
          if (StreamIn[x].DSP[x2].EndFunc <> nil) then
            StreamIn[x].DSP[x2].EndFunc(StreamIn[x].Data, StreamIn[x].DSP[x2].fftdata);
    end;

  for x := 0 to high(StreamOut) do
    begin
      if (length(StreamOut[x].DSP) > 0) then
        for x2 := 0 to high(StreamOut[x].DSP) do
          if (StreamOut[x].DSP[x2].EndFunc <> nil) then
            StreamOut[x].DSP[x2].EndFunc(StreamOut[x].Data, StreamOut[x].DSP[x2].fftdata);
    end;

  if (StreamOut[x].Data.TypePut = 0) then
    begin
      WriteWave(StreamOut[x].Data.Filename, StreamOut[x].FileBuffer);
      // StreamOut[x].FileBuffer.Data.Free;
    end;

  if (StreamOut[x].Data.TypePut = 4) then
    begin
      WriteWaveFromMem(StreamOut[x].Data.Filename, StreamOut[x].FileBuffer);
      // StreamOut[x].FileBuffer.Data.Free;
    end;

    {$IF DEFINED(sndfile)}
  if (StreamOut[x].Data.TypePut = 6) then
    begin
      sf_write_sync(StreamOut[x].Data.HandleSt);
      sf_close(StreamOut[x].Data.HandleSt);
    end;

  if (StreamOut[x].Data.TypePut = 5) then
    begin
      sf_write_sync(StreamOut[x].Data.HandleSt);
      sf_close(StreamOut[x].Data.HandleSt);
    end;
  {$endif}

 {$IF DEFINED(mse)}
  if EndProc <> nil then
    begin
      application.queueasynccall(EndProc);
    end;
     {$else}

  {$IF not DEFINED(Library)}
  if EndProc <> nil then
  {$IF FPC_FULLVERSION>=20701}
    thethread.{$IF DEFINED(usequeue)}Queue{$else}Synchronize{$endif}(thethread,EndProc);
  {$else}
  thethread.{$IF DEFINED(usequeue)}Queue{$else}Synchronize{$endif}(thethread,EndProc);
  //  Execute EndProc procedure
  {$endif}

  {$elseif not DEFINED(java)}
  if (EndProc <> nil) then
    EndProc;
  {$else}
  if (EndProc <> nil) then
  {$IF FPC_FULLVERSION>=20701}
    thethread.{$IF DEFINED(usequeue)}Queue{$else}Synchronize{$endif}(thethread,@endprocjava);
  {$else}
  thethread.{$IF DEFINED(usequeue)}Queue{$else}Synchronize{$endif}(thethread,@endprocjava);
  //  Execute EndProc procedure
  {$endif}

  {$endif}
   {$endif}

   {$IF DEFINED(portaudio)}
  for x := 0 to high(StreamOut) do
    if (StreamOut[x].Data.HandleSt <> nil) and
       (StreamOut[x].Data.TypePut = 1) then
      Pa_StopStream(StreamOut[x].Data.HandleSt);
   {$ENDIF}

  if EndProcOnly <> nil then EndProcOnly;

  StreamIn[x].Data.Poseek := 0;
  // set to begin
  doseek(x);

  Status := 2;

  if isGlobalPause = true then
    begin
      RTLeventReSetEvent(uosInit.evGlobalPause)
    end
  else
    begin
      RTLeventReSetEvent(evPause);
    end;

end;

procedure Tuos_Player.DoTerminatePlayer;
var 
  x, x2 : integer;
begin

  if length(PlugIn) > 0 then
    begin
      for x := 0 to high(PlugIn) do
        begin
   {$IF DEFINED(soundtouch)}
          if Plugin[x].Name = 'soundtouch' then
            begin
              soundtouch_clear(Plugin[x].PlugHandle);
              soundtouch_destroyInstance(Plugin[x].PlugHandle);
            end;

          if Plugin[x].Name = 'getbpm' then
            begin
              bpm_destroyInstance(Plugin[x].PlugHandle);
            end;
   {$endif}

   {$IF DEFINED(bs2b)}
          if Plugin[x].Name = 'bs2b' then
            begin
              bs2b_close(Plugin[x].Abs2b);
            end;
   {$endif}
        end;
    end;

  {$IF DEFINED(uos_debug) and DEFINED(unix)}
  writeln('Destroy DSP In');
  {$endif}

  for x := 0 to high(StreamIn) do
    begin
      if (length(StreamIn[x].DSP) > 0) then
        for x2 := 0 to high(StreamIn[x].DSP) do
          if (StreamIn[x].DSP[x2].EndFunc <> nil) then
            StreamIn[x].DSP[x2].EndFunc(StreamIn[x].Data, StreamIn[x].DSP[x2].fftdata);
    end;

  {$IF DEFINED(uos_debug) and DEFINED(unix)}
  writeln('Destroy DSP Out');
  {$endif}

  for x := 0 to high(StreamOut) do
    begin
      if (assigned(StreamOut[x].DSP)) and  (assigned(StreamOut[x]))  then if  (length(StreamOut[x].
                                                                             DSP) > 0) then
                                                                            for x2 := 0 to high(
                                                                                StreamOut[x].DSP) do
                                                                              if (StreamOut[x].DSP[
                                                                                 x2].EndFunc <> nil)
                                                                                then
                                                                                StreamOut[x].DSP[x2]
                                                                                .EndFunc(StreamOut[x
                                                                                         ].Data,
                                                                                         StreamOut[x
                                                                                         ].DSP[x2].
                                                                                         fftdata);
    end;

  for x := 0 to high(StreamIn) do
    if assigned(StreamIn[x].Data.HandleSt) then if (StreamIn[x].Data.HandleSt <> nil) then
                                                  case StreamIn[x].Data.TypePut of 
                                                    0: case StreamIn[x].Data.LibOpen of 
   {$IF DEFINED(sndfile)}
                                                         0: sf_close(StreamIn[x].Data.HandleSt);
   {$endif}
   {$IF DEFINED(mpg123)}
                                                         1:
                                                            begin
                                                              mpg123_close(StreamIn[x].Data.HandleSt
                                                              );
                                                              mpg123_delete(StreamIn[x].Data.
                                                                            HandleSt);
                                                            end;
   {$ENDIF}
   {$IF DEFINED(neaac)}
                                                         2 :
                                                             begin
                                                               MP4CloseFile(StreamIn[x].AACI);
                                                             end;
   {$endif}
   {$IF DEFINED(cdrom)}
                                                         3:
                                                            begin
                                                              CDROM_Close(StreamIn[x].pCD);
                                                            end;
   {$endif}
   {$IF DEFINED(opus)}
                                                         4:
                                                            begin
                                                              op_free(StreamIn[x].Data.HandleOP);
                                                              sleep(50);
                                                              // needed ?
                                                            end;
   {$ENDIF}

    {$IF DEFINED(xmp)}
                                                         5:
                                                            begin
                                                              xmp_end_player(StreamIn[x].Data.
                                                                             HandleSt);
                                                              xmp_release_module(StreamIn[x].Data.
                                                                                 HandleSt);
                                                              xmp_free_context(StreamIn[x].Data.
                                                                               HandleSt);
                                                            end;
   {$ENDIF}

                                                         99: // if nothing was defined

                                                       end;

   {$IF DEFINED(portaudio)}
                                                    1:
                                                       begin
                                                         Pa_StopStream(StreamIn[x].Data.HandleSt);
                                                         Pa_CloseStream(StreamIn[x].Data.HandleSt);
                                                       end;
   {$endif}

   {$IF DEFINED(webstream)}
                                                    2:
                                                       begin
                                                         StreamIn[x].httpget.Terminate;
                                                         sleep(100);
                                                         StreamIn[x].inpipe.destroy;
                                                         StreamIn[x].outpipe.destroy;

                                                         case StreamIn[x].Data.LibOpen of 
   {$IF DEFINED(mpg123)}
                                                           1:
                                                              begin
                                                                mpg123_close(StreamIn[x].Data.
                                                                             HandleSt);
                                                                mpg123_delete(StreamIn[x].Data.
                                                                              HandleSt);
                                                              end;
   {$ENDIF}
   {$IF DEFINED(opus)}
                                                           4:
                                                              begin
                                                                op_free(StreamIn[x].Data.HandleOP);
                                                                sleep(50);
                                                                // needed ?
                                                              end;
   {$ENDIF}
   {$IF DEFINED(fdkaac)}
                                                           2 :
                                                               begin
                                                                 aacDecoder_Close(StreamIn[x].Data.
                                                                                  HandleSt);
                                                               end;
    {$ENDIF}
                                                         end;
                                                       end;
   {$ENDIF}

                                                  end;

  for x := 0 to high(StreamOut) do
    begin
   {$IF DEFINED(portaudio)}
      if (StreamOut[x].Data.HandleSt <> nil) and
         (StreamOut[x].Data.TypePut = 1) then
        begin
          Pa_StopStream(StreamOut[x].Data.HandleSt);
          Pa_CloseStream(StreamOut[x].Data.HandleSt);
        end;
   {$ENDIF}

   {$IF DEFINED(shout)}
      if  (StreamOut[x].Data.TypePut = 2) then
        begin
          //  freeandnil(StreamOut[x].encoder) ;
          shout_free(StreamOut[x].Data.HandleSt);

        end;
   {$endif}

      if (StreamOut[x].Data.TypePut = 0) then
        begin
          WriteWave(StreamOut[x].Data.Filename, StreamOut[x].FileBuffer);
          //  StreamOut[x].FileBuffer.Data.Free;
        end;

      if (StreamOut[x].Data.TypePut = 4) then
        begin
          WriteWaveFromMem(StreamOut[x].Data.Filename, StreamOut[x].FileBuffer);
          StreamOut[x].FileBuffer.Data.Free;
        end;

    {$IF DEFINED(sndfile)}

      if (StreamOut[x].Data.TypePut = 6) then
        begin
          sf_close( StreamOut[x].Data.HandleSt);
        end;

      if (StreamOut[x].Data.TypePut = 7) then
        begin
          sf_close( StreamOut[x].Data.HandleSt);
        end;
    {$endif}

    end;


end;

procedure Tuos_Player.DoMainLoopProc(x: integer);
{$IF (FPC_FULLVERSION < 20701) and DEFINED(fpgui)}
var 
  msg: TfpgMessageParams;
  // for fpgui
 {$endif}
begin

 {$IF DEFINED(mse)}
  if StreamIn[x].LoopProc <> nil then
    begin
      application.queueasynccall(StreamIn[x].LoopProc);
    end;
     {$else}

  // The synchro main loop procedure
  {$IF not DEFINED(Library)}
  if StreamIn[x].LoopProc <> nil then
  {$IF FPC_FULLVERSION>=20701}
    thethread.{$IF DEFINED(usequeue)}Queue{$else}Synchronize{$endif}(thethread,StreamIn[x].LoopProc)
  ;
  {$else}
  {$IF (FPC_FULLVERSION < 20701) and DEFINED(fpgui)}
  begin
    msg.user.Param1 := -1 ;
    // it is the main loop procedure
    msg.user.Param2 := 0 ;
    //  it is a INput procedure
    fpgPostMessage(self, refer, MSG_CUSTOM1, msg);
  end;
  {$else}
  thethread.{$IF DEFINED(usequeue)}Queue{$else}Synchronize{$endif}(thethread,StreamIn[x].LoopProc);
  {$endif}
  {$endif}

  {$elseif not DEFINED(java)}
  if (StreamIn[x].LoopProc <> nil) then
    StreamIn[x].LoopProc;
  {$else}
  if (StreamIn[x].LoopProc <> nil) then
  {$IF FPC_FULLVERSION>=20701}
    thethread.{$IF DEFINED(usequeue)}Queue{$else}Synchronize{$endif}(thethread,@Streamin[x].
                                                                     LoopProcjava);
  {$else}
  thethread.{$IF DEFINED(usequeue)}Queue{$else}Synchronize{$endif}(thethread,@Streamin[x].
                                                                   LoopProcjava);
  {$endif}
  {$endif}
   {$endif}
end;

procedure Tuos_Player.DoBeginMethods;
{$IF (FPC_FULLVERSION < 20701) and DEFINED(fpgui)}
var 
  msg: TfpgMessageParams;
  // for fpgui
 {$endif}
begin
{$IF DEFINED(mse)}
  if BeginProc <> nil then
    begin
      application.queueasynccall(BeginProc);
    end;
 {$else}

 {$IF not DEFINED(Library)}
  if BeginProc <> nil then
    //  Execute BeginProc procedure
  {$IF FPC_FULLVERSION>=20701}
    thethread.{$IF DEFINED(usequeue)}Queue{$else}Synchronize{$endif}(thethread,BeginProc);
  {$else}
  {$IF (FPC_FULLVERSION < 20701) and DEFINED(fpgui)}
  begin
    msg.user.Param1 := -2 ;
    // it is the first proc
    fpgPostMessage(self, refer, MSG_CUSTOM1, msg);
  end;
  {$else}
  thethread.{$IF DEFINED(usequeue)}Queue{$else}Synchronize{$endif}(thethread,BeginProc);
  {$endif}
  {$endif}
  {$elseif not DEFINED(java)}
  if BeginProc <> nil then
    BeginProc;
  {$else}
  if BeginProc <> nil then
  {$IF FPC_FULLVERSION>=20701}
    thethread.{$IF DEFINED(usequeue)}Queue{$else}Synchronize{$endif}(thethread,@BeginProcjava);
  {$else}
  thethread.{$IF DEFINED(usequeue)}Queue{$else}Synchronize{$endif}(thethread,@BeginProcjava);
  {$endif}
  {$endif}
  {$endif}
end;

procedure Tuos_Player.DoLoopBeginMethods;
{$IF (FPC_FULLVERSION < 20701) and DEFINED(fpgui)}
var 
  msg: TfpgMessageParams;
  // for fpgui
 {$endif}
begin
{$IF DEFINED(mse)}
  if LoopBeginProc <> nil then
    begin
      application.queueasynccall(LoopBeginProc);
    end;
 {$else}
  {$IF not DEFINED(Library)}
  if LoopBeginProc <> nil then
    //  Execute BeginProc procedure
  {$IF FPC_FULLVERSION>=20701}
    thethread.{$IF DEFINED(usequeue)}Queue{$else}Synchronize{$endif}(thethread,LoopBeginProc);
  {$else}
  {$IF (FPC_FULLVERSION < 20701) and DEFINED(fpgui)}
  begin
    msg.user.Param1 := -2 ;
    // it is the first proc
    fpgPostMessage(self, refer, MSG_CUSTOM1, msg);
  end;
  {$else}
  thethread.{$IF DEFINED(usequeue)}Queue{$else}Synchronize{$endif}(thethread,LoopBeginProc);
  {$endif}
  {$endif}
  {$elseif not DEFINED(java)}
  if loopBeginProc <> nil then
    loopBeginProc;
  {$else}
  if loopBeginProc <> nil then
  {$IF FPC_FULLVERSION>=20701}
    thethread.{$IF DEFINED(usequeue)}Queue{$else}Synchronize{$endif}(thethread,@loopBeginProcjava);
  {$else}
  thethread.{$IF DEFINED(usequeue)}Queue{$else}Synchronize{$endif}(thethread,@loopBeginProcjava);
  {$endif}
  {$endif}
  {$endif}
end;

procedure Tuos_Player.WriteOut(x:integer;  x2 : integer);
var 
  err, rat, wantframestemp: integer;

{$IF DEFINED(uos_debug) and DEFINED(unix)}
  st : string;
  i : integer;
{$endif}
  Bufferst2mo: TDArFloat;
begin
  // Convert Input format into Output format if needed:
 {$IF DEFINED(uos_debug) and DEFINED(unix)}
  writeln('Convert Input format into Output');
 {$endif}
  case StreamOut[x].Data.SampleFormat of 
    0: case StreamIn[x2].Data.SampleFormat of 
         1: StreamOut[x].Data.Buffer := 
                                        CvInt32toFloat32(StreamOut[x].Data.Buffer);
         2: StreamOut[x].Data.Buffer := 
                                        CvInt16toFloat32(StreamOut[x].Data.Buffer);
       end;
  end;
  // End convert.
 {$IF DEFINED(uos_debug) and DEFINED(unix)}
  writeln('Finally give buffer to output');
 {$endif}

  // writeln(inttostr(StreamOut[x].Data.TypePut));

  // Finally give buffer to output
  case StreamOut[x].Data.TypePut of 
  {$IF DEFINED(portaudio)}
    1: // Give to output device using portaudio
       begin

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
         writeln('Give to output device');
         writeln('length(StreamOut[x].Data.Buffer) =' + inttostr(length(StreamOut[x].Data.Buffer)));
 {$endif}

         if (StreamIn[x2].Data.TypePut <> 1) or
            ((StreamIn[x2].Data.TypePut = 1) and (StreamIn[x2].Data.Channels > 1)) then
           begin
  {$IF DEFINED(uos_debug) and DEFINED(unix)}
             st := '';
             for i := 0 to length(StreamOut[x].Data.Buffer) -1 do
               st := st + '|' + inttostr(i) + '=' + floattostr(StreamOut[x].Data.Buffer[i]);
             WriteLn('OUTPUT DATA into portaudio------------------------------');
             //WriteLn(st);
  {$endif}

             //  err :=// if you want clean buffer

             if assigned(StreamOut[x].Data.HandleSt) then
               Pa_WriteStream(StreamOut[x].Data.HandleSt,
                              @StreamOut[x].Data.Buffer[0], StreamIn[x2].Data.outframes Div StreamIn
                              [x2].Data.ratio);

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
             writeln('give to output device 1');
{$endif}
           end
         else
           begin
             // err :=// if you want clean buffer
             Pa_WriteStream(StreamOut[x].Data.HandleSt,
                            @StreamOut[x].Data.Buffer[0], StreamIn[x2].Data.outframes);
           end;
         // if err <> 0 then status := 0;// if you want clean buffer ...
{$IF DEFINED(uos_debug) and DEFINED(unix)}
         writeln('End give to output device 2');
{$endif}
       end;
  {$endif}


  {$IF DEFINED(shout)}
    2: // Give to IceCast server
       begin

{$IF DEFINED(uos_debug) and DEFINED(unix)}
         writeln('Give to output IceCast server');
 {$endif}

         case StreamOut[x].Data.SampleFormat of 
           0:
              begin
                err := opus_encode_float(StreamOut[x].encoder,  @StreamOut[x].Data.Buffer[0],
                       cFRAME_SIZE*3, StreamOut[x].cbits, cMAX_PACKET_SIZE);
              end;
           1:
              begin
                err := opus_encode(StreamOut[x].encoder,  @StreamOut[x].Data.Buffer[0], cFRAME_SIZE*
                       3, StreamOut[x].cbits, cMAX_PACKET_SIZE);
              end;
           2:
              begin
                err := opus_encode(StreamOut[x].encoder, @StreamOut[x].Data.Buffer[0], cFRAME_SIZE*3
                       , StreamOut[x].cbits, cMAX_PACKET_SIZE);
              end;
         end;

         StreamOut[x].data.outframes := err;

{$IF DEFINED(uos_debug) and DEFINED(unix)}
         WriteLn('opus_encode outframes =' + inttostr(err));
         WriteLn('----------------------------------');
         //  writeln(tencoding.utf8.getstring(StreamOut[x].cbits));
  {$endif}

         if err > 0 then

           err := shout_send_raw(StreamOut[x].Data.HandleSt, StreamOut[x].cbits, StreamOut[x].data.
                  outframes);

{$IF DEFINED(uos_debug) and DEFINED(unix)}
         if err = SHOUTERR_SUCCESS then
           WriteLn('shout_send ok ' + inttostr(err))
         else
           WriteLn('shout_send error: '+ inttostr(err) + ' ' + pchar(shout_get_error(StreamOut[x].
                                                                     Data.HandleSt)));
         writeln('End give output to IceCast server');
 {$endif}

         shout_sync(StreamOut[x].Data.HandleSt);
       end;
  {$endif}

    3:
       begin
         // Give to memory buffer

         wantframestemp := StreamIn[x2].Data.outframes ;

  {$IF DEFINED(uos_debug) and DEFINED(unix)}
         WriteLn('Before Give to memory ------------------------------');
         st := '';
         for i := 0 to wantframestemp -1 do
           st := st + '|' + inttostr(i) + '=' + floattostr(StreamOut[x].Data.Buffer[i]);
         WriteLn(st);
         WriteLn('OUTPUT DATA AFTER5 ------------------------------');
         writeln('Streamout[x].Data.posmem before = '+inttostr( Streamout[x].Data.posmem)) ;

         writeln('StreamIn[x2].Data.outframes * StreamIn[x2].Data.channels = '+inttostr( StreamIn[x2
                 ].Data.outframes * StreamIn[x2].Data.channels)) ;
         writeln('length(tempoutmemory) = '+ inttostr(length(tempoutmemory)));
         writeln('Begin Give to memory buffer');
         writeln('(StreamIn[x2].Data.outframes ) -1 = ' +
                 inttostr((StreamIn[x2].Data.outframes) -1));
 {$endif}

         if StreamIn[x2].Data.numbuf > -1 then
           begin
             // writeln('theinc = ' +  inttostr(theinc));
             inc(theinc);
             if theinc > StreamIn[x2].Data.numbuf then status := 0 ;
           end;

         SetLength(Streamout[x].BufferOut^,length(Streamout[x].BufferOut^) + wantframestemp );

         Streamout[x].Data.posmem := length(Streamout[x].BufferOut^) -  wantframestemp;

         for x2 := 0 to (wantframestemp) -1 do
           begin
             Streamout[x].BufferOut^[Streamout[x].Data.posmem + x2] := StreamOut[x].Data.Buffer[x2];
           end;
         Streamout[x].Data.posmem := Streamout[x].Data.posmem + (wantframestemp);

         //  if Streamout[x].Data.SampleFormat > 0 then
         //StreamOut[x].Data.Buffer := ConvertSampleFormat(StreamOut[x].Data);

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
         writeln('Streamout[x].Data.posmem after = '+inttostr( Streamout[x].Data.posmem)) ;
         st := '';
         for i := 0 to length(tempoutmemory) -1 do
           st := st + '|' + inttostr(i) + '=' + floattostr(tempoutmemory[i]);
         WriteLn('OUTPUT DATA AFTER5 ------------------------------');
         //WriteLn(st);
 {$endif}

       end;

    4: // Give to wav file from TMemoryStream
       begin

         case StreamOut[x].Data.SampleFormat of 
           0: rat := 2 ;
           1: rat := 2 ;
           2: rat := 1 ;
         end;

         if (StreamOut[x].FileBuffer.wChannels = 1) and (StreamIn[x2].Data.Channels = 2) then
           begin

             Bufferst2mo  := CvSteroToMono(StreamOut[x].Data.Buffer, StreamIn[x2].Data.outframes);

             StreamOut[x].FileBuffer.DataMS.WriteBuffer(
                                                        Bufferst2mo[0],
                                                        StreamIn[x2].Data.outframes * rat);
           end
         else
           if (StreamOut[x].FileBuffer.wChannels = 1) and (StreamIn[x2].Data.Channels = 1) then
             begin
               StreamOut[x].FileBuffer.DataMS.WriteBuffer(
                                                          StreamOut[x].Data.Buffer[0],  StreamIn[x2]
                                                          .Data.outframes * StreamIn[x2].Data.ratio
                                                          * rat * 2);
             end
         else

           StreamOut[x].FileBuffer.DataMS.WriteBuffer(
                                                      StreamOut[x].Data.Buffer[0],  StreamIn[x2].
                                                      Data.outframes * StreamIn[x2].Data.Channels *
                                                      rat);
       end;

  {$IF DEFINED(sndfile)}
    5: // Give to MemoryStream
       begin

         if StreamIn[x2].Data.TypePut = 1 then rat := StreamIn[x2].Data.Channels
         else rat := 1;

         // writeln('MemoryStream');

         if assigned(StreamOut[x].MemorySteamOut) then

           case StreamOut[x].Data.SampleFormat of 

             0: StreamOut[x].Data.OutFrames := 
                                               sf_write_float(StreamOut[x].Data.HandleSt,
                                               @StreamOut[x].Data.Buffer[0], StreamOut[x].Data.
                                               Wantframes *rat );
             1: StreamOut[x].Data.OutFrames := 
                                               sf_write_int(StreamOut[x].Data.HandleSt,
                                               @StreamOut[x].Data.Buffer[0], StreamOut[x].Data.
                                               Wantframes *rat );
             2: StreamOut[x].Data.OutFrames := 
                                               sf_write_short(StreamOut[x].Data.HandleSt,
                                               @StreamOut[x].Data.Buffer[0], StreamOut[x].Data.
                                               Wantframes *rat);
           end;
       end;

    6: // give to ogg file from Tfilestream
       begin
         //writeln('ok ogg');


  // if StreamIn[x2].Data.outframes = StreamOut[x].Data.Wantframes * StreamOut[x].Data.channels then
         case StreamOut[x].Data.SampleFormat of 
           0: StreamOut[x].Data.OutFrames := 
                                             sf_write_float(StreamOut[x].Data.HandleSt,
                                             @StreamOut[x].Data.Buffer[0], StreamOut[x].Data.
                                             Wantframes * StreamOut[x].Data.channels);
           1: StreamOut[x].Data.OutFrames := 
                                             sf_write_int(StreamOut[x].Data.HandleSt,
                                             @StreamOut[x].Data.Buffer[0], StreamOut[x].Data.
                                             Wantframes * StreamOut[x].Data.channels);
           2: StreamOut[x].Data.OutFrames := 
                                             sf_write_short(StreamOut[x].Data.HandleSt,
                                             @StreamOut[x].Data.Buffer[0], StreamOut[x].Data.
                                             Wantframes * StreamOut[x].Data.channels);
         end;
         sf_write_sync(StreamOut[x].Data.HandleSt);
         // writeln(inttostr(StreamOut[x].Data.OutFrames));
       end;

 {$endif}


    0: // Give to wav file from TFileStream
       begin
         case StreamOut[x].Data.SampleFormat of 
           0: rat := 2 ;
           1: rat := 2 ;
           2: rat := 1 ;
         end;

         if (StreamOut[x].FileBuffer.wChannels = 1) and (StreamIn[x2].Data.Channels = 2) then
           begin

             Bufferst2mo  := CvSteroToMono(StreamOut[x].Data.Buffer, StreamIn[x2].Data.outframes);

             StreamOut[x].FileBuffer.Data.WriteBuffer(
                                                      Bufferst2mo[0],
                                                      StreamIn[x2].Data.outframes * rat);
           end
         else
           if (StreamOut[x].FileBuffer.wChannels = 1) and (StreamIn[x2].Data.Channels = 1) then
             begin
               StreamOut[x].FileBuffer.Data.WriteBuffer(
                                                        StreamOut[x].Data.Buffer[0],  StreamIn[x2].
                                                        Data.outframes * StreamIn[x2].Data.ratio *
                                                        rat * 2);
             end
         else

           StreamOut[x].FileBuffer.Data.WriteBuffer(
                                                    StreamOut[x].Data.Buffer[0],  StreamIn[x2].Data.
                                                    outframes * StreamIn[x2].Data.Channels * rat);
       end;

  end;
end;

procedure Tuos_Player.WriteOutPlug(x:integer;  x2 : integer);
var 
  x3, x4, err, wantframestemp: integer;
  {$IF DEFINED(uos_debug) and DEFINED(unix)}
  st : string;
  i : integer;
 {$endif}
  BufferplugINFLTMP: TDArFloat;
  BufferplugFL: TDArFloat;
  BufferplugSH: TDArShort;
  BufferplugLO: TDArLong;
  Bufferst2mo: TDArFloat;
begin
  // convert buffer if needed
  case StreamOut[x].Data.SampleFormat of 
    1: StreamOut[x].Data.Buffer := 
                                   CvInt32toFloat32(StreamOut[x].Data.Buffer);
    2: StreamOut[x].Data.Buffer := 
                                   CvInt16toFloat32(StreamOut[x].Data.Buffer);
  end;

  // transfer buffer out to temp
  SetLength(BufferplugINFLTMP, (StreamIn[x2].Data.outframes) *
  StreamIn[x2].Data.Channels);

  if length(BufferplugINFLTMP) > 2 then
    for x3 := 0 to (length(BufferplugINFLTMP) div 2) - 1 do
      BufferplugINFLTMP[x3] := cfloat(StreamOut[x].Data.Buffer[x3]);

  // dealing with input plugin
  for x3 := 0 to high(PlugIn) do
    begin
      if PlugIn[x3].Enabled = True then
        begin
  {$IF DEFINED(bs2b) or DEFINED(soundtouch) or DEFINED(noiseremoval)}
          BufferplugFL := Plugin[x3].PlugFunc(BufferplugINFLTMP,
                          Plugin[x3].PlugHandle, Plugin[x3].Abs2b, StreamIn[x2].Data,
                          Plugin[x3].param1, Plugin[x3].param2, Plugin[x3].param3, Plugin[x3].param4
                          ,
                          Plugin[x3].param5, Plugin[x3].param6, Plugin[x3].param7, Plugin[x3].param8
                          );
  {$endif}

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
          writeln('PlugFunc: Length(BufferplugINFLTMP,BufferplugFL) = ' +
                  inttostr(Length(BufferplugINFLTMP)) + ' , ' + inttostr(Length(BufferplugFL)));
 {$endif}

          if (length(PlugIn) > 1) then
            begin
              // TO CHECK : works only if SoundTouch is last or only plugin
              for x4 := 0 to length(BufferplugFL) - 1 do
                BufferplugINFLTMP[x4] := cfloat(BufferplugFL[x4]);
            end;
        end;

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
      writeln('2-PlugFunc: Length(BufferplugINFLTMP,BufferplugFL) = ' +
              inttostr(Length(BufferplugINFLTMP)) + ' , ' + inttostr(Length(BufferplugFL)));
 {$endif}
    end;

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
  writeln('Give the processed input to output.');
  writeln('Length(BufferplugFL) = ' + inttostr(Length(BufferplugFL)));
 {$endif}
  if Length(BufferplugFL) > 0 then
    begin

      case StreamOut[x].Data.SampleFormat of 
        1:
           begin
             SetLength(BufferplugLO, length(BufferplugFL));
             BufferplugLO := CvFloat32ToInt32(BufferplugFL);
           end;
        2:
           begin
             SetLength(BufferplugSH, length(BufferplugFL));
             BufferplugSH := CvFloat32ToInt16(BufferplugFL);

           end;
      end;

      case StreamOut[x].Data.TypePut of 

  {$IF DEFINED(portaudio)}
        1: // Give to output device
           begin

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
             writeln('Before Pa_WriteStream: Length(BufferplugFL) = ' + inttostr(Length(BufferplugFL
             )));
 {$endif}
             case StreamOut[x].Data.SampleFormat of 
               0:
                  begin
                    err := 
                           Pa_WriteStream(StreamOut[x].Data.HandleSt,
                           @BufferplugFL[0], Length(BufferplugFL) Div
                           StreamIn[x2].Data.Channels);
                  end;
               1:
                  begin
                    BufferplugLO := CvFloat32ToInt32(BufferplugFL);
                    err := 
                           Pa_WriteStream(StreamOut[x].Data.HandleSt,
                           @BufferplugLO[0], Length(BufferplugLO) Div
                           StreamIn[x2].Data.Channels);
                  end;
               2:
                  begin
                    BufferplugSH := CvFloat32ToInt16(BufferplugFL);

                    err := 
                           Pa_WriteStream(StreamOut[x].Data.HandleSt,
                           @BufferplugSH[0], Length(BufferplugSH) Div
                           StreamIn[x2].Data.Channels);
                  end;
             end;
             // if err <> 0 then status := 0;// if you want clean buffer ...

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
             writeln('Pa_WriteStream error = '+ inttostr(err));
 {$endif}
           end;
  {$endif}

  {$IF DEFINED(shout)}
        2: // Give to IceCast server
           begin

{$IF DEFINED(uos_debug) and DEFINED(unix)}
             writeln('Give to output IceCast server');
 {$endif}

             case StreamOut[x].Data.SampleFormat of 
               0:
                  begin
                    err := opus_encode_float(StreamOut[x].encoder, @BufferplugFL[0], cFRAME_SIZE,
                           StreamOut[x].cbits, cMAX_PACKET_SIZE);
                  end;
               1:
                  begin
                    err := opus_encode(StreamOut[x].encoder, @BufferplugLO[0], cFRAME_SIZE,
                           StreamOut[x].cbits, cMAX_PACKET_SIZE);
                  end;
               2:
                  begin
                    err := opus_encode(StreamOut[x].encoder, @BufferplugSH[0], cFRAME_SIZE,
                           StreamOut[x].cbits, cMAX_PACKET_SIZE);
                  end;
             end;

             StreamOut[x].data.outframes  := err ;

{$IF DEFINED(uos_debug) and DEFINED(unix)}
             WriteLn('opus_encode outframes =' + inttostr(err));
             WriteLn('----------------------------------');
             //  writeln(tencoding.utf8.getstring(StreamOut[x].cbits));
  {$endif}

             if err > 0 then

               err := shout_send(StreamOut[x].Data.HandleSt, StreamOut[x].cbits, StreamOut[x].data.
                      outframes);

{$IF DEFINED(uos_debug) and DEFINED(unix)}
             if err = SHOUTERR_SUCCESS then
               WriteLn('shout_send ok ' + inttostr(err))
             else
               WriteLn('shout_send error: '+ inttostr(err) + ' ' + pchar(shout_get_error(StreamOut[x
                                                                         ].Data.HandleSt)));
             writeln('End give output to IceCast server');
 {$endif}

             shout_sync(StreamOut[x].Data.HandleSt);
             // ?

           end;
  {$endif}

        0:
           begin
             // Give to wav file from TFileStream

             if (StreamOut[x].FileBuffer.wChannels = 1) and (StreamIn[x2].Data.Channels = 2) then
               begin
                 Bufferst2mo :=  CvSteroToMono(BufferplugFL, Length(BufferplugFL) Div 2);
                 BufferplugSH := CvFloat32ToInt16(Bufferst2mo);
               end
             else
               begin
                 BufferplugSH := CvFloat32ToInt16(BufferplugFL);
               end;
             StreamOut[x].FileBuffer.Data.WriteBuffer(BufferplugSH[0],
                                                      Length(BufferplugSH));

           end;

        4:
           begin
             // Give to wav file from TMemoryStream

             if (StreamOut[x].FileBuffer.wChannels = 1) and (StreamIn[x2].Data.Channels = 2) then
               begin
                 Bufferst2mo :=  CvSteroToMono(BufferplugFL, Length(BufferplugFL) Div 2);
                 BufferplugSH := CvFloat32ToInt16(Bufferst2mo);
               end
             else
               begin
                 BufferplugSH := CvFloat32ToInt16(BufferplugFL);
               end;
             StreamOut[x].FileBuffer.DataMS.WriteBuffer(BufferplugSH[0],
                                                        Length(BufferplugSH));

           end;

        5: // Give to MemoryStream
           begin

             case StreamOut[x].Data.SampleFormat of 
               0:  StreamOut[x].MemorySteamOut.WriteBuffer(BufferplugFL[0],
                                                           Length(BufferplugFL));

               1:  StreamOut[x].MemorySteamOut.WriteBuffer(BufferplugLO[0],
                                                           Length(BufferplugLO));

               2:  StreamOut[x].MemorySteamOut.WriteBuffer(BufferplugSH[0],
                                                           Length(BufferplugSH));

             end;
           end;


        3:
           begin
             // Give to memory buffer
             wantframestemp := Length(BufferplugFL) ;
             SetLength(Streamout[x].BufferOut^,length(Streamout[x].BufferOut^) + wantframestemp );

             for x2 := 0 to wantframestemp -1 do
               Streamout[x].BufferOut^[Streamout[x].Data.posmem + x2] := BufferplugFL[x2];

             Streamout[x].Data.posmem := Streamout[x].Data.posmem + wantframestemp;

  {$IF DEFINED(uos_debug) and DEFINED(unix)}
             writeln('Streamout[x].Data.posmem = '+inttostr( Streamout[x].Data.posmem)) ;
             st := '';
             for i := 0 to length(tempoutmemory) -1 do
               st := st + '|' + inttostr(i) + '|' + floattostr(tempoutmemory[i]);
             WriteLn('OUTPUT DATA AFTER4 ------------------------------');
             WriteLn(st);
  {$endif}
           end;

      end;
    end;
end;

{$IF DEFINED(webstream)}
procedure Tuos_Player.ReadUrl(x : integer);
var 
  err : integer;
  
   {$IF DEFINED(fdkaac)}
  FErrorCode    : AAC_DECODER_ERROR;
  FByteFilled, FBytesRead : longword;
  FOutputBuff   : array of cfloat;
  FCStreamInfo  : PCStreamInfo;
  len, len2, len3: integer;
  rawAACBuffer:  PByte;
   {$endif}  
  
{$IF DEFINED(uos_debug) and DEFINED(unix)}
  i : integer;
  st : string;
{$endif}
begin
  case StreamIn[x].Data.LibOpen of 
    1 :
        begin
{$IF DEFINED(mpg123)}

{$IF DEFINED(uos_debug) and DEFINED(unix)}
          writeln('===> Before mpg123_read') ;
{$endif}
          err := 
                 mpg123_read(StreamIn[x].Data.HandleSt, @StreamIn[x].Data.Buffer[0],
                 StreamIn[x].Data.wantframes, StreamIn[x].Data.outframes);

{$IF DEFINED(uos_debug) and DEFINED(unix)}
          writeln('===> mpg123_read error => ' + inttostr(err)) ;
{$endif}
          StreamIn[x].Data.outframes := 
                                        StreamIn[x].Data.outframes Div StreamIn[x].Data.Channels;
{$ENDIF}
        end;
        
    2:
       begin
{$IF DEFINED(fdkaac)}
         setlength(FOutputBuff, StreamIn[x].Data.wantframes);

         GetMem(rawAACBuffer,StreamIn[x].Data.wantframes);

         //   writeln('avant bytesRead');
         FBytesRead := StreamIn[x].InPipe.Read(rawAACBuffer[0],1024);

         // writeln('StreamIn[x].Data.bytesRead ' + inttostr(StreamIn[x].Data.bytesRead));       
        
         FByteFilled := FBytesRead;
         FErrorCode := aacDecoder_Fill(StreamIn[x].Data.HandleSt,@rawAACBuffer, FBytesRead,
                       FByteFilled);

         // writeLn('FByteFilled ' + inttostr(FByteFilled));

         len2 := 0;
         len3 := 0;

         while true do
           begin
             FErrorCode := aacDecoder_DecodeFrame(StreamIn[x].Data.HandleSt, PSmallInt(FOutputBuff),
                           StreamIn[x].Data.wantframes, 0);

             if (FErrorCode <> AAC_DECODER_ERROR.AAC_DEC_OK) then
               begin
                 if FErrorCode = AAC_DECODER_ERROR.AAC_DEC_NOT_ENOUGH_BITS then
                   break;
                 //  writeln(Format('Decode failed: %x', [Integer(FErrorCode)]));
               end;
             // else  writeln('Decode ok ');

             FCStreamInfo := aacDecoder_GetStreamInfo(StreamIn[x].Data.HandleSt);
             if ((not assigned(FCStreamInfo)) or (FCStreamInfo^.sampleRate <= 0)) then
               raise Exception.Create('No stream info');

             for len := 0 to (FCStreamInfo^.frameSize) -1 do

               begin
                 //   writeln(round(FOutputBuff[len]));
                 StreamIn[x].Data.Buffer[len + len2] :=  FOutputBuff[len];
                 //   writeln((StreamIn[x].Data.Buffer[len + len2]));
                 inc(len3);
               end;
             len2 := len2 + FCStreamInfo^.frameSize;
           end;
        
         //  StreamIn[x].Data.outframes := len3 * StreamIn[x].Data.Channels;
         StreamIn[x].Data.outframes := len3 * 2;

         if StreamIn[x].Data.SampleFormat < 2 then
           begin
             StreamIn[x].Data.Buffer := CvInt16ToFloat32(StreamIn[x].Data.Buffer);
             if StreamIn[x].Data.SampleFormat = 1 then
               StreamIn[x].Data.Buffer := CvFloat32toInt32fl(StreamIn[x].Data.Buffer, length(
                                          StreamIn[x].Data.Buffer));
           end;

         freemem(rawAACBuffer);

         //  writeln('---------- FIN read url ok ');
{$ENDIF}
       end;        
        
    4 :
        begin
{$IF DEFINED(opus)}

{$IF DEFINED(uos_debug) and DEFINED(unix)}
          writeln('===> Before op_read_x.') ;
{$endif}

          case StreamIn[x].Data.SampleFormat of 
            0:
               begin
                 StreamIn[x].Data.outframes := cint(op_read_float(StreamIn[x].Data.HandleOP,
                                               @StreamIn[x].Data.Buffer[0], cint(StreamIn[x].Data.
                                               Wantframes
                                               Div StreamIn[x].Data.channels) , Nil));
               end;
            1:
               begin
                 StreamIn[x].Data.outframes := cint(op_read_float(StreamIn[x].Data.HandleOP,
                                               @StreamIn[x].Data.Buffer[0], cint(StreamIn[x].Data.
                                               Wantframes
                                               Div StreamIn[x].Data.channels), Nil));

                 // no int32 format with opus => need a conversion from float32 to int32.
                 StreamIn[x].Data.Buffer := Cvfloat32ToInt32fl( StreamIn[x].Data.Buffer,
                                            StreamIn[x].Data.outframes * StreamIn[x].Data.Channels )
                 ;
               end;
            2:
               begin

                 StreamIn[x].Data.outframes := cint( op_read(StreamIn[x].Data.HandleOP,
                                               @StreamIn[x].Data.Buffer[0], cint(StreamIn[x].Data.
                                               Wantframes
                                               Div StreamIn[x].Data.channels), Nil));

               end;
          end;

          setlength(StreamIn[x].data.Buffer, StreamIn[x].Data.outframes * StreamIn[x].Data.Channels)
          ;

{$IF DEFINED(uos_debug) and DEFINED(unix)}
          writeln('Seek outframes = '+inttostr(StreamIn[x].Data.outframes)) ;
          st := '';
          for i := 0 to length(StreamIn[x].data.Buffer) -1 do
            st := st + '|' + inttostr(i) + '|' + floattostr(StreamIn[x].data.Buffer[i]);
          WriteLn('OUTPUT DATA AFTER1 ------------------------------');
          //  WriteLn(st);
          writeln(' StreamIn[x].Data.outframes = '+inttostr(StreamIn[x].Data.outframes * StreamIn[x]
                  .Data.Channels)) ;
{$endif}

          if StreamIn[x].Data.outframes < 0 then StreamIn[x].Data.outframes := 0 ;

{$ENDIF}
        end;
  end;

  if (StreamIn[x].Data.TypePut = 2) and ((StreamIn[x].Data.LibOpen = 1 ) or (StreamIn[x].Data.
     LibOpen = 4 )) then
    begin
      if StreamIn[x].httpget.IsRunning = false then  StreamIn[x].Data.status := 0;
      // no more data then close the stream
  {$IF DEFINED(uos_debug) and DEFINED(unix)}
      writeln('Check if internet is stopped.');
  {$endif}
    end;

end;
{$endif}

procedure Tuos_Player.ReadFile(x : integer);
{$IF DEFINED(neaac) or DEFINED(uos_debug)}
var 
{$endif}
{$IF DEFINED(neaac)}
  outBytes: longword;
{$endif}
{$IF DEFINED(uos_debug) and DEFINED(unix)}
  i : integer;
  st : string;
{$endif}
begin

  if length(StreamIn[x].Data.Buffer) <> StreamIn[x].Data.Wantframes then
    setlength(StreamIn[x].Data.Buffer,StreamIn[x].Data.Wantframes);

  case StreamIn[x].Data.LibOpen of 
    // Here we are, reading the data and store it in buffer
 {$IF DEFINED(sndfile)}
    0:
       begin
 {$IF DEFINED(uos_debug) and DEFINED(unix)}
         WriteLn('Before sf_read ' + inttostr(StreamIn[x].Data.Wantframes) +
         ' length(StreamIn[x].Data.Buffer ' +
         inttostr(length(StreamIn[x].Data.Buffer)));
 {$endif}
         case StreamIn[x].Data.SampleFormat of 
           0: StreamIn[x].Data.OutFrames := 
                                            sf_read_float(StreamIn[x].Data.HandleSt,
                                            @StreamIn[x].Data.Buffer[0], StreamIn[x].Data.Wantframes
                                            );
           1: StreamIn[x].Data.OutFrames := 
                                            sf_read_int(StreamIn[x].Data.HandleSt,
                                            @StreamIn[x].Data.Buffer[0], StreamIn[x].Data.Wantframes
                                            );
           2: StreamIn[x].Data.OutFrames := 
                                            sf_read_short(StreamIn[x].Data.HandleSt,
                                            @StreamIn[x].Data.Buffer[0], StreamIn[x].Data.Wantframes
                                            );
         end;

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
         writeln(inttostr(StreamIn[x].Data.lastbuf));
         WriteLn('after sf_read');
 {$endif}
         if  StreamIn[x].Data.outframes < 0 then  StreamIn[x].Data.outframes := 0 ;

         if (StreamIn[x].Data.lastbuf < 0) and (StreamIn[x].Data.outframes < StreamIn[x].Data.
            wantframes) then
           begin
             StreamIn[x].Data.outframes := StreamIn[x].Data.wantframes;
             StreamIn[x].Data.lastbuf := StreamIn[x].Data.lastbuf -1;
             if StreamIn[x].Data.lastbuf = -9 then StreamIn[x].Data.lastbuf := 0;
           end;

         setlength(StreamIn[x].data.Buffer,StreamIn[x].Data.outframes);

{$IF DEFINED(uos_debug) and DEFINED(unix)}
         st := '';

         for i := 0 to length(StreamIn[x].data.Buffer) -1 do
           case StreamIn[x].Data.SampleFormat of 
             0: st := st + '|' + inttostr(i) + '=' + floattostr(StreamIn[x].data.Buffer[i]);
             1: st := st + '|' + inttostr(i) + '=' + inttostr(cint32(StreamIn[x].data.Buffer[i]));
             2: st := st + '|' + inttostr(i) + '=' + inttostr(cint16(cint32(StreamIn[x].data.Buffer[
                      i])));
           end;

         WriteLn('OUTPUT DATA sf_read_() ---------------------------');
         WriteLn('StreamIn[x].Data.outframes = ' + inttostr(StreamIn[x].Data.outframes));
         WriteLn(st);
 {$endif}

       end;
 {$endif}
 {$IF DEFINED(mpg123)}
    1:
       begin

         mpg123_read(StreamIn[x].Data.HandleSt, @StreamIn[x].Data.Buffer[0],
                     StreamIn[x].Data.wantframes, StreamIn[x].Data.outframes);

         if  StreamIn[x].Data.outframes < 0 then  StreamIn[x].Data.outframes := 0 ;

         setlength(StreamIn[x].data.Buffer,StreamIn[x].Data.outframes Div
                   (StreamIn[x].Data.channels) );

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
         st := '';
         for i := 0 to length(StreamIn[x].data.Buffer) -1 do
           case StreamIn[x].Data.SampleFormat of 
             0: st := st + '|' + floattostr(StreamIn[x].data.Buffer[i]);
             1: st := st + '|' + inttostr(cint32(StreamIn[x].data.Buffer[i]));
             2: st := st + '|' + inttostr(cint16(cint32(StreamIn[x].data.Buffer[i])));
           end;
         WriteLn('OUTPUT DATA mpg123_read_() ---------------------------');
         // WriteLn(st);
 {$endif}

         StreamIn[x].Data.outframes := 
                                       StreamIn[x].Data.outframes Div StreamIn[x].Data.Channels;
       end;
 {$endif}

 {$IF DEFINED(neaac)}
    2 :
        begin
          StreamIn[x].AACI.lwDataLen := 0;
          case StreamIn[x].AACI.outputFormat of 
            FAAD_FMT_16BIT, FAAD_FMT_32BIT, FAAD_FMT_FLOAT :
                                                             begin
                                                               outBytes := StreamIn[x].Data.
                                                                           Wantframes;
                                                               MP4GetData(StreamIn[x].AACI, StreamIn
                                                                          [x].AACI.pData, outBytes);
                                                               Move(StreamIn[x].AACI.pData^,
                                                                    StreamIn[x].Data.Buffer[0],
                                                                    outBytes);
                                                               StreamIn[x].AACI.lwDataLen := 

                                                                                            outBytes
                                                               ;
                                                             end;
          end;
          if StreamIn[x].AACI.lwDataLen > (StreamIn[x].AACI.BitsPerSample div 8) then
            StreamIn[x].Data.outframes := trunc(StreamIn[x].AACI.lwDataLen Div (StreamIn[x].AACI.
                                          BitsPerSample Div 8))
          else
            StreamIn[x].Data.outframes := 0;

          if  StreamIn[x].Data.outframes < 0 then  StreamIn[x].Data.outframes := 0 ;


     //  setlength(StreamIn[x].data.Buffer,StreamIn[x].Data.outframes * StreamIn[x].Data.channels );

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
          st := '';
          for i := 0 to length(StreamIn[x].data.Buffer) -1 do
            case StreamIn[x].Data.SampleFormat of 
              0: st := st + '|' + floattostr(StreamIn[x].data.Buffer[i]);
              1: st := st + '|' + inttostr(cint32(StreamIn[x].data.Buffer[i]));
              2: st := st + '|' + inttostr(cint16(cint32(StreamIn[x].data.Buffer[i])));
            end;
          WriteLn('OUTPUT DATA MP4GetData() ---------------------------');
          // WriteLn(st);
 {$endif}

        end;
 {$endif}

 {$IF DEFINED(cdrom)}
    3:
       begin
         StreamIn[x].pCD^.pDataLen := 0;
         case StreamIn[x].pCD^.BitsPerSample of 
           16 :
                begin
                  outBytes  := StreamIn[x].Data.Wantframes;
                  CDROM_GetData(StreamIn[x].pCD, StreamIn[x].pCD^.pData, outBytes);
                  Move(StreamIn[x].pCD^.pData^, StreamIn[x].Data.Buffer[0], outBytes);
                  StreamIn[x].pCD^.pDataLen := outBytes;
                end;
         end;

         if StreamIn[x].pCD^.pDataLen > (StreamIn[x].pCD^.BitsPerSample div 8) then
           StreamIn[x].Data.outframes := StreamIn[x].pCD^.pDataLen Div (StreamIn[x].pCD^.
                                         BitsPerSample Div 8)
         else
           StreamIn[x].Data.outframes := 0;

       end;
 {$endif}

 {$IF DEFINED(opus)}
    4:
       begin

         case StreamIn[x].Data.SampleFormat of 
           0: StreamIn[x].Data.outframes := op_read_float(StreamIn[x].Data.HandleOP,
                                            @StreamIn[x].Data.Buffer[0], cint(StreamIn[x].Data.
                                            Wantframes Div StreamIn[x].Data.channels), Nil);
           1:
              begin
                StreamIn[x].Data.outframes := op_read_float(StreamIn[x].Data.HandleOP,
                                              @StreamIn[x].Data.Buffer[0],cint(StreamIn[x].Data.
                                              Wantframes  Div StreamIn[x].Data.channels), Nil);

                // no int32 format with opus => needs a conversion from float32 to int32.
                StreamIn[x].Data.Buffer := Cvfloat32ToInt32fl( StreamIn[x].Data.Buffer,
                                           StreamIn[x].Data.outframes * StreamIn[x].Data.Channels );
              end;
           2:
              begin
                StreamIn[x].Data.outframes := op_read(StreamIn[x].Data.HandleOP,
                                              @StreamIn[x].Data.Buffer[0], cint(StreamIn[x].Data.
                                              Wantframes), Nil);
              end;

         end;

         setlength(StreamIn[x].data.Buffer,int32(StreamIn[x].Data.outframes * StreamIn[x].Data.
                   Channels));

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
         st := '';
         for i := 0 to length(StreamIn[x].data.Buffer) -1 do
           case StreamIn[x].Data.SampleFormat of 
             0: st := st + '|' + floattostr(StreamIn[x].data.Buffer[i]);
             1: st := st + '|' + inttostr(cint32(StreamIn[x].data.Buffer[i]));
             2: st := st + '|' + inttostr(cint16(cint32(StreamIn[x].data.Buffer[i])));
           end;
         WriteLn('OUTPUT DATA op_read_ ---------------------------');
         // WriteLn(st);
 {$endif}

         if  StreamIn[x].Data.outframes < 0 then  StreamIn[x].Data.outframes := 0 ;
         StreamIn[x].Data.outframes :=  StreamIn[x].Data.outframes * StreamIn[x].Data.Channels ;

       end;
 {$endif}

  {$IF DEFINED(xmp)}
    5:
       begin
 {$IF DEFINED(uos_debug) and DEFINED(unix)}
         WriteLn('Before xmp_play_buffer ' + inttostr(StreamIn[x].Data.Wantframes) +
         ' length(StreamIn[x].Data.Buffer ' +
         inttostr(length(StreamIn[x].Data.Buffer)));
 {$endif}

         if xmp_play_buffer(StreamIn[x].Data.HandleSt,
            @StreamIn[x].Data.Buffer[0], StreamIn[x].Data.Wantframes * StreamIn[x].Data.channels , 0
            ) < 0 then
           StreamIn[x].Data.outframes := 0
         else
           begin
             StreamIn[x].Data.outframes := StreamIn[x].Data.Wantframes;

             if StreamIn[x].Data.SampleFormat < 2 then
               begin
                 StreamIn[x].Data.Buffer := CvInt16ToFloat32(StreamIn[x].Data.Buffer);
                 if StreamIn[x].Data.SampleFormat = 1 then
                   StreamIn[x].Data.Buffer := CvFloat32toInt32fl(StreamIn[x].Data.Buffer, length(
                                              StreamIn[x].Data.Buffer));
               end;
           end;

   {$IF DEFINED(uos_debug) and DEFINED(unix)}
         writeln(inttostr(StreamIn[x].Data.lastbuf));
         WriteLn('after xmp_play_buffer');
   {$endif}
         setlength(StreamIn[x].data.Buffer,StreamIn[x].Data.outframes);

   {$IF DEFINED(uos_debug) and DEFINED(unix)}

         st := '';

         for i := 0 to length(StreamIn[x].data.Buffer) -1 do
           begin
             st := st + '|' + inttostr(i) + '=' + inttostr(cint16(cint32(StreamIn[x].data.Buffer[
                   i])));
           end;

         WriteLn('OUTPUT DATA xmp_read_ ---------------------------');
         WriteLn('StreamIn[x].Data.outframes = ' + inttostr(StreamIn[x].Data.outframes));
         //  WriteLn(st);
  {$endif}

       end;
 {$endif}

    99: // if nothing was defined
  end;

  SetLength(StreamIn[x].Data.Buffer, StreamIn[x].Data.outframes);
end;

procedure Tuos_Player.CheckIfPaused ;
begin
  if isGlobalPause = true then
    begin
      RTLeventWaitFor(uosInit.evGlobalPause);
      RTLeventSetEvent(uosInit.evGlobalPause);
    end
  else
    begin
      RTLeventWaitFor(evPause);
      // is there a pause waiting ?
      RTLeventSetEvent(evPause);
    end;
end;

{$IF DEFINED(mse)}
function Tuos_Player.execute(thread: tmsethread): integer;
// The Main Loop Procedure
  {$else}
procedure TuosThread.Execute;
// The Main Loop Procedure
  {$endif}
var 
  x, x2, x3 : cint32;
  plugenabled: boolean;
  curpos: cint64 = 0;
  {$IF DEFINED(uos_debug) and DEFINED(unix)}
  st : string;
  i : integer;
   {$endif}

begin

  theinc := 0;


{$IF DEFINED(mse)}
 {$else}
  with  Tuos_Player(theparent) do
    begin
 {$endif}

      CheckIfPaused ;
      // is there a pause waiting ?

      DoBeginMethods();

      CheckIfPaused ;
      // is there a pause waiting ?

      repeat

        if uosisactif then DoLoopBeginMethods
        else nofree := false;

        CheckIfPaused ;
        // is there a pause waiting ?
        // Dealing with input
        for x := 0 to high(StreamIn) do
          begin

            if (StreamIn[x].data.hasfilters) and uosisactif then
              begin
                setlength(StreamIn[x].Data.levelfiltersar,StreamIn[x].Data.nbfilters * StreamIn[x].
                          Data.channels );
                StreamIn[x].Data.incfilters := 0;
              end;

  {$IF DEFINED(uos_debug) and DEFINED(unix)}
            WriteLn('Before for x := 0 to high(StreamIn)');
  {$endif}

            CheckIfPaused ;
            // is there a pause waiting ?

            if (StreamIn[x].Data.Status > 0) and
               (StreamIn[x].Data.Enabled = True) then
              begin

                StreamIn[x].Data.levelfilters := '';

  {$IF DEFINED(uos_debug) and DEFINED(unix)}
                WriteLn('Before StreamIn[x].Data.Seekable = True');
  {$endif}
                if (StreamIn[x].Data.Poseek > -1) and (StreamIn[x].Data.Seekable = True) and
                   uosisactif then
                  begin
                    // there is a seek waiting

                    DoSeek(x);

                    curpos := StreamIn[x].Data.Poseek;
                    StreamIn[x].Data.Poseek := -1;
                  end;

                if (StreamIn[x].Data.positionEnable = 1)  and (StreamIn[x].Data.Seekable = True)
                  then
                  StreamIn[x].Data.position := curpos;

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
                writeln('DSPin BeforeBufProc 1');
 {$endif}
                if (StreamIn[x].Data.Status = 1) and (length(StreamIn[x].DSP) > 0) then
                  DoDSPinBeforeBufProc(x);
                // Procedure in DSP to execute before fill buffer.
  {$IF DEFINED(uos_debug) and DEFINED(unix)}
                writeln('DSPin BeforeBufProc 2');
  {$endif}

                if uosisactif then
                  begin
                    CheckIfPaused ;
                    // is there a pause waiting ?
                    case StreamIn[x].Data.TypePut of 

                      0: // It is a input from audio file.
                         ReadFile(x);

  {$IF DEFINED(portaudio)}
                      1: // for Input from device
                         ReadDevice(x);
  {$endif}

  {$IF DEFINED(webstream)}
                      2: // for Input from Internet audio stream.
                         ReadUrl(x);
  {$ENDIF}

  {$IF DEFINED(synthesizer)}
                      3: // for Input from Synthesizer
                         ReadSynth(x);
  {$endif}

                      4: // for Input from memory
                         ReadMem(x);

                      5: // for Input from endless muted
                         ReadEndless(x);

                      6: // for Input from decoded memory-stream
                         ReadMemDec(x);

                    end;
                    //case StreamIn[x].Data.TypePut of

                  end
                else StreamIn[x].Data.OutFrames := 0;

                if StreamIn[x].Data.OutFrames = 0 then StreamIn[x].Data.status := 0;

                if (StreamIn[x].Data.Seekable = True) then if StreamIn[x].Data.OutFrames < 100 then
                                                             StreamIn[x].Data.status := 0;
                // no more data then close the stream

  {$IF DEFINED(uos_debug) and DEFINED(unix)}
                writeln('StreamIn[x].Data.status = ' + inttostr(StreamIn[x].Data.status));
 {$endif}

                if  StreamIn[x].Data.status > 0 then// still working
                  begin

                    if (StreamIn[x].Data.positionEnable = 1) then
                      begin
                        if (StreamIn[x].Data.LibOpen = 1) and (StreamIn[x].Data.SampleFormat < 2)
                          then

                          curpos := curpos + (StreamIn[x].Data.OutFrames Div
                                    (StreamIn[x].Data.Channels * 2))
                                    // strange outframes float 32 with Mpg123 ?
                        else
                          curpos := curpos + (StreamIn[x].Data.OutFrames Div
                                    (StreamIn[x].Data.Channels));

                        StreamIn[x].Data.position := curpos;
                        // new position
                      end;

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
                    writeln('Getting the level before DSP procedure');
 {$endif}

                    if (StreamIn[x].Data.levelEnable = 1) or (StreamIn[x].Data.levelEnable = 3) then
                      StreamIn[x].Data := DSPLevel(StreamIn[x].Data);

                    // Adding level in array-level// ideal for pre-wave form
                    if (StreamIn[x].Data.levelArrayEnable = 1) then
                      begin
                        if (StreamIn[x].Data.levelEnable = 0) or (StreamIn[x].Data.levelEnable = 3)
                          then
                          StreamIn[x].Data := DSPLevel(StreamIn[x].Data);
                        DoArrayLevel(x);
                      end;

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
                    writeln('DSPin AfterBuffProcBefore');
 {$endif}

                    if (StreamIn[x].Data.Status = 1) and (length(StreamIn[x].DSP) > 0) then
                      DoDSPinAfterBufProc(x) ;
 {$IF DEFINED(uos_debug) and DEFINED(unix)}
                    writeln('DSPin AfterBuffProcAfter');
 {$endif}

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
                    writeln('The synchro main loop procedurebefore');
 {$endif}
                    DoMainLoopProc(x);

  {$IF DEFINED(uos_debug) and DEFINED(unix)}
                    writeln('Getting the level after DSP procedure');
 {$endif}

                    // Getting the level after DSP procedure
                    if ((StreamIn[x].Data.levelEnable = 2) or (StreamIn[x].Data.levelEnable = 3))
                      then StreamIn[x].Data := DSPLevel(StreamIn[x].Data);

                    // Adding level in array-level
                    if (StreamIn[x].Data.levelArrayEnable = 2) then
                      begin
                        if (StreamIn[x].Data.levelEnable = 0) or (StreamIn[x].Data.levelEnable = 1)
                          then
                          StreamIn[x].Data := DSPLevel(StreamIn[x].Data);
                        DoArrayLevel(x);
                      end;

  {$IF DEFINED(uos_debug) and DEFINED(unix)}
                    writeln('End level after DSP procedure');
 {$endif}

                  end;
                //if  StreamIn[x].Data.status > 0 then

              end;
            //if (StreamIn[x].Data.Status > 0) and (StreamIn[x].Data.Enabled = True) then

          end;
        // end for low(StreamIn[x]) to high(StreamIn[x])

        // Seeking if StreamIn is terminated
 {$IF DEFINED(uos_debug) and DEFINED(unix)}
        writeln('Seeking if StreamIn is terminated');
 {$endif}

        if status <> 0 then SeekIfTerminated;

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
        writeln('status = ' +inttostr(status));
 {$endif}

        CheckIfPaused ;
        // is there a pause waiting ?

        // Give Buffer to Output
        if status = 1 then
          begin
  {$IF DEFINED(uos_debug) and DEFINED(unix)}
            writeln('Give Buffer to Output');
  {$endif}

            if uosisactif then for x := 0 to high(StreamOut) do

                                 if (StreamOut[x].Data.Enabled = True)
                                   then
                                   begin

                                     if StreamOut[x].data.hasfilters then
                                       begin
                                         setlength(StreamOut[x].Data.levelfiltersar,StreamOut[x].
                                                   Data.nbfilters * StreamOut[x].Data.channels );
                                         StreamOut[x].Data.incfilters := 0;
                                       end;

                                     for x2 := 0 to high(StreamOut[x].Data.Buffer) do
                                       StreamOut[x].Data.Buffer[x2] := cfloat(0.0);
                                     // clear output
  {$IF DEFINED(uos_debug) and DEFINED(unix)}
                                     writeln('Buffer[x2] := cfloat(0.0)');
  {$endif}
                                     for x2 := 0 to high(StreamIn) do
                                       if  (StreamIn[x2].Data.status > 0)  and
                                          (StreamIn[x2].Data.Enabled = True)
                                          and  ((StreamIn[x2].Data.Output = x) or (StreamIn[x2].Data
                                          .Output = -1))
                                         then
                                         begin
  {$IF DEFINED(uos_debug) and DEFINED(unix)}
                                           writeln('length(StreamIn[x2].Data.Buffer) = ' +inttostr(
                                                   length(StreamIn[x2].Data.Buffer)));
                                           writeln('length(StreamOut[x].Data.Buffer) = ' +inttostr(
                                                   length(StreamOut[x].Data.Buffer)));
                                           writeln(

                                                  'for x3 := 0 to high(StreamIn[x2].Data.Buffer) do'
                                           );
                                           writeln('high(StreamIn[x2].Data.Buffer) = '+ inttostr(
                                                   high(StreamIn[x2].Data.Buffer)));
  {$endif}

                                           for x3 := 0 to high(StreamIn[x2].Data.Buffer) do
                                             begin
                                               if x3 < high(StreamOut[x].Data.Buffer) + 1 then
                                                 StreamOut[x].Data.Buffer[x3] := 
                                                                                 cfloat(StreamOut[x]
                                                                                 .Data.Buffer[x3]) +
                                                                                 cfloat(StreamIn[x2]
                                                                                 .Data.Buffer[x3]);

                                             end;

   {$IF DEFINED(uos_debug) and DEFINED(unix)}
                                           WriteLn(

                                           'StreamOut[x].Data.Buffer ------------------------------'
                                           );
                                           st := '';
                                           for i := 0 to length(StreamOut[0].Data.Buffer) -1 do
                                             st := st + '|' + inttostr(i) + '=' + floattostr(
                                                   Streamout[0].Data.Buffer[i]);
                                           // WriteLn(st); 
                                           writeln(

                                                'for x3 := 0 to high(StreamIn[x2].Data.Buffer) done'
                                           );
   {$endif}

                                           case StreamIn[x2].Data.LibOpen of 
                                             0:  StreamOut[x].Data.outframes := StreamIn[x2].Data.
                                                                                outframes ;
                                             // sndfile
                                             1:  StreamOut[x].Data.outframes := StreamIn[x2].Data.
                                                                                outframes Div
                                                                                StreamIn[x2].Data.
                                                                                Channels;
                                             // mpg123
                                             2:  StreamOut[x].Data.outframes := StreamIn[x2].Data.
                                                                                outframes ;
                                             // aac
                                             3:  StreamOut[x].Data.outframes := StreamIn[x2].Data.
                                                                                outframes ;
                                             // CDRom
                                             4:  StreamOut[x].Data.outframes := StreamIn[x2].Data.
                                                                                outframes ;
                                             // opus
                                           end;

                                         end;

                                     // copy buffer-in into buffer-out
  {$IF DEFINED(uos_debug) and DEFINED(unix)}
                                     writeln('copy buffer-in into buffer-out');
  {$endif}

                                     // DSPOut AfterBuffProc
                                     if (length(StreamOut[x].DSP) > 0) and uosisactif then

                                       DoDSPOutAfterBufProc(x) ;

                                     // apply plugin (ex: SoundTouch Library)
                                     plugenabled := False;

  {$IF DEFINED(uos_debug) and DEFINED(unix)}
                                     writeln(' if (length(Plugin) > 0) then');
  {$endif}

                                     if (length(Plugin) > 0) then
                                       begin
                                         for x3 := 0 to high(PlugIn) do
                                           if Plugin[x3].Enabled = True then
                                             plugenabled := True;
                                       end;
                                     //

                                     if uosisactif then
                                       begin
                                         if plugenabled = True then
                                           WriteOutPlug(x, x2)
                                         else// No plugin
                                           WriteOut(x, x2);
                                       end;

                                   end;
          end;

   {$IF DEFINED(uos_debug) and DEFINED(unix)}
        WriteLn('Before LoopEndProc ------------------------------');
  {$endif}

        if uosisactif then DoLoopEndMethods;

        if length(StreamIn) > 1 then// clear buffer for multi-input
          for x2 := 0 to high(StreamIn) do
            for x3 := 0 to high(StreamIn[x2].Data.Buffer) do
              StreamIn[x2].Data.Buffer[x3] := cfloat(0.0);

   {$IF DEFINED(uos_debug) and DEFINED(unix)}
        WriteLn('Before if (nofree = true) and (status = 0)-----');
  {$endif}

        if (nofree = true) and (status = 0)  then

          DoTerminateNoFreePlayer ;

    {$IF DEFINED(uos_debug) and DEFINED(unix)}
        WriteLn('Before until status = 0;----');
  {$endif}

      until status = 0;

      // End of Loop ---

  {$IF DEFINED(uos_debug) and DEFINED(unix)}
      WriteLn('Before Terminate Thread---');
  {$endif}

      // Terminate Thread
      if status = 0 then
        begin

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
          writeln('Status = 0');
 {$endif}

          DoTerminatePlayer;

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
          writeln('EndProc---');
 {$endif}

          if uosisactif then  DoEndProc;

          if uosisactif then if EndProcOnly <> nil then EndProcOnly;

          isAssigned := false ;

  {$IF DEFINED(uos_debug) and DEFINED(unix)}
          writeln('EndProc All');
 {$endif}
        end;

 {$IF DEFINED(uos_debug) and DEFINED(unix)}
      writeln('This is the end...');
 {$endif}

 {$IF DEFINED(mse)}

  {$else}
      // FreeOnTerminate:=True;
      // terminate();
    end;
 {$endif}
end;

procedure Tuos_Init.unloadPlugin(PluginName: Pchar);
// Unload Plugin... 
begin

 {$IF DEFINED(soundtouch)}
  if lowercase(PluginName) = 'soundtouch' then  st_Unload();
 {$endif}
  {$IF DEFINED(bs2b)}
  if lowercase(PluginName) = 'bs2b' then bs_Unload();
 {$endif}

end;

procedure Tuos_Init.unloadlib;
begin
  {$IF DEFINED(sndfile)}
  Sf_Unload();
  {$endif}
  {$IF DEFINED(mpg123)}
  Mp_Unload();
  {$endif}
  {$IF DEFINED(xmp)}
  xmp_Unload();
  {$endif}
  {$IF DEFINED(portaudio)}
  Pa_Unload();
  {$endif}
  {$IF DEFINED(neaac)}
  Aa_Unload;
  {$endif}
  {$IF DEFINED(fdkaac)}
  ad_Unload;
  {$endif}
  {$IF DEFINED(opus)}
  //op_Unload;
  of_Unload;
  {$endif}
  {$IF DEFINED(windows)}
  Set8087CW(old8087cw);
  {$endif}
end;

function Tuos_Init.InitLib(): cint32;
begin
  Result := -1;
  {$IF DEFINED(mpg123)}
  if (uosLoadResult.MPloadERROR = 0) then
    if mpg123_init() = MPG123_OK then
      begin
        mpversion := UTF8Decode(mpg123_decoders()^);
        uosLoadResult.MPinitError := 0;
        Result := 0;
      end
  else
    begin
      Result := -2;
      uosLoadResult.MPinitError := 1;
    end;
  {$endif}

  {$IF DEFINED(portaudio)}
  if (uosLoadResult.PAloadERROR = 0) then
    begin
      uosLoadResult.PAinitError := Pa_Initialize();
      paversion := UTF8Decode(Pa_GetVersionText());
      if uosLoadResult.PAinitError = 0 then
        begin
          Result := 0;
          DefDevInInfo := Nil ;
          DefDevOutInfo := Nil ;

          DefDevOut := Pa_GetDefaultOutputDevice();
          if DefDevOut >= 0  then
            DefDevOutInfo := Pa_GetDeviceInfo(DefDevOut);
          if DefDevOutInfo <> nil then
            DefDevOutAPIInfo := Pa_GetHostApiInfo(DefDevOutInfo^.hostApi);

          DefDevIn := Pa_GetDefaultInputDevice();
          if DefDevIn >= 0  then
            DefDevInInfo := Pa_GetDeviceInfo(DefDevIn);
          if DefDevInInfo <> nil then
            DefDevInAPIInfo := Pa_GetHostApiInfo(DefDevInInfo^.hostApi);
        end;

    end;
  {$endif}

   {$IF DEFINED(sndfile)}
  if (Result = -1) and (uosLoadResult.SFloadERROR = 0) then
    begin
      sfversion := UTF8Decode(sf_version_string());
      Result := 0;
    end;
   {$endif}

   {$IF DEFINED(xmp)}
  if (Result = -1) and (uosLoadResult.XMloadERROR = 0) then
    begin
      Result := 0;
    end;
  {$endif}

end;

function Tuos_Init.loadlib(): cint32;
begin
  Result := -1;
  uosLoadResult.PAloadERROR := -1;
  uosLoadResult.SFloadERROR := -1;
  uosLoadResult.MPloadERROR := -1;
  uosLoadResult.AAloadError := -1;
  uosLoadResult.OPloadERROR := -1;
  uosLoadResult.STloadERROR := -1;
  uosLoadResult.BSloadERROR := -1;
  uosLoadResult.XMloadERROR := -1;
  uosLoadResult.FAloadERROR := -1;

  {$IF DEFINED(portaudio)}
  if (PA_FileName <>  nil) and (PA_FileName <>  '') then
    begin
      if PA_FileName =  'system' then PA_FileName :=  '' ;
      if Pa_Load(PA_FileName) then
        begin
          //  {
          Result := 0;
          uosLoadResult.PAloadERROR := 0;
          uosDefaultDeviceOut := Pa_GetDefaultOutPutDevice();
          uosDefaultDeviceIn := Pa_GetDefaultInPutDevice();
          uosDeviceCount := Pa_GetDeviceCount();
          // }
        end
      else
        uosLoadResult.PAloadERROR := 2;
    end
  else
    uosLoadResult.PAloadERROR := -1;
  {$endif}

  {$IF DEFINED(sndfile)}
  if (SF_FileName <> nil) and (SF_FileName <>  '') then
    begin
      if Sf_FileName =  'system' then sf_FileName :=  '' ;
      if Sf_Load(SF_FileName) then
        begin
          uosLoadResult.SFloadERROR := 0;
          if uosLoadResult.PAloadERROR = -1 then
            Result := 0;
        end
      else
        begin
          uosLoadResult.SFloadERROR := 2;
          Result := -1;
        end;
    end
  else
    uosLoadResult.SFloadERROR := -1;
  {$endif}

  {$IF DEFINED(mpg123)}
  if (MP_FileName <> nil) and (MP_FileName <>  '') then
    begin
      if mp_FileName =  'system' then mp_FileName :=  '' ;
      if mp_Load(Mp_FileName) then
        begin
          uosLoadResult.MPloadERROR := 0;
          if (uosLoadResult.PAloadERROR = -1) and (uosLoadResult.SFloadERROR = -1) then
            Result := 0;
        end
      else
        begin
          uosLoadResult.MPloadERROR := 2;
          Result := -1;
        end;
    end
  else
    uosLoadResult.MPloadERROR := -1;
  {$endif}

  {$IF DEFINED(neaac)}
  if (AA_FileName <> nil) and (AA_FileName <>  '') and (M4_FileName <> nil) and (M4_FileName <>  '')
    then
    begin
      if m4_FileName =  'system' then m4_FileName :=  '' ;
      if aa_FileName =  'system' then aa_FileName :=  '' ;

      if aa_load(UTF8String(M4_FileName), UTF8String(AA_FileName)) then
        begin
          uosLoadResult.AAloadERROR := 0;
          if (uosLoadResult.MPloadERROR = -1) and (uosLoadResult.PAloadERROR = -1) and
             (uosLoadResult.SFloadERROR = -1)  then
            Result := 0;
        end
      else
        begin
          uosLoadResult.AAloadERROR := 2;
          Result := -1;
        end;
    end
  else
    uosLoadResult.AAloadERROR := -1;
  {$endif}

  {$IF DEFINED(opus)}
  if (OF_FileName <> nil) and (OF_FileName <>  '') then
    begin
      if of_FileName =  'system' then of_FileName :=  '' ;
      if (of_load(UTF8String(OF_FileName)))  then
        begin
          uosLoadResult.OPloadERROR := 0;
          if (uosLoadResult.MPloadERROR = -1) and (uosLoadResult.PAloadERROR = -1) and
             (uosLoadResult.SFloadERROR = -1) and (uosLoadResult.AAloadERROR = -1)
            then
            Result := 0;
        end
      else
        begin
          uosLoadResult.OPloadERROR := 2;
          Result := -1;
        end;
    end
  else
    uosLoadResult.OPloadERROR := -1;
  {$endif}

  {$IF DEFINED(xmp)}
  if (XM_FileName <> nil) and (XM_FileName <>  '') then
    begin
      if XM_FileName =  'system' then XM_FileName :=  '' ;
      if (xmp_Load(UTF8String(XM_FileName)))  then
        begin
          uosLoadResult.XMloadERROR := 0;
          if (uosLoadResult.MPloadERROR = -1) and (uosLoadResult.PAloadERROR = -1) and
             (uosLoadResult.SFloadERROR = -1) and (uosLoadResult.AAloadERROR = -1) and
             (uosLoadResult.OPloadERROR = -1)
            then
            Result := 0;
        end
      else
        begin
          uosLoadResult.XMloadERROR := 2;
          Result := -1;
        end;
    end
  else
    uosLoadResult.XMloadERROR := -1;
  {$endif}
  
    {$IF DEFINED(fdkaac)}
  if (FA_FileName <> nil) and (FA_FileName <>  '') then
    begin
      if FA_FileName =  'system' then FA_FileName :=  '' ;
      if (ad_Load(UTF8String(FA_FileName)))  then
        begin
          uosLoadResult.FAloadERROR := 0;
          if (uosLoadResult.MPloadERROR = -1) and (uosLoadResult.PAloadERROR = -1) and
             (uosLoadResult.SFloadERROR = -1) and (uosLoadResult.AAloadERROR = -1) and
             (uosLoadResult.OPloadERROR = -1) and (uosLoadResult.XMloadERROR = -1)
            then
            Result := 0;
        end
      else
        begin
          uosLoadResult.FAloadERROR := 2;
          Result := -1;
        end;
    end
  else
    uosLoadResult.FAloadERROR := -1;
  {$endif}

  if Result = 0 then  Result := InitLib();
end;


function uos_loadPlugin(PluginName, PluginFilename: PChar) : cint32;
begin
  Result := -1;
  {$IF DEFINED(soundtouch)}
  if ((lowercase(PluginName) = 'soundtouch') or (lowercase(PluginName) = 'getbpm')) and (
     PluginFileName <> nil) and (PluginFileName <>  '')  then
    begin
      if PluginFileName =  'system' then PluginFileName :=  '' ;
      if ST_Load(PluginFileName) then
        begin
          Result := 0;
          uosLoadResult.STloadERROR := 0;
          uosInit.Plug_ST_FileName := PluginFileName;
        end
      else
        begin
          uosLoadResult.STloadERROR := 2;
          Result := -1;
        end;
    end;

  {$endif}

  {$IF DEFINED(bs2b)}
  if (lowercase(PluginName) = 'bs2b') and (PluginFileName <> nil) and (PluginFileName <>  '') then
    begin
      if PluginFileName =  'system' then PluginFileName :=  '' ;
      if BS_Load(PluginFileName) then
        begin
          Result := 0;
          uosLoadResult.BSloadERROR := 0;
          uosInit.Plug_BS_FileName := PluginFileName;
        end
      else
        begin
          uosLoadResult.BSloadERROR := 2;
          Result := -1;
        end;
    end;
  {$endif}
end;


{$IF DEFINED(shout)}
function uos_LoadServerLib(ShoutFileName, OpusFileName : PChar) : cint32;
// Shout => needed for dealing with IceCast server
// Opus => needed for dealing with encoding opus stream
begin
  Result := -1;
  if not fileexists(ShoutFileName) then
  else
    if sh_Load(UTF8String(ShoutFileName)) then
      Result := 0;

  if result = 0 then
    if not fileexists(OpusFileName) then
      Result := -2
  else
    if op_Load(UTF8String(OpusFileName)) then
      Result := 0
  else Result := -1 ;
end;

procedure uos_unloadServerLib();
// Unload server libraries... Do not forget to call it before close application...
begin
  shout_shutdown;
  sh_unload;
  op_unload;
end;
{$endif}

function uos_loadlib(PortAudioFileName, SndFileFileName, Mpg123FileName, Mp4ffFileName, FaadFileName
                     , opusfileFileName, XMPFileName, fdkaacFilename : PChar) : cint32;
begin
  result := -1 ;
  if not assigned(uosInit) then
    begin

  {$IF DEFINED(windows)}
      old8087cw := Get8087CW;
      Set8087CW($133f);
  {$endif}

      uosInit := TUOS_Init.Create;
      // Create Libraries Loader-Init
    end;

  uosInit.PA_FileName := PortAudioFileName;
  uosInit.SF_FileName := SndFileFileName;
  uosInit.MP_FileName := Mpg123FileName;
  uosInit.AA_FileName := FaadFileName;
  uosInit.M4_FileName := Mp4ffFileName;
  uosInit.OF_FileName := opusfileFileName;
  uosInit.XM_FileName := XMPFileName;
  uosInit.FA_FileName := fdkaacFilename;

  result := uosInit.loadlib ;
end;

function uos_loadlib(PortAudioFileName, SndFileFileName, Mpg123FileName, Mp4ffFileName, FaadFileName
                     , opusfileFileName, XMPFileName : PChar) : cint32;
begin
  result := uos_loadlib(PortAudioFileName, SndFileFileName, Mpg123FileName, Mp4ffFileName,
            FaadFileName
            , opusfileFileName, XMPFileName, nil);
end;

function uos_loadlib(PortAudioFileName, SndFileFileName, Mpg123FileName, Mp4ffFileName, FaadFileName
                     , opusfileFileName: PChar) : cint32;
begin
  result := uos_loadlib(PortAudioFileName, SndFileFileName, Mpg123FileName, Mp4ffFileName,
            FaadFileName
            , opusfileFileName, Nil, nil);
end;

function uos_GetVersion() : cint32 ;
begin
  result := uos_version ;
end;

function Tuos_Player.SetGlobalEvent(isenabled : boolean) : boolean;
// Set the RTL Events Global (will pause/start/replay all the players synchro with same rtl event)) 
// result : true if set ok.
begin
  result := false;
  if (isAssigned = True) then
    begin
      isGlobalPause := isenabled;
      result := true;
    end;
end;

procedure uos_unloadlib() ;
begin
  if assigned(uosInit) then
    begin
      uosInit.unloadlib ;
    end;
end;

procedure uos_unloadlibCust(PortAudio, SndFile, Mpg123, AAC, opus, xmp, fdkaac: boolean);
// Custom Unload libraries... if true, then unload the library. You may unload what and when you want...
begin
  uosInit.unloadlibcust(PortAudio, SndFile, Mpg123, AAC, opus, xmp, fdkaac) ;
end;

procedure uos_UnloadPlugin(PluginName: PChar);
// load plugin...
begin
  uosInit.unloadplugin(PluginName);
end;

function uos_GetInfoLibraries() : PansiChar ;
begin
  result := pchar(paversion  + ' | Sndfile: ' + sfversion  + ' | Mpg123: ' + mpversion);
end;

{$IF DEFINED(portaudio)}
procedure uos_UpdateDevice();
begin
  Pa_Terminate();
  Pa_Initialize();
end;

procedure uos_GetInfoDevice();
var 
  x: cint32;
  devinf: PPaDeviceInfo;
  apiinf: PPaHostApiInfo;
begin
  x := 0;
  uosDeviceCount := 0;
  SetLength(uosDeviceInfos, 0);

  uos_UpdateDevice();

  if Pa_GetDeviceCount() > 0 then
    begin
      uosDeviceCount := Pa_GetDeviceCount();

      SetLength(uosDeviceInfos, uosDeviceCount);
      uosDefaultDeviceOut := Pa_GetDefaultOutPutDevice();
      uosDefaultDeviceIn := Pa_GetDefaultInPutDevice();

      while x < uosDeviceCount  do
        begin
          uosDeviceInfos[x].DeviceNum := x;

          devinf := Pa_GetDeviceInfo(x);
          apiinf := Pa_GetHostApiInfo(devinf^.hostApi);

          uosDeviceInfos[x].DeviceName := UTF8Decode(devinf^._name);
          uosDeviceInfos[x].HostAPIName := UTF8Decode(apiinf^._name);

          if x = uosDefaultDeviceIn then
            uosDeviceInfos[x].DefaultDevIn := True
          else
            uosDeviceInfos[x].DefaultDevIn := False;

          if x = uosDefaultDeviceOut then
            uosDeviceInfos[x].DefaultDevOut := True
          else
            uosDeviceInfos[x].DefaultDevOut := False;

          uosDeviceInfos[x].ChannelsIn := devinf^.maxInputChannels;
          uosDeviceInfos[x].ChannelsOut := devinf^.maxOutPutChannels;
          uosDeviceInfos[x].SampleRate := devinf^.defaultSampleRate;
          uosDeviceInfos[x].LatencyHighIn := devinf^.defaultHighInputLatency;
          uosDeviceInfos[x].LatencyLowIn := devinf^.defaultLowInputLatency;
          uosDeviceInfos[x].LatencyHighOut := devinf^.defaultHighOutputLatency;
          uosDeviceInfos[x].LatencyLowOut := devinf^.defaultLowOutputLatency;

          if uosDeviceInfos[x].ChannelsIn = 0 then
            begin
              if uosDeviceInfos[x].ChannelsOut = 0 then
                uosDeviceInfos[x].DeviceType := 'None'
              else  uosDeviceInfos[x].DeviceType := 'Out' ;
            end
          else
            begin
              if uosDeviceInfos[x].ChannelsOut = 0 then
                uosDeviceInfos[x].DeviceType := 'In'
              else  uosDeviceInfos[x].DeviceType := 'In/Out' ;
            end ;
          Inc(x);
        end;
    end;
end;

function uos_GetInfoDeviceStr() : PansiChar ;
var 
  x : cint32 ;
  devtmp , bool1, bool2 : UTF8String;
begin

  uos_GetInfoDevice() ;

  x := 0;
  devtmp := '';

  while  x < length(uosDeviceInfos) do
    begin
      if uosDeviceInfos[x].DefaultDevIn then bool1 := 'Yes'
      else bool1 := 'No';
      if uosDeviceInfos[x].DefaultDevOut then bool2 := 'Yes'
      else bool2 := 'No';

      devtmp := devtmp +

                'DeviceNum: ' + inttostr(uosDeviceInfos[x].DeviceNum) + ' |' +
                ' Name: ' + uosDeviceInfos[x].DeviceName +  ' |' +
                ' Type: ' + uosDeviceInfos[x].DeviceType + ' |' +
                ' DefIn: ' + bool1 + ' |' +
                ' DefOut: ' + bool2 + ' |' +
                ' ChanIn: ' +  IntToStr(uosDeviceInfos[x ].ChannelsIn)+ ' |' +
                ' ChanOut: ' +  IntToStr(uosDeviceInfos[x].ChannelsOut) + ' |' +
                ' SampleRate: ' +  floattostrf(uosDeviceInfos[x].SampleRate, ffFixed, 15, 0) + ' |'
                +
                ' LatencyHighIn: ' + floattostrf(uosDeviceInfos[x].LatencyHighIn, ffFixed, 15, 8) +
                ' |' +
                ' LatencyHighOut: ' + floattostrf(uosDeviceInfos[x].LatencyHighOut, ffFixed, 15, 8)+
                ' |' +
                ' LatencyLowIn: ' + floattostrf(uosDeviceInfos[x].LatencyLowIn, ffFixed, 15, 8)+
                ' |' +
                ' LatencyLowOut: ' + floattostrf(uosDeviceInfos[x].LatencyLowOut, ffFixed, 15, 8)+
                ' |' +
                ' HostAPI: ' + uosDeviceInfos[x].HostAPIName ;
      if x < length(uosDeviceInfos)-1 then  devtmp := devtmp +  #13#10 ;
      Inc(x);
    end;
  result :=  pansichar( devtmp + ' ' );

  // }
end;
{$endif}

{$IF DEFINED(Java)}
procedure Tuos_Player.beginprocjava();
begin
  (PEnv^^).CallVoidMethod(PEnv,Obj,BeginProc)  ;
end;

procedure Tuos_Player.endprocjava();
begin
  (PEnv^^).CallVoidMethod(PEnv,Obj,EndProc)  ;
end;

procedure Tuos_Player.LoopBeginProcjava();
begin
  (PEnv^^).CallVoidMethod(PEnv,Obj,LoopBeginProc)  ;
end;

procedure Tuos_Player.LoopEndProcjava();
begin
  (PEnv^^).CallVoidMethod(PEnv,Obj,LoopEndProc)  ;
end;

procedure Tuos_DSP.LoopProcjava();
begin
  // todo
end;

procedure Tuos_InStream.LoopProcjava();
begin
  // todo
end;

procedure Tuos_OutStream.LoopProcjava();
begin
  // todo
end;

{$endif}

{$IF DEFINED(webstream)}
procedure Tuos_InStream.UpdateIcyMetaInterval;
begin
  if Data.HandleSt<>nil then
    mpg123_param(Data.HandleSt, MPG123_ICY_INTERVAL, httpget.IcyMetaInt, 0);
end;
{$endif}

function AssignDefaultForUOSData: Tuos_Data;
var 
  i: Integer;
begin
  with Result do
    begin
      Enabled := False;
      TypePut := -1;
      //nothing
      Seekable := False;
      Status := 0;
      // no data


      SetLength(Buffer,0);
      SetLength(MemoryBuffer,0);
      MemoryStream := Nil;
      posmem := 0;

  {$IF DEFINED(opus)}
      SetLength(BufferTMP,0);
  {$endif}

      DSPVolumeIndex := -1;
      DSPNoiseIndex := -1;
      VLeft := 0;

      VRight := 0;

      hasfilters := false;

      nbfilters := 0;

      incfilters := 0;

      PositionEnable := 0;
      LevelEnable := 0;
      LevelLeft := 0;
      LevelRight := 0;
      levelArrayEnable := 0;

      //----------------------------//
      SampleRate := 44100;
  {$IF DEFINED(synthesizer)}
      freqLsine := 440;
      freqRsine := freqLsine;
      dursine := 0;
      posdursine := 0;
      harmonic := 0;
  {$endif}
      SamplerateRoot := SampleRate;
      //----------------------------//

      Wantframes := 0;
      OutFrames := 0;

      SampleFormat := -1;
      // default
      Channels := -1;
      // default

      HandleSt := Nil;
  {$IF DEFINED(opus)}
      HandleOP := Nil;
  {$endif}

      Filename := '';
      Title := '';
      Copyright := '';
      Software := '';
      Artist := '';
      Comment := '';
      Date := '';
      for i:= 0 to High(Tag) do
        Tag[i] := #0;
      Album := '';
      Genre := '';
      HDFormat := 0;
      Frames := 0;
      Sections := 0;
      Encoding := -1;
      // unknow
      bitrate := -1;
      // unknow
      Length := 0;
      LibOpen := -1;
      // nothing open
      Ratio := 0;

      BPM := 0;

      numbuf := -1;
      //default

      Output := -1;
      //error

      Position := 0;
      Poseek := 0;
    end;
end;

constructor Tuos_FFT.Create;
var 
  i: Integer;
begin
  inherited;

  AlsoBuf := False;

  TypeFilterL := 0;
  LowFrequencyL := 0;
  HighFrequencyL := 0;
  GainL := 0;

  for i:= 0 to High(a3) do
    a3[i] := 0;
  for i:= 0 to High(a32) do
    a32[i] := 0;

  for i:= 0 to High(TArray01) do
    begin
      b2[i] := 0;
      x0[i] := 0;
      x1[i] := 0;
      y0[i] := 0;
      y1[i] := 0;
      b22[i] := 0;
      x02[i] := 0;
      x12[i] := 0;
      y02[i] := 0;
      y12[i] := 0;
    end;

  C := 0;
  D := 0;
  C2 := 0;
  D2 := 0;

  TypeFilterR := 0;
  LowFrequencyR := 0;
  HighFrequencyR := 0;
  GainR := 0;
  for i:= 0 to High(a3r) do
    a3r[i] := 0;
  for i:= 0 to High(a32r) do
    a32r[i] := 0;

  for i:= 0 to High(TArray01) do
    begin
      b2r[i] := 0;
      x0r[i] := 0;
      x1r[i] := 0;
      y0r[i] := 0;
      y1r[i] := 0;
      b22r[i] := 0;
      x02r[i] := 0;
      x12r[i] := 0;
      y02r[i] := 0;
      y12r[i] := 0;
    end;

  Cr := 0;
  Dr := 0;
  C2r := 0;
  D2r := 0;

  levelstring := '';

  {$IF DEFINED(noiseremoval)}
  FNoise := Nil;
  {$endif}
end;

constructor Tuos_DSP.Create;
begin
  inherited;

  Enabled := False;
  BefFunc := Nil;
  AftFunc := Nil;
  EndFunc := Nil;
  LoopProc := Nil;
  fftdata := Nil;
end;

constructor Tuos_InStream.Create;
begin
  inherited;

  Data := AssignDefaultForUOSData;
  SetLength(DSP,0);

  {$IF DEFINED(neaac)}
  AACI := Nil;
  {$endif}

  {$IF DEFINED(cdrom)}
  pCD := Nil;
  {$endif}

  {$IF DEFINED(webstream)}
  httpget := Nil;

  InHandle := 0;
  OutHandle := 0;

  InPipe := Nil;
  OutPipe := Nil;
  {$ENDIF}

  {$IF DEFINED(portaudio)}
  with PAParam do
    begin
      device := 0;
      channelCount := 0;
      sampleFormat := Nil;
      suggestedLatency := 0;
      hostApiSpecificStreamInfo := Nil;
    end;
  {$endif}

  LoopProc := Nil;
end;

constructor Tuos_OutStream.Create;
{$IF DEFINED(shout)}
var 
  i: integer;
{$endif}
begin
  inherited;

  Data := AssignDefaultForUOSData;
  BufferOut := Nil;
  SetLength(DSP,0);

  {$IF DEFINED(portaudio)}
  with PAParam do
    begin
      //TODO: check if the default settings are ok
      device := 0;
      channelCount := 0;
      sampleFormat := Nil;
      suggestedLatency := 0;
      hostApiSpecificStreamInfo := Nil;
    end;
  {$endif}

  {$IF DEFINED(shout)}
  encoder := Nil;
  for i:= 0 to High(cbits) do
    cbits[i] := 0;
  //byte
  {$endif}



  with FileBuffer do
    begin
      ERROR := 0;
      wSamplesPerSec := 44100;
      wBitsPerSample := 32;
      wChannels := 2;
      FileFormat := -1;
      Data := Nil;
      DataMS := Nil;
    end;
  LoopProc := Nil;

  MemorySteamOut := Nil;

  {$IF DEFINED(Java)}
  //  procedure LoopProcjava;
  {$endif}
end;

constructor Tuos_Plugin.Create;
begin
  inherited;

  Enabled := False;
  Name := '';

  {$IF DEFINED(windows)}
  PlugHandle := 0;
  {$else}
  PlugHandle := Nil;
  {$endif}

  {$IF DEFINED(bs2b) or DEFINED(soundtouch)}
  Abs2b := Nil;
  PlugFunc := Nil;
  {$endif}
  param1 := -1;
  param2 := -1;
  param3 := -1;
  param4 := -1;
  param5 := -1;
  param6 := -1;
  param7 := -1;
  param8 := -1;

  SetLength(Buffer,0);
end;

constructor Tuos_Init.Create;
begin
  {$IF DEFINED(portaudio)}
  DefDevOut := -1;
  DefDevOutInfo := Nil;
  DefDevOutAPIInfo := Nil;
  DefDevIn := -1;
  DefDevInInfo := Nil;
  DefDevInAPIInfo := Nil;
  {$endif}

  TDummyThread.Create(false);
  evGlobalPause := RTLEventCreate;

  SetExceptionMask(GetExceptionMask + [exZeroDivide] + [exInvalidOp] +
                   [exDenormalized] + [exOverflow] + [exUnderflow] + [exPrecision]);
  uosLoadResult.PAloadERROR := -1;
  uosLoadResult.PCloadERROR := -1;
  uosLoadResult.SFloadERROR := -1;
  uosLoadResult.BSloadERROR := -1;
  uosLoadResult.STloadERROR := -1;
  uosLoadResult.MPloadERROR := -1;
  uosLoadResult.AAloadERROR := -1;
  uosLoadResult.OPloadERROR := -1;
  uosLoadResult.XMloadERROR := -1;
  uosLoadResult.PAinitError := -1;
  uosLoadResult.MPinitError := -1;

  PA_FileName := Nil;
  // PortAudio
  SF_FileName := Nil;
  // SndFile
  MP_FileName := Nil;
  // Mpg123
  AA_FileName := Nil;
  // Faad
  M4_FileName := Nil;
  // Mp4ff
  OF_FileName := Nil;
  // opusfile
  XM_FileName := Nil;
  // XMP
  Plug_ST_FileName := Nil;
  // Plugin SoundTouch
  Plug_BS_FileName := Nil;
  // Plugin bs2b
end;

constructor Tuos_Player.create();
begin
  evPause := RTLEventCreate;

  Index := -1;
  //default for independent instance

  isAssigned := true;
  isGlobalPause := false;
  intobuf := false;
  NLooped := 0;
  NoFree := False;
  status := -1;
  BeginProc := Nil;
  EndProc := Nil;
  EndProcOnly := Nil;
  loopBeginProc := Nil;
  loopEndProc := Nil;

  thethread := Nil;
  SetLength(StreamIn,0);
  SetLength(StreamOut,0);
  SetLength(PlugIn,0);

  {$IF DEFINED(Java)}
  PEnv := Nil;
  Obj := Nil;
  {$endif}
end;

{$IF DEFINED(mse)}
{$else}
procedure TuosThread.DoTerminate;
begin
 {$IF FPC_FULLVERSION>=20701}
  //Terminate the thread the calls places into the queuelist will be removed
  RemoveQueuedEvents(Self);
 {$ENDIF}
  //notice that is no longer valid (for safe destroy event of theparent)
  Tuos_Player(theparent).thethread := Nil;
  //execute player destroy
  FreeAndNil(theparent);
end;
 {$endif}

destructor Tuos_Player.Destroy;
var 
  x: cint32;
begin

  if thethread <> nil then
    begin
   {$ifdef mse}
      thethread.terminate();
      application.waitforthread(thethread);
      //calls unlockall()/relockall in order to avoid possible deadlock
      thethread.destroy();
  {$endif}

    end;

  if assigned(evPause) then RTLeventdestroy(evPause);

  if length(StreamOut) > 0 then
    for x := 0 to high(StreamOut) do
      freeandnil(StreamOut[x]);

  if length(StreamIn) > 0 then
    for x := 0 to high(StreamIn) do
      freeandnil(StreamIn[x]);

  if length(Plugin) > 0 then
    for x := 0 to high(Plugin) do
      freeandnil(Plugin[x]);

  //Note: if Index = -1 is a independent instance
  if Index <> -1 then
    begin
      //now notice that player is really free
      uosPlayersStat[Index] := -1 ;
      uosPlayers[Index] := Nil;
    end;

  inherited Destroy;

end;

destructor Tuos_DSP.Destroy;
begin
  if assigned(fftdata) then
    begin
  {$IF DEFINED(noiseremoval)}
      if assigned(fftdata.FNoise) then FreeAndNil(fftdata.FNoise);
  {$endif}
      FreeandNil(fftdata);
    end;

  inherited Destroy;
end;

destructor Tuos_InStream.Destroy;
var 
  x: cint32;
begin
  {$IF DEFINED(neaac)}
  if assigned(AACI) then
    begin
      if assigned(AACI.fsStream) then
        begin
          freeandnil(AACI.fsStream);
          sleep(100);
        end;
      freeandnil(AACI);
      sleep(100);
    end;
  {$endif}
  if assigned(Data.MemoryStream) then
    freeandnil(Data.MemoryStream);

  if length(DSP) > 0 then
    for x := 0 to high(DSP) do
      freeandnil(DSP[x]);

  inherited Destroy;

end;

destructor Tuos_OutStream.Destroy;
var 
  x: cint32;
begin
  if length(DSP) > 0 then
    for x := 0 to high(DSP) do
      freeandnil(DSP[x]);

  inherited Destroy;
end;

procedure Tuos_Init.unloadlibCust(PortAudio, SndFile, Mpg123, AAC, opus, xmp, fdkaac: boolean);
// Custom Unload libraries... if true, then unload the library. You may unload what and when you want...
begin
  {$IF DEFINED(portaudio)}
  if PortAudio = true then  Pa_Unload();
  {$endif}
  {$IF DEFINED(sndfile)}
  if SndFile = true then  sf_Unload();
  {$endif}
  {$IF DEFINED(mpg123)}
  if Mpg123 = true then  mp_Unload();
  {$endif}
  {$IF DEFINED(xmp)}
  if xmp = true then  xmp_Unload();
  {$endif}
  {$IF DEFINED(fdkaac)}
  if fdkaac = true then  ad_Unload();
  {$endif}
  {$IF DEFINED(neaac)}
  if AAC = True then aa_Unload();
  {$endif}
  {$IF DEFINED(opus)}
  if opus = True then
    begin
      of_Unload();
      // op_Unload();
    end;
  {$endif}
end;

procedure uos_Free();
begin
  uos_unloadlib() ;

  if assigned(uosInit) then
    begin
      if assigned(uosInit.evGlobalPause) then
        RTLeventdestroy(uosInit.evGlobalPause);
      freeandnil(uosInit);
    end;
end;

initialization 
SetLength(tempoutmemory,0);
SetLength(uosPlayers,0);
SetLength(uosPlayersStat,0);
SetLength(uosLevelArray,0);
SetLength(uosDeviceInfos,0);
uosInit := Nil;

end.
