From 1a4ffac26eabbd19251b74aa4b08ef401011caaf Mon Sep 17 00:00:00 2001 From: Marek Ossowski Date: Fri, 22 Aug 2025 22:09:18 +0200 Subject: [PATCH] Renaming and refactoring --- app/src/main/java/xdsopl/robot36/Decoder.java | 66 ++++++++++--------- .../main/java/xdsopl/robot36/Demodulator.java | 23 ++++--- app/src/main/java/xdsopl/robot36/Mode.java | 10 ++- app/src/main/java/xdsopl/robot36/PaulDon.java | 6 +- .../main/java/xdsopl/robot36/RGBDecoder.java | 6 +- .../main/java/xdsopl/robot36/RawDecoder.java | 6 +- .../java/xdsopl/robot36/Robot_36_Color.java | 6 +- .../java/xdsopl/robot36/Robot_72_Color.java | 6 +- 8 files changed, 72 insertions(+), 57 deletions(-) diff --git a/app/src/main/java/xdsopl/robot36/Decoder.java b/app/src/main/java/xdsopl/robot36/Decoder.java index dc7d9ea..ced9c00 100644 --- a/app/src/main/java/xdsopl/robot36/Decoder.java +++ b/app/src/main/java/xdsopl/robot36/Decoder.java @@ -157,7 +157,7 @@ public class Decoder { private Mode findMode(ArrayList modes, int code) { for (Mode mode : modes) - if (mode.getCode() == code) + if (mode.getVISCode() == code) return mode; return null; } @@ -332,7 +332,7 @@ public class Decoder { } if (lockMode && mode != currentMode) return false; - mode.reset(); + mode.resetState(); imageBuffer.width = mode.getWidth(); imageBuffer.height = mode.getHeight(); imageBuffer.line = 0; @@ -346,29 +346,29 @@ public class Decoder { for (int i = 0; i < pulses.length; ++i) pulses[i] = oldestSyncPulseIndex + i * currentScanLineSamples; Arrays.fill(lines, currentScanLineSamples); - shiftSamples(lastSyncPulseIndex + mode.getBegin()); + shiftSamples(lastSyncPulseIndex + mode.getFirstPixelSampleIndex()); drawLines(0xff00ff00, 8); drawLines(0xff000000, 10); return true; } - private boolean processSyncPulse(ArrayList modes, float[] freqOffs, int[] pulses, int[] lines, int index) { - for (int i = 1; i < pulses.length; ++i) - pulses[i - 1] = pulses[i]; - pulses[pulses.length - 1] = index; - for (int i = 1; i < lines.length; ++i) - lines[i - 1] = lines[i]; - lines[lines.length - 1] = pulses[pulses.length - 1] - pulses[pulses.length - 2]; + private boolean processSyncPulse(ArrayList modes, float[] freqOffs, int[] syncIndexes, int[] lineLengths, int latestSyncIndex) { + for (int i = 1; i < syncIndexes.length; ++i) + syncIndexes[i - 1] = syncIndexes[i]; + syncIndexes[syncIndexes.length - 1] = latestSyncIndex; + for (int i = 1; i < lineLengths.length; ++i) + lineLengths[i - 1] = lineLengths[i]; + lineLengths[lineLengths.length - 1] = syncIndexes[syncIndexes.length - 1] - syncIndexes[syncIndexes.length - 2]; for (int i = 1; i < freqOffs.length; ++i) freqOffs[i - 1] = freqOffs[i]; - freqOffs[pulses.length - 1] = demodulator.frequencyOffset; - if (lines[0] == 0) + freqOffs[syncIndexes.length - 1] = demodulator.frequencyOffset; + if (lineLengths[0] == 0) return false; - double mean = scanLineMean(lines); + double mean = scanLineMean(lineLengths); int scanLineSamples = (int) Math.round(mean); if (scanLineSamples < scanLineMinSamples || scanLineSamples > scratchBuffer.length) return false; - if (scanLineStdDev(lines, mean) > scanLineToleranceSamples) + if (scanLineStdDev(lineLengths, mean) > scanLineToleranceSamples) return false; boolean pictureChanged = false; if (lockMode || imageBuffer.line >= 0 && imageBuffer.line < imageBuffer.height) { @@ -379,7 +379,7 @@ public class Decoder { currentMode = detectMode(modes, scanLineSamples); pictureChanged = currentMode != prevMode || Math.abs(currentScanLineSamples - scanLineSamples) > scanLineToleranceSamples - || Math.abs(lastSyncPulseIndex + scanLineSamples - pulses[pulses.length - 1]) > syncPulseToleranceSamples; + || Math.abs(lastSyncPulseIndex + scanLineSamples - syncIndexes[syncIndexes.length - 1]) > syncPulseToleranceSamples; } if (pictureChanged) { drawLines(0xff000000, 10); @@ -387,23 +387,24 @@ public class Decoder { drawLines(0xff000000, 10); } float frequencyOffset = (float) frequencyOffsetMean(freqOffs); - if (pulses[0] >= scanLineSamples && pictureChanged) { - int endPulse = pulses[0]; + if (syncIndexes[0] >= scanLineSamples && pictureChanged) { + int endPulse = syncIndexes[0]; int extrapolate = endPulse / scanLineSamples; int firstPulse = endPulse - extrapolate * scanLineSamples; for (int pulseIndex = firstPulse; pulseIndex < endPulse; pulseIndex += scanLineSamples) copyLines(currentMode.decodeScanLine(pixelBuffer, scratchBuffer, scanLineBuffer, scopeBuffer.width, pulseIndex, scanLineSamples, frequencyOffset)); } - for (int i = pictureChanged ? 0 : lines.length - 1; i < lines.length; ++i) - copyLines(currentMode.decodeScanLine(pixelBuffer, scratchBuffer, scanLineBuffer, scopeBuffer.width, pulses[i], lines[i], frequencyOffset)); - lastSyncPulseIndex = pulses[pulses.length - 1]; + for (int i = pictureChanged ? 0 : lineLengths.length - 1; i < lineLengths.length; ++i) + copyLines(currentMode.decodeScanLine(pixelBuffer, scratchBuffer, scanLineBuffer, scopeBuffer.width, syncIndexes[i], lineLengths[i], frequencyOffset)); + lastSyncPulseIndex = syncIndexes[syncIndexes.length - 1]; currentScanLineSamples = scanLineSamples; lastFrequencyOffset = frequencyOffset; - shiftSamples(lastSyncPulseIndex + currentMode.getBegin()); + shiftSamples(lastSyncPulseIndex + currentMode.getFirstPixelSampleIndex()); return true; } public boolean process(float[] recordBuffer, int channelSelect) { + boolean newLinesPresent = false; boolean syncPulseDetected = demodulator.process(recordBuffer, channelSelect); int syncPulseIndex = currentSample + demodulator.syncPulseOffset; int channels = channelSelect > 0 ? 2 : 1; @@ -417,25 +418,28 @@ public class Decoder { if (syncPulseDetected) { switch (demodulator.syncPulseWidth) { case FiveMilliSeconds: - return processSyncPulse(syncPulse5msModes, last5msFrequencyOffsets, last5msSyncPulses, last5msScanLines, syncPulseIndex); + newLinesPresent = processSyncPulse(syncPulse5msModes, last5msFrequencyOffsets, last5msSyncPulses, last5msScanLines, syncPulseIndex); + break; case NineMilliSeconds: leaderBreakIndex = syncPulseIndex; - return processSyncPulse(syncPulse9msModes, last9msFrequencyOffsets, last9msSyncPulses, last9msScanLines, syncPulseIndex); + newLinesPresent = processSyncPulse(syncPulse9msModes, last9msFrequencyOffsets, last9msSyncPulses, last9msScanLines, syncPulseIndex); + break; case TwentyMilliSeconds: leaderBreakIndex = syncPulseIndex; - return processSyncPulse(syncPulse20msModes, last20msFrequencyOffsets, last20msSyncPulses, last20msScanLines, syncPulseIndex); + newLinesPresent = processSyncPulse(syncPulse20msModes, last20msFrequencyOffsets, last20msSyncPulses, last20msScanLines, syncPulseIndex); + break; default: - return false; + break; } - } - if (handleHeader()) - return true; - if (currentSample > lastSyncPulseIndex + (currentScanLineSamples * 5) / 4) { + } else if (handleHeader()) { + newLinesPresent = true; + } else if (currentSample > lastSyncPulseIndex + (currentScanLineSamples * 5) / 4) { copyLines(currentMode.decodeScanLine(pixelBuffer, scratchBuffer, scanLineBuffer, scopeBuffer.width, lastSyncPulseIndex, currentScanLineSamples, lastFrequencyOffset)); lastSyncPulseIndex += currentScanLineSamples; - return true; + newLinesPresent = true; } - return false; + + return newLinesPresent; } public void setMode(String name) { diff --git a/app/src/main/java/xdsopl/robot36/Demodulator.java b/app/src/main/java/xdsopl/robot36/Demodulator.java index 2bf882a..b499dbf 100644 --- a/app/src/main/java/xdsopl/robot36/Demodulator.java +++ b/app/src/main/java/xdsopl/robot36/Demodulator.java @@ -13,6 +13,8 @@ public class Demodulator { private final SchmittTrigger syncPulseTrigger; private final Phasor baseBandOscillator; private final Delay syncPulseValueDelay; + private final double scanLineBandwidth; + private final double centerFrequency; private final float syncPulseFrequencyValue; private final float syncPulseFrequencyTolerance; private final int syncPulse5msMinSamples; @@ -33,10 +35,12 @@ public class Demodulator { public int syncPulseOffset; public float frequencyOffset; + public static final double syncPulseFrequency = 1200; + public static final double blackFrequency = 1500; + public static final double whiteFrequency = 2300; + Demodulator(int sampleRate) { - double blackFrequency = 1500; - double whiteFrequency = 2300; - double scanLineBandwidth = whiteFrequency - blackFrequency; + scanLineBandwidth = whiteFrequency - blackFrequency; frequencyModulation = new FrequencyModulation(scanLineBandwidth, sampleRate); double syncPulse5msSeconds = 0.005; double syncPulse9msSeconds = 0.009; @@ -63,20 +67,23 @@ public class Demodulator { Kaiser kaiser = new Kaiser(); for (int i = 0; i < baseBandLowPass.length; ++i) baseBandLowPass.taps[i] = (float) (kaiser.window(2.0, i, baseBandLowPass.length) * Filter.lowPass(cutoffFrequency, sampleRate, i, baseBandLowPass.length)); - double centerFrequency = (lowestFrequency + highestFrequency) / 2; + centerFrequency = (lowestFrequency + highestFrequency) / 2; baseBandOscillator = new Phasor(-centerFrequency, sampleRate); - double syncPulseFrequency = 1200; - syncPulseFrequencyValue = (float) ((syncPulseFrequency - centerFrequency) * 2 / scanLineBandwidth); + syncPulseFrequencyValue = (float) normalizeFrequency(syncPulseFrequency); syncPulseFrequencyTolerance = (float) (50 * 2 / scanLineBandwidth); double syncPorchFrequency = 1500; double syncHighFrequency = (syncPulseFrequency + syncPorchFrequency) / 2; double syncLowFrequency = (syncPulseFrequency + syncHighFrequency) / 2; - double syncLowValue = (syncLowFrequency - centerFrequency) * 2 / scanLineBandwidth; - double syncHighValue = (syncHighFrequency - centerFrequency) * 2 / scanLineBandwidth; + double syncLowValue = normalizeFrequency(syncLowFrequency); + double syncHighValue = normalizeFrequency(syncHighFrequency); syncPulseTrigger = new SchmittTrigger((float) syncLowValue, (float) syncHighValue); baseBand = new Complex(); } + private double normalizeFrequency(double frequency) { + return (frequency - centerFrequency) * 2 / scanLineBandwidth; + } + public boolean process(float[] buffer, int channelSelect) { boolean syncPulseDetected = false; int channels = channelSelect > 0 ? 2 : 1; diff --git a/app/src/main/java/xdsopl/robot36/Mode.java b/app/src/main/java/xdsopl/robot36/Mode.java index 3614711..f751112 100644 --- a/app/src/main/java/xdsopl/robot36/Mode.java +++ b/app/src/main/java/xdsopl/robot36/Mode.java @@ -9,19 +9,23 @@ package xdsopl.robot36; public interface Mode { String getName(); - int getCode(); + int getVISCode(); int getWidth(); int getHeight(); - int getBegin(); + int getFirstPixelSampleIndex(); int getFirstSyncPulseIndex(); int getScanLineSamples(); - void reset(); + void resetState(); + /** + * @param frequencyOffset normalized correction of frequency (expected vs actual) + * @return true if scanline was decoded + */ boolean decodeScanLine(PixelBuffer pixelBuffer, float[] scratchBuffer, float[] scanLineBuffer, int scopeBufferWidth, int syncPulseIndex, int scanLineSamples, float frequencyOffset); } diff --git a/app/src/main/java/xdsopl/robot36/PaulDon.java b/app/src/main/java/xdsopl/robot36/PaulDon.java index 8883081..74ab9d3 100644 --- a/app/src/main/java/xdsopl/robot36/PaulDon.java +++ b/app/src/main/java/xdsopl/robot36/PaulDon.java @@ -56,7 +56,7 @@ public class PaulDon implements Mode { } @Override - public int getCode() { + public int getVISCode() { return code; } @@ -71,7 +71,7 @@ public class PaulDon implements Mode { } @Override - public int getBegin() { + public int getFirstPixelSampleIndex() { return beginSamples; } @@ -86,7 +86,7 @@ public class PaulDon implements Mode { } @Override - public void reset() { + public void resetState() { } @Override diff --git a/app/src/main/java/xdsopl/robot36/RGBDecoder.java b/app/src/main/java/xdsopl/robot36/RGBDecoder.java index febef26..12de680 100644 --- a/app/src/main/java/xdsopl/robot36/RGBDecoder.java +++ b/app/src/main/java/xdsopl/robot36/RGBDecoder.java @@ -51,7 +51,7 @@ public class RGBDecoder implements Mode { } @Override - public int getCode() { + public int getVISCode() { return code; } @@ -66,7 +66,7 @@ public class RGBDecoder implements Mode { } @Override - public int getBegin() { + public int getFirstPixelSampleIndex() { return beginSamples; } @@ -81,7 +81,7 @@ public class RGBDecoder implements Mode { } @Override - public void reset() { + public void resetState() { } @Override diff --git a/app/src/main/java/xdsopl/robot36/RawDecoder.java b/app/src/main/java/xdsopl/robot36/RawDecoder.java index f86a63d..1620363 100644 --- a/app/src/main/java/xdsopl/robot36/RawDecoder.java +++ b/app/src/main/java/xdsopl/robot36/RawDecoder.java @@ -29,7 +29,7 @@ public class RawDecoder implements Mode { } @Override - public int getCode() { + public int getVISCode() { return -1; } @@ -44,7 +44,7 @@ public class RawDecoder implements Mode { } @Override - public int getBegin() { + public int getFirstPixelSampleIndex() { return 0; } @@ -59,7 +59,7 @@ public class RawDecoder implements Mode { } @Override - public void reset() { + public void resetState() { } @Override diff --git a/app/src/main/java/xdsopl/robot36/Robot_36_Color.java b/app/src/main/java/xdsopl/robot36/Robot_36_Color.java index 8ccdcdb..129e0f1 100644 --- a/app/src/main/java/xdsopl/robot36/Robot_36_Color.java +++ b/app/src/main/java/xdsopl/robot36/Robot_36_Color.java @@ -59,7 +59,7 @@ public class Robot_36_Color implements Mode { } @Override - public int getCode() { + public int getVISCode() { return 8; } @@ -74,7 +74,7 @@ public class Robot_36_Color implements Mode { } @Override - public int getBegin() { + public int getFirstPixelSampleIndex() { return beginSamples; } @@ -89,7 +89,7 @@ public class Robot_36_Color implements Mode { } @Override - public void reset() { + public void resetState() { lastEven = false; } diff --git a/app/src/main/java/xdsopl/robot36/Robot_72_Color.java b/app/src/main/java/xdsopl/robot36/Robot_72_Color.java index 88a9786..07a0564 100644 --- a/app/src/main/java/xdsopl/robot36/Robot_72_Color.java +++ b/app/src/main/java/xdsopl/robot36/Robot_72_Color.java @@ -57,7 +57,7 @@ public class Robot_72_Color implements Mode { } @Override - public int getCode() { + public int getVISCode() { return 12; } @@ -72,7 +72,7 @@ public class Robot_72_Color implements Mode { } @Override - public int getBegin() { + public int getFirstPixelSampleIndex() { return beginSamples; } @@ -87,7 +87,7 @@ public class Robot_72_Color implements Mode { } @Override - public void reset() { + public void resetState() { } @Override