apply a mutated bisqwit's deemph approach instead

This commit is contained in:
zeromus 2015-09-17 19:38:07 +00:00
parent 75f75d6900
commit 52d00c97b7
1 changed files with 93 additions and 4 deletions

View File

@ -86,8 +86,6 @@ pal *palo;
(type) (y + to_rgb [4] * i + to_rgb [5] * q)\
)
static void ApplyDeemphasisNTSC(int entry, u8& r, u8& g, u8& b)
{
static float const to_float = 1.0f / 0xFF;
@ -155,10 +153,101 @@ static void ApplyDeemphasisNTSC(int entry, u8& r, u8& g, u8& b)
{ 0.956f, 0.621f, -0.272f, -0.647f, -1.105f, 1.702f };
fb = YIQ_TO_RGB( y, i, q, default_decoder, float, fr, fg );
#define CLAMP(x) (x<0?0:(x>1.0f?1.0f:x))
#define CLAMP(x) ((x)<0?0:((x)>1.0f?1.0f:(x)))
r = (u8)(CLAMP(fr)*255);
g = (u8)(CLAMP(fg)*255);
b = (u8)(CLAMP(fb)*255);
//doesnt help
//float gamma=1.8f;
// auto gammafix = [=](float f) { return f < 0.f ? 0.f : std::pow(f, 2.2f / gamma); };
// auto clamp = [](int v) { return v<0 ? 0 : v>255 ? 255 : v; };
// r = clamp(255 * gammafix(y + 0.946882f*i + 0.623557f*q));
// g = clamp(255 * gammafix(y + -0.274788f*i + -0.635691f*q));
// b = clamp(255 * gammafix(y + -1.108545f*i + 1.709007f*q));
}
float bisqwit_gammafix(float f, float gamma) { return f < 0.f ? 0.f : std::pow(f, 2.2f / gamma); }
int bisqwit_clamp(int v) { return v<0 ? 0 : v>255 ? 255 : v; }
// Calculate the luma and chroma by emulating the relevant circuits:
int bisqwit_wave(int p, int color) { return (color+p+8)%12 < 6; }
static void ApplyDeemphasisBisqwit(int entry, u8& r, u8& g, u8& b)
{
if(entry<64) return;
int myr, myg, myb;
// The input value is a NES color index (with de-emphasis bits).
// We need RGB values. Convert the index into RGB.
// For most part, this process is described at:
// http://wiki.nesdev.com/w/index.php/NTSC_video
// Decode the color index
int color = (entry & 0x0F), level = color<0xE ? (entry>>4) & 3 : 1;
// Voltage levels, relative to synch voltage
static const float black=.518f, white=1.962f, attenuation=.746f,
levels[8] = {.350f, .518f, .962f,1.550f, // Signal low
1.094f,1.506f,1.962f,1.962f}; // Signal high
float lo_and_hi[2] = { levels[level + 4 * (color == 0x0)],
levels[level + 4 * (color < 0xD)] };
//fceux alteration: two passes
//1st pass calculates bisqwit's base color
//2nd pass calculates it with deemph
//finally, we'll do something dumb: find a 'scale factor' between them and apply it to the input palette. (later, we could pregenerate the scale factors)
//whatever, it gets the job done.
for(int pass=0;pass<2;pass++)
{
float y=0.f, i=0.f, q=0.f, gamma=1.8f;
for(int p=0; p<12; ++p) // 12 clock cycles per pixel.
{
// NES NTSC modulator (square wave between two voltage levels):
float spot = lo_and_hi[bisqwit_wave(p,color)];
// De-emphasis bits attenuate a part of the signal:
if(pass==1)
{
if(((entry & 0x40) && bisqwit_wave(p,12))
|| ((entry & 0x80) && bisqwit_wave(p, 4))
|| ((entry &0x100) && bisqwit_wave(p, 8))) spot *= attenuation;
}
// Normalize:
float v = (spot - black) / (white-black) / 12.f;
// Ideal TV NTSC demodulator:
y += v;
i += v * std::cos(3.141592653 * p / 6);
q += v * std::sin(3.141592653 * p / 6); // Or cos(... p-3 ... )
// Note: Integrating cos() and sin() for p-0.5 .. p+0.5 range gives
// the exactly same result, scaled by a factor of 2*cos(pi/12).
}
// Convert YIQ into RGB according to FCC-sanctioned conversion matrix.
int rt = bisqwit_clamp(255 * bisqwit_gammafix(y + 0.946882f*i + 0.623557f*q,gamma));
int gt = bisqwit_clamp(255 * bisqwit_gammafix(y + -0.274788f*i + -0.635691f*q,gamma));
int bt = bisqwit_clamp(255 * bisqwit_gammafix(y + -1.108545f*i + 1.709007f*q,gamma));
if(pass==0) myr = rt, myg = gt, myb = bt;
else
{
float rscale = (float)rt / myr;
float gscale = (float)gt / myg;
float bscale = (float)bt / myb;
#define BCLAMP(x) ((x)<0?0:((x)>255?255:(x)))
if(myr!=0) r = (u8)(BCLAMP(r*rscale));
if(myg!=0) g = (u8)(BCLAMP(g*gscale));
if(myb!=0) b = (u8)(BCLAMP(b*bscale));
}
}
}
//classic algorithm
@ -195,7 +284,7 @@ static void ApplyDeemphasisComplete(pal* pal512)
for(int p=0;p<64;p++,idx++)
{
pal512[idx] = pal512[p];
ApplyDeemphasisNTSC(idx,pal512[idx].r,pal512[idx].g,pal512[idx].b);
ApplyDeemphasisBisqwit(idx,pal512[idx].r,pal512[idx].g,pal512[idx].b);
}
}
}