SPU2-X: Added config setting for ProLogic decoding level.

Refactored the ProLogicII code into a separate file and changed it to floating point math for easier debugging. 
Added a basic ProLogic decoder that doesn't try to do surround separation into L/R.

The setting does not have a GUI option yet, since the PLII decoder is experimental and doesn't give too good results.
To change it, set DplDecodingLevel to one of: 0=none, 1=ProLogic, 2=ProLogicII. The default is 0.

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@4859 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
gigaherz 2011-08-10 20:08:29 +00:00
parent c0f9d1b619
commit a4a40441c9
9 changed files with 265 additions and 111 deletions

View File

@ -68,6 +68,8 @@ extern float FinalVolume;
extern bool postprocess_filter_enabled;
extern bool postprocess_filter_dealias;
extern int dplLevel;
extern u32 OutputModule;
extern int SndOutLatencyMS;
extern int SynchMode;

View File

@ -0,0 +1,162 @@
#include "Global.h"
static const u8 sLogTable[256] = {
0x00,0x3C,0x60,0x78,0x8C,0x9C,0xA8,0xB4,0xBE,0xC8,0xD0,0xD8,0xDE,0xE4,0xEA,0xF0,
0xF6,0xFA,0xFE,0x04,0x08,0x0C,0x10,0x14,0x16,0x1A,0x1E,0x20,0x24,0x26,0x2A,0x2C,
0x2E,0x32,0x34,0x36,0x38,0x3A,0x3E,0x40,0x42,0x44,0x46,0x48,0x4A,0x4C,0x4E,0x50,
0x50,0x52,0x54,0x56,0x58,0x5A,0x5A,0x5C,0x5E,0x60,0x60,0x62,0x64,0x66,0x66,0x68,
0x6A,0x6A,0x6C,0x6E,0x6E,0x70,0x70,0x72,0x74,0x74,0x76,0x76,0x78,0x7A,0x7A,0x7C,
0x7C,0x7E,0x7E,0x80,0x80,0x82,0x82,0x84,0x84,0x86,0x86,0x88,0x88,0x8A,0x8A,0x8C,
0x8C,0x8C,0x8E,0x8E,0x90,0x90,0x92,0x92,0x92,0x94,0x94,0x96,0x96,0x96,0x98,0x98,
0x9A,0x9A,0x9A,0x9C,0x9C,0x9C,0x9E,0x9E,0xA0,0xA0,0xA0,0xA2,0xA2,0xA2,0xA4,0xA4,
0xA4,0xA6,0xA6,0xA6,0xA8,0xA8,0xA8,0xAA,0xAA,0xAA,0xAC,0xAC,0xAC,0xAC,0xAE,0xAE,
0xAE,0xB0,0xB0,0xB0,0xB2,0xB2,0xB2,0xB2,0xB4,0xB4,0xB4,0xB6,0xB6,0xB6,0xB6,0xB8,
0xB8,0xB8,0xB8,0xBA,0xBA,0xBA,0xBC,0xBC,0xBC,0xBC,0xBE,0xBE,0xBE,0xBE,0xC0,0xC0,
0xC0,0xC0,0xC2,0xC2,0xC2,0xC2,0xC2,0xC4,0xC4,0xC4,0xC4,0xC6,0xC6,0xC6,0xC6,0xC8,
0xC8,0xC8,0xC8,0xC8,0xCA,0xCA,0xCA,0xCA,0xCC,0xCC,0xCC,0xCC,0xCC,0xCE,0xCE,0xCE,
0xCE,0xCE,0xD0,0xD0,0xD0,0xD0,0xD0,0xD2,0xD2,0xD2,0xD2,0xD2,0xD4,0xD4,0xD4,0xD4,
0xD4,0xD6,0xD6,0xD6,0xD6,0xD6,0xD8,0xD8,0xD8,0xD8,0xD8,0xD8,0xDA,0xDA,0xDA,0xDA,
0xDA,0xDC,0xDC,0xDC,0xDC,0xDC,0xDC,0xDE,0xDE,0xDE,0xDE,0xDE,0xDE,0xE0,0xE0,0xE0,
};
static float Gfl=0,Gfr=0;
static float LMax=0,RMax=0;
static float LAccum=0;
static float RAccum=0;
static s32 ANum=0;
const float Scale = 4294967296.0f; // tweak this value to change the overall output volume
const float GainL = 0.80f * Scale;
const float GainR = 0.80f * Scale;
const float GainC = 0.75f * Scale;
const float GainSL = 0.90f * Scale;
const float GainSR = 0.90f * Scale;
const float GainLFE= 0.90f * Scale;
const float AddCLR = 0.20f * Scale; // Stereo expansion
extern void ResetDplIIDecoder()
{
Gfl=0;
Gfr=0;
LMax=0;
RMax=0;
LAccum=0;
RAccum=0;
ANum=0;
}
void ProcessDplIISample32( const StereoOut32& src, Stereo51Out32DplII * s)
{
float ValL = src.Left / (float)(1<<(SndOutVolumeShift+16));
float ValR = src.Right / (float)(1<<(SndOutVolumeShift+16));
float XL = abs(ValL);
float XR = abs(ValR);
if(XL>LMax) LMax = XL; // 23
if(XR>RMax) RMax = XR;
ANum++;
if(ANum>=128)
{
ANum=0;
LAccum = (LAccum * 0.9f + LMax * 0.1f);
RAccum = (RAccum * 0.9f + RMax * 0.1f);
LMax = 0;
RMax = 0;
float Tfl=RAccum/std::max(1.0f,LAccum);
float Tfr=LAccum/std::max(1.0f,RAccum);
float gMax = std::max(1.0f,std::max(Tfl,Tfr));
Tfl = Tfl/gMax;
Tfr = Tfr/gMax;
if(Tfl<0.00001f) Tfl=0.00001f;
if(Tfr<0.00001f) Tfr=0.00001f;
Gfl = Gfl * 0.78f + Tfl * 0.22f;
Gfr = Gfr * 0.78f + Tfr * 0.22f;
}
float C = (ValL+ValR) * 0.5f;
float L = ValL - C;
float R = ValR - C;
float SUB = C;
float Cfl = (1+log(Gfl+1)/log(2.0f));
float Cfr = (1+log(Gfr+1)/log(2.0f));
float VL = L * Cfl;
float VR = R * Cfr;
float SL = (VR*1.73f - VL*1.22f)*0.25*Cfr; // not sure about this
float SR = (VR*1.22f - VL*1.73f)*0.25*Cfl;
s32 CX = (s32)(C * AddCLR);
s->Left = (s32)(L * GainL ) + CX;
s->Right = (s32)(R * GainR ) + CX;
s->Center = (s32)(C * GainC );
s->LFE = (s32)(SUB * GainLFE);
s->LeftBack = (s32)(SL * GainSL );
s->RightBack = (s32)(SR * GainSR );
}
void ProcessDplIISample16( const StereoOut32& src, Stereo51Out16DplII * s)
{
Stereo51Out32DplII ss;
ProcessDplIISample32(src, &ss);
s->Left = ss.Left >> 16;
s->Right = ss.Right >> 16;
s->Center = ss.Center >> 16;
s->LFE = ss.LFE >> 16;
s->LeftBack = ss.LeftBack >> 16;
s->RightBack = ss.RightBack >> 16;
}
void ProcessDplSample32( const StereoOut32& src, Stereo51Out32Dpl * s)
{
float ValL = src.Left / (float)(1<<(SndOutVolumeShift+16));
float ValR = src.Right / (float)(1<<(SndOutVolumeShift+16));
float C = (ValL+ValR)*0.5f; //+15.8
float S = (ValL-ValR)*0.5f;
float L=ValL-C; //+15.8
float R=ValR-C;
float SUB = C;
s32 CX = (s32)(C * AddCLR); // +15.16
s->Left = (s32)(L * GainL ) + CX; // +15.16 = +31, can grow to +32 if (GainL + AddCLR)>255
s->Right = (s32)(R * GainR ) + CX;
s->Center = (s32)(C * GainC ); // +15.16 = +31
s->LFE = (s32)(SUB * GainLFE);
s->LeftBack = (s32)(S * GainSL );
s->RightBack = (s32)(S * GainSR );
}
void ProcessDplSample16( const StereoOut32& src, Stereo51Out16Dpl * s)
{
Stereo51Out32Dpl ss;
ProcessDplSample32(src, &ss);
s->Left = ss.Left >> 16;
s->Right = ss.Right >> 16;
s->Center = ss.Center >> 16;
s->LFE = ss.LFE >> 16;
s->LeftBack = ss.LeftBack >> 16;
s->RightBack = ss.RightBack >> 16;
}

View File

@ -234,6 +234,7 @@ template void SndBuffer::ReadSamples(Stereo21Out16*);
template void SndBuffer::ReadSamples(Stereo40Out16*);
template void SndBuffer::ReadSamples(Stereo41Out16*);
template void SndBuffer::ReadSamples(Stereo51Out16*);
template void SndBuffer::ReadSamples(Stereo51Out16Dpl*);
template void SndBuffer::ReadSamples(Stereo51Out16DplII*);
template void SndBuffer::ReadSamples(Stereo71Out16*);
@ -242,6 +243,8 @@ template void SndBuffer::ReadSamples(Stereo21Out32*);
template void SndBuffer::ReadSamples(Stereo40Out32*);
template void SndBuffer::ReadSamples(Stereo41Out32*);
template void SndBuffer::ReadSamples(Stereo51Out32*);
template void SndBuffer::ReadSamples(Stereo51Out32Dpl*);
template void SndBuffer::ReadSamples(Stereo51Out32DplII*);
template void SndBuffer::ReadSamples(Stereo71Out32*);
void SndBuffer::_WriteSamples(StereoOut32 *bData, int nSamples)

View File

@ -36,6 +36,18 @@ static const int SampleRate = 48000;
extern int FindOutputModuleById( const wchar_t* omodid );
struct Stereo51Out16DplII;
struct Stereo51Out32DplII;
struct Stereo51Out16Dpl; // similar to DplII but without rear balancing
struct Stereo51Out32Dpl;
extern void ResetDplIIDecoder();
extern void ProcessDplIISample16( const StereoOut32& src, Stereo51Out16DplII * s);
extern void ProcessDplIISample32( const StereoOut32& src, Stereo51Out32DplII * s);
extern void ProcessDplSample16( const StereoOut32& src, Stereo51Out16Dpl * s);
extern void ProcessDplSample32( const StereoOut32& src, Stereo51Out32Dpl * s);
struct StereoOut16
{
s16 Left;
@ -198,111 +210,53 @@ struct Stereo51Out16DplII
void ResampleFrom( const StereoOut32& src )
{
static const u8 sLogTable[256] = {
0x00,0x3C,0x60,0x78,0x8C,0x9C,0xA8,0xB4,0xBE,0xC8,0xD0,0xD8,0xDE,0xE4,0xEA,0xF0,
0xF6,0xFA,0xFE,0x04,0x08,0x0C,0x10,0x14,0x16,0x1A,0x1E,0x20,0x24,0x26,0x2A,0x2C,
0x2E,0x32,0x34,0x36,0x38,0x3A,0x3E,0x40,0x42,0x44,0x46,0x48,0x4A,0x4C,0x4E,0x50,
0x50,0x52,0x54,0x56,0x58,0x5A,0x5A,0x5C,0x5E,0x60,0x60,0x62,0x64,0x66,0x66,0x68,
0x6A,0x6A,0x6C,0x6E,0x6E,0x70,0x70,0x72,0x74,0x74,0x76,0x76,0x78,0x7A,0x7A,0x7C,
0x7C,0x7E,0x7E,0x80,0x80,0x82,0x82,0x84,0x84,0x86,0x86,0x88,0x88,0x8A,0x8A,0x8C,
0x8C,0x8C,0x8E,0x8E,0x90,0x90,0x92,0x92,0x92,0x94,0x94,0x96,0x96,0x96,0x98,0x98,
0x9A,0x9A,0x9A,0x9C,0x9C,0x9C,0x9E,0x9E,0xA0,0xA0,0xA0,0xA2,0xA2,0xA2,0xA4,0xA4,
0xA4,0xA6,0xA6,0xA6,0xA8,0xA8,0xA8,0xAA,0xAA,0xAA,0xAC,0xAC,0xAC,0xAC,0xAE,0xAE,
0xAE,0xB0,0xB0,0xB0,0xB2,0xB2,0xB2,0xB2,0xB4,0xB4,0xB4,0xB6,0xB6,0xB6,0xB6,0xB8,
0xB8,0xB8,0xB8,0xBA,0xBA,0xBA,0xBC,0xBC,0xBC,0xBC,0xBE,0xBE,0xBE,0xBE,0xC0,0xC0,
0xC0,0xC0,0xC2,0xC2,0xC2,0xC2,0xC2,0xC4,0xC4,0xC4,0xC4,0xC6,0xC6,0xC6,0xC6,0xC8,
0xC8,0xC8,0xC8,0xC8,0xCA,0xCA,0xCA,0xCA,0xCC,0xCC,0xCC,0xCC,0xCC,0xCE,0xCE,0xCE,
0xCE,0xCE,0xD0,0xD0,0xD0,0xD0,0xD0,0xD2,0xD2,0xD2,0xD2,0xD2,0xD4,0xD4,0xD4,0xD4,
0xD4,0xD6,0xD6,0xD6,0xD6,0xD6,0xD8,0xD8,0xD8,0xD8,0xD8,0xD8,0xDA,0xDA,0xDA,0xDA,
0xDA,0xDC,0xDC,0xDC,0xDC,0xDC,0xDC,0xDE,0xDE,0xDE,0xDE,0xDE,0xDE,0xE0,0xE0,0xE0,
};
ProcessDplIISample16(src, this);
}
};
static s32 Gfl=0,Gfr=0;
static s32 LMax=0,RMax=0;
struct Stereo51Out32DplII
{
s32 Left;
s32 Right;
s32 Center;
s32 LFE;
s32 LeftBack;
s32 RightBack;
static s32 LAccum;
static s32 RAccum;
static s32 ANum;
void ResampleFrom( const StereoOut32& src )
{
ProcessDplIISample32(src, this);
}
};
s32 ValL = src.Left >> (SndOutVolumeShift-8);
s32 ValR = src.Right >> (SndOutVolumeShift-8);
s32 XL = abs(ValL>>8);
s32 XR = abs(ValR>>8);
struct Stereo51Out16Dpl
{
s16 Left;
s16 Right;
s16 Center;
s16 LFE;
s16 LeftBack;
s16 RightBack;
if(XL>LMax) LMax = XL;
if(XR>RMax) RMax = XR;
void ResampleFrom( const StereoOut32& src )
{
ProcessDplSample16(src, this);
}
};
ANum++;
if(ANum>=128)
{
ANum=0;
LAccum = 1+((LAccum * 224 + LMax * 31)>>8);
RAccum = 1+((RAccum * 224 + RMax * 31)>>8);
struct Stereo51Out32Dpl
{
s32 Left;
s32 Right;
s32 Center;
s32 LFE;
s32 LeftBack;
s32 RightBack;
LMax = 0;
RMax = 0;
s32 Tfl=(RAccum)*255/(LAccum);
s32 Tfr=(LAccum)*255/(RAccum);
int gMax = std::max(Tfl,Tfr);
Tfl = Tfl*255/gMax;
Tfr = Tfr*255/gMax;
if(Tfl>255) Tfl=255;
if(Tfr>255) Tfr=255;
if(Tfl<1) Tfl=1;
if(Tfr<1) Tfr=1;
Gfl = (Gfl * 200 + Tfl * 56)>>8;
Gfr = (Gfr * 200 + Tfr * 56)>>8;
}
s32 L,R,C,SUB,SL,SR;
C=(ValL+ValR)>>1; //16.8
ValL-=C;//16.8
ValR-=C;//16.8
L=ValL>>8; //16.0
R=ValR>>8; //16.0
C=C>>8; //16.0
SUB = C;
{
s32 Cfl = 1+sLogTable[Gfl];
s32 Cfr = 1+sLogTable[Gfr];
s32 VL=(ValL>>4) * Cfl; //16.12
s32 VR=(ValR>>4) * Cfr;
//s32 SC = (VL-VR)>>15;
SL = (((VR/148 - VL/209)>>4)*Cfr)>>8;
SR = (((VR/209 - VL/148)>>4)*Cfl)>>8;
}
// Random-ish values to get it to compile
int GainL = 200;
int GainR = 200;
int GainC = 180;
int GainSL = 230;
int GainSR = 230;
int GainLFE = 200;
int AddCLR = 55;
int AddCX = (C * AddCLR)>>8;
Left = (((L * GainL ))>>8) + AddCX;
Right = (((R * GainR ))>>8) + AddCX;
Center = (((C * GainC ))>>8);
LFE = (((SUB * GainLFE))>>8);
LeftBack = (((SL * GainSL ))>>8);
RightBack = (((SR * GainSR ))>>8);
void ResampleFrom( const StereoOut32& src )
{
ProcessDplSample32(src, this);
}
};

View File

@ -104,7 +104,7 @@ private:
return 0;
}
};
public:
SampleReader* ActualPaCallback;
@ -189,10 +189,8 @@ public:
case 3: speakers = 8; break; // Surround 7.1
default: speakers = 2;
}
actualUsedChannels = devinfo->maxOutputChannels;
if(actualUsedChannels > speakers)
actualUsedChannels = speakers;
actualUsedChannels = std::min(speakers, devinfo->maxOutputChannels);
switch( actualUsedChannels )
{
case 2:
@ -217,14 +215,28 @@ public:
case 6:
case 7:
ConLog( "* SPU2 > 5.1 speaker expansion enabled.\n" );
ActualPaCallback = new ConvertedSampleReader<Stereo51Out32>(&writtenSoFar); //"normal" stereo upmix
//ActualPaCallback = new ConvertedSampleReader<Stereo51Out32DplII>(&writtenSoFar); //gigas PLII
switch(dplLevel)
{
case 0:
ConLog( "* SPU2 > 5.1 speaker expansion enabled.\n" );
ActualPaCallback = new ConvertedSampleReader<Stereo51Out32>(&writtenSoFar); //"normal" stereo upmix
break;
case 1:
ConLog( "* SPU2 > 5.1 speaker expansion with basic ProLogic dematrixing enabled.\n" );
ActualPaCallback = new ConvertedSampleReader<Stereo51Out32Dpl>(&writtenSoFar); // basic Dpl decoder without rear stereo balancing
break;
case 2:
ConLog( "* SPU2 > 5.1 speaker expansion with experimental ProLogicII dematrixing enabled.\n" );
ActualPaCallback = new ConvertedSampleReader<Stereo51Out32DplII>(&writtenSoFar); //gigas PLII
break;
}
actualUsedChannels = 6; // we do not support 7.0 or 6.2 configurations, downgrade to 5.1
break;
default: // anything 8 or more gets the 7.1 treatment!
ConLog( "* SPU2 > 7.1 speaker expansion enabled.\n" );
ActualPaCallback = new ConvertedSampleReader<Stereo71Out32>(&writtenSoFar);
actualUsedChannels = 8; // we do not support 7.2 or more, downgrade to 7.1
break;
}

View File

@ -58,6 +58,8 @@ wchar_t dspPlugin[256];
int numSpeakers = 0;
int dplLevel = 0;
/*****************************************************************************/
void ReadSettings()
@ -69,7 +71,8 @@ void ReadSettings()
postprocess_filter_dealias = CfgReadBool( L"MIXING", L"DealiasFilter", false );
FinalVolume = ((float)CfgReadInt( L"MIXING", L"FinalVolume", 100 )) / 100;
if ( FinalVolume > 1.0f) FinalVolume = 1.0f;
numSpeakers = CfgReadInt( L"OUTPUT", L"XAudio2_SpeakerConfiguration", 0);
numSpeakers = CfgReadInt( L"OUTPUT", L"SpeakerConfiguration", 0);
dplLevel = CfgReadInt( L"OUTPUT", L"DplDecodingLevel", 0);
SndOutLatencyMS = CfgReadInt(L"OUTPUT",L"Latency", 150);
if((SynchMode == 0) && (SndOutLatencyMS < LATENCY_MIN_TS)) // can't use low-latency with timestretcher atm
@ -124,7 +127,8 @@ void WriteSettings()
CfgWriteStr(L"OUTPUT",L"Output_Module", mods[OutputModule]->GetIdent() );
CfgWriteInt(L"OUTPUT",L"Latency", SndOutLatencyMS);
CfgWriteInt(L"OUTPUT",L"Synch_Mode", SynchMode);
CfgWriteInt(L"OUTPUT",L"XAudio2_SpeakerConfiguration", numSpeakers);
CfgWriteInt(L"OUTPUT",L"SpeakerConfiguration", numSpeakers);
CfgWriteInt( L"OUTPUT", L"DplDecodingLevel", dplLevel);
if( Config_WaveOut.Device.empty() ) Config_WaveOut.Device = L"default";
CfgWriteStr(L"WAVEOUT",L"Device",Config_WaveOut.Device);

View File

@ -200,6 +200,7 @@ private:
case 4: chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT; break;
case 5: chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT; break;
case 6: chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY; break;
case 8: chanMask |= SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT | SPEAKER_LOW_FREQUENCY; break;
}
_init( pXAudio2, chanMask );
}
@ -316,9 +317,21 @@ public:
case 6:
case 7:
ConLog( "* SPU2 > 5.1 speaker expansion enabled.\n" );
voiceContext = new StreamingVoice<Stereo51Out16>( pXAudio2 ); //"normal" stereo upmix
//voiceContext = new StreamingVoice<Stereo51Out16DplII>( pXAudio2 ); //gigas PLII
switch(dplLevel)
{
case 0:
ConLog( "* SPU2 > 5.1 speaker expansion enabled.\n" );
voiceContext = new StreamingVoice<Stereo51Out16>( pXAudio2 ); //"normal" stereo upmix
break;
case 1:
ConLog( "* SPU2 > 5.1 speaker expansion with basic ProLogic dematrixing enabled.\n" );
voiceContext = new StreamingVoice<Stereo51Out16Dpl>( pXAudio2 ); // basic Dpl decoder without rear stereo balancing
break;
case 2:
ConLog( "* SPU2 > 5.1 speaker expansion with experimental ProLogicII dematrixing enabled.\n" );
voiceContext = new StreamingVoice<Stereo51Out16DplII>( pXAudio2 ); //gigas PLII
break;
}
break;
default: // anything 8 or more gets the 7.1 treatment!

View File

@ -289,6 +289,7 @@
<ClInclude Include="resource.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\DplIIdecoder.cpp" />
<ClCompile Include="..\PrecompiledHeader.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='DebugStrict|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>

View File

@ -240,6 +240,9 @@
<ClCompile Include="..\PS2E-spu2.cpp">
<Filter>Source Files\PluginInterface</Filter>
</ClCompile>
<ClCompile Include="..\DplIIdecoder.cpp">
<Filter>Source Files\Sound Output</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="..\..\LGPL.txt">