Skip to content
This repository was archived by the owner on Sep 11, 2023. It is now read-only.

Commit 3a42b48

Browse files
authored
Merge pull request #93 from Gumball2415/feature-refactor-composite-emulation
Refactor SMPTE-C implementation
2 parents 9920cf3 + 2ff21bf commit 3a42b48

14 files changed

+74
-137
lines changed

Core/BisqwitNtscFilter.cpp

Lines changed: 22 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,11 @@
88
#include "EmulationSettings.h"
99
#include "Console.h"
1010

11-
BisqwitNtscFilter::BisqwitNtscFilter(shared_ptr<Console> console, int resDivider, bool SMPTE_C) : BaseVideoFilter(console)
11+
BisqwitNtscFilter::BisqwitNtscFilter(shared_ptr<Console> console, int resDivider) : BaseVideoFilter(console)
1212
{
1313
_resDivider = resDivider;
1414
_stopThread = false;
1515
_workDone = false;
16-
_SMPTE_C = SMPTE_C;
1716

1817
const int8_t signalLumaLow[4] = { -29, -15, 22, 71 };
1918
const int8_t signalLumaHigh[4] = { 32, 66, 105, 105 };
@@ -50,7 +49,7 @@ BisqwitNtscFilter::BisqwitNtscFilter(shared_ptr<Console> console, int resDivider
5049
outputBuffer += GetOverscan().GetScreenWidth() * 64 / _resDivider / _resDivider * (120 - GetOverscan().Top);
5150
}
5251

53-
DecodeFrame(120, 239 - GetOverscan().Bottom, _ppuOutputBuffer, outputBuffer, (IsOddFrame() ? 8 : 0) + 327360, SMPTE_C);
52+
DecodeFrame(120, 239 - GetOverscan().Bottom, _ppuOutputBuffer, outputBuffer, (IsOddFrame() ? 8 : 0) + 327360);
5453

5554
_workDone = true;
5655
}
@@ -70,7 +69,7 @@ void BisqwitNtscFilter::ApplyFilter(uint16_t *ppuOutputBuffer)
7069

7170
_workDone = false;
7271
_waitWork.Signal();
73-
DecodeFrame(GetOverscan().Top, 120, ppuOutputBuffer, GetOutputBuffer(), (IsOddFrame() ? 8 : 0) + GetOverscan().Top*341*8, _SMPTE_C);
72+
DecodeFrame(GetOverscan().Top, 120, ppuOutputBuffer, GetOutputBuffer(), (IsOddFrame() ? 8 : 0) + GetOverscan().Top*341*8);
7473
while(!_workDone) {}
7574
}
7675

@@ -94,6 +93,11 @@ void BisqwitNtscFilter::OnBeforeApplyFilter()
9493
const double pi = std::atan(1.0) * 4;
9594
int contrast = (int)((pictureSettings.Contrast + 1.0) * (pictureSettings.Contrast + 1.0) * 167941);
9695
int saturation = (int)((pictureSettings.Saturation + 1.0) * (pictureSettings.Saturation + 1.0) * 144044);
96+
bool colorimetryCorrection = _console->GetSettings()->GetNtscFilterSettings().ColorimetryCorrection;
97+
98+
// [saturation at 0] * 100 / [I or Q width at 0]
99+
double SatFactor = 144044 * 100 / 12;
100+
97101
for(int i = 0; i < 27; i++) {
98102
_sinetable[i] = (int8_t)(8 * std::sin(i * 2 * pi / 12 + pictureSettings.Hue * pi));
99103
}
@@ -104,30 +108,14 @@ void BisqwitNtscFilter::OnBeforeApplyFilter()
104108

105109
_y = contrast / _yWidth;
106110

107-
// magic numbers is corresponding values from the YIQ to RGB formula
108-
// but divided by 13,995 * [arbitrary value]
109-
/*
110-
_ir = (int)(( 0.95599 / (13995 * 34.2457747)) * contrast * saturation / _iWidth);
111-
_ig = (int)((-0.27201 / (13995 * 212.3864250)) * contrast * saturation / _iWidth);
112-
_ib = (int)((-1.10674 / (13995 * 78.0674723)) * contrast * saturation / _iWidth);
113-
_qr = (int)(( 0.62082 / (13995 * 44.7370743)) * contrast * saturation / _qWidth);
114-
_qg = (int)((-0.64720 / (13995 * 73.0015960)) * contrast * saturation / _qWidth);
115-
_qb = (int)(( 1.70423 / (13995 * 73.0404051)) * contrast * saturation / _qWidth);
116-
*/
117-
_ir = (int)(contrast * 1.994681e-6 * saturation / _iWidth);
118-
_ig = (int)(contrast * 9.151351e-8 * saturation / _iWidth);
119-
_ib = (int)(contrast * -1.012984e-6 * saturation / _iWidth);
120-
_qr = (int)(contrast * 9.915742e-7 * saturation / _qWidth);
121-
_qg = (int)(contrast * -6.334805e-7 * saturation / _qWidth);
122-
_qb = (int)(contrast * 1.667217e-6 * saturation / _qWidth);
123-
124-
// alternate values based on the SMPTE C color primaries
125-
_irC = (int)((0.95599 / (13995 * 80)) * contrast * saturation / _iWidth);
126-
_igC = (int)((-0.27201 / (13995 * 80)) * contrast * saturation / _iWidth);
127-
_ibC = (int)((-1.10674 / (13995 * 80)) * contrast * saturation / _iWidth);
128-
_qrC = (int)((0.62082 / (13995 * 80)) * contrast * saturation / _qWidth);
129-
_qgC = (int)((-0.64720 / (13995 * 80)) * contrast * saturation / _qWidth);
130-
_qbC = (int)((1.70423 / (13995 * 80)) * contrast * saturation / _qWidth);
111+
_ir = colorimetryCorrection ? (int)(contrast * 1.994681e-6 * saturation / _iWidth) : (int)(contrast * (0.95599 / SatFactor) * saturation / _iWidth);
112+
_qr = colorimetryCorrection ? (int)(contrast * 9.915742e-7 * saturation / _qWidth) : (int)(contrast * (0.62082 / SatFactor) * saturation / _qWidth);
113+
114+
_ig = colorimetryCorrection ? (int)(contrast * 9.151351e-8 * saturation / _iWidth) : (int)(contrast * (-0.27201 / SatFactor) * saturation / _iWidth);
115+
_qg = colorimetryCorrection ? (int)(contrast * -6.334805e-7 * saturation / _qWidth) : (int)(contrast * (-0.64720 / SatFactor) * saturation / _qWidth);
116+
117+
_ib = colorimetryCorrection ? (int)(contrast * -1.012984e-6 * saturation / _iWidth) : (int)(contrast * (-1.10674 / SatFactor) * saturation / _iWidth);
118+
_qb = colorimetryCorrection ? (int)(contrast * 1.667217e-6 * saturation / _qWidth) : (int)(contrast * (1.70423 / SatFactor) * saturation / _qWidth);
131119
}
132120

133121
void BisqwitNtscFilter::RecursiveBlend(int iterationCount, uint64_t *output, uint64_t *currentLine, uint64_t *nextLine, int pixelsPerCycle, bool verticalBlend)
@@ -209,7 +197,7 @@ void BisqwitNtscFilter::GenerateNtscSignal(int8_t *ntscSignal, int &phase, int r
209197
phase += (341 - 256 - _paddingSize * 2) * _signalsPerPixel;
210198
}
211199

212-
void BisqwitNtscFilter::DecodeFrame(int startRow, int endRow, uint16_t *ppuOutputBuffer, uint32_t* outputBuffer, int startPhase, bool SMPTE_C)
200+
void BisqwitNtscFilter::DecodeFrame(int startRow, int endRow, uint16_t *ppuOutputBuffer, uint32_t* outputBuffer, int startPhase)
213201
{
214202
int pixelsPerCycle = 8 / _resDivider;
215203
int phase = startPhase;
@@ -229,7 +217,7 @@ void BisqwitNtscFilter::DecodeFrame(int startRow, int endRow, uint16_t *ppuOutpu
229217
GenerateNtscSignal(rowSignal, phase, y);
230218

231219
//Convert the NTSC signal to RGB
232-
NtscDecodeLine(lineWidth * _signalsPerPixel, rowSignal, outputBuffer, (startCycle + 7) % 12, SMPTE_C);
220+
NtscDecodeLine(lineWidth * _signalsPerPixel, rowSignal, outputBuffer, (startCycle + 7) % 12);
233221

234222
outputBuffer += rowPixelGap;
235223
}
@@ -281,7 +269,7 @@ void BisqwitNtscFilter::DecodeFrame(int startRow, int endRow, uint16_t *ppuOutpu
281269
* In essence it conveys in one integer the same information that real NTSC signal
282270
* would convey in the colorburst period in the beginning of each scanline.
283271
*/
284-
void BisqwitNtscFilter::NtscDecodeLine(int width, const int8_t* signal, uint32_t* target, int phase0, bool SMPTE_C)
272+
void BisqwitNtscFilter::NtscDecodeLine(int width, const int8_t* signal, uint32_t* target, int phase0)
285273
{
286274
auto Read = [=](int pos) -> char { return pos >= 0 ? signal[pos] : 0; };
287275
auto Cos = [=](int pos) -> char { return _sinetable[(pos + 36) % 12 + phase0]; };
@@ -299,9 +287,9 @@ void BisqwitNtscFilter::NtscDecodeLine(int width, const int8_t* signal, uint32_t
299287
qsum += Read(s) * Sin(s) - Read(s - _qWidth) * Sin(s - _qWidth);
300288

301289
if(!(s % _resDivider) && s >= leftOverscan) {
302-
int r = std::min(255, std::max(0, (ysum*_y + isum*(SMPTE_C ? _irC : _ir) + qsum*(SMPTE_C ? _qrC : _qr)) / 65536));
303-
int g = std::min(255, std::max(0, (ysum*_y + isum*(SMPTE_C ? _igC : _ig) + qsum*(SMPTE_C ? _qgC : _qg)) / 65536));
304-
int b = std::min(255, std::max(0, (ysum*_y + isum*(SMPTE_C ? _ibC : _ib) + qsum*(SMPTE_C ? _qbC : _qb)) / 65536));
290+
int r = std::min(255, std::max(0, (ysum*_y + isum*_ir + qsum*_qr) / 65536));
291+
int g = std::min(255, std::max(0, (ysum*_y + isum*_ig + qsum*_qg) / 65536));
292+
int b = std::min(255, std::max(0, (ysum*_y + isum*_ib + qsum*_qb) / 65536));
305293

306294
*target = 0xFF000000 | (r << 16) | (g << 8) | b;
307295
target++;

Core/BisqwitNtscFilter.h

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ class BisqwitNtscFilter : public BaseVideoFilter
2020
atomic<bool> _workDone;
2121

2222
bool _keepVerticalRes = false;
23-
bool _SMPTE_C = false;
2423

2524
int _resDivider = 1;
2625
uint16_t *_ppuOutputBuffer = nullptr;
@@ -34,8 +33,8 @@ class BisqwitNtscFilter : public BaseVideoFilter
3433
*/
3534
int _yWidth, _iWidth, _qWidth;
3635
int _y;
37-
int _ir, _ig, _ib, _irC, _igC, _ibC;
38-
int _qr, _qg, _qb, _qrC, _qgC, _qbC;
36+
int _ir, _ig, _ib;
37+
int _qr, _qg, _qb;
3938

4039
//To finetune hue, you would have to recalculate sinetable[]. (Coarse changes can be made with Phase0.)
4140
int8_t _sinetable[27]; // 8*sin(x*2pi/12)
@@ -44,14 +43,14 @@ class BisqwitNtscFilter : public BaseVideoFilter
4443

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

47-
void NtscDecodeLine(int width, const int8_t* signal, uint32_t* target, int phase0, bool SMPTE_C);
46+
void NtscDecodeLine(int width, const int8_t* signal, uint32_t* target, int phase0);
4847

4948
void GenerateNtscSignal(int8_t *ntscSignal, int &phase, int rowNumber);
50-
void DecodeFrame(int startRow, int endRow, uint16_t *ppuOutputBuffer, uint32_t* outputBuffer, int startPhase, bool SMPTE_C);
49+
void DecodeFrame(int startRow, int endRow, uint16_t *ppuOutputBuffer, uint32_t* outputBuffer, int startPhase);
5150
void OnBeforeApplyFilter();
5251

5352
public:
54-
BisqwitNtscFilter(shared_ptr<Console> console, int resDivider, bool SMPTE_C);
53+
BisqwitNtscFilter(shared_ptr<Console> console, int resDivider);
5554
virtual ~BisqwitNtscFilter();
5655

5756
virtual void ApplyFilter(uint16_t *ppuOutputBuffer);

Core/EmulationSettings.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -168,9 +168,6 @@ enum class VideoFilterType
168168
Prescale8x = 23,
169169
Prescale10x = 24,
170170
Raw = 25,
171-
BisqwitNtscSMPTECQuarterRes = 26,
172-
BisqwitNtscSMPTECHalfRes = 27,
173-
BisqwitNtscSMPTEC = 28,
174171
HdPack = 999
175172
};
176173

@@ -234,6 +231,7 @@ struct NtscFilterSettings
234231
bool MergeFields = false;
235232
bool VerticalBlend = false;
236233
bool KeepVerticalResolution = false;
234+
bool ColorimetryCorrection = true;
237235

238236
double YFilterLength = 0;
239237
double IFilterLength = 0;
@@ -1226,7 +1224,7 @@ class EmulationSettings
12261224
return _pictureSettings;
12271225
}
12281226

1229-
void SetNtscFilterSettings(double artifacts, double bleed, double fringing, double gamma, double resolution, double sharpness, bool mergeFields, double yFilterLength, double iFilterLength, double qFilterLength, bool verticalBlend, bool keepVerticalResolution)
1227+
void SetNtscFilterSettings(double artifacts, double bleed, double fringing, double gamma, double resolution, double sharpness, bool mergeFields, double yFilterLength, double iFilterLength, double qFilterLength, bool verticalBlend, bool keepVerticalResolution, bool colorimetryCorrection)
12301228
{
12311229
_ntscFilterSettings.Artifacts = artifacts;
12321230
_ntscFilterSettings.Bleed = bleed;
@@ -1243,6 +1241,7 @@ class EmulationSettings
12431241

12441242
_ntscFilterSettings.VerticalBlend = verticalBlend;
12451243
_ntscFilterSettings.KeepVerticalResolution = keepVerticalResolution;
1244+
_ntscFilterSettings.ColorimetryCorrection = colorimetryCorrection;
12461245
}
12471246

12481247
NtscFilterSettings GetNtscFilterSettings()

Core/ScaleFilter.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,6 @@ shared_ptr<ScaleFilter> ScaleFilter::GetScaleFilter(VideoFilterType filter)
107107
case VideoFilterType::BisqwitNtsc:
108108
case VideoFilterType::BisqwitNtscHalfRes:
109109
case VideoFilterType::BisqwitNtscQuarterRes:
110-
case VideoFilterType::BisqwitNtscSMPTEC:
111-
case VideoFilterType::BisqwitNtscSMPTECHalfRes:
112-
case VideoFilterType::BisqwitNtscSMPTECQuarterRes:
113110
case VideoFilterType::NTSC:
114111
case VideoFilterType::HdPack:
115112
case VideoFilterType::Raw:

Core/VideoDecoder.cpp

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,9 @@ void VideoDecoder::UpdateVideoFilter()
7070
switch(_videoFilterType) {
7171
case VideoFilterType::None: break;
7272
case VideoFilterType::NTSC: _videoFilter.reset(new NtscFilter(_console)); break;
73-
case VideoFilterType::BisqwitNtsc: _videoFilter.reset(new BisqwitNtscFilter(_console, 1, false)); break;
74-
case VideoFilterType::BisqwitNtscHalfRes: _videoFilter.reset(new BisqwitNtscFilter(_console, 2, false)); break;
75-
case VideoFilterType::BisqwitNtscQuarterRes: _videoFilter.reset(new BisqwitNtscFilter(_console, 4, false)); break;
76-
case VideoFilterType::BisqwitNtscSMPTEC: _videoFilter.reset(new BisqwitNtscFilter(_console, 1, true)); break;
77-
case VideoFilterType::BisqwitNtscSMPTECHalfRes: _videoFilter.reset(new BisqwitNtscFilter(_console, 2, true)); break;
78-
case VideoFilterType::BisqwitNtscSMPTECQuarterRes: _videoFilter.reset(new BisqwitNtscFilter(_console, 4, true)); break;
73+
case VideoFilterType::BisqwitNtsc: _videoFilter.reset(new BisqwitNtscFilter(_console, 1)); break;
74+
case VideoFilterType::BisqwitNtscHalfRes: _videoFilter.reset(new BisqwitNtscFilter(_console, 2)); break;
75+
case VideoFilterType::BisqwitNtscQuarterRes: _videoFilter.reset(new BisqwitNtscFilter(_console, 4)); break;
7976
case VideoFilterType::Raw: _videoFilter.reset(new RawVideoFilter(_console)); break;
8077
default: _scaleFilter = ScaleFilter::GetScaleFilter(_videoFilterType); break;
8178
}

GUI.NET/Config/VideoInfo.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ public class VideoInfo
4141
[MinMax(-100, 100)] public Int32 NtscSharpness = 0;
4242
public bool NtscMergeFields = false;
4343
public bool NtscVerticalBlend = true;
44+
public bool NtscColorimetryCorrection = true;
4445

4546
[MinMax(-50, 400)] public Int32 NtscYFilterLength = 0;
4647
[MinMax(0, 400)] public Int32 NtscIFilterLength = 50;
@@ -109,7 +110,7 @@ static public void ApplyConfig()
109110
InteropEmu.SetVideoAspectRatio(videoInfo.AspectRatio, videoInfo.CustomAspectRatio);
110111

111112
InteropEmu.SetPictureSettings(videoInfo.Brightness / 100.0, videoInfo.Contrast / 100.0, videoInfo.Saturation / 100.0, videoInfo.Hue / 100.0, videoInfo.ScanlineIntensity / 100.0);
112-
InteropEmu.SetNtscFilterSettings(videoInfo.NtscArtifacts / 100.0, videoInfo.NtscBleed / 100.0, videoInfo.NtscFringing / 100.0, videoInfo.NtscGamma / 100.0, videoInfo.NtscResolution / 100.0, videoInfo.NtscSharpness / 100.0, videoInfo.NtscMergeFields, videoInfo.NtscYFilterLength / 100.0, videoInfo.NtscIFilterLength / 100.0, videoInfo.NtscQFilterLength / 100.0, videoInfo.NtscVerticalBlend);
113+
InteropEmu.SetNtscFilterSettings(videoInfo.NtscArtifacts / 100.0, videoInfo.NtscBleed / 100.0, videoInfo.NtscFringing / 100.0, videoInfo.NtscGamma / 100.0, videoInfo.NtscResolution / 100.0, videoInfo.NtscSharpness / 100.0, videoInfo.NtscMergeFields, videoInfo.NtscYFilterLength / 100.0, videoInfo.NtscIFilterLength / 100.0, videoInfo.NtscQFilterLength / 100.0, videoInfo.NtscVerticalBlend, videoInfo.NtscColorimetryCorrection);
113114

114115
if(!string.IsNullOrWhiteSpace(videoInfo.PaletteData)) {
115116
try {

0 commit comments

Comments
 (0)