Skip to content

Commit 300de47

Browse files
authored
Merge pull request #2361 from hasinur010/tap2tone
TapToTone: Add signal visualization for better debugging and analysis.
2 parents 9abad7d + 25a1034 commit 300de47

5 files changed

Lines changed: 108 additions & 9 deletions

File tree

apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TapLatencyAnalyser.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@
2323
public class TapLatencyAnalyser {
2424
public static final int TYPE_TAP = 0;
2525
float[] mHighPassBuffer;
26+
float[] mFastBuffer;
27+
float[] mSlowBuffer;
28+
float[] mLowThresholdBuffer;
29+
float [] mArmedIndexes;
2630

2731
private float mDroop = 0.995f;
2832
private static final float EDGE_THRESHOLD = 0.01f;
@@ -56,6 +60,10 @@ public TapLatencyEvent[] analyze(float[] buffer, int offset, int numSamples) {
5660

5761
// Apply envelope follower.
5862
float[] peakBuffer = new float[numSamples];
63+
mFastBuffer = new float[numSamples];
64+
mSlowBuffer = new float[numSamples];
65+
mLowThresholdBuffer = new float[numSamples];
66+
mArmedIndexes = new float[numSamples];
5967
fillPeakBuffer(mHighPassBuffer, 0, numSamples, peakBuffer);
6068
// Look for two attacks.
6169
return scanForEdges(peakBuffer, numSamples);
@@ -69,6 +77,22 @@ public float[] getFilteredBuffer() {
6977
return mHighPassBuffer;
7078
}
7179

80+
81+
public float[] getFastBuffer() {
82+
return mFastBuffer;
83+
}
84+
85+
public float[] getSlowBuffer() {
86+
return mSlowBuffer;
87+
}
88+
89+
public float[] getLowThresholdBuffer() {
90+
return mLowThresholdBuffer;
91+
}
92+
93+
public float[] getArmedIndexes() {
94+
return mArmedIndexes;
95+
}
7296
// Based on https://en.wikipedia.org/wiki/High-pass_filter
7397
private void highPassFilter(
7498
float[] buffer, int offset, int numSamples, float[] highPassBuffer) {
@@ -124,6 +148,8 @@ private TapLatencyEvent[] scanForEdges(float[] peakBuffer, int numSamples) {
124148
for (float level : peakBuffer) {
125149
slow = slow + (level - slow) * slowCoefficient; // low pass filter
126150
fast = fast + (level - fast) * fastCoefficient; // low pass filter
151+
mSlowBuffer[sampleIndex] = slow;
152+
mFastBuffer[sampleIndex] = fast;
127153
if (armed && (fast > EDGE_THRESHOLD) && (fast > (2.0 * slow))) {
128154
events.add(new TapLatencyEvent(TYPE_TAP, sampleIndex));
129155
armed = false;
@@ -132,10 +158,16 @@ private TapLatencyEvent[] scanForEdges(float[] peakBuffer, int numSamples) {
132158
// on the smaller variations that occur after the initial peak.
133159
lowThreshold = fast * LOW_FRACTION;
134160
}
161+
mLowThresholdBuffer[sampleIndex] = lowThreshold;
135162
// Use hysteresis when rearming.
136163
if (fast < lowThreshold) {
137164
armed = true;
138165
}
166+
if (armed) {
167+
mArmedIndexes[sampleIndex] = 1.0f;
168+
} else {
169+
mArmedIndexes[sampleIndex] = 0.0f;
170+
}
139171
sampleIndex++;
140172
}
141173
return events.toArray(new TapLatencyEvent[0]);

apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TapToToneActivity.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import static com.mobileer.oboetester.MidiTapTester.NoteListener;
2020

2121
import android.content.pm.PackageManager;
22+
import android.graphics.Color;
2223
import android.media.AudioDeviceInfo;
2324
import android.media.AudioManager;
2425
import android.media.midi.MidiDevice;
@@ -89,7 +90,18 @@ protected void onCreate(Bundle savedInstanceState) {
8990

9091

9192
// Start a blip test when the waveform view is tapped.
92-
WaveformView mWaveformView = (WaveformView) findViewById(R.id.waveview_audio);
93+
WaveformView mWaveformView = (WaveformView) findViewById(R.id.waveview_audio_original);
94+
WaveformView mFastWaveformView = (WaveformView) findViewById(R.id.waveview_audio_fast_avg);
95+
WaveformView mSlowWaveformView = (WaveformView) findViewById(R.id.waveview_audio_slow_avg);
96+
WaveformView mLowThresholdWaveformView = (WaveformView) findViewById(R.id.waveview_audio_lowThreshold);
97+
WaveformView mArmedWaveformView = (WaveformView) findViewById(R.id.waveview_audio_armed_waveform);
98+
99+
update(R.id.waveview_audio_original, Color.BLUE, Color.argb(128,0, 120, 0), Color.TRANSPARENT);
100+
update(R.id.waveview_audio_fast_avg, Color.argb(255,0, 247, 255), Color.TRANSPARENT, Color.argb(70, 255, 238, 0));
101+
update(R.id.waveview_audio_slow_avg, Color.argb(255, 174, 0, 255), Color.TRANSPARENT, Color.argb(70, 255, 238, 0));
102+
update(R.id.waveview_audio_lowThreshold, Color.argb(255, 255, 132, 0), Color.TRANSPARENT, Color.argb(70, 255, 238, 0));
103+
update(R.id.waveview_audio_armed_waveform, Color.argb(50, 255, 238, 0), Color.TRANSPARENT, Color.RED);
104+
93105
mWaveformView.setOnTouchListener((view, event) -> {
94106
// Do not call view.performClick() because it may trigger a touch sound!
95107
int action = event.getActionMasked();
@@ -124,6 +136,11 @@ protected void onCreate(Bundle savedInstanceState) {
124136
useNoisePulse(mUseNoisePulseCheckBox.isChecked());
125137
}
126138

139+
private void update(int waveformViewId, int waveColor, int backgroundColor, int cursorColor) {
140+
WaveformView waveformView = (WaveformView) findViewById(waveformViewId);
141+
waveformView.updateTheme(waveColor, backgroundColor, cursorColor);
142+
}
143+
127144
private void updateButtons(boolean running) {
128145
mStartButton.setEnabled(!running);
129146
mStopButton.setEnabled(running);

apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TapToToneTester.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ public class TapToToneTester {
3030

3131
private final Activity mActivity;
3232
private final WaveformView mWaveformView;
33+
WaveformView mFastWaveformView;
34+
WaveformView mSlowWaveformView;
35+
WaveformView mLowThresholdWaveformView;
36+
WaveformView mArmedWaveformView;
3337
private final TextView mResultView;
3438
private final Spinner mAudioSourceSpinner;
3539

@@ -55,8 +59,12 @@ public TapToToneTester(Activity activity, String tapInstructions) {
5559
mActivity = activity;
5660
mTapInstructions = tapInstructions;
5761
mResultView = (TextView) activity.findViewById(R.id.resultView);
58-
mWaveformView = (WaveformView) activity.findViewById(R.id.waveview_audio);
62+
mWaveformView = (WaveformView) activity.findViewById(R.id.waveview_audio_original);
5963
mWaveformView.setEnabled(false);
64+
mFastWaveformView = (WaveformView) activity.findViewById(R.id.waveview_audio_fast_avg);
65+
mSlowWaveformView = (WaveformView) activity.findViewById(R.id.waveview_audio_slow_avg);
66+
mLowThresholdWaveformView = (WaveformView) activity.findViewById(R.id.waveview_audio_lowThreshold);
67+
mArmedWaveformView = (WaveformView) activity.findViewById(R.id.waveview_audio_armed_waveform);
6068

6169
float analysisTimeMax = ANALYSIS_TIME_TOTAL + mAnalysisTimeMargin;
6270
mRecorder = new AudioRecordThread(ANALYSIS_SAMPLE_RATE,
@@ -180,7 +188,7 @@ public void showTestResults(TestResult result) {
180188
for (int i = 0; i < numEdges; i++) {
181189
cursors[i] = result.events[i].sampleIndex;
182190
}
183-
mWaveformView.setCursorData(cursors);
191+
mArmedWaveformView.setCursorData(cursors);
184192
}
185193
// Did we get a good measurement?
186194
if (result.events.length < 2) {
@@ -203,6 +211,10 @@ public void showTestResults(TestResult result) {
203211
text = String.format(Locale.getDefault(), "tap-to-tone latency = %3d msec\n", latencyMillis);
204212
}
205213
mWaveformView.setSampleData(result.filtered);
214+
mFastWaveformView.setSampleData(mTapLatencyAnalyser.getFastBuffer());
215+
mSlowWaveformView.setSampleData(mTapLatencyAnalyser.getSlowBuffer());
216+
mLowThresholdWaveformView.setSampleData(mTapLatencyAnalyser.getLowThresholdBuffer());
217+
mArmedWaveformView.setSampleData(mTapLatencyAnalyser.getArmedIndexes());
206218
}
207219

208220
if (mMeasurementCount > 0) {
@@ -217,6 +229,10 @@ public void showTestResults(TestResult result) {
217229
public void run() {
218230
mResultView.setText(postText);
219231
mWaveformView.postInvalidate();
232+
mFastWaveformView.postInvalidate();
233+
mSlowWaveformView.postInvalidate();
234+
mLowThresholdWaveformView.postInvalidate();
235+
mArmedWaveformView.postInvalidate();
220236
}
221237
});
222238

apps/OboeTester/app/src/main/java/com/mobileer/oboetester/WaveformView.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,12 @@ private void init() {
7373
mMessagePaint.setTextSize(MESSAGE_TEXT_SIZE);
7474
}
7575

76+
public void updateTheme(int waveColor, int backgroundColor, int cursorColor) {
77+
mWavePaint.setColor(waveColor);
78+
mBackgroundPaint.setColor(backgroundColor);
79+
mCursorPaint.setColor(cursorColor);
80+
}
81+
7682
@Override
7783
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
7884
mCurrentWidth = w;

apps/OboeTester/app/src/main/res/layout/activity_tap_to_tone.xml

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -128,12 +128,40 @@
128128
android:textStyle="bold"
129129
android:text="@string/tap_help" />
130130

131-
<com.mobileer.oboetester.WaveformView
132-
android:id="@+id/waveview_audio"
133-
android:layout_width="fill_parent"
134-
android:layout_height="fill_parent"
135-
android:minHeight="100dp"
136-
/>
131+
<FrameLayout
132+
android:layout_width="match_parent"
133+
android:layout_height="fill_parent">
134+
<com.mobileer.oboetester.WaveformView
135+
android:id="@+id/waveview_audio_original"
136+
android:layout_width="fill_parent"
137+
android:layout_height="fill_parent"
138+
android:minHeight="100dp"
139+
/>
140+
<com.mobileer.oboetester.WaveformView
141+
android:id="@+id/waveview_audio_fast_avg"
142+
android:layout_width="fill_parent"
143+
android:layout_height="fill_parent"
144+
android:minHeight="100dp"
145+
/>
146+
<com.mobileer.oboetester.WaveformView
147+
android:id="@+id/waveview_audio_slow_avg"
148+
android:layout_width="fill_parent"
149+
android:layout_height="fill_parent"
150+
android:minHeight="100dp"
151+
/>
152+
<com.mobileer.oboetester.WaveformView
153+
android:id="@+id/waveview_audio_lowThreshold"
154+
android:layout_width="fill_parent"
155+
android:layout_height="fill_parent"
156+
android:minHeight="100dp"
157+
/>
158+
<com.mobileer.oboetester.WaveformView
159+
android:id="@+id/waveview_audio_armed_waveform"
160+
android:layout_width="fill_parent"
161+
android:layout_height="fill_parent"
162+
android:minHeight="100dp"
163+
/>
164+
</FrameLayout>
137165
</LinearLayout>
138166
</ScrollView>
139167
</LinearLayout>

0 commit comments

Comments
 (0)