Merge "Cleanup/enhance AEC test. Standardize ReportLog keys."
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java
index 06340e3..fe898b0 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java
@@ -17,8 +17,11 @@
package com.android.cts.verifier.audio;
import android.content.Context;
-import android.media.*;
import android.media.audiofx.AcousticEchoCanceler;
+import android.media.AudioManager;
+import android.media.AudioTrack;
+import android.media.AudioRecord;
+import android.media.MediaRecorder;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
@@ -26,130 +29,74 @@
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
+
import com.android.compatibility.common.util.ResultType;
import com.android.compatibility.common.util.ResultUnit;
-import com.android.cts.verifier.CtsVerifierReportLog;
-import com.android.cts.verifier.R;
+import com.android.cts.verifier.audio.soundio.SoundPlayerObject;
+import com.android.cts.verifier.audio.soundio.SoundRecorderObject;
import com.android.cts.verifier.audio.wavelib.*;
+import com.android.cts.verifier.CtsVerifierReportLog;
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+
+import static com.android.cts.verifier.TestListActivity.sCurrentDisplayMode;
+import static com.android.cts.verifier.TestListAdapter.setTestNameSuffix;
public class AudioAEC extends AudioFrequencyActivity implements View.OnClickListener {
private static final String TAG = "AudioAEC";
- private static final int TEST_NONE = -1;
+ // Test State
private static final int TEST_AEC = 0;
- private static final int TEST_COUNT = 1;
- private static final float MAX_VAL = (float)(1 << 15);
- private int mCurrentTest = TEST_NONE;
+ // UI
private LinearLayout mLinearLayout;
private Button mButtonTest;
private Button mButtonMandatoryYes;
private Button mButtonMandatoryNo;
private ProgressBar mProgress;
private TextView mResultTest;
- private boolean mTestAECPassed;
- private SoundPlayerObject mSPlayer;
- private SoundRecorderObject mSRecorder;
- private AcousticEchoCanceler mAec;
- private boolean mMandatory = true;
-
+ // Sound IO
private final int mBlockSizeSamples = 4096;
private final int mSamplingRate = 48000;
private final int mSelectedRecordSource = MediaRecorder.AudioSource.VOICE_COMMUNICATION;
+ private SoundPlayerObject mSPlayer;
+ private SoundRecorderObject mSRecorder;
+
+ // Test Results
+ private boolean mMandatory = true;
+ private boolean mTestAECPassed;
+
private final int TEST_DURATION_MS = 8000;
private final int SHOT_FREQUENCY_MS = 200;
private final int CORRELATION_DURATION_MS = TEST_DURATION_MS - 3000;
private final int SHOT_COUNT_CORRELATION = CORRELATION_DURATION_MS/SHOT_FREQUENCY_MS;
private final int SHOT_COUNT = TEST_DURATION_MS/SHOT_FREQUENCY_MS;
+
private final float MIN_RMS_DB = -60.0f; //dB
private final float MIN_RMS_VAL = (float)Math.pow(10,(MIN_RMS_DB/20));
private final double TEST_THRESHOLD_AEC_ON = 0.5;
private final double TEST_THRESHOLD_AEC_OFF = 0.6;
- private RmsHelper mRMSRecorder1 = new RmsHelper(mBlockSizeSamples, SHOT_COUNT);
- private RmsHelper mRMSRecorder2 = new RmsHelper(mBlockSizeSamples, SHOT_COUNT);
+ private RmsHelper mRMSRecorder1 =
+ new RmsHelper(mBlockSizeSamples, SHOT_COUNT, MIN_RMS_DB, MIN_RMS_VAL);
+ private RmsHelper mRMSRecorder2 =
+ new RmsHelper(mBlockSizeSamples, SHOT_COUNT, MIN_RMS_DB, MIN_RMS_VAL);
- private RmsHelper mRMSPlayer1 = new RmsHelper(mBlockSizeSamples, SHOT_COUNT);
- private RmsHelper mRMSPlayer2 = new RmsHelper(mBlockSizeSamples, SHOT_COUNT);
+ private RmsHelper mRMSPlayer1 =
+ new RmsHelper(mBlockSizeSamples, SHOT_COUNT, MIN_RMS_DB, MIN_RMS_VAL);
+ private RmsHelper mRMSPlayer2 =
+ new RmsHelper(mBlockSizeSamples, SHOT_COUNT, MIN_RMS_DB, MIN_RMS_VAL);
private Thread mTestThread;
- //RMS helpers
- public class RmsHelper {
- private double mRmsCurrent;
- public int mBlockSize;
- private int mShoutCount;
- public boolean mRunning = false;
-
- private short[] mAudioShortArray;
-
- private DspBufferDouble mRmsSnapshots;
- private int mShotIndex;
-
- public RmsHelper(int blockSize, int shotCount) {
- mBlockSize = blockSize;
- mShoutCount = shotCount;
- reset();
- }
-
- public void reset() {
- mAudioShortArray = new short[mBlockSize];
- mRmsSnapshots = new DspBufferDouble(mShoutCount);
- mShotIndex = 0;
- mRmsCurrent = 0;
- mRunning = false;
- }
-
- public void captureShot() {
- if (mShotIndex >= 0 && mShotIndex < mRmsSnapshots.getSize()) {
- mRmsSnapshots.setValue(mShotIndex++, mRmsCurrent);
- }
- }
-
- public void setRunning(boolean running) {
- mRunning = running;
- }
-
- public double getRmsCurrent() {
- return mRmsCurrent;
- }
-
- public DspBufferDouble getRmsSnapshots() {
- return mRmsSnapshots;
- }
-
- public boolean updateRms(PipeShort pipe, int channelCount, int channel) {
- if (mRunning) {
- int samplesAvailable = pipe.availableToRead();
- while (samplesAvailable >= mBlockSize) {
- pipe.read(mAudioShortArray, 0, mBlockSize);
-
- double rmsTempSum = 0;
- int count = 0;
- for (int i = channel; i < mBlockSize; i += channelCount) {
- float value = mAudioShortArray[i] / MAX_VAL;
-
- rmsTempSum += value * value;
- count++;
- }
- float rms = count > 0 ? (float)Math.sqrt(rmsTempSum / count) : 0f;
- if (rms < MIN_RMS_VAL) {
- rms = MIN_RMS_VAL;
- }
-
- double alpha = 0.9;
- double total_rms = rms * alpha + mRmsCurrent * (1.0f - alpha);
- mRmsCurrent = total_rms;
-
- samplesAvailable = pipe.availableToRead();
- }
- return true;
- }
- return false;
- }
- }
+ // ReportLog schema
+ private static final String SECTION_AEC = "aec_activity";
+ private static final String KEY_AEC_MANDATORY = "aec_mandatory";
+ private static final String KEY_AEC_MAX_WITH = "max_with_aec";
+ private static final String KEY_AEC_MAX_WITHOUT = "max_without_aec";
+ private static final String KEY_AEC_RESULT = "result_string";
//compute Acoustic Coupling Factor
private double computeAcousticCouplingFactor(DspBufferDouble buffRmsPlayer,
@@ -196,7 +143,7 @@
super.onCreate(savedInstanceState);
setContentView(R.layout.audio_aec_activity);
- //
+ // "AEC Mandatory" Buttons
mLinearLayout = (LinearLayout)findViewById(R.id.audio_aec_test_layout);
mButtonMandatoryYes = (Button) findViewById(R.id.audio_aec_mandatory_yes);
mButtonMandatoryYes.setOnClickListener(this);
@@ -204,16 +151,15 @@
mButtonMandatoryNo.setOnClickListener(this);
enableUILayout(mLinearLayout, false);
- // Test
+ // Test Button
mButtonTest = (Button) findViewById(R.id.audio_aec_button_test);
mButtonTest.setOnClickListener(this);
mProgress = (ProgressBar) findViewById(R.id.audio_aec_test_progress_bar);
mResultTest = (TextView) findViewById(R.id.audio_aec_test_result);
- showView(mProgress, false);
+ showProgressIndicator(false);
mSPlayer = new SoundPlayerObject(false, mBlockSizeSamples) {
-
@Override
public void periodicNotification(AudioTrack track) {
int channelCount = getChannelCount();
@@ -233,12 +179,11 @@
setPassFailButtonClickListeners();
getPassButton().setEnabled(false);
- setInfoResources(R.string.audio_aec_test,
- R.string.audio_aec_info, -1);
+ setInfoResources(R.string.audio_aec_test, R.string.audio_aec_info, -1);
}
- private void showView(View v, boolean show) {
- v.setVisibility(show ? View.VISIBLE : View.INVISIBLE);
+ private void showProgressIndicator(boolean show) {
+ mProgress.setVisibility(show ? View.VISIBLE : View.INVISIBLE);
}
@Override
@@ -263,7 +208,6 @@
mMandatory = true;
Log.v(TAG,"AEC marked as mandatory");
break;
-
}
}
@@ -273,7 +217,11 @@
Log.v(TAG,"test Thread already running.");
return;
}
+
mTestThread = new Thread(new AudioTestRunner(TAG, TEST_AEC, mMessageHandler) {
+ // AcousticEchoCanceler
+ private AcousticEchoCanceler mAec;
+
public void run() {
super.run();
@@ -489,28 +437,38 @@
String msg) {
CtsVerifierReportLog reportLog = getReportLog();
- reportLog.addValue("AEC_mandatory",
+ reportLog.addValue(KEY_AEC_MANDATORY,
aecMandatory,
ResultType.NEUTRAL,
ResultUnit.NONE);
- reportLog.addValue("max_with_AEC",
+ reportLog.addValue(KEY_AEC_MAX_WITH,
maxAEC,
ResultType.LOWER_BETTER,
ResultUnit.SCORE);
- reportLog.addValue("max_without_AEC",
+ reportLog.addValue(KEY_AEC_MAX_WITHOUT,
maxNoAEC,
ResultType.HIGHER_BETTER,
ResultUnit.SCORE);
- reportLog.addValue("result_string",
+ reportLog.addValue(KEY_AEC_RESULT,
msg,
ResultType.NEUTRAL,
ResultUnit.NONE);
}
- @Override // PassFailButtons
+ //
+ // PassFailButtons Overrides
+ //
+ public String getReportFileName() { return PassFailButtons.AUDIO_TESTS_REPORT_LOG_NAME; }
+
+ @Override
+ public final String getReportSectionName() {
+ return setTestNameSuffix(sCurrentDisplayMode, SECTION_AEC);
+ }
+
+ @Override
public void recordTestResults() {
getReportLog().submit();
}
@@ -522,7 +480,7 @@
public void testStarted(int testId, String str) {
super.testStarted(testId, str);
Log.v(TAG, "Test Started! " + testId + " str:"+str);
- showView(mProgress, true);
+ showProgressIndicator(true);
mTestAECPassed = false;
getPassButton().setEnabled(false);
mResultTest.setText("test in progress..");
@@ -539,7 +497,7 @@
public void testEndedOk(int testId, String str) {
super.testEndedOk(testId, str);
Log.v(TAG, "Test EndedOk. " + testId + " str:"+str);
- showView(mProgress, false);
+ showProgressIndicator(false);
mResultTest.setText("test completed. " + str);
if (mTestAECPassed) {
getPassButton().setEnabled(true);;
@@ -550,7 +508,7 @@
public void testEndedError(int testId, String str) {
super.testEndedError(testId, str);
Log.v(TAG, "Test EndedError. " + testId + " str:"+str);
- showView(mProgress, false);
+ showProgressIndicator(false);
mResultTest.setText("test failed. " + str);
}
};
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyLineActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyLineActivity.java
index 22e2c7d..654506d 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyLineActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyLineActivity.java
@@ -18,6 +18,7 @@
import com.android.cts.verifier.CtsVerifierReportLog;
import com.android.cts.verifier.R;
+import com.android.cts.verifier.audio.soundio.SoundPlayerObject;
import com.android.cts.verifier.audio.wavelib.*;
import com.android.compatibility.common.util.ResultType;
import com.android.compatibility.common.util.ResultUnit;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyMicActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyMicActivity.java
index 72f5ae1..f46fe8c 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyMicActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyMicActivity.java
@@ -19,6 +19,7 @@
import com.android.cts.verifier.R;
import com.android.cts.verifier.CtsVerifierReportLog;
+import com.android.cts.verifier.audio.soundio.SoundPlayerObject;
import com.android.cts.verifier.audio.wavelib.*;
import com.android.compatibility.common.util.ResultType;
import com.android.compatibility.common.util.ResultUnit;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencySpeakerActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencySpeakerActivity.java
index 3788048..deb1887 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencySpeakerActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencySpeakerActivity.java
@@ -18,6 +18,7 @@
import com.android.cts.verifier.CtsVerifierReportLog;
import com.android.cts.verifier.R;
+import com.android.cts.verifier.audio.soundio.SoundPlayerObject;
import com.android.cts.verifier.audio.wavelib.*;
import com.android.compatibility.common.util.ResultType;
import com.android.compatibility.common.util.ResultUnit;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyUnprocessedActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyUnprocessedActivity.java
index 5509501..182d8be 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyUnprocessedActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyUnprocessedActivity.java
@@ -18,6 +18,7 @@
import com.android.cts.verifier.CtsVerifierReportLog;
import com.android.cts.verifier.R;
+import com.android.cts.verifier.audio.soundio.SoundPlayerObject;
import com.android.cts.verifier.audio.wavelib.*;
import com.android.compatibility.common.util.ResultType;
import com.android.compatibility.common.util.ResultUnit;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyVoiceRecognitionActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyVoiceRecognitionActivity.java
index 5ed51e3..2435da5 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyVoiceRecognitionActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyVoiceRecognitionActivity.java
@@ -18,6 +18,8 @@
import com.android.cts.verifier.CtsVerifierReportLog;
import com.android.cts.verifier.R;
+import com.android.cts.verifier.audio.soundio.SoundPlayerObject;
+import com.android.cts.verifier.audio.soundio.SoundRecorderObject;
import com.android.cts.verifier.audio.wavelib.*;
import com.android.compatibility.common.util.ResultType;
import com.android.compatibility.common.util.ResultUnit;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundSpeakerTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundSpeakerTestActivity.java
index 01802a4..dcac83ab 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundSpeakerTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundSpeakerTestActivity.java
@@ -37,6 +37,10 @@
import android.widget.TextView;
import java.util.Arrays;
+import com.android.cts.verifier.audio.audiolib.AudioCommon;
+import com.android.cts.verifier.audio.soundio.SoundGenerator;
+import com.android.cts.verifier.audio.wavlib.WavAnalyzer;
+
import com.androidplot.xy.PointLabelFormatter;
import com.androidplot.xy.LineAndPointFormatter;
import com.androidplot.xy.SimpleXYSeries;
@@ -181,11 +185,12 @@
@Override
public void run() {
Double recordingDuration_millis = new Double(1000 * (2.5
- + Common.PREFIX_LENGTH_S
- + Common.PAUSE_BEFORE_PREFIX_DURATION_S
- + Common.PAUSE_AFTER_PREFIX_DURATION_S
- + Common.PIP_NUM * (Common.PIP_DURATION_S + Common.PAUSE_DURATION_S)
- * Common.REPETITIONS));
+ + AudioCommon.PREFIX_LENGTH_S
+ + AudioCommon.PAUSE_BEFORE_PREFIX_DURATION_S
+ + AudioCommon.PAUSE_AFTER_PREFIX_DURATION_S
+ + AudioCommon.PIP_NUM
+ * (AudioCommon.PIP_DURATION_S + AudioCommon.PAUSE_DURATION_S)
+ * AudioCommon.REPETITIONS));
Log.d(TAG, "Recording for " + recordingDuration_millis + "ms");
try {
Thread.sleep(recordingDuration_millis.intValue());
@@ -262,17 +267,17 @@
XYPlot plot = (XYPlot) popupView.findViewById(R.id.responseChart);
plot.setDomainStep(XYStepMode.INCREMENT_BY_VAL, 2000);
- Double[] frequencies = new Double[Common.PIP_NUM];
- for (int i = 0; i < Common.PIP_NUM; i++) {
- frequencies[i] = new Double(Common.FREQUENCIES_ORIGINAL[i]);
+ Double[] frequencies = new Double[AudioCommon.PIP_NUM];
+ for (int i = 0; i < AudioCommon.PIP_NUM; i++) {
+ frequencies[i] = new Double(AudioCommon.FREQUENCIES_ORIGINAL[i]);
}
if (wavAnalyzerTask != null) {
double[][] power = wavAnalyzerTask.getPower();
- for(int i = 0; i < Common.REPETITIONS; i++) {
- Double[] powerWrap = new Double[Common.PIP_NUM];
- for (int j = 0; j < Common.PIP_NUM; j++) {
+ for(int i = 0; i < AudioCommon.REPETITIONS; i++) {
+ Double[] powerWrap = new Double[AudioCommon.PIP_NUM];
+ for (int j = 0; j < AudioCommon.PIP_NUM; j++) {
powerWrap[j] = new Double(10 * Math.log10(power[j][i]));
}
XYSeries series = new SimpleXYSeries(
@@ -287,8 +292,8 @@
}
double[] noiseDB = wavAnalyzerTask.getNoiseDB();
- Double[] noiseDBWrap = new Double[Common.PIP_NUM];
- for (int i = 0; i < Common.PIP_NUM; i++) {
+ Double[] noiseDBWrap = new Double[AudioCommon.PIP_NUM];
+ for (int i = 0; i < AudioCommon.PIP_NUM; i++) {
noiseDBWrap[i] = new Double(noiseDB[i]);
}
@@ -303,8 +308,8 @@
plot.addSeries(noiseSeries, noiseSeriesFormat);
double[] dB = wavAnalyzerTask.getDB();
- Double[] dBWrap = new Double[Common.PIP_NUM];
- for (int i = 0; i < Common.PIP_NUM; i++) {
+ Double[] dBWrap = new Double[AudioCommon.PIP_NUM];
+ for (int i = 0; i < AudioCommon.PIP_NUM; i++) {
dBWrap[i] = new Double(dB[i]);
}
@@ -318,7 +323,7 @@
R.xml.ultrasound_line_formatter_median);
plot.addSeries(series, seriesFormat);
- Double[] passX = new Double[] {Common.MIN_FREQUENCY_HZ, Common.MAX_FREQUENCY_HZ};
+ Double[] passX = new Double[] {AudioCommon.MIN_FREQUENCY_HZ, AudioCommon.MAX_FREQUENCY_HZ};
Double[] passY = new Double[] {wavAnalyzerTask.getThreshold(), wavAnalyzerTask.getThreshold()};
XYSeries passSeries = new SimpleXYSeries(
Arrays.asList(passX), Arrays.asList(passY), "passing");
@@ -334,7 +339,7 @@
* Plays the generated pips.
*/
private void play() {
- play(SoundGenerator.getInstance().getByte(), Common.PLAYING_SAMPLE_RATE_HZ);
+ play(SoundGenerator.getInstance().getByte(), AudioCommon.PLAYING_SAMPLE_RATE_HZ);
}
/**
@@ -364,7 +369,7 @@
WavAnalyzer wavAnalyzer;
public WavAnalyzerTask(byte[] recording) {
- wavAnalyzer = new WavAnalyzer(recording, Common.RECORDING_SAMPLE_RATE_HZ,
+ wavAnalyzer = new WavAnalyzer(recording, AudioCommon.RECORDING_SAMPLE_RATE_HZ,
WavAnalyzerTask.this);
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundTestActivity.java
index f5e4271..3d5688d 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundTestActivity.java
@@ -37,6 +37,10 @@
import android.widget.TextView;
import java.util.Arrays;
+import com.android.cts.verifier.audio.audiolib.AudioCommon;
+import com.android.cts.verifier.audio.soundio.SoundGenerator;
+import com.android.cts.verifier.audio.wavlib.WavAnalyzer;
+
import com.androidplot.xy.PointLabelFormatter;
import com.androidplot.xy.LineAndPointFormatter;
import com.androidplot.xy.SimpleXYSeries;
@@ -161,11 +165,11 @@
@Override
public void run() {
Double recordingDuration_millis = new Double(1000 * (2.5
- + Common.PREFIX_LENGTH_S
- + Common.PAUSE_BEFORE_PREFIX_DURATION_S
- + Common.PAUSE_AFTER_PREFIX_DURATION_S
- + Common.PIP_NUM * (Common.PIP_DURATION_S + Common.PAUSE_DURATION_S)
- * Common.REPETITIONS));
+ + AudioCommon.PREFIX_LENGTH_S
+ + AudioCommon.PAUSE_BEFORE_PREFIX_DURATION_S
+ + AudioCommon.PAUSE_AFTER_PREFIX_DURATION_S
+ + AudioCommon.PIP_NUM * (AudioCommon.PIP_DURATION_S + AudioCommon.PAUSE_DURATION_S)
+ * AudioCommon.REPETITIONS));
Log.d(TAG, "Recording for " + recordingDuration_millis + "ms");
try {
Thread.sleep(recordingDuration_millis.intValue());
@@ -221,18 +225,18 @@
XYPlot plot = (XYPlot) popupView.findViewById(R.id.responseChart);
plot.setDomainStep(XYStepMode.INCREMENT_BY_VAL, 2000);
- Double[] frequencies = new Double[Common.PIP_NUM];
- for (int i = 0; i < Common.PIP_NUM; i++) {
- frequencies[i] = new Double(Common.FREQUENCIES_ORIGINAL[i]);
+ Double[] frequencies = new Double[AudioCommon.PIP_NUM];
+ for (int i = 0; i < AudioCommon.PIP_NUM; i++) {
+ frequencies[i] = new Double(AudioCommon.FREQUENCIES_ORIGINAL[i]);
}
if (wavAnalyzerTask != null && wavAnalyzerTask.getPower() != null &&
wavAnalyzerTask.getNoiseDB() != null && wavAnalyzerTask.getDB() != null) {
double[][] power = wavAnalyzerTask.getPower();
- for(int i = 0; i < Common.REPETITIONS; i++) {
- Double[] powerWrap = new Double[Common.PIP_NUM];
- for (int j = 0; j < Common.PIP_NUM; j++) {
+ for(int i = 0; i < AudioCommon.REPETITIONS; i++) {
+ Double[] powerWrap = new Double[AudioCommon.PIP_NUM];
+ for (int j = 0; j < AudioCommon.PIP_NUM; j++) {
powerWrap[j] = new Double(10 * Math.log10(power[j][i]));
}
XYSeries series = new SimpleXYSeries(
@@ -247,8 +251,8 @@
}
double[] noiseDB = wavAnalyzerTask.getNoiseDB();
- Double[] noiseDBWrap = new Double[Common.PIP_NUM];
- for (int i = 0; i < Common.PIP_NUM; i++) {
+ Double[] noiseDBWrap = new Double[AudioCommon.PIP_NUM];
+ for (int i = 0; i < AudioCommon.PIP_NUM; i++) {
noiseDBWrap[i] = new Double(noiseDB[i]);
}
@@ -263,8 +267,8 @@
plot.addSeries(noiseSeries, noiseSeriesFormat);
double[] dB = wavAnalyzerTask.getDB();
- Double[] dBWrap = new Double[Common.PIP_NUM];
- for (int i = 0; i < Common.PIP_NUM; i++) {
+ Double[] dBWrap = new Double[AudioCommon.PIP_NUM];
+ for (int i = 0; i < AudioCommon.PIP_NUM; i++) {
dBWrap[i] = new Double(dB[i]);
}
@@ -278,7 +282,7 @@
R.xml.ultrasound_line_formatter_median);
plot.addSeries(series, seriesFormat);
- Double[] passX = new Double[] {Common.MIN_FREQUENCY_HZ, Common.MAX_FREQUENCY_HZ};
+ Double[] passX = new Double[] {AudioCommon.MIN_FREQUENCY_HZ, AudioCommon.MAX_FREQUENCY_HZ};
Double[] passY = new Double[] {wavAnalyzerTask.getThreshold(), wavAnalyzerTask.getThreshold()};
XYSeries passSeries = new SimpleXYSeries(
Arrays.asList(passX), Arrays.asList(passY), "passing");
@@ -294,7 +298,7 @@
* Plays the generated pips.
*/
private void play() {
- play(SoundGenerator.getInstance().getByte(), Common.PLAYING_SAMPLE_RATE_HZ);
+ play(SoundGenerator.getInstance().getByte(), AudioCommon.PLAYING_SAMPLE_RATE_HZ);
}
/**
@@ -324,7 +328,7 @@
WavAnalyzer wavAnalyzer;
public WavAnalyzerTask(byte[] recording) {
- wavAnalyzer = new WavAnalyzer(recording, Common.RECORDING_SAMPLE_RATE_HZ,
+ wavAnalyzer = new WavAnalyzer(recording, AudioCommon.RECORDING_SAMPLE_RATE_HZ,
WavAnalyzerTask.this);
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/SoundGenerator.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/SoundGenerator.java
deleted file mode 100644
index 0ad9371..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/SoundGenerator.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package com.android.cts.verifier.audio;
-
-/**
- * Sound generator.
- */
-public class SoundGenerator {
-
- private static SoundGenerator instance;
-
- private final byte[] generatedSound;
- private final double[] sample;
-
- private SoundGenerator() {
- // Initialize sample.
- int pipNum = Common.PIP_NUM;
- int prefixTotalLength = Util.toLength(Common.PREFIX_LENGTH_S, Common.PLAYING_SAMPLE_RATE_HZ)
- + Util.toLength(Common.PAUSE_BEFORE_PREFIX_DURATION_S, Common.PLAYING_SAMPLE_RATE_HZ)
- + Util.toLength(Common.PAUSE_AFTER_PREFIX_DURATION_S, Common.PLAYING_SAMPLE_RATE_HZ);
- int repetitionLength = pipNum * Util.toLength(
- Common.PIP_DURATION_S + Common.PAUSE_DURATION_S, Common.PLAYING_SAMPLE_RATE_HZ);
- int sampleLength = prefixTotalLength + Common.REPETITIONS * repetitionLength;
- sample = new double[sampleLength];
-
- // Fill sample with prefix.
- System.arraycopy(Common.PREFIX_FOR_PLAYER, 0, sample,
- Util.toLength(Common.PAUSE_BEFORE_PREFIX_DURATION_S, Common.PLAYING_SAMPLE_RATE_HZ),
- Common.PREFIX_FOR_PLAYER.length);
-
- // Fill the sample.
- for (int i = 0; i < pipNum * Common.REPETITIONS; i++) {
- double[] pip = getPip(Common.WINDOW_FOR_PLAYER, Common.FREQUENCIES[i]);
- System.arraycopy(pip, 0, sample,
- prefixTotalLength + i * Util.toLength(
- Common.PIP_DURATION_S + Common.PAUSE_DURATION_S, Common.PLAYING_SAMPLE_RATE_HZ),
- pip.length);
- }
-
- // Convert sample to byte.
- generatedSound = new byte[2 * sample.length];
- int i = 0;
- for (double dVal : sample) {
- short val = (short) ((dVal * 32767));
- generatedSound[i++] = (byte) (val & 0x00ff);
- generatedSound[i++] = (byte) ((val & 0xff00) >>> 8);
- }
- }
-
- public static SoundGenerator getInstance() {
- if (instance == null) {
- instance = new SoundGenerator();
- }
- return instance;
- }
-
- /**
- * Gets a pip sample.
- */
- private static double[] getPip(double[] window, double frequency) {
- int pipArrayLength = window.length;
- double[] pipArray = new double[pipArrayLength];
- double radPerSample = 2 * Math.PI / (Common.PLAYING_SAMPLE_RATE_HZ / frequency);
- for (int i = 0; i < pipArrayLength; i++) {
- pipArray[i] = window[i] * Math.sin(i * radPerSample);
- }
- return pipArray;
- }
-
- /**
- * Get generated sound in byte[].
- */
- public byte[] getByte() {
- return generatedSound;
- }
-
- /**
- * Get sample in double[].
- */
- public double[] getSample() {
- return sample;
- }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/Common.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/audiolib/AudioCommon.java
similarity index 90%
rename from apps/CtsVerifier/src/com/android/cts/verifier/audio/Common.java
rename to apps/CtsVerifier/src/com/android/cts/verifier/audio/audiolib/AudioCommon.java
index df7460a..ba5e39b2 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/Common.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/audiolib/AudioCommon.java
@@ -1,15 +1,18 @@
-package com.android.cts.verifier.audio;
+package com.android.cts.verifier.audio.audiolib;
import android.media.AudioManager;
import android.media.AudioTrack;
+import com.android.cts.verifier.audio.AudioRecordHelper;
+import com.android.cts.verifier.audio.Util;
+
import java.util.ArrayList;
import java.util.Random;
/**
* This class stores common constants and methods.
*/
-public class Common {
+public class AudioCommon {
public static final int RECORDING_SAMPLE_RATE_HZ
= AudioRecordHelper.getInstance().getSampleRate();
@@ -95,7 +98,7 @@
private static double[] frequencies() {
double[] originalFrequencies = originalFrequencies();
- double[] randomFrequencies = new double[Common.REPETITIONS * originalFrequencies.length];
+ double[] randomFrequencies = new double[AudioCommon.REPETITIONS * originalFrequencies.length];
for (int i = 0; i < REPETITIONS * originalFrequencies.length; i++) {
randomFrequencies[i] = originalFrequencies[ORDER[i] % originalFrequencies.length];
}
@@ -108,13 +111,13 @@
*/
private static double[] originalFrequencies() {
ArrayList<Double> frequencies = new ArrayList<Double>();
- double frequency = Common.MIN_FREQUENCY_HZ;
- while (frequency <= Common.MAX_FREQUENCY_HZ) {
+ double frequency = AudioCommon.MIN_FREQUENCY_HZ;
+ while (frequency <= AudioCommon.MAX_FREQUENCY_HZ) {
frequencies.add(new Double(frequency));
if ((frequency >= 18500) && (frequency < 20000)) {
- frequency += Common.FREQUENCY_STEP_HZ;
+ frequency += AudioCommon.FREQUENCY_STEP_HZ;
} else {
- frequency += Common.FREQUENCY_STEP_HZ * 10;
+ frequency += AudioCommon.FREQUENCY_STEP_HZ * 10;
}
}
Double[] frequenciesArray = frequencies.toArray(new Double[frequencies.size()]);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/soundio/SoundGenerator.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/soundio/SoundGenerator.java
new file mode 100644
index 0000000..3ea5790
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/soundio/SoundGenerator.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.cts.verifier.audio.soundio;
+
+import com.android.cts.verifier.audio.audiolib.AudioCommon;
+import com.android.cts.verifier.audio.Util;
+
+/**
+ * Sound generator.
+ */
+public class SoundGenerator {
+
+ private static SoundGenerator instance;
+
+ private final byte[] generatedSound;
+ private final double[] sample;
+
+ private SoundGenerator() {
+ // Initialize sample.
+ int pipNum = AudioCommon.PIP_NUM;
+ int prefixTotalLength =
+ Util.toLength(AudioCommon.PREFIX_LENGTH_S, AudioCommon.PLAYING_SAMPLE_RATE_HZ)
+ + Util.toLength(AudioCommon.PAUSE_BEFORE_PREFIX_DURATION_S,
+ AudioCommon.PLAYING_SAMPLE_RATE_HZ)
+ + Util.toLength(AudioCommon.PAUSE_AFTER_PREFIX_DURATION_S,
+ AudioCommon.PLAYING_SAMPLE_RATE_HZ);
+ int repetitionLength = pipNum * Util.toLength(
+ AudioCommon.PIP_DURATION_S + AudioCommon.PAUSE_DURATION_S,
+ AudioCommon.PLAYING_SAMPLE_RATE_HZ);
+ int sampleLength = prefixTotalLength + AudioCommon.REPETITIONS * repetitionLength;
+ sample = new double[sampleLength];
+
+ // Fill sample with prefix.
+ System.arraycopy(AudioCommon.PREFIX_FOR_PLAYER, 0, sample,
+ Util.toLength(AudioCommon.PAUSE_BEFORE_PREFIX_DURATION_S,
+ AudioCommon.PLAYING_SAMPLE_RATE_HZ),
+ AudioCommon.PREFIX_FOR_PLAYER.length);
+
+ // Fill the sample.
+ for (int i = 0; i < pipNum * AudioCommon.REPETITIONS; i++) {
+ double[] pip = getPip(AudioCommon.WINDOW_FOR_PLAYER, AudioCommon.FREQUENCIES[i]);
+ System.arraycopy(pip, 0, sample,
+ prefixTotalLength + i * Util.toLength(
+ AudioCommon.PIP_DURATION_S + AudioCommon.PAUSE_DURATION_S,
+ AudioCommon.PLAYING_SAMPLE_RATE_HZ),
+ pip.length);
+ }
+
+ // Convert sample to byte.
+ generatedSound = new byte[2 * sample.length];
+ int i = 0;
+ for (double dVal : sample) {
+ short val = (short) ((dVal * 32767));
+ generatedSound[i++] = (byte) (val & 0x00ff);
+ generatedSound[i++] = (byte) ((val & 0xff00) >>> 8);
+ }
+ }
+
+ public static SoundGenerator getInstance() {
+ if (instance == null) {
+ instance = new SoundGenerator();
+ }
+ return instance;
+ }
+
+ /**
+ * Gets a pip sample.
+ */
+ private static double[] getPip(double[] window, double frequency) {
+ int pipArrayLength = window.length;
+ double[] pipArray = new double[pipArrayLength];
+ double radPerSample = 2 * Math.PI / (AudioCommon.PLAYING_SAMPLE_RATE_HZ / frequency);
+ for (int i = 0; i < pipArrayLength; i++) {
+ pipArray[i] = window[i] * Math.sin(i * radPerSample);
+ }
+ return pipArray;
+ }
+
+ /**
+ * Get generated sound in byte[].
+ */
+ public byte[] getByte() {
+ return generatedSound;
+ }
+
+ /**
+ * Get sample in double[].
+ */
+ public double[] getSample() {
+ return sample;
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/SoundPlayerObject.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/soundio/SoundPlayerObject.java
similarity index 99%
rename from apps/CtsVerifier/src/com/android/cts/verifier/audio/SoundPlayerObject.java
rename to apps/CtsVerifier/src/com/android/cts/verifier/audio/soundio/SoundPlayerObject.java
index 0d93dbb..156460b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/SoundPlayerObject.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/soundio/SoundPlayerObject.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.cts.verifier.audio;
+package com.android.cts.verifier.audio.soundio;
import android.content.Context;
import android.media.AudioAttributes;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/SoundRecorderObject.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/soundio/SoundRecorderObject.java
similarity index 98%
rename from apps/CtsVerifier/src/com/android/cts/verifier/audio/SoundRecorderObject.java
rename to apps/CtsVerifier/src/com/android/cts/verifier/audio/soundio/SoundRecorderObject.java
index 8950ec5..d83a5dd 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/SoundRecorderObject.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/soundio/SoundRecorderObject.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.cts.verifier.audio;
+package com.android.cts.verifier.audio.soundio;
import android.media.AudioFormat;
import android.media.AudioRecord;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/RmsHelper.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/RmsHelper.java
new file mode 100644
index 0000000..71d3ec1
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/RmsHelper.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.cts.verifier.audio.wavelib;
+
+public class RmsHelper {
+ private double mRmsCurrent;
+ public int mBlockSize;
+ private int mShoutCount;
+ public boolean mRunning = false;
+
+ private short[] mAudioShortArray;
+
+ private DspBufferDouble mRmsSnapshots;
+ private int mShotIndex;
+
+ private final float mMinRmsDb;
+ private final float mMinRmsVal;
+
+ private static final float MAX_VAL = (float)(1 << 15);
+
+ public RmsHelper(int blockSize, int shotCount, float minRmsDb, float minRmsVal) {
+ mBlockSize = blockSize;
+ mShoutCount = shotCount;
+ mMinRmsDb = minRmsDb;
+ mMinRmsVal = minRmsVal;
+
+ reset();
+ }
+
+ public void reset() {
+ mAudioShortArray = new short[mBlockSize];
+ mRmsSnapshots = new DspBufferDouble(mShoutCount);
+ mShotIndex = 0;
+ mRmsCurrent = 0;
+ mRunning = false;
+ }
+
+ public void captureShot() {
+ if (mShotIndex >= 0 && mShotIndex < mRmsSnapshots.getSize()) {
+ mRmsSnapshots.setValue(mShotIndex++, mRmsCurrent);
+ }
+ }
+
+ public void setRunning(boolean running) {
+ mRunning = running;
+ }
+
+ public double getRmsCurrent() {
+ return mRmsCurrent;
+ }
+
+ public DspBufferDouble getRmsSnapshots() {
+ return mRmsSnapshots;
+ }
+
+ public boolean updateRms(PipeShort pipe, int channelCount, int channel) {
+ if (mRunning) {
+ int samplesAvailable = pipe.availableToRead();
+ while (samplesAvailable >= mBlockSize) {
+ pipe.read(mAudioShortArray, 0, mBlockSize);
+
+ double rmsTempSum = 0;
+ int count = 0;
+ for (int i = channel; i < mBlockSize; i += channelCount) {
+ float value = mAudioShortArray[i] / MAX_VAL;
+
+ rmsTempSum += value * value;
+ count++;
+ }
+ float rms = count > 0 ? (float)Math.sqrt(rmsTempSum / count) : 0f;
+ if (rms < mMinRmsVal) {
+ rms = mMinRmsVal;
+ }
+
+ double alpha = 0.9;
+ double total_rms = rms * alpha + mRmsCurrent * (1.0f - alpha);
+ mRmsCurrent = total_rms;
+
+ samplesAvailable = pipe.availableToRead();
+ }
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/WavAnalyzer.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/WavAnalyzer.java
similarity index 64%
rename from apps/CtsVerifier/src/com/android/cts/verifier/audio/WavAnalyzer.java
rename to apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/WavAnalyzer.java
index b75c40b..6fdccb4 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/WavAnalyzer.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/WavAnalyzer.java
@@ -1,4 +1,22 @@
-package com.android.cts.verifier.audio;
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.cts.verifier.audio.wavlib;
+
+import com.android.cts.verifier.audio.audiolib.AudioCommon;
+import com.android.cts.verifier.audio.Util;
import org.apache.commons.math.complex.Complex;
@@ -60,7 +78,7 @@
/**
* Check if the recording is clipped.
*/
- boolean isClipped() {
+ public boolean isClipped() {
for (int i = 1; i < data.length; i++) {
if ((Math.abs(data[i]) >= Short.MAX_VALUE) && (Math.abs(data[i - 1]) >= Short.MAX_VALUE)) {
listener.sendMessage("WARNING: Data is clipped."
@@ -74,11 +92,11 @@
/**
* Check if the result is consistant across trials.
*/
- boolean isConsistent() {
- double[] coeffOfVar = new double[Common.PIP_NUM];
- for (int i = 0; i < Common.PIP_NUM; i++) {
- double[] powerAtFreq = new double[Common.REPETITIONS];
- for (int j = 0; j < Common.REPETITIONS; j++) {
+ public boolean isConsistent() {
+ double[] coeffOfVar = new double[AudioCommon.PIP_NUM];
+ for (int i = 0; i < AudioCommon.PIP_NUM; i++) {
+ double[] powerAtFreq = new double[AudioCommon.REPETITIONS];
+ for (int j = 0; j < AudioCommon.REPETITIONS; j++) {
powerAtFreq[j] = power[i][j];
}
coeffOfVar[i] = Util.std(powerAtFreq) / Util.mean(powerAtFreq);
@@ -94,7 +112,7 @@
/**
* Determine test pass/fail using the frequency response. Package visible for unit testing.
*/
- boolean responsePassesHifiTest(double[] dB) {
+ public boolean responsePassesHifiTest(double[] dB) {
for (int i = 0; i < dB.length; i++) {
// Precautionary; NaN should not happen.
if (Double.isNaN(dB[i])) {
@@ -104,16 +122,16 @@
}
}
- if (Util.mean(dB) - Util.mean(noiseDB) < Common.SIGNAL_MIN_STRENGTH_DB_ABOVE_NOISE) {
+ if (Util.mean(dB) - Util.mean(noiseDB) < AudioCommon.SIGNAL_MIN_STRENGTH_DB_ABOVE_NOISE) {
listener.sendMessage("WARNING: Signal is too weak or background noise is too strong."
+ " Turn up the volume of the playback device or move to a quieter location.\n");
return false;
}
- int indexOf2000Hz = Util.findClosest(Common.FREQUENCIES_ORIGINAL, 2000.0);
- threshold = dB[indexOf2000Hz] + Common.PASSING_THRESHOLD_DB;
- int indexOf18500Hz = Util.findClosest(Common.FREQUENCIES_ORIGINAL, 18500.0);
- int indexOf20000Hz = Util.findClosest(Common.FREQUENCIES_ORIGINAL, 20000.0);
+ int indexOf2000Hz = Util.findClosest(AudioCommon.FREQUENCIES_ORIGINAL, 2000.0);
+ threshold = dB[indexOf2000Hz] + AudioCommon.PASSING_THRESHOLD_DB;
+ int indexOf18500Hz = Util.findClosest(AudioCommon.FREQUENCIES_ORIGINAL, 18500.0);
+ int indexOf20000Hz = Util.findClosest(AudioCommon.FREQUENCIES_ORIGINAL, 20000.0);
double[] responseInRange = new double[indexOf20000Hz - indexOf18500Hz];
System.arraycopy(dB, indexOf18500Hz, responseInRange, 0, responseInRange.length);
if (Util.mean(responseInRange) < threshold) {
@@ -128,15 +146,15 @@
* Calculate the Fourier Coefficient at the pip frequency to calculate the frequency response.
* Package visible for unit testing.
*/
- double[] measurePipStrength() {
+ public double[] measurePipStrength() {
listener.sendMessage("Aligning data... Please wait...\n");
final int dataStartI = alignData();
final int prefixTotalLength = dataStartI
- + Util.toLength(Common.PREFIX_LENGTH_S + Common.PAUSE_AFTER_PREFIX_DURATION_S, sampleRate);
+ + Util.toLength(AudioCommon.PREFIX_LENGTH_S + AudioCommon.PAUSE_AFTER_PREFIX_DURATION_S, sampleRate);
listener.sendMessage("Done.\n");
listener.sendMessage("Prefix starts at " + (double) dataStartI / sampleRate + " s \n");
- if (dataStartI > Math.round(sampleRate * (Common.PREFIX_LENGTH_S
- + Common.PAUSE_BEFORE_PREFIX_DURATION_S + Common.PAUSE_AFTER_PREFIX_DURATION_S))) {
+ if (dataStartI > Math.round(sampleRate * (AudioCommon.PREFIX_LENGTH_S
+ + AudioCommon.PAUSE_BEFORE_PREFIX_DURATION_S + AudioCommon.PAUSE_AFTER_PREFIX_DURATION_S))) {
listener.sendMessage("WARNING: Unexpected prefix start time. May have missed the prefix.\n"
+ "PLAY button should be pressed on the playback device within one second"
+ " after RECORD is pressed on the recording device.\n"
@@ -145,17 +163,17 @@
}
listener.sendMessage("Analyzing noise strength... Please wait...\n");
- noisePower = new double[Common.PIP_NUM][Common.NOISE_SAMPLES];
- noiseDB = new double[Common.PIP_NUM];
- for (int s = 0; s < Common.NOISE_SAMPLES; s++) {
- double[] noisePoints = new double[Common.WINDOW_FOR_RECORDER.length];
+ noisePower = new double[AudioCommon.PIP_NUM][AudioCommon.NOISE_SAMPLES];
+ noiseDB = new double[AudioCommon.PIP_NUM];
+ for (int s = 0; s < AudioCommon.NOISE_SAMPLES; s++) {
+ double[] noisePoints = new double[AudioCommon.WINDOW_FOR_RECORDER.length];
System.arraycopy(data, dataStartI - (s + 1) * noisePoints.length - 1,
noisePoints, 0, noisePoints.length);
for (int j = 0; j < noisePoints.length; j++) {
- noisePoints[j] = noisePoints[j] * Common.WINDOW_FOR_RECORDER[j];
+ noisePoints[j] = noisePoints[j] * AudioCommon.WINDOW_FOR_RECORDER[j];
}
- for (int i = 0; i < Common.PIP_NUM; i++) {
- double freq = Common.FREQUENCIES_ORIGINAL[i];
+ for (int i = 0; i < AudioCommon.PIP_NUM; i++) {
+ double freq = AudioCommon.FREQUENCIES_ORIGINAL[i];
Complex fourierCoeff = new Complex(0, 0);
final Complex rotator = new Complex(0,
-2.0 * Math.PI * freq / sampleRate).exp();
@@ -168,48 +186,48 @@
noisePower[i][s] = fourierCoeff.multiply(fourierCoeff.conjugate()).abs();
}
}
- for (int i = 0; i < Common.PIP_NUM; i++) {
+ for (int i = 0; i < AudioCommon.PIP_NUM; i++) {
double meanNoisePower = 0;
- for (int j = 0; j < Common.NOISE_SAMPLES; j++) {
+ for (int j = 0; j < AudioCommon.NOISE_SAMPLES; j++) {
meanNoisePower += noisePower[i][j];
}
- meanNoisePower /= Common.NOISE_SAMPLES;
+ meanNoisePower /= AudioCommon.NOISE_SAMPLES;
noiseDB[i] = 10 * Math.log10(meanNoisePower);
}
listener.sendMessage("Analyzing pips... Please wait...\n");
- power = new double[Common.PIP_NUM][Common.REPETITIONS];
- for (int i = 0; i < Common.PIP_NUM * Common.REPETITIONS; i++) {
- if (i % Common.PIP_NUM == 0) {
- listener.sendMessage("#" + (i / Common.PIP_NUM + 1) + "\n");
+ power = new double[AudioCommon.PIP_NUM][AudioCommon.REPETITIONS];
+ for (int i = 0; i < AudioCommon.PIP_NUM * AudioCommon.REPETITIONS; i++) {
+ if (i % AudioCommon.PIP_NUM == 0) {
+ listener.sendMessage("#" + (i / AudioCommon.PIP_NUM + 1) + "\n");
}
int pipExpectedStartI;
pipExpectedStartI = prefixTotalLength
- + Util.toLength(i * (Common.PIP_DURATION_S + Common.PAUSE_DURATION_S), sampleRate);
+ + Util.toLength(i * (AudioCommon.PIP_DURATION_S + AudioCommon.PAUSE_DURATION_S), sampleRate);
// Cut out the data points for the current pip.
- double[] pipPoints = new double[Common.WINDOW_FOR_RECORDER.length];
+ double[] pipPoints = new double[AudioCommon.WINDOW_FOR_RECORDER.length];
System.arraycopy(data, pipExpectedStartI, pipPoints, 0, pipPoints.length);
- for (int j = 0; j < Common.WINDOW_FOR_RECORDER.length; j++) {
- pipPoints[j] = pipPoints[j] * Common.WINDOW_FOR_RECORDER[j];
+ for (int j = 0; j < AudioCommon.WINDOW_FOR_RECORDER.length; j++) {
+ pipPoints[j] = pipPoints[j] * AudioCommon.WINDOW_FOR_RECORDER[j];
}
Complex fourierCoeff = new Complex(0, 0);
final Complex rotator = new Complex(0,
- -2.0 * Math.PI * Common.FREQUENCIES[i] / sampleRate).exp();
+ -2.0 * Math.PI * AudioCommon.FREQUENCIES[i] / sampleRate).exp();
Complex phasor = new Complex(1, 0);
for (int j = 0; j < pipPoints.length; j++) {
fourierCoeff = fourierCoeff.add(phasor.multiply(pipPoints[j]));
phasor = phasor.multiply(rotator);
}
fourierCoeff = fourierCoeff.multiply(1.0 / pipPoints.length);
- int j = Common.ORDER[i];
- power[j % Common.PIP_NUM][j / Common.PIP_NUM] =
+ int j = AudioCommon.ORDER[i];
+ power[j % AudioCommon.PIP_NUM][j / AudioCommon.PIP_NUM] =
fourierCoeff.multiply(fourierCoeff.conjugate()).abs();
}
// Calculate median of trials.
- double[] dB = new double[Common.PIP_NUM];
- for (int i = 0; i < Common.PIP_NUM; i++) {
+ double[] dB = new double[AudioCommon.PIP_NUM];
+ for (int i = 0; i < AudioCommon.PIP_NUM; i++) {
dB[i] = 10 * Math.log10(Util.median(power[i]));
}
return dB;
@@ -218,38 +236,40 @@
/**
* Align data using prefix. Package visible for unit testing.
*/
- int alignData() {
+ public int alignData() {
// Zeropadding samples to add in the correlation to avoid FFT wraparound.
- final int zeroPad = Util.toLength(Common.PREFIX_LENGTH_S, Common.RECORDING_SAMPLE_RATE_HZ) - 1;
- int fftSize = Util.nextPowerOfTwo((int) Math.round(sampleRate * (Common.PREFIX_LENGTH_S
- + Common.PAUSE_BEFORE_PREFIX_DURATION_S + Common.PAUSE_AFTER_PREFIX_DURATION_S + 0.5))
+ final int zeroPad =
+ Util.toLength(AudioCommon.PREFIX_LENGTH_S, AudioCommon.RECORDING_SAMPLE_RATE_HZ) - 1;
+ int fftSize = Util.nextPowerOfTwo((int) Math.round(sampleRate * (AudioCommon.PREFIX_LENGTH_S
+ + AudioCommon.PAUSE_BEFORE_PREFIX_DURATION_S
+ + AudioCommon.PAUSE_AFTER_PREFIX_DURATION_S + 0.5))
+ zeroPad);
double[] dataCut = new double[fftSize - zeroPad];
System.arraycopy(data, 0, dataCut, 0, fftSize - zeroPad);
double[] xCorrDataPrefix = Util.computeCrossCorrelation(
Util.padZeros(Util.toComplex(dataCut), fftSize),
- Util.padZeros(Util.toComplex(Common.PREFIX_FOR_RECORDER), fftSize));
+ Util.padZeros(Util.toComplex(AudioCommon.PREFIX_FOR_RECORDER), fftSize));
return Util.findMaxIndex(xCorrDataPrefix);
}
- double[] getDB() {
+ public double[] getDB() {
return dB;
}
- double[][] getPower() {
+ public double[][] getPower() {
return power;
}
- double[] getNoiseDB() {
+ public double[] getNoiseDB() {
return noiseDB;
}
- double getThreshold() {
+ public double getThreshold() {
return threshold;
}
- boolean getResult() {
+ public boolean getResult() {
return result;
}