diff --git a/OSBindings/Mac/Clock Signal/ScanTarget/CSScanTarget.mm b/OSBindings/Mac/Clock Signal/ScanTarget/CSScanTarget.mm index 2f5faedf2..fd6afff8b 100644 --- a/OSBindings/Mac/Clock Signal/ScanTarget/CSScanTarget.mm +++ b/OSBindings/Mac/Clock Signal/ScanTarget/CSScanTarget.mm @@ -540,7 +540,7 @@ using BufferingScanTarget = Outputs::Display::BufferingScanTarget; uniforms()->cyclesMultiplier = 1.0f; if(_pipeline != Pipeline::DirectToDisplay) { - // Pick a suitable cycle multiplier. + // Pick a suitable cycle multiplier. TODO: can I reduce this from a multiple of 4? const float minimumSize = 4.0f * float(modals.colour_cycle_numerator) / float(modals.colour_cycle_denominator); while(uniforms()->cyclesMultiplier * modals.cycles_per_line < minimumSize) { uniforms()->cyclesMultiplier += 1.0f; @@ -568,18 +568,28 @@ using BufferingScanTarget = Outputs::Display::BufferingScanTarget; { auto *const chromaCoefficients = uniforms()->chromaCoefficients; SignalProcessing::FIRFilter chrominancefilter(15, float(_lineBufferPixelsPerLine), 0.0f, colourCyclesPerLine * 0.25f); // * (isSVideoOutput ? 1.0f : 0.25f) - const auto calculatedCoefficients = chrominancefilter.get_coefficients(); + const auto calculatedChromaCoefficients = chrominancefilter.get_coefficients(); for(size_t c = 0; c < 8; ++c) { - chromaCoefficients[c].y = chromaCoefficients[c].z = calculatedCoefficients[c] * (isSVideoOutput ? 4.0f : 4.0f); + chromaCoefficients[c].y = chromaCoefficients[c].z = calculatedChromaCoefficients[c] * (isSVideoOutput ? 4.0f : 4.0f); chromaCoefficients[c].x = 0.0f; } chromaCoefficients[7].x = 1.0f; + + // Luminance is under-filtered during the separation phase in order not to subtract too much from chrominance; + // therefore an additional filtering is applied here. + if(!isSVideoOutput) { + SignalProcessing::FIRFilter luminancefilter(15, float(_lineBufferPixelsPerLine), 0.0f, colourCyclesPerLine); + const auto calculatedLumaCoefficients = luminancefilter.get_coefficients(); + for(size_t c = 0; c < 8; ++c) { + chromaCoefficients[c].x = calculatedLumaCoefficients[c]; + } + } } - // Generate the luminance filter. + // Generate the luminance separation filter. { auto *const luminanceCoefficients = uniforms()->lumaCoefficients; - SignalProcessing::FIRFilter luminancefilter(15, float(_lineBufferPixelsPerLine), 0.0f, colourCyclesPerLine); + SignalProcessing::FIRFilter luminancefilter(15, float(_lineBufferPixelsPerLine), 0.0f, colourCyclesPerLine * 1.25f); const auto calculatedCoefficients = luminancefilter.get_coefficients(); memcpy(luminanceCoefficients, calculatedCoefficients.data(), sizeof(float)*8); } diff --git a/OSBindings/Mac/Clock Signal/ScanTarget/ScanTarget.metal b/OSBindings/Mac/Clock Signal/ScanTarget/ScanTarget.metal index c98c7c8b2..ac67ff1d8 100644 --- a/OSBindings/Mac/Clock Signal/ScanTarget/ScanTarget.metal +++ b/OSBindings/Mac/Clock Signal/ScanTarget/ScanTarget.metal @@ -295,7 +295,7 @@ float3 convertRed1Green1Blue1(SourceInterpolator vert, texture2d texture } \ \ fragment float4 svideoSample##name(SourceInterpolator vert [[stage_in]], texture2d texture [[texture(0)]], constant Uniforms &uniforms [[buffer(0)]]) { \ - const auto colour = uniforms.fromRGB * convert##name(vert, texture); \ + const auto colour = uniforms.fromRGB * clamp(convert##name(vert, texture), float(0.0f), float(1.0f)); \ const float2 qam = quadrature(vert.colourPhase); \ const float chroma = dot(colour.gb, qam); \ return float4( \ @@ -306,7 +306,7 @@ float3 convertRed1Green1Blue1(SourceInterpolator vert, texture2d texture } \ \ fragment float4 compositeSample##name(SourceInterpolator vert [[stage_in]], texture2d texture [[texture(0)]], constant Uniforms &uniforms [[buffer(0)]]) { \ - const auto colour = uniforms.fromRGB * convert##name(vert, texture); \ + const auto colour = uniforms.fromRGB * clamp(convert##name(vert, texture), float3(0.0f), float3(1.0f)); \ const float2 colourSubcarrier = quadrature(vert.colourPhase); \ const float level = mix(colour.r, dot(colour.gb, colourSubcarrier), vert.colourAmplitude); \ return float4( \ @@ -442,10 +442,10 @@ kernel void separateLumaKernel( texture2d inTexture [[textu #undef Sample // TODO: determine why centreSample.a doesn't seem to be giving the real composite amplitude, and stop - // hard-coding 0.15f below. + // hard-coding 0.15f and 7.0f below. outTexture.write(float4( luminance / (1.0f - 0.15f), - (centreSample.gb - float2(0.5f)) * (centreSample.r - luminance) + float2(0.5f), + (centreSample.gb - float2(0.5f)) * (centreSample.r - luminance) * 28.0f + float2(0.5f), 1.0f ), gid + uint2(7, offset));