mirror of
https://github.com/xdsopl/robot36.git
synced 2026-01-30 19:34:13 +01:00
synchronize using sync pulses
This commit is contained in:
parent
d207823011
commit
89772839f4
|
|
@ -26,6 +26,8 @@ public class Demodulator {
|
|||
private Complex syncPulse;
|
||||
private Complex scanLine;
|
||||
|
||||
public int syncPulseOffset;
|
||||
|
||||
Demodulator(int sampleRate) {
|
||||
double powerWindowSeconds = 0.5;
|
||||
int powerWindowSamples = (int) Math.round(powerWindowSeconds * sampleRate) | 1;
|
||||
|
|
@ -61,7 +63,8 @@ public class Demodulator {
|
|||
scanLine = new Complex();
|
||||
}
|
||||
|
||||
public void process(float[] buffer) {
|
||||
public boolean process(float[] buffer) {
|
||||
boolean syncPulseDetected = false;
|
||||
for (int i = 0; i < buffer.length; ++i) {
|
||||
baseBand = baseBandLowPass.avg(baseBand.set(buffer[i]).mul(baseBandOscillator.rotate()));
|
||||
syncPulse = syncPulseFilter.avg(syncPulse.set(baseBand).mul(syncPulseOscillator.rotate()));
|
||||
|
|
@ -76,19 +79,17 @@ public class Demodulator {
|
|||
syncPulseMaxPosition = syncPulseCounter;
|
||||
}
|
||||
++syncPulseCounter;
|
||||
buffer[i] = syncPulseLevel;
|
||||
} else if (syncPulseCounter > 0 && syncPulseCounter < syncPulseSamples) {
|
||||
int offset = syncPulseCounter - syncPulseMaxPosition;
|
||||
if (offset <= i)
|
||||
buffer[i - offset] = -1;
|
||||
syncPulseOffset = i + syncPulseMaxPosition - syncPulseCounter;
|
||||
syncPulseDetected = true;
|
||||
syncPulseCounter = 0;
|
||||
syncPulseMaxLevel = 0;
|
||||
buffer[i] = scanLineLevel;
|
||||
} else {
|
||||
syncPulseCounter = 0;
|
||||
syncPulseMaxLevel = 0;
|
||||
buffer[i] = scanLineLevel;
|
||||
}
|
||||
buffer[i] = scanLineLevel;
|
||||
}
|
||||
return syncPulseDetected;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ public class MainActivity extends AppCompatActivity {
|
|||
private int tint;
|
||||
private int curLine;
|
||||
private int curColumn;
|
||||
private int syncPulseToleranceSamples;
|
||||
|
||||
private void setStatus(int id) {
|
||||
status.setText(id);
|
||||
|
|
@ -55,30 +56,49 @@ public class MainActivity extends AppCompatActivity {
|
|||
@Override
|
||||
public void onPeriodicNotification(AudioRecord audioRecord) {
|
||||
audioRecord.read(recordBuffer, 0, recordBuffer.length, AudioRecord.READ_BLOCKING);
|
||||
demodulator.process(recordBuffer);
|
||||
visualizeSignal();
|
||||
visualizeSignal(demodulator.process(recordBuffer));
|
||||
}
|
||||
};
|
||||
|
||||
private void visualizeSignal() {
|
||||
private void slideUpOneLine() {
|
||||
for (int i = 0; i < scopeWidth; ++i)
|
||||
scopePixels[scopeWidth * (curLine + scopeHeight) + i] = scopePixels[scopeWidth * curLine + i];
|
||||
curLine = (curLine + 1) % scopeHeight;
|
||||
scopeBitmap.setPixels(scopePixels, scopeWidth * curLine, scopeWidth, 0, 0, scopeWidth, scopeHeight);
|
||||
scopeView.invalidate();
|
||||
}
|
||||
|
||||
private void visualizeSignal(boolean syncPulseDetected) {
|
||||
int syncPulseOffset = curColumn + demodulator.syncPulseOffset;
|
||||
if (syncPulseDetected && syncPulseOffset >= syncPulseToleranceSamples && syncPulseOffset < curColumn) {
|
||||
syncPulseDetected = false;
|
||||
int nextLine = (curLine + 1) % scopeHeight;
|
||||
for (int i = 0; i < curColumn - syncPulseOffset; ++i)
|
||||
scopePixels[scopeWidth * nextLine + i] = scopePixels[scopeWidth * curLine + syncPulseOffset + i];
|
||||
for (int i = syncPulseOffset; i < scopeWidth; ++i)
|
||||
scopePixels[scopeWidth * curLine + i] = 0xff00ff00;
|
||||
curColumn -= syncPulseOffset;
|
||||
slideUpOneLine();
|
||||
}
|
||||
for (float v : recordBuffer) {
|
||||
int pixelColor = 0xff00ff00;
|
||||
if (v >= 0) {
|
||||
int intensity = (int) Math.round(255 * Math.sqrt(v));
|
||||
pixelColor = 0xff000000 | 0x00010101 * intensity;
|
||||
}
|
||||
int intensity = (int) Math.round(255 * Math.sqrt(v));
|
||||
int pixelColor = 0xff000000 | 0x00010101 * intensity;
|
||||
scopePixels[scopeWidth * curLine + curColumn] = pixelColor;
|
||||
if (++curColumn >= scopeWidth) {
|
||||
boolean syncNow = syncPulseDetected && syncPulseOffset == curColumn;
|
||||
if (syncNow || ++curColumn >= scopeWidth) {
|
||||
syncPulseDetected = false;
|
||||
curColumn = 0;
|
||||
for (int i = 0; i < scopeWidth; ++i)
|
||||
scopePixels[scopeWidth * (curLine + scopeHeight) + i] = scopePixels[scopeWidth * curLine + i];
|
||||
curLine = (curLine + 1) % scopeHeight;
|
||||
scopeBitmap.setPixels(scopePixels, scopeWidth * curLine, scopeWidth, 0, 0, scopeWidth, scopeHeight);
|
||||
scopeView.invalidate();
|
||||
slideUpOneLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void initTools(int sampleRate) {
|
||||
demodulator = new Demodulator(sampleRate);
|
||||
double syncPulseToleranceSeconds = 0.001;
|
||||
syncPulseToleranceSamples = (int) Math.round(syncPulseToleranceSeconds * sampleRate);
|
||||
}
|
||||
|
||||
private void initAudioRecord() {
|
||||
int audioSource = MediaRecorder.AudioSource.UNPROCESSED;
|
||||
int channelConfig = AudioFormat.CHANNEL_IN_MONO;
|
||||
|
|
@ -95,7 +115,7 @@ public class MainActivity extends AppCompatActivity {
|
|||
if (audioRecord.getState() == AudioRecord.STATE_INITIALIZED) {
|
||||
audioRecord.setRecordPositionUpdateListener(recordListener);
|
||||
audioRecord.setPositionNotificationPeriod(recordBuffer.length);
|
||||
demodulator = new Demodulator(sampleRate);
|
||||
initTools(sampleRate);
|
||||
startListening();
|
||||
} else {
|
||||
setStatus(R.string.audio_init_failed);
|
||||
|
|
|
|||
Loading…
Reference in a new issue