fpPS4/ps4_libsceaudioout.pas
2022-09-05 16:28:53 +03:00

754 lines
18 KiB
ObjectPascal

unit ps4_libSceAudioOut;
{$mode objfpc}{$H+}
{/$define silent}
interface
uses
atomic,
spinlock,
libportaudio,
ps4_handles,
ps4_program,
Classes,
SysUtils;
implementation
uses
sys_signal;
const
SCE_AUDIO_OUT_ERROR_NOT_OPENED =-2144993279; // 0x80260001
SCE_AUDIO_OUT_ERROR_BUSY =-2144993278; // 0x80260002
SCE_AUDIO_OUT_ERROR_INVALID_PORT =-2144993277; // 0x80260003
SCE_AUDIO_OUT_ERROR_INVALID_POINTER =-2144993276; // 0x80260004
SCE_AUDIO_OUT_ERROR_PORT_FULL =-2144993275; // 0x80260005
SCE_AUDIO_OUT_ERROR_INVALID_SIZE =-2144993274; // 0x80260006
SCE_AUDIO_OUT_ERROR_INVALID_FORMAT =-2144993273; // 0x80260007
SCE_AUDIO_OUT_ERROR_INVALID_SAMPLE_FREQ=-2144993272; // 0x80260008
SCE_AUDIO_OUT_ERROR_INVALID_VOLUME =-2144993271; // 0x80260009
SCE_AUDIO_OUT_ERROR_INVALID_PORT_TYPE =-2144993270; // 0x8026000A
SCE_AUDIO_OUT_ERROR_INVALID_CONF_TYPE =-2144993268; // 0x8026000C
SCE_AUDIO_OUT_ERROR_OUT_OF_MEMORY =-2144993267; // 0x8026000D
SCE_AUDIO_OUT_ERROR_ALREADY_INIT =-2144993266; // 0x8026000E
SCE_AUDIO_OUT_ERROR_NOT_INIT =-2144993265; // 0x8026000F
SCE_AUDIO_OUT_ERROR_MEMORY =-2144993264; // 0x80260010
SCE_AUDIO_OUT_ERROR_SYSTEM_RESOURCE =-2144993263; // 0x80260011
SCE_AUDIO_OUT_ERROR_TRANS_EVENT =-2144993262; // 0x80260012
SCE_AUDIO_OUT_ERROR_INVALID_FLAG =-2144993261; // 0x80260013
SCE_AUDIO_OUT_ERROR_INVALID_MIXLEVEL =-2144993260; // 0x80260014
SCE_AUDIO_OUT_ERROR_INVALID_ARG =-2144993259; // 0x80260015
SCE_AUDIO_OUT_ERROR_INVALID_PARAM =-2144993258; // 0x80260016
SCE_AUDIO_MIN_LEN=256;
SCE_AUDIO_MAX_LEN=(256*8);
SCE_AUDIO_OUT_PORT_TYPE_MAIN =0;
SCE_AUDIO_OUT_PORT_TYPE_BGM =1;
SCE_AUDIO_OUT_PORT_TYPE_VOICE =2;
SCE_AUDIO_OUT_PORT_TYPE_PERSONAL =3;
SCE_AUDIO_OUT_PORT_TYPE_PADSPK =4;
SCE_AUDIO_OUT_PORT_TYPE_AUX =127;
SCE_AUDIO_OUT_PARAM_FORMAT_S16_MONO =0;
SCE_AUDIO_OUT_PARAM_FORMAT_S16_STEREO =1;
SCE_AUDIO_OUT_PARAM_FORMAT_S16_8CH =2;
SCE_AUDIO_OUT_PARAM_FORMAT_FLOAT_MONO =3;
SCE_AUDIO_OUT_PARAM_FORMAT_FLOAT_STEREO =4;
SCE_AUDIO_OUT_PARAM_FORMAT_FLOAT_8CH =5;
SCE_AUDIO_OUT_PARAM_FORMAT_S16_8CH_STD =6;
SCE_AUDIO_OUT_PARAM_FORMAT_FLOAT_8CH_STD=7;
SCE_AUDIO_OUT_PARAM_FORMAT_MASK =$000000FF;
SCE_AUDIO_OUT_PARAM_FORMAT_SHIFT =0;
SCE_AUDIO_OUT_PARAM_ATTR_RESTRICTED =$00010000;
SCE_AUDIO_OUT_PARAM_ATTR_MIX_TO_MAIN =$00020000;
SCE_AUDIO_OUT_PARAM_ATTR_MASK =$000F0000;
SCE_AUDIO_OUT_PARAM_ATTR_SHIFT =16;
SCE_AUDIO_VOLUME_SHIFT =15;
SCE_AUDIO_VOLUME_0DB =(1<<SCE_AUDIO_VOLUME_SHIFT);
SCE_AUDIO_VOLUME_FLAG_L_CH =(1 shl 0);
SCE_AUDIO_VOLUME_FLAG_R_CH =(1 shl 1);
SCE_AUDIO_VOLUME_FLAG_C_CH =(1 shl 2);
SCE_AUDIO_VOLUME_FLAG_LFE_CH =(1 shl 3);
SCE_AUDIO_VOLUME_FLAG_LS_CH =(1 shl 4);
SCE_AUDIO_VOLUME_FLAG_RS_CH =(1 shl 5);
SCE_AUDIO_VOLUME_FLAG_LE_CH =(1 shl 6);
SCE_AUDIO_VOLUME_FLAG_RE_CH =(1 shl 7);
SCE_AUDIO_OUT_STATE_OUTPUT_UNKNOWN =$00;
SCE_AUDIO_OUT_STATE_OUTPUT_CONNECTED_PRIMARY =$01;
SCE_AUDIO_OUT_STATE_OUTPUT_CONNECTED_SECONDARY =$02;
SCE_AUDIO_OUT_STATE_OUTPUT_CONNECTED_TERTIARY =$04;
SCE_AUDIO_OUT_STATE_OUTPUT_CONNECTED_HEADPHONE =$40;
SCE_AUDIO_OUT_STATE_OUTPUT_CONNECTED_EXTERNAL =$80;
SCE_AUDIO_OUT_STATE_CHANNEL_UNKNOWN =0;
SCE_AUDIO_OUT_STATE_CHANNEL_DISCONNECTED=0;
SCE_AUDIO_OUT_STATE_CHANNEL_1 =1;
SCE_AUDIO_OUT_STATE_CHANNEL_2 =2;
SCE_AUDIO_OUT_STATE_CHANNEL_6 =6;
SCE_AUDIO_OUT_STATE_CHANNEL_8 =8;
type
pSceAudioOutPortState=^SceAudioOutPortState;
SceAudioOutPortState=packed record
output:Word;
channel:Byte;
reserved8_1:Byte;
volume:Word;
rerouteCounter:Word;
flag:QWord;
reserved64:array[0..1] of QWORD;
end;
PSceAudioOutOutputParam=^SceAudioOutOutputParam;
SceAudioOutOutputParam=packed record
handle:Integer;
align:Integer;
ptr:Pointer;
end;
var
_lazy_init:Integer=0;
_lazy_wait:Integer=0;
HAudioOuts:TIntegerHandles;
function ps4_sceAudioOutInit():Integer; SysV_ABI_CDecl;
begin
if XCHG(_lazy_init,1)=0 then
begin
_sig_lock;
Result:=Pa_Initialize();
_sig_unlock;
if (Result<>0) then Exit(SCE_AUDIO_OUT_ERROR_TRANS_EVENT);
_sig_lock;
HAudioOuts:=TIntegerHandles.Create;
_sig_unlock;
fetch_add(_lazy_wait,1);
end else
begin
wait_until_equal(_lazy_wait,0);
Result:=SCE_AUDIO_OUT_ERROR_ALREADY_INIT;
end;
//Writeln('sceAudioOutInit');
//Result:=111;
end;
{
userId
User ID of the output destination
type
Virtual device type
index
Device index (unused; specify 0)
len
Granularity (number of samples to be output at once; 256, 512, 768, 1024, 1280, 1536, 1792, or 2048)
freq
Sampling frequency (Hz; specify 48000)
param
Data format, etc.
}
type
TAudioOutHandle=class(TClassHandle)
userId,_type,index:Integer;
len,freq,param:DWORD;
volume:array[0..7] of Integer;
pstream:PaStream;
pnumOutputChannels:Integer;
psampleFormat:PaSampleFormat;
bufsize:Integer;
buf:Pointer;
//d:QWORD;
Destructor Destroy; override;
end;
Destructor TAudioOutHandle.Destroy;
begin
if (pstream<>nil) then
begin
Pa_StopStream(pstream);
Pa_CloseStream(pstream);
end;
FreeMem(buf);
inherited;
end;
//int32_t SceUserServiceUserId;
function ps4_sceAudioOutOpen(userId,_type,index:Integer;
len,freq,param:DWORD):Integer; SysV_ABI_CDecl;
Var
H:TAudioOutHandle;
i:Byte;
err:Integer;
pstream:PaStream;
pnumOutputChannels:Integer;
psampleFormat:PaSampleFormat;
begin
Result:=0;
if (HAudioOuts=nil) then Exit(SCE_AUDIO_OUT_ERROR_NOT_INIT);
case _type of
SCE_AUDIO_OUT_PORT_TYPE_MAIN :;
SCE_AUDIO_OUT_PORT_TYPE_BGM :;
SCE_AUDIO_OUT_PORT_TYPE_VOICE :;
SCE_AUDIO_OUT_PORT_TYPE_PERSONAL:;
SCE_AUDIO_OUT_PORT_TYPE_PADSPK :;
SCE_AUDIO_OUT_PORT_TYPE_AUX :;
else
Exit(SCE_AUDIO_OUT_ERROR_INVALID_PORT_TYPE);
end;
case len of
256,
512,
768,
1024,
1280,
1536,
1792,
2048:;
else
Exit(SCE_AUDIO_OUT_ERROR_INVALID_SIZE);
end;
case freq of
48000:;
else
Exit(SCE_AUDIO_OUT_ERROR_INVALID_SAMPLE_FREQ);
end;
case (param and SCE_AUDIO_OUT_PARAM_FORMAT_MASK) of
SCE_AUDIO_OUT_PARAM_FORMAT_S16_MONO:
begin
pnumOutputChannels:=1;
psampleFormat:=paInt16;
end;
SCE_AUDIO_OUT_PARAM_FORMAT_S16_STEREO:
begin
pnumOutputChannels:=2;
psampleFormat:=paInt16;
end;
SCE_AUDIO_OUT_PARAM_FORMAT_S16_8CH:
begin
pnumOutputChannels:=8;
psampleFormat:=paInt16;
end;
SCE_AUDIO_OUT_PARAM_FORMAT_FLOAT_MONO:
begin
pnumOutputChannels:=1;
psampleFormat:=paFloat32;
end;
SCE_AUDIO_OUT_PARAM_FORMAT_FLOAT_STEREO:
begin
pnumOutputChannels:=2;
psampleFormat:=paFloat32;
end;
SCE_AUDIO_OUT_PARAM_FORMAT_FLOAT_8CH:
begin
pnumOutputChannels:=8;
psampleFormat:=paFloat32;
end;
SCE_AUDIO_OUT_PARAM_FORMAT_S16_8CH_STD:
begin
pnumOutputChannels:=8;
psampleFormat:=paInt16;
end;
SCE_AUDIO_OUT_PARAM_FORMAT_FLOAT_8CH_STD:
begin
pnumOutputChannels:=8;
psampleFormat:=paFloat32;
end;
else
Exit(SCE_AUDIO_OUT_ERROR_INVALID_FORMAT);
end;
pstream:=nil;
err:=0;
if (_type=SCE_AUDIO_OUT_PORT_TYPE_MAIN) or (_type=SCE_AUDIO_OUT_PORT_TYPE_BGM) then //so far only MAIN/BGM
begin
_sig_lock;
err:=Pa_OpenDefaultStream(@pstream,
0,
pnumOutputChannels,
psampleFormat,
freq,
paFramesPerBufferUnspecified,nil,nil);
_sig_unlock;
if (err<>0) and (pnumOutputChannels>2) then
begin
pnumOutputChannels:=2;
_sig_lock;
err:=Pa_OpenDefaultStream(@pstream,
0,
pnumOutputChannels,
psampleFormat,
freq,
paFramesPerBufferUnspecified,nil,nil);
_sig_unlock;
end;
if (err<>0) then
begin
Writeln(StdErr,'Pa_GetErrorText:',PaErrorCode(err),':',Pa_GetErrorText(err));
//Exit(SCE_AUDIO_OUT_ERROR_NOT_INIT);
end;
end;
err:=0;
if (pstream<>nil) then
begin
_sig_lock;
err:=Pa_StartStream(pstream);
_sig_unlock;
end;
if (err<>0) then
begin
Exit(SCE_AUDIO_OUT_ERROR_NOT_INIT);
end;
_sig_lock;
H:=TAudioOutHandle.Create;
_sig_unlock;
H.userId:=userId;
H._type :=_type ;
H.index :=index ;
H.len :=len ;
H.freq :=freq ;
H.param :=param ;
For i:=0 to 7 do
H.volume[i]:=SCE_AUDIO_VOLUME_0DB;
H.pstream :=pstream;
H.pnumOutputChannels:=pnumOutputChannels;
H.psampleFormat :=psampleFormat;
_sig_lock;
if not HAudioOuts.New(H,Result) then Result:=SCE_AUDIO_OUT_ERROR_PORT_FULL;
_sig_unlock;
Case QWORD(psampleFormat) of
QWORD(paInt16 ):H.bufsize:=2*pnumOutputChannels*len;
QWORD(paFloat32):H.bufsize:=4*pnumOutputChannels*len;
end;
_sig_lock;
H.buf:=GetMem(H.bufsize);
_sig_unlock;
H.Release;
Writeln('AudioOutOpen:',userId,':',_type,':',index,':',len,':',freq,':',param);
end;
function ps4_sceAudioOutClose(handle:Integer):Integer; SysV_ABI_CDecl;
begin
Result:=0;
if (HAudioOuts=nil) then Exit(SCE_AUDIO_OUT_ERROR_NOT_INIT);
_sig_lock;
if not HAudioOuts.Delete(handle) then Result:=SCE_AUDIO_OUT_ERROR_INVALID_PORT;
_sig_unlock;
end;
function ps4_sceAudioOutGetPortState(handle:Integer;state:pSceAudioOutPortState):Integer; SysV_ABI_CDecl;
Var
H:TAudioOutHandle;
begin
if (HAudioOuts=nil) then Exit(SCE_AUDIO_OUT_ERROR_NOT_INIT);
if (state=nil) then Exit(SCE_AUDIO_OUT_ERROR_INVALID_POINTER);
_sig_lock;
H:=TAudioOutHandle(HAudioOuts.Acqure(handle));
_sig_unlock;
if (H=nil) then Exit(SCE_AUDIO_OUT_ERROR_INVALID_PORT);
state^:=Default(SceAudioOutPortState);
state^.output:=SCE_AUDIO_OUT_STATE_OUTPUT_CONNECTED_PRIMARY;
case (H.param and SCE_AUDIO_OUT_PARAM_FORMAT_MASK) of
SCE_AUDIO_OUT_PARAM_FORMAT_S16_MONO,
SCE_AUDIO_OUT_PARAM_FORMAT_FLOAT_MONO:
state^.channel:=SCE_AUDIO_OUT_STATE_CHANNEL_1;
SCE_AUDIO_OUT_PARAM_FORMAT_S16_STEREO,
SCE_AUDIO_OUT_PARAM_FORMAT_FLOAT_STEREO:
state^.channel:=SCE_AUDIO_OUT_STATE_CHANNEL_2;
SCE_AUDIO_OUT_PARAM_FORMAT_S16_8CH,
SCE_AUDIO_OUT_PARAM_FORMAT_FLOAT_8CH,
SCE_AUDIO_OUT_PARAM_FORMAT_S16_8CH_STD,
SCE_AUDIO_OUT_PARAM_FORMAT_FLOAT_8CH_STD:
state^.channel:=SCE_AUDIO_OUT_STATE_CHANNEL_8;
end;
state^.volume:=127; //user volume 0..127 (-1)
H.Release;
Result:=0;
end;
function ps4_sceAudioOutSetVolume(handle,flag:Integer;vol:PInteger):Integer; SysV_ABI_CDecl;
Var
H:TAudioOutHandle;
i:Integer;
begin
if (HAudioOuts=nil) then Exit(SCE_AUDIO_OUT_ERROR_NOT_INIT);
if (vol=nil) then Exit(SCE_AUDIO_OUT_ERROR_INVALID_POINTER);
i:=vol^;
if (i>SCE_AUDIO_VOLUME_0DB) then Exit(SCE_AUDIO_OUT_ERROR_INVALID_VOLUME);
{$ifdef silent}if (i>800) then i:=800;{$endif}
_sig_lock;
H:=TAudioOutHandle(HAudioOuts.Acqure(handle));
_sig_unlock;
if (H=nil) then Exit(SCE_AUDIO_OUT_ERROR_INVALID_PORT);
if (flag and SCE_AUDIO_VOLUME_FLAG_L_CH <>0) then H.volume[0]:=i;
if (flag and SCE_AUDIO_VOLUME_FLAG_R_CH <>0) then H.volume[1]:=i;
if (flag and SCE_AUDIO_VOLUME_FLAG_C_CH <>0) then H.volume[2]:=i;
if (flag and SCE_AUDIO_VOLUME_FLAG_LFE_CH<>0) then H.volume[3]:=i;
if (flag and SCE_AUDIO_VOLUME_FLAG_LS_CH <>0) then H.volume[4]:=i;
if (flag and SCE_AUDIO_VOLUME_FLAG_RS_CH <>0) then H.volume[5]:=i;
if (flag and SCE_AUDIO_VOLUME_FLAG_LE_CH <>0) then H.volume[6]:=i;
if (flag and SCE_AUDIO_VOLUME_FLAG_RE_CH <>0) then H.volume[7]:=i;
H.Release;
Writeln('sceAudioOutSetVolume:',handle,':',flag);
Result:=0;
end;
function ps4_sceAudioOutSetMixLevelPadSpk(handle,mixLevel:Integer):Integer; SysV_ABI_CDecl;
Var
H:TAudioOutHandle;
begin
if (HAudioOuts=nil) then Exit(SCE_AUDIO_OUT_ERROR_NOT_INIT);
_sig_lock;
H:=TAudioOutHandle(HAudioOuts.Acqure(handle));
_sig_unlock;
//ignore
H.Release;
Result:=0;
end;
procedure _VecMulI16M(Src,Dst:Pointer;count:Integer;volume:Integer);// inline;
begin
if volume=SCE_AUDIO_VOLUME_0DB then
begin
Move(Src^,Dst^,count*2);
end else
While (count>0) do
begin
PSmallInt(Dst)^:=(PSmallInt(Src)^*volume) div SCE_AUDIO_VOLUME_0DB;
Inc(Src,2);
Inc(Dst,2);
Dec(count);
end;
end;
procedure _VecMulI16S(Src,Dst:Pointer;count:Integer;volume:PInteger); inline;
begin
if (volume[0]=SCE_AUDIO_VOLUME_0DB) and (volume[1]=SCE_AUDIO_VOLUME_0DB) then
begin
Move(Src^,Dst^,count*2*2);
end else
While (count>0) do
begin
PSmallInt(Dst)^:=(PSmallInt(Src)^*volume[0]) div SCE_AUDIO_VOLUME_0DB;
Inc(Src,2);
Inc(Dst,2);
PSmallInt(Dst)^:=(PSmallInt(Src)^*volume[1]) div SCE_AUDIO_VOLUME_0DB;
Inc(Src,2);
Inc(Dst,2);
Dec(count);
end;
end;
procedure _VecMulF32M(Src,Dst:Pointer;count:Integer;volume:Integer); inline;
var
fvolume:Single;
begin
if volume=SCE_AUDIO_VOLUME_0DB then
begin
Move(Src^,Dst^,count*4);
end else
begin
fvolume:=volume/SCE_AUDIO_VOLUME_0DB;
While (count>0) do
begin
PSingle(Dst)^:=PSingle(Src)^*fvolume;
Inc(Src,4);
Inc(Dst,4);
Dec(count);
end;
end;
end;
procedure _VecMulF32S(Src,Dst:Pointer;count:Integer;volume:PInteger); inline;
var
fvolume:array[0..1] of Single;
begin
if (volume[0]=SCE_AUDIO_VOLUME_0DB) and (volume[1]=SCE_AUDIO_VOLUME_0DB) then
begin
Move(Src^,Dst^,count*4*2);
end else
begin
fvolume[0]:=volume[0]/SCE_AUDIO_VOLUME_0DB;
fvolume[1]:=volume[1]/SCE_AUDIO_VOLUME_0DB;
While (count>0) do
begin
PSingle(Dst)^:=PSingle(Src)^*fvolume[0];
Inc(Src,4);
Inc(Dst,4);
PSingle(Dst)^:=PSingle(Src)^*fvolume[1];
Inc(Src,4);
Inc(Dst,4);
Dec(count);
end;
end;
end;
// 1+3/√2
//L=FL+0.707*C+0.707*SL+0.707*BL
//R=FR+0.707*C+0.707*SR+0.707*BR
//1/√2
const
_FL=0;
_FR=1;
_FC=2;
_LF=3;
_SL=4;
_SR=5;
_BL=6;
_BR=7;
procedure _VecMulF32CH8ToS(Src,Dst:Pointer;count:Integer;volume:PInteger);
const
fdiv1:Single=1+(3/Sqrt(2));
fdiv2:Single=(1/Sqrt(2))*(1+(3/Sqrt(2)));
var
fvolume:array[0..7] of Single;
fL,fR:Single;
begin
fvolume[_FL]:=(volume[_FL]/SCE_AUDIO_VOLUME_0DB)*fdiv1;
fvolume[_FR]:=(volume[_FR]/SCE_AUDIO_VOLUME_0DB)*fdiv1;
fvolume[_FC]:=(volume[_FC]/SCE_AUDIO_VOLUME_0DB)*fdiv2;
fvolume[_SL]:=(volume[_SL]/SCE_AUDIO_VOLUME_0DB)*fdiv2;
fvolume[_SR]:=(volume[_SR]/SCE_AUDIO_VOLUME_0DB)*fdiv2;
fvolume[_BL]:=(volume[_BL]/SCE_AUDIO_VOLUME_0DB)*fdiv2;
fvolume[_BR]:=(volume[_BR]/SCE_AUDIO_VOLUME_0DB)*fdiv2;
While (count>0) do
begin
fL:=(PSingle(Src)[_FL]*fvolume[_FL])+
(PSingle(Src)[_FC]*fvolume[_FC])+
(PSingle(Src)[_SL]*fvolume[_SL])+
(PSingle(Src)[_BL]*fvolume[_BL]);
fR:=(PSingle(Src)[_FR]*fvolume[_FR])+
(PSingle(Src)[_FC]*fvolume[_FC])+
(PSingle(Src)[_SR]*fvolume[_SR])+
(PSingle(Src)[_BR]*fvolume[_BR]);
//fL:=fL*0.05;
//fR:=fR*0.05;
PSingle(Dst)^:=fL;
Inc(Dst,4);
PSingle(Dst)^:=fR;
Inc(Dst,4);
Inc(Src,4*8);
Dec(count);
end;
end;
function ps4_sceAudioOutOutput(handle:Integer;ptr:Pointer):Integer; SysV_ABI_CDecl;
Var
H:TAudioOutHandle;
count,err:Integer;
begin
if (HAudioOuts=nil) then Exit(SCE_AUDIO_OUT_ERROR_NOT_INIT);
if (ptr=nil) then Exit(0);
err:=0;
_sig_lock;
H:=TAudioOutHandle(HAudioOuts.Acqure(handle));
_sig_unlock;
if (H=nil) then Exit(SCE_AUDIO_OUT_ERROR_INVALID_PORT);
count:=H.len;
if (H.pstream<>nil) then
case (H.param and SCE_AUDIO_OUT_PARAM_FORMAT_MASK) of
SCE_AUDIO_OUT_PARAM_FORMAT_S16_MONO:
begin
_VecMulI16M(ptr,H.buf,count,H.volume[0]);
_sig_lock;
err:=Pa_WriteStream(H.pstream,H.buf,count);
_sig_unlock;
end;
SCE_AUDIO_OUT_PARAM_FORMAT_S16_STEREO:
begin
_VecMulI16S(ptr,H.buf,count,@H.volume);
_sig_lock;
err:=Pa_WriteStream(H.pstream,H.buf,count);
_sig_unlock;
end;
SCE_AUDIO_OUT_PARAM_FORMAT_S16_8CH:
begin
Assert(false);
end;
SCE_AUDIO_OUT_PARAM_FORMAT_FLOAT_MONO:
begin
_VecMulF32M(ptr,H.buf,count,H.volume[0]);
_sig_lock;
err:=Pa_WriteStream(H.pstream,H.buf,count);
_sig_unlock;
end;
SCE_AUDIO_OUT_PARAM_FORMAT_FLOAT_STEREO:
begin
_VecMulF32S(ptr,H.buf,count,@H.volume);
_sig_lock;
err:=Pa_WriteStream(H.pstream,H.buf,count);
_sig_unlock;
end;
SCE_AUDIO_OUT_PARAM_FORMAT_FLOAT_8CH:
begin
if H.pnumOutputChannels=2 then
begin
_VecMulF32CH8ToS(ptr,H.buf,count,@H.volume);
_sig_lock;
err:=Pa_WriteStream(H.pstream,H.buf,count);
_sig_unlock;
end else
begin
Assert(false);
end;
end;
SCE_AUDIO_OUT_PARAM_FORMAT_S16_8CH_STD:
begin
Assert(false);
end;
SCE_AUDIO_OUT_PARAM_FORMAT_FLOAT_8CH_STD:
begin
Assert(false);
end;
end;
Case err of
0:;
Integer(paOutputUnderflowed):;
else
Writeln(StdErr,'Pa_GetErrorText:',PaErrorCode(err),':',Pa_GetErrorText(err));
end;
//Writeln('sceAudioOutOutput:',handle,':',HexStr(ptr));
_sig_lock;
H.Release;
_sig_unlock;
Result:=0;
end;
function ps4_sceAudioOutOutputs(param:PSceAudioOutOutputParam;num:DWORD):Integer; SysV_ABI_CDecl;
var
i:DWORD;
begin
if (param=nil) then Exit(SCE_AUDIO_OUT_ERROR_INVALID_POINTER);
if (num=0) then Exit(SCE_AUDIO_OUT_ERROR_INVALID_PARAM);
For i:=0 to num-1 do
begin
Result:=ps4_sceAudioOutOutput(param[i].handle,param[i].ptr);
if (Result<>0) then Exit;
end;
end;
function Load_libSceAudioOut(Const name:RawByteString):TElf_node;
var
lib:PLIBRARY;
begin
Result:=TElf_node.Create;
Result.pFileName:=name;
lib:=Result._add_lib('libSceAudioOut');
lib^.set_proc($25F10F5D5C6116A0,@ps4_sceAudioOutInit);
lib^.set_proc($7A436FB13DB6AEC6,@ps4_sceAudioOutOpen);
lib^.set_proc($B35FFFB84F66045C,@ps4_sceAudioOutClose);
lib^.set_proc($1AB43DB3822B35A4,@ps4_sceAudioOutGetPortState);
lib^.set_proc($6FEB8057CF489711,@ps4_sceAudioOutSetVolume);
lib^.set_proc($C15C0F539D294B57,@ps4_sceAudioOutSetMixLevelPadSpk);
lib^.set_proc($40E42D6DE0EAB13E,@ps4_sceAudioOutOutput);
lib^.set_proc($C373DD6924D2C061,@ps4_sceAudioOutOutputs);
end;
const
SCE_AUDIO_IN_ERROR_NOT_OPENED=$80260109;
function ps4_sceAudioInOpen(userID,busType,index,len,freq,param:Integer):Integer; SysV_ABI_CDecl;
begin
Result:=Integer(SCE_AUDIO_IN_ERROR_NOT_OPENED);
end;
function Load_libSceAudioIn(Const name:RawByteString):TElf_node;
var
lib:PLIBRARY;
begin
Result:=TElf_node.Create;
Result.pFileName:=name;
lib:=Result._add_lib('libSceAudioIn');
lib^.set_proc($E4D13C4A373B542F,@ps4_sceAudioInOpen);
end;
initialization
ps4_app.RegistredPreLoad('libSceAudioOut.prx',@Load_libSceAudioOut);
ps4_app.RegistredPreLoad('libSceAudioIn.prx',@Load_libSceAudioIn);
end.