diff --git a/app/src/main/java/xdsopl/robot36/Decoder.java b/app/src/main/java/xdsopl/robot36/Decoder.java index 29a872e..75eb167 100644 --- a/app/src/main/java/xdsopl/robot36/Decoder.java +++ b/app/src/main/java/xdsopl/robot36/Decoder.java @@ -12,6 +12,7 @@ public class Decoder { private final Demodulator demodulator; private final float[] scanLineBuffer; + private final float[] scratchBuffer; private final int[] evenBuffer; private final int[] oddBuffer; private final int[] scopePixels; @@ -51,6 +52,7 @@ public class Decoder { double scanLineMaxSeconds = 7; int scanLineMaxSamples = (int) Math.round(scanLineMaxSeconds * sampleRate); scanLineBuffer = new float[scanLineMaxSamples]; + scratchBuffer = new float[sampleRate]; int scanLineCount = 4; last5msScanLines = new int[scanLineCount]; last9msScanLines = new int[scanLineCount]; @@ -171,10 +173,10 @@ public class Decoder { int extrapolate = endPulse / scanLineSamples; int firstPulse = endPulse - extrapolate * scanLineSamples; for (int pulseIndex = firstPulse; pulseIndex < endPulse; pulseIndex += scanLineSamples) - copyLines(mode.decodeScanLine(evenBuffer, oddBuffer, scanLineBuffer, pulseIndex, scanLineSamples, frequencyOffset)); + copyLines(mode.decodeScanLine(evenBuffer, oddBuffer, scratchBuffer, scanLineBuffer, pulseIndex, scanLineSamples, frequencyOffset)); } for (int i = pictureChanged ? 0 : lines.length - 1; i < lines.length; ++i) - copyLines(mode.decodeScanLine(evenBuffer, oddBuffer, scanLineBuffer, pulses[i], lines[i], frequencyOffset)); + copyLines(mode.decodeScanLine(evenBuffer, oddBuffer, scratchBuffer, scanLineBuffer, pulses[i], lines[i], frequencyOffset)); int shift = pulses[pulses.length - 1] - scanLineReserveSamples; if (shift > scanLineReserveSamples) { adjustSyncPulses(last5msSyncPulses, shift); @@ -219,7 +221,7 @@ public class Decoder { return processSyncPulse(syncPulse20msModes, last20msFrequencyOffsets, last20msSyncPulses, last20msScanLines, syncPulseIndex); } } else if (lastSyncPulseIndex >= scanLineReserveSamples && curSample > lastSyncPulseIndex + (lastScanLineSamples * 5) / 4) { - copyLines(lastMode.decodeScanLine(evenBuffer, oddBuffer, scanLineBuffer, lastSyncPulseIndex, lastScanLineSamples, lastFrequencyOffset)); + copyLines(lastMode.decodeScanLine(evenBuffer, oddBuffer, scratchBuffer, scanLineBuffer, lastSyncPulseIndex, lastScanLineSamples, lastFrequencyOffset)); lastSyncPulseIndex += lastScanLineSamples; return true; } diff --git a/app/src/main/java/xdsopl/robot36/Mode.java b/app/src/main/java/xdsopl/robot36/Mode.java index 5fcf40b..a378049 100644 --- a/app/src/main/java/xdsopl/robot36/Mode.java +++ b/app/src/main/java/xdsopl/robot36/Mode.java @@ -11,5 +11,5 @@ public interface Mode { int getScanLineSamples(); - int decodeScanLine(int[] evenBuffer, int[] oddBuffer, float[] scanLineBuffer, int prevPulseIndex, int scanLineSamples, float frequencyOffset); + int decodeScanLine(int[] evenBuffer, int[] oddBuffer, float[] scratchBuffer, float[] scanLineBuffer, 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 8443f69..3428d7b 100644 --- a/app/src/main/java/xdsopl/robot36/PaulDon.java +++ b/app/src/main/java/xdsopl/robot36/PaulDon.java @@ -55,24 +55,24 @@ public class PaulDon implements Mode { } @Override - public int decodeScanLine(int[] evenBuffer, int[] oddBuffer, float[] scanLineBuffer, int prevPulseIndex, int scanLineSamples, float frequencyOffset) { - if (prevPulseIndex + beginSamples < 0 || prevPulseIndex + endSamples > scanLineBuffer.length) + public int decodeScanLine(int[] evenBuffer, int[] oddBuffer, float[] scratchBuffer, float[] scanLineBuffer, int syncPulseIndex, int scanLineSamples, float frequencyOffset) { + if (syncPulseIndex + beginSamples < 0 || syncPulseIndex + endSamples > scanLineBuffer.length) return 0; lowPassFilter.cutoff(evenBuffer.length, 2 * channelSamples, 2); lowPassFilter.reset(); - for (int i = prevPulseIndex + beginSamples; i < prevPulseIndex + endSamples; ++i) - scanLineBuffer[i] = lowPassFilter.avg(scanLineBuffer[i]); + for (int i = beginSamples; i < endSamples; ++i) + scratchBuffer[i] = lowPassFilter.avg(scanLineBuffer[syncPulseIndex + i]); lowPassFilter.reset(); - for (int i = prevPulseIndex + endSamples - 1; i >= prevPulseIndex + beginSamples; --i) - scanLineBuffer[i] = freqToLevel(lowPassFilter.avg(scanLineBuffer[i]), frequencyOffset); + for (int i = endSamples - 1; i >= beginSamples; --i) + scratchBuffer[i] = freqToLevel(lowPassFilter.avg(scratchBuffer[i]), frequencyOffset); for (int i = 0; i < evenBuffer.length; ++i) { - int position = (i * channelSamples) / evenBuffer.length + prevPulseIndex; + int position = (i * channelSamples) / evenBuffer.length; int yEvenPos = position + yEvenBeginSamples; int vAvgPos = position + vAvgBeginSamples; int uAvgPos = position + uAvgBeginSamples; int yOddPos = position + yOddBeginSamples; - evenBuffer[i] = ColorConverter.YUV2RGB(scanLineBuffer[yEvenPos], scanLineBuffer[uAvgPos], scanLineBuffer[vAvgPos]); - oddBuffer[i] = ColorConverter.YUV2RGB(scanLineBuffer[yOddPos], scanLineBuffer[uAvgPos], scanLineBuffer[vAvgPos]); + evenBuffer[i] = ColorConverter.YUV2RGB(scratchBuffer[yEvenPos], scratchBuffer[uAvgPos], scratchBuffer[vAvgPos]); + oddBuffer[i] = ColorConverter.YUV2RGB(scratchBuffer[yOddPos], scratchBuffer[uAvgPos], scratchBuffer[vAvgPos]); } return 2; } diff --git a/app/src/main/java/xdsopl/robot36/RGBDecoder.java b/app/src/main/java/xdsopl/robot36/RGBDecoder.java index 5350c47..056b361 100644 --- a/app/src/main/java/xdsopl/robot36/RGBDecoder.java +++ b/app/src/main/java/xdsopl/robot36/RGBDecoder.java @@ -48,21 +48,21 @@ public class RGBDecoder implements Mode { } @Override - public int decodeScanLine(int[] evenBuffer, int[] oddBuffer, float[] scanLineBuffer, int prevPulseIndex, int scanLineSamples, float frequencyOffset) { - if (prevPulseIndex + beginSamples < 0 || prevPulseIndex + endSamples > scanLineBuffer.length) + public int decodeScanLine(int[] evenBuffer, int[] oddBuffer, float[] scratchBuffer, float[] scanLineBuffer, int syncPulseIndex, int scanLineSamples, float frequencyOffset) { + if (syncPulseIndex + beginSamples < 0 || syncPulseIndex + endSamples > scanLineBuffer.length) return 0; lowPassFilter.cutoff(evenBuffer.length, 2 * greenSamples, 2); lowPassFilter.reset(); - for (int i = prevPulseIndex + beginSamples; i < prevPulseIndex + endSamples; ++i) - scanLineBuffer[i] = lowPassFilter.avg(scanLineBuffer[i]); + for (int i = beginSamples; i < endSamples; ++i) + scratchBuffer[i] = lowPassFilter.avg(scanLineBuffer[syncPulseIndex + i]); lowPassFilter.reset(); - for (int i = prevPulseIndex + endSamples - 1; i >= prevPulseIndex + beginSamples; --i) - scanLineBuffer[i] = freqToLevel(lowPassFilter.avg(scanLineBuffer[i]), frequencyOffset); + for (int i = endSamples - 1; i >= beginSamples; --i) + scratchBuffer[i] = freqToLevel(lowPassFilter.avg(scratchBuffer[i]), frequencyOffset); for (int i = 0; i < evenBuffer.length; ++i) { - int redPos = redBeginSamples + (i * redSamples) / evenBuffer.length + prevPulseIndex; - int greenPos = greenBeginSamples + (i * greenSamples) / evenBuffer.length + prevPulseIndex; - int bluePos = blueBeginSamples + (i * blueSamples) / evenBuffer.length + prevPulseIndex; - evenBuffer[i] = ColorConverter.RGB(scanLineBuffer[redPos], scanLineBuffer[greenPos], scanLineBuffer[bluePos]); + int redPos = redBeginSamples + (i * redSamples) / evenBuffer.length; + int greenPos = greenBeginSamples + (i * greenSamples) / evenBuffer.length; + int bluePos = blueBeginSamples + (i * blueSamples) / evenBuffer.length; + evenBuffer[i] = ColorConverter.RGB(scratchBuffer[redPos], scratchBuffer[greenPos], scratchBuffer[bluePos]); } return 1; } diff --git a/app/src/main/java/xdsopl/robot36/RawDecoder.java b/app/src/main/java/xdsopl/robot36/RawDecoder.java index 94d940c..92840e3 100644 --- a/app/src/main/java/xdsopl/robot36/RawDecoder.java +++ b/app/src/main/java/xdsopl/robot36/RawDecoder.java @@ -28,19 +28,19 @@ public class RawDecoder implements Mode { } @Override - public int decodeScanLine(int[] evenBuffer, int[] oddBuffer, float[] scanLineBuffer, int prevPulseIndex, int scanLineSamples, float frequencyOffset) { - if (prevPulseIndex < 0 || prevPulseIndex + scanLineSamples > scanLineBuffer.length) + public int decodeScanLine(int[] evenBuffer, int[] oddBuffer, float[] scratchBuffer, float[] scanLineBuffer, int syncPulseIndex, int scanLineSamples, float frequencyOffset) { + if (syncPulseIndex < 0 || syncPulseIndex + scanLineSamples > scanLineBuffer.length) return 0; lowPassFilter.cutoff(evenBuffer.length, 2 * scanLineSamples, 2); lowPassFilter.reset(); - for (int i = prevPulseIndex; i < prevPulseIndex + scanLineSamples; ++i) - scanLineBuffer[i] = lowPassFilter.avg(scanLineBuffer[i]); + for (int i = 0; i < scanLineSamples; ++i) + scratchBuffer[i] = lowPassFilter.avg(scanLineBuffer[syncPulseIndex + i]); lowPassFilter.reset(); - for (int i = prevPulseIndex + scanLineSamples - 1; i >= prevPulseIndex; --i) - scanLineBuffer[i] = freqToLevel(lowPassFilter.avg(scanLineBuffer[i]), frequencyOffset); + for (int i = scanLineSamples - 1; i >= 0; --i) + scratchBuffer[i] = freqToLevel(lowPassFilter.avg(scratchBuffer[i]), frequencyOffset); for (int i = 0; i < evenBuffer.length; ++i) { - int position = (i * scanLineSamples) / evenBuffer.length + prevPulseIndex; - evenBuffer[i] = ColorConverter.GRAY(scanLineBuffer[position]); + int position = (i * scanLineSamples) / evenBuffer.length; + evenBuffer[i] = ColorConverter.GRAY(scratchBuffer[position]); } return 1; } 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 3fa021e..28b8f2d 100644 --- a/app/src/main/java/xdsopl/robot36/Robot_36_Color.java +++ b/app/src/main/java/xdsopl/robot36/Robot_36_Color.java @@ -60,12 +60,12 @@ public class Robot_36_Color implements Mode { } @Override - public int decodeScanLine(int[] evenBuffer, int[] oddBuffer, float[] scanLineBuffer, int prevPulseIndex, int scanLineSamples, float frequencyOffset) { - if (prevPulseIndex + beginSamples < 0 || prevPulseIndex + endSamples > scanLineBuffer.length) + public int decodeScanLine(int[] evenBuffer, int[] oddBuffer, float[] scratchBuffer, float[] scanLineBuffer, int syncPulseIndex, int scanLineSamples, float frequencyOffset) { + if (syncPulseIndex + beginSamples < 0 || syncPulseIndex + endSamples > scanLineBuffer.length) return 0; float separator = 0; for (int i = 0; i < separatorSamples; ++i) - separator += scanLineBuffer[prevPulseIndex + separatorBeginSamples + i]; + separator += scanLineBuffer[syncPulseIndex + separatorBeginSamples + i]; separator /= separatorSamples; separator -= frequencyOffset; boolean even = separator < 0; @@ -74,19 +74,19 @@ public class Robot_36_Color implements Mode { lastEven = even; lowPassFilter.cutoff(evenBuffer.length, 2 * luminanceSamples, 2); lowPassFilter.reset(); - for (int i = prevPulseIndex + beginSamples; i < prevPulseIndex + endSamples; ++i) - scanLineBuffer[i] = lowPassFilter.avg(scanLineBuffer[i]); + for (int i = beginSamples; i < endSamples; ++i) + scratchBuffer[i] = lowPassFilter.avg(scanLineBuffer[syncPulseIndex + i]); lowPassFilter.reset(); - for (int i = prevPulseIndex + endSamples - 1; i >= prevPulseIndex + beginSamples; --i) - scanLineBuffer[i] = freqToLevel(lowPassFilter.avg(scanLineBuffer[i]), frequencyOffset); + for (int i = endSamples - 1; i >= beginSamples; --i) + scratchBuffer[i] = freqToLevel(lowPassFilter.avg(scratchBuffer[i]), frequencyOffset); for (int i = 0; i < evenBuffer.length; ++i) { - int luminancePos = luminanceBeginSamples + (i * luminanceSamples) / evenBuffer.length + prevPulseIndex; - int chrominancePos = chrominanceBeginSamples + (i * chrominanceSamples) / evenBuffer.length + prevPulseIndex; + int luminancePos = luminanceBeginSamples + (i * luminanceSamples) / evenBuffer.length; + int chrominancePos = chrominanceBeginSamples + (i * chrominanceSamples) / evenBuffer.length; if (even) { - evenBuffer[i] = ColorConverter.RGB(scanLineBuffer[luminancePos], 0, scanLineBuffer[chrominancePos]); + evenBuffer[i] = ColorConverter.RGB(scratchBuffer[luminancePos], 0, scratchBuffer[chrominancePos]); } else { int evenYUV = evenBuffer[i]; - int oddYUV = ColorConverter.RGB(scanLineBuffer[luminancePos], scanLineBuffer[chrominancePos], 0); + int oddYUV = ColorConverter.RGB(scratchBuffer[luminancePos], scratchBuffer[chrominancePos], 0); evenBuffer[i] = ColorConverter.YUV2RGB((evenYUV & 0x00ff00ff) | (oddYUV & 0x0000ff00)); oddBuffer[i] = ColorConverter.YUV2RGB((oddYUV & 0x00ffff00) | (evenYUV & 0x000000ff)); } 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 29cc5d6..9074100 100644 --- a/app/src/main/java/xdsopl/robot36/Robot_72_Color.java +++ b/app/src/main/java/xdsopl/robot36/Robot_72_Color.java @@ -58,21 +58,21 @@ public class Robot_72_Color implements Mode { } @Override - public int decodeScanLine(int[] evenBuffer, int[] oddBuffer, float[] scanLineBuffer, int prevPulseIndex, int scanLineSamples, float frequencyOffset) { - if (prevPulseIndex + beginSamples < 0 || prevPulseIndex + endSamples > scanLineBuffer.length) + public int decodeScanLine(int[] evenBuffer, int[] oddBuffer, float[] scratchBuffer, float[] scanLineBuffer, int syncPulseIndex, int scanLineSamples, float frequencyOffset) { + if (syncPulseIndex + beginSamples < 0 || syncPulseIndex + endSamples > scanLineBuffer.length) return 0; lowPassFilter.cutoff(evenBuffer.length, 2 * luminanceSamples, 2); lowPassFilter.reset(); - for (int i = prevPulseIndex + beginSamples; i < prevPulseIndex + endSamples; ++i) - scanLineBuffer[i] = lowPassFilter.avg(scanLineBuffer[i]); + for (int i = beginSamples; i < endSamples; ++i) + scratchBuffer[i] = lowPassFilter.avg(scanLineBuffer[syncPulseIndex + i]); lowPassFilter.reset(); - for (int i = prevPulseIndex + endSamples - 1; i >= prevPulseIndex + beginSamples; --i) - scanLineBuffer[i] = freqToLevel(lowPassFilter.avg(scanLineBuffer[i]), frequencyOffset); + for (int i = endSamples - 1; i >= beginSamples; --i) + scratchBuffer[i] = freqToLevel(lowPassFilter.avg(scratchBuffer[i]), frequencyOffset); for (int i = 0; i < evenBuffer.length; ++i) { - int yPos = yBeginSamples + (i * luminanceSamples) / evenBuffer.length + prevPulseIndex; - int uPos = uBeginSamples + (i * chrominanceSamples) / evenBuffer.length + prevPulseIndex; - int vPos = vBeginSamples + (i * chrominanceSamples) / evenBuffer.length + prevPulseIndex; - evenBuffer[i] = ColorConverter.YUV2RGB(scanLineBuffer[yPos], scanLineBuffer[uPos], scanLineBuffer[vPos]); + int yPos = yBeginSamples + (i * luminanceSamples) / evenBuffer.length; + int uPos = uBeginSamples + (i * chrominanceSamples) / evenBuffer.length; + int vPos = vBeginSamples + (i * chrominanceSamples) / evenBuffer.length; + evenBuffer[i] = ColorConverter.YUV2RGB(scratchBuffer[yPos], scratchBuffer[uPos], scratchBuffer[vPos]); } return 1; }