Skip to content

Commit fc54675

Browse files
NovaSquirrelmkwong98
authored andcommitted
Merge pull request SourMesen#121 from Gumball2415/feature-refactor-composite-emulation
Fix color emphasis emulation in Bisqwit's NTSC filter
1 parent eff962a commit fc54675

File tree

2 files changed

+59
-37
lines changed

2 files changed

+59
-37
lines changed

Core/BisqwitNtscFilter.cpp

Lines changed: 57 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,26 @@ BisqwitNtscFilter::BisqwitNtscFilter(shared_ptr<Console> console, int resDivider
1414
_stopThread = false;
1515
_workDone = false;
1616

17-
const int8_t signalLumaLow[4] = { -29, -15, 22, 71 };
18-
const int8_t signalLumaHigh[4] = { 32, 66, 105, 105 };
17+
const int8_t signalLumaLow[2][4] = { { -29, -15, 22, 71 }, { -38, -28, -1, 34 } };
18+
const int8_t signalLumaHigh[2][4] = { { 32, 66, 105, 105 }, { 6, 31, 58, 58 } };
1919

2020
//Precalculate the low and high signal chosen for each 64 base colors
21-
for(int i = 0; i <= 0x3F; i++) {
22-
int r = (i & 0x0F) >= 0x0E ? 0x1D : i;
23-
24-
int m = signalLumaLow[r / 0x10];
25-
int q = signalLumaHigh[r / 0x10];
26-
if((r & 0x0F) == 13) {
27-
q = m;
28-
} else if((r & 0x0F) == 0) {
29-
m = q;
21+
//with their respective attenuated values
22+
for (int h = 0; h <= 1; h++) {
23+
for(int i = 0; i <= 0x3F; i++) {
24+
int r = (i & 0x0F) >= 0x0E ? 0x1D : i;
25+
26+
int m = signalLumaLow[h][r / 0x10];
27+
int q = signalLumaHigh[h][r / 0x10];
28+
if((r & 0x0F) == 13) {
29+
q = m;
30+
} else if((r & 0x0F) == 0) {
31+
m = q;
32+
}
33+
_signalLow[h][i] = m;
34+
_signalHigh[h][i] = q;
3035
}
31-
_signalLow[i] = m;
32-
_signalHigh[i] = q;
3336
}
34-
3537
_extraThread = std::thread([=]() {
3638
//Worker thread to improve decode speed
3739
while(!_stopThread) {
@@ -165,33 +167,53 @@ void BisqwitNtscFilter::RecursiveBlend(int iterationCount, uint64_t *output, uin
165167
void BisqwitNtscFilter::GenerateNtscSignal(int8_t *ntscSignal, int &phase, int rowNumber)
166168
{
167169
for(int x = -_paddingSize; x < 256 + _paddingSize; x++) {
168-
uint16_t color = _ppuOutputBuffer[(rowNumber << 8) | (x < 0 ? 0 : (x >= 256 ? 255 : x))];
169-
170-
int8_t low = _signalLow[color & 0x3F];
171-
int8_t high = _signalHigh[color & 0x3F];
172-
int8_t emphasis = color >> 6;
170+
// pixel_color = Pixel color (9-bit) given as input. Bitmask format: "eeellcccc".
171+
uint16_t pixel_color = _ppuOutputBuffer[(rowNumber << 8) | (x < 0 ? 0 : (x >= 256 ? 255 : x))];
172+
173+
int8_t emphasis = pixel_color >> 6;
174+
int8_t color = pixel_color & 0x3F;
175+
176+
auto phase_shift_up = [=](uint16_t value, uint16_t amt) {
177+
amt = amt % 12;
178+
uint16_t uint12_value = value & 0xFFF;
179+
uint32_t result = (((uint12_value << 12) | uint12_value) & 0xFFFFFFFF);
180+
return uint16_t((result >> (amt % 12)) & 0xFFFF);
181+
};
182+
183+
uint16_t emphasis_wave = 0;
184+
if (emphasis & 0b001) // tint R; color phase C
185+
emphasis_wave |= 0b000000111111;
186+
if (emphasis & 0b010) // tint G; color phase 4
187+
emphasis_wave |= 0b001111110000;
188+
if (emphasis & 0b100) // tint B; color phase 8
189+
emphasis_wave |= 0b111100000011;
190+
if (emphasis)
191+
emphasis_wave = phase_shift_up(emphasis_wave, (color & 0x0F));
173192

174193
uint16_t phaseBitmask = _bitmaskLut[std::abs(phase - (color & 0x0F)) % 12];
194+
bool attenuate = 0;
175195

176-
uint8_t voltage;
177-
for(int j = 0; j < 8; j++) {
178-
phaseBitmask <<= 1;
179-
voltage = high;
180-
if(phaseBitmask >= 0x40) {
181-
if(phaseBitmask == 0x1000) {
182-
phaseBitmask = 1;
183-
} else {
184-
voltage = low;
185-
}
186-
}
196+
int8_t voltage;
197+
for(int j = 0; j < _signalsPerPixel; j++) {
198+
// colors $xE and $xF are not affected by emphasis
199+
// https://forums.nesdev.org/viewtopic.php?p=160669#p160669
200+
if ((color & 0x0F) <= 0x0D)
201+
attenuate = (phaseBitmask & emphasis_wave);
187202

188-
if(phaseBitmask & emphasis) {
189-
voltage -= voltage / 4;
203+
voltage = _signalHigh[attenuate][color];
204+
205+
// 12 phases done, wrap back to beginning
206+
if(phaseBitmask >= (1 << 12)) {
207+
phaseBitmask = 1;
190208
}
191-
209+
else {
210+
// 6 out of 12 cycles
211+
if (phaseBitmask >= (1 << 6))
212+
voltage = _signalLow[attenuate][color];
213+
}
214+
phaseBitmask <<= 1;
192215
ntscSignal[((x + _paddingSize) << 3) | j] = voltage;
193216
}
194-
195217
phase += _signalsPerPixel;
196218
}
197219
phase += (341 - 256 - _paddingSize * 2) * _signalsPerPixel;
@@ -217,7 +239,7 @@ void BisqwitNtscFilter::DecodeFrame(int startRow, int endRow, uint16_t *ppuOutpu
217239
GenerateNtscSignal(rowSignal, phase, y);
218240

219241
//Convert the NTSC signal to RGB
220-
NtscDecodeLine(lineWidth * _signalsPerPixel, rowSignal, outputBuffer, (startCycle + 7) % 12);
242+
NtscDecodeLine(lineWidth * _signalsPerPixel, rowSignal, outputBuffer, (startCycle + 6) % 12);
221243

222244
outputBuffer += rowPixelGap;
223245
}

Core/BisqwitNtscFilter.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ class BisqwitNtscFilter : public BaseVideoFilter
3838

3939
//To finetune hue, you would have to recalculate sinetable[]. (Coarse changes can be made with Phase0.)
4040
int8_t _sinetable[27]; // 8*sin(x*2pi/12)
41-
int8_t _signalLow[0x40];
42-
int8_t _signalHigh[0x40];
41+
int8_t _signalLow[2][0x40];
42+
int8_t _signalHigh[2][0x40];
4343

4444
void RecursiveBlend(int iterationCount, uint64_t *output, uint64_t *currentLine, uint64_t *nextLine, int pixelsPerCycle, bool verticalBlend);
4545

0 commit comments

Comments
 (0)