mirror of
https://github.com/xdsopl/robot36.git
synced 2025-12-06 07:12:07 +01:00
Merge 157cd71c33 into 1502f20af1
This commit is contained in:
commit
41bb8cf81b
|
|
@ -6,6 +6,8 @@ Copyright 2024 Ahmet Inan <xdsopl@gmail.com>
|
||||||
|
|
||||||
package xdsopl.robot36;
|
package xdsopl.robot36;
|
||||||
|
|
||||||
|
import android.graphics.Color;
|
||||||
|
|
||||||
public final class ColorConverter {
|
public final class ColorConverter {
|
||||||
|
|
||||||
private static int clamp(int value) {
|
private static int clamp(int value) {
|
||||||
|
|
@ -36,6 +38,24 @@ public final class ColorConverter {
|
||||||
return 0xff000000 | (R << 16) | (G << 8) | B;
|
return 0xff000000 | (R << 16) | (G << 8) | B;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int[] argb2components(int argb) {
|
||||||
|
return new int[] { (argb >> 24) & 0xff, (argb >> 16) & 0xff, (argb >> 8) & 0xff, argb & 0xff };
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int blend(int argbLeft, int argbRight, float ratioOfArgbRight) {
|
||||||
|
int[] componentsLeft = argb2components(argbLeft);
|
||||||
|
int[] componentsRight = argb2components(argbRight);
|
||||||
|
int[] output = new int[4];
|
||||||
|
|
||||||
|
ratioOfArgbRight = clamp(ratioOfArgbRight);
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
output[i] = clamp(Math.round(componentsLeft[i] * (1 - ratioOfArgbRight) + componentsRight[i] * ratioOfArgbRight));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Color.argb(output[0], output[1], output[2], output[3]);
|
||||||
|
}
|
||||||
|
|
||||||
public static int GRAY(float level) {
|
public static int GRAY(float level) {
|
||||||
return 0xff000000 | 0x00010101 * compress(level);
|
return 0xff000000 | 0x00010101 * compress(level);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,9 +33,11 @@ public class Demodulator {
|
||||||
public int syncPulseOffset;
|
public int syncPulseOffset;
|
||||||
public float frequencyOffset;
|
public float frequencyOffset;
|
||||||
|
|
||||||
|
public static final double syncPulseFrequency = 1200;
|
||||||
|
public static final double blackFrequency = 1500;
|
||||||
|
public static final double whiteFrequency = 2300;
|
||||||
|
|
||||||
Demodulator(int sampleRate) {
|
Demodulator(int sampleRate) {
|
||||||
double blackFrequency = 1500;
|
|
||||||
double whiteFrequency = 2300;
|
|
||||||
double scanLineBandwidth = whiteFrequency - blackFrequency;
|
double scanLineBandwidth = whiteFrequency - blackFrequency;
|
||||||
frequencyModulation = new FrequencyModulation(scanLineBandwidth, sampleRate);
|
frequencyModulation = new FrequencyModulation(scanLineBandwidth, sampleRate);
|
||||||
double syncPulse5msSeconds = 0.005;
|
double syncPulse5msSeconds = 0.005;
|
||||||
|
|
@ -65,7 +67,6 @@ public class Demodulator {
|
||||||
baseBandLowPass.taps[i] = (float) (kaiser.window(2.0, i, baseBandLowPass.length) * Filter.lowPass(cutoffFrequency, sampleRate, i, baseBandLowPass.length));
|
baseBandLowPass.taps[i] = (float) (kaiser.window(2.0, i, baseBandLowPass.length) * Filter.lowPass(cutoffFrequency, sampleRate, i, baseBandLowPass.length));
|
||||||
double centerFrequency = (lowestFrequency + highestFrequency) / 2;
|
double centerFrequency = (lowestFrequency + highestFrequency) / 2;
|
||||||
baseBandOscillator = new Phasor(-centerFrequency, sampleRate);
|
baseBandOscillator = new Phasor(-centerFrequency, sampleRate);
|
||||||
double syncPulseFrequency = 1200;
|
|
||||||
syncPulseFrequencyValue = (float) ((syncPulseFrequency - centerFrequency) * 2 / scanLineBandwidth);
|
syncPulseFrequencyValue = (float) ((syncPulseFrequency - centerFrequency) * 2 / scanLineBandwidth);
|
||||||
syncPulseFrequencyTolerance = (float) (50 * 2 / scanLineBandwidth);
|
syncPulseFrequencyTolerance = (float) (50 * 2 / scanLineBandwidth);
|
||||||
double syncPorchFrequency = 1500;
|
double syncPorchFrequency = 1500;
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import android.content.SharedPreferences;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.Color;
|
||||||
import android.media.AudioFormat;
|
import android.media.AudioFormat;
|
||||||
import android.media.AudioRecord;
|
import android.media.AudioRecord;
|
||||||
import android.media.MediaRecorder;
|
import android.media.MediaRecorder;
|
||||||
|
|
@ -72,6 +73,7 @@ public class MainActivity extends AppCompatActivity {
|
||||||
private ImageView peakMeterView;
|
private ImageView peakMeterView;
|
||||||
private PixelBuffer imageBuffer;
|
private PixelBuffer imageBuffer;
|
||||||
private ShortTimeFourierTransform stft;
|
private ShortTimeFourierTransform stft;
|
||||||
|
private final int binWidthHz = 10;
|
||||||
private short[] shortBuffer;
|
private short[] shortBuffer;
|
||||||
private float[] recordBuffer;
|
private float[] recordBuffer;
|
||||||
private AudioRecord audioRecord;
|
private AudioRecord audioRecord;
|
||||||
|
|
@ -223,8 +225,22 @@ public class MainActivity extends AppCompatActivity {
|
||||||
double lowest = Math.log(1e-9);
|
double lowest = Math.log(1e-9);
|
||||||
double highest = Math.log(1);
|
double highest = Math.log(1);
|
||||||
double range = highest - lowest;
|
double range = highest - lowest;
|
||||||
|
int lowestBin = 14;
|
||||||
for (int i = 0; i < stride; ++i)
|
for (int i = 0; i < stride; ++i)
|
||||||
waterfallPlotBuffer.pixels[line + i] = rainbow((Math.log(stft.power[i + 14]) - lowest) / range);
|
waterfallPlotBuffer.pixels[line + i] = rainbow((Math.log(stft.power[i + lowestBin]) - lowest) / range);
|
||||||
|
|
||||||
|
int[] markerFrequencies = new int[] {
|
||||||
|
(int)Demodulator.syncPulseFrequency,
|
||||||
|
(int)Demodulator.blackFrequency,
|
||||||
|
(int)Demodulator.whiteFrequency,
|
||||||
|
};
|
||||||
|
for (int freq: markerFrequencies) {
|
||||||
|
int marker = freq / binWidthHz - lowestBin;
|
||||||
|
waterfallPlotBuffer.pixels[line + marker - 1] = Color.BLACK;
|
||||||
|
waterfallPlotBuffer.pixels[line + marker] = ColorConverter.blend(waterfallPlotBuffer.pixels[line + marker], Color.GREEN, 0.8f);
|
||||||
|
waterfallPlotBuffer.pixels[line + marker + 1] = Color.BLACK;
|
||||||
|
}
|
||||||
|
|
||||||
System.arraycopy(waterfallPlotBuffer.pixels, line, waterfallPlotBuffer.pixels, line + stride * (waterfallPlotBuffer.height / 2), stride);
|
System.arraycopy(waterfallPlotBuffer.pixels, line, waterfallPlotBuffer.pixels, line + stride * (waterfallPlotBuffer.height / 2), stride);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -315,7 +331,7 @@ public class MainActivity extends AppCompatActivity {
|
||||||
if (rateChanged) {
|
if (rateChanged) {
|
||||||
decoder = new Decoder(scopeBuffer, imageBuffer, getString(R.string.raw_mode), recordRate);
|
decoder = new Decoder(scopeBuffer, imageBuffer, getString(R.string.raw_mode), recordRate);
|
||||||
decoder.setMode(currentMode);
|
decoder.setMode(currentMode);
|
||||||
stft = new ShortTimeFourierTransform(recordRate / 10, 3);
|
stft = new ShortTimeFourierTransform(recordRate / binWidthHz, 3);
|
||||||
}
|
}
|
||||||
startListening();
|
startListening();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue