aboutsummaryrefslogtreecommitdiff
path: root/apps/OboeTester/app/src/main/cpp/analyzer/GlitchAnalyzer.h
diff options
context:
space:
mode:
Diffstat (limited to 'apps/OboeTester/app/src/main/cpp/analyzer/GlitchAnalyzer.h')
-rw-r--r--apps/OboeTester/app/src/main/cpp/analyzer/GlitchAnalyzer.h143
1 files changed, 99 insertions, 44 deletions
diff --git a/apps/OboeTester/app/src/main/cpp/analyzer/GlitchAnalyzer.h b/apps/OboeTester/app/src/main/cpp/analyzer/GlitchAnalyzer.h
index 52b00139..747c5ea9 100644
--- a/apps/OboeTester/app/src/main/cpp/analyzer/GlitchAnalyzer.h
+++ b/apps/OboeTester/app/src/main/cpp/analyzer/GlitchAnalyzer.h
@@ -50,10 +50,18 @@ public:
return mMagnitude;
}
+ int getSinePeriod() const {
+ return mSinePeriod;
+ }
+
int32_t getGlitchCount() const {
return mGlitchCount;
}
+ int32_t getGlitchLength() const {
+ return mGlitchLength;
+ }
+
int32_t getStateFrameCount(int state) const {
return mStateFrameCounters[state];
}
@@ -63,7 +71,7 @@ public:
if (mState != STATE_LOCKED
|| mMeanSquareSignal < threshold
|| mMeanSquareNoise < threshold) {
- return 0.0;
+ return -999.0; // error indicator
} else {
double signalToNoise = mMeanSquareSignal / mMeanSquareNoise; // power ratio
double signalToNoiseDB = 10.0 * log(signalToNoise);
@@ -124,21 +132,22 @@ public:
result_code result = RESULT_OK;
float sample = frameData[getInputChannel()];
- float peak = mPeakFollower.process(sample);
- mInfiniteRecording.write(sample);
// Force a periodic glitch to test the detector!
- if (mForceGlitchDuration > 0) {
+ if (mForceGlitchDurationFrames > 0) {
if (mForceGlitchCounter == 0) {
- ALOGE("%s: force a glitch!!", __func__);
- mForceGlitchCounter = getSampleRate();
- } else if (mForceGlitchCounter <= mForceGlitchDuration) {
+ ALOGE("%s: finish a glitch!!", __func__);
+ mForceGlitchCounter = kForceGlitchPeriod;
+ } else if (mForceGlitchCounter <= mForceGlitchDurationFrames) {
// Force an abrupt offset.
- sample += (sample > 0.0) ? -0.5f : 0.5f;
+ sample += (sample > 0.0) ? -kForceGlitchOffset : kForceGlitchOffset;
}
--mForceGlitchCounter;
}
+ float peak = mPeakFollower.process(sample);
+ mInfiniteRecording.write(sample);
+
mStateFrameCounters[mState]++; // count how many frames we are in each state
switch (mState) {
@@ -175,11 +184,12 @@ public:
// Must be a multiple of the period or the calculation will not be accurate.
if (mFramesAccumulated == mSinePeriod * PERIODS_NEEDED_FOR_LOCK) {
setMagnitude(calculateMagnitudePhase(&mPhaseOffset));
-// ALOGD("%s() mag = %f, offset = %f, prev = %f",
-// __func__, mMagnitude, mPhaseOffset, mPreviousPhaseOffset);
+ ALOGD("%s() mag = %f, mPhaseOffset = %f",
+ __func__, mMagnitude, mPhaseOffset);
if (mMagnitude > mThreshold) {
- if (abs(mPhaseOffset) < kMaxPhaseError) {
+ if (fabs(mPhaseOffset) < kMaxPhaseError) {
mState = STATE_LOCKED;
+ mConsecutiveBadFrames = 0;
// ALOGD("%5d: switch to STATE_LOCKED", mFrameCounter);
}
// Adjust mInputPhase to match measured phase
@@ -196,24 +206,36 @@ public:
double diff = predicted - sample;
double absDiff = fabs(diff);
mMaxGlitchDelta = std::max(mMaxGlitchDelta, absDiff);
- if (absDiff > mScaledTolerance) {
- result = ERROR_GLITCHES;
- onGlitchStart();
-// LOGI("diff glitch detected, absDiff = %g", absDiff);
- } else {
+ if (absDiff > mScaledTolerance) { // bad frame
+ mConsecutiveBadFrames++;
+ mConsecutiveGoodFrames = 0;
+ LOGI("diff glitch frame #%d detected, absDiff = %g > %g",
+ mConsecutiveBadFrames, absDiff, mScaledTolerance);
+ if (mConsecutiveBadFrames > 0) {
+ result = ERROR_GLITCHES;
+ onGlitchStart();
+ }
+ resetAccumulator();
+ } else { // good frame
+ mConsecutiveBadFrames = 0;
+ mConsecutiveGoodFrames++;
+
mSumSquareSignal += predicted * predicted;
mSumSquareNoise += diff * diff;
-
// Track incoming signal and slowly adjust magnitude to account
// for drift in the DRC or AGC.
// Must be a multiple of the period or the calculation will not be accurate.
if (transformSample(sample, mInputPhase)) {
+ // Adjust phase to account for sample rate drift.
+ mInputPhase += mPhaseOffset;
+
mMeanSquareNoise = mSumSquareNoise * mInverseSinePeriod;
mMeanSquareSignal = mSumSquareSignal * mInverseSinePeriod;
- resetAccumulator();
+ mSumSquareNoise = 0.0;
+ mSumSquareSignal = 0.0;
- if (abs(mPhaseOffset) > kMaxPhaseError) {
+ if (fabs(mPhaseOffset) > kMaxPhaseError) {
result = ERROR_GLITCHES;
onGlitchStart();
ALOGD("phase glitch detected, phaseOffset = %g", mPhaseOffset);
@@ -229,22 +251,25 @@ public:
case STATE_GLITCHING: {
// Predict next sine value
- mGlitchLength++;
double predicted = sinf(mInputPhase) * mMagnitude;
double diff = predicted - sample;
double absDiff = fabs(diff);
mMaxGlitchDelta = std::max(mMaxGlitchDelta, absDiff);
- if (absDiff < mScaledTolerance) { // close enough?
- // If we get a full sine period of non-glitch samples in a row then consider the glitch over.
+ if (absDiff > mScaledTolerance) { // bad frame
+ mConsecutiveBadFrames++;
+ mConsecutiveGoodFrames = 0;
+ mGlitchLength++;
+ if (mGlitchLength > maxMeasurableGlitchLength()) {
+ onGlitchTerminated();
+ }
+ } else { // good frame
+ mConsecutiveBadFrames = 0;
+ mConsecutiveGoodFrames++;
+ // If we get a full sine period of good samples in a row then consider the glitch over.
// We don't want to just consider a zero crossing the end of a glitch.
- if (mNonGlitchCount++ > mSinePeriod) {
+ if (mConsecutiveGoodFrames > mSinePeriod) {
onGlitchEnd();
}
- } else {
- mNonGlitchCount = 0;
- if (mGlitchLength > (4 * mSinePeriod)) {
- relock();
- }
}
incrementInputPhase();
} break;
@@ -258,6 +283,8 @@ public:
return result;
}
+ int maxMeasurableGlitchLength() const { return 2 * mSinePeriod; }
+
// advance and wrap phase
void incrementInputPhase() {
mInputPhase += mPhaseIncrement;
@@ -269,16 +296,29 @@ public:
bool isOutputEnabled() override { return mState != STATE_IDLE; }
void onGlitchStart() {
- mGlitchCount++;
-// ALOGD("%5d: STARTED a glitch # %d", mFrameCounter, mGlitchCount);
mState = STATE_GLITCHING;
mGlitchLength = 1;
- mNonGlitchCount = 0;
mLastGlitchPosition = mInfiniteRecording.getTotalWritten();
+ ALOGD("%5d: STARTED a glitch # %d, pos = %5d",
+ mFrameCounter, mGlitchCount, (int)mLastGlitchPosition);
+ ALOGD("glitch mSinePeriod = %d", mSinePeriod);
+ }
+
+ /**
+ * Give up waiting for a glitch to end and try to resync.
+ */
+ void onGlitchTerminated() {
+ mGlitchCount++;
+ ALOGD("%5d: TERMINATED a glitch # %d, length = %d", mFrameCounter, mGlitchCount, mGlitchLength);
+ // We don't know how long the glitch really is so set the length to -1.
+ mGlitchLength = -1;
+ mState = STATE_WAITING_FOR_LOCK;
+ resetAccumulator();
}
void onGlitchEnd() {
-// ALOGD("%5d: ENDED a glitch # %d, length = %d", mFrameCounter, mGlitchCount, mGlitchLength);
+ mGlitchCount++;
+ ALOGD("%5d: ENDED a glitch # %d, length = %d", mFrameCounter, mGlitchCount, mGlitchLength);
mState = STATE_LOCKED;
resetAccumulator();
}
@@ -286,14 +326,6 @@ public:
// reset the sine wave detector
void resetAccumulator() override {
BaseSineAnalyzer::resetAccumulator();
- mSumSquareSignal = 0.0;
- mSumSquareNoise = 0.0;
- }
-
- void relock() {
-// ALOGD("relock: %d because of a very long %d glitch", mFrameCounter, mGlitchLength);
- mState = STATE_WAITING_FOR_LOCK;
- resetAccumulator();
}
void reset() override {
@@ -305,6 +337,7 @@ public:
void prepareToTest() override {
BaseSineAnalyzer::prepareToTest();
mGlitchCount = 0;
+ mGlitchLength = 0;
mMaxGlitchDelta = 0.0;
for (int i = 0; i < NUM_STATES; i++) {
mStateFrameCounters[i] = 0;
@@ -312,7 +345,26 @@ public:
}
int32_t getLastGlitch(float *buffer, int32_t length) {
- return mInfiniteRecording.readFrom(buffer, mLastGlitchPosition - 32, length);
+ const int margin = mSinePeriod;
+ int32_t numSamples = mInfiniteRecording.readFrom(buffer,
+ mLastGlitchPosition - margin,
+ length);
+ ALOGD("%s: glitch at %d, edge = %7.4f, %7.4f, %7.4f",
+ __func__, (int)mLastGlitchPosition,
+ buffer[margin - 1], buffer[margin], buffer[margin+1]);
+ return numSamples;
+ }
+
+ int32_t getRecentSamples(float *buffer, int32_t length) {
+ int firstSample = mInfiniteRecording.getTotalWritten() - length;
+ int32_t numSamples = mInfiniteRecording.readFrom(buffer,
+ firstSample,
+ length);
+ return numSamples;
+ }
+
+ void setForcedGlitchDuration(int frames) {
+ mForceGlitchDurationFrames = frames;
}
private:
@@ -347,13 +399,16 @@ private:
double mInputPhase = 0.0;
double mMaxGlitchDelta = 0.0;
int32_t mGlitchCount = 0;
- int32_t mNonGlitchCount = 0;
+ int32_t mConsecutiveBadFrames = 0;
+ int32_t mConsecutiveGoodFrames = 0;
int32_t mGlitchLength = 0;
int mDownCounter = IDLE_FRAME_COUNT;
int32_t mFrameCounter = 0;
- int32_t mForceGlitchDuration = 0; // if > 0 then force a glitch for debugging
- int32_t mForceGlitchCounter = 4 * 48000; // count down and trigger at zero
+ int32_t mForceGlitchDurationFrames = 0; // if > 0 then force a glitch for debugging
+ static constexpr int32_t kForceGlitchPeriod = 2 * 48000; // How often we glitch
+ static constexpr float kForceGlitchOffset = 0.20f;
+ int32_t mForceGlitchCounter = kForceGlitchPeriod; // count down and trigger at zero
// measure background noise continuously as a deviation from the expected signal
double mSumSquareSignal = 0.0;