HIGHLY EXPERIMENTAL implementation of Hermite interpolation method.

Test at your own risk. Tension can be changed in the code.

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@2723 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
gigaherz 2010-03-16 15:33:59 +00:00
parent ad4bbbf920
commit 329617d351
2 changed files with 64 additions and 0 deletions

View File

@ -483,6 +483,66 @@ static s32 __forceinline GetVoiceValues_Cubic( V_Core& thiscore, uint voiceidx )
return MulShr32( val, vc.ADSR.Value );
}
/*
Tension: 32767 is high, 0 normal, -32768 is low
*/
template<s32 i_tension>
__forceinline
static s32 HermiteInterpolate(
s32 y0, // 16.0
s32 y1, // 16.0
s32 y2, // 16.0
s32 y3, // 16.0
s32 mu // 0.12
)
{
s32 m00 = ((y1-y0)*i_tension) >> 16; // 16.0
s32 m01 = ((y2-y1)*i_tension) >> 16; // 16.0
s32 m0 = m00 + m01;
s32 m10 = ((y2-y1)*i_tension) >> 16; // 16.0
s32 m11 = ((y3-y2)*i_tension) >> 16; // 16.0
s32 m1 = m10 + m11;
s32 t0 = (( 2*y1 + m0 + m1 - 2*y2) * mu) >> 12; // 16.0
s32 t1 = ((t0 - 3*y1 - 2*m0 - m1 + 3*y2) * mu) >> 12; // 16.0
s32 t2 = ((t1 + m0 ) * mu) >> 12; // 16.0
s32 t3 = t2 + y1; // 16.0
return(t3);
}
// Returns a 16 bit result in Value.
static s32 __forceinline GetVoiceValues_Hermite( V_Core& thiscore, uint voiceidx )
{
V_Voice& vc( thiscore.Voices[voiceidx] );
while( vc.SP > 0 )
{
vc.PV4 = vc.PV3;
vc.PV3 = vc.PV2;
vc.PV2 = vc.PV1;
vc.PV1 = GetNextDataBuffered( thiscore, voiceidx );
//vc.PV1 <<= 2;
//vc.SPc = vc.SP&4095; // just the fractional part, please!
vc.SP -= 4096;
}
CalculateADSR( thiscore, voiceidx );
const s32 mu = vc.SP + 4096;
// The template parameter should specify the "tension" for the hermite function,
// see the comments in the function for usage.
s32 val = HermiteInterpolate<16384>(vc.PV4,vc.PV3,vc.PV2,vc.PV1,mu);
// Note! It's very important that ADSR stay as accurate as possible. By the way
// it is used, various sound effects can end prematurely if we truncate more than
// one or two bits. (or maybe it's better with no truncation at all?)
return MulShr32( val, vc.ADSR.Value );
}
// Noise values need to be mixed without going through interpolation, since it
// can wreak havoc on the noise (causing muffling or popping). Not that this noise
// generator is accurate in its own right.. but eh, ah well :)
@ -560,6 +620,9 @@ static __forceinline StereoOut32 MixVoice( uint coreidx, uint voiceidx )
Value = GetNoiseValues( thiscore, voiceidx );
else
{
if( Interpolation == 3 )
Value = GetVoiceValues_Hermite( thiscore, voiceidx );
else
if( Interpolation == 2 )
Value = GetVoiceValues_Cubic( thiscore, voiceidx );
else

View File

@ -142,6 +142,7 @@ BOOL CALLBACK ConfigProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
SendDialogMsg( hWnd, IDC_INTERPOLATE, CB_ADDSTRING,0,(LPARAM) L"0 - Nearest (none/fast)" );
SendDialogMsg( hWnd, IDC_INTERPOLATE, CB_ADDSTRING,0,(LPARAM) L"1 - Linear (recommended)" );
SendDialogMsg( hWnd, IDC_INTERPOLATE, CB_ADDSTRING,0,(LPARAM) L"2 - Cubic (slower/maybe better)" );
SendDialogMsg( hWnd, IDC_INTERPOLATE, CB_ADDSTRING,0,(LPARAM) L"3 - Hermite (highly experimental)" );
SendDialogMsg( hWnd, IDC_INTERPOLATE, CB_SETCURSEL,Interpolation,0 );
SendDialogMsg( hWnd, IDC_REVERB_BOOST, CB_RESETCONTENT,0,0 );