12755 lines
460 KiB
ObjectPascal
12755 lines
460 KiB
ObjectPascal
|
|
|
|
{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.
|