1
0
mirror of https://github.com/TomHarte/CLK.git synced 2026-03-12 10:42:14 +00:00

Detect and expose is-interlaced flag.

With plenty of exposition to avoid confusing the reader into thinking that the emulator is predicated on this in an unrealistic fashion.
This commit is contained in:
Thomas Harte
2026-02-21 21:17:35 -05:00
parent f156265318
commit ea3e9a96f1
2 changed files with 40 additions and 0 deletions

View File

@@ -234,6 +234,29 @@ void BufferingScanTarget::announce(
++read;
frame_read_.store(read, std::memory_order_relaxed);
}
// Look for an even-odd pattern in start-of-frame line placement as an indication that
// incoming video is interlaced. That might be helpful information in deciding exactly
// how to display scans pleasantly, depending on the display target.
start_history_[start_history_pointer_] = location;
++start_history_pointer_;
static constexpr int CoordinateEpsilon = 100;
const auto similar_enough = [&](const size_t start, const size_t stride) {
for(size_t index = start + stride; index < start_history_.size(); index += stride) {
if(
abs(start_history_[index - stride].x - start_history_[index].x) > CoordinateEpsilon ||
abs(start_history_[index - stride].y - start_history_[index].y) > CoordinateEpsilon
) {
return false;
}
}
return true;
};
is_interlaced_.store(
!similar_enough(0, 1) && similar_enough(0, 2) && similar_enough(1, 2),
std::memory_order_relaxed
);
}
// Proceed from here only if a change in visibility has occurred.
@@ -416,3 +439,7 @@ const Outputs::Display::ScanTarget::Modals &BufferingScanTarget::modals() const
bool BufferingScanTarget::has_new_modals() const {
return modals_are_dirty_.load(std::memory_order_relaxed);
}
bool BufferingScanTarget::is_interlaced() const {
return is_interlaced_.load(std::memory_order_relaxed);
}

View File

@@ -164,6 +164,13 @@ public:
/// @returns the current @c Modals.
const Modals &modals() const;
/// @returns whether the current output being received appears to describe an interlaced signal.
/// This is a hint only, potentially to provide for better deinterlacing of output, being derived locally
/// from line positioning. Specifically: if a scan target pays no heed to this whatsoever it's likely to
/// end up doing the equivalent of a bob. If it so desires, it might prefer to do something closer to
/// a weave if and only if interlaced video is detected.
bool is_interlaced() const;
/// @returns @c true if new modals are available; @c false otherwise.
///
/// Safe to call from any thread.
@@ -317,6 +324,12 @@ private:
std::atomic<Numeric::CircularCounter<uint16_t, NumFrames>> frame_read_;
std::atomic<Numeric::CircularCounter<uint16_t, NumFrames>> frame_write_;
// A recent history of field start positions, to allow detection of interlaced video.
// That can be used as a hint for display purposes.
static constexpr size_t StartHistoryLength = 16;
std::array<Outputs::Display::ScanTarget::Scan::EndPoint, StartHistoryLength> start_history_;
Numeric::CircularCounter<size_t, StartHistoryLength> start_history_pointer_;
std::atomic<bool> is_interlaced_ = false;
// By convention everything in the PointerSet points to the next instance
// of whatever it is that will be used. So a client should start with whatever