From a943a0b59ad1d438efce3464c2dbac32a4e4d715 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 17 Jul 2022 19:22:09 -0400 Subject: [PATCH 1/2] Make sharpening slightly more aggressive. --- .../Clock Signal/ScanTarget/CSScanTarget.mm | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/OSBindings/Mac/Clock Signal/ScanTarget/CSScanTarget.mm b/OSBindings/Mac/Clock Signal/ScanTarget/CSScanTarget.mm index a58a499b8..547d37735 100644 --- a/OSBindings/Mac/Clock Signal/ScanTarget/CSScanTarget.mm +++ b/OSBindings/Mac/Clock Signal/ScanTarget/CSScanTarget.mm @@ -747,6 +747,8 @@ using BufferingScanTarget = Outputs::Display::BufferingScanTarget; const auto chromaCoefficients = boxCoefficients(radiansPerPixel, 3.141592654f); _chromaKernelSize = 15; for(size_t c = 0; c < 8; ++c) { + // Bit of a fix here: if the pipeline is for composite then assume that chroma separation wasn't + // perfect and deemphasise the colour. firCoefficients[c].y = firCoefficients[c].z = (isSVideoOutput ? 2.0f : 1.0f) * chromaCoefficients[c]; firCoefficients[c].x = 0.0f; if(fabsf(chromaCoefficients[c]) < 0.01f) { @@ -756,13 +758,20 @@ using BufferingScanTarget = Outputs::Display::BufferingScanTarget; firCoefficients[7].x = 1.0f; // Luminance will be very soft as a result of the separation phase; apply a sharpen filter to try to undo that. - // This is applied separately because the first composite processing step is going to select between the nominal - // chroma and luma parts to take the place of luminance depending on whether a colour burst was found, and high-pass - // filtering the chrominance channel would be visually detrimental. // - // The low cut off ['Hz' but per line, not per second] is somewhat arbitrary. + // This is applied separately in order to partition three parts of the signal rather than two: + // + // 1) the luminance; + // 2) not the luminance: + // 2a) the chrominance; and + // 2b) some noise. + // + // There are real numerical hazards here given the low number of taps I am permitting to be used, so the sharpen + // filter below is just one that I found worked well. Since all numbers are fixed, the actual cutoff frequency is + // going to be a function of the input clock, which is a bit phoney but the best way to stay safe within the + // PCM sampling limits. if(!isSVideoOutput) { - SignalProcessing::FIRFilter sharpenFilter(15, float(_lineBufferPixelsPerLine), 40.0f, colourCyclesPerLine); + SignalProcessing::FIRFilter sharpenFilter(15, 1368, 60.0f, 227.5f); const auto sharpen = sharpenFilter.get_coefficients(); size_t sharpenFilterSize = 15; bool isStart = true; From 28a7dc194c89438ac9a65929b4ba9f99bd67784d Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 17 Jul 2022 22:01:30 -0400 Subject: [PATCH 2/2] Increase saturation. --- OSBindings/Mac/Clock Signal/ScanTarget/CSScanTarget.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OSBindings/Mac/Clock Signal/ScanTarget/CSScanTarget.mm b/OSBindings/Mac/Clock Signal/ScanTarget/CSScanTarget.mm index 547d37735..5a895b66c 100644 --- a/OSBindings/Mac/Clock Signal/ScanTarget/CSScanTarget.mm +++ b/OSBindings/Mac/Clock Signal/ScanTarget/CSScanTarget.mm @@ -749,7 +749,7 @@ using BufferingScanTarget = Outputs::Display::BufferingScanTarget; for(size_t c = 0; c < 8; ++c) { // Bit of a fix here: if the pipeline is for composite then assume that chroma separation wasn't // perfect and deemphasise the colour. - firCoefficients[c].y = firCoefficients[c].z = (isSVideoOutput ? 2.0f : 1.0f) * chromaCoefficients[c]; + firCoefficients[c].y = firCoefficients[c].z = (isSVideoOutput ? 2.0f : 1.25f) * chromaCoefficients[c]; firCoefficients[c].x = 0.0f; if(fabsf(chromaCoefficients[c]) < 0.01f) { _chromaKernelSize -= 2;